<commit_before>(function() {

  var root = this;
  root.Theremin = {}

  window.AudioContext = window.AudioContext || window.webkitAudioContext
                                            || window.mozAudioContext
                                            || window.oAudioContext
                                            || window.msAudioContext;

  if (!window.AudioContext) throw "The Web Audio API is not available in this environment"

}).call(this);<commit_msg>window-> root<commit_after>(function() {

  var root = this;
  root.Theremin = {};

  root.AudioContext = root.AudioContext || root.webkitAudioContext
                                        || root.mozAudioContext
                                        || root.oAudioContext
                                        || root.msAudioContext;

  if (!root.AudioContext) throw "The Web Audio API is not available in this environment";

}).call(this);<|endoftext|>


<commit_before>require.paths.unshift(__dirname + '/lib/node');

var express = require('express'),
    fs = require('fs'),
    path = require('path'),
    rmrf = require('./rm-rf'),
    Step = require('step'),
    mess = require('mess'),
    events = require('events'),
    _ = require('underscore')._;

var settings = require('./settings');
var app = module.exports = express.createServer();

app.use(express.bodyDecoder());
app.use(express.methodOverride());
app.use(express.staticProvider('client'));

app.get('/api', function(req, res, params) {
  res.send({
    api: 'basic',
    version: 1.0
  });
});

app.get('/api/project/:projectId?', loadProjects, function(req, res, next) {
    if (req.param('projectId')) {
        res.send(res.projects.pop());
    }
    else {
        res.send(res.projects);
    }
});

app.put('/api/project/:projectId', function(req, res, next) {
    var project = new Project(req.body);
    project.validate(project.Stylesheet, function(err, tree) {
        if (!err) {
            project.save(function(err) {
                project.load(function(err, project) {
                    res.send(project);
                });
            });
        } else {
            res.send(err, 500);
        }
    });
});

app.post('/api/project/:projectId', function(req, res, next) {
    var project = new Project(req.body);
    project.save(function(err) {
        project.load(function(err, project) {
            res.send(project);
        });
    });
});

app.del('/api/project/:projectId', loadProjects, function(req, res, next) {
    var project = res.projects.pop();
    project.delete(function() {
        res.send({});
    });
});

/**
 * Project model.
 */
var Project = function(object) {
    this.srs = '';
    this.Stylesheet = [];
    this.Layer = [];
    _.extend(this, object);
};

Project.prototype.validate = function(stylesheets, callback) {
    Step(
        function() {
            var group = this.group();
            _.each(stylesheets, function(stylesheet) {
                new(mess.Parser)({
                    filename: stylesheet.id
                }).parse(stylesheet.data, function(err, tree) {
                    try {
                        tree.toCSS({ compress: false });
                        group()(null);
                    } catch (e) {
                        group()(e);
                    }
                });
            });
        },
        function(err, res) {
            callback(err);
        }
    );
};

Project.prototype.load = function(callback) {
    var self = this;
    var projectPath = path.join(settings.files, 'project', this.id);
    fs.readFile(path.join(projectPath, self.id + '.mml'),
    'utf-8',
    function(err, data) {
        if (err || !data) {
            return callback(new Error('Error reading project file.'));
        }
        var object = JSON.parse(data);
        if (data && object) {
            _.extend(self, object);
        }
        if (self.Stylesheet && self.Stylesheet.length > 0) {
            var queue = new events.EventEmitter;
            var queueLength = self.Stylesheet.length;
            _.each(self.Stylesheet, function(filename, key) {
                fs.readFile(path.join(projectPath, filename),
                'utf-8',
                function(err, data) {
                    self.Stylesheet[key] = {
                        id: filename,
                        data: data
                    };
                    queueLength--;
                    if (queueLength === 0) {
                        queue.emit('complete');
                    }
                });
            });
            queue.on('complete', function() {
                callback(null, self);
            });
        }
        else {
            callback(err, self);
        }
    });
};

Project.prototype.save = function(callback) {
    var self = this;
    var projectPath = path.join(settings.files, 'project', this.id);

    rmrf(projectPath, function() {
        fs.mkdir(projectPath, 0777, function() {
            var data = _.extend({}, self);
            var files = [];
            if (data.id) {
                delete data.id;
            }
            if (data.Stylesheet) {
                _.each(data.Stylesheet, function(stylesheet, key) {
                    if (stylesheet.id) {
                        files.push({
                            filename: stylesheet.id,
                            data: stylesheet.data
                        });
                        data.Stylesheet[key] = stylesheet.id;
                    }
                });
            }
            files.push({
                filename: self.id + '.mml',
                data: JSON.stringify(data)
            });

            var queue = new events.EventEmitter;
            var queueLength = files.length;
            for (var i = 0; i < files.length; i++) {
                // @TODO work through stylesheet queue and save each one individually.
                fs.writeFile(path.join(projectPath, files[i].filename), files[i].data, function(err) {
                    queueLength--;
                    if (queueLength === 0) {
                        queue.emit('complete');
                    }
                });
            }
            queue.on('complete', callback);
        });
    });
}

Project.prototype.delete = function(callback) {
    var projectPath = path.join(settings.files, 'project', this.id);
    rmrf(projectPath, callback);
};

function loadProjects(req, res, next) {
    res.projects = [];
    if (req.param('projectId')) {
        var project = new Project({id: req.param('projectId') });
        project.load(function(err, project) {
            if (project) {
                res.projects.push(project);
                next();
            }
            else {
                next(err);
            }
        });
    }
    else {
        var queue = new events.EventEmitter;
        var basepath = path.join(settings.files, 'project');
        path.exists(basepath, function(exists) {
            if (!exists) fs.mkdirSync(basepath, 0777);
            fs.readdir(basepath, function(err, projects) {
                if (err) {
                    return next(new Error('Error reading projects directory.'));
                }
                else if (projects.length === 0) {
                    next();
                }
                var queueLength = projects.length;
                for (var i = 0; i < projects.length; i++) {
                    var project = new Project({id: projects[i] });
                    project.load(function(err, project) {
                        if (!err) {
                            res.projects.push(project);
                        }
                        queueLength--;
                        if (queueLength === 0) {
                            // Sort projects by id, ascending.
                            res.projects.sort(function(a, b) {
                                return a.id <= b.id ? -1 : 1;
                            });
                            queue.emit('complete');
                        }
                    });
                }
            });
        });
        queue.on('complete', next);
    }
}

require('./providers/providers')(app, settings);
require('./inspect')(app, settings);

// Note that tilehandler must come last as its route rule acts as a "catchall"
// @TODO: Either prefix the tile endpoint or come up with some other method of
// allowing better route handling.
require('./tilehandler')(app, settings);

// "Bootstrap" (aka install) the application.
require('./bootstrap')(app, settings);

app.listen(settings.port);
<commit_msg>Catch syntax errors as well<commit_after>require.paths.unshift(__dirname + '/lib/node');

var express = require('express'),
    fs = require('fs'),
    path = require('path'),
    rmrf = require('./rm-rf'),
    Step = require('step'),
    mess = require('mess'),
    events = require('events'),
    _ = require('underscore')._;

var settings = require('./settings');
var app = module.exports = express.createServer();

app.use(express.bodyDecoder());
app.use(express.methodOverride());
app.use(express.staticProvider('client'));

app.get('/api', function(req, res, params) {
  res.send({
    api: 'basic',
    version: 1.0
  });
});

app.get('/api/project/:projectId?', loadProjects, function(req, res, next) {
    if (req.param('projectId')) {
        res.send(res.projects.pop());
    }
    else {
        res.send(res.projects);
    }
});

app.put('/api/project/:projectId', function(req, res, next) {
    var project = new Project(req.body);
    project.validate(project.Stylesheet, function(err, tree) {
        if (!err) {
            project.save(function(err) {
                project.load(function(err, project) {
                    res.send(project);
                });
            });
        } else {
            res.send(err, 500);
        }
    });
});

app.post('/api/project/:projectId', function(req, res, next) {
    var project = new Project(req.body);
    project.save(function(err) {
        project.load(function(err, project) {
            res.send(project);
        });
    });
});

app.del('/api/project/:projectId', loadProjects, function(req, res, next) {
    var project = res.projects.pop();
    project.delete(function() {
        res.send({});
    });
});

