<commit_before>/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 */

'use strict';

var extensions;
var modules;
var tmpl;
var urlparser = require('./../modules/urlparser');
var urlVars = urlparser.urlVars;
var backboneEvents;

const semver = require('semver');
require("bootstrap");

module.exports = {

    /**
     *
     * @param o
     * @returns {exports}
     */
    set: function (o) {
        modules = o;
        backboneEvents = o.backboneEvents;
        return this;
    },

    /**
     *
     */
    init: function () {
        var me = this, configFile, stop = false;

        var loadConfig = function () {
            $.getJSON("/api/config/" + urlparser.db + "/" + configFile, function (data) {
                window.vidiConfig.brandName = data.brandName ? data.brandName : window.vidiConfig.brandName;
                window.vidiConfig.baseLayers = data.baseLayers ? data.baseLayers : window.vidiConfig.baseLayers;
                window.vidiConfig.enabledExtensions = data.enabledExtensions ? data.enabledExtensions : window.vidiConfig.enabledExtensions;
                window.vidiConfig.searchConfig = data.searchConfig ? data.searchConfig : window.vidiConfig.searchConfig;
                window.vidiConfig.aboutBox = data.aboutBox ? data.aboutBox : window.vidiConfig.aboutBox;
                window.vidiConfig.enabledSearch = data.enabledSearch ? data.enabledSearch : window.vidiConfig.enabledSearch;
                window.vidiConfig.schemata = data.schemata ? data.schemata : window.vidiConfig.schemata;
                window.vidiConfig.template = data.template ? data.template : window.vidiConfig.template;
                window.vidiConfig.enabledPrints = data.enabledPrints ? data.enabledPrints : window.vidiConfig.enabledPrints;
                window.vidiConfig.activateMainTab = data.activateMainTab ? data.activateMainTab : window.vidiConfig.activateMainTab;
                window.vidiConfig.extensionConfig = data.extensionConfig ? data.extensionConfig : window.vidiConfig.extensionConfig;
                window.vidiConfig.singleTiled = data.singleTiled ? data.singleTiled : window.vidiConfig.singleTiled;
                window.vidiConfig.doNotCloseLoadScreen = data.doNotCloseLoadScreen ? data.doNotCloseLoadScreen : window.vidiConfig.doNotCloseLoadScreen;
            }).fail(function () {
                console.log("Could not load: " + configFile);

                if (stop) {
                    me.render();
                    return;
                }

                if (window.vidiConfig.defaultConfig) {
                    configFile = window.vidiConfig.defaultConfig;
                    stop = true;
                    loadConfig();
                } else {
                    me.render();
                }
            }).always(function () {
                $.getJSON(`/app/${urlparser.db}/public/version.json`, function (data) {
                    window.vidiConfig.appVersion = data.version;
                    window.vidiConfig.appExtensionsBuild = '0';
                    if (`extensionsBuild` in data) {
                        window.vidiConfig.appExtensionsBuild = data.extensionsBuild;
                    }
                }).fail(function () {
                    console.error(`Unable to detect the current application version`);
                }).done(function () {
                    me.render();
                });
            });
        };

        if (urlVars.config) {
            configFile = urlVars.config;
        } else if (window.vidiConfig.autoLoadingConfig) {
            configFile = urlparser.db + ".json";
        } else if (window.vidiConfig.defaultConfig) {
            configFile = window.vidiConfig.defaultConfig;
        }

        if (configFile) {
            loadConfig();
        } else {
            me.render();
        }

    },

    /**
     *
     */
    render: function () {
        var me = this;

        // Render template and set some styling
        // ====================================

        if (typeof window.vidiConfig.template === "undefined") {
            tmpl = "default.tmpl";
        } else {
            tmpl = window.vidiConfig.template;
        }

        // Check if template is set in URL vars
        // ====================================

        if (typeof urlVars.tmpl !== "undefined") {
            var par = urlVars.tmpl.split("#");
            if (par.length > 1) {
                par.pop();
            }
            tmpl = par.join();
        }

        // If px and py is provided for print templates,
        // add the values to the dict before rendering
        // =============================================

        if (urlVars.px && urlVars.py) {
            gc2i18n.dict.printWidth = urlVars.px + "px";
            gc2i18n.dict.printHeight = urlVars.py + "px";
            gc2i18n.dict.printDataTime = decodeURIComponent(urlVars.td); // TODO typo
            gc2i18n.dict.printDateTime = decodeURIComponent(urlVars.td);
            gc2i18n.dict.printDate = decodeURIComponent(urlVars.d);
            window.vidiTimeout = 1000;
        } else {
            window.vidiTimeout = 0;
        }

        if (urlVars.l) {
            gc2i18n.dict._showLegend = urlVars.l;
        }
        gc2i18n.dict._showHeader = urlVars.h || "inline";
        gc2i18n.dict.brandName = window.vidiConfig.brandName;
        gc2i18n.dict.aboutBox = window.vidiConfig.aboutBox;

        // Render the page
        // ===============

        if (typeof Templates[tmpl] !== "undefined") {
            $("#main-container").html(Templates[tmpl].render(gc2i18n.dict));
            console.info("Using pre-processed template: " + tmpl);
            me.startApp();
        } else {
            $.get("/api/template/" + urlparser.db + "/" + tmpl, function (template) {
                var rendered = Mustache.render(template, gc2i18n.dict);
                $("#main-container").html(rendered);
                console.info("Loaded external template: " + tmpl);
                me.startApp();
            }).fail(function () {
                alert("Could not load template: " + tmpl);
            })
        }
    },

    /**
     *
     */
    startApp: function () {

        // Load style sheet
        //===================

        $('<link/>').attr({
            rel: 'stylesheet',
            type: 'text/css',
            href: '/css/styles.css'
        }).appendTo('head');

        // Add the tooltip div
        // ===================

        $("body").append('

');

        // Detect the database and schema
        let splitLocation = window.location.pathname.split(`/`);
        if (splitLocation.length === 4 || splitLocation.length === 5) {
            let database = splitLocation[2];
            let schema = splitLocation[3];
            if (!database || database.length === 0 || !schema || schema.length === 0) {
                console.warn(`Unable to detect current database and schema`);
            } else {
                window.vidiConfig.appDatabase = database;
                window.vidiConfig.appSchema = schema;
            }
        } else {
            console.warn(`Unable to detect current database and schema`);
        }

        // Init the modules
        // ================

        modules.cloud.init();
        modules.state.setExtent();

        // Calling mandatory init method
        [`backboneEvents`, `socketId`, `bindEvent`, `baseLayer`, `infoClick`,
            `advancedInfo`, `draw`, `measurements`, `stateSnapshots`, `print`, `layerTree`].map(name => {
            modules[name].init();
        });

        /**
         * Fetch meta > initialize settings > create layer tree >
         * initialize state > load layers > initialize extensions > finish
         */
        modules.meta.init().then(() => {
            return modules.setting.init();
        }, (error) => {
            console.log(error); // Stacktrace
            alert("Vidi is loaded without schema. Can't set extent or add layers");
            backboneEvents.get().trigger("ready:meta");
        }).then(() => {
            return modules.layerTree.create();
        }).finally(() => {
            modules.state.init().then(() => {

                try {

                // Require search module
                // =====================

                // Hack to compile Glob files. Don´t call this function!
                function ಠ_ಠ() {
                    require('./search/*.js', {glob: true});
                }

                if (typeof vidiConfig.searchModules !== "undefined") {
                    $.each(vidiConfig.searchModules, function (i, v) {
                        modules.search[v] = require('./search/' + v + '.js');
                        modules.search[v].set(modules);
                    });
                    modules.search[window.vidiConfig.enabledSearch].init();
                }

                // Require extensions modules
                // ==========================

                //Hack to compile Glob files. Don´t call this function!
                function ಠ_ಠ() {
                    require('./../../extensions/*/browser/*.js', {glob: true});
                    require('./../../extensions/*/browser/*/*.js', {glob: true});
                }

                if (typeof vidiConfig.extensions !== "undefined" && typeof vidiConfig.extensions.browser !== "undefined") {
                    $.each(vidiConfig.extensions.browser, function (i, v) {
                        modules.extensions[Object.keys(v)[0]] = {};
                        $.each(v[Object.keys(v)[0]], function (n, m) {
                            modules.extensions[Object.keys(v)[0]][m] = require('./../../extensions/' + Object.keys(v)[0] + '/browser/' + m + ".js");
                            modules.extensions[Object.keys(v)[0]][m].set(modules);
                        })
                    });

                    if (typeof window.vidiConfig.enabledExtensions === "object") {
                        $.each(vidiConfig.extensions.browser, function (i, v) {
                            $.each(v[Object.keys(v)[0]], function (n, m) {
                                if (window.vidiConfig.enabledExtensions.indexOf(Object.keys(v)[0]) > -1) {
                                    modules.extensions[Object.keys(v)[0]][m].init();
                                }
                            })
                        });
                    }
                }

                // Init some GUI stuff after modules are loaded
                // ============================================
                $("[data-toggle=tooltip]").tooltip();

                $.material.init();
                touchScroll(".tab-pane");
                touchScroll("#info-modal-body-wrapper");
                $("#loadscreentext").html(__("Loading data"));
                if (window.vidiConfig.activateMainTab) {
                    setTimeout(function () {
                        $('#main-tabs a[href="#' + window.vidiConfig.activateMainTab + '-content"]').tab('show');
                    }, 200);
                }

                $(window).resize(_.debounce(function () {
                    $("#myNavmenu").offcanvas('hide');
                    setTimeout(function () {
                        modules.cloud.get().map.invalidateSize();
                    }, 100);
                }, 0));

                } catch (e) {
                    console.error("Could not perform application initialization", e.message);
                }
            });
        });

        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('/service-worker.bundle.js').then((registration) => {
                console.log('Service worker registration succeeded');
            }).catch(error => {
                console.error(`Unable to register the service worker, please load the application over HTTPS in order to use its full functionality`);
            });
        } else {
            console.warn(`Service workers are not supported in this browser, some features may be unavailable`);
        }

        if (window.localforage) {
            localforage.getItem('appVersion').then(versionValue => {
                localforage.getItem('appExtensionsBuild').then(extensionsBuildValue => {
                    if (versionValue === null) {
                        localforage.setItem('appVersion', window.vidiConfig.appVersion).then(() => {
                            localforage.setItem('appExtensionsBuild', window.vidiConfig.appExtensionsBuild).then(() => {
                                console.log(`Versioning: setting new application version (${window.vidiConfig.appVersion}, ${window.vidiConfig.appExtensionsBuild})`);
                            });
                        }).catch(error => {
                            throw new Error(`Unable to store current application version`);
                        });
                    } else {
                        // If two versions are correctly detected
                        if (semver.valid(window.vidiConfig.appVersion) !== null && semver.valid(versionValue) !== null) {
                            if (semver.gt(window.vidiConfig.appVersion, versionValue) ||
                                (window.vidiConfig.appVersion === versionValue && window.vidiConfig.appExtensionsBuild !== extensionsBuildValue)) {
                                if (confirm(`Update application to the newest version (current: ${versionValue}, extensions: ${extensionsBuildValue}, latest: ${window.vidiConfig.appVersion}, extensions: ${window.vidiConfig.appExtensionsBuild})?`)) {
                                    let unregisteringRequests = [];

                                    // Unregister service worker
                                    navigator.serviceWorker.getRegistrations().then((registrations) => {
                                        for(let registration of registrations) {
                                            console.log(`Versioning: unregistering service worker`, registration);
                                            unregisteringRequests.push(registration.unregister());
                                            registration.unregister();
                                        }
                                    });

                                    Promise.all(unregisteringRequests).then((values) => {
                                        // Clear caches
                                        caches.keys().then(function(names) {
                                            for (let name of names) {
                                                console.log(`Versioning: clearing cache`, name);
                                                caches.delete(name);
                                            }
                                        });

                                        // Remove current app version
                                        localforage.removeItem('appVersion').then(() => {
                                            location.reload();
                                        });
                                    });
                                }
                            } else {
                                console.log('Versioning: new application version is not available');
                            }
                        } else if (semver.valid(value) === null) {
                            console.warn(`Seems like current application version is invalid, resetting it`);
                            localforage.setItem('appVersion', '1.0.0').then(() => {}).catch(error => {
                                localforage.setItem('appExtensionsBuild', '0').then(() => {}).catch(error => {
                                    throw new Error(`Unable to store current application version`);
                                });
                            });
                        }
                    }
                });
            });
        } else {
            throw new Error(`localforage is not available`);
        }
    }
};<commit_msg>Some bugs<commit_after>/**
 * @fileoverview Description of file, its uses and information
 * about its dependencies.
 */

