<commit_before>import { getDevPath } from './utils/dev';
import webpack from 'webpack';
import path from 'path';

import autoprefixer from 'autoprefixer';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import BrowserSyncPlugin from 'browser-sync-webpack-plugin';
import writeStats from './utils/write-stats';

const bourbon = './node_modules/bourbon/app/assets/stylesheets/';
const neat = './node_modules/bourbon-neat/app/assets/stylesheets/';

/* resolver: should be a path to a file that will return the final new NODE_PATH
 */
export default function createBuilder(options, resolver = 'roc-web/lib/get-resolve-path') {
    const allowedModes = ['dev', 'test', 'dist'];
    const allowedTargets = ['server', 'client'];

    if (allowedModes.indexOf(options.mode) === -1) {
        throw new Error(`Invalid mode, must be one of ${allowedModes}. Was instead ${options.mode}.`);
    }

    if (allowedTargets.indexOf(options.target) === -1) {
        throw new Error(`Invalid target, must be one of ${allowedTargets}. Was instead ${options.target}.`);
    }

    if (!options.outputPath) {
        throw new Error('A output path needs to be defined in the options.');
    }

    const DEV = (options.mode === 'dev');
    const TEST = (options.mode === 'test');
    const DIST = (options.mode === 'dist');

    const SERVER = (options.target === 'server');
    const CLIENT = (options.target === 'client');

    const COMPONENT_BUILD = !!options.componentBuild;

    const ENV = DIST ? 'production' : 'development';

    let webpackConfig = {};

    webpackConfig.bail = true;

    /**
    * Entry
    */
    if (SERVER) {
        webpackConfig.entry = {
            app: [
                require.resolve('../../app/server-entry')
            ]
        };
    }

    /**
    * Target
    */
    if (SERVER) {
        webpackConfig.target = 'node';
    }

    const devPath = getDevPath({
        buildPath: options.outputPath
    });

    if (SERVER) {
        webpackConfig.externals = [
            {
                [resolver]: true
            },
            function(context, request, callback) {
                // If a roc module include it in the bundle
                if (request.substr(0, 4) === 'roc-') {
                    return callback();
                }

                // If a normal node_module mark it as external
                if (/^[a-zA-Z\-0-9]{1}.*$/.test(request)) {
                    return callback(null, true);
                }

                // Everything else should be included, that will be relative and absolute paths
                callback();
            }
        ];
    }

    /**
    * Devtool
    *
    * TODO: Consider tweaking this option & handle production correct
    * We want the source map files to be stored on a seperate server.
    */
    if (CLIENT && DEV) {
        webpackConfig.devtool = 'cheap-module-inline-source-map';
    } else if (CLIENT && TEST) {
        webpackConfig.devtool = 'inline-source-map';
    } else {
        webpackConfig.devtool = 'source-map';
    }

    /**
    * Output
    */
    if (TEST) {
        webpackConfig.output = {};
    } else {
        webpackConfig.output = {
            path: options.outputPath.absolute,
            publicPath: DIST ? '/' : devPath,
            filename: (DIST && CLIENT) ? '[name].[hash].js' : '[name].bundle.js',
            chunkFilename: (DIST && CLIENT) ? '[name].[hash].js' : '[name].bundle.js'
        };
    }

    if (SERVER) {
        webpackConfig.output.libraryTarget = 'commonjs2';
    }

    if (CLIENT && DEV) {
        webpackConfig.output.filename = '[name].client.bundle.js';
    }

    /**
    * Loaders
    */

    // Base
    webpackConfig.module = {
        preLoaders: [],
        loaders: []
    };

    // ISPARTA LOADER
    if (TEST) {
        webpackConfig.module.loaders.push({
            test: /\.js$/,
            loader: 'babel-loader',
            // FIXME
            include: [
                /tests/,
                /karma/
            ]
        });
        webpackConfig.module.preLoaders.push({
            test: /\.js$/,
            loader: 'isparta-loader',
            // FIXME
            exclude: [
                /node_modules/,
                /tests/,
                /karma/,
                /src\/vendor/
            ]
        });
    }

    // JS LOADER
    const jsLoader = {
        test: /\.js$/,
        loader: 'babel-loader',
        include: function(absPath) {
            /* This function will look at the absolute path for the current file
             * to determine if it should be processed by the babel-loader.
             *
             * What this does exactly is that is finds the last match of "roc-X/SOMETHING".
             * If SOMETHING is "node_modules" it will ignore it otherwise process it using
             * babel.
             */
            const regexp = /(roc-[^/]*)\/([^/]*)/g;
            let match, matches = [];
            while ((match = regexp.exec(absPath))) {
                matches.push({ roc: match[0], next: match[1] });
            }
            const last = matches[matches.length - 1];
            if (last.next !== 'node_modules') {
                // We want to process this with babel-loader
                return true;
            }
        },
        exclude: [
            /node_modules/
        ]
    };

    if (!TEST) {
        webpackConfig.module.loaders.push(jsLoader);
    }

    // STYLE LOADER
    const styleLoader = {
        test: /\.scss$/
    };

    // JSON LOADER
    const jsonLoader = {
        test: /\.json$/,
        loader: 'json-loader'
    };

    let styleLoaders = 'css-loader';

    if (SERVER) {
        styleLoaders += '/locals';
    }

    styleLoaders += '?sourceMap&module&importLoaders=1&localIdentName=';

    // Define how the class names should be defined
    if (DIST) {
        styleLoaders += '[hash:base64:5]';
    } else {
        styleLoaders += '[path]_[name]__[local]___[hash:base64:5]';
    }

    // We can add an external sass dependecie here.
    styleLoaders += '!postcss!sass?sourceMap&' +
    'includePaths[]=' + bourbon + '&' +
    'includePaths[]=' + neat;

    if (CLIENT) {
        styleLoaders = ExtractTextPlugin.extract('style', styleLoaders);
    }

    styleLoader.loader = styleLoaders;

    webpackConfig.module.loaders.push(styleLoader);

    // Post CSS webpackConfig
    webpackConfig.postcss = [
        autoprefixer({
            browsers: ['last 2 version']
        })
    ];

    // FILE LOADERS
    webpackConfig.module.loaders.push({
        test: /\.(png|svg)$/,
        loader: 'url-loader?limit=100000'
    });

    webpackConfig.module.loaders.push({
        test: /\.(jpg)$/,
        loader: 'file-loader'
    });

    webpackConfig.module.loaders.push(jsonLoader);

    /**
    * Resolve
    */
    webpackConfig.resolve = {
        fallback: [
            path.join(__dirname, '../../node_modules')
        ],
        extensions: ['', '.js', '.css', '.scss']
    };

    webpackConfig.resolveLoader = {
        root: [
            path.join(process.cwd(), 'node_modules'),
            path.join(__dirname, '../../node_modules')
        ]
    };

    /**
    * Plugins
    */
    webpackConfig.plugins = [];

    if (CLIENT) {
        webpackConfig.plugins.push(
            new webpack.IgnorePlugin(/^config$/)
        );
    }

    webpackConfig.plugins.push(
        new ExtractTextPlugin('[name].[hash].css', {
            disable: CLIENT && DEV
        })
    );

    webpackConfig.plugins.push(
        // process.env.NODE_ENV is used by React and some other libs to determine what to run
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(ENV),
            '__DEV__': DEV,
            '__TEST__': TEST,
            '__DIST__': DIST,
            '__SERVER__': SERVER,
            '__CLIENT__': CLIENT,
            'ROC_SERVER_ENTRY': JSON.stringify(options.entry),
            'ROC_PATH_RESOLVER': JSON.stringify(resolver),
            'COMPONENT_BUILD': COMPONENT_BUILD
        })
    );

    if (DIST) {
        webpackConfig.plugins.push(function() {
            this.plugin('done', writeStats);
        });
    }

    if (DEV && CLIENT) {
        webpackConfig.plugins.push(
            new webpack.optimize.OccurenceOrderPlugin(),
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoErrorsPlugin()
        );
    }

    if (DIST) {
        webpackConfig.plugins.push(
            new webpack.optimize.DedupePlugin(),
            new webpack.optimize.OccurenceOrderPlugin()
        );
    }

    if (DIST && CLIENT) {
        webpackConfig.plugins.push(
            new webpack.optimize.UglifyJsPlugin({
                /* eslint-disable */
                compress: {
                    warnings: false,
                    screw_ie8: true,
                    drop_debugger: true
                }
                /* eslint-enable */
            })
        );
    }

    // FIXME
    if (CLIENT && DEV && !TEST) {
        webpackConfig.plugins.push(
            new BrowserSyncPlugin({
                host: 'localhost',
                port: 3002,
                logFileChanges: false,
                ui: {
                    port:3003
                }
            }, {
                reload: false
            })
        );
    }

    if (COMPONENT_BUILD) {
        webpackConfig.output.libraryTarget = 'umd';
    }

    return {
        config: webpackConfig,
        build: webpack
    };
}
<commit_msg>Made component name from build static<commit_after>import { getDevPath } from './utils/dev';
import webpack from 'webpack';
import path from 'path';

import autoprefixer from 'autoprefixer';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import BrowserSyncPlugin from 'browser-sync-webpack-plugin';
import writeStats from './utils/write-stats';

const bourbon = './node_modules/bourbon/app/assets/stylesheets/';
const neat = './node_modules/bourbon-neat/app/assets/stylesheets/';

/* resolver: should be a path to a file that will return the final new NODE_PATH
 */