/**
 * Project model.
 */
var Project = function(object) {
    this.srs = '';
    this.Stylesheet = [];
    this.Layer = [];
    _.extend(this, object);
};

Project.prototype.validate = function(stylesheets, callback) {
    Step(
        function() {
            var group = this.group();
            _.each(stylesheets, function(stylesheet) {
                new(mess.Parser)({
                    filename: stylesheet.id
                }).parse(stylesheet.data, function(err, tree) {
                    if (!err) {
                        try {
                            tree.toCSS({ compress: false });
                            group()(null);
                        } catch (e) {
                            group()(e);
                        }
                    } else {
                        group()(err);
                    }
                });
            });
        },
        function(err, res) {
            callback(err);
        }
    );
};

Project.prototype.load = function(callback) {
    var self = this;
    var projectPath = path.join(settings.files, 'project', this.id);
    fs.readFile(path.join(projectPath, self.id + '.mml'),
    'utf-8',
    function(err, data) {
        if (err || !data) {
            return callback(new Error('Error reading project file.'));
        }
        var object = JSON.parse(data);
        if (data && object) {
            _.extend(self, object);
        }
        if (self.Stylesheet && self.Stylesheet.length > 0) {
            var queue = new events.EventEmitter;
            var queueLength = self.Stylesheet.length;
            _.each(self.Stylesheet, function(filename, key) {
                fs.readFile(path.join(projectPath, filename),
                'utf-8',
                function(err, data) {
                    self.Stylesheet[key] = {
                        id: filename,
                        data: data
                    };
                    queueLength--;
                    if (queueLength === 0) {
                        queue.emit('complete');
                    }
                });
            });
            queue.on('complete', function() {
                callback(null, self);
            });
        }
        else {
            callback(err, self);
        }
    });
};

Project.prototype.save = function(callback) {
    var self = this;
    var projectPath = path.join(settings.files, 'project', this.id);

    rmrf(projectPath, function() {
        fs.mkdir(projectPath, 0777, function() {
            var data = _.extend({}, self);
            var files = [];
            if (data.id) {
                delete data.id;
            }
            if (data.Stylesheet) {
                _.each(data.Stylesheet, function(stylesheet, key) {
                    if (stylesheet.id) {
                        files.push({
                            filename: stylesheet.id,
                            data: stylesheet.data
                        });
                        data.Stylesheet[key] = stylesheet.id;
                    }
                });
            }
            files.push({
                filename: self.id + '.mml',
                data: JSON.stringify(data)
            });

            var queue = new events.EventEmitter;
            var queueLength = files.length;
            for (var i = 0; i < files.length; i++) {
                // @TODO work through stylesheet queue and save each one individually.
                fs.writeFile(path.join(projectPath, files[i].filename), files[i].data, function(err) {
                    queueLength--;
                    if (queueLength === 0) {
                        queue.emit('complete');
                    }
                });
            }
            queue.on('complete', callback);
        });
    });
}

Project.prototype.delete = function(callback) {
    var projectPath = path.join(settings.files, 'project', this.id);
    rmrf(projectPath, callback);
};

function loadProjects(req, res, next) {
    res.projects = [];
    if (req.param('projectId')) {
        var project = new Project({id: req.param('projectId') });
        project.load(function(err, project) {
            if (project) {
                res.projects.push(project);
                next();
            }
            else {
                next(err);
            }
        });
    }
    else {
        var queue = new events.EventEmitter;
        var basepath = path.join(settings.files, 'project');
        path.exists(basepath, function(exists) {
            if (!exists) fs.mkdirSync(basepath, 0777);
            fs.readdir(basepath, function(err, projects) {
                if (err) {
                    return next(new Error('Error reading projects directory.'));
                }
                else if (projects.length === 0) {
                    next();
                }
                var queueLength = projects.length;
                for (var i = 0; i < projects.length; i++) {
                    var project = new Project({id: projects[i] });
                    project.load(function(err, project) {
                        if (!err) {
                            res.projects.push(project);
                        }
                        queueLength--;
                        if (queueLength === 0) {
                            // Sort projects by id, ascending.
                            res.projects.sort(function(a, b) {
                                return a.id <= b.id ? -1 : 1;
                            });
                            queue.emit('complete');
                        }
                    });
                }
            });
        });
        queue.on('complete', next);
    }
}

require('./providers/providers')(app, settings);
require('./inspect')(app, settings);

// Note that tilehandler must come last as its route rule acts as a "catchall"
// @TODO: Either prefix the tile endpoint or come up with some other method of
// allowing better route handling.
require('./tilehandler')(app, settings);

// "Bootstrap" (aka install) the application.
require('./bootstrap')(app, settings);

app.listen(settings.port);
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2014 Vanderbilt University, All rights reserved.
 *
 * Author: Zsolt Lattmann
 */

// TODO: Use PluginManagerConfiguration
// TODO: Load ActiveSelection objects and pass it correctly
// TODO: Add more statistics to the result object
// TODO: Result object rename name -> pluginName, time -> finishTime)
// TODO: Make this class testable
// TODO: PluginManager should download the plugins