'use strict';

var extensions;
var modules;
var tmpl;
var urlparser = require('./../modules/urlparser');
var urlVars = urlparser.urlVars;
var backboneEvents;

const semver = require('semver');
require("bootstrap");

module.exports = {

    /**
     *
     * @param o
     * @returns {exports}
     */
    set: function (o) {
        modules = o;
        backboneEvents = o.backboneEvents;
        return this;
    },

    /**
     *
     */
    init: function () {
        var me = this, configFile, stop = false;

        var loadConfig = function () {
            $.getJSON("/api/config/" + urlparser.db + "/" + configFile, function (data) {
                window.vidiConfig.brandName = data.brandName ? data.brandName : window.vidiConfig.brandName;
                window.vidiConfig.baseLayers = data.baseLayers ? data.baseLayers : window.vidiConfig.baseLayers;
                window.vidiConfig.enabledExtensions = data.enabledExtensions ? data.enabledExtensions : window.vidiConfig.enabledExtensions;
                window.vidiConfig.searchConfig = data.searchConfig ? data.searchConfig : window.vidiConfig.searchConfig;
                window.vidiConfig.aboutBox = data.aboutBox ? data.aboutBox : window.vidiConfig.aboutBox;
                window.vidiConfig.enabledSearch = data.enabledSearch ? data.enabledSearch : window.vidiConfig.enabledSearch;
                window.vidiConfig.schemata = data.schemata ? data.schemata : window.vidiConfig.schemata;
                window.vidiConfig.template = data.template ? data.template : window.vidiConfig.template;
                window.vidiConfig.enabledPrints = data.enabledPrints ? data.enabledPrints : window.vidiConfig.enabledPrints;
                window.vidiConfig.activateMainTab = data.activateMainTab ? data.activateMainTab : window.vidiConfig.activateMainTab;
                window.vidiConfig.extensionConfig = data.extensionConfig ? data.extensionConfig : window.vidiConfig.extensionConfig;
                window.vidiConfig.singleTiled = data.singleTiled ? data.singleTiled : window.vidiConfig.singleTiled;
                window.vidiConfig.doNotCloseLoadScreen = data.doNotCloseLoadScreen ? data.doNotCloseLoadScreen : window.vidiConfig.doNotCloseLoadScreen;
            }).fail(function () {
                console.log("Could not load: " + configFile);

                if (stop) {
                    me.render();
                    return;
                }

                if (window.vidiConfig.defaultConfig) {
                    configFile = window.vidiConfig.defaultConfig;
                    stop = true;
                    loadConfig();
                }
            }).always(function () {
                $.getJSON(`/app/${urlparser.db}/public/version.json`, function (data) {
                    window.vidiConfig.appVersion = data.version;
                    window.vidiConfig.appExtensionsBuild = '0';
                    if (`extensionsBuild` in data) {
                        window.vidiConfig.appExtensionsBuild = data.extensionsBuild;
                    }
                }).fail(function () {
                    console.error(`Unable to detect the current application version`);
                }).always(function () {
                    me.render();
                });
            });
        };

        if (urlVars.config) {
            configFile = urlVars.config;
        } else if (window.vidiConfig.autoLoadingConfig) {
            configFile = urlparser.db + ".json";
        } else if (window.vidiConfig.defaultConfig) {
            configFile = window.vidiConfig.defaultConfig;
        }

        if (configFile) {
            loadConfig();
        } else {
            me.render();
        }

    },

    /**
     *
     */
    render: function () {
        var me = this;

        // Render template and set some styling
        // ====================================

        if (typeof window.vidiConfig.template === "undefined") {
            tmpl = "default.tmpl";
        } else {
            tmpl = window.vidiConfig.template;
        }

        // Check if template is set in URL vars
        // ====================================

        if (typeof urlVars.tmpl !== "undefined") {
            var par = urlVars.tmpl.split("#");
            if (par.length > 1) {
                par.pop();
            }
            tmpl = par.join();
        }

        // If px and py is provided for print templates,
        // add the values to the dict before rendering
        // =============================================

        if (urlVars.px && urlVars.py) {
            gc2i18n.dict.printWidth = urlVars.px + "px";
            gc2i18n.dict.printHeight = urlVars.py + "px";
            gc2i18n.dict.printDataTime = decodeURIComponent(urlVars.td); // TODO typo
            gc2i18n.dict.printDateTime = decodeURIComponent(urlVars.td);
            gc2i18n.dict.printDate = decodeURIComponent(urlVars.d);
            window.vidiTimeout = 1000;
        } else {
            window.vidiTimeout = 0;
        }

        if (urlVars.l) {
            gc2i18n.dict._showLegend = urlVars.l;
        }
        gc2i18n.dict._showHeader = urlVars.h || "inline";
        gc2i18n.dict.brandName = window.vidiConfig.brandName;
        gc2i18n.dict.aboutBox = window.vidiConfig.aboutBox;

        // Render the page
        // ===============

        if (typeof Templates[tmpl] !== "undefined") {
            $("#main-container").html(Templates[tmpl].render(gc2i18n.dict));
            console.info("Using pre-processed template: " + tmpl);
            me.startApp();
        } else {
            $.get("/api/template/" + urlparser.db + "/" + tmpl, function (template) {
                var rendered = Mustache.render(template, gc2i18n.dict);
                $("#main-container").html(rendered);
                console.info("Loaded external template: " + tmpl);
                me.startApp();
            }).fail(function () {
                alert("Could not load template: " + tmpl);
            })
        }
    },

    /**
     *
     */
    startApp: function () {

        // Load style sheet
        //===================

        $('<link/>').attr({
            rel: 'stylesheet',
            type: 'text/css',
            href: '/css/styles.css'
        }).appendTo('head');

        // Add the tooltip div
        // ===================

        $("body").append('

');

        // Detect the database and schema
        let splitLocation = window.location.pathname.split(`/`);
        if (splitLocation.length === 4 || splitLocation.length === 5) {
            let database = splitLocation[2];
            let schema = splitLocation[3];
            if (!database || database.length === 0 || !schema || schema.length === 0) {
                console.warn(`Unable to detect current database and schema`);
            } else {
                window.vidiConfig.appDatabase = database;
                window.vidiConfig.appSchema = schema;
            }
        } else {
            console.warn(`Unable to detect current database and schema`);
        }

        // Init the modules
        // ================

        modules.cloud.init();
        modules.state.setExtent();

        // Calling mandatory init method
        [`backboneEvents`, `socketId`, `bindEvent`, `baseLayer`, `infoClick`,
            `advancedInfo`, `draw`, `measurements`, `stateSnapshots`, `print`, `layerTree`].map(name => {
            modules[name].init();
        });

        /**
         * Fetch meta > initialize settings > create layer tree >
         * initialize state > load layers > initialize extensions > finish
         */
        modules.meta.init().then(() => {
            return modules.setting.init();
        }, (error) => {
            console.log(error); // Stacktrace
            alert("Vidi is loaded without schema. Can't set extent or add layers");
            backboneEvents.get().trigger("ready:meta");
        }).then(() => {
            return modules.layerTree.create();
        }).finally(() => {
            modules.state.init().then(() => {

                try {

                // Require search module
                // =====================

                // Hack to compile Glob files. Don´t call this function!
                function ಠ_ಠ() {
                    require('./search/*.js', {glob: true});
                }

                if (typeof vidiConfig.searchModules !== "undefined") {
                    $.each(vidiConfig.searchModules, function (i, v) {
                        modules.search[v] = require('./search/' + v + '.js');
                        modules.search[v].set(modules);
                    });
                    modules.search[window.vidiConfig.enabledSearch].init();
                }

                // Require extensions modules
                // ==========================

                //Hack to compile Glob files. Don´t call this function!
                function ಠ_ಠ() {
                    require('./../../extensions/*/browser/*.js', {glob: true});
                    require('./../../extensions/*/browser/*/*.js', {glob: true});
                }

                if (typeof vidiConfig.extensions !== "undefined" && typeof vidiConfig.extensions.browser !== "undefined") {
                    $.each(vidiConfig.extensions.browser, function (i, v) {
                        modules.extensions[Object.keys(v)[0]] = {};
                        $.each(v[Object.keys(v)[0]], function (n, m) {
                            modules.extensions[Object.keys(v)[0]][m] = require('./../../extensions/' + Object.keys(v)[0] + '/browser/' + m + ".js");
                            modules.extensions[Object.keys(v)[0]][m].set(modules);
                        })
                    });

                    if (typeof window.vidiConfig.enabledExtensions === "object") {
                        $.each(vidiConfig.extensions.browser, function (i, v) {
                            $.each(v[Object.keys(v)[0]], function (n, m) {
                                if (window.vidiConfig.enabledExtensions.indexOf(Object.keys(v)[0]) > -1) {
                                    modules.extensions[Object.keys(v)[0]][m].init();
                                }
                            })
                        });
                    }
                }

                // Init some GUI stuff after modules are loaded
                // ============================================
                $("[data-toggle=tooltip]").tooltip();

                $.material.init();
                touchScroll(".tab-pane");
                touchScroll("#info-modal-body-wrapper");
                $("#loadscreentext").html(__("Loading data"));
                if (window.vidiConfig.activateMainTab) {
                    setTimeout(function () {
                        $('#main-tabs a[href="#' + window.vidiConfig.activateMainTab + '-content"]').tab('show');
                    }, 200);
                }

                $(window).resize(_.debounce(function () {
                    $("#myNavmenu").offcanvas('hide');
                    setTimeout(function () {
                        modules.cloud.get().map.invalidateSize();
                    }, 100);
                }, 0));

                } catch (e) {
                    console.error("Could not perform application initialization", e.message);
                }
            });
        });

        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('/service-worker.bundle.js').then((registration) => {
                console.log('Service worker registration succeeded');
            }).catch(error => {
                console.error(`Unable to register the service worker, please load the application over HTTPS in order to use its full functionality`);
            });
        } else {
            console.warn(`Service workers are not supported in this browser, some features may be unavailable`);
        }

        if (window.localforage) {
            localforage.getItem('appVersion').then(versionValue => {
                localforage.getItem('appExtensionsBuild').then(extensionsBuildValue => {
                    if (versionValue === null) {
                        localforage.setItem('appVersion', window.vidiConfig.appVersion).then(() => {
                            localforage.setItem('appExtensionsBuild', window.vidiConfig.appExtensionsBuild).then(() => {
                                console.log(`Versioning: setting new application version (${window.vidiConfig.appVersion}, ${window.vidiConfig.appExtensionsBuild})`);
                            });
                        }).catch(error => {
                            throw new Error(`Unable to store current application version`);
                        });
                    } else {
                        // If two versions are correctly detected
                        if (semver.valid(window.vidiConfig.appVersion) !== null && semver.valid(versionValue) !== null) {
                            if (semver.gt(window.vidiConfig.appVersion, versionValue) ||
                                (window.vidiConfig.appVersion === versionValue && window.vidiConfig.appExtensionsBuild !== extensionsBuildValue)) {
                                if (confirm(`Update application to the newest version (current: ${versionValue}, extensions: ${extensionsBuildValue}, latest: ${window.vidiConfig.appVersion}, extensions: ${window.vidiConfig.appExtensionsBuild})?`)) {
                                    let unregisteringRequests = [];

                                    // Unregister service worker
                                    navigator.serviceWorker.getRegistrations().then((registrations) => {
                                        for(let registration of registrations) {
                                            console.log(`Versioning: unregistering service worker`, registration);
                                            unregisteringRequests.push(registration.unregister());
                                            registration.unregister();
                                        }
                                    });

                                    Promise.all(unregisteringRequests).then((values) => {
                                        // Clear caches
                                        caches.keys().then(function(names) {
                                            for (let name of names) {
                                                console.log(`Versioning: clearing cache`, name);
                                                caches.delete(name);
                                            }
                                        });

                                        // Remove current app version
                                        localforage.removeItem('appVersion').then(() => {
                                            location.reload();
                                        });
                                    });
                                }
                            } else {
                                console.log('Versioning: new application version is not available');
                            }
                        } else if (typeof value === "undefined" || semver.valid(value) === null) {
                            console.warn(`Seems like current application version is invalid, resetting it`);
                            localforage.setItem('appVersion', '1.0.0').then(() => {}).catch(error => {
                                localforage.setItem('appExtensionsBuild', '0').then(() => {}).catch(error => {
                                    throw new Error(`Unable to store current application version`);
                                });
                            });
                        }
                    }
                });
            });
        } else {
            throw new Error(`localforage is not available`);
        }
    }
};<|endoftext|>


<commit_before>// ## Tweet Controller
var mongoose = require('mongoose');
var Tweet = mongoose.model('Tweet');
var Analytics = mongoose.model('Analytics');
var _ = require('underscore');

function logAnalytics(req) {
  var url = req.protocol + '://' + req.get('host') + req.originalUrl;
  console.log(req.ip);
  var crude_ip_array = req.ip.split(':')
  console.log(crude_ip_array);
  var ipArrayLength = crude_ip_array.length;
  // cleanup IP to remove unwanted characters
  var cleanIp = crude_ip_array[ipArrayLength - 1];
  console.log('ip', cleanIp)
  var analytics = new Analytics(
      {
        'ip': cleanIp,
        'user': req.user,
        'url': url
  });
  analytics.save(function (err) {
    if (err) {
      console.log(err);
    }
  });
}

exports.tweet = function(req, res, next, id) {
  logAnalytics(req);
  Tweet.load(id, function(err, tweet) {
    if (err) {
      return next(err);
    }
    if (!tweet) {
      return next(new Error('Failed to load tweet' + id));
    }
    req.tweet = tweet;
    next();
  });
};

// ### New Tweet
exports.new = function(req, res) {
  logAnalytics(req);
  res.render('tweets/new', {
    title: 'New Tweet',
    tweet: new Tweet({})
  });
};

// ### Create a Tweet
exports.create = function(req, res) {
  logAnalytics(req);
  var tweet = new Tweet(req.body);
  tweet.user = req.user;
  tweet.uploadAndSave(req.files.image, function(err) {
    if (err) {
      res.render('tweets/new', {
        title: 'New Tweet',
        tweet: tweet,
        error: err.errors
      });
    } else {
      res.redirect('/');
    }
  });
};

// ### Edit Tweet
exports.edit = function(req, res) {
  logAnalytics(req);
  res.render('tweets/edit', {
    title: 'Edit' + req.tweet.title,
    tweet: req.tweet
  });
};

// ### Show Tweet
exports.show = function(req, res) {
  logAnalytics(req);
  res.render('tweets/show', {
    title: req.tweet.title,
    tweet: req.tweet
  });
};

// ### Update a tweet
exports.update = function(req, res) {
  logAnalytics(req);
  var tweet = req.tweet;
  tweet = _.extend(tweet, req.body);
  tweet.uploadAndSave(req.files.image, function(err) {
    if (err) {
      res.render('tweets/edit', {
        title: 'Edit Tweet',
        tweet: tweet,
        error: err.errors
      });
    } else {
      res.redirect('/');
    }
  });
};

// ### Delete a tweet
exports.destroy = function(req, res) {
  logAnalytics(req);
  var tweet = req.tweet;
  tweet.remove(function(err) {
    if (err) {
      return res.render('500');
    }
    res.redirect('/');
  });
};

exports.index = function(req, res) {
  logAnalytics(req);
  var page = (req.param('page') > 0 ? req.param('page') : 1) - 1;
  var perPage = 15;
  var options = {
    perPage: perPage,
    page: page
  };

  Tweet.list(options, function(err, tweets) {
    if (err) {
      return res.render('500');
    }
    Tweet.count().exec(function(err, count) {
      if (err) {
        return res.render('500');
      }
      res.render('tweets/index', {
        title: 'List of Tweets',
        tweets: tweets,
        page: page + 1,
        pages: Math.ceil(count / perPage)
      });
    });
  });
};
<commit_msg>only log production urls<commit_after>// ## Tweet Controller
var mongoose = require('mongoose');
var Tweet = mongoose.model('Tweet');
var Analytics = mongoose.model('Analytics');
var _ = require('underscore');

function logAnalytics(req) {
  var url = req.protocol + '://' + req.get('host') + req.originalUrl;
  var crude_ip_array = req.ip.split(':')
  var ipArrayLength = crude_ip_array.length;
  // cleanup IP to remove unwanted characters
  var cleanIp = crude_ip_array[ipArrayLength - 1];
  if (req.get('host').split(':')[0] !== 'localhost') {
    var analytics = new Analytics(
        {
          'ip': cleanIp,
          'user': req.user,
          'url': url
    });
    analytics.save(function (err) {
      if (err) {
        console.log(err);
      }
    });
  }
}

exports.tweet = function(req, res, next, id) {
  logAnalytics(req);
  Tweet.load(id, function(err, tweet) {
    if (err) {
      return next(err);
    }
    if (!tweet) {
      return next(new Error('Failed to load tweet' + id));
    }
    req.tweet = tweet;
    next();
  });
};

// ### New Tweet
exports.new = function(req, res) {
  logAnalytics(req);
  res.render('tweets/new', {
    title: 'New Tweet',
    tweet: new Tweet({})
  });
};

// ### Create a Tweet
exports.create = function(req, res) {
  logAnalytics(req);
  var tweet = new Tweet(req.body);
  tweet.user = req.user;
  tweet.uploadAndSave(req.files.image, function(err) {
    if (err) {
      res.render('tweets/new', {
        title: 'New Tweet',
        tweet: tweet,
        error: err.errors
      });
    } else {
      res.redirect('/');
    }
  });
};

// ### Edit Tweet
exports.edit = function(req, res) {
  logAnalytics(req);
  res.render('tweets/edit', {
    title: 'Edit' + req.tweet.title,
    tweet: req.tweet
  });
};

// ### Show Tweet
exports.show = function(req, res) {
  logAnalytics(req);
  res.render('tweets/show', {
    title: req.tweet.title,
    tweet: req.tweet
  });
};

// ### Update a tweet
exports.update = function(req, res) {
  logAnalytics(req);
  var tweet = req.tweet;
  tweet = _.extend(tweet, req.body);
  tweet.uploadAndSave(req.files.image, function(err) {
    if (err) {
      res.render('tweets/edit', {
        title: 'Edit Tweet',
        tweet: tweet,
        error: err.errors
      });
    } else {
      res.redirect('/');
    }
  });
};

// ### Delete a tweet
exports.destroy = function(req, res) {
  logAnalytics(req);
  var tweet = req.tweet;
  tweet.remove(function(err) {
    if (err) {
      return res.render('500');
    }
    res.redirect('/');
  });
};

exports.index = function(req, res) {
  logAnalytics(req);
  var page = (req.param('page') > 0 ? req.param('page') : 1) - 1;
  var perPage = 15;
  var options = {
    perPage: perPage,
    page: page
  };

  Tweet.list(options, function(err, tweets) {
    if (err) {
      return res.render('500');
    }
    Tweet.count().exec(function(err, count) {
      if (err) {
        return res.render('500');
      }
      res.render('tweets/index', {
        title: 'List of Tweets',
        tweets: tweets,
        page: page + 1,
        pages: Math.ceil(count / perPage)
      });
    });
  });
};
<|endoftext|>


<commit_before>/*
  (c) 2013 Instant Communication Ltd.
  under terms of ISC License
*/

(function(define) {
    return define(function() {
        var pluralRe = /^Plural-Forms:\s*nplurals\s*=\s*(\d+);\s*plural\s*=\s*([^a-zA-Z0-9\$]*([a-zA-Z0-9\$]+).+)$/m;

        function format(s, ctx) {
            return s.replace(/(^|.)\{([^\}]+)\}/g, function(match, prev, k) {
                if (prev === '\\') {
                    return '{' + k + '}';
                }
                return prev + ctx[k];
            });
        }

        function parsePlural(header) {
            var rv = {
                pluralNum: 2,
                isPlural: function(n) {
                    return n !== 1;
                }
            };
            if (!header) {
                return rv;
            }

            var match = header.match(pluralRe);
            if (!match) {
                return rv;
            }

            rv.pluralNum = parseInt(match[1], 10);
            var expr = match[2];
            var varName = match[3];

            var code = "(function (" + varName + ") { return " + expr + " })";
            try {
                rv.isPlural = eval(code);
            } catch (e) {
                console.log("Could not evaluate: " + code);
            }
            return rv;
        }

        function gettrans(messages, isPlural, msg1, msg2, num) {
            if (!messages || !messages[msg1]) {
                return num !== undefined && isPlural(num) ? msg2 : msg1;
            }

            var trans = messages[msg1];

            if (msg2 === undefined && num === undefined) {
                return typeof trans === 'string' ? trans : trans[0];
            }

            if (num !== undefined && typeof trans === 'string') {
                throw format('Plural number ({num}) provided for "{msg1}", ' +
                             'but only singular translation exists: {trans}',
                             {num: num, msg1: msg1, trans: trans});
            }

            return trans[isPlural(num)];
        }

        return function(messages) {
            function puttext(msg1, msg2, num, ctx) {
                // in case of `puttext(msg, ctx);`
                if (typeof msg2 === 'object' && num === undefined &&
                    ctx === undefined) {
                    ctx = msg2;
                    msg2 = undefined;
                }

                var text = gettrans(puttext.messages, puttext.plural, msg1, msg2, num);
                if (ctx) {
                    return format(text, ctx);
                }
                return text;
            }

            puttext.format = format;
            puttext.setMessages = function(messages) {
                puttext.messages = messages;
                var parsed = parsePlural(messages && messages[""]);
                puttext.pluralNum = parsed.pluralNum;
                puttext.plural = parsed.isPlural;
            };
            puttext.setMessages(messages);

            return puttext;
        };
    });
})(typeof define !== 'undefined' ? define : function(factory) {
    return window.puttext = factory();
});
<commit_msg>80 chars in line<commit_after>/*
  (c) 2013 Instant Communication Ltd.
  under terms of ISC License
*/

(function(define) {
    return define(function() {
        var pluralRe = /^Plural-Forms:\s*nplurals\s*=\s*(\d+);\s*plural\s*=\s*([^a-zA-Z0-9\$]*([a-zA-Z0-9\$]+).+)$/m;

        function format(s, ctx) {
            return s.replace(/(^|.)\{([^\}]+)\}/g, function(match, prev, k) {
                if (prev === '\\') {
                    return '{' + k + '}';
                }
                return prev + ctx[k];
            });
        }

        function parsePlural(header) {
            var rv = {
                pluralNum: 2,
                isPlural: function(n) {
                    return n !== 1;
                }
            };
            if (!header) {
                return rv;
            }

            var match = header.match(pluralRe);
            if (!match) {
                return rv;
            }

            rv.pluralNum = parseInt(match[1], 10);
            var expr = match[2];
            var varName = match[3];

            var code = "(function (" + varName + ") { return " + expr + " })";
            try {
                rv.isPlural = eval(code);
            } catch (e) {
                console.log("Could not evaluate: " + code);
            }
            return rv;
        }

        function gettrans(messages, isPlural, msg1, msg2, num) {
            if (!messages || !messages[msg1]) {
                return num !== undefined && isPlural(num) ? msg2 : msg1;
            }

            var trans = messages[msg1];

            if (msg2 === undefined && num === undefined) {
                return typeof trans === 'string' ? trans : trans[0];
            }

            if (num !== undefined && typeof trans === 'string') {
                throw format('Plural number ({num}) provided for "{msg1}", ' +
                             'but only singular translation exists: {trans}',
                             {num: num, msg1: msg1, trans: trans});
            }

            return trans[isPlural(num)];
        }

        return function(messages) {
            function puttext(msg1, msg2, num, ctx) {
                // in case of `puttext(msg, ctx);`
                if (typeof msg2 === 'object' && num === undefined &&
                    ctx === undefined) {
                    ctx = msg2;
                    msg2 = undefined;
                }

                var text = gettrans(puttext.messages, puttext.plural,
                                    msg1, msg2, num);
                if (ctx) {
                    return format(text, ctx);
                }
                return text;
            }

            puttext.format = format;
            puttext.setMessages = function(messages) {
                puttext.messages = messages;
                var parsed = parsePlural(messages && messages[""]);
                puttext.pluralNum = parsed.pluralNum;
                puttext.plural = parsed.isPlural;
            };
            puttext.setMessages(messages);

            return puttext;
        };
    });
})(typeof define !== 'undefined' ? define : function(factory) {
    return window.puttext = factory();
});
<|endoftext|>


<commit_before>'use strict';
const express = require('express'),
  url = require('url'),
  bodyParser = require('body-parser'),
  {isDate} = require('util').types;

const createMockServer = ({name = 'server', rootPath = '', port, handlers = []}) => {
  let server;
  const serverName = name,
    mockHandlers = [],

    environment = {
      SERVER_BASE_URL: '<mockUrl>',
      SERVER_HOST: '<mockHost>',
      SERVER_HOSTNAME: '<mockHostname>',
      SERVER_PORT: '<mockPort>'
    },
    savedEnvironment = {},
    space = length =>
    '                                                                 '
    .substr(0, length),

    camelToDash = str => str
    .replace(/(^[A-Z])/, ([first]) => first.toLowerCase())
    .replace(/([A-Z])/g, ([letter]) => `-${letter.toLowerCase()}`)
    .replace(/([a-z])([0-9])/g, ([letter, number]) => `${letter}-${number}`),

    toXml = ({name, value, includeDeclaration = false, indent = 0}) => {
      const xml = includeDeclaration ?
        '<?xml version="1.0" encoding="UTF-8"?>\n' :
        '';
      name = camelToDash(name);
      if (value === null || value === undefined) {
        return xml + space(indent) + '<' + name + ' nil="true"/>';
      } else if (typeof value === 'boolean') {
        return xml + space(indent) + '<' + name + ' type="boolean">' +
          value + '</' + name + '>';
      } else if (typeof value === 'number') {
        return xml + space(indent) + '<' + name + ' type="integer">' +
          value + '</' + name + '>';
      } else if (typeof value === 'string') {
        return xml + space(indent) + '<' + name + '>' +
          value + '</' + name + '>';
      } else if (isDate(value)) {
        return xml + space(indent) + '<' + name + ' type="datetime">' +
          value.toISOString().replace(/\.[0-9]{3}Z/, 'Z') + '</' + name + '>';
      } else if (Array.isArray(value)) {
        if (value.length === 0) {
          return xml + space(indent) + '<' + name + ' type="array"/>';
        }
        return xml + space(indent) + '<' + name + ' type="array">\n' +
          value.map(
            item => toXml({
              name: name + '-item',
              value: item,
              indent: indent + 2
            })
          ).join('\n') + '\n' +
          space(indent) + '</' + name + '>';
      }
      if (Object.keys(value).length === 0) {
        return xml + space(indent) + '<' + name + '/>';
      }
      return xml + space(indent) + '<' + name + '>\n' +
        Object.entries(value).map(([key, item]) => toXml({
          name: key,
          value: item,
          indent: indent + 2
        }).join('\n') + '\n' + space(indent) + '</' + name + '>');
    },

    setEnvironment = mockUrl => {
      const urlParsed = url.parse(mockUrl);
      Object.entries(environment).forEach(([key, value]) => {
        savedEnvironment[key] = process.env[key];
        if (value === '<mockUrl>') {
          process.env[key] = mockUrl;
        } else if (value === '<mockPort>') {
          process.env[key] = urlParsed.port;
        } else if (value === '<mockHostname>') {
          process.env[key] = urlParsed.hostname;
        } else if (value === '<mockHost>') {
          process.env[key] = urlParsed.host;
        } else {
          process.env[key] = value;
        }
      });
    },

    restoreEnvironment = () => Object.keys(environment)
    .forEach(key => {
      process.env[key] = savedEnvironment[key];
    }),

    mockServer = {
      app: express(),

      addDefaultHandler() {
        mockServer.app.all(
          '*',
          (req, res, next) => {
            // eslint-disable-next-line no-console
            console.log('no', serverName, 'handler for', req.method, req.url);
            next();
          }
        );
      },

      env() {
        return process.env;
      },

      mockHandler({name, method = 'get', path, responseName}) {
        mockServer[name] = jest.fn();
        mockHandlers.push(mockServer[name]);
        mockServer.app[method](rootPath + path + '*', (req, res) => {
          const response = mockServer[name]({
            path: req.path,
            headers: req.headers,
            body: req.body,
            query: req.query
          });
          if (response && response.error) {
            res.status(response.error.statusCode || 500).send(response.error);
          } else if (req.headers.accept === 'application/xml') {
            res.setHeader('Content-Type', 'application/xml');
            res.send(toXml({
              name: responseName || name,
              includeDeclaration: true,
              value: response
            }));
          } else if (req.path.match(/(xml|html?)$/)) {
            if (response && response.headers) {
              res.set(response.headers).send(response.body);
            } else {
              res.send(response);
            }
          } else {
            res.json(response);
          }
        });
      },

      clearMocks() {
        for (const mockHandler of mockHandlers) {
          mockHandler.mockClear();
        }
      },

      start() {
        return new Promise((resolve, reject) => {
          server = mockServer.app.listen(port || 0, (err) => {
            if (err) {
              reject(err);
            } else {
              const mockPort = server.address().port,
                mockUrl = 'http://localhost:' + mockPort + rootPath;
              // console.log(serverName, 'listening at', mockUrl);
              setEnvironment(mockUrl);
              resolve(true);
            }
          });
        });
      },

      stop() {
        return new Promise(resolve => {
          restoreEnvironment();
          server.close(() => resolve(true));
        });
      }
    };

  mockServer.app.use(bodyParser.urlencoded({
    extended: false
  }));
  mockServer.app.use(bodyParser.json());

  for (const handler of handlers) {
    mockServer.mockHandler(handler);
  }

  mockServer.addDefaultHandler();
  return mockServer;
};

const mockServer = (handlers = []) => {
  return createMockServer({
    handlers
  });

};

exports.mockServer = mockServer;
<commit_msg>fix lint error<commit_after>'use strict';
const express = require('express'),
  url = require('url'),
  bodyParser = require('body-parser'),
  {isDate} = require('util').types;

const createMockServer = ({name = 'server', rootPath = '', port, handlers = []}) => {
  let server;
  const serverName = name,
    mockHandlers = [],

    environment = {
      SERVER_BASE_URL: '<mockUrl>',
      SERVER_HOST: '<mockHost>',
      SERVER_HOSTNAME: '<mockHostname>',
      SERVER_PORT: '<mockPort>'
    },
    savedEnvironment = {},
    space = length =>
    '                                                                 '
    .substr(0, length),

    camelToDash = str => str
    .replace(/(^[A-Z])/, ([first]) => first.toLowerCase())
    .replace(/([A-Z])/g, ([letter]) => `-${letter.toLowerCase()}`)
    .replace(/([a-z])([0-9])/g, ([letter, number]) => `${letter}-${number}`),

    toXml = ({name, value, includeDeclaration = false, indent = 0}) => {
      const xml = includeDeclaration ?
        '<?xml version="1.0" encoding="UTF-8"?>\n' :
        '';
      name = camelToDash(name);
      if (value === null || value === undefined) {
        return xml + space(indent) + '<' + name + ' nil="true"/>';
      } else if (typeof value === 'boolean') {
        return xml + space(indent) + '<' + name + ' type="boolean">' +
          value + '</' + name + '>';
      } else if (typeof value === 'number') {
        return xml + space(indent) + '<' + name + ' type="integer">' +
          value + '</' + name + '>';
      } else if (typeof value === 'string') {
        return xml + space(indent) + '<' + name + '>' +
          value + '</' + name + '>';
      } else if (isDate(value)) {
        return xml + space(indent) + '<' + name + ' type="datetime">' +
          value.toISOString().replace(/\.[0-9]{3}Z/, 'Z') + '</' + name + '>';
      } else if (Array.isArray(value)) {
        if (value.length === 0) {
          return xml + space(indent) + '<' + name + ' type="array"/>';
        }
        return xml + space(indent) + '<' + name + ' type="array">\n' +
          value.map(
            item => toXml({
              name: name + '-item',
              value: item,
              indent: indent + 2
            })
          ).join('\n') + '\n' +
          space(indent) + '</' + name + '>';
      }
      if (Object.keys(value).length === 0) {
        return xml + space(indent) + '<' + name + '/>';
      }
      return xml + space(indent) + '<' + name + '>\n' +
        Object.entries(value).map(([key, item]) => toXml({
          name: key,
          value: item,
          indent: indent + 2
        }).join('\n') + '\n' + space(indent) + '</' + name + '>');
    },

    setEnvironment = mockUrl => {
      const urlParsed = url.parse(mockUrl);
      Object.entries(environment).forEach(([key, value]) => {
        savedEnvironment[key] = process.env[key];
        if (value === '<mockUrl>') {
          process.env[key] = mockUrl;
        } else if (value === '<mockPort>') {
          process.env[key] = urlParsed.port;
        } else if (value === '<mockHostname>') {
          process.env[key] = urlParsed.hostname;
        } else if (value === '<mockHost>') {
          process.env[key] = urlParsed.host;
        } else {
          process.env[key] = value;
        }
      });
    },

    restoreEnvironment = () => Object.keys(environment)
    .forEach(key => {
      process.env[key] = savedEnvironment[key];
    }),

    mockServer = {
      app: express(),

      addDefaultHandler() {
        mockServer.app.all(
          '*',
          (req, res, next) => {
            // eslint-disable-next-line no-console
            console.log('no', serverName, 'handler for', req.method, req.url);
            next();
          }
        );
      },

      env() {
        return process.env;
      },

      mockHandler({name, method = 'get', path, responseName}) {
        mockServer[name] = jest.fn();
        mockHandlers.push(mockServer[name]);
        mockServer.app[method](rootPath + path + '*', (req, res) => {
          const response = mockServer[name]({
            path: req.path,
            headers: req.headers,
            body: req.body,
            query: req.query
          });
          if (response && response.error) {
            res.status(response.error.statusCode || 500).send(response.error);
          } else if (req.headers.accept === 'application/xml') {
            res.setHeader('Content-Type', 'application/xml');
            res.send(toXml({
              name: responseName || name,
              includeDeclaration: true,
              value: response
            }));
          } else if (req.path.match(/(xml|html?)$/)) {
            if (response && response.headers) {
              res.set(response.headers).send(response.body);
            } else {
              res.send(response);
            }
          } else {
            res.json(response);
          }
        });
      },

      clearMocks() {
        for (const mockHandler of mockHandlers) {
          mockHandler.mockClear();
        }
      },

      start() {
        return new Promise((resolve, reject) => {
          server = mockServer.app.listen(port || 0, (err) => {
            if (err) {
              reject(err);
            } else {
              const mockPort = server.address().port,
                mockUrl = 'http://localhost:' + mockPort + rootPath;
              // console.log(serverName, 'listening at', mockUrl);
              setEnvironment(mockUrl);
              resolve(true);
            }
          });
        });
      },

      stop() {
        return new Promise(resolve => {
          restoreEnvironment();
          server.close(() => resolve(true));
        });
      }
    };

  mockServer.app.use(bodyParser.urlencoded({
    extended: false
  }));
  mockServer.app.use(bodyParser.json());

  for (const handler of handlers) {
    mockServer.mockHandler(handler);
  }

  mockServer.addDefaultHandler();
  return mockServer;
};

const mockServer = (handlers = []) => createMockServer({
  handlers
});

exports.mockServer = mockServer;
<|endoftext|>


<commit_before>function CALCULATE_ALL_MOVES_ADV(p1, p2, field) {
	checkAirLock(p1, field);
	checkAirLock(p2, field);
	checkForecast(p1, field.getWeather());
	checkForecast(p2, field.getWeather());
	checkIntimidate(p1, p2);
	checkIntimidate(p2, p1);
	var side1 = field.getSide(1);
	var side2 = field.getSide(0);
	var results = [[], []];
	for (var i = 0; i < 4; i++) {
		results[0][i] = CALCULATE_DAMAGE_ADV(p1, p2, p1.moves[i], side1);
		results[1][i] = CALCULATE_DAMAGE_ADV(p2, p1, p2.moves[i], side2);
	}
	return results;
}

function CALCULATE_MOVES_OF_ATTACKER_ADV(attacker, defender, field) {
	checkAirLock(attacker, field);
	checkAirLock(defender, field);
	checkForecast(attacker, field.getWeather());
	checkForecast(defender, field.getWeather());
	checkIntimidate(attacker, defender);
	checkIntimidate(defender, attacker);
	var defenderSide = field.getSide(~~(mode === "one-vs-all"));
	var results = [];
	for (var i = 0; i < 4; i++) {
		results[i] = CALCULATE_DAMAGE_ADV(attacker, defender, attacker.moves[i], defenderSide);
	}
	return results;
}

function CALCULATE_DAMAGE_ADV(attacker, defender, move, field) {
	var description = {
		"attackerName": attacker.name,
		"moveName": move.name,
		"defenderName": defender.name
	};

	if (move.bp === 0) {
		return {"damage": [0], "description": buildDescription(description)};
	}

	if (field.isProtected) {
		description.isProtected = true;
		return {"damage": [0], "description": buildDescription(description)};
	}

	if (move.name === "Weather Ball") {
		move.type = field.weather === "Sun" ? "Fire" :
			field.weather === "Rain" ? "Water" :
				field.weather === "Sand" ? "Rock" :
					field.weather === "Hail" ? "Ice" :
						"Normal";
		description.weather = field.weather;
		description.moveType = move.type;
		description.moveBP = move.bp;
	}

	var typeEffect1 = getMoveEffectiveness(move, defender.type1, field.isForesight);
	var typeEffect2 = defender.type2 ? getMoveEffectiveness(move, defender.type2, field.isForesight) : 1;
	var typeEffectiveness = typeEffect1 * typeEffect2;

	if (typeEffectiveness === 0) {
		return {"damage": [0], "description": buildDescription(description)};
	}

	if ((defender.ability.indexOf("Flash Fire") !== -1 && move.type === "Fire") ||
            (defender.ability === "Levitate" && move.type === "Ground") ||
            (defender.ability === "Volt Absorb" && move.type === "Electric") ||
            (defender.ability === "Water Absorb" && move.type === "Water") ||
            (defender.ability === "Wonder Guard" && typeEffectiveness <= 1) ||
            (defender.ability === "Soundproof" && move.isSound)) {
		description.defenderAbility = defender.ability;
		return {"damage": [0], "description": buildDescription(description)};
	}

	description.HPEVs = defender.HPEVs + " HP";

	var lv = attacker.level;
	if (move.name === "Seismic Toss" || move.name === "Night Shade") {
		return {"damage": [lv], "description": buildDescription(description)};
	}

	if (move.hits > 1) {
		description.hits = move.hits;
	}

	var bp;
	switch (move.name) {
	case "Flail":
	case "Reversal":
		var p = Math.floor(48 * attacker.curHP / attacker.maxHP);
		bp = p <= 1 ? 200 : p <= 4 ? 150 : p <= 9 ? 100 : p <= 16 ? 80 : p <= 32 ? 40 : 20;
		description.moveBP = bp;
		break;
	case "Eruption":
	case "Water Spout":
		bp = Math.max(1, Math.floor(150 * attacker.curHP / attacker.maxHP));
		description.moveBP = bp;
		break;
	case "Low Kick":
		var w = defender.weight;
		bp = w >= 200 ? 120 : w >= 100 ? 100 : w >= 50 ? 80 : w >= 25 ? 60 : w >= 10 ? 40 : 20;
		description.moveBP = bp;
		break;
	default:
		bp = move.bp;
	}

	var isPhysical = typeChart[move.type].category === "Physical";
	var attackStat = isPhysical ? AT : SA;
	description.attackEVs = attacker.evs[attackStat] +
            (NATURES[attacker.nature][0] === attackStat ? "+" : NATURES[attacker.nature][1] === attackStat ? "-" : "") + " " +
            toSmogonStat(attackStat);
	var defenseStat = isPhysical ? DF : SD;
	description.defenseEVs = defender.evs[defenseStat] +
            (NATURES[defender.nature][0] === defenseStat ? "+" : NATURES[defender.nature][1] === defenseStat ? "-" : "") + " " +
            toSmogonStat(defenseStat);
	var at = attacker.rawStats[attackStat];
	var df = defender.rawStats[defenseStat];

	if (isPhysical && (attacker.ability === "Huge Power" || attacker.ability === "Pure Power")) {
		at *= 2;
		description.attackerAbility = attacker.ability;
	}

	if (attacker.item !== "Sea Incense" && getItemBoostType(attacker.item) === move.type) {
		at = Math.floor(at * 1.1);
		description.attackerItem = attacker.item;
	} else if (attacker.item === "Sea Incense" && move.type === "Water") {
		at = Math.floor(at * 1.05);
		description.attackerItem = attacker.item;
	} else if ((isPhysical && attacker.item === "Choice Band") ||
            (!isPhysical && attacker.item === "Soul Dew" && (attacker.name === "Latios" || attacker.name === "Latias"))) {
		at = Math.floor(at * 1.5);
		description.attackerItem = attacker.item;
	} else if ((!isPhysical && attacker.item === "Deep Sea Tooth" && attacker.name === "Clamperl") ||
            (!isPhysical && attacker.item === "Light Ball" && attacker.name === "Pikachu") ||
            (isPhysical && attacker.item === "Thick Club" && (attacker.name === "Cubone" || attacker.name === "Marowak"))) {
		at *= 2;
		description.attackerItem = attacker.item;
	}

	if (!isPhysical && defender.item === "Soul Dew" && (defender.name === "Latios" || defender.name === "Latias")) {
		df = Math.floor(df * 1.5);
		description.defenderItem = defender.item;
	} else if ((!isPhysical && defender.item === "Deep Sea Scale" && defender.name === "Clamperl") ||
            (isPhysical && defender.item === "Metal Powder" && defender.name === "Ditto")) {
		df *= 2;
		description.defenderItem = defender.item;
	}

	if (defender.ability === "Thick Fat" && (move.type === "Fire" || move.type === "Ice")) {
		at = Math.floor(at / 2);
		description.defenderAbility = defender.ability;
	} else if (isPhysical && defender.ability === "Marvel Scale" && defender.status !== "Healthy") {
		df = Math.floor(df * 1.5);
		description.defenderAbility = defender.ability;
	}

	if (isPhysical && (attacker.ability === "Hustle" || (attacker.ability === "Guts" && attacker.status !== "Healthy")) || (!isPhysical && (attacker.ability === "Plus" || attacker.ability === "Minus"))) {
		at = Math.floor(at * 1.5);
		description.attackerAbility = attacker.ability;
	} else if (attacker.curHP <= attacker.maxHP / 3 &&
            ((attacker.ability === "Overgrow" && move.type === "Grass") ||
            (attacker.ability === "Blaze" && move.type === "Fire") ||
            (attacker.ability === "Torrent" && move.type === "Water") ||
            (attacker.ability === "Swarm" && move.type === "Bug"))) {
		bp = Math.floor(bp * 1.5);
		description.attackerAbility = attacker.ability;
	}

	if (move.name === "Explosion" || move.name === "Self-Destruct") {
		df = Math.floor(df / 2);
	}

	var isCritical = move.isCrit && ["Battle Armor", "Shell Armor"].indexOf(defender.ability) === -1;

	var attackBoost = attacker.boosts[attackStat];
	var defenseBoost = defender.boosts[defenseStat];
	if (attackBoost > 0 || (!isCritical && attackBoost < 0)) {
		at = getModifiedStat(at, attackBoost);
		description.attackBoost = attackBoost;
	}
	if (defenseBoost < 0 || (!isCritical && defenseBoost > 0)) {
		df = getModifiedStat(df, defenseBoost);
		description.defenseBoost = defenseBoost;
	}

	var baseDamage = Math.floor(Math.floor(Math.floor(2 * lv / 5 + 2) * at * bp / df) / 50);

	if (attacker.status === "Burned" && isPhysical && attacker.ability !== "Guts") {
		baseDamage = Math.floor(baseDamage / 2);
		description.isBurned = true;
	}

	if (!isCritical) {
		var screenMultiplier = field.format !== "Singles" ? (2 / 3) : (1 / 2);
		if (isPhysical && field.isReflect) {
			baseDamage = Math.floor(baseDamage * screenMultiplier);
			description.isReflect = true;
		} else if (!isPhysical && field.isLightScreen) {
			baseDamage = Math.floor(baseDamage * screenMultiplier);
			description.isLightScreen = true;
		}
	}

	if (field.format !== "Singles" && move.isSpread) {
		// some sources say 3/4, some say 2/3, some say 1/2...using 3/4 for now since that's what DPP+ use
		baseDamage = Math.floor(baseDamage * 3 / 4);
	}

	if ((field.weather === "Sun" && move.type === "Fire") || (field.weather === "Rain" && move.type === "Water")) {
		baseDamage = Math.floor(baseDamage * 1.5);
		description.weather = field.weather;
	} else if ((field.weather === "Sun" && move.type === "Water") || (field.weather === "Rain" && move.type === "Fire") ||
            (move.name === "Solar Beam" && ["Rain", "Sand", "Hail"].indexOf(field.weather) !== -1)) {
		baseDamage = Math.floor(baseDamage / 2);
		description.weather = field.weather;
	}

	if (attacker.ability === "Flash Fire (activated)" && move.type === "Fire") {
		baseDamage = Math.floor(baseDamage * 1.5);
		description.attackerAbility = "Flash Fire";
	}

	baseDamage = Math.max(1, baseDamage) + 2;

	if (isCritical) {
		baseDamage *= 2;
		description.isCritical = true;
	}

	if (move.name === "Weather Ball" && field.weather !== "") {
		baseDamage *= 2;
		description.moveBP = move.bp * 2;
	}

	if (field.isHelpingHand) {
		baseDamage = Math.floor(baseDamage * 1.5);
		description.isHelpingHand = true;
	}

	if (move.type === attacker.type1 || move.type === attacker.type2) {
		baseDamage = Math.floor(baseDamage * 1.5);
	}

	baseDamage = Math.floor(baseDamage * typeEffectiveness);

	var damage = [];
	for (var i = 85; i <= 100; i++) {
		damage[i - 85] = Math.max(1, Math.floor(baseDamage * i / 100));
	}
	return {"damage": damage, "description": buildDescription(description)};
}
<commit_msg>fixed spread damage<commit_after>function CALCULATE_ALL_MOVES_ADV(p1, p2, field) {
	checkAirLock(p1, field);
	checkAirLock(p2, field);
	checkForecast(p1, field.getWeather());
	checkForecast(p2, field.getWeather());
	checkIntimidate(p1, p2);
	checkIntimidate(p2, p1);
	var side1 = field.getSide(1);
	var side2 = field.getSide(0);
	var results = [[], []];
	for (var i = 0; i < 4; i++) {
		results[0][i] = CALCULATE_DAMAGE_ADV(p1, p2, p1.moves[i], side1);
		results[1][i] = CALCULATE_DAMAGE_ADV(p2, p1, p2.moves[i], side2);
	}
	return results;
}

function CALCULATE_MOVES_OF_ATTACKER_ADV(attacker, defender, field) {
	checkAirLock(attacker, field);
	checkAirLock(defender, field);
	checkForecast(attacker, field.getWeather());
	checkForecast(defender, field.getWeather());
	checkIntimidate(attacker, defender);
	checkIntimidate(defender, attacker);
	var defenderSide = field.getSide(~~(mode === "one-vs-all"));
	var results = [];
	for (var i = 0; i < 4; i++) {
		results[i] = CALCULATE_DAMAGE_ADV(attacker, defender, attacker.moves[i], defenderSide);
	}
	return results;
}

function CALCULATE_DAMAGE_ADV(attacker, defender, move, field) {
	var description = {
		"attackerName": attacker.name,
		"moveName": move.name,
		"defenderName": defender.name
	};

	if (move.bp === 0) {
		return {"damage": [0], "description": buildDescription(description)};
	}

	if (field.isProtected) {
		description.isProtected = true;
		return {"damage": [0], "description": buildDescription(description)};
	}

	if (move.name === "Weather Ball") {
		move.type = field.weather === "Sun" ? "Fire" :
			field.weather === "Rain" ? "Water" :
				field.weather === "Sand" ? "Rock" :
					field.weather === "Hail" ? "Ice" :
						"Normal";
		description.weather = field.weather;
		description.moveType = move.type;
		description.moveBP = move.bp;
	}

	var typeEffect1 = getMoveEffectiveness(move, defender.type1, field.isForesight);
	var typeEffect2 = defender.type2 ? getMoveEffectiveness(move, defender.type2, field.isForesight) : 1;
	var typeEffectiveness = typeEffect1 * typeEffect2;

	if (typeEffectiveness === 0) {
		return {"damage": [0], "description": buildDescription(description)};
	}

	if ((defender.ability.indexOf("Flash Fire") !== -1 && move.type === "Fire") ||
            (defender.ability === "Levitate" && move.type === "Ground") ||
            (defender.ability === "Volt Absorb" && move.type === "Electric") ||
            (defender.ability === "Water Absorb" && move.type === "Water") ||
            (defender.ability === "Wonder Guard" && typeEffectiveness <= 1) ||
            (defender.ability === "Soundproof" && move.isSound)) {
		description.defenderAbility = defender.ability;
		return {"damage": [0], "description": buildDescription(description)};
	}

	description.HPEVs = defender.HPEVs + " HP";

	var lv = attacker.level;
	if (move.name === "Seismic Toss" || move.name === "Night Shade") {
		return {"damage": [lv], "description": buildDescription(description)};
	}

	if (move.hits > 1) {
		description.hits = move.hits;
	}

	var bp;
	switch (move.name) {
	case "Flail":
	case "Reversal":
		var p = Math.floor(48 * attacker.curHP / attacker.maxHP);
		bp = p <= 1 ? 200 : p <= 4 ? 150 : p <= 9 ? 100 : p <= 16 ? 80 : p <= 32 ? 40 : 20;
		description.moveBP = bp;
		break;
	case "Eruption":
	case "Water Spout":
		bp = Math.max(1, Math.floor(150 * attacker.curHP / attacker.maxHP));
		description.moveBP = bp;
		break;
	case "Low Kick":
		var w = defender.weight;
		bp = w >= 200 ? 120 : w >= 100 ? 100 : w >= 50 ? 80 : w >= 25 ? 60 : w >= 10 ? 40 : 20;
		description.moveBP = bp;
		break;
	default:
		bp = move.bp;
	}

	var isPhysical = typeChart[move.type].category === "Physical";
	var attackStat = isPhysical ? AT : SA;
	description.attackEVs = attacker.evs[attackStat] +
            (NATURES[attacker.nature][0] === attackStat ? "+" : NATURES[attacker.nature][1] === attackStat ? "-" : "") + " " +
            toSmogonStat(attackStat);
	var defenseStat = isPhysical ? DF : SD;
	description.defenseEVs = defender.evs[defenseStat] +
            (NATURES[defender.nature][0] === defenseStat ? "+" : NATURES[defender.nature][1] === defenseStat ? "-" : "") + " " +
            toSmogonStat(defenseStat);
	var at = attacker.rawStats[attackStat];
	var df = defender.rawStats[defenseStat];

	if (isPhysical && (attacker.ability === "Huge Power" || attacker.ability === "Pure Power")) {
		at *= 2;
		description.attackerAbility = attacker.ability;
	}

	if (attacker.item !== "Sea Incense" && getItemBoostType(attacker.item) === move.type) {
		at = Math.floor(at * 1.1);
		description.attackerItem = attacker.item;
	} else if (attacker.item === "Sea Incense" && move.type === "Water") {
		at = Math.floor(at * 1.05);
		description.attackerItem = attacker.item;
	} else if ((isPhysical && attacker.item === "Choice Band") ||
            (!isPhysical && attacker.item === "Soul Dew" && (attacker.name === "Latios" || attacker.name === "Latias"))) {
		at = Math.floor(at * 1.5);
		description.attackerItem = attacker.item;
	} else if ((!isPhysical && attacker.item === "Deep Sea Tooth" && attacker.name === "Clamperl") ||
            (!isPhysical && attacker.item === "Light Ball" && attacker.name === "Pikachu") ||
            (isPhysical && attacker.item === "Thick Club" && (attacker.name === "Cubone" || attacker.name === "Marowak"))) {
		at *= 2;
		description.attackerItem = attacker.item;
	}

	if (!isPhysical && defender.item === "Soul Dew" && (defender.name === "Latios" || defender.name === "Latias")) {
		df = Math.floor(df * 1.5);
		description.defenderItem = defender.item;
	} else if ((!isPhysical && defender.item === "Deep Sea Scale" && defender.name === "Clamperl") ||
            (isPhysical && defender.item === "Metal Powder" && defender.name === "Ditto")) {
		df *= 2;
		description.defenderItem = defender.item;
	}

	if (defender.ability === "Thick Fat" && (move.type === "Fire" || move.type === "Ice")) {
		at = Math.floor(at / 2);
		description.defenderAbility = defender.ability;
	} else if (isPhysical && defender.ability === "Marvel Scale" && defender.status !== "Healthy") {
		df = Math.floor(df * 1.5);
		description.defenderAbility = defender.ability;
	}

	if (isPhysical && (attacker.ability === "Hustle" || (attacker.ability === "Guts" && attacker.status !== "Healthy")) || (!isPhysical && (attacker.ability === "Plus" || attacker.ability === "Minus"))) {
		at = Math.floor(at * 1.5);
		description.attackerAbility = attacker.ability;
	} else if (attacker.curHP <= attacker.maxHP / 3 &&
            ((attacker.ability === "Overgrow" && move.type === "Grass") ||
            (attacker.ability === "Blaze" && move.type === "Fire") ||
            (attacker.ability === "Torrent" && move.type === "Water") ||
            (attacker.ability === "Swarm" && move.type === "Bug"))) {
		bp = Math.floor(bp * 1.5);
		description.attackerAbility = attacker.ability;
	}

	if (move.name === "Explosion" || move.name === "Self-Destruct") {
		df = Math.floor(df / 2);
	}

	var isCritical = move.isCrit && ["Battle Armor", "Shell Armor"].indexOf(defender.ability) === -1;

	var attackBoost = attacker.boosts[attackStat];
	var defenseBoost = defender.boosts[defenseStat];
	if (attackBoost > 0 || (!isCritical && attackBoost < 0)) {
		at = getModifiedStat(at, attackBoost);
		description.attackBoost = attackBoost;
	}
	if (defenseBoost < 0 || (!isCritical && defenseBoost > 0)) {
		df = getModifiedStat(df, defenseBoost);
		description.defenseBoost = defenseBoost;
	}

	var baseDamage = Math.floor(Math.floor(Math.floor(2 * lv / 5 + 2) * at * bp / df) / 50);

	if (attacker.status === "Burned" && isPhysical && attacker.ability !== "Guts") {
		baseDamage = Math.floor(baseDamage / 2);
		description.isBurned = true;
	}

	if (!isCritical) {
		var screenMultiplier = field.format !== "Singles" ? (2 / 3) : (1 / 2);
		if (isPhysical && field.isReflect) {
			baseDamage = Math.floor(baseDamage * screenMultiplier);
			description.isReflect = true;
		} else if (!isPhysical && field.isLightScreen) {
			baseDamage = Math.floor(baseDamage * screenMultiplier);
			description.isLightScreen = true;
		}
	}

	if (field.format !== "Singles" && move.isSpread && (move.name !== "Explosion" && move.name !== "Self-Destruct" && move.name !== "Earthquake" && move.name !== "Magnitude")) {
		// weird gen 3 spread damage mechanics
		baseDamage = Math.floor(baseDamage / 2);
	}

	if ((field.weather === "Sun" && move.type === "Fire") || (field.weather === "Rain" && move.type === "Water")) {
		baseDamage = Math.floor(baseDamage * 1.5);
		description.weather = field.weather;
	} else if ((field.weather === "Sun" && move.type === "Water") || (field.weather === "Rain" && move.type === "Fire") ||
            (move.name === "Solar Beam" && ["Rain", "Sand", "Hail"].indexOf(field.weather) !== -1)) {
		baseDamage = Math.floor(baseDamage / 2);
		description.weather = field.weather;
	}

	if (attacker.ability === "Flash Fire (activated)" && move.type === "Fire") {
		baseDamage = Math.floor(baseDamage * 1.5);
		description.attackerAbility = "Flash Fire";
	}

	baseDamage = Math.max(1, baseDamage) + 2;

	if (isCritical) {
		baseDamage *= 2;
		description.isCritical = true;
	}

	if (move.name === "Weather Ball" && field.weather !== "") {
		baseDamage *= 2;
		description.moveBP = move.bp * 2;
	}

	if (field.isHelpingHand) {
		baseDamage = Math.floor(baseDamage * 1.5);
		description.isHelpingHand = true;
	}

	if (move.type === attacker.type1 || move.type === attacker.type2) {
		baseDamage = Math.floor(baseDamage * 1.5);
	}

	baseDamage = Math.floor(baseDamage * typeEffectiveness);

	var damage = [];
	for (var i = 85; i <= 100; i++) {
		damage[i - 85] = Math.max(1, Math.floor(baseDamage * i / 100));
	}
	return {"damage": damage, "description": buildDescription(description)};
}
<|endoftext|>


<commit_before>import {
  ROUTE_ACCESS_PREFIX,
  FRAMEWORK_ID_VALID_CHARACTERS
} from '../constants/FrameworkConstants';
import Application from './Application';
import {cleanServiceJSON} from '../../../../../src/js/utils/CleanJSONUtil';
import FrameworkSpec from './FrameworkSpec';

module.exports = class Framework extends Application {
  getName() {
    const labels = this.getLabels();
    if (labels && labels.DCOS_PACKAGE_FRAMEWORK_NAME) {
      return labels.DCOS_PACKAGE_FRAMEWORK_NAME;
    }

    return super.getName();
  }

  getNodeIDs() {
    return this.get('slave_ids');
  }

  getResourceID() {
    const regexp = new RegExp(`[^${FRAMEWORK_ID_VALID_CHARACTERS}]`, 'g');

    // Strip non-alphanumeric chars from name for safety
    return ROUTE_ACCESS_PREFIX + (this.get('name') || '').replace(regexp, '');
  }

  getSpec() {
    return new FrameworkSpec(cleanServiceJSON(this.get()));
  }

  getTasksSummary() {
    const tasksSummary = Object.assign({}, super.getTasksSummary());
    const tasksRunning = this.get('TASK_RUNNING') || 0;
    tasksSummary.tasksRunning += tasksRunning;
    tasksSummary.tasksUnknown += tasksRunning;

    return tasksSummary;
  }

  getUsageStats(resource) {
    const value = this.get('used_resources')[resource];

    return {value};
  }

  getResources() {
    // TODO: Circular reference workaround DCOS_OSS-783
    const MesosStateStore = require('../../../../../src/js/stores/MesosStateStore');

    const tasks = MesosStateStore.getTasksByService(this) || [];

    const instances = this.getInstancesCount();
    const {cpus = 0, mem = 0, gpus = 0, disk = 0} =
      this.getSpec().getResources();

    const frameworkResources = {
      cpus: cpus * instances,
      mem: mem * instances,
      gpus: gpus * instances,
      disk: disk * instances
    };

    // Aggregate all the child tasks resources
    // resources of child frameworks won't be aggregated
    return tasks
      .filter(function (task) {
        return task.state === 'TASK_RUNNING';
      })
      .filter(function (task) {
        return !task.isStartedByMarathon;
      })
      .reduce(function (memo, task) {
        const {cpus, mem, gpus, disk} = task.resources;

        return {
          cpus: memo.cpus + cpus,
          mem: memo.mem + mem,
          gpus: memo.gpus + gpus,
          disk: memo.disk + disk
        };
      }, frameworkResources);
  }

};
<commit_msg>fix(Framework.js): remove redundant filter.<commit_after>import {
  ROUTE_ACCESS_PREFIX,
  FRAMEWORK_ID_VALID_CHARACTERS
} from '../constants/FrameworkConstants';
import Application from './Application';
import {cleanServiceJSON} from '../../../../../src/js/utils/CleanJSONUtil';
import FrameworkSpec from './FrameworkSpec';

module.exports = class Framework extends Application {
  getName() {
    const labels = this.getLabels();
    if (labels && labels.DCOS_PACKAGE_FRAMEWORK_NAME) {
      return labels.DCOS_PACKAGE_FRAMEWORK_NAME;
    }

    return super.getName();
  }

  getNodeIDs() {
    return this.get('slave_ids');
  }

  getResourceID() {
    const regexp = new RegExp(`[^${FRAMEWORK_ID_VALID_CHARACTERS}]`, 'g');

    // Strip non-alphanumeric chars from name for safety
    return ROUTE_ACCESS_PREFIX + (this.get('name') || '').replace(regexp, '');
  }

  getSpec() {
    return new FrameworkSpec(cleanServiceJSON(this.get()));
  }

  getTasksSummary() {
    const tasksSummary = Object.assign({}, super.getTasksSummary());
    const tasksRunning = this.get('TASK_RUNNING') || 0;
    tasksSummary.tasksRunning += tasksRunning;
    tasksSummary.tasksUnknown += tasksRunning;

    return tasksSummary;
  }

  getUsageStats(resource) {
    const value = this.get('used_resources')[resource];

    return {value};
  }

  getResources() {
    // TODO: Circular reference workaround DCOS_OSS-783
    const MesosStateStore = require('../../../../../src/js/stores/MesosStateStore');

    const tasks = MesosStateStore.getTasksByService(this) || [];

    const instances = this.getInstancesCount();
    const {cpus = 0, mem = 0, gpus = 0, disk = 0} =
      this.getSpec().getResources();

    const frameworkResources = {
      cpus: cpus * instances,
      mem: mem * instances,
      gpus: gpus * instances,
      disk: disk * instances
    };

    // Aggregate all the child tasks resources
    // resources of child frameworks won't be aggregated
    return tasks
      .filter(function (task) {
        return task.state === 'TASK_RUNNING' && !task.isStartedByMarathon;
      })
      .reduce(function (memo, task) {
        const {cpus, mem, gpus, disk} = task.resources;

        return {
          cpus: memo.cpus + cpus,
          mem: memo.mem + mem,
          gpus: memo.gpus + gpus,
          disk: memo.disk + disk
        };
      }, frameworkResources);
  }

};
<|endoftext|>


<commit_before>import React from 'react';
import { mount } from 'enzyme';
import Mention from '..';

const { toContentState } = Mention;

describe('Mention', () => {
  beforeAll(() => {
    jest.useFakeTimers();
  });

  afterAll(() => {
    jest.useRealTimers();
  });

  it('should has focus function', () => {
    const handleFocus = jest.fn();
    const wrapper = mount(
      <Mention
        defaultValue={toContentState('@afc163')}
        onFocus={handleFocus}
        suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
      />,
    );
    wrapper.instance().focus();
    jest.runAllTimers();
    expect(handleFocus).toBeCalled();
  });

  it('basic suggestion', () => {
    const handleSearch = jest.fn();
    const wrapper = mount(
      <Mention suggestions={['afc163', 'raohai']} onSearchChange={handleSearch} />,
    );
    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@a' });
    jest.runAllTimers();
    expect(handleSearch).toBeCalledWith('a', '@');
  });

  it('change suggestions', () => {
    const container = mount(
);
    const wrapper = mount(
      <Mention
        suggestions={['afc163', 'raohai']}
        getSuggestionContainer={() => container.getDOMNode()}
      />,
    );
    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@' });
    jest.runAllTimers();
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(2);
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe(
      'afc163',
    );
    wrapper.setProps({ suggestions: ['yesmeck', 'yiminghe', 'lucy'] });
    jest.runAllTimers();
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(3);
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe(
      'yesmeck',
    );
  });

  it('select item', () => {
    const onChange = jest.fn();
    const onSelect = jest.fn();
    const wrapper = mount(
      <Mention suggestions={['afc163', 'raohai']} onChange={onChange} onSelect={onSelect} />,
    );
    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@' });
    jest.runAllTimers();
    expect(onChange).toBeCalled();
    expect(onSelect).not.toBeCalled();
    // enzyme cannot find .ant-mention-dropdown-item in react 15
    // I don't know why
    if (process.env.REACT === '15') {
      return;
    }
    wrapper
      .find('.ant-mention-dropdown-item')
      .at(0)
      .simulate('mouseDown');
    wrapper
      .find('.ant-mention-dropdown-item')
      .at(0)
      .simulate('mouseUp');
    wrapper
      .find('.ant-mention-dropdown-item')
      .at(0)
      .simulate('click');
    jest.runAllTimers();
    expect(onSelect).toBeCalled();
    expect(wrapper.find('.public-DraftStyleDefault-block').text()).toBe('@afc163 ');
  });

  it('defaultSuggestion filter', () => {
    if (process.env.REACT === '15') {
      return;
    }

    const wrapper = mount(<Mention defaultSuggestions={['light', 'bamboo']} />);

    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@b' });
    jest.runAllTimers();

    const items = wrapper.find('div.ant-mention-dropdown-item');
    expect(items.length).toBe(1);
    expect(items.at(0).props().children).toBe('bamboo');
  });
});
<commit_msg>test: update cases for Mention<commit_after>import React from 'react';
import { mount } from 'enzyme';
import Mention from '..';
import { Nav } from 'rc-editor-mention';

const { toContentState } = Mention;

describe('Mention', () => {
  beforeAll(() => {
    jest.useFakeTimers();
  });

  afterAll(() => {
    jest.useRealTimers();
  });

  it('should has focus function', () => {
    const handleFocus = jest.fn();
    const wrapper = mount(
      <Mention
        defaultValue={toContentState('@afc163')}
        onFocus={handleFocus}
        suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
      />,
    );
    wrapper.instance().focus();
    jest.runAllTimers();
    expect(handleFocus).toBeCalled();
  });

  it('basic suggestion', () => {
    const handleSearch = jest.fn();
    const wrapper = mount(
      <Mention suggestions={['afc163', 'raohai']} onSearchChange={handleSearch} />,
    );
    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@a' });
    jest.runAllTimers();
    expect(handleSearch).toBeCalledWith('a', '@');
  });

  it('change suggestions', () => {
    const container = mount(
);
    const wrapper = mount(
      <Mention
        suggestions={['afc163', 'raohai']}
        getSuggestionContainer={() => container.getDOMNode()}
      />,
    );
    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@' });
    jest.runAllTimers();
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(2);
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe(
      'afc163',
    );
    wrapper.setProps({ suggestions: ['yesmeck', 'yiminghe', 'lucy'] });
    jest.runAllTimers();
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(3);
    expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe(
      'yesmeck',
    );
  });

  it('select item', () => {
    const onChange = jest.fn();
    const onSelect = jest.fn();
    const wrapper = mount(
      <Mention suggestions={['afc163', 'raohai']} onChange={onChange} onSelect={onSelect} />,
    );
    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@' });
    jest.runAllTimers();
    expect(onChange).toBeCalled();
    expect(onSelect).not.toBeCalled();
    // enzyme cannot find .ant-mention-dropdown-item in react 15
    // I don't know why
    if (process.env.REACT === '15') {
      return;
    }
    wrapper
      .find('.ant-mention-dropdown-item')
      .at(0)
      .simulate('mouseDown');
    wrapper
      .find('.ant-mention-dropdown-item')
      .at(0)
      .simulate('mouseUp');
    wrapper
      .find('.ant-mention-dropdown-item')
      .at(0)
      .simulate('click');
    jest.runAllTimers();
    expect(onSelect).toBeCalled();
    expect(wrapper.find('.public-DraftStyleDefault-block').text()).toBe('@afc163 ');
  });

  it('defaultSuggestion filter', () => {
    if (process.env.REACT === '15') {
      return;
    }

    const wrapper = mount(<Mention defaultSuggestions={['light', 'bamboo']} />);

    wrapper.find('DraftEditorContents').simulate('focus');
    const ed = wrapper.find('.public-DraftEditor-content');
    ed.simulate('beforeInput', { data: '@b' });
    jest.runAllTimers();

    const items = wrapper.find('div.ant-mention-dropdown-item');
    expect(items.length).toBe(1);
    expect(items.at(0).props().children).toBe('bamboo');
  });

  it('onBlur', () => {
    const e = { test: 1 };
    const onBlur = event => {
      expect(event).toEqual(e);
    };
    const wrapper = mount(<Mention onBlur={onBlur} />).instance();
    wrapper.onBlur(e);
    expect(wrapper.state.focus).toBe(false);
  });

  it('check filteredSuggestions', () => {
    let wrapper = mount(<Mention defaultSuggestions={[]} />).instance();
    wrapper.defaultSearchChange('test');
    expect(wrapper.state.filteredSuggestions).toEqual([]);
    wrapper.defaultSearchChange('light');
    expect(wrapper.state.filteredSuggestions).toEqual([]);
    wrapper = mount(<Mention defaultSuggestions={[]} />).instance();
    wrapper.defaultSearchChange('test');
    expect(wrapper.state.filteredSuggestions).toEqual([]);
  });
});
<|endoftext|>