<commit_before>/**
 * Copyright 2015 Kitware Inc.
 *
 * 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.
 */

/**
 * Define tasks related to loading, configuring, and building plugins.
 */
module.exports = function (grunt) {
    var _ = require('underscore');
    var fs = require('fs');
    var path = require('path');
    var child_process = require('child_process'); // eslint-disable-line camelcase

    var customWebpackPlugins = require('./webpack.plugins.js');
    var paths = require('./webpack.paths.js');

    var buildAll = grunt.option('all-plugins');
    var plugins = grunt.option('plugins');

    if (_.isString(plugins) && plugins) {
        plugins = plugins.split(',');
    } else if (!buildAll) {
        return;
    }

    require('colors');

    grunt.config.merge({
        default: {
            plugin: {}
        }
    });

    /**
     * Adds configuration for plugin related multitasks:
     *
     *   * copy:plugin-<plugin name>
     *      Copies any other files that are served statically
     */
    var addMultitasks = function (plugin) {
        var pluginTarget = 'plugin-' + plugin,
            pluginPath = path.resolve(grunt.config.get('pluginDir'), plugin),
            staticPath = path.resolve(grunt.config.get('staticDir'), 'built', 'plugins', plugin),
            cfg = {
                copy: {},
                default: {},
                plugin: {}
            };

        // create the plugin's build directory under the web-root
        grunt.file.mkdir(staticPath);

        // TODO: this could be moved to Webpack using kevlened/copy-webpack-plugin
        cfg.copy[pluginTarget] = {
            files: [{
                expand: true,
                cwd: pluginPath + '/web_client',
                src: ['extra/**'],
                dest: staticPath
            }]
        };

        // the task 'plugin:<plugin name>' is a task alias to run all
        // of the main tasks defined above and possibly more if
        // the plugin itself appends tasks to this array
        cfg.plugin[plugin] = {
            tasks: [
                'copy:' + pluginTarget
            ]
        };

        grunt.config.merge(cfg);
    };

    var configurePluginForBuilding = function (dir) {
        var plugin = path.basename(dir);
        var json = path.resolve(dir, 'plugin.json');
        var yml = path.resolve(dir, 'plugin.yml');
        var config = {};
        var cfgFile = 'no config file';

        if (!fs.statSync(dir).isDirectory()) {
            grunt.fail.warn('Plugin directory not found: ' + dir);
            return;
        }

        if (fs.existsSync(json)) {
            config = grunt.file.readYAML(json);
            cfgFile = 'plugin.json';
        } else if (fs.existsSync(yml)) {
            cfgFile = 'plugin.yml';
            config = grunt.file.readYAML(yml);
        }

        grunt.log.writeln(`Configuring plugin ${plugin.magenta} (${cfgFile})`);

        var doAutoBuild = (
            !_.isObject(config.grunt) ||
            _.isUndefined(config.grunt.autobuild) ||
            _.isNull(config.grunt.autobuild) ||
            !!config.grunt.autobuild
        );

        if (doAutoBuild) {
            // merge in configuration for the main plugin build tasks
            addMultitasks(plugin);
        }

        // Find the plugin's webpack helper file; default to the identity
        // function.
        var webpackHelperFile = path.resolve(dir, config.webpack && config.webpack.configHelper || 'webpack.helper.js');
        var webpackHelper;
        if (fs.existsSync(webpackHelperFile)) {
            grunt.log.writeln(`  >> Loading webpack helper from ${webpackHelperFile}`);
            webpackHelper = require(webpackHelperFile);
        } else {
            grunt.verbose.writeln('  >> No webpack helper file found.');
            webpackHelper = function (x) {
                return x;
            };
        }

        // Configure the output file; default to 'plugin.min.js' - Girder loads
        // files named "plugin.min.js" into the Girder web client at runtime, so
        // the user can control whether this is a "Girder client extension" or
        // just a standalone web client.
        var output = config.webpack && config.webpack.output || 'plugin';

        var pluginNodeDir = path.resolve(process.cwd(), 'node_modules_' + plugin, 'node_modules');

        // Add webpack target and name resolution for this plugin if
        // web_client/main.js (or user-specified name) exists.
        var webClient = path.resolve(dir + '/web_client');
        var mains = config.webpack && config.webpack.main || {};

        if (_.isString(mains)) {
            // If main was specified as a string, use "plugin" as the target name.
            mains = {
                plugin: mains
            };
        } else if (_.isEmpty(mains)) {
            // By default, use web_client/main.js if it exists.
            var mainJs = path.join(webClient, 'main.js');

            if (fs.existsSync(mainJs)) {
                mains = {
                    plugin: mainJs
                };
            }
        };

        _.each(mains, (main, output) => {
            if (!path.isAbsolute(main)) {
                main = path.join(dir, main)
            }
            if (!fs.existsSync(main)) {
                throw `Entry point file ${main} not found.`;
            }

            var helperConfig = {
                plugin,
                output,
                main,
                pluginEntry: `plugins/${plugin}/${output}`,
                pluginDir: dir,
                nodeDir: pluginNodeDir
            };

            grunt.config.merge({
                webpack: {
                    [`${output}_${plugin}`]: {
                        entry: {
                            [helperConfig.pluginEntry]: [main]
                        },
                        plugins: [
                            new customWebpackPlugins.DllReferenceByPathPlugin({
                                context: '.',
                                manifest: path.join(paths.web_built, 'girder_lib-manifest.json')
                            })
                        ]
                    },
                    options: {
                        // Add an import alias to the global config for this plugin
                        resolve: {
                            alias: {
                                [`girder_plugins/${plugin}/node`]: pluginNodeDir,
                                [`girder_plugins/${plugin}`]: webClient
                            },
                            modules: [
                                path.resolve(process.cwd(), 'node_modules'),
                                pluginNodeDir
                            ]
                        },
                        resolveLoader: {
                            modules: [
                                path.resolve(process.cwd(), 'node_modules'),
                                pluginNodeDir
                            ]
                        }
                    }
                }
            });

            grunt.config.merge({
                default: {
                    [`webpack:${output}_${plugin}`]: {
                        dependencies: ['build'] // plugin builds must run after core build
                    }
                }
            });

            // If the plugin config has no webpack section, no defaultLoaders
            // property in the webpack section, or the defaultLoaders is
            // explicitly set to anything besides false, then augment the
            // webpack loader configurations with the plugin source directory.
            if (!config.webpack || config.webpack.defaultLoaders === undefined || config.webpack.defaultLoaders !== false) {
                var numLoaders = grunt.config.get('webpack.options.module.loaders').length;
                for (var i = 0; i < numLoaders; i++) {
                    var selector = 'webpack.options.module.loaders.' + i + '.include';
                    var loaders = grunt.config.get(selector);
                    var pluginPath = path.resolve(dir);
                    var realPath = fs.realpathSync(dir);
                    var loaderIncludes = [pluginPath];

                    // We add the plugin path to the include list for the loaders, and also
                    // add the realpath (i.e. following symlinks) to workaround an issue where
                    // webpack doesn't resolve symlinked include directories correctly.
                    if (realPath !== pluginPath) {
                        loaderIncludes.push(realPath);
                    }

                    grunt.config.set(selector, loaders.concat(loaderIncludes));
                }
            }

            var newConfig = webpackHelper(grunt.config.get('webpack.options'), helperConfig);
            grunt.config.set('webpack.options', newConfig);
        });

        grunt.registerTask('npm-install', 'Install plugin NPM dependencies', function (plugin, localNodeModules) {
            // Start building the list of arguments to the NPM executable.
            //
            // We want color output embedded in the Grunt output.
            var args = ['--color=always'];

            // If the plugin requested to install the dependencies in its own
            // dedicated directory, set the prefix option.
            if (localNodeModules === 'true') {
                args = args.concat(['--prefix', path.resolve('node_modules_' + plugin)]);
            }

            // Get the list of the packages to install and append them to the
            // args object.
            var modules = Array.prototype.slice.call(arguments, 2);
            args = args.concat(['install'], modules);

            // Launch the child process.
            var child = child_process.spawnSync('npm', args, {
                stdio: 'inherit'
            });

            return child.status === 0;
        });

        function addDependencies(deps, localNodeModules) {
            // install any additional npm packages during init
            var npm = (
                _(deps || {})
                    .map(function (version, dep) {
                        return [
                            dep.replace(':', '\\:'),
                            version.replace(':', '\\:')
                        ].join('@');
                    })
            );

            if (npm.length) {
                grunt.config.set('default.npm-install:' + plugin + ':' + !!localNodeModules + ':' + grunt.config.escape(npm.join(':')), {});
            }
        }

        if (config.npm) {
            var modules = {};

            // If the config contains a "file" section, load NPM dependencies
            // from it.
            if (config.npm.file) {
                var npmFile = require(path.resolve(dir, config.npm.file));
                var fields = config.npm.fields || ['devDependencies', 'dependencies', 'optionalDependencies'];

                grunt.log.writeln('  >> Loading NPM dependencies from: ' + config.npm.file);
                grunt.log.writeln('  >> Using fields: ' + fields.join(', '));

                fields.forEach(function (field) {
                    _.each(npmFile[field] || {}, function (version, dep) {
                        modules[dep] = version;
                    });
                });
            }

            // Additionally add any extra dependencies found in the
            // "dependencies" property.
            if (config.npm.dependencies) {
                if (config.npm.file) {
                    grunt.log.writeln('  >> Loading additional NPM dependencies');
                } else {
                    grunt.log.writeln('  >> Loading NPM dependencies');
                }

                _.each(config.npm.dependencies, function (version, dep) {
                    modules[dep] = version;
                });
            }

            if (config.npm.localNodeModules) {
                grunt.log.writeln(`  >> Installing NPM dependencies to dedicated directory: node_modules_${plugin}`);
            } else {
                grunt.verbose.writeln('  >> Installing NPM dependencies to Girder node_modules directory');
            }

            // Invoke the npm installation task.
            addDependencies(modules, config.npm.localNodeModules);
        }

        if (config.grunt) {
            grunt.log.writeln((
                'Configuring plugin: ' + plugin + ' (custom Gruntfile)'
            ).bold);

            addDependencies(config.grunt.dependencies);

            // load the plugin's gruntfile
            try {
                require(
                    path.resolve(dir, config.grunt.file || 'Gruntfile.js')
                )(grunt);
            } catch (e) {
                // the error can be safely ignored when doing `grunt init`
                // otherwise a default task will most likely fail later on
                // write out a warning to help the developers debug errors
                grunt.log.writeln((
                    'Failed to load ' + plugin + '/' + (config.grunt.file || 'Gruntfile.js') + ':'
                ).yellow);
                grunt.log.writeln('>>> ' + e.toString().split('\n').join('\n>>> ').yellow);
            }

            // add default targets
            _(config.grunt.defaultTargets || []).each(function (target) {
                grunt.config.set('default.' + target, {});
            });
        }
    };

    if (buildAll) {
        // Glob for plugins and configure each one to be built
        grunt.file.expand(grunt.config.get('pluginDir') + '/*').forEach(function (dir) {
            configurePluginForBuilding(dir);
        });
    } else {
        // Build only the plugins that were requested via --plugins
        plugins.forEach(function (name) {
            configurePluginForBuilding(path.resolve(grunt.config.get('pluginDir'), name));
        });
    }

    /**
     * Register a "meta" task that will configure and run other tasks
     * to build a plugin. Keys in the config for this task should be the
     * directory of the plugin within the base plugins path.
     */
    grunt.registerMultiTask('plugin', 'Build and configure plugins', function () {
        var plugin = this.target,
            tasks = 'plugin.' + plugin + '.tasks';

        this.requiresConfig('pluginDir', tasks);

        // queue the build tasks
        grunt.config.get(tasks).forEach(function (task) {
            grunt.task.run(task);
        });
    });
};
<commit_msg>Fix static analysis problems<commit_after>/**
 * Copyright 2015 Kitware Inc.
 *
 * 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.
 */