'use strict';
define([
    './PluginBase',
    './PluginContext',
    'logManager'],
    function (PluginBase, PluginContext, LogManager) {

        var PluginManagerBase = function (storage, Core, plugins) {
            this.logger = LogManager.create("PluginManager");
            this._Core = Core;       // webgme core is used to operate on objects
            this._storage = storage; // webgme storage
            this._plugins = plugins; // key value pair of pluginName: pluginType - plugins are already loaded/downloaded
            this._pluginConfigs = {}; // keeps track of the current configuration for each plugins by name

            var pluginNames = Object.keys(this._plugins);
            for (var i = 0; i < pluginNames.length; i += 1) {
                var p = new this._plugins[pluginNames[i]]();
                this._pluginConfigs[pluginNames[i]] = p.getDefaultConfig();
            }
        };

        PluginManagerBase.prototype.initialize = function (managerConfiguration, configCallback, callbackContext) {
            var self = this,
                plugins = this._plugins;

            //#1: PluginManagerBase should load the plugins

            //#2: PluginManagerBase iterates through each plugin and collects the config data
            var pluginConfigs = {};

            for (var p in plugins) {
                if (plugins.hasOwnProperty(p)) {
                    var plugin = new plugins[p]();
                    pluginConfigs[p] = plugin.getConfigStructure();
                }
            }

            if (configCallback) {
                configCallback.call(callbackContext, pluginConfigs, function (updatedPluginConfig) {
                    for (var p in updatedPluginConfig) {
                        if (updatedPluginConfig.hasOwnProperty(p)) {
                            //save it back to the plugin
                            self._pluginConfigs[p] = updatedPluginConfig[p];
                        }
                    }
                });
            }
        };

        /**
         * Gets a new instance of a plugin by name.
         *
         * @param {string} name
         * @returns {PluginBase}
         */
        PluginManagerBase.prototype.getPluginByName = function (name) {
            return this._plugins[name];
        };

        PluginManagerBase.prototype.loadMetaNodes = function (pluginContext, callback) {
            var self = this;

            this.logger.debug('Loading meta nodes');

            // get meta members
            var metaIDs = pluginContext.core.getMemberPaths(pluginContext.rootNode, 'MetaAspectSet');

            var len = metaIDs.length;

            var nodeObjs = [];

            var allObjectsLoadedHandler = function () {
                var len2 = nodeObjs.length;

                var nameObjMap = {};

                while (len2--) {
                    var nodeObj = nodeObjs[len2];

                    nameObjMap[pluginContext.core.getAttribute(nodeObj, 'name')] = nodeObj;
                }

                pluginContext.META = nameObjMap;

                self.logger.debug('Meta nodes are loaded');

                callback(null, pluginContext);
            };

            var loadedMetaObjectHandler = function (err, nodeObj) {
                nodeObjs.push(nodeObj);

                if (nodeObjs.length === metaIDs.length) {
                    allObjectsLoadedHandler();
                }
            };

            while (len--) {
                pluginContext.core.loadByPath(pluginContext.rootNode, metaIDs[len], loadedMetaObjectHandler);
            }
        };

        /**
         *
         * @param {PluginManagerConfiguration} managerConfiguration
         * @param {function} callback
         */
        PluginManagerBase.prototype.getPluginContext = function (managerConfiguration, callback) {

            // TODO: check if callback is a function

            var self = this;

            var pluginContext = new PluginContext();

            // based on the string values get the node objects
            // 1) Open project
            // 2) Load branch OR commit hash
            // 3) Load rootNode
            // 4) Load active object
            // 5) Load active selection
            // 6) Update context
            // 7) return

            pluginContext.project = this._storage;
            pluginContext.projectName = managerConfiguration.project;
            pluginContext.core = new self._Core(pluginContext.project, {corerel: 2});
            pluginContext.commitHash = managerConfiguration.commit;
            pluginContext.activeNode = managerConfiguration.activeNode;
            pluginContext.activeSelection = []; // managerConfiguration.activeSelection; // TODO: load all these objects

            // TODO: add activeNode and activeSelection

            var loadCommitHashAndRun = function (commitHash) {
                self.logger.info('Loading commit ' + commitHash);
                pluginContext.project.loadObject(commitHash, function (err, commitObj) {
                    if (!err && commitObj !== null && commitObj !== undefined) {
                        pluginContext.core.loadRoot(commitObj.root, function (err, rootNode) {
                            if (!err) {
                                pluginContext.rootNode = rootNode;
                                if (typeof pluginContext.activeNode === 'string') {
                                    pluginContext.core.loadByPath(pluginContext.rootNode, pluginContext.activeNode, function (err, activeNode) {
                                        if (!err) {
                                            pluginContext.activeNode = activeNode;
                                            self.loadMetaNodes(pluginContext, callback);
                                        } else {
                                            callback("unable to load selected object", pluginContext);
                                        }
                                    });
                                } else {
                                    pluginContext.activeNode = null;
                                    self.loadMetaNodes(pluginContext, callback);
                                }
                            } else {
                                callback("unable to load root", pluginContext);
                            }
                        });
                    } else {
                        callback('cannot find commit', pluginContext);
                    }

                });
            };

            // load commit hash and run based on branch name or commit hash
            if (managerConfiguration.branchName) {
                pluginContext.project.getBranchNames(function (err, branchNames) {
                    self.logger.debug(branchNames);

                    if (branchNames.hasOwnProperty(managerConfiguration.branchName)) {
                        pluginContext.commitHash = branchNames[managerConfiguration.branchName];
                        pluginContext.branchName = managerConfiguration.branchName;
                        loadCommitHashAndRun(pluginContext.commitHash);
                    } else {
                        callback('cannot find branch', pluginContext);
                    }
                });
            } else {
                loadCommitHashAndRun(pluginContext.commitHash);
            }

        };

        PluginManagerBase.prototype.executePlugin = function (name, managerConfiguration, done) {
            // TODO: check if name is a string
            // TODO: check if managerConfiguration is an instance of PluginManagerConfiguration
            // TODO: check if done is a function

            var PluginClass = this.getPluginByName(name);

            var plugin = new PluginClass();

            var pluginLogger = LogManager.create('Plugin.' + name);

            managerConfiguration.FS.createArtifact(name + '-output');
            // TODO: write some information about this execution into the output directory

            plugin.initialize(pluginLogger, managerConfiguration.FS);

            plugin.setCurrentConfig(this._pluginConfigs[name]);

            this.getPluginContext(managerConfiguration, function (err, pluginContext) {
                if (err) {
                    // TODO: this has to return with an empty PluginResult object and NOT with null.
                    done(err, null);

                } else {

                    //set logging level at least to INFO level since the plugins write messages with INFO level onto the console
                    var logLevel = LogManager.getLogLevel();
                    if (logLevel < LogManager.logLevels.INFO) {
                        // elevate log level if it is less then info
                        LogManager.setLogLevel(LogManager.logLevels.INFO);
                    }

                    // TODO: Would be nice to log to file and to console at the same time.
                    //LogManager.setFileLogPath('PluginManager.log');

                    plugin.configure(pluginContext);

                    var startTime = (new Date()).toISOString();

                    plugin.main(function (err, result) {
                        //set loglevel back to previous value
                        LogManager.setLogLevel(logLevel);

                        // set common information (meta info) about the plugin and measured execution times
                        result.setFinishTime((new Date()).toISOString());
                        result.setStartTime(startTime);

                        result.setPluginName(plugin.getName());
                        result.setError(err);

                        done(err, result);
                    });
                }
            });
        };

        return PluginManagerBase;
    });<commit_msg>Add active selection support to PluginManager<commit_after>/*
 * Copyright (C) 2014 Vanderbilt University, All rights reserved.
 *
 * Author: Zsolt Lattmann
 */

// TODO: Use PluginManagerConfiguration
// TODO: Load ActiveSelection objects and pass it correctly
// TODO: Add more statistics to the result object
// TODO: Result object rename name -> pluginName, time -> finishTime)
// TODO: Make this class testable
// TODO: PluginManager should download the plugins