export default function createBuilder(options, resolver = 'roc-web/lib/get-resolve-path') {
    const allowedModes = ['dev', 'test', 'dist'];
    const allowedTargets = ['server', 'client'];

    if (allowedModes.indexOf(options.mode) === -1) {
        throw new Error(`Invalid mode, must be one of ${allowedModes}. Was instead ${options.mode}.`);
    }

    if (allowedTargets.indexOf(options.target) === -1) {
        throw new Error(`Invalid target, must be one of ${allowedTargets}. Was instead ${options.target}.`);
    }

    if (!options.outputPath) {
        throw new Error('A output path needs to be defined in the options.');
    }

    const DEV = (options.mode === 'dev');
    const TEST = (options.mode === 'test');
    const DIST = (options.mode === 'dist');

    const SERVER = (options.target === 'server');
    const CLIENT = (options.target === 'client');

    const COMPONENT_BUILD = !!options.componentBuild;

    const ENV = DIST ? 'production' : 'development';

    let webpackConfig = {};

    webpackConfig.bail = true;

    /**
    * Entry
    */
    if (SERVER) {
        webpackConfig.entry = {
            app: [
                require.resolve('../../app/server-entry')
            ]
        };
    }

    /**
    * Target
    */
    if (SERVER) {
        webpackConfig.target = 'node';
    }

    const devPath = getDevPath({
        buildPath: options.outputPath
    });

    if (SERVER) {
        webpackConfig.externals = [
            {
                [resolver]: true
            },
            function(context, request, callback) {
                // If a roc module include it in the bundle
                if (request.substr(0, 4) === 'roc-') {
                    return callback();
                }

                // If a normal node_module mark it as external
                if (/^[a-zA-Z\-0-9]{1}.*$/.test(request)) {
                    return callback(null, true);
                }

                // Everything else should be included, that will be relative and absolute paths
                callback();
            }
        ];
    }

    /**
    * Devtool
    *
    * TODO: Consider tweaking this option & handle production correct
    * We want the source map files to be stored on a seperate server.
    */
    if (CLIENT && DEV) {
        webpackConfig.devtool = 'cheap-module-inline-source-map';
    } else if (CLIENT && TEST) {
        webpackConfig.devtool = 'inline-source-map';
    } else {
        webpackConfig.devtool = 'source-map';
    }

    /**
    * Output
    */
    if (TEST) {
        webpackConfig.output = {};
    } else {
        webpackConfig.output = {
            path: options.outputPath.absolute,
            publicPath: DIST ? '/' : devPath,
            filename: (DIST && CLIENT) ? '[name].[hash].js' : '[name].bundle.js',
            chunkFilename: (DIST && CLIENT) ? '[name].[hash].js' : '[name].bundle.js'
        };
    }

    if (SERVER) {
        webpackConfig.output.libraryTarget = 'commonjs2';
    }

    if (CLIENT && DEV) {
        webpackConfig.output.filename = '[name].client.bundle.js';
    }

    /**
    * Loaders
    */

    // Base
    webpackConfig.module = {
        preLoaders: [],
        loaders: []
    };

    // ISPARTA LOADER
    if (TEST) {
        webpackConfig.module.loaders.push({
            test: /\.js$/,
            loader: 'babel-loader',
            // FIXME
            include: [
                /tests/,
                /karma/
            ]
        });
        webpackConfig.module.preLoaders.push({
            test: /\.js$/,
            loader: 'isparta-loader',
            // FIXME
            exclude: [
                /node_modules/,
                /tests/,
                /karma/,
                /src\/vendor/
            ]
        });
    }

    // JS LOADER
    const jsLoader = {
        test: /\.js$/,
        loader: 'babel-loader',
        include: function(absPath) {
            /* This function will look at the absolute path for the current file
             * to determine if it should be processed by the babel-loader.
             *
             * What this does exactly is that is finds the last match of "roc-X/SOMETHING".
             * If SOMETHING is "node_modules" it will ignore it otherwise process it using
             * babel.
             */
            const regexp = /(roc-[^/]*)\/([^/]*)/g;
            let match, matches = [];
            while ((match = regexp.exec(absPath))) {
                matches.push({ roc: match[0], next: match[1] });
            }
            const last = matches[matches.length - 1];
            if (last.next !== 'node_modules') {
                // We want to process this with babel-loader
                return true;
            }
        },
        exclude: [
            /node_modules/
        ]
    };

    if (!TEST) {
        webpackConfig.module.loaders.push(jsLoader);
    }

    // STYLE LOADER
    const styleLoader = {
        test: /\.scss$/
    };

    // JSON LOADER
    const jsonLoader = {
        test: /\.json$/,
        loader: 'json-loader'
    };

    let styleLoaders = 'css-loader';

    if (SERVER) {
        styleLoaders += '/locals';
    }

    styleLoaders += '?sourceMap&module&importLoaders=1&localIdentName=';

    // Define how the class names should be defined
    if (DIST) {
        styleLoaders += '[hash:base64:5]';
    } else {
        styleLoaders += '[path]_[name]__[local]___[hash:base64:5]';
    }

    // We can add an external sass dependecie here.
    styleLoaders += '!postcss!sass?sourceMap&' +
    'includePaths[]=' + bourbon + '&' +
    'includePaths[]=' + neat;

    if (CLIENT) {
        styleLoaders = ExtractTextPlugin.extract('style', styleLoaders);
    }

    styleLoader.loader = styleLoaders;

    webpackConfig.module.loaders.push(styleLoader);

    // Post CSS webpackConfig
    webpackConfig.postcss = [
        autoprefixer({
            browsers: ['last 2 version']
        })
    ];

    // FILE LOADERS
    webpackConfig.module.loaders.push({
        test: /\.(png|svg)$/,
        loader: 'url-loader?limit=100000'
    });

    webpackConfig.module.loaders.push({
        test: /\.(jpg)$/,
        loader: 'file-loader'
    });

    webpackConfig.module.loaders.push(jsonLoader);

    /**
    * Resolve
    */
    webpackConfig.resolve = {
        fallback: [
            path.join(__dirname, '../../node_modules')
        ],
        extensions: ['', '.js', '.css', '.scss']
    };

    webpackConfig.resolveLoader = {
        root: [
            path.join(process.cwd(), 'node_modules'),
            path.join(__dirname, '../../node_modules')
        ]
    };

    /**
    * Plugins
    */
    webpackConfig.plugins = [];

    if (CLIENT) {
        webpackConfig.plugins.push(
            new webpack.IgnorePlugin(/^config$/)
        );
    }

    webpackConfig.plugins.push(
        new ExtractTextPlugin('[name].[hash].css', {
            disable: CLIENT && DEV
        })
    );

    webpackConfig.plugins.push(
        // process.env.NODE_ENV is used by React and some other libs to determine what to run
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify(ENV),
            '__DEV__': DEV,
            '__TEST__': TEST,
            '__DIST__': DIST,
            '__SERVER__': SERVER,
            '__CLIENT__': CLIENT,
            'ROC_SERVER_ENTRY': JSON.stringify(options.entry),
            'ROC_PATH_RESOLVER': JSON.stringify(resolver),
            'COMPONENT_BUILD': COMPONENT_BUILD
        })
    );

    if (DIST) {
        webpackConfig.plugins.push(function() {
            this.plugin('done', writeStats);
        });
    }

    if (DEV && CLIENT) {
        webpackConfig.plugins.push(
            new webpack.optimize.OccurenceOrderPlugin(),
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoErrorsPlugin()
        );
    }

    if (DIST) {
        webpackConfig.plugins.push(
            new webpack.optimize.DedupePlugin(),
            new webpack.optimize.OccurenceOrderPlugin()
        );
    }

    if (DIST && CLIENT) {
        webpackConfig.plugins.push(
            new webpack.optimize.UglifyJsPlugin({
                /* eslint-disable */
                compress: {
                    warnings: false,
                    screw_ie8: true,
                    drop_debugger: true
                }
                /* eslint-enable */
            })
        );
    }

    // FIXME
    if (CLIENT && DEV && !TEST) {
        webpackConfig.plugins.push(
            new BrowserSyncPlugin({
                host: 'localhost',
                port: 3002,
                logFileChanges: false,
                ui: {
                    port:3003
                }
            }, {
                reload: false
            })
        );
    }

    if (COMPONENT_BUILD) {
        webpackConfig.output.libraryTarget = 'umd';
        webpackConfig.output.filename = '[name].component.js';
    }

    return {
        config: webpackConfig,
        build: webpack
    };
}
<|endoftext|>


<commit_before>import winston from 'winston';
import ConfigLoader from './config_loader';
import SiteVisitor from './site_visitor';
import TaskRunner from './task_runner';

/**
 * Represents the whole application.
 */
export default class {
    constructor(configPath) {
        /**
         * Path of the config file the application works with.
         *
         * @type {String}
         * @private
         */
        this._configPath = configPath;

        /**
         * @type {SiteVisitor|null}
         * @private
         */
        this._siteVisitor = null;

        /**
         * @type {ConfigLoader|null}
         * @private
         */
        this._configLoader = null;

        /**
         * @type {winston.Logger}
         * @private
         */
        this._logger = null;

        /**
         * @type {TaskRunner|null}
         * @private
         */
        this._taskRunner = null;

        /**
         * Application configs object.
         *
         * @type {null}
         * @private
         */
        this._config = null;

        /**
         * Indicates if the application is running or not.
         *
         * @type {boolean}
         * @private
         */
        this._isRunning = false;
    }

    /**
     * Runs the application.
     *
     * @returns {Promise}
     */
    run() {
        if (this._isRunning) {
            return Promise.reject(new Error('The application is already running.'));
        }

        return this._loadConfigs()
            .then(this._createLogger.bind(this))
            .then(this._prepareSiteVisitor.bind(this))
            .then(this._scheduleVisits.bind(this))
            .then(() => {
                this._isRunning = true;
                this._logger.info('[Application] The application is running.');
            });
    }

    /**
     * Stops the application.
     *
     * @returns {Promise}
     */
    stop() {
        if (!this._isRunning) {
            return Promise.reject(new Error('The application was not running.'));
        }

        return this._taskRunner.stop()
            .then(() => {
                this._taskRunner = null;
            })
            .then(() => {
                return this._siteVisitor.disconnect();
            })
            .then(() => {
                this._isRunning = false;
                this._logger.info('[Application] The application is stopped.');
            });
    }

    /**
     * Loads and parses configuration file.
     *
     * The loaded config will be available via this._config once the returned
     * promise becomes resolved.
     *
     * @returns {Promise}
     * @private
     */
    _loadConfigs() {
        if (!this._configLoader) {
            this._configLoader = new ConfigLoader();
        }

        return this._configLoader.load(this._configPath)
            .then(config => {
                this._config = config;
            });
    }

    /**
     * Prepare site visitor to work with requests.
     *
     * A ready to use will be available via this._siteVisitor once the
     * returned promise becomes resolved.
     *
     * @returns {Promise}
     * @private
     */
    _prepareSiteVisitor() {
        if (!this._siteVisitor) {
            this._siteVisitor = new SiteVisitor(this._logger);
        }

        return this._siteVisitor.connect(
            this._config.auth.email,
            this._config.auth.password
        );
    }

    /**
     * Creates the logger.
     *
     * A ready to use logger will be available as this._logger once the returned
     * promise becomes resolved.
     *
     * @returns {Promise}
     * @private
     */
    _createLogger() {
        if (!this._logger) {
            this._logger = new winston.Logger({
                transports: [
                    // Make sure the timestamp is included into the log
                    new winston.transports.Console({ timestamp: true })
                ]
            });
        }

        return Promise.resolve();
    }

    /**
     * Initiate visit processes.
     *
     * @returns {Promise}
     * @private
     */
    _scheduleVisits() {
        const sites = ['https://stackoverflow.com'].concat(
            this._config.sites.stackoverflow.map(site => {
                return `https://${site}.stackoverflow.com`;
            }),
            this._config.sites.stackexchange.map(site => {
                return `https://${site}.stackexchange.com`;
            })
        );

        this._taskRunner = new TaskRunner(() => {
            this._siteVisitor.visit(sites);
        }, 24 * 60 * 60);

        return this._taskRunner.start();
    }
}
<commit_msg>Visit target sites 6 times a day<commit_after>import winston from 'winston';
import ConfigLoader from './config_loader';
import SiteVisitor from './site_visitor';
import TaskRunner from './task_runner';

/**
 * Represents the whole application.
 */
export default class {
    constructor(configPath) {
        /**
         * Path of the config file the application works with.
         *
         * @type {String}
         * @private
         */
        this._configPath = configPath;

        /**
         * @type {SiteVisitor|null}
         * @private
         */
        this._siteVisitor = null;

        /**
         * @type {ConfigLoader|null}
         * @private
         */
        this._configLoader = null;

        /**
         * @type {winston.Logger}
         * @private
         */
        this._logger = null;

        /**
         * @type {TaskRunner|null}
         * @private
         */
        this._taskRunner = null;

        /**
         * Application configs object.
         *
         * @type {null}
         * @private
         */
        this._config = null;

        /**
         * Indicates if the application is running or not.
         *
         * @type {boolean}
         * @private
         */
        this._isRunning = false;
    }

    /**
     * Runs the application.
     *
     * @returns {Promise}
     */
    run() {
        if (this._isRunning) {
            return Promise.reject(new Error('The application is already running.'));
        }

        return this._loadConfigs()
            .then(this._createLogger.bind(this))
            .then(this._prepareSiteVisitor.bind(this))
            .then(this._scheduleVisits.bind(this))
            .then(() => {
                this._isRunning = true;
                this._logger.info('[Application] The application is running.');
            });
    }

    /**
     * Stops the application.
     *
     * @returns {Promise}
     */
    stop() {
        if (!this._isRunning) {
            return Promise.reject(new Error('The application was not running.'));
        }

        return this._taskRunner.stop()
            .then(() => {
                this._taskRunner = null;
            })
            .then(() => {
                return this._siteVisitor.disconnect();
            })
            .then(() => {
                this._isRunning = false;
                this._logger.info('[Application] The application is stopped.');
            });
    }

    /**
     * Loads and parses configuration file.
     *
     * The loaded config will be available via this._config once the returned
     * promise becomes resolved.
     *
     * @returns {Promise}
     * @private
     */
    _loadConfigs() {
        if (!this._configLoader) {
            this._configLoader = new ConfigLoader();
        }

        return this._configLoader.load(this._configPath)
            .then(config => {
                this._config = config;
            });
    }

    /**
     * Prepare site visitor to work with requests.
     *
     * A ready to use will be available via this._siteVisitor once the
     * returned promise becomes resolved.
     *
     * @returns {Promise}
     * @private
     */
    _prepareSiteVisitor() {
        if (!this._siteVisitor) {
            this._siteVisitor = new SiteVisitor(this._logger);
        }

        return this._siteVisitor.connect(
            this._config.auth.email,
            this._config.auth.password
        );
    }

    /**
     * Creates the logger.
     *
     * A ready to use logger will be available as this._logger once the returned
     * promise becomes resolved.
     *
     * @returns {Promise}
     * @private
     */
    _createLogger() {
        if (!this._logger) {
            this._logger = new winston.Logger({
                transports: [
                    // Make sure the timestamp is included into the log
                    new winston.transports.Console({ timestamp: true })
                ]
            });
        }

        return Promise.resolve();
    }

    /**
     * Initiate visit processes.
     *
     * @returns {Promise}
     * @private
     */
    _scheduleVisits() {
        const sites = ['https://stackoverflow.com'].concat(
            this._config.sites.stackoverflow.map(site => {
                return `https://${site}.stackoverflow.com`;
            }),
            this._config.sites.stackexchange.map(site => {
                return `https://${site}.stackexchange.com`;
            })
        );

        // Visit all target sites 6 times a day. In this we're sure the visit
        // will be counted by SO.
        this._taskRunner = new TaskRunner(() => {
            this._siteVisitor.visit(sites);
        }, 4 * 60 * 60);

        return this._taskRunner.start();
    }
}
<|endoftext|>


<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org
 *
 * Audio Mngt Objects
 *
 *
 */
(function () {
    /**
     * There is no constructor function for me.audio.
     * @namespace me.audio
     * @memberOf me
     */
    me.audio = (function () {
        /*
         * PRIVATE STUFF
         */

        // hold public stuff in our singleton
        var api = {};

        // audio channel list
        var audioTracks = {};

        // current music
        var current_track_id = null;

        // a retry counter
        var retry_counter = 0;

        /**
         * event listener callback on load error
         * @ignore
         */
        function soundLoadError(sound_name, onerror_cb) {
            // check the retry counter
            if (retry_counter++ > 3) {
                // something went wrong
                var errmsg = "melonJS: failed loading " + sound_name;
                if (me.sys.stopOnAudioError === false) {
                    // disable audio
                    me.audio.disable();
                    // call error callback if defined
                    if (onerror_cb) {
                        onerror_cb();
                    }
                    // warning
                    console.log(errmsg + ", disabling audio");
                }
                else {
                    // throw an exception and stop everything !
                    throw new api.Error(errmsg);
                }
            // else try loading again !
            }
            else {
                audioTracks[sound_name].load();
            }
        }

        /*
         * PUBLIC STUFF
         */

        /**
         * Base class for Audio exception handling.
         * @name Error
         * @class
         * @memberOf me.audio
         * @constructor
         * @param {String} msg Error message.
         */
        api.Error = me.Error.extend({
            init : function (msg) {
                this._super(me.Error, "init", [ msg ]);
                this.name = "me.audio.Error";
            }
        });

        /**
         * initialize the audio engine

         * the melonJS loader will try to load audio files corresponding to the
         * browser supported audio format

         * if no compatible audio codecs are found, audio will be disabled
         * @name init
         * @memberOf me.audio
         * @public
         * @function
         * @param {String}
         *          audioFormat audio format provided ("mp3, ogg, m4a, wav")
         * @return {Boolean} Indicates whether audio initialization was successful
         * @example
         * // initialize the "sound engine", giving "mp3" and "ogg" as desired audio format
         * // i.e. on Safari, the loader will load all audio.mp3 files,
         * // on Opera the loader will however load audio.ogg files
         * if (!me.audio.init("mp3,ogg")) {
         *     alert("Sorry but your browser does not support html 5 audio !");
         *     return;
         * }
         */
        api.init = function (audioFormat) {
            if (!me.initialized) {
                throw new api.Error("me.audio.init() called before engine initialization.");
            }
            // if no param is given to init we use mp3 by default
            audioFormat = typeof audioFormat === "string" ? audioFormat : "mp3";
            // convert it into an array
            this.audioFormats = audioFormat.split(",");

            return !Howler.noAudio;
        };

        /**
         * enable audio output

         * only useful if audio supported and previously disabled through
         *
         * @see me.audio#disable
         * @name enable
         * @memberOf me.audio
         * @public
         * @function
         */
        api.enable = function () {
            this.unmuteAll();
        };

        /**
         * disable audio output
         *
         * @name disable
         * @memberOf me.audio
         * @public
         * @function
         */
        api.disable = function () {
            this.muteAll();
        };

        /**
         * Load an audio file.

         *

         * sound item must contain the following fields :

         * - name    : name of the sound

         * - src     : source path

         * @ignore
         */
        api.load = function (sound, onload_cb, onerror_cb) {
            var urls = [];
            if (typeof(this.audioFormats) === "undefined" || this.audioFormats.length === 0) {
                throw new api.Error("target audio extension(s) should be set through me.audio.init() before calling the preloader.");
            }
            for (var i = 0; i < this.audioFormats.length; i++) {
                urls.push(sound.src + sound.name + "." + this.audioFormats[i] + me.loader.nocache);
            }
            audioTracks[sound.name] = new Howl({
                src : urls,
                volume : Howler.volume(),
                onloaderror : function () {
                    audioTracks[sound.name] = this;
                    soundLoadError.call(me.audio, sound.name, onerror_cb);
                },
                onload : function () {
                    audioTracks[sound.name] = this;
                    retry_counter = 0;
                    if (onload_cb) {
                        onload_cb();
                    }
                }
            });

            return 1;
        };

        /**
         * play the specified sound
         * @name play
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Boolean} [loop=false] loop audio
         * @param {Function} [onend] Function to call when sound instance ends playing.
         * @param {Number} [volume=default] Float specifying volume (0.0 - 1.0 values accepted).
         * @return {Number} the sound instance ID.
         * @example
         * // play the "cling" audio clip
         * me.audio.play("cling");
         * // play & repeat the "engine" audio clip
         * me.audio.play("engine", true);
         * // play the "gameover_sfx" audio clip and call myFunc when finished
         * me.audio.play("gameover_sfx", false, myFunc);
         * // play the "gameover_sfx" audio clip with a lower volume level
         * me.audio.play("gameover_sfx", false, null, 0.5);
         */
        api.play = function (sound_name, loop, onend, volume) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                var instance_id = sound.play();
                if (typeof loop === "boolean") {
                    // arg[0] can take different types in howler 2.0
                    sound.loop(loop, instance_id);
                }
                sound.volume(typeof(volume) === "number" ? volume.clamp(0.0, 1.0) : Howler.volume(), instance_id);
                if (typeof(onend) === "function") {
                    if (loop === true) {
                        sound.on("end", onend, instance_id);
                    }
                    else {
                        sound.once("end", onend, instance_id);
                    }
                }
                return instance_id;
            }
        };

        /**
         * Fade a currently playing sound between two volumee.
         * @name fade
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} from Volume to fade from (0.0 to 1.0).
         * @param {Number} to Volume to fade to (0.0 to 1.0).
         * @param {Number} duration Time in milliseconds to fade.
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will fade.
         */
        api.fade = function (sound_name, from, to, duration, instance_id) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                sound.fade(from, to, duration, instance_id);
            }
        };

        /**
         * stop the specified sound on all channels
         * @name stop
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will stop.
         * @example
         * me.audio.stop("cling");
         */
        api.stop = function (sound_name, instance_id) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                sound.stop(instance_id);
                // remove the defined onend callback (if any defined)
                sound.off("end", instance_id);
            }
        };

        /**
         * pause the specified sound on all channels

         * this function does not reset the currentTime property
         * @name pause
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will pause.
         * @example
         * me.audio.pause("cling");
         */
        api.pause = function (sound_name, instance_id) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                sound.pause(instance_id);
            }
        };

        /**
         * play the specified audio track

         * this function automatically set the loop property to true

         * and keep track of the current sound being played.
         * @name playTrack
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio track name - case sensitive
         * @param {Number} [volume=default] Float specifying volume (0.0 - 1.0 values accepted).
         * @return {Number} the sound instance ID.
         * @example
         * me.audio.playTrack("awesome_music");
         */
        api.playTrack = function (sound_name, volume) {
            current_track_id = sound_name;
            return me.audio.play(
                current_track_id,
                true,
                null,
                volume
            );
        };

        /**
         * stop the current audio track
         *
         * @see me.audio#playTrack
         * @name stopTrack
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * // play a awesome music
         * me.audio.playTrack("awesome_music");
         * // stop the current music
         * me.audio.stopTrack();
         */
        api.stopTrack = function () {
            if (current_track_id !== null) {
                audioTracks[current_track_id].stop();
                current_track_id = null;
            }
        };

        /**
         * pause the current audio track
         *
         * @name pauseTrack
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * me.audio.pauseTrack();
         */
        api.pauseTrack = function () {
            if (current_track_id !== null) {
                audioTracks[current_track_id].pause();
            }
        };

        /**
         * resume the previously paused audio track
         *
         * @name resumeTrack
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * // play an awesome music
         * me.audio.playTrack("awesome_music");
         * // pause the audio track
         * me.audio.pauseTrack();
         * // resume the music
         * me.audio.resumeTrack();
         */
        api.resumeTrack = function () {
            if (current_track_id !== null) {
                audioTracks[current_track_id].play();
            }
        };

        /**
         * returns the current track Id
         * @name getCurrentTrack
         * @memberOf me.audio
         * @public
         * @function
         * @return {String} audio track name
         */
        api.getCurrentTrack = function () {
            return current_track_id;
        };

        /**
         * set the default global volume
         * @name setVolume
         * @memberOf me.audio
         * @public
         * @function
         * @param {Number} volume Float specifying volume (0.0 - 1.0 values accepted).
         */
        api.setVolume = function (volume) {
            Howler.volume(volume);
        };

        /**
         * get the default global volume
         * @name getVolume
         * @memberOf me.audio
         * @public
         * @function
         * @returns {Number} current volume value in Float [0.0 - 1.0] .
         */
        api.getVolume = function () {
            return Howler.volume();
        };

        /**
         * mute the specified sound
         * @name mute
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will mute.
         */
        api.mute = function (sound_name, instance_id, mute) {
            // if not defined : true
            mute = (typeof(mute) === "undefined" ? true : !!mute);
            var sound = audioTracks[sound_name];
            if (sound && typeof(sound) !== "undefined") {
                sound.mute(mute, instance_id);
            }
        };

        /**
         * unmute the specified sound
         * @name unmute
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will unmute.
         */
        api.unmute = function (sound_name, instance_id) {
            api.mute(sound_name, instance_id, false);
        };

        /**
         * mute all audio
         * @name muteAll
         * @memberOf me.audio
         * @public
         * @function
         */
        api.muteAll = function () {
            Howler.mute(true);
        };

        /**
         * unmute all audio
         * @name unmuteAll
         * @memberOf me.audio
         * @public
         * @function
         */
        api.unmuteAll = function () {
            Howler.mute(false);
        };

        /**
         * unload specified audio track to free memory
         *
         * @name unload
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio track name - case sensitive
         * @return {Boolean} true if unloaded
         * @example
         * me.audio.unload("awesome_music");
         */
        api.unload = function (sound_name) {
            sound_name = sound_name;
            if (!(sound_name in audioTracks)) {
                return false;
            }

            // destroy the Howl object
            audioTracks[sound_name].unload();
            if (typeof(audioTracks[sound_name].dispose) === "function") {
                // cocoonJS implements a dispose function to free
                // corresponding allocated audio in memory
                audioTracks[sound_name].dispose();
            }
            delete audioTracks[sound_name];
            return true;
        };

        /**
         * unload all audio to free memory
         *
         * @name unloadAll
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * me.audio.unloadAll();
         */
        api.unloadAll = function () {
            for (var sound_name in audioTracks) {
                if (audioTracks.hasOwnProperty(sound_name)) {
                    api.unload(sound_name);
                }
            }
        };

        // return our object
        return api;
    })();
})();
<commit_msg>audio: Workaround a bug in Opera<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2015, Olivier Biot, Jason Oster, Aaron McLeod
 * http://www.melonjs.org
 *
 * Audio Mngt Objects
 *
 *
 */
(function () {
    /**
     * There is no constructor function for me.audio.
     * @namespace me.audio
     * @memberOf me
     */
    me.audio = (function () {
        /*
         * PRIVATE STUFF
         */

        // hold public stuff in our singleton
        var api = {};

        // audio channel list
        var audioTracks = {};

        // current music
        var current_track_id = null;

        // a retry counter
        var retry_counter = 0;

        /**
         * event listener callback on load error
         * @ignore
         */
        function soundLoadError(sound_name, onerror_cb) {
            // check the retry counter
            if (retry_counter++ > 3) {
                // something went wrong
                var errmsg = "melonJS: failed loading " + sound_name;
                if (me.sys.stopOnAudioError === false) {
                    // disable audio
                    me.audio.disable();
                    // call error callback if defined
                    if (onerror_cb) {
                        onerror_cb();
                    }
                    // warning
                    console.log(errmsg + ", disabling audio");
                }
                else {
                    // throw an exception and stop everything !
                    throw new api.Error(errmsg);
                }
            // else try loading again !
            }
            else {
                audioTracks[sound_name].load();
            }
        }

        /*
         * PUBLIC STUFF
         */

        /**
         * Base class for Audio exception handling.
         * @name Error
         * @class
         * @memberOf me.audio
         * @constructor
         * @param {String} msg Error message.
         */
        api.Error = me.Error.extend({
            init : function (msg) {
                this._super(me.Error, "init", [ msg ]);
                this.name = "me.audio.Error";
            }
        });

        /**
         * initialize the audio engine

         * the melonJS loader will try to load audio files corresponding to the
         * browser supported audio format

         * if no compatible audio codecs are found, audio will be disabled
         * @name init
         * @memberOf me.audio
         * @public
         * @function
         * @param {String}
         *          audioFormat audio format provided ("mp3, ogg, m4a, wav")
         * @return {Boolean} Indicates whether audio initialization was successful
         * @example
         * // initialize the "sound engine", giving "mp3" and "ogg" as desired audio format
         * // i.e. on Safari, the loader will load all audio.mp3 files,
         * // on Opera the loader will however load audio.ogg files
         * if (!me.audio.init("mp3,ogg")) {
         *     alert("Sorry but your browser does not support html 5 audio !");
         *     return;
         * }
         */
        api.init = function (audioFormat) {
            if (!me.initialized) {
                throw new api.Error("me.audio.init() called before engine initialization.");
            }
            // if no param is given to init we use mp3 by default
            audioFormat = typeof audioFormat === "string" ? audioFormat : "mp3";
            // convert it into an array
            this.audioFormats = audioFormat.split(",");

            // XXX: workaround https://github.com/goldfire/howler.js/issues/328
            if (me.device.ua.includes("OPR/")) {
                this.audioFormats = this.audioFormats.filter(function (f) {
                    return f !== "mp3";
                });
                if (!this.audioFormats.length) {
                    this.audioFormats.push("ogg");
                }
            }

            return !Howler.noAudio;
        };

        /**
         * enable audio output

         * only useful if audio supported and previously disabled through
         *
         * @see me.audio#disable
         * @name enable
         * @memberOf me.audio
         * @public
         * @function
         */
        api.enable = function () {
            this.unmuteAll();
        };

        /**
         * disable audio output
         *
         * @name disable
         * @memberOf me.audio
         * @public
         * @function
         */
        api.disable = function () {
            this.muteAll();
        };

        /**
         * Load an audio file.

         *

         * sound item must contain the following fields :

         * - name    : name of the sound

         * - src     : source path

         * @ignore
         */
        api.load = function (sound, onload_cb, onerror_cb) {
            var urls = [];
            if (typeof(this.audioFormats) === "undefined" || this.audioFormats.length === 0) {
                throw new api.Error("target audio extension(s) should be set through me.audio.init() before calling the preloader.");
            }
            for (var i = 0; i < this.audioFormats.length; i++) {
                urls.push(sound.src + sound.name + "." + this.audioFormats[i] + me.loader.nocache);
            }
            audioTracks[sound.name] = new Howl({
                src : urls,
                volume : Howler.volume(),
                onloaderror : function () {
                    audioTracks[sound.name] = this;
                    soundLoadError.call(me.audio, sound.name, onerror_cb);
                },
                onload : function () {
                    audioTracks[sound.name] = this;
                    retry_counter = 0;
                    if (onload_cb) {
                        onload_cb();
                    }
                }
            });

            return 1;
        };

        /**
         * play the specified sound
         * @name play
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Boolean} [loop=false] loop audio
         * @param {Function} [onend] Function to call when sound instance ends playing.
         * @param {Number} [volume=default] Float specifying volume (0.0 - 1.0 values accepted).
         * @return {Number} the sound instance ID.
         * @example
         * // play the "cling" audio clip
         * me.audio.play("cling");
         * // play & repeat the "engine" audio clip
         * me.audio.play("engine", true);
         * // play the "gameover_sfx" audio clip and call myFunc when finished
         * me.audio.play("gameover_sfx", false, myFunc);
         * // play the "gameover_sfx" audio clip with a lower volume level
         * me.audio.play("gameover_sfx", false, null, 0.5);
         */
        api.play = function (sound_name, loop, onend, volume) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                var instance_id = sound.play();
                if (typeof loop === "boolean") {
                    // arg[0] can take different types in howler 2.0
                    sound.loop(loop, instance_id);
                }
                sound.volume(typeof(volume) === "number" ? volume.clamp(0.0, 1.0) : Howler.volume(), instance_id);
                if (typeof(onend) === "function") {
                    if (loop === true) {
                        sound.on("end", onend, instance_id);
                    }
                    else {
                        sound.once("end", onend, instance_id);
                    }
                }
                return instance_id;
            }
        };

        /**
         * Fade a currently playing sound between two volumee.
         * @name fade
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} from Volume to fade from (0.0 to 1.0).
         * @param {Number} to Volume to fade to (0.0 to 1.0).
         * @param {Number} duration Time in milliseconds to fade.
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will fade.
         */
        api.fade = function (sound_name, from, to, duration, instance_id) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                sound.fade(from, to, duration, instance_id);
            }
        };

        /**
         * stop the specified sound on all channels
         * @name stop
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will stop.
         * @example
         * me.audio.stop("cling");
         */
        api.stop = function (sound_name, instance_id) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                sound.stop(instance_id);
                // remove the defined onend callback (if any defined)
                sound.off("end", instance_id);
            }
        };

        /**
         * pause the specified sound on all channels

         * this function does not reset the currentTime property
         * @name pause
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will pause.
         * @example
         * me.audio.pause("cling");
         */
        api.pause = function (sound_name, instance_id) {
            var sound = audioTracks[sound_name];
            if (sound && typeof sound !== "undefined") {
                sound.pause(instance_id);
            }
        };

        /**
         * play the specified audio track

         * this function automatically set the loop property to true

         * and keep track of the current sound being played.
         * @name playTrack
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio track name - case sensitive
         * @param {Number} [volume=default] Float specifying volume (0.0 - 1.0 values accepted).
         * @return {Number} the sound instance ID.
         * @example
         * me.audio.playTrack("awesome_music");
         */
        api.playTrack = function (sound_name, volume) {
            current_track_id = sound_name;
            return me.audio.play(
                current_track_id,
                true,
                null,
                volume
            );
        };

        /**
         * stop the current audio track
         *
         * @see me.audio#playTrack
         * @name stopTrack
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * // play a awesome music
         * me.audio.playTrack("awesome_music");
         * // stop the current music
         * me.audio.stopTrack();
         */
        api.stopTrack = function () {
            if (current_track_id !== null) {
                audioTracks[current_track_id].stop();
                current_track_id = null;
            }
        };

        /**
         * pause the current audio track
         *
         * @name pauseTrack
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * me.audio.pauseTrack();
         */
        api.pauseTrack = function () {
            if (current_track_id !== null) {
                audioTracks[current_track_id].pause();
            }
        };

        /**
         * resume the previously paused audio track
         *
         * @name resumeTrack
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * // play an awesome music
         * me.audio.playTrack("awesome_music");
         * // pause the audio track
         * me.audio.pauseTrack();
         * // resume the music
         * me.audio.resumeTrack();
         */
        api.resumeTrack = function () {
            if (current_track_id !== null) {
                audioTracks[current_track_id].play();
            }
        };

        /**
         * returns the current track Id
         * @name getCurrentTrack
         * @memberOf me.audio
         * @public
         * @function
         * @return {String} audio track name
         */
        api.getCurrentTrack = function () {
            return current_track_id;
        };

        /**
         * set the default global volume
         * @name setVolume
         * @memberOf me.audio
         * @public
         * @function
         * @param {Number} volume Float specifying volume (0.0 - 1.0 values accepted).
         */
        api.setVolume = function (volume) {
            Howler.volume(volume);
        };

        /**
         * get the default global volume
         * @name getVolume
         * @memberOf me.audio
         * @public
         * @function
         * @returns {Number} current volume value in Float [0.0 - 1.0] .
         */
        api.getVolume = function () {
            return Howler.volume();
        };

        /**
         * mute the specified sound
         * @name mute
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name - case sensitive
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will mute.
         */
        api.mute = function (sound_name, instance_id, mute) {
            // if not defined : true
            mute = (typeof(mute) === "undefined" ? true : !!mute);
            var sound = audioTracks[sound_name];
            if (sound && typeof(sound) !== "undefined") {
                sound.mute(mute, instance_id);
            }
        };

        /**
         * unmute the specified sound
         * @name unmute
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio clip name
         * @param {Number} [id] the sound instance ID. If none is passed, all sounds in group will unmute.
         */
        api.unmute = function (sound_name, instance_id) {
            api.mute(sound_name, instance_id, false);
        };

        /**
         * mute all audio
         * @name muteAll
         * @memberOf me.audio
         * @public
         * @function
         */
        api.muteAll = function () {
            Howler.mute(true);
        };

        /**
         * unmute all audio
         * @name unmuteAll
         * @memberOf me.audio
         * @public
         * @function
         */
        api.unmuteAll = function () {
            Howler.mute(false);
        };

        /**
         * unload specified audio track to free memory
         *
         * @name unload
         * @memberOf me.audio
         * @public
         * @function
         * @param {String} sound_name audio track name - case sensitive
         * @return {Boolean} true if unloaded
         * @example
         * me.audio.unload("awesome_music");
         */
        api.unload = function (sound_name) {
            sound_name = sound_name;
            if (!(sound_name in audioTracks)) {
                return false;
            }

            // destroy the Howl object
            audioTracks[sound_name].unload();
            if (typeof(audioTracks[sound_name].dispose) === "function") {
                // cocoonJS implements a dispose function to free
                // corresponding allocated audio in memory
                audioTracks[sound_name].dispose();
            }
            delete audioTracks[sound_name];
            return true;
        };

        /**
         * unload all audio to free memory
         *
         * @name unloadAll
         * @memberOf me.audio
         * @public
         * @function
         * @example
         * me.audio.unloadAll();
         */
        api.unloadAll = function () {
            for (var sound_name in audioTracks) {
                if (audioTracks.hasOwnProperty(sound_name)) {
                    api.unload(sound_name);
                }
            }
        };

        // return our object
        return api;
    })();
})();
<|endoftext|>


<commit_before>cordova.define('cordova/plugin_list', function(require, exports, module) {
module.exports = [
    {
        "file": "plugins/phonegap-plugin-push/www/push.js",
        "id": "phonegap-plugin-push.PushNotification",
        "pluginId": "phonegap-plugin-push",
        "clobbers": [
            "PushNotification"
        ]
    },
    {
        "file": "plugins/cordova-plugin-whitelist/whitelist.js",
        "id": "cordova-plugin-whitelist.whitelist",
        "pluginId": "cordova-plugin-whitelist",
        "runs": true
    }
];
module.exports.metadata =
// TOP OF METADATA
{}
// BOTTOM OF METADATA
});
<commit_msg>plugin order change, (automatically changed after some cordova operations)<commit_after>cordova.define('cordova/plugin_list', function(require, exports, module) {
module.exports = [
    {
        "file": "plugins/cordova-plugin-whitelist/whitelist.js",
        "id": "cordova-plugin-whitelist.whitelist",
        "pluginId": "cordova-plugin-whitelist",
        "runs": true
    },
    {
        "file": "plugins/phonegap-plugin-push/www/push.js",
        "id": "phonegap-plugin-push.PushNotification",
        "pluginId": "phonegap-plugin-push",
        "clobbers": [
            "PushNotification"
        ]
    }
];
module.exports.metadata =
// TOP OF METADATA
{}
// BOTTOM OF METADATA
});<|endoftext|>


<commit_before>(function(){
var currentVisibleDropdown;

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

  className: "fact-block",

  events: {
    "click a.remove": "removeFactFromChannel",
    "click li.destroy": "destroyFact",
	  "click .controls li.supporting,.controls li.weakening": "toggleEvidence"
  },
  initialize: function(opts) {
    this.useTemplate('facts','_fact');
    this.model.bind('destroy', this.remove, this);

    if ( opts.tmpl ) {
      this.tmpl = opts.tmpl;
    }

    $(this.el).attr('data-fact-id', this.model.id);
  },

  render: function() {
    $( this.el )
      .html( Mustache.to_html(this.tmpl, this.model.toJSON(), this.partials)).factlink();

    this.initAddToChannel();
    this.initializeFactRelationsViews();

    return this;
  },

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

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

  removeFactFromChannel: function() {
    this.model.destroy({
      error: function() {
        alert("Error while removing Factlink from Channel" );
      },
      forChannel: true
    });
  },

  destroyFact: function() {
    this.model.destroy({
      error: function() {
        alert("Error while destroying the Factlink" );
      },
      forChannel: false
    });
  },

  initAddToChannel: function() {
    if ( $(this.el).find('.channel-listing') && typeof currentUser !== "undefined" ) {

      var addToChannelView = new AddToChannelView({
        collection: currentUser.channels,

        el: $(this.el).find('.channel-listing'),

        model: this.model,

        forFact: this.model
      }).render();

      // Channels are in the container
      $('.add-to-channel', this.el)
        .hoverIntent(function(e) {
          addToChannelView.el.fadeIn("fast");
        }, function() {
          addToChannelView.el.delay(600).fadeOut("fast");
        });
    }
  },

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

    this.supportingFactRelationsView = new FactRelationsView({collection: supportingFactRelations});
    this.weakeningFactRelationsView = new FactRelationsView({collection: weakeningFactRelations});

    $('.dropdown-container', this.el).append(this.supportingFactRelationsView.render().el);
    $('.dropdown-container', this.el).append(this.weakeningFactRelationsView.render().el);
  },

  showDropdownContainer: function(className) {
    if (typeof currentVisibleDropdown === "undefined") {
      console.info( "Showing dropdownContainer" );
      $('.dropdown-container', this.el).slideDown('fast');
    }

    $(this.el).addClass("active");
  },

  hideDropdownContainer: function(className) {
    $(this.el).removeClass("active");
    console.info( "Hiding dropdownContainer" );

    $('.dropdown-container', this.el).slideUp('fast');
  },

  switchToRelationDropdown: function(type){
    if (type === "supporting") {
      this.weakeningFactRelationsView.hide();
      this.supportingFactRelationsView.showAndFetch();
    } else {
      this.supportingFactRelationsView.hide();
      this.weakeningFactRelationsView.showAndFetch();
    }
  },

  toggleEvidence: function(e) {
    var $target = $(e.target).closest('li');
    var $tabButtons = $(this.el).find('.controls li');
    var type = $target.hasClass('supporting') ? 'supporting' : 'weakening';

    $tabButtons.removeClass("active");

    if ( type !== currentVisibleDropdown ) {
      this.showDropdownContainer(type);

      currentVisibleDropdown = type;

      this.switchToRelationDropdown(type);
      $target.addClass("active");
    } else {
      this.hideDropdownContainer();

      currentVisibleDropdown = undefined;
    }

  }
});
})();
<commit_msg>no slide but hide, will look at it later<commit_after>(function(){
var currentVisibleDropdown;

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

  className: "fact-block",

  events: {
    "click a.remove": "removeFactFromChannel",
    "click li.destroy": "destroyFact",
	  "click .controls li.supporting,.controls li.weakening": "toggleEvidence"
  },
  initialize: function(opts) {
    this.useTemplate('facts','_fact');
    this.model.bind('destroy', this.remove, this);

    if ( opts.tmpl ) {
      this.tmpl = opts.tmpl;
    }

    $(this.el).attr('data-fact-id', this.model.id);
  },

  render: function() {
    $( this.el )
      .html( Mustache.to_html(this.tmpl, this.model.toJSON(), this.partials)).factlink();

    this.initAddToChannel();
    this.initializeFactRelationsViews();

    return this;
  },

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

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

  removeFactFromChannel: function() {
    this.model.destroy({
      error: function() {
        alert("Error while removing Factlink from Channel" );
      },
      forChannel: true
    });
  },

  destroyFact: function() {
    this.model.destroy({
      error: function() {
        alert("Error while destroying the Factlink" );
      },
      forChannel: false
    });
  },

  initAddToChannel: function() {
    if ( $(this.el).find('.channel-listing') && typeof currentUser !== "undefined" ) {

      var addToChannelView = new AddToChannelView({
        collection: currentUser.channels,

        el: $(this.el).find('.channel-listing'),

        model: this.model,

        forFact: this.model
      }).render();

      // Channels are in the container
      $('.add-to-channel', this.el)
        .hoverIntent(function(e) {
          addToChannelView.el.fadeIn("fast");
        }, function() {
          addToChannelView.el.delay(600).fadeOut("fast");
        });
    }
  },

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

    this.supportingFactRelationsView = new FactRelationsView({collection: supportingFactRelations});
    this.weakeningFactRelationsView = new FactRelationsView({collection: weakeningFactRelations});

    $('.dropdown-container', this.el).append(this.supportingFactRelationsView.render().el);
    $('.dropdown-container', this.el).append(this.weakeningFactRelationsView.render().el);
  },

  showDropdownContainer: function(className) {
    if (typeof currentVisibleDropdown === "undefined") {
      console.info( "Showing dropdownContainer" );
      $('.dropdown-container', this.el).show();
    }

    $(this.el).addClass("active");
  },

  hideDropdownContainer: function(className) {
    $(this.el).removeClass("active");
    console.info( "Hiding dropdownContainer" );

    $('.dropdown-container', this.el).hide();
  },

  switchToRelationDropdown: function(type){
    if (type === "supporting") {
      this.weakeningFactRelationsView.hide();
      this.supportingFactRelationsView.showAndFetch();
    } else {
      this.supportingFactRelationsView.hide();
      this.weakeningFactRelationsView.showAndFetch();
    }
  },

  toggleEvidence: function(e) {
    var $target = $(e.target).closest('li');
    var $tabButtons = $(this.el).find('.controls li');
    var type = $target.hasClass('supporting') ? 'supporting' : 'weakening';

    $tabButtons.removeClass("active");

    if ( type !== currentVisibleDropdown ) {
      this.showDropdownContainer(type);

      currentVisibleDropdown = type;

      this.switchToRelationDropdown(type);
      $target.addClass("active");
    } else {
      this.hideDropdownContainer();

      currentVisibleDropdown = undefined;
    }

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


<commit_before>'use strict';

var _                    = require('mano').i18n.bind('View: User')
  , startsWith           = require('es5-ext/string/#/starts-with')
  , uncapitalize         = require('es5-ext/string/#/uncapitalize')
  , loginDialog          = require('./components/login-dialog')
  , registerDialog       = require('./components/register-dialog')
  , modalContainer       = require('./components/modal-container')
  , roleMenuItem         = require('./components/role-menu-item')
  , requestAccountDialog = require('./components/request-account-dialog')
  , greedy               = require('./utils/greedy-menu')
  , db                   = require('../db');

exports._parent = require('./base');

var myAccountButton = function (user, roleTitle) {
	return form({ method: 'post', action: '/change-business-process/' },
		input({ type: 'hidden',
			name: user.__id__ + '/currentBusinessProcess', value: null }),
		button({ type: 'submit' }, roleTitle));
};

exports.menu = function () {
	modalContainer.append(loginDialog);
	modalContainer.append(registerDialog(this));

	insert(_if(this.user._isDemo,
		div(
			{ class: 'submitted-menu-demo-info-wrapper' },
			ul({ class: 'header-top-menu-demo' },
				li(a({ class: 'demo-public-out', href: '/logout/', rel: 'server' }, _("Out of demo mode"))),
				li(a({ class: 'demo-public-login', href: '#login' }, _("Log in")))),
			div({ class: 'submitted-menu-demo-info' },
				p(_("Did this demo convinced you?")),
				a({ href: '#register' }, _("Create account")))
		),
		ul(
			{ class: 'header-top-menu' },
			list(exports._menuItems, function (item) { return item.call(this); }.bind(this))
		)));
};

exports.main = function () {
	div({ class: 'submitted-menu' },
		div({ class: 'submitted-menu-bar content' },
			this.user._currentRoleResolved.map(function (role) {
				var greedyElement = nav({ class: 'greedy-menu' },
					button({ class: 'toggle-links' }, i({ class: 'fa fa-bars' })),
					ul({ class: 'submitted-menu-items greedy-menu-items', id: 'submitted-menu' },
						exports._submittedMenu.call(this))
					);
				greedy({ element: greedyElement, counter: true });
				return greedyElement;
			}.bind(this)),
			_if(this.user._isDemo, div({ class: 'submitted-menu-demo' },
				a({ class: 'submitted-menu-demo-ribon' }, _("Demo"))))));

	div({ id: 'sub-main-prepend' },
		insert(_if(this.user._isDemo,
			div({ class: 'submitted-menu-demo-msg' },
				div({ class: 'content' },
					h3(_("Demo version")),
					p(_("Introduction to demo version")))))),

		insert(_if(this.manager, function () {
			return this.manager._currentlyManagedUser.map(function (managedUser) {
				if (!managedUser) return;
				var isUserReallyManaged = eq(this.manager, managedUser._manager);

				requestAccountDialog(managedUser);

				return div({ class: 'manager-bar' },
					div({ class: 'content' },
						div({ class: 'manager-bar-info' },
							span(_("Client"), ": "),
								this.appName === 'user' ? a({ href: '/' }, managedUser._fullName)
								: myAccountButton(this.manager, managedUser._fullName)),
						_if(isUserReallyManaged, div({ class: 'manager-bar-actions' },
							_if(not(managedUser._isActiveAccount),
								a({
									class: 'actions-create',
									href: '#request-create-account'
								}, span(_('Create account for this client')))),
							a({ href: '/managed-user-profile/' },
								span({ class: 'hint-optional hint-optional-left',
										'data-hint': _('edit user details') },
									i({ class: 'fa fa-cog' })))))));
			}.bind(this));
		}.bind(this))),

		insert(exports._subMainPrependExtraItems.call(this)));

	div({ class: 'user-forms', id: 'sub-main' });
};

exports._submittedMenu = function () {
	var user = this.manager || this.user, isOfficialRole;
	// user.currentRoleResolved may not be resolved yet...
	if (!user.currentRoleResolved) {
		return;
	}
	if (user.currentRoleResolved === 'statistics') {
		return [li({ id: 'dashboard-nav' }, a({ href: '/' }, _("Dashboard"))),
			li({ id: 'files-nav' }, a({ href: '/files/' }, _("Files"))),
			li({ id: 'time-nav' }, a({ href: '/time/' }, _("Time")))];
	}

	isOfficialRole = user.officialRoles.has(user.currentRoleResolved);
	return isOfficialRole ? list(user.officialRoles, exports._getSubmittedMenuItem.bind(this)) :
			exports._getSubmittedMenuItem.call(this, user.currentRoleResolved);
};

exports._getSubmittedMenuItem = function (role) {
	var user      = this.manager || this.user
	  , appName   = this.appName
	  , roleTitle = db.Role.meta[role].label
	  , viewPath, pending, pendingCount;

	if (role === 'user' && startsWith.call(appName, 'business-process-')) {
		return li(myAccountButton(user, roleTitle));
	}

	if (startsWith.call(role, 'official')) {
		viewPath = exports._getPendingViewPath.call(this, role);

		if (viewPath) {
			pending  = db.views.businessProcesses.getBySKeyPath(viewPath);

			if (pending && pending.pending) {
				pendingCount = pending.pending._totalSize;
			} else {
				pendingCount = '-';
			}
		} else {
			pendingCount = '-';
		}

		if (user.currentRoleResolved === role) {
			return li({ class: 'submitted-menu-item-active' }, a({ href: '/' }, roleTitle,
				' (', pendingCount, ')'));
		}

		return li(form({ method: 'post', action: '/set-role/' },
			input({ type: 'hidden', name: user.__id__ + '/currentRole', value: role }),
			button({ type: 'submit' }, roleTitle, ' (', pendingCount, ')')));
	}

	if (user.currentRoleResolved === role) {
		if (user.currentRoleResolved === 'manager') {
			if (appName === 'manager' || appName === 'manager-registration') {
				return li({ class: 'submitted-menu-item-active' }, a({ href: '/' }, roleTitle));
			}
			return li({ class: 'submitted-menu-item-active' },
				exports._getManagerButton(user, roleTitle));
		}
		return li({ class: 'submitted-menu-item-active' }, a({ href: '/' }, roleTitle));
	}

	return li(form({ method: 'post', action: '/set-role/' },
		input({ type: 'hidden', name: user.__id__ + '/currentRole', value: role }),
		button({ type: 'submit' }, roleTitle)));
};

exports._getPendingViewPath = function (role) {
	return uncapitalize.call(role.slice('official'.length));
};

exports._subMainPrependExtraItems = Function.prototype;

exports._extraRoleLabel = function () {
	return _if(or(this.manager, eq(this.user._currentRoleResolved, 'manager')), li(
		span(
			{ class: 'manager-label' },
			_("Notary")
		)
	));
};

exports._getManagerButton = function (user, roleTitle) {
	return form({ method: 'post', action: '/change-currently-managed-user/' },
		input({ type: 'hidden',
			name: user.__id__ + '/currentBusinessProcess', value: null }),
		input({ type: 'hidden',
			name: user.__id__ + '/currentlyManagedUser', value: null }),
		button({ type: 'submit' }, roleTitle));
};

var userNameMenuItem = function () {
	var user         = this.manager || this.user;

	return [
		li(
			{ id: "drop-down-menu", class: "header-top-dropdown-container" },
			a(span({ class: 'header-top-user-name header-top-dropdown-button' },
				user._fullName,
				i({ id: 'drop-down-menu-angle', class: 'fa fa-angle-down header-top-dropdown-button' }))),
			ul(
				{ class: "header-top-menu-dropdown-content" },
				_if(user.officialRoles._size, user._currentRoleResolved.map(function (role) {
					if (!role) return;

					if (!db.Role.isOfficialRole(role)) {
						return [
							li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
							li(form({ method: 'post', action: '/set-role/' },
								input({ type: 'hidden', name: user.__id__ + '/currentRole',
									value: user.officialRoles.first }),
								button({ type: 'submit' }, _("Roles"))))];
					}
					return [
						li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
						li({ class: 'header-top-menu-dropdown-item-active' },
							a({ href: '/' }, _("Roles")))];
				})),
				_if(or(user.roles._has('user'), user.roles._has('manager')), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'user'),
					roleMenuItem(this, 'manager')
				]),
				_if(or(user.roles._has('inspector'), user.roles._has('supervisor'),
						user.roles._has('dispatcher'), user.roles._has('managerValidation')), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'dispatcher'),
					roleMenuItem(this, 'inspector'),
					roleMenuItem(this, 'supervisor'),
					roleMenuItem(this, 'managerValidation')
				]),
				_if(user.roles._has('statistics'), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'statistics')
				]),
				_if(or(user.roles._has('metaAdmin'), user.roles._has('usersAdmin')), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'metaAdmin'),
					roleMenuItem(this, 'usersAdmin')
				]),
				li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
				li(
					a(
						{ href: '/profile/' },
						_("My informations")
					)
				),
				li(
					a(
						{ href: '/logout/', rel: 'server' },
						_("Log out")
					)
				)
			)
		),
		script(function () {
			var dropDownMenu      = $('drop-down-menu')
			  , dropDownMenuAngle = $('drop-down-menu-angle');

			dropDownMenu.onclick = function () {
				if (dropDownMenu.hasClass("header-top-menu-opened")) {
					dropDownMenu.removeClass("header-top-menu-opened");
					dropDownMenuAngle.removeClass("fa-angle-up");
					dropDownMenuAngle.addClass("fa-angle-down");
				} else {
					dropDownMenu.addClass("header-top-menu-opened");
					dropDownMenuAngle.addClass("fa-angle-up");
					dropDownMenuAngle.removeClass("fa-angle-down");
				}
			};

			document.onclick = function (event) {
				var evt = event || window.event;
				var clicked = null;
				if (typeof evt.target !== 'undefined') {
					clicked = $(evt.target);
				} else {
					clicked = $(evt.srcElement);
				}
				if (!clicked.hasClass('header-top-dropdown-button')) {
					dropDownMenu.removeClass("header-top-menu-opened");
					dropDownMenuAngle.removeClass("fa-angle-up");
					dropDownMenuAngle.addClass("fa-angle-down");
				}
			};
		})
	];
};

exports._menuItems = [
	exports._extraRoleLabel,
	userNameMenuItem
];
<commit_msg>Update eregistrations package<commit_after>'use strict';

var _                    = require('mano').i18n.bind('View: User')
  , startsWith           = require('es5-ext/string/#/starts-with')
  , uncapitalize         = require('es5-ext/string/#/uncapitalize')
  , loginDialog          = require('./components/login-dialog')
  , registerDialog       = require('./components/register-dialog')
  , modalContainer       = require('./components/modal-container')
  , roleMenuItem         = require('./components/role-menu-item')
  , requestAccountDialog = require('./components/request-account-dialog')
  , greedy               = require('./utils/greedy-menu')
  , db                   = require('../db');

exports._parent = require('./base');

var myAccountButton = function (user, roleTitle) {
	return form({ method: 'post', action: '/change-business-process/' },
		input({ type: 'hidden',
			name: user.__id__ + '/currentBusinessProcess', value: null }),
		button({ type: 'submit' }, roleTitle));
};

exports.menu = function () {
	modalContainer.append(loginDialog);
	modalContainer.append(registerDialog(this));

	insert(_if(this.user._isDemo,
		div(
			{ class: 'submitted-menu-demo-info-wrapper' },
			ul({ class: 'header-top-menu-demo' },
				li(a({ class: 'demo-public-out', href: '/logout/', rel: 'server' }, _("Out of demo mode"))),
				li(a({ class: 'demo-public-login', href: '#login' }, _("Log in")))),
			div({ class: 'submitted-menu-demo-info' },
				p(_("Did this demo convinced you?")),
				a({ href: '#register' }, _("Create account")))
		),
		ul(
			{ class: 'header-top-menu' },
			list(exports._menuItems, function (item) { return item.call(this); }.bind(this))
		)));
};

exports.main = function () {
	div({ class: 'submitted-menu' },
		div({ class: 'submitted-menu-bar content' },
			this.user._currentRoleResolved.map(function (role) {
				var greedyElement = nav({ class: 'greedy-menu' },
					button({ class: 'toggle-links' }, i({ class: 'fa fa-bars' })),
					ul({ class: 'submitted-menu-items greedy-menu-items', id: 'submitted-menu' },
						exports._submittedMenu.call(this))
					);
				greedy({ element: greedyElement, counter: true });
				return greedyElement;
			}.bind(this)),
			_if(this.user._isDemo, div({ class: 'submitted-menu-demo' },
				a({ class: 'submitted-menu-demo-ribon' }, _("Demo"))))));

	div({ id: 'sub-main-prepend' },
		insert(_if(this.user._isDemo,
			div({ class: 'submitted-menu-demo-msg' },
				div({ class: 'content' },
					exports._demoBannerContent.call(this))))),

		insert(_if(this.manager, function () {
			return this.manager._currentlyManagedUser.map(function (managedUser) {
				if (!managedUser) return;
				var isUserReallyManaged = eq(this.manager, managedUser._manager);

				requestAccountDialog(managedUser);

				return div({ class: 'manager-bar' },
					div({ class: 'content' },
						div({ class: 'manager-bar-info' },
							span(_("Client"), ": "),
								this.appName === 'user' ? a({ href: '/' }, managedUser._fullName)
								: myAccountButton(this.manager, managedUser._fullName)),
						_if(isUserReallyManaged, div({ class: 'manager-bar-actions' },
							_if(not(managedUser._isActiveAccount),
								a({
									class: 'actions-create',
									href: '#request-create-account'
								}, span(_('Create account for this client')))),
							a({ href: '/managed-user-profile/' },
								span({ class: 'hint-optional hint-optional-left',
										'data-hint': _('edit user details') },
									i({ class: 'fa fa-cog' })))))));
			}.bind(this));
		}.bind(this))),

		insert(exports._subMainPrependExtraItems.call(this)));

	div({ class: 'user-forms', id: 'sub-main' });
};

exports._submittedMenu = function () {
	var user = this.manager || this.user, isOfficialRole;
	// user.currentRoleResolved may not be resolved yet...
	if (!user.currentRoleResolved) {
		return;
	}
	if (user.currentRoleResolved === 'statistics') {
		return [li({ id: 'dashboard-nav' }, a({ href: '/' }, _("Dashboard"))),
			li({ id: 'files-nav' }, a({ href: '/files/' }, _("Files"))),
			li({ id: 'time-nav' }, a({ href: '/time/' }, _("Time")))];
	}

	isOfficialRole = user.officialRoles.has(user.currentRoleResolved);
	return isOfficialRole ? list(user.officialRoles, exports._getSubmittedMenuItem.bind(this)) :
			exports._getSubmittedMenuItem.call(this, user.currentRoleResolved);
};

exports._getSubmittedMenuItem = function (role) {
	var user      = this.manager || this.user
	  , appName   = this.appName
	  , roleTitle = db.Role.meta[role].label
	  , viewPath, pending, pendingCount;

	if (role === 'user' && startsWith.call(appName, 'business-process-')) {
		return li(myAccountButton(user, roleTitle));
	}

	if (startsWith.call(role, 'official')) {
		viewPath = exports._getPendingViewPath.call(this, role);

		if (viewPath) {
			pending  = db.views.businessProcesses.getBySKeyPath(viewPath);

			if (pending && pending.pending) {
				pendingCount = pending.pending._totalSize;
			} else {
				pendingCount = '-';
			}
		} else {
			pendingCount = '-';
		}

		if (user.currentRoleResolved === role) {
			return li({ class: 'submitted-menu-item-active' }, a({ href: '/' }, roleTitle,
				' (', pendingCount, ')'));
		}

		return li(form({ method: 'post', action: '/set-role/' },
			input({ type: 'hidden', name: user.__id__ + '/currentRole', value: role }),
			button({ type: 'submit' }, roleTitle, ' (', pendingCount, ')')));
	}

	if (user.currentRoleResolved === role) {
		if (user.currentRoleResolved === 'manager') {
			if (appName === 'manager' || appName === 'manager-registration') {
				return li({ class: 'submitted-menu-item-active' }, a({ href: '/' }, roleTitle));
			}
			return li({ class: 'submitted-menu-item-active' },
				exports._getManagerButton(user, roleTitle));
		}
		return li({ class: 'submitted-menu-item-active' }, a({ href: '/' }, roleTitle));
	}

	return li(form({ method: 'post', action: '/set-role/' },
		input({ type: 'hidden', name: user.__id__ + '/currentRole', value: role }),
		button({ type: 'submit' }, roleTitle)));
};

exports._getPendingViewPath = function (role) {
	return uncapitalize.call(role.slice('official'.length));
};

exports._subMainPrependExtraItems = Function.prototype;

exports._extraRoleLabel = function () {
	return _if(or(this.manager, eq(this.user._currentRoleResolved, 'manager')), li(
		span(
			{ class: 'manager-label' },
			_("Notary")
		)
	));
};

exports._getManagerButton = function (user, roleTitle) {
	return form({ method: 'post', action: '/change-currently-managed-user/' },
		input({ type: 'hidden',
			name: user.__id__ + '/currentBusinessProcess', value: null }),
		input({ type: 'hidden',
			name: user.__id__ + '/currentlyManagedUser', value: null }),
		button({ type: 'submit' }, roleTitle));
};

var userNameMenuItem = function () {
	var user         = this.manager || this.user;

	return [
		li(
			{ id: "drop-down-menu", class: "header-top-dropdown-container" },
			a(span({ class: 'header-top-user-name header-top-dropdown-button' },
				user._fullName,
				i({ id: 'drop-down-menu-angle', class: 'fa fa-angle-down header-top-dropdown-button' }))),
			ul(
				{ class: "header-top-menu-dropdown-content" },
				_if(user.officialRoles._size, user._currentRoleResolved.map(function (role) {
					if (!role) return;

					if (!db.Role.isOfficialRole(role)) {
						return [
							li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
							li(form({ method: 'post', action: '/set-role/' },
								input({ type: 'hidden', name: user.__id__ + '/currentRole',
									value: user.officialRoles.first }),
								button({ type: 'submit' }, _("Roles"))))];
					}
					return [
						li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
						li({ class: 'header-top-menu-dropdown-item-active' },
							a({ href: '/' }, _("Roles")))];
				})),
				_if(or(user.roles._has('user'), user.roles._has('manager')), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'user'),
					roleMenuItem(this, 'manager')
				]),
				_if(or(user.roles._has('inspector'), user.roles._has('supervisor'),
						user.roles._has('dispatcher'), user.roles._has('managerValidation')), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'dispatcher'),
					roleMenuItem(this, 'inspector'),
					roleMenuItem(this, 'supervisor'),
					roleMenuItem(this, 'managerValidation')
				]),
				_if(user.roles._has('statistics'), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'statistics')
				]),
				_if(or(user.roles._has('metaAdmin'), user.roles._has('usersAdmin')), [
					li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
					roleMenuItem(this, 'metaAdmin'),
					roleMenuItem(this, 'usersAdmin')
				]),
				li({ class: 'header-top-menu-dropdown-content-separator' }, hr()),
				li(
					a(
						{ href: '/profile/' },
						_("My informations")
					)
				),
				li(
					a(
						{ href: '/logout/', rel: 'server' },
						_("Log out")
					)
				)
			)
		),
		script(function () {
			var dropDownMenu      = $('drop-down-menu')
			  , dropDownMenuAngle = $('drop-down-menu-angle');

			dropDownMenu.onclick = function () {
				if (dropDownMenu.hasClass("header-top-menu-opened")) {
					dropDownMenu.removeClass("header-top-menu-opened");
					dropDownMenuAngle.removeClass("fa-angle-up");
					dropDownMenuAngle.addClass("fa-angle-down");
				} else {
					dropDownMenu.addClass("header-top-menu-opened");
					dropDownMenuAngle.addClass("fa-angle-up");
					dropDownMenuAngle.removeClass("fa-angle-down");
				}
			};

			document.onclick = function (event) {
				var evt = event || window.event;
				var clicked = null;
				if (typeof evt.target !== 'undefined') {
					clicked = $(evt.target);
				} else {
					clicked = $(evt.srcElement);
				}
				if (!clicked.hasClass('header-top-dropdown-button')) {
					dropDownMenu.removeClass("header-top-menu-opened");
					dropDownMenuAngle.removeClass("fa-angle-up");
					dropDownMenuAngle.addClass("fa-angle-down");
				}
			};
		})
	];
};

exports._menuItems = [
	exports._extraRoleLabel,
	userNameMenuItem
];

exports._demoBannerContent = function () {
	return [h3(_("Demo version")),
		p(_("Introduction to demo version"))];
};
<|endoftext|>


<commit_before>/**
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      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.
 */

module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: [
    '@typescript-eslint',
  ],
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended',
    'plugin:@typescript-eslint/eslint-recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended'
  ],
  rules: {
    'eqeqeq': 'error',
    '@typescript-eslint/explicit-function-return-type': 'off',
  }
}
<commit_msg>Remove extra eslintrc<commit_after><|endoftext|>