/**
 * Define tasks related to loading, configuring, and building plugins.
 */
module.exports = function (grunt) {
    var _ = require('underscore');
    var fs = require('fs');
    var path = require('path');
    var child_process = require('child_process'); // eslint-disable-line camelcase

    var customWebpackPlugins = require('./webpack.plugins.js');
    var paths = require('./webpack.paths.js');

    var buildAll = grunt.option('all-plugins');
    var plugins = grunt.option('plugins');

    if (_.isString(plugins) && plugins) {
        plugins = plugins.split(',');
    } else if (!buildAll) {
        return;
    }

    require('colors');

    grunt.config.merge({
        default: {
            plugin: {}
        }
    });

    /**
     * Adds configuration for plugin related multitasks:
     *
     *   * copy:plugin-<plugin name>
     *      Copies any other files that are served statically
     */
    var addMultitasks = function (plugin) {
        var pluginTarget = 'plugin-' + plugin,
            pluginPath = path.resolve(grunt.config.get('pluginDir'), plugin),
            staticPath = path.resolve(grunt.config.get('staticDir'), 'built', 'plugins', plugin),
            cfg = {
                copy: {},
                default: {},
                plugin: {}
            };

        // create the plugin's build directory under the web-root
        grunt.file.mkdir(staticPath);

        // TODO: this could be moved to Webpack using kevlened/copy-webpack-plugin
        cfg.copy[pluginTarget] = {
            files: [{
                expand: true,
                cwd: pluginPath + '/web_client',
                src: ['extra/**'],
                dest: staticPath
            }]
        };

        // the task 'plugin:<plugin name>' is a task alias to run all
        // of the main tasks defined above and possibly more if
        // the plugin itself appends tasks to this array
        cfg.plugin[plugin] = {
            tasks: [
                'copy:' + pluginTarget
            ]
        };

        grunt.config.merge(cfg);
    };

    var configurePluginForBuilding = function (dir) {
        var plugin = path.basename(dir);
        var json = path.resolve(dir, 'plugin.json');
        var yml = path.resolve(dir, 'plugin.yml');
        var config = {};
        var cfgFile = 'no config file';

        if (!fs.statSync(dir).isDirectory()) {
            grunt.fail.warn('Plugin directory not found: ' + dir);
            return;
        }

        if (fs.existsSync(json)) {
            config = grunt.file.readYAML(json);
            cfgFile = 'plugin.json';
        } else if (fs.existsSync(yml)) {
            cfgFile = 'plugin.yml';
            config = grunt.file.readYAML(yml);
        }

        grunt.log.writeln(`Configuring plugin ${plugin.magenta} (${cfgFile})`);

        var doAutoBuild = (
            !_.isObject(config.grunt) ||
            _.isUndefined(config.grunt.autobuild) ||
            _.isNull(config.grunt.autobuild) ||
            !!config.grunt.autobuild
        );

        if (doAutoBuild) {
            // merge in configuration for the main plugin build tasks
            addMultitasks(plugin);
        }

        // Find the plugin's webpack helper file; default to the identity
        // function.
        var webpackHelperFile = path.resolve(dir, config.webpack && config.webpack.configHelper || 'webpack.helper.js');
        var webpackHelper;
        if (fs.existsSync(webpackHelperFile)) {
            grunt.log.writeln(`  >> Loading webpack helper from ${webpackHelperFile}`);
            webpackHelper = require(webpackHelperFile);
        } else {
            grunt.verbose.writeln('  >> No webpack helper file found.');
            webpackHelper = function (x) {
                return x;
            };
        }

        // Configure the output file; default to 'plugin.min.js' - Girder loads
        // files named "plugin.min.js" into the Girder web client at runtime, so
        // the user can control whether this is a "Girder client extension" or
        // just a standalone web client.
        var output = config.webpack && config.webpack.output || 'plugin';

        var pluginNodeDir = path.resolve(process.cwd(), 'node_modules_' + plugin, 'node_modules');

        // Add webpack target and name resolution for this plugin if
        // web_client/main.js (or user-specified name) exists.
        var webClient = path.resolve(dir + '/web_client');
        var mains = config.webpack && config.webpack.main || {};

        if (_.isString(mains)) {
            // If main was specified as a string, convert to an object
            mains = {
                [output]: mains
            };
        } else if (_.isEmpty(mains)) {
            // By default, use web_client/main.js if it exists.
            var mainJs = path.join(webClient, 'main.js');

            if (fs.existsSync(mainJs)) {
                mains = {
                    [output]: mainJs
                };
            }
        }

        _.each(mains, (main, output) => {
            if (!path.isAbsolute(main)) {
                main = path.join(dir, main);
            }
            if (!fs.existsSync(main)) {
                throw new Error(`Entry point file ${main} not found.`);
            }

            var helperConfig = {
                plugin,
                output,
                main,
                pluginEntry: `plugins/${plugin}/${output}`,
                pluginDir: dir,
                nodeDir: pluginNodeDir
            };

            grunt.config.merge({
                webpack: {
                    [`${output}_${plugin}`]: {
                        entry: {
                            [helperConfig.pluginEntry]: [main]
                        },
                        plugins: [
                            new customWebpackPlugins.DllReferenceByPathPlugin({
                                context: '.',
                                manifest: path.join(paths.web_built, 'girder_lib-manifest.json')
                            })
                        ]
                    },
                    options: {
                        // Add an import alias to the global config for this plugin
                        resolve: {
                            alias: {
                                [`girder_plugins/${plugin}/node`]: pluginNodeDir,
                                [`girder_plugins/${plugin}`]: webClient
                            },
                            modules: [
                                path.resolve(process.cwd(), 'node_modules'),
                                pluginNodeDir
                            ]
                        },
                        resolveLoader: {
                            modules: [
                                path.resolve(process.cwd(), 'node_modules'),
                                pluginNodeDir
                            ]
                        }
                    }
                }
            });

            grunt.config.merge({
                default: {
                    [`webpack:${output}_${plugin}`]: {
                        dependencies: ['build'] // plugin builds must run after core build
                    }
                }
            });

            // If the plugin config has no webpack section, no defaultLoaders
            // property in the webpack section, or the defaultLoaders is
            // explicitly set to anything besides false, then augment the
            // webpack loader configurations with the plugin source directory.
            if (!config.webpack || config.webpack.defaultLoaders === undefined || config.webpack.defaultLoaders !== false) {
                var numLoaders = grunt.config.get('webpack.options.module.loaders').length;
                for (var i = 0; i < numLoaders; i++) {
                    var selector = 'webpack.options.module.loaders.' + i + '.include';
                    var loaders = grunt.config.get(selector);
                    var pluginPath = path.resolve(dir);
                    var realPath = fs.realpathSync(dir);
                    var loaderIncludes = [pluginPath];

                    // We add the plugin path to the include list for the loaders, and also
                    // add the realpath (i.e. following symlinks) to workaround an issue where
                    // webpack doesn't resolve symlinked include directories correctly.
                    if (realPath !== pluginPath) {
                        loaderIncludes.push(realPath);
                    }

                    grunt.config.set(selector, loaders.concat(loaderIncludes));
                }
            }

            var newConfig = webpackHelper(grunt.config.get('webpack.options'), helperConfig);
            grunt.config.set('webpack.options', newConfig);
        });

        grunt.registerTask('npm-install', 'Install plugin NPM dependencies', function (plugin, localNodeModules) {
            // Start building the list of arguments to the NPM executable.
            //
            // We want color output embedded in the Grunt output.
            var args = ['--color=always'];

            // If the plugin requested to install the dependencies in its own
            // dedicated directory, set the prefix option.
            if (localNodeModules === 'true') {
                args = args.concat(['--prefix', path.resolve('node_modules_' + plugin)]);
            }

            // Get the list of the packages to install and append them to the
            // args object.
            var modules = Array.prototype.slice.call(arguments, 2);
            args = args.concat(['install'], modules);

            // Launch the child process.
            var child = child_process.spawnSync('npm', args, {
                stdio: 'inherit'
            });

            return child.status === 0;
        });

        function addDependencies(deps, localNodeModules) {
            // install any additional npm packages during init
            var npm = (
                _(deps || {})
                    .map(function (version, dep) {
                        return [
                            dep.replace(':', '\\:'),
                            version.replace(':', '\\:')
                        ].join('@');
                    })
            );

            if (npm.length) {
                grunt.config.set('default.npm-install:' + plugin + ':' + !!localNodeModules + ':' + grunt.config.escape(npm.join(':')), {});
            }
        }

        if (config.npm) {
            var modules = {};

            // If the config contains a "file" section, load NPM dependencies
            // from it.
            if (config.npm.file) {
                var npmFile = require(path.resolve(dir, config.npm.file));
                var fields = config.npm.fields || ['devDependencies', 'dependencies', 'optionalDependencies'];

                grunt.log.writeln('  >> Loading NPM dependencies from: ' + config.npm.file);
                grunt.log.writeln('  >> Using fields: ' + fields.join(', '));

                fields.forEach(function (field) {
                    _.each(npmFile[field] || {}, function (version, dep) {
                        modules[dep] = version;
                    });
                });
            }

            // Additionally add any extra dependencies found in the
            // "dependencies" property.
            if (config.npm.dependencies) {
                if (config.npm.file) {
                    grunt.log.writeln('  >> Loading additional NPM dependencies');
                } else {
                    grunt.log.writeln('  >> Loading NPM dependencies');
                }

                _.each(config.npm.dependencies, function (version, dep) {
                    modules[dep] = version;
                });
            }

            if (config.npm.localNodeModules) {
                grunt.log.writeln(`  >> Installing NPM dependencies to dedicated directory: node_modules_${plugin}`);
            } else {
                grunt.verbose.writeln('  >> Installing NPM dependencies to Girder node_modules directory');
            }

            // Invoke the npm installation task.
            addDependencies(modules, config.npm.localNodeModules);
        }

        if (config.grunt) {
            grunt.log.writeln((
                'Configuring plugin: ' + plugin + ' (custom Gruntfile)'
            ).bold);

            addDependencies(config.grunt.dependencies);

            // load the plugin's gruntfile
            try {
                require(
                    path.resolve(dir, config.grunt.file || 'Gruntfile.js')
                )(grunt);
            } catch (e) {
                // the error can be safely ignored when doing `grunt init`
                // otherwise a default task will most likely fail later on
                // write out a warning to help the developers debug errors
                grunt.log.writeln((
                    'Failed to load ' + plugin + '/' + (config.grunt.file || 'Gruntfile.js') + ':'
                ).yellow);
                grunt.log.writeln('>>> ' + e.toString().split('\n').join('\n>>> ').yellow);
            }

            // add default targets
            _(config.grunt.defaultTargets || []).each(function (target) {
                grunt.config.set('default.' + target, {});
            });
        }
    };

    if (buildAll) {
        // Glob for plugins and configure each one to be built
        grunt.file.expand(grunt.config.get('pluginDir') + '/*').forEach(function (dir) {
            configurePluginForBuilding(dir);
        });
    } else {
        // Build only the plugins that were requested via --plugins
        plugins.forEach(function (name) {
            configurePluginForBuilding(path.resolve(grunt.config.get('pluginDir'), name));
        });
    }

    /**
     * Register a "meta" task that will configure and run other tasks
     * to build a plugin. Keys in the config for this task should be the
     * directory of the plugin within the base plugins path.
     */
    grunt.registerMultiTask('plugin', 'Build and configure plugins', function () {
        var plugin = this.target,
            tasks = 'plugin.' + plugin + '.tasks';

        this.requiresConfig('pluginDir', tasks);

        // queue the build tasks
        grunt.config.get(tasks).forEach(function (task) {
            grunt.task.run(task);
        });
    });
};
<|endoftext|>


<commit_before>(function(){
var ViewWithPopover = extendWithPopover( Backbone.Factlink.PlainView );

window.FactView = ViewWithPopover.extend({
  tagName: "div",

  className: "fact-block",

  events: {
    "click .hide-from-channel": "removeFactFromChannel",
    "click li.delete": "destroyFact",

    "click .tab-control .supporting"     : "tabClick",
    "click .tab-control .weakening"      : "tabClick",
    "click .tab-control .add-to-channel" : "tabClick",

    "click a.more": "showCompleteDisplaystring",
    "click a.less": "hideCompleteDisplaystring"
  },

  template: "facts/_fact",

  partials: {
    fact_bubble: "facts/_fact_bubble",
    fact_wheel: "facts/_fact_wheel",
    interacting_users: "facts/_interacting_users"
  },

  interactingUserViews: [],

  popover: [
    {
      selector: ".top-right-arrow",
      popoverSelector: "ul.top-right"
    }
  ],

  initialize: function(opts) {
    this._currentTab = undefined;
    this.interactingUserViews = [];

    this.model.bind('destroy', this.close, this);
    this.model.bind('change', this.render, this);

    this.initAddToChannel();
    this.initFactRelationsViews();

    this.wheel = new Wheel(this.model.getFactWheel());
  },

  onRender: function() {
    this.renderAddToChannel();
    this.initFactRelationsViews();

    this.$('.authority').tooltip();

    if ( this.factWheelView ) {
      this.wheel.set(this.model.getFactWheel());
      this.$('.wheel').replaceWith(this.factWheelView.reRender().el);
    } else {
      this.factWheelView = new InteractiveWheelView({
        model: this.wheel,
        fact: this.model,
        el: this.$('.wheel')
      }).render();
    }
  },

  remove: function() {
    this.$el.fadeOut('fast', function() {
      $(this).remove();
    });

    _.each(this.interactingUserViews, function(view){
      view.close();
    },this);

    if(this.addToChannelView){
      this.addToChannelView.close();
    }
    // Hides the popup (if necessary)
    if ( parent.remote ) {
      parent.remote.hide();
      parent.remote.stopHighlightingFactlink(this.model.id);
    }
  },

  removeFactFromChannel: function(e) {
    e.preventDefault();

    var self = this;

    this.model.removeFromChannel(
      currentChannel, {
      error: function() {
        alert("Error while hiding Factlink from Channel" );
      },
      success: function() {
        self.model.collection.remove(self.model);
        mp_track("Channel: Silence Factlink from Channel", {
          factlink_id: self.model.id,
          channel_id: currentChannel.id
        });
      }
    });
  },

  destroyFact: function(e) {
    e.preventDefault();

    this.model.destroy({
      error: function() {
        alert("Error while removing the Factlink" );
      },
      success: function() {
        mp_track("Factlink: Destroy");
      }
    });
  },

  initAddToChannel: function() {
  },

  renderAddToChannel: function() {
    var self = this;
    var add_el = '.tab-content .add-to-channel .dropdown-container .wrapper .add-to-channel-container';
    if ( this.$(add_el).length > 0 && typeof currentUser !== "undefined" ) {
      var addToChannelView = new AutoCompletedAddToChannelView({
        el: this.$(add_el)[0]
      });
      _.each(this.model.getOwnContainingChannels(),function(ch){
        //hacky hacky bang bang
        if (ch.get('type') === 'channel'){
          addToChannelView.collection.add(ch);
        }
      });
      addToChannelView.vent.bindTo("addChannel", function(channel){
        self.model.addToChannel(channel,{});
      });
      addToChannelView.vent.bindTo("removeChannel", function(channel){
        self.model.removeFromChannel(channel,{});
        if (window.currentChannel && currentChannel.get('id') === channel.get('id')){
          self.model.collection.remove(self.model);
        }
      });
      addToChannelView.render();
      this.addToChannelView = addToChannelView;
    }
  },

  initFactRelationsViews: function() {
    this.supportingFactRelations = new SupportingFactRelations([], { fact: this.model } );
    this.weakeningFactRelations = new WeakeningFactRelations([], { fact: this.model } );
  },

  switchToRelationDropdown: function(type){
    mp_track("Factlink: Open tab", {factlink_id: this.model.id,type: type});

    if (type === "supporting") {
      this.hideFactRelations('weakening');
      this.showFactRelations('supporting');
    } else {
      this.hideFactRelations('supporting');
      this.showFactRelations('weakening');
    }
  },

  showFactRelations: function(type){
    if (! (type+"FactRelationsView" in this )){
      this[type+"FactRelationsView"] = new FactRelationsView({
        collection: this[type+"FactRelations"]
      });

      this.$('.'+type+' .dropdown-container')
        .append( this[type+'FactRelationsView'].render().el );
    }

    this.$('.'+type+' .dropdown-container').show();
    this[type+"FactRelationsView"].fetch();
  },

  hideFactRelations: function(type){
    this.$('.'+type+' .dropdown-container').hide();
  },

  tabClick: function(e) {

    e.preventDefault();
    e.stopPropagation();

    var $target = $(e.target).closest('li');

    // Need a way to identify the clicked tab. Using the li class sucks monkeyballs.
    tab = $target.attr('class').split(' ')[0];

    // Remove .active
    var $tabButtons = this.$el.find('.tab-control li');
    $tabButtons.removeClass("active");

    if (tab !== this._currentTab) {
      // Open the clicked tab
      this._currentTab = tab;
      this.hideTabs();

      $target.addClass('active');
      // Show the tab
      this.$('.tab-content > .' + tab).show();
      // Keep showing the tabs (in the li)
      this.$('.tab-control > li').addClass('tabOpened');
      this.handleTabActions(tab);

    } else {
      // Same tab was clicked - hide it!
      this.hideTabs();
      this._currentTab = undefined;
    }
  },

  hideTabs: function() {
    this.$('.tab-content > div').hide();
    this.$('.tab-control > li').removeClass('tabOpened');
  },

  handleTabActions: function(tab) {
    switch (tab) {
    case "supporting":
    case "weakening":
      this.switchToRelationDropdown(tab);
      return true;

    case "channels":
      return true;

    default:
      return true;
    }
  },

  highlight: function() {
    var self = this;
    self.$el.animate({"background-color": "#ffffe1"}, {duration: 2000, complete: function() {
      $(this).animate({"background-color": "#ffffff"}, 2000);
    }});
  },

  showCompleteDisplaystring: function (e) {
    this.$('.normal').hide().siblings('.full').show();
  },

  hideCompleteDisplaystring: function (e) {
    this.$('.full').hide().siblings('.normal').show();
  }
});
})();
<commit_msg>only render add to channels when needed<commit_after>(function(){
var ViewWithPopover = extendWithPopover( Backbone.Factlink.PlainView );

window.FactView = ViewWithPopover.extend({
  tagName: "div",

  className: "fact-block",

  events: {
    "click .hide-from-channel": "removeFactFromChannel",
    "click li.delete": "destroyFact",

    "click .tab-control .supporting"     : "tabClick",
    "click .tab-control .weakening"      : "tabClick",
    "click .tab-control .add-to-channel" : "tabClick",

    "click a.more": "showCompleteDisplaystring",
    "click a.less": "hideCompleteDisplaystring"
  },

  template: "facts/_fact",

  partials: {
    fact_bubble: "facts/_fact_bubble",
    fact_wheel: "facts/_fact_wheel",
    interacting_users: "facts/_interacting_users"
  },

  interactingUserViews: [],

  popover: [
    {
      selector: ".top-right-arrow",
      popoverSelector: "ul.top-right"
    }
  ],

  initialize: function(opts) {
    this._currentTab = undefined;
    this.interactingUserViews = [];

    this.model.bind('destroy', this.close, this);
    this.model.bind('change', this.render, this);

    this.initFactRelationsViews();

    this.wheel = new Wheel(this.model.getFactWheel());
  },

  onRender: function() {

    this.$('.authority').tooltip();

    if ( this.factWheelView ) {
      this.wheel.set(this.model.getFactWheel());
      this.$('.wheel').replaceWith(this.factWheelView.reRender().el);
    } else {
      this.factWheelView = new InteractiveWheelView({
        model: this.wheel,
        fact: this.model,
        el: this.$('.wheel')
      }).render();
    }
  },

  remove: function() {
    this.$el.fadeOut('fast', function() {
      $(this).remove();
    });

    _.each(this.interactingUserViews, function(view){
      view.close();
    },this);

    if(this.addToChannelView){
      this.addToChannelView.close();
    }
    // Hides the popup (if necessary)
    if ( parent.remote ) {
      parent.remote.hide();
      parent.remote.stopHighlightingFactlink(this.model.id);
    }
  },

  removeFactFromChannel: function(e) {
    e.preventDefault();

    var self = this;

    this.model.removeFromChannel(
      currentChannel, {
      error: function() {
        alert("Error while hiding Factlink from Channel" );
      },
      success: function() {
        self.model.collection.remove(self.model);
        mp_track("Channel: Silence Factlink from Channel", {
          factlink_id: self.model.id,
          channel_id: currentChannel.id
        });
      }
    });
  },

  destroyFact: function(e) {
    e.preventDefault();

    this.model.destroy({
      error: function() {
        alert("Error while removing the Factlink" );
      },
      success: function() {
        mp_track("Factlink: Destroy");
      }
    });
  },

  renderAddToChannel: function() {
    var self = this;
    var add_el = '.tab-content .add-to-channel .dropdown-container .wrapper .add-to-channel-container';

    if ( this.$(add_el).length > 0 && typeof currentUser !== "undefined" &&
        ! ('addToChannelView' in this)) {
      var addToChannelView = new AutoCompletedAddToChannelView({
        el: this.$(add_el)[0]
      });
      _.each(this.model.getOwnContainingChannels(),function(ch){
        //hacky hacky bang bang
        if (ch.get('type') === 'channel'){
          addToChannelView.collection.add(ch);
        }
      });
      addToChannelView.vent.bindTo("addChannel", function(channel){
        self.model.addToChannel(channel,{});
      });
      addToChannelView.vent.bindTo("removeChannel", function(channel){
        self.model.removeFromChannel(channel,{});
        if (window.currentChannel && currentChannel.get('id') === channel.get('id')){
          self.model.collection.remove(self.model);
        }
      });
      addToChannelView.render();
      this.addToChannelView = addToChannelView;
    }
  },

  initFactRelationsViews: function() {
    this.supportingFactRelations = new SupportingFactRelations([], { fact: this.model } );
    this.weakeningFactRelations = new WeakeningFactRelations([], { fact: this.model } );
  },

  switchToRelationDropdown: function(type){
    mp_track("Factlink: Open tab", {factlink_id: this.model.id,type: type});

    if (type === "supporting") {
      this.hideFactRelations('weakening');
      this.showFactRelations('supporting');
    } else {
      this.hideFactRelations('supporting');
      this.showFactRelations('weakening');
    }
  },

  showFactRelations: function(type){
    if (! (type+"FactRelationsView" in this )){
      this[type+"FactRelationsView"] = new FactRelationsView({
        collection: this[type+"FactRelations"]
      });

      this.$('.'+type+' .dropdown-container')
        .append( this[type+'FactRelationsView'].render().el );
    }

    this.$('.'+type+' .dropdown-container').show();
    this[type+"FactRelationsView"].fetch();
  },

  hideFactRelations: function(type){
    this.$('.'+type+' .dropdown-container').hide();
  },

  tabClick: function(e) {

    e.preventDefault();
    e.stopPropagation();

    var $target = $(e.target).closest('li');

    // Need a way to identify the clicked tab. Using the li class sucks monkeyballs.
    tab = $target.attr('class').split(' ')[0];

    // Remove .active
    var $tabButtons = this.$el.find('.tab-control li');
    $tabButtons.removeClass("active");

    if (tab !== this._currentTab) {
      // Open the clicked tab
      this._currentTab = tab;
      this.hideTabs();

      $target.addClass('active');
      // Show the tab
      this.$('.tab-content > .' + tab).show();
      // Keep showing the tabs (in the li)
      this.$('.tab-control > li').addClass('tabOpened');
      this.handleTabActions(tab);

    } else {
      // Same tab was clicked - hide it!
      this.hideTabs();
      this._currentTab = undefined;
    }
  },

  hideTabs: function() {
    this.$('.tab-content > div').hide();
    this.$('.tab-control > li').removeClass('tabOpened');
  },

  handleTabActions: function(tab) {
    switch (tab) {
    case "supporting":
    case "weakening":
      this.switchToRelationDropdown(tab);
      return true;

    case "add-to-channel":
      this.renderAddToChannel();
      return true;

    default:
      return true;
    }
  },

  highlight: function() {
    var self = this;
    self.$el.animate({"background-color": "#ffffe1"}, {duration: 2000, complete: function() {
      $(this).animate({"background-color": "#ffffff"}, 2000);
    }});
  },

  showCompleteDisplaystring: function (e) {
    this.$('.normal').hide().siblings('.full').show();
  },

  hideCompleteDisplaystring: function (e) {
    this.$('.full').hide().siblings('.normal').show();
  }
});
})();
<|endoftext|>


<commit_before>/**
 * Module dependencies.
 */

var path = require('path');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var o = require('outline');

/**
 * Module constants.
 */

var packagePathCache = {};

/**
 * `Metronome` constructor.
 */

function Metronome(settings) {
  EventEmitter.call(this);
  this.settings = settings || {};
  this._packages = {};
  this._queue = [];
  this._busy = false;
  this._services = {};
}

util.inherits(Metronome, EventEmitter);

/**
 * `Metronome` prototype.
 */

o.extend(Metronome.prototype, {

  /**
   * Register module with static config.
   */

  register: function register(config, base) {
    this._enqueue(function (callback) {
      this._register(config, base, function (err) {
        if (err) return _this.emit('err', err);
        callback();
      });
    });
  },

  /**
   * Register modules from config file.
   */

  config: function config(configFile) {
    var _this = this;
    _this._enqueue(function (callback) {
      require(configFile).forEach(function (config) {
        _this._register(config, path.dirname(configFile), function (err) {
          if (err) return _this.emit('err', err);
          callback();
        });
      });
      return this;
    });
  },

  /**
   * Register modules by scanning a directory containing config files.
   */

  scan: function scan(directory) {
    var _this = this;
    _this._enqueue(function (callback) {

      // Make directory absolute.
      if (directory[0] === '.') {
        directory = path.join(_this.get('root directory') || process.cwd(),
                             directory);
      }

      // List files.
      fs.readdir(directory, function (err, names) {
        if (err) return _this.emit('error', err);

        // Load each in order.
        function iterator(name, next) {
          if (name[0] === '.' && _this.get('ignore hidden files') !== false) {
            return next();
          }
          var absolutePath = path.join(directory, name);
          try {
            var required = require(absolutePath);
          }
          catch (err) {
            return _this.emit('error', err);
          }

          // Register it.
          _this._register(required, directory, function (err) {
            if (err) return _this.emit('error', err);
            next();
          });
        }

        function done(err) {
          if (err) return _this.emit('error', err);
          callback();
        }

        o.each(names, iterator, done);

      });
    });
    return _this;
  },

  /**
   * Start app.
   */

  bootstrap: function start() {
    var _this = this;
    _this._enqueue(function (callback) {

      // Prepare process.
      var remaining = Object.keys(_this._packages);
      var done = [];
      var reverse = {};
      o.each(_this._packages, function (data, name) {
        o.each(data.provides, function (service) {
          reverse[service] = name;
        });
      });

      // Check for missing dependencies, and check whether we can satisfy
      // weak dependencies.
      var consumes = {};
      try {
        o.each(_this._packages, function (data, name) {
          var missingDependencies = [];
          var packageConsumes = [];
          o.each(data.consumes, function (service) {
            if (!reverse[service]) return missingDependencies.push(service);
            packageConsumes.push(service);
          });
          if (missingDependencies.length) {
            throw Error([
              'Can\'t bootstrap package "', name,
              '" because of missing dependencies: "',
              missingDependencies.join('", "'), '".'
            ].join(''));
          }
          o.each(data.optionallyConsumes, function (service) {
            if (reverse[service]) packageConsumes.push(service);
          });
          consumes[name] = packageConsumes;
        });
      }
      catch (err) {
        return _this.emit('error', err);
      }

      // Helper checking whether we may process loading some package now.
      var canLoad = function canLoad(name) {
        var packageConsumes = consumes[name];
        var missing = o.filter(packageConsumes, function (service) {
          if (!_this._services[service]) return true;
        });
        return !missing.length;
      }

      // Helper bootstraping a specific package.
      var setup = function setup(name, done) {
        _this.emit('setup', name);
        var packageData = _this._packages[name];
        var config = packageData.config;
        packageData.setup(config, _this._services, function (err, services) {
          if (err) return done(err);
          o.each(packageData.provides || {}, function (service) {
            _this._services[service] = services[service] || {};
          });
          done();
        });
      }

      // Start a big dirty infinite loop to start with the best order.
      var iterate = function iterate() {
        var newRemaining = [];
        o.each(remaining, function (remainingItem, next) {
          if (!canLoad(remainingItem)) {
            newRemaining.push(remainingItem);
            next();
          }
          else {
            setup(remainingItem, function (err) {
              next(err);
            });
          }
        }, function (err) {
          if (err) return _this.emit('error', err);

          // Maybe we're done
          if (!newRemaining.length) {
            _this.emit('bootstraped');
            return callback();
          }

          // Dit we reach a deadlock?
          if (newRemaining.length === remaining.length) {
            return _this.emit('error', Error([
              'Can\'t bootstrap because of circular dependency in packages: "',
              remaining.join('", "'), '".'
            ].join('')));
          }

          // Let's go for another round!
          remaining = newRemaining;
          process.nextTick(iterate);
        })
      };

      // Start the thing.
      iterate();

    });
    return _this;
  },

  /**
   * Get settings.
   */

  get: function get(key) {
    return this.settings[key];
  },

  /**
   * Set settings.
   */

  set: function set(key, value) {
    this.settings[key] = value;
    return this
  },

  /**
   * Get service.
   */

  service: function service(name) {
    return this._services[name];
  },

  /**
   * Enqueue arbitraity function.
   */

  then: function then(fn) {
    var _this = this;
    _this._enqueue(function (callback) {
      if (fn.length) {
        fn(function (err) {
          if (err) return _this.emit('error', err);
          callback();
        });
      }
      else {
        try {
          fn();
        }
        catch (err) {
          return _this.emit('error', err);
        }
        callback();
      }
    });
    return _this;
  },

  /**
   * Register method.
   */

  _register: function _register(config, root, callback) {
    var _this = this;
    config = typeof config === 'string' ? { packagePath: config } : config;
    resolvePackage(config.packagePath, root, function (packagePath) {
      if (!packagePath) {
        return callback(Error([
          'Can\'t locate package "', config.packagePath, '".'
        ].join('')));
      }
      var manifest = require(path.join(packagePath, 'package.json'));
      var name = manifest.name || path.basename(packagePath);
      var indexFile = manifest.main || 'index.js';
      var setup = require(path.join(packagePath, indexFile));
      _this._packages[name] = {
        path: packagePath,
        setup: setup,
        provides: manifest.provides || [],
        consumes: manifest.consumes || [],
        optionallyConsumes: manifest.optionallyConsumes || [],
        config: config
      }
      callback();
    });
  },

  /**
   * Processing queue.
   */

  _enqueue: function _enqueue(fn) {
    var _this = this;

    var callNext = function (err) {
      if (!_this._queue.length) {
        _this._busy = false;
      }
      else {
        var next = _this._queue.shift();
        process.nextTick(function () {
          next(callNext);
        });
      }
    }

    if (!_this._busy) {
      _this._busy = true;
      fn(callNext);
    }
    else {
      _this._queue.push(fn);
    }

    return _this;
  }

});

/**
 * Factory.
 */

module.exports = function factory(options) {
  return new Metronome(options);
}

/**
 * Expose `Metronome`.
 */

module.exports.Metronome = Metronome;

/**
 * Expose version.
 */

module.exports.__defineGetter__('version', function () {
  return require(path.join(__dirname, 'package.json')).version;
});

/**
 * Node style, resolve package.
 */

function resolvePackage(packagePath, base, callback) {
  var tryPaths = [];
  if (packagePath[0] === '/') {
    tryPaths.push(packagePath);
  } else if (packagePath[0] === '.') {
    tryPaths.push(path.join(base, packagePath));
  } else {
    var tmpBase = base;
    while (true) {
      tryPaths.push(path.join(tmpBase, 'node_modules', packagePath));
      if (tmpBase === (tmpBase = path.dirname(tmpBase))) break;
    }
  }

  o.detect(tryPaths, isPackagePath, function (resolvedPath) {
    return callback(resolvedPath);
  });
}

function isPackagePath(packagePath, callback) {
  fs.exists(path.join(packagePath, 'package.json'), callback);
}<commit_msg>Improved support for modules not exposing anything.<commit_after>/**
 * Module dependencies.
 */

var path = require('path');
var fs = require('fs');
var EventEmitter = require('events').EventEmitter;
var util = require('util');
var o = require('outline');

/**
 * Module constants.
 */

var packagePathCache = {};

/**
 * `Metronome` constructor.
 */

function Metronome(settings) {
  EventEmitter.call(this);
  this.settings = settings || {};
  this._packages = {};
  this._queue = [];
  this._busy = false;
  this._services = {};
}

util.inherits(Metronome, EventEmitter);

/**
 * `Metronome` prototype.
 */

o.extend(Metronome.prototype, {

  /**
   * Register module with static config.
   */

  register: function register(config, base) {
    this._enqueue(function (callback) {
      this._register(config, base, function (err) {
        if (err) return _this.emit('err', err);
        callback();
      });
    });
  },

  /**
   * Register modules from config file.
   */

  config: function config(configFile) {
    var _this = this;
    _this._enqueue(function (callback) {
      require(configFile).forEach(function (config) {
        _this._register(config, path.dirname(configFile), function (err) {
          if (err) return _this.emit('err', err);
          callback();
        });
      });
      return this;
    });
  },

  /**
   * Register modules by scanning a directory containing config files.
   */

  scan: function scan(directory) {
    var _this = this;
    _this._enqueue(function (callback) {

      // Make directory absolute.
      if (directory[0] === '.') {
        directory = path.join(_this.get('root directory') || process.cwd(),
                             directory);
      }

      // List files.
      fs.readdir(directory, function (err, names) {
        if (err) return _this.emit('error', err);

        // Load each in order.
        function iterator(name, next) {
          if (name[0] === '.' && _this.get('ignore hidden files') !== false) {
            return next();
          }
          var absolutePath = path.join(directory, name);
          try {
            var required = require(absolutePath);
          }
          catch (err) {
            return _this.emit('error', err);
          }

          // Register it.
          _this._register(required, directory, function (err) {
            if (err) return _this.emit('error', err);
            next();
          });
        }

        function done(err) {
          if (err) return _this.emit('error', err);
          callback();
        }

        o.each(names, iterator, done);

      });
    });
    return _this;
  },

  /**
   * Start app.
   */

  bootstrap: function start() {
    var _this = this;
    _this._enqueue(function (callback) {

      // Prepare process.
      var remaining = Object.keys(_this._packages);
      var done = [];
      var reverse = {};
      o.each(_this._packages, function (data, name) {
        o.each(data.provides, function (service) {
          reverse[service] = name;
        });
      });

      // Check for missing dependencies, and check whether we can satisfy
      // weak dependencies.
      var consumes = {};
      try {
        o.each(_this._packages, function (data, name) {
          var missingDependencies = [];
          var packageConsumes = [];
          o.each(data.consumes, function (service) {
            if (!reverse[service]) return missingDependencies.push(service);
            packageConsumes.push(service);
          });
          if (missingDependencies.length) {
            throw Error([
              'Can\'t bootstrap package "', name,
              '" because of missing dependencies: "',
              missingDependencies.join('", "'), '".'
            ].join(''));
          }
          o.each(data.optionallyConsumes, function (service) {
            if (reverse[service]) packageConsumes.push(service);
          });
          consumes[name] = packageConsumes;
        });
      }
      catch (err) {
        return _this.emit('error', err);
      }

      // Helper checking whether we may process loading some package now.
      var canLoad = function canLoad(name) {
        var packageConsumes = consumes[name];
        var missing = o.filter(packageConsumes, function (service) {
          if (!_this._services[service]) return true;
        });
        return !missing.length;
      }

      // Helper bootstraping a specific package.
      var setup = function setup(name, done) {
        _this.emit('setup', name);
        var packageData = _this._packages[name];
        var config = packageData.config;
        packageData.setup(config, _this._services, function (err, services) {
          if (err) return done(err);
          services = services || {};
          o.each(packageData.provides, function (service) {
            _this._services[service] = services[service] || {};
          });
          done();
        });
      }

      // Start a big dirty infinite loop to start with the best order.
      var iterate = function iterate() {
        var newRemaining = [];
        o.each(remaining, function (remainingItem, next) {
          if (!canLoad(remainingItem)) {
            newRemaining.push(remainingItem);
            next();
          }
          else {
            setup(remainingItem, function (err) {
              next(err);
            });
          }
        }, function (err) {
          if (err) return _this.emit('error', err);

          // Maybe we're done
          if (!newRemaining.length) {
            _this.emit('bootstraped');
            return callback();
          }

          // Dit we reach a deadlock?
          if (newRemaining.length === remaining.length) {
            return _this.emit('error', Error([
              'Can\'t bootstrap because of circular dependency in packages: "',
              remaining.join('", "'), '".'
            ].join('')));
          }

          // Let's go for another round!
          remaining = newRemaining;
          process.nextTick(iterate);
        })
      };

      // Start the thing.
      iterate();

    });
    return _this;
  },

  /**
   * Get settings.
   */

  get: function get(key) {
    return this.settings[key];
  },

  /**
   * Set settings.
   */

  set: function set(key, value) {
    this.settings[key] = value;
    return this
  },

  /**
   * Get service.
   */

  service: function service(name) {
    return this._services[name];
  },

  /**
   * Enqueue arbitraity function.
   */

  then: function then(fn) {
    var _this = this;
    _this._enqueue(function (callback) {
      if (fn.length) {
        fn(function (err) {
          if (err) return _this.emit('error', err);
          callback();
        });
      }
      else {
        try {
          fn();
        }
        catch (err) {
          return _this.emit('error', err);
        }
        callback();
      }
    });
    return _this;
  },

  /**
   * Register method.
   */

  _register: function _register(config, root, callback) {
    var _this = this;
    config = typeof config === 'string' ? { packagePath: config } : config;
    resolvePackage(config.packagePath, root, function (packagePath) {
      if (!packagePath) {
        return callback(Error([
          'Can\'t locate package "', config.packagePath, '".'
        ].join('')));
      }
      var manifest = require(path.join(packagePath, 'package.json'));
      var name = manifest.name || path.basename(packagePath);
      var indexFile = manifest.main || 'index.js';
      var setup = require(path.join(packagePath, indexFile));
      _this._packages[name] = {
        path: packagePath,
        setup: setup,
        provides: manifest.provides || [],
        consumes: manifest.consumes || [],
        optionallyConsumes: manifest.optionallyConsumes || [],
        config: config
      }
      callback();
    });
  },

  /**
   * Processing queue.
   */

  _enqueue: function _enqueue(fn) {
    var _this = this;

    var callNext = function (err) {
      if (!_this._queue.length) {
        _this._busy = false;
      }
      else {
        var next = _this._queue.shift();
        process.nextTick(function () {
          next(callNext);
        });
      }
    }

    if (!_this._busy) {
      _this._busy = true;
      fn(callNext);
    }
    else {
      _this._queue.push(fn);
    }

    return _this;
  }

});

/**
 * Factory.
 */

module.exports = function factory(options) {
  return new Metronome(options);
}

/**
 * Expose `Metronome`.
 */

module.exports.Metronome = Metronome;

/**
 * Expose version.
 */

module.exports.__defineGetter__('version', function () {
  return require(path.join(__dirname, 'package.json')).version;
});

/**
 * Node style, resolve package.
 */

function resolvePackage(packagePath, base, callback) {
  var tryPaths = [];
  if (packagePath[0] === '/') {
    tryPaths.push(packagePath);
  } else if (packagePath[0] === '.') {
    tryPaths.push(path.join(base, packagePath));
  } else {
    var tmpBase = base;
    while (true) {
      tryPaths.push(path.join(tmpBase, 'node_modules', packagePath));
      if (tmpBase === (tmpBase = path.dirname(tmpBase))) break;
    }
  }

  o.detect(tryPaths, isPackagePath, function (resolvedPath) {
    return callback(resolvedPath);
  });
}

function isPackagePath(packagePath, callback) {
  fs.exists(path.join(packagePath, 'package.json'), callback);
}<|endoftext|>


<commit_before>export { init, testResultSame, disposeTensors };

import * as ChannelShuffler from "../Conv/ChannelShuffler.js";
import * as TensorTools from "../util/TensorTools.js";

/**
 * Test different channel shuffle implementation for CNN ShuffleNet.
 *
 * @see {@link https://www.measurethat.net/Benchmarks/Show/10945/9/colorfulcakechen-cnn-channel-shuffler-cf328d1847fabd52a}
 */

/**
 * A test set.
 */
class HeightWidthDepthGroup {

  /**
   * @param {number} height      image height
   * @param {number} width       image width
   * @param {number} depth       image channel count
   * @param {number} groupCount  Split the data into how many groups. ( depth / groupCount ) should be an integer.
   */
  constructor( height, width, depth, groupCount ) {

    this.height = height;
    this.width = width;
    this.depth = depth;
    this.groupCount = groupCount;

    this.valueCount = height * width * depth;

    this.concatenatedShape = [ height, width, depth ];

    this.dataTensor3dArray = tf.tidy( () => {
      let dataTensor1d = tf.linspace( 0, this.valueCount - 1, this.valueCount );

      let dataTensor3d = dataTensor1d.reshape( [ height, width, depth ] );
      return dataTensor3d.split( groupCount, dataTensor3d.rank - 1 );  // Along the last axis.
    });

    this.shuffleInfo = new ChannelShuffler.ShuffleInfo( this.concatenatedShape, groupCount );
    ( this.concatGatherUnsorted = new ChannelShuffler.ConcatGather() ).init( this.concatenatedShape, groupCount );
    ( this.splitConcatSortedShared = new ChannelShuffler.SplitConcat() ).init( this.concatenatedShape, groupCount );
    ( this.concatPointwiseConv = new ChannelShuffler.ConcatPointwiseConv() ).init( this.concatenatedShape, groupCount );
  }

  disposeTensors() {
    if ( this.dataTensor3dArray ) {
      tf.dispose( this.dataTensor3dArray );
      this.dataTensor3dArray = null;
    }

    if ( this.concatGatherUnsorted )
      this.concatGatherUnsorted.disposeTensors();

    if ( this.concatPointwiseConv )
      this.concatPointwiseConv.disposeTensors();
  }

  // Test concat-reshape-transpose-reshape-split
  test_ConcatReshapeTransposeReshapeSplit() {
    let shuffledArray = this.shuffleInfo.concatReshapeTransposeReshapeSplit( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Test concat-gather (Unsorted)
  test_ConcatGatherUnsorted() {
    let shuffledArray = this.concatGatherUnsorted.concatGather( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Test split-concat (Sorted Shared)
  test_SplitConcatSortedShared() {
    let shuffledArray = this.splitConcatSortedShared.splitConcat( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Test concat-pointwise-convolution
  test_ConcatPointwiseConv() {
    let shuffledArray = this.concatPointwiseConv.concatGather( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Testing whether the results of different implementation are the same.
  testResultSame() {
    tf.tidy( () => {
      let memoryInfo0 = tf.memory();

      let t1Array = this.shuffleInfo.concatReshapeTransposeReshapeSplit( this.dataTensor3dArray );
      let memoryInfo1 = tf.memory();
      tf.util.assert( memoryInfo1.numTensors == ( memoryInfo0.numTensors + t1Array.length ), `ConcatReshapeTransposeReshapeSplit() memory leak`);

      let t2Array = this.concatGatherUnsorted.concatGather( this.dataTensor3dArray );
      let memoryInfo2 = tf.memory();
      tf.util.assert( memoryInfo2.numTensors == ( memoryInfo1.numTensors + t2Array.length ), `ConcatGatherUnsorted() memory leak`);

      let t3Array = this.splitConcatSortedShared.splitConcat( this.dataTensor3dArray );
      let memoryInfo3 = tf.memory();
      tf.util.assert( memoryInfo3.numTensors == ( memoryInfo2.numTensors + t3Array.length ), `SplitConcatSortedShared() memory leak`);

      let t4Array = this.concatPointwiseConv.concatGather( this.dataTensor3dArray );
      let memoryInfo4 = tf.memory();
      tf.util.assert( memoryInfo4.numTensors == ( memoryInfo3.numTensors + t4Array.length ), `PointwiseConv() memory leak`);

      tf.util.assert(
        TensorTools.Comparator.isTensorArrayEqual( t1Array, t2Array ),
        `ConcatReshapeTransposeReshapeSplit() != ConcatGatherUnsorted()`);

//!!! Sorted never equal to Unsorted.
//       tf.util.assert(
//         ChannelShuffler.Layer.isTensorArrayEqual( t2Array, t3Array ),
//         `ConcatGatherUnsorted() != SplitConcatSortedShared()`);

      // Because the sorted will never equal to unsorted, try to compare their sum.
      // (Using average may be have some floating-point error.)
      tf.tidy( () => {
//         let t2MeanArray = t2Array.map( t => t.mean() );
//         let t3MeanArray = t3Array.map( t => t.mean() );
        let lastAxisId = t2Array[ 0 ].rank - 1;
        let t2SumArray = t2Array.map( t => t.sum( lastAxisId ) );
        let t3SumArray = t3Array.map( t => t.sum( lastAxisId ) );

        tf.util.assert(
          TensorTools.Comparator.isTensorArrayEqual( t2SumArray, t3SumArray ),
          `ConcatGatherUnsorted() != SplitConcatSortedShared()`);
      });

      tf.util.assert(
        TensorTools.Comparator.isTensorArrayEqual( t2Array, t4Array ),
        `ConcatGatherUnsorted() != PointwiseConv()`);
    });
  }

}

function init() {
  globalThis.testSet_110x110x24_g8 = new HeightWidthDepthGroup( 110, 110, 24, 8 ); // height, width, depth, groupCount
  globalThis.testSet_110x110x24_g4 = new HeightWidthDepthGroup( 110, 110, 24, 4 );
  globalThis.testSet_110x110x24_g3 = new HeightWidthDepthGroup( 110, 110, 24, 3 );
  globalThis.testSet_110x110x24_g2 = new HeightWidthDepthGroup( 110, 110, 24, 2 );
  globalThis.testSet_110x110x24_g1 = new HeightWidthDepthGroup( 110, 110, 24, 1 );
}

function testResultSame() {
  globalThis.testSet_110x110x24_g8.testResultSame();
  globalThis.testSet_110x110x24_g4.testResultSame();
  globalThis.testSet_110x110x24_g3.testResultSame();
  globalThis.testSet_110x110x24_g2.testResultSame();
  globalThis.testSet_110x110x24_g1.testResultSame();
}

function disposeTensors() {
  if ( globalThis.testSet_110x110x24_g8 ) {
    globalThis.testSet_110x110x24_g8.disposeTensors();
    globalThis.testSet_110x110x24_g8 = null;
  }

  if ( globalThis.testSet_110x110x24_g4 ) {
    globalThis.testSet_110x110x24_g4.disposeTensors();
    globalThis.testSet_110x110x24_g4 = null;
  }

  if ( globalThis.testSet_110x110x24_g3 ) {
    globalThis.testSet_110x110x24_g3.disposeTensors();
    globalThis.testSet_110x110x24_g3 = null;
  }

  if ( globalThis.testSet_110x110x24_g2 ) {
    globalThis.testSet_110x110x24_g2.disposeTensors();
    globalThis.testSet_110x110x24_g2 = null;
  }

  if ( globalThis.testSet_110x110x24_g1 ) {
    globalThis.testSet_110x110x24_g1.disposeTensors();
    globalThis.testSet_110x110x24_g1 = null;
  }
}

//tf.ready().then( init );
<commit_msg>Update jsPerf_CNNChannelShuffle.js<commit_after>export { init, testResultSame, disposeTensors };

import * as ChannelShuffler from "../Conv/ChannelShuffler.js";
import * as TensorTools from "../util/TensorTools.js";

/**
 * Test different channel shuffle implementation for CNN ShuffleNet.
 *
 * @see {@link https://www.measurethat.net/Benchmarks/Show/10945/13/colorfulcakechen-cnn-channel-shuffler-0faaacfd48ff64bed}
 */

/**
 * A test set.
 */
class HeightWidthDepthGroup {

  /**
   * @param {number} height      image height
   * @param {number} width       image width
   * @param {number} depth       image channel count
   * @param {number} groupCount  Split the data into how many groups. ( depth / groupCount ) should be an integer.
   */
  constructor( height, width, depth, groupCount ) {

    this.height = height;
    this.width = width;
    this.depth = depth;
    this.groupCount = groupCount;

    this.valueCount = height * width * depth;

    this.concatenatedShape = [ height, width, depth ];

    this.dataTensor3dArray = tf.tidy( () => {
      let dataTensor1d = tf.linspace( 0, this.valueCount - 1, this.valueCount );

      let dataTensor3d = dataTensor1d.reshape( [ height, width, depth ] );
      return dataTensor3d.split( groupCount, dataTensor3d.rank - 1 );  // Along the last axis.
    });

    this.shuffleInfo = new ChannelShuffler.ShuffleInfo( this.concatenatedShape, groupCount );
    ( this.concatGatherUnsorted = new ChannelShuffler.ConcatGather() ).init( this.concatenatedShape, groupCount );
    ( this.splitConcatSortedShared = new ChannelShuffler.SplitConcat() ).init( this.concatenatedShape, groupCount );
    ( this.concatPointwiseConv = new ChannelShuffler.ConcatPointwiseConv() ).init( this.concatenatedShape, groupCount );
  }

  disposeTensors() {
    if ( this.dataTensor3dArray ) {
      tf.dispose( this.dataTensor3dArray );
      this.dataTensor3dArray = null;
    }

    if ( this.concatGatherUnsorted )
      this.concatGatherUnsorted.disposeTensors();

    if ( this.concatPointwiseConv )
      this.concatPointwiseConv.disposeTensors();
  }

  // Test concat-reshape-transpose-reshape-split
  test_ConcatReshapeTransposeReshapeSplit() {
    let shuffledArray = this.shuffleInfo.concatReshapeTransposeReshapeSplit( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Test concat-gather (Unsorted)
  test_ConcatGatherUnsorted() {
    let shuffledArray = this.concatGatherUnsorted.concatGather( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Test split-concat (Sorted Shared)
  test_SplitConcatSortedShared() {
    let shuffledArray = this.splitConcatSortedShared.splitConcat( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Test concat-pointwise-convolution
  test_ConcatPointwiseConv() {
    let shuffledArray = this.concatPointwiseConv.concatGather( this.dataTensor3dArray );
    tf.dispose( shuffledArray );
  }

  // Testing whether the results of different implementation are the same.
  testResultSame() {
    tf.tidy( () => {
      let memoryInfo0 = tf.memory();

      let t1Array = this.shuffleInfo.concatReshapeTransposeReshapeSplit( this.dataTensor3dArray );
      let memoryInfo1 = tf.memory();
      tf.util.assert( memoryInfo1.numTensors == ( memoryInfo0.numTensors + t1Array.length ), `ConcatReshapeTransposeReshapeSplit() memory leak`);

      let t2Array = this.concatGatherUnsorted.concatGather( this.dataTensor3dArray );
      let memoryInfo2 = tf.memory();
      tf.util.assert( memoryInfo2.numTensors == ( memoryInfo1.numTensors + t2Array.length ), `ConcatGatherUnsorted() memory leak`);

      let t3Array = this.splitConcatSortedShared.splitConcat( this.dataTensor3dArray );
      let memoryInfo3 = tf.memory();
      tf.util.assert( memoryInfo3.numTensors == ( memoryInfo2.numTensors + t3Array.length ), `SplitConcatSortedShared() memory leak`);

      let t4Array = this.concatPointwiseConv.concatGather( this.dataTensor3dArray );
      let memoryInfo4 = tf.memory();
      tf.util.assert( memoryInfo4.numTensors == ( memoryInfo3.numTensors + t4Array.length ), `PointwiseConv() memory leak`);

      tf.util.assert(
        TensorTools.Comparator.isTensorArrayEqual( t1Array, t2Array ),
        `ConcatReshapeTransposeReshapeSplit() != ConcatGatherUnsorted()`);

//!!! Sorted never equal to Unsorted.
//       tf.util.assert(
//         ChannelShuffler.Layer.isTensorArrayEqual( t2Array, t3Array ),
//         `ConcatGatherUnsorted() != SplitConcatSortedShared()`);

      // Because the sorted will never equal to unsorted, try to compare their sum.
      // (Using average may be have some floating-point error.)
      tf.tidy( () => {
//         let t2MeanArray = t2Array.map( t => t.mean() );
//         let t3MeanArray = t3Array.map( t => t.mean() );
        let lastAxisId = t2Array[ 0 ].rank - 1;
        let t2SumArray = t2Array.map( t => t.sum( lastAxisId ) );
        let t3SumArray = t3Array.map( t => t.sum( lastAxisId ) );

        tf.util.assert(
          TensorTools.Comparator.isTensorArrayEqual( t2SumArray, t3SumArray ),
          `ConcatGatherUnsorted() != SplitConcatSortedShared()`);
      });

      tf.util.assert(
        TensorTools.Comparator.isTensorArrayEqual( t2Array, t4Array ),
        `ConcatGatherUnsorted() != PointwiseConv()`);
    });
  }

}

function init() {
  globalThis.testSet_110x110x24_g8 = new HeightWidthDepthGroup( 110, 110, 24, 8 ); // height, width, depth, groupCount
  globalThis.testSet_110x110x24_g4 = new HeightWidthDepthGroup( 110, 110, 24, 4 );
  globalThis.testSet_110x110x24_g3 = new HeightWidthDepthGroup( 110, 110, 24, 3 );
  globalThis.testSet_110x110x24_g2 = new HeightWidthDepthGroup( 110, 110, 24, 2 );
  globalThis.testSet_110x110x24_g1 = new HeightWidthDepthGroup( 110, 110, 24, 1 );
}

function testResultSame() {
  globalThis.testSet_110x110x24_g8.testResultSame();
  globalThis.testSet_110x110x24_g4.testResultSame();
  globalThis.testSet_110x110x24_g3.testResultSame();
  globalThis.testSet_110x110x24_g2.testResultSame();
  globalThis.testSet_110x110x24_g1.testResultSame();
}

function disposeTensors() {
  if ( globalThis.testSet_110x110x24_g8 ) {
    globalThis.testSet_110x110x24_g8.disposeTensors();
    globalThis.testSet_110x110x24_g8 = null;
  }

  if ( globalThis.testSet_110x110x24_g4 ) {
    globalThis.testSet_110x110x24_g4.disposeTensors();
    globalThis.testSet_110x110x24_g4 = null;
  }

  if ( globalThis.testSet_110x110x24_g3 ) {
    globalThis.testSet_110x110x24_g3.disposeTensors();
    globalThis.testSet_110x110x24_g3 = null;
  }

  if ( globalThis.testSet_110x110x24_g2 ) {
    globalThis.testSet_110x110x24_g2.disposeTensors();
    globalThis.testSet_110x110x24_g2 = null;
  }

  if ( globalThis.testSet_110x110x24_g1 ) {
    globalThis.testSet_110x110x24_g1.disposeTensors();
    globalThis.testSet_110x110x24_g1 = null;
  }
}

//tf.ready().then( init );
<|endoftext|>


<commit_before>var _ = require('lodash'),
    parseString = require('xml2js').parseString,
    reTitle = /<title>(.+) - YouTube</i,
    Captions = require('../models/Captions'),
    request = require('request'),
    uriMatch,
    reASR = /ttsurl":"(.+?)"/i,
    reVidID = /youtube(.+)/i,
    relang = /thing/i,
    asrURI,
    videoID,
    videoURL,
    title,
    titleStr,
    langCode,
    captionsAsr = [],
    craptionObj,
    craptionID;

exports.getCaptions = function(req, res) {
    Captions.find(function(err, captions) {
        if (err) console.log(err);
        res.json(captions);
    });
};

exports.getVideo = function(req, res) {
    Captions.findById(req.params.id, function(err, caption) {
      if (err) console.log(err);

      if (caption) {
        res.json(caption);
      }
      else {
        videoID = req.params.id.match(reVidID)[1];
        console.log(videoID);
        craptionID = 'youtube' + videoID;
        videoURL = 'https://www.youtube.com/watch?v=' + videoID;
        request(videoURL, function(error, response, body) {
          if (error) {
            // console.log(response);
          }
          if (!error && response.statusCode == 200) {
            titleStr = body.match(reTitle);
            title = titleStr !== null ? titleStr[1] : 'No title was found';
            uriMatch = body.match(reASR);
            asrURI = uriMatch[1];
            asrURI = asrURI.replace(/\\u0026/g, '&');
            asrURI = asrURI.replace(/\\/g, '');
            asrURI = asrURI.replace(/%2C/g, ',');
            asrURI = asrURI + '&type=track&lang=en&name&kind=asr&fmt=1'
            console.log(asrURI);
            request(asrURI, function(error, response, body) {
              parseString(body, function(err, result) {
                _.forEach(result.transcript.text, function(element) {
                  captionsAsr.push({
                    'start': parseFloat(element['$'].start),
                    'dur': parseFloat(element['$'].dur),
                    'value': element['_'],
                    'extra_data': []
                  });
                });
                // console.log(captionsAsr);
                craptionObj = new Captions({
                  '_id': craptionID,
                  'title': title,
                  'url': videoURL,
                  'captions': captionsAsr
                });
                craptionObj.save(function(err, craptionObj) {
                  if (err) return console.error(err);
                  console.log(craptionObj);
                  Captions.findById(req.params.id, function(err, caption) {
                    if (err) console.log(err);

                    if (caption) {
                      res.json(caption);
                    }
                  });
                });
              });
            });
          }
        });
      }
    });
};

exports.getCaption = function(req, res) {
    Captions.findById(req.params.id, function(err, caption) {
      if (err) console.log(err);

      if (caption) {
          res.json(caption.captions);
      }
      else {
        res.send('this is the error')
        console.log('this');
      }
    });
};

exports.getTitle = function(req, res) {
    Captions.findById(req.params.id, function(err, caption) {
      if (err) console.log(err);
      res.json(caption.title)
    });
};<commit_msg>Add some error handling if video doesn't have asr<commit_after>var _ = require('lodash'),
    parseString = require('xml2js').parseString,
    reTitle = /<title>(.+) - YouTube</i,
    Captions = require('../models/Captions'),
    request = require('request'),
    uriMatch,
    reASR = /ttsurl":"(.+?)"/i,
    reVidID = /youtube(.+)/i,
    relang = /thing/i,
    asrURI,
    videoID,
    videoURL,
    title,
    titleStr,
    langCode,
    captionsAsr = [],
    craptionObj,
    craptionID;

exports.getCaptions = function(req, res) {
    Captions.find(function(err, captions) {
        if (err) console.log(err);
        res.json(captions);
    });
};

exports.getVideo = function(req, res) {
    Captions.findById(req.params.id, function(err, caption) {
      if (err) console.log(err);

      if (caption) {
        res.json(caption);
      }
      else {
        videoID = req.params.id.match(reVidID)[1];
        console.log(videoID);
        craptionID = 'youtube' + videoID;
        videoURL = 'https://www.youtube.com/watch?v=' + videoID;
        request(videoURL, function(error, response, body) {
          if (error) {
            // console.log(response);
          }
          if (!error && response.statusCode == 200) {
            titleStr = body.match(reTitle);
            title = titleStr !== null ? titleStr[1] : 'No title was found';
            uriMatch = body.match(reASR);
            if (uriMatch) {
              console.log(uriMatch);
              asrURI = uriMatch[1];
              asrURI = asrURI.replace(/\\u0026/g, '&');
              asrURI = asrURI.replace(/\\/g, '');
              asrURI = asrURI.replace(/%2C/g, ',');
              asrURI = asrURI + '&type=track&lang=en&name&kind=asr&fmt=1'
              console.log(asrURI);
              request(asrURI, function(error, response, body) {
                parseString(body, function(err, result) {
                  _.forEach(result.transcript.text, function(element) {
                    captionsAsr.push({
                      'start': parseFloat(element['$'].start),
                      'dur': parseFloat(element['$'].dur),
                      'value': element['_'],
                      'extra_data': []
                    });
                  });
                  // console.log(captionsAsr);
                  craptionObj = new Captions({
                    '_id': craptionID,
                    'title': title,
                    'url': videoURL,
                    'captions': captionsAsr
                  });
                  craptionObj.save(function(err, craptionObj) {
                    if (err) return console.error(err);
                    console.log(craptionObj);
                    Captions.findById(req.params.id, function(err, caption) {
                      if (err) console.log(err);

                      if (caption) {
                        res.json(caption);
                      }
                    });
                  });
                });
              });
            }
            else {
              res.send("Didn't work");
            }
          }
        });
      }
    });
};

exports.getCaption = function(req, res) {
    Captions.findById(req.params.id, function(err, caption) {
      if (err) console.log(err);

      if (caption) {
          res.json(caption.captions);
      }
      else {
        res.send('this is the error')
        console.log('this');
      }
    });
};

exports.getTitle = function(req, res) {
    Captions.findById(req.params.id, function(err, caption) {
      if (err) console.log(err);
      res.json(caption.title)
    });
};<|endoftext|>


<commit_before>/*
	Usage:
	npm run-script apply-fixes
*/
const fs = require('fs')
const shell = require('shelljs')

// Configure Glog
shell.cd('node_modules/react-native')
shell.exec('scripts/ios-install-third-party.sh')
shell.cd('third-party/glog-0.3.4')
shell.exec('./configure')
shell.cd('../../../../')

// Fix an issue with Android default text color
const TEXT_FIX_PATH = './node_modules/react-native/Libraries/Text/Text.js'
const TEXT_ERR = 'if \\(this.context.isInAParentText\\)'
const TEXT_FIX = 'newProps = {...newProps, style: [{color: \'black\'}, this.props.style] }\n    if (this.context.isInAParentText)'

// Set correct safe area for iPhone XR
const XR_FIX_PATH = './node_modules/react-native-safe-area-view/index.js'
const XR_FIX_REPL1 = 'const X_HEIGHT = 812;'
const XR_FIX_REPL1_FIX = 'const X_HEIGHT = 812;const XSMAX_WIDTH = 414;const XSMAX_HEIGHT = 896;'
const XR_FIX_REPL2 = '\\(D_HEIGHT === X_WIDTH && D_WIDTH === X_HEIGHT\\)\\)'
const XR_FIX_REPL2_FIX = '\(D_HEIGHT === X_WIDTH && D_WIDTH === X_HEIGHT\)\) || \(\(D_HEIGHT === XSMAX_HEIGHT && D_WIDTH === XSMAX_WIDTH\) || \(D_HEIGHT === XSMAX_WIDTH && D_WIDTH === XSMAX_HEIGHT\)\)' // eslint-disable-line no-useless-escape
const XR_FIX_REPL3 = 'return DeviceInfo.isIPhoneX_deprecated;'
const XR_FIX_REPL3_FIX = '//return DeviceInfo.isIPhoneX_deprecated;'

const makeReplacements = (FILE_PATH, REPLACEMENTS) => {
	fs.readFile(FILE_PATH, 'utf8', (readErr, data) => {
		if (readErr) {
			return console.log(readErr)
		} else {
			for (let i = 0; REPLACEMENTS.length > i; i++) {
				data = data.replace(new RegExp(REPLACEMENTS[i].initial, 'g'), REPLACEMENTS[i].fixed)
			}

			fs.writeFile(FILE_PATH, data, 'utf8', (writeErr) => {
				if (writeErr) {
					return console.log(writeErr)
				} else {
					console.log('SUCCESS: File ' + FILE_PATH + ' updated with fixed value.')
				}
			})
		}
	})
}

makeReplacements(TEXT_FIX_PATH, [
	{ initial: TEXT_ERR, fixed: TEXT_FIX }
])

makeReplacements(XR_FIX_PATH, [
	{ initial: XR_FIX_REPL1, fixed: XR_FIX_REPL1_FIX },
	{ initial: XR_FIX_REPL2, fixed: XR_FIX_REPL2_FIX },
	{ initial: XR_FIX_REPL3, fixed: XR_FIX_REPL3_FIX }
])
<commit_msg>Fix libfishhook linking<commit_after>/*
	Usage:
	npm run-script apply-fixes
*/
const fs = require('fs')
const shell = require('shelljs')

// Configure Glog
shell.cd('node_modules/react-native')
shell.exec('scripts/ios-install-third-party.sh')
shell.cd('third-party/glog-0.3.4')
shell.exec('./configure')
shell.cd('../../../../')

// Fix an issue with libfishhook.a linking
const LIBFH_PATH = './node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj/project.pbxproj'
const LIBFH_OLD_1 = '13526A521F362F7F0008EF00'
const LIBFH_OLD_2 = '13526A511F362F7F0008EF00'
const LIBFH_NEW_1 = '2D3ABDC220C7206E00DF56E9'
const LIBFH_NEW_2 = '3DBE0D001F3B181A0099AA32'

// Fix an issue with Android default text color
const TEXT_FIX_PATH = './node_modules/react-native/Libraries/Text/Text.js'
const TEXT_ERR = 'if \\(this.context.isInAParentText\\)'
const TEXT_FIX = 'newProps = {...newProps, style: [{color: \'black\'}, this.props.style] }\n    if (this.context.isInAParentText)'

// Set correct safe area for iPhone XR
const XR_FIX_PATH = './node_modules/react-native-safe-area-view/index.js'
const XR_FIX_REPL1 = 'const X_HEIGHT = 812;'
const XR_FIX_REPL1_FIX = 'const X_HEIGHT = 812;const XSMAX_WIDTH = 414;const XSMAX_HEIGHT = 896;'
const XR_FIX_REPL2 = '\\(D_HEIGHT === X_WIDTH && D_WIDTH === X_HEIGHT\\)\\)'
const XR_FIX_REPL2_FIX = '\(D_HEIGHT === X_WIDTH && D_WIDTH === X_HEIGHT\)\) || \(\(D_HEIGHT === XSMAX_HEIGHT && D_WIDTH === XSMAX_WIDTH\) || \(D_HEIGHT === XSMAX_WIDTH && D_WIDTH === XSMAX_HEIGHT\)\)' // eslint-disable-line no-useless-escape
const XR_FIX_REPL3 = 'return DeviceInfo.isIPhoneX_deprecated;'
const XR_FIX_REPL3_FIX = '//return DeviceInfo.isIPhoneX_deprecated;'

const makeReplacements = (FILE_PATH, REPLACEMENTS) => {
	fs.readFile(FILE_PATH, 'utf8', (readErr, data) => {
		if (readErr) {
			return console.log(readErr)
		} else {
			for (let i = 0; REPLACEMENTS.length > i; i++) {
				data = data.replace(new RegExp(REPLACEMENTS[i].initial, 'g'), REPLACEMENTS[i].fixed)
			}

			fs.writeFile(FILE_PATH, data, 'utf8', (writeErr) => {
				if (writeErr) {
					return console.log(writeErr)
				} else {
					console.log('SUCCESS: File ' + FILE_PATH + ' updated with fixed value.')
				}
			})
		}
	})
}

makeReplacements(LIBFH_PATH, [
	{ initial: LIBFH_OLD_1, fixed: LIBFH_NEW_1 },
	{ initial: LIBFH_OLD_2, fixed: LIBFH_NEW_2 }
])

makeReplacements(TEXT_FIX_PATH, [
	{ initial: TEXT_ERR, fixed: TEXT_FIX }
])

makeReplacements(XR_FIX_PATH, [
	{ initial: XR_FIX_REPL1, fixed: XR_FIX_REPL1_FIX },
	{ initial: XR_FIX_REPL2, fixed: XR_FIX_REPL2_FIX },
	{ initial: XR_FIX_REPL3, fixed: XR_FIX_REPL3_FIX }
])
<|endoftext|>


<commit_before>import React from 'react';
import { hashHistory } from 'react-router'
import { Link } from 'react-router'

import { storeUser, user, logout } from './auth';
import API from './api';
import moment from 'moment';

export class EventRow extends React.Component {
    state = { joined: false, expand: false }

    componentWillMount() {
      this.setState({ joined: this.props.ev.joined });
    }

    expand = (e) => {
        if (this.state.expand) {
            this.setState({ expand: false });
        } else {
            this.setState({ expand: true });
        }
    }

    join = (e) => {
        var self = this;
        API.joinEvent(this.props.ev.pk)
            .then(function() {
                self.setState({joined: true});
            }).catch(function(error) {
                alert(error);
            });
    }

    leave = (e) => {
        var self = this;
        API.leaveEvent(this.props.ev.pk)
            .then(function() {
                self.setState({joined: false});
            }).catch(function(error) {
                alert(error);
            });
    }

    price = (ev) => {
        if (parseFloat(ev.price)) {
            return (

                     { parseFloat(ev.price) }

            )
        }
        return (

                free

        )
    }

    maxp = (ev) => {
        if (parseInt(ev.max_players)) {
            return (

                     { ev.max_players }

            )
        }
        return ''
    }

    joinButton = (ev) => {
        if (this.state.joined) {
            return (
                <button onClick={ this.leave } className="btn btn-danger">
                    Leave
                </button>
            )
        }

        return (
            <button onClick={ this.join } className="btn btn-success">
                Join
            </button>
        )
    }

    playButton = (ev) => {
        if (this.props.active && this.props.active.pk == ev.pk) {
            return (
                <button onClick={ this.props.unplay } className="btn btn-primary">

                </button>
            )
        }

        return (
            <button onClick={ this.props.play } className="btn btn-default">

            </button>
        )
    }

    renderDesc() {
        if (!this.props.expand && !this.state.expand) {
            return ()
        }

        return (

{ this.props.ev.game.name }

{ this.props.ev.game.desc }

        );
    }

    render() {
        return (

                        { this.joinButton(this.props.ev) }

{ this.props.ev.name }

{ moment(this.props.ev.start_date).format('lll') }

{ moment(this.props.ev.end_date).format('lll') }

                        { this.playButton(this.props.ev) }

                { this.renderDesc() }

                { this.price(this.props.ev) }
                { this.maxp(this.props.ev) }

        )
    }
}

export default class Events extends React.Component {
    state = { user: user, events: [], active: user.activeEvent }

    componentDidMount() {
        this.updateEvents();
        this.retitle();
    }

    updateEvents = () => {
        var self = this;
        API.allEvents(user.apikey)
            .then(function(events) {
                self.setState({ events: events });
            });
    }

    retitle = () => {
        var title = 'Events';
        if (user.activeEvent) {
          title = title + ' - ' + user.activeEvent.name;
        }
        this.props.setAppState({ title: title });
    }

    play = (e) => {
        user.activeEvent = e;
        storeUser();
        this.setState({ active: user.activeEvent });
        this.retitle();
    }

    unplay = () => {
        user.activeEvent = null;
        storeUser();
        this.setState({ active: user.activeEvent });
        this.retitle();
    }

    render() {
        var self = this;
        return (

                {this.state.events.map(function(ev, i){
                    function play() { self.play(ev); }
                    return <EventRow ev={ev} key={i}
                                     active={self.state.active}
                                     play={play.bind(self)}
                                     unplay={self.unplay.bind(self)} />;
                 })}

        );
    }
}
<commit_msg>frontend: Avoiding show/hide ev desc on all click<commit_after>import React from 'react';
import { hashHistory } from 'react-router'
import { Link } from 'react-router'

import { storeUser, user, logout } from './auth';
import API from './api';
import moment from 'moment';

export class EventRow extends React.Component {
    state = { joined: false, expand: false }

    componentWillMount() {
      this.setState({ joined: this.props.ev.joined });
    }

    expand = (e) => {
        if (this.state.expand) {
            this.setState({ expand: false });
        } else {
            this.setState({ expand: true });
        }
    }

    join = (e) => {
        e.preventDefault();
        e.stopPropagation();

        var self = this;
        API.joinEvent(this.props.ev.pk)
            .then(function() {
                self.setState({joined: true});
            }).catch(function(error) {
                alert(error);
            });
    }

    leave = (e) => {
        e.preventDefault();
        e.stopPropagation();

        var self = this;
        API.leaveEvent(this.props.ev.pk)
            .then(function() {
                self.setState({joined: false});
            }).catch(function(error) {
                alert(error);
            });
    }

    price = (ev) => {
        if (parseFloat(ev.price)) {
            return (

                     { parseFloat(ev.price) }

            )
        }
        return (

                free

        )
    }

    maxp = (ev) => {
        if (parseInt(ev.max_players)) {
            return (

                     { ev.max_players }

            )
        }
        return ''
    }

    joinButton = (ev) => {
        if (this.state.joined) {
            return (
                <button onClick={ this.leave } className="btn btn-danger">
                    Leave
                </button>
            )
        }

        return (
            <button onClick={ this.join } className="btn btn-success">
                Join
            </button>
        )
    }

    playButton = (ev) => {
        if (this.props.active && this.props.active.pk == ev.pk) {
            return (
                <button onClick={ this.props.unplay } className="btn btn-primary">

                </button>
            )
        }

        return (
            <button onClick={ this.props.play } className="btn btn-default">

            </button>
        )
    }

    renderDesc() {
        if (!this.props.expand && !this.state.expand) {
            return ()
        }

        return (

{ this.props.ev.game.name }

{ this.props.ev.game.desc }

        );
    }

    render() {
        return (

                        { this.joinButton(this.props.ev) }

{ this.props.ev.name }

{ moment(this.props.ev.start_date).format('lll') }

{ moment(this.props.ev.end_date).format('lll') }

                        { this.playButton(this.props.ev) }

                { this.renderDesc() }

                { this.price(this.props.ev) }
                { this.maxp(this.props.ev) }

        )
    }
}

export default class Events extends React.Component {
    state = { user: user, events: [], active: user.activeEvent }

    componentDidMount() {
        this.updateEvents();
        this.retitle();
    }

    updateEvents = () => {
        var self = this;
        API.allEvents(user.apikey)
            .then(function(events) {
                self.setState({ events: events });
            });
    }

    retitle = () => {
        var title = 'Events';
        if (user.activeEvent) {
          title = title + ' - ' + user.activeEvent.name;
        }
        this.props.setAppState({ title: title });
    }

    play = (e, ev) => {
        e.preventDefault();
        e.stopPropagation();

        user.activeEvent = ev;
        storeUser();
        this.setState({ active: user.activeEvent });
        this.retitle();
    }

    unplay = (e) => {
        e.preventDefault();
        e.stopPropagation();

        user.activeEvent = null;
        storeUser();
        this.setState({ active: user.activeEvent });
        this.retitle();
    }

    render() {
        var self = this;
        return (

                {this.state.events.map(function(ev, i){
                    function play(e) { self.play(e, ev); }
                    return <EventRow ev={ev} key={i}
                                     active={self.state.active}
                                     play={play.bind(self)}
                                     unplay={self.unplay.bind(self)} />;
                 })}

        );
    }
}
<|endoftext|>