'use strict';
define([
    './PluginBase',
    './PluginContext',
    'logManager'],
    function (PluginBase, PluginContext, LogManager) {

        var PluginManagerBase = function (storage, Core, plugins) {
            this.logger = LogManager.create("PluginManager");
            this._Core = Core;       // webgme core class is used to operate on objects
            this._storage = storage; // webgme storage
            this._plugins = plugins; // key value pair of pluginName: pluginType - plugins are already loaded/downloaded
            this._pluginConfigs = {}; // keeps track of the current configuration for each plugins by name

            var pluginNames = Object.keys(this._plugins);
            for (var i = 0; i < pluginNames.length; i += 1) {
                var p = new this._plugins[pluginNames[i]]();
                this._pluginConfigs[pluginNames[i]] = p.getDefaultConfig();
            }
        };

        PluginManagerBase.prototype.initialize = function (managerConfiguration, configCallback, callbackContext) {
            var self = this,
                plugins = this._plugins;

            //#1: PluginManagerBase should load the plugins

            //#2: PluginManagerBase iterates through each plugin and collects the config data
            var pluginConfigs = {};

            for (var p in plugins) {
                if (plugins.hasOwnProperty(p)) {
                    var plugin = new plugins[p]();
                    pluginConfigs[p] = plugin.getConfigStructure();
                }
            }

            if (configCallback) {
                configCallback.call(callbackContext, pluginConfigs, function (updatedPluginConfig) {
                    for (var p in updatedPluginConfig) {
                        if (updatedPluginConfig.hasOwnProperty(p)) {
                            //save it back to the plugin
                            self._pluginConfigs[p] = updatedPluginConfig[p];
                        }
                    }
                });
            }
        };

        /**
         * Gets a new instance of a plugin by name.
         *
         * @param {string} name
         * @returns {plugin.PluginBase}
         */
        PluginManagerBase.prototype.getPluginByName = function (name) {
            return this._plugins[name];
        };

        PluginManagerBase.prototype.loadMetaNodes = function (pluginContext, callback) {
            var self = this;

            this.logger.debug('Loading meta nodes');

            // get meta members
            var metaIDs = pluginContext.core.getMemberPaths(pluginContext.rootNode, 'MetaAspectSet');

            var len = metaIDs.length;

            var nodeObjs = [];

            var allObjectsLoadedHandler = function () {
                var len2 = nodeObjs.length;

                var nameObjMap = {};

                while (len2--) {
                    var nodeObj = nodeObjs[len2];

                    nameObjMap[pluginContext.core.getAttribute(nodeObj, 'name')] = nodeObj;
                }

                pluginContext.META = nameObjMap;

                self.logger.debug('Meta nodes are loaded');

                callback(null, pluginContext);
            };

            var loadedMetaObjectHandler = function (err, nodeObj) {
                nodeObjs.push(nodeObj);

                if (nodeObjs.length === metaIDs.length) {
                    allObjectsLoadedHandler();
                }
            };

            while (len--) {
                pluginContext.core.loadByPath(pluginContext.rootNode, metaIDs[len], loadedMetaObjectHandler);
            }
        };

        /**
         *
         * @param {plugin.PluginManagerConfiguration} managerConfiguration
         * @param {function} callback
         */
        PluginManagerBase.prototype.getPluginContext = function (managerConfiguration, callback) {

            // TODO: check if callback is a function

            var self = this;

            var pluginContext = new PluginContext();

            // based on the string values get the node objects
            // 1) Open project
            // 2) Load branch OR commit hash
            // 3) Load rootNode
            // 4) Load active object
            // 5) Load active selection
            // 6) Update context
            // 7) return

            pluginContext.project = this._storage;
            pluginContext.projectName = managerConfiguration.project;
            pluginContext.core = new self._Core(pluginContext.project, {corerel: 2});
            pluginContext.commitHash = managerConfiguration.commit;
            pluginContext.activeNode = null;    // active object
            pluginContext.activeSelection = []; // selected objects

            // add activeSelection
            var loadActiveSelectionAndMetaNodes = function () {
                  if (managerConfiguration.activeSelection.length === 0) {
                      self.loadMetaNodes(pluginContext, callback);
                  } else {
                      var remaining = managerConfiguration.activeSelection.length;

                      for (var i = 0; i < managerConfiguration.activeSelection.length; i += 1) {
                          (function(activeNodePath){
                              pluginContext.core.loadByPath(pluginContext.rootNode, activeNodePath, function (err, activeNode) {
                                  remaining -= 1;

                                  if (err) {
                                      self.logger.error('unable to load active selection: ' + activeNodePath);
                                      return;
                                  }

                                  pluginContext.activeSelection.push(activeNode);

                                  if (remaining === 0) {
                                      // all nodes from active selection are loaded
                                      self.loadMetaNodes(pluginContext, callback);
                                  }
                              });
                          })(managerConfiguration.activeSelection[i]);
                      }
                  }
            };

            // add activeNode
            var loadCommitHashAndRun = function (commitHash) {
                self.logger.info('Loading commit ' + commitHash);
                pluginContext.project.loadObject(commitHash, function (err, commitObj) {
                    if (err) {
                        callback(err, pluginContext);
                        return;
                    }

                    if (typeof commitObj === 'undefined' || commitObj === null) {
                        callback('cannot find commit', pluginContext);
                        return;
                    }

                    pluginContext.core.loadRoot(commitObj.root, function (err, rootNode) {
                        if (err) {
                            callback("unable to load root", pluginContext);
                            return;
                        }

                        pluginContext.rootNode = rootNode;
                        if (typeof managerConfiguration.activeNode === 'string') {
                            pluginContext.core.loadByPath(pluginContext.rootNode, managerConfiguration.activeNode, function (err, activeNode) {
                                if (err) {
                                    callback("unable to load selected object", pluginContext);
                                    return;
                                }

                                pluginContext.activeNode = activeNode;
                                loadActiveSelectionAndMetaNodes();
                            });
                        } else {
                            pluginContext.activeNode = null;
                            loadActiveSelectionAndMetaNodes();
                        }
                    });
               });
            };

            // load commit hash and run based on branch name or commit hash
            if (managerConfiguration.branchName) {
                pluginContext.project.getBranchNames(function (err, branchNames) {
                    self.logger.debug(branchNames);

                    if (branchNames.hasOwnProperty(managerConfiguration.branchName)) {
                        pluginContext.commitHash = branchNames[managerConfiguration.branchName];
                        pluginContext.branchName = managerConfiguration.branchName;
                        loadCommitHashAndRun(pluginContext.commitHash);
                    } else {
                        callback('cannot find branch', pluginContext);
                    }
                });
            } else {
                loadCommitHashAndRun(pluginContext.commitHash);
            }

        };

        PluginManagerBase.prototype.executePlugin = function (name, managerConfiguration, callback) {
            // TODO: check if name is a string
            // TODO: check if managerConfiguration is an instance of PluginManagerConfiguration
            // TODO: check if callback is a function

            var PluginClass = this.getPluginByName(name);

            var plugin = new PluginClass();

            var pluginLogger = LogManager.create('Plugin.' + name);

            managerConfiguration.FS.createArtifact(name + '-output');
            // TODO: write some information about this execution into the output directory

            plugin.initialize(pluginLogger, managerConfiguration.FS);

            plugin.setCurrentConfig(this._pluginConfigs[name]);

            this.getPluginContext(managerConfiguration, function (err, pluginContext) {
                if (err) {
                    // TODO: this has to return with an empty PluginResult object and NOT with null.
                    callback(err, null);
                    return;

                }

                //set logging level at least to INFO level since the plugins write messages with INFO level onto the console
                var logLevel = LogManager.getLogLevel();
                if (logLevel < LogManager.logLevels.INFO) {
                    // elevate log level if it is less then info
                    LogManager.setLogLevel(LogManager.logLevels.INFO);
                }

                // TODO: Would be nice to log to file and to console at the same time.
                //LogManager.setFileLogPath('PluginManager.log');

                plugin.configure(pluginContext);

                var startTime = (new Date()).toISOString();

                plugin.main(function (err, result) {
                    //set logging level back to previous value
                    LogManager.setLogLevel(logLevel);

                    // set common information (meta info) about the plugin and measured execution times
                    result.setFinishTime((new Date()).toISOString());
                    result.setStartTime(startTime);

                    result.setPluginName(plugin.getName());
                    result.setError(err);

                    callback(err, result);
                });

            });
        };

        return PluginManagerBase;
    });<|endoftext|>


<commit_before>;(function(exports) {
  var library = {
    first: function(x) {
      return x[0];
    },
    rest: function(x) {
      return x.slice(1);
    },
    print: function(x) {
      console.log(x);
      return x;
    }
  };

  var Ctx = function(scope, parent) {
    this.scope = scope;
    this.parent = parent;
    this.get = function(identifier) {
      var item = this.scope[identifier];
      if (item !== undefined) {
        return item;
      } else if (this.parent !== undefined) {
        return this.parent.get(identifier);
      }
    };
  };

  var lambda = function(input, ctx) {
    return {
      type: "function",
      value: function(args) {
        var lambdaScope = input[1].reduce(function(acc, x, i) {
          acc[x.value] = args[i];
          return acc;
        }, {});
        return interpret(input[2], new Ctx(lambdaScope, ctx));
      }
    };
  };

  var fn = function(input, ctx) {
    return {
      type: "function",
      value: function(args) {
        return ctx.get(input.value).apply(undefined, args);
      }
    };
  };

  var interpret = function(input, ctx) {
    if (ctx === undefined) {
      return interpret(input, new Ctx(library));
    } else if (input instanceof Array) {
      if (input[0].value === "lambda") {
        return lambda(input, ctx);
      } else {
        var list = input.map(function(x) { return interpret(x, ctx); });
        if (list[0].type === "function") {
          return list[0].value(list.slice(1));
        } else {
          return list;
        }
      }
    } else if (input.type === "identifier") {
      if (ctx.get(input.value) instanceof Function) { // prepare fn
        return fn(input, ctx);
      } else { // var lookup
        return ctx.get(input.value);
      }
    } else { // literal
      return input.value;
    }
  };

  var atDepth = function(output, depth) {
    if (depth === 0) {
      return output;
    } else {
      return atDepth(output[output.length - 1], depth - 1);
    }
  };

  var type = function(input) {
    if (!isNaN(parseFloat(input))) {
      return { type:'literal', value: parseFloat(input) };
    } else if (input[0] === '"' && input.slice(-1) === '"') {
      return { type:'literal', value: input.slice(1, -1) };
    } else {
      return { type:'identifier', value: input };
    }
  };

  var parenthesize = function(input) {
    var output = [];
    var depth = 0;
    while (input.length > 0) {
      var token = input.shift();
      if (token === "(") {
        atDepth(output, depth++).push([]);
      } else if (token === ")") {
        depth--;
      } else {
        atDepth(output, depth).push(type(token));
      }
    }

    return output.pop();
  };

  var tokenize = function(input) {
    return input.split('"').map(function(x, i) {
                   return i % 2 === 0 ? x : x.replace(/ /g, "spaceholder");
                 }).join('"')
                .replace(/\(/g, ' ( ')
                .replace(/\)/g, ' ) ')
                .trim()
                .split(/ +/)
                .map(function(x) {
                  return x.replace(/spaceholder/g, " ");
                });
  };

  var parse = function(input) {
    return parenthesize(tokenize(input));
  };

  exports.tinyLisp = {};
  exports.tinyLisp.parse = parse;
  exports.tinyLisp.interpret = interpret;
})(typeof exports === 'undefined' ? this : exports);
<commit_msg>Use forEach rather than while in parse().<commit_after>;(function(exports) {
  var library = {
    first: function(x) {
      return x[0];
    },
    rest: function(x) {
      return x.slice(1);
    },
    print: function(x) {
      console.log(x);
      return x;
    }
  };

  var Ctx = function(scope, parent) {
    this.scope = scope;
    this.parent = parent;
    this.get = function(identifier) {
      var item = this.scope[identifier];
      if (item !== undefined) {
        return item;
      } else if (this.parent !== undefined) {
        return this.parent.get(identifier);
      }
    };
  };

  var lambda = function(input, ctx) {
    return {
      type: "function",
      value: function(args) {
        var lambdaScope = input[1].reduce(function(acc, x, i) {
          acc[x.value] = args[i];
          return acc;
        }, {});
        return interpret(input[2], new Ctx(lambdaScope, ctx));
      }
    };
  };

  var fn = function(input, ctx) {
    return {
      type: "function",
      value: function(args) {
        return ctx.get(input.value).apply(undefined, args);
      }
    };
  };

  var interpret = function(input, ctx) {
    if (ctx === undefined) {
      return interpret(input, new Ctx(library));
    } else if (input instanceof Array) {
      if (input[0].value === "lambda") {
        return lambda(input, ctx);
      } else {
        var list = input.map(function(x) { return interpret(x, ctx); });
        if (list[0].type === "function") {
          return list[0].value(list.slice(1));
        } else {
          return list;
        }
      }
    } else if (input.type === "identifier") {
      if (ctx.get(input.value) instanceof Function) { // prepare fn
        return fn(input, ctx);
      } else { // var lookup
        return ctx.get(input.value);
      }
    } else { // literal
      return input.value;
    }
  };

  var atDepth = function(output, depth) {
    if (depth === 0) {
      return output;
    } else {
      return atDepth(output[output.length - 1], depth - 1);
    }
  };

  var type = function(input) {
    if (!isNaN(parseFloat(input))) {
      return { type:'literal', value: parseFloat(input) };
    } else if (input[0] === '"' && input.slice(-1) === '"') {
      return { type:'literal', value: input.slice(1, -1) };
    } else {
      return { type:'identifier', value: input };
    }
  };

  var parenthesize = function(input) {
    var output = [];
    var depth = 0;
    input.forEach (function(token) {
      if (token === "(") {
        atDepth(output, depth++).push([]);
      } else if (token === ")") {
        depth--;
      } else {
        atDepth(output, depth).push(type(token));
      }
    });

    return output.pop();
  };

  var tokenize = function(input) {
    return input.split('"').map(function(x, i) {
                   return i % 2 === 0 ? x : x.replace(/ /g, "spaceholder");
                 }).join('"')
                .replace(/\(/g, ' ( ')
                .replace(/\)/g, ' ) ')
                .trim()
                .split(/ +/)
                .map(function(x) {
                  return x.replace(/spaceholder/g, " ");
                });
  };

  var parse = function(input) {
    return parenthesize(tokenize(input));
  };

  exports.tinyLisp = {};
  exports.tinyLisp.parse = parse;
  exports.tinyLisp.interpret = interpret;
})(typeof exports === 'undefined' ? this : exports);
<|endoftext|>


<commit_before>/*globals define*/
/*jshint browser: true*/

/**
 * Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 08:58:20 GMT-0500 (CDT).
 */

define([
    './lib/ace',
    'underscore',
    'css!./styles/TextEditorWidget.css'
], function (
    ace,
    _
) {
    'use strict';

    var TextEditorWidget,
        WIDGET_CLASS = 'text-editor';

    TextEditorWidget = function (logger, container) {
        this._logger = logger.fork('Widget');

        this._el = container;
        this._el.css({height: '100%'});
        this.editor = ace.edit(this._el[0]);
        this.editor.getSession().setMode('ace/mode/lua');

        // Get the config from component settings for themes
        // TODO
        this.editor.setOptions({
            fontSize: '12pt'
        });
        this.editor.$blockScrolling = Infinity;
        this.DELAY = 750;
        // this.editor.setTheme('ace/theme/monokai');

        this.editor.on('input', _.debounce(this.saveText.bind(this), this.DELAY));
        this.currentHeader = '';
        this.activeNode = null;
        this._initialize();

        this._logger.debug('ctor finished');
    };

    TextEditorWidget.prototype._initialize = function () {
        // set widget class
        this._el.addClass(WIDGET_CLASS);
    };

    TextEditorWidget.prototype.onWidgetContainerResize = function () {
        this.editor.resize();
    };

    // Adding/Removing/Updating items
    TextEditorWidget.prototype.getHeader = function (desc) {
        return `-- Editing "${desc.name}"`;
    };

    TextEditorWidget.prototype.addNode = function (desc) {
        // Set the current text based on the given
        // Create the header
        var header = this.getHeader(desc);

        this.activeNode = desc.id;
        this.editor.setValue(header + '\n' + desc.text, 2);
        this.currentHeader = header;
    };

    TextEditorWidget.prototype.saveText = function () {
        var text = this.editor.getValue().replace(this.currentHeader + '\n', '');
        if (this.activeNode) {
            this.saveTextFor(this.activeNode, text);
        } else {
            this._logger.error(`Active node is invalid! (${this.activeNode})`);
        }
    };

    TextEditorWidget.prototype.removeNode = function (gmeId) {
        if (this.activeNode === gmeId) {
            this.editor.setValue('');
            this.activeNode = null;
        }
    };

    TextEditorWidget.prototype.updateNode = function (desc) {
        // Check for header changes
        if (this.activeNode === desc.id &&
            this.getHeader(desc) !== this.currentHeader) {
            this.addNode(desc);
        }
        // TODO: Handle concurrent editing... Currently, last save wins and there are no
        // updates after opening the node. Supporting multiple users editing the same
        // operation/layer is important but more work than it is worth for now
        //var currentText = this.editor.getValue().replace(this.currentHeader, '');
        //if (this.activeNode === desc.id && desc.text !== currentText) {
            //this.addNode(desc);
        //}
    };

    /* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
    TextEditorWidget.prototype.destroy = function () {
    };

    TextEditorWidget.prototype.onActivate = function () {
        this._logger.debug('TextEditorWidget has been activated');
    };

    TextEditorWidget.prototype.onDeactivate = function () {
        this._logger.debug('TextEditorWidget has been deactivated');
    };

    return TextEditorWidget;
});
<commit_msg>set tab size to 3. Fixes #214<commit_after>/*globals define*/
/*jshint browser: true*/

/**
 * Generated by VisualizerGenerator 1.7.0 from webgme on Wed May 18 2016 08:58:20 GMT-0500 (CDT).
 */

define([
    './lib/ace',
    'underscore',
    'css!./styles/TextEditorWidget.css'
], function (
    ace,
    _
) {
    'use strict';

    var TextEditorWidget,
        WIDGET_CLASS = 'text-editor';

    TextEditorWidget = function (logger, container) {
        this._logger = logger.fork('Widget');

        this._el = container;
        this._el.css({height: '100%'});
        this.editor = ace.edit(this._el[0]);
        this.editor.getSession().setOptions({
            mode: 'ace/mode/lua',
            tabSize: 3,
            useSoftTabs: true
        });
        // Get the config from component settings for themes
        // TODO
        this.editor.setOptions({
            fontSize: '12pt'
        });
        this.editor.$blockScrolling = Infinity;
        this.DELAY = 750;
        // this.editor.setTheme('ace/theme/monokai');

        this.editor.on('input', _.debounce(this.saveText.bind(this), this.DELAY));
        this.currentHeader = '';
        this.activeNode = null;
        this._initialize();

        this._logger.debug('ctor finished');
    };

    TextEditorWidget.prototype._initialize = function () {
        // set widget class
        this._el.addClass(WIDGET_CLASS);
    };

    TextEditorWidget.prototype.onWidgetContainerResize = function () {
        this.editor.resize();
    };

    // Adding/Removing/Updating items
    TextEditorWidget.prototype.getHeader = function (desc) {
        return `-- Editing "${desc.name}"`;
    };

    TextEditorWidget.prototype.addNode = function (desc) {
        // Set the current text based on the given
        // Create the header
        var header = this.getHeader(desc);

        this.activeNode = desc.id;
        this.editor.setValue(header + '\n' + desc.text, 2);
        this.currentHeader = header;
    };

    TextEditorWidget.prototype.saveText = function () {
        var text = this.editor.getValue().replace(this.currentHeader + '\n', '');
        if (this.activeNode) {
            this.saveTextFor(this.activeNode, text);
        } else {
            this._logger.error(`Active node is invalid! (${this.activeNode})`);
        }
    };

    TextEditorWidget.prototype.removeNode = function (gmeId) {
        if (this.activeNode === gmeId) {
            this.editor.setValue('');
            this.activeNode = null;
        }
    };

    TextEditorWidget.prototype.updateNode = function (desc) {
        // Check for header changes
        if (this.activeNode === desc.id &&
            this.getHeader(desc) !== this.currentHeader) {
            this.addNode(desc);
        }
        // TODO: Handle concurrent editing... Currently, last save wins and there are no
        // updates after opening the node. Supporting multiple users editing the same
        // operation/layer is important but more work than it is worth for now
        //var currentText = this.editor.getValue().replace(this.currentHeader, '');
        //if (this.activeNode === desc.id && desc.text !== currentText) {
            //this.addNode(desc);
        //}
    };

    /* * * * * * * * Visualizer life cycle callbacks * * * * * * * */
    TextEditorWidget.prototype.destroy = function () {
    };

    TextEditorWidget.prototype.onActivate = function () {
        this._logger.debug('TextEditorWidget has been activated');
    };

    TextEditorWidget.prototype.onDeactivate = function () {
        this._logger.debug('TextEditorWidget has been deactivated');
    };

    return TextEditorWidget;
});
<|endoftext|>


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

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import {classMap} from "lit/directives/class-map.js";
import "../forms/file-upload.js";

/**
 * Token filter. Select2 version with opencga dynamic datasource
 *
 */

export default class SelectTokenFilter extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            config: {
                type: Object
            },
            value: {
                type: String
            }
        };
    }

    _init() {
        this._prefix = "select-" + UtilsNew.randomString(6) + "_";
    }

    connectedCallback() {
        super.connectedCallback();
        this._config = {...this.getDefaultConfig(), ...this.config};
        this.state = [];
    }

    firstUpdated() {
        this.select = $("#" + this._prefix);
        this.select.select2({
            tags: this._config.freeTag === true,
            multiple: true,
            width: "style",
            placeholder: this._config.placeholder,
            minimumInputLength: this._config.minimumInputLength,
            ajax: {
                transport: async (params, success, failure) => this._config.source(params, success, failure),
                // NOTE processResults() expects a RestResponse instance, override the whole ajax() method in case of external data source (not Opencga)
                processResults: (restResponse, params) => {
                    const _params = params;
                    _params.page = _params.page || 1;
                    return {
                        results: this._config.preprocessResults(restResponse.getResults()),
                        pagination: {
                            more: (_params.page * this._config.limit) < restResponse.getResponse().numMatches
                        }
                    };
                }
            },
            /* dropdown template */
            templateResult: item => {
                if (item.loading) {
                    return $(`<i class="fa fa-spinner fa-spin" aria-hidden="true"></i> <span>${item.text}</span>`);
                }
                // NOTE this function silently fails in case of errors if not wrapped in try/catch block
                try {
                    const {name, ...rest} = this._config.fields(item) ?? item.id;
                    // if name is not defined it means tags=true, _config.fields() mapper function is defined but the user is typing a non existing word (in data source). This avoids printing `undefined` in dropdown.
                    if (name) {
                        return $(`<span>${name}</span> ${(rest ? Object.entries(rest).map(([label, value]) => `
${label} ${value || "-"}
`).join("") : "") }`);
                    } else {
                        return item.id;
                    }

                } catch (e) {
                    console.error(e);
                }
            },
            /* selection template. At this stage select2 assumes item as an {id,text} pair or a string. */
            templateSelection: item => {
                return item.id ?? item.text;
            },
            ...this._config.select2Config
        })
            .on("select2:select", e => {
                this.filterChange(e);
                /* dynamic width. DONE in css */
                /* if (this._config.dynamicWidth) {
                    let width = 200;
                    $(".select2-selection__choice", this).each(function () {
                        const token = $(this);
                        const tokenWidth = token.outerWidth();
                        width += tokenWidth;
                    });
                    console.log("$(this).find(\"span.select2-selection\")", $(this).find("span.select2-selection"))
                    $(this).find("span.select2-selection").css("max-width", width);
                }*/
            })
            .on("select2:unselect", e => {
                this.filterChange(e);
            });

    }

    updated(_changedProperties) {
        if (_changedProperties.has("config")) {
            this._config = {...this.getDefaultConfig(), ...this.config};
        }
        if (_changedProperties.has("value")) {
            // manual addition of <option> elements is needed when tags=true in select2. We do it in any case.
            this.select.empty();
            const regExpSeparators = new RegExp("[" + this._config.separator.join("") + "]");
            this.addOptions(UtilsNew.isNotEmpty(this.value) ? this.value?.split(regExpSeparators) : "");
        }

    }

    addOptions(ids) {
        if (ids) {
            const _ids = [...new Set(ids)];
            for (const id of _ids) {
                // Create a DOM Option and pre-select by default
                const newOption = new Option(id, id, true, true);
                // Append it to the select
                this.select.append(newOption).trigger("change");
            }
            this.select.trigger("change");
        } else {
            this.select.val(null).trigger("change");
        }
    }

    fileUploaded(e) {
        if (e.detail.value) {
            const list = e.detail.value.join(",");
            // TODO this.value could be a string separated by other chars than commas
            this.value = this.value ? this.value + "," + list : list;
        }
    }

    filterChange(e) {
        // join by "," only as the operator (, or ;) is not a concern of this component.
        // this component only needs to split by all separators (defined in config) in updated() fn,
        // but it doesn't need to reckon which one is being used at the moment (some tokens can contain commas (e.g. in HPO))
        const selection = this.select.select2("data").map(el => el.id).join(",");
        console.log("filterChange", selection);
        const event = new CustomEvent("filterChange", {
            detail: {
                value: selection
            }
        });
        this.dispatchEvent(event);
    }

    toggleFileUpload(e) {
        $(`#${this._prefix}-select-wrapper .file-drop-area`).collapse("toggle");
    }

    getDefaultConfig() {
        return {
            separator: [","],
            limit: 10,
            minimumInputLength: 0,
            maxItems: 0,
            placeholder: "Start typing",
            freeTag: false,
            fileUpload: false,
            source: () => {
                throw new Error("Data source not defined");
            },
            fields: item => ({
                "name": item.id,
            }),
            /* remap results coming from opencga */
            preprocessResults(results) {
                if (results.length) {
                    if ("string" === typeof results[0]) {
                        return results.map(s => ({id: s}));
                    }
                }
                return results;
            }
        };
    }

    render() {
        return html`
            <form>

                        <select class="form-control"  id="${this._prefix}" @change="${this.filterChange}"></select>
                        ${this._config.fileUpload ? html`<span class="input-group-addon file-upload-toggle" @click="${this.toggleFileUpload}"><i class="fas fa-upload"></i></span>` : ""}

                    ${this._config.fileUpload ? html`<file-upload @filterChange="${this.fileUploaded}"></file-upload>` : ""}

            </form>
        `;
    }

}

customElements.define("select-token-filter", SelectTokenFilter);
<commit_msg>wc: keep original select-token-filter when file upload is disabled (#265)<commit_after>/**
 * Copyright 2015-2019 OpenCB
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {LitElement, html} from "lit";
import UtilsNew from "../../../core/utilsNew.js";
import {classMap} from "lit/directives/class-map.js";
import "../forms/file-upload.js";

/**
 * Token filter. Select2 version with opencga dynamic datasource
 *
 */

export default class SelectTokenFilter extends LitElement {

    constructor() {
        super();
        this._init();
    }

    createRenderRoot() {
        return this;
    }

    static get properties() {
        return {
            config: {
                type: Object
            },
            value: {
                type: String
            }
        };
    }

    _init() {
        this._prefix = "select-" + UtilsNew.randomString(6) + "_";
    }

    connectedCallback() {
        super.connectedCallback();
        this._config = {...this.getDefaultConfig(), ...this.config};
        this.state = [];
    }

    firstUpdated() {
        this.select = $("#" + this._prefix);
        this.select.select2({
            tags: this._config.freeTag === true,
            multiple: true,
            width: "style",
            placeholder: this._config.placeholder,
            minimumInputLength: this._config.minimumInputLength,
            ajax: {
                transport: async (params, success, failure) => this._config.source(params, success, failure),
                // NOTE processResults() expects a RestResponse instance, override the whole ajax() method in case of external data source (not Opencga)
                processResults: (restResponse, params) => {
                    const _params = params;
                    _params.page = _params.page || 1;
                    return {
                        results: this._config.preprocessResults(restResponse.getResults()),
                        pagination: {
                            more: (_params.page * this._config.limit) < restResponse.getResponse().numMatches
                        }
                    };
                }
            },
            /* dropdown template */
            templateResult: item => {
                if (item.loading) {
                    return $(`<i class="fa fa-spinner fa-spin" aria-hidden="true"></i> <span>${item.text}</span>`);
                }
                // NOTE this function silently fails in case of errors if not wrapped in try/catch block
                try {
                    const {name, ...rest} = this._config.fields(item) ?? item.id;
                    // if name is not defined it means tags=true, _config.fields() mapper function is defined but the user is typing a non existing word (in data source). This avoids printing `undefined` in dropdown.
                    if (name) {
                        return $(`<span>${name}</span> ${(rest ? Object.entries(rest).map(([label, value]) => `
${label} ${value || "-"}
`).join("") : "") }`);
                    } else {
                        return item.id;
                    }

                } catch (e) {
                    console.error(e);
                }
            },
            /* selection template. At this stage select2 assumes item as an {id,text} pair or a string. */
            templateSelection: item => {
                return item.id ?? item.text;
            },
            ...this._config.select2Config
        })
            .on("select2:select", e => {
                this.filterChange(e);
                /* dynamic width. DONE in css */
                /* if (this._config.dynamicWidth) {
                    let width = 200;
                    $(".select2-selection__choice", this).each(function () {
                        const token = $(this);
                        const tokenWidth = token.outerWidth();
                        width += tokenWidth;
                    });
                    console.log("$(this).find(\"span.select2-selection\")", $(this).find("span.select2-selection"))
                    $(this).find("span.select2-selection").css("max-width", width);
                }*/
            })
            .on("select2:unselect", e => {
                this.filterChange(e);
            });

    }

    updated(_changedProperties) {
        if (_changedProperties.has("config")) {
            this._config = {...this.getDefaultConfig(), ...this.config};
        }
        if (_changedProperties.has("value")) {
            // manual addition of <option> elements is needed when tags=true in select2. We do it in any case.
            this.select.empty();
            const regExpSeparators = new RegExp("[" + this._config.separator.join("") + "]");
            this.addOptions(UtilsNew.isNotEmpty(this.value) ? this.value?.split(regExpSeparators) : "");
        }

    }

    addOptions(ids) {
        if (ids) {
            const _ids = [...new Set(ids)];
            for (const id of _ids) {
                // Create a DOM Option and pre-select by default
                const newOption = new Option(id, id, true, true);
                // Append it to the select
                this.select.append(newOption).trigger("change");
            }
            this.select.trigger("change");
        } else {
            this.select.val(null).trigger("change");
        }
    }

    fileUploaded(e) {
        if (e.detail.value) {
            const list = e.detail.value.join(",");
            // TODO this.value could be a string separated by other chars than commas
            this.value = this.value ? this.value + "," + list : list;
        }
    }

    filterChange(e) {
        // join by "," only as the operator (, or ;) is not a concern of this component.
        // this component only needs to split by all separators (defined in config) in updated() fn,
        // but it doesn't need to reckon which one is being used at the moment (some tokens can contain commas (e.g. in HPO))
        const selection = this.select.select2("data").map(el => el.id).join(",");
        console.log("filterChange", selection);
        const event = new CustomEvent("filterChange", {
            detail: {
                value: selection
            }
        });
        this.dispatchEvent(event);
    }

    toggleFileUpload(e) {
        $(`#${this._prefix}-select-wrapper .file-drop-area`).collapse("toggle");
    }

    getDefaultConfig() {
        return {
            separator: [","],
            limit: 10,
            minimumInputLength: 0,
            maxItems: 0,
            placeholder: "Start typing",
            freeTag: false,
            fileUpload: false,
            source: () => {
                throw new Error("Data source not defined");
            },
            fields: item => ({
                "name": item.id,
            }),
            /* remap results coming from opencga */
            preprocessResults(results) {
                if (results.length) {
                    if ("string" === typeof results[0]) {
                        return results.map(s => ({id: s}));
                    }
                }
                return results;
            }
        };
    }

    render() {
        if (this._config.fileUpload) {
            return html`
                <form>

                            <select class="form-control"  id="${this._prefix}" @change="${this.filterChange}"></select>

                        <file-upload @filterChange="${this.fileUploaded}"></file-upload>

                </form>
            `;
        }

        return html`

                <select class="form-control"  id="${this._prefix}" @change="${this.filterChange}"></select>

        `;
    }

}

customElements.define("select-token-filter", SelectTokenFilter);
<|endoftext|>


<commit_before>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redexutil/LICENSE

import assert from 'assert';
import bunyan from 'bunyan';
import lodash from 'lodash';

const defaultLevel = 'info';
const levels = ['debug', 'info', 'warn', 'error'];
const extraLevels = ['state', 'digest', 'child'];
const allLevels = levels.concat(extraLevels);
const digestLimit = 100;
const state = {
   limit: 10,
   stats: {},
   logging: {
      error: [],
      warn: [],
      info: [],
      debug: [],
      digest: []
   }
};

function getStats(name) {
   let stats = state.stats[name];
   if (!stats) {
      stats = {
         counts: {},
         averages: {},
         peaks: {},
      };
      state.stats[name] = stats;
   }
   return stats;
}

function increment(logger, name, prop) {
   let stats = getStats(name);
   let count = stats.counts[prop] || 0;
   count += 1;
   stats.counts[prop] = count;
   return count;
}

function peak(logger, name, prop, value) {
   let stats = getStats(name);
   let count = stats.counts[prop] || 0;
   count += 1;
   stats.counts[prop] = count;
   //
   let average = stats.averages[prop];
   if (!average) {
      average = value;
   } else if (count > 1) {
      average = ((count - 1) * average + value)/count;
   }
   stats.averages[prop] = average;
   //
   let peak = stats.peaks[prop];
   if (!stats.peaks.hasOwnProperty(prop)) {
      stats.peaks[prop] = value;
      return value;
   }
   if (value > peak) {
      stats.peaks[prop] = value;
      peak = value;
      logger.info('peak', prop, value, count, average);
   }
   return peak;
}

function basename(file) {
   var matcher = file.match(/([^\/]+)\.[a-z]+$/);
   if (matcher) {
      return matcher[1];
   } else {
      return file;
   }
}

module.exports = {
   publish() {
      return Object.assign({}, state.stats, state.logging);
   },
   pub() {
      return Object.assign({}, state.stats, state.logging);
   },
   counters() { // TODO deprecate
      return {};
   },
   create(name, level) {
      name = basename(name);
      level = level || global.loggerLevel || process.env.loggerLevel || defaultLevel;
      if (lodash.includes(levels, level)) {
         let logger = bunyan.createLogger({name, level});
         return decorate(logger, name, level);
      } else {
         assert(lodash.includes(extraLevels, level), 'level: ' + level);
         return decorate(null, name, level);
      }
   }
};

function logging(logger, name, loggerLevel, context, level, args, count) {
   increment(logger, name, level);
   args = [].slice.call(args); // convert arguments to array
   if (!lodash.isEmpty(context)) {
      if (lodash.isArray(context)) {
         args = context.concat(args);
      }
   }
   if (!state.logging.hasOwnProperty(level)) {
      args.splice(0, 0, 'Invalid level: ' + level);
      level = 'warn';
   }
   if (logger) {
      if (level === 'digest') {
         if (count < digestLimit/10 && count % digestLimit === 0) {
            logger.info('digest', count, ...args);
         }
      } else if (lodash.includes(levels, level)) {
         if (levels.indexOf(level) >= levels.indexOf(loggerLevel)) {
            logger[level].call(logger, ...args);
            let error = findArgsError(args);
            if (error) {
               if (error.code && error.code === 'ETIMEOUT') {
               } else {
                  logger[level].call(logger, error);
               }
            }
         }
      } else {
      }
   }
   let date = new Date().toISOString().substring(0, 16);
   let message = [date, name, ...args];
   state.logging[level].splice(0, 0, message);
   if (state.logging[level].length > state.limit) { // trim
      state.logging[level].length = state.limit;
   }
}

function findArgsError(args) {
   if (lodash.isError(args[0])) {
      return args[0];
   } else if (lodash.isError(args[1])) {
      return args[1];
   } else if (lodash.isError(args[args.length - 1])) {
      return args[args.length - 1];
   }
}

function decorate(logger, name, level) {
   let count = 0;
   let context = [];
   const those = {
      get name() {
         return name;
      },
      verbose() {
      },
      vdebug() {
      },
      debug() {
         if (level === 'debug') {
            logging(logger, name, level, context, 'debug', arguments);
         }
      },
      info() {
         if (level !== 'warn') {
            logging(logger, name, level, context, 'info', arguments);
         }
      },
      dev() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      wverbose() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      wdebug() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      winfo() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      dverbose() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      ddebug() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      dinfo() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      tdebug() {
         if (process.env.envType === 'test') {
            logging(logger, name, level, context, 'info', arguments);
         }
      },
      warn() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      error() {
         logging(logger, name, level, context, 'error', arguments);
      },
      state() {
         logging(logger, name, level, context, 'state', arguments);
      },
      digest() {
         if (level === 'debug') {
            count += 1;
            logging(logger, name, level, context, 'digest', arguments, count);
         }
      },
      context() {
         context = [].slice.call(arguments);
      },
      child() {
         let childName = [name].concat([].slice.call(arguments)).join('.');
         return Loggers.create(childName, level);
      },
      increment(prop) {
         if (level === 'debug') {
            logging(logger, name, level, context, 'debug', ['increment', ...arguments]);
         }
         return increment(logger, name, prop);
      },
      peak(prop, value) {
         return peak(logger, name, prop, value);
      },
      timer(prop, time) {
         return peak(logger, name, prop, new Date().getTime() - time);
      }
   };
   return those;
}
<commit_msg>eowyn<commit_after>// Copyright (c) 2015, Evan Summers (twitter.com/evanxsummers)
// ISC license, see http://github.com/evanx/redexutil/LICENSE

import assert from 'assert';
import bunyan from 'bunyan';
import lodash from 'lodash';

const defaultLevel = 'info';
const levels = ['debug', 'info', 'warn', 'error'];
const extraLevels = ['state', 'digest', 'child'];
const allLevels = levels.concat(extraLevels);
const digestLimit = 100;
const state = {
   limit: 10,
   stats: {},
   logging: {
      error: [],
      warn: [],
      info: [],
      debug: [],
      digest: []
   }
};

function getStats(name) {
   let stats = state.stats[name];
   if (!stats) {
      stats = {
         counts: {},
         averages: {},
         peaks: {},
      };
      state.stats[name] = stats;
   }
   return stats;
}

function increment(logger, name, prop) {
   let stats = getStats(name);
   let count = stats.counts[prop] || 0;
   count += 1;
   stats.counts[prop] = count;
   return count;
}

function peak(logger, name, prop, value) {
   let stats = getStats(name);
   let count = stats.counts[prop] || 0;
   count += 1;
   stats.counts[prop] = count;
   //
   let average = stats.averages[prop];
   if (!average) {
      average = value;
   } else if (count > 1) {
      average = ((count - 1) * average + value)/count;
   }
   stats.averages[prop] = average;
   //
   let peak = stats.peaks[prop];
   if (!stats.peaks.hasOwnProperty(prop)) {
      stats.peaks[prop] = value;
      return value;
   }
   if (value > peak) {
      stats.peaks[prop] = value;
      peak = value;
      logger.info('peak', prop, value, count, average);
   }
   return peak;
}

function basename(file) {
   var matcher = file.match(/([^\/]+)\.[a-z]+$/);
   if (matcher) {
      return matcher[1];
   } else {
      return file;
   }
}

module.exports = {
   publish() {
      return Object.assign({}, state.stats, state.logging);
   },
   pub() {
      return Object.assign({}, state.stats, state.logging);
   },
   counters() { // TODO deprecate
      return {};
   },
   create(name, level) {
      name = basename(name);
      level = level || global.loggerLevel || process.env.loggerLevel || defaultLevel;
      if (lodash.includes(levels, level)) {
         let logger = bunyan.createLogger({name, level});
         return decorate(logger, name, level);
      } else {
         assert(lodash.includes(extraLevels, level), 'level: ' + level);
         return decorate(null, name, level);
      }
   }
};

function logging(logger, name, loggerLevel, context, level, args, count) {
   increment(logger, name, level);
   args = [].slice.call(args); // convert arguments to array
   if (!lodash.isEmpty(context)) {
      if (lodash.isArray(context)) {
         args = context.concat(args);
      }
   }
   if (!state.logging.hasOwnProperty(level)) {
      args.splice(0, 0, 'Invalid level: ' + level);
      level = 'warn';
   }
   if (logger) {
      if (level === 'digest') {
         if (count < digestLimit/10 && count % digestLimit === 0) {
            logger.info('digest', count, ...args);
         }
      } else if (lodash.includes(levels, level)) {
         if (levels.indexOf(level) >= levels.indexOf(loggerLevel)) {
            logger[level].call(logger, ...args);
            let error = findArgsError(args);
            if (error) {
               if (error.code && error.code === 'ETIMEOUT') {
               } else {
                  logger[level].call(logger, error);
               }
            }
         }
      } else {
      }
   }
   let date = new Date().toISOString().substring(0, 16);
   let message = [date, name, ...args];
   state.logging[level].splice(0, 0, message);
   if (state.logging[level].length > state.limit) { // trim
      state.logging[level].length = state.limit;
   }
}

function findArgsError(args) {
   if (lodash.isError(args[0])) {
      return args[0];
   } else if (lodash.isError(args[1])) {
      return args[1];
   } else if (lodash.isError(args[args.length - 1])) { // TODO
      return args[args.length - 1];
   }
}

function decorate(logger, name, level) {
   let count = 0;
   let context = [];
   const those = {
      get name() {
         return name;
      },
      verbose() {
      },
      vdebug() {
      },
      debug() {
         if (level === 'debug') {
            logging(logger, name, level, context, 'debug', arguments);
         }
      },
      info() {
         if (level !== 'warn') {
            logging(logger, name, level, context, 'info', arguments);
         }
      },
      dev() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      wverbose() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      wdebug() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      winfo() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      dverbose() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      ddebug() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      dinfo() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      tdebug() {
         if (process.env.envType === 'test') {
            logging(logger, name, level, context, 'info', arguments);
         }
      },
      warn() {
         logging(logger, name, level, context, 'warn', arguments);
      },
      error() {
         logging(logger, name, level, context, 'error', arguments);
      },
      state() {
         logging(logger, name, level, context, 'state', arguments);
      },
      digest() {
         if (level === 'debug') {
            count += 1;
            logging(logger, name, level, context, 'digest', arguments, count);
         }
      },
      context() {
         context = [].slice.call(arguments);
      },
      child() {
         let childName = [name].concat([].slice.call(arguments)).join('.');
         return Loggers.create(childName, level);
      },
      increment(prop) {
         if (level === 'debug') {
            logging(logger, name, level, context, 'debug', ['increment', ...arguments]);
         }
         return increment(logger, name, prop);
      },
      peak(prop, value) {
         return peak(logger, name, prop, value);
      },
      timer(prop, time) {
         return peak(logger, name, prop, new Date().getTime() - time);
      }
   };
   return those;
}
<|endoftext|>