<commit_before>/**
 * @author Lukas Gamper, lukas.gamper@usystems.ch
 * @copyright uSystems GmbH, www.usystems.ch
 */
var SinglePageFuzzer;
(function (SinglePageFuzzer) {
    'use strict';
    /**
     * Default implementation of the config interface
     */
    var Config = (function () {
        function Config() {
            // run until stop is called
            this.stopAfter = 0;
            this.preventUnload = false;
            this.patchXMLHttpRequestSend = true;
            this.allowedChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
                'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
                'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Y', 'ä', 'ö', 'ü,', 'Ä', 'Ö', 'Ü',
                'ß', 'à', 'ç', 'è', 'ê', 'ë', 'ì', 'î', 'ï', 'ò', 'ó', 'ù', 'ą', 'ć', 'ĉ', 'ę', 'ĝ', 'ĥ', 'ĵ', 'ł', 'ń',
                'œ', 'ś', 'ŝ', 'ŭ', 'ź', 'ż', '+', '%', '&', '/', '\\', '!', '^', '`', '"', '\'', '[', ']', '<', '>', ':',
                '?', ';', '{', '}', '$', ' ', '\t', '\n'];
        }
        return Config;
    }());
    SinglePageFuzzer.Config = Config;
    /**
     * Start the Fuzzer
     * @param {IConfig} config options for the fuzzer
     */
    function start(config) {
        if (config === void 0) { config = new Config(); }
        // make sure the runner has stopped
        stop();
        // create new runner
        Context.runner = new Runner(config);
    }
    SinglePageFuzzer.start = start;
    /**
     * Generate a random number from a normal distribution using the Box-Muller transformation
     * https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
     * @param {number} mean mean of the distribution
     * @param {number} std standard deviation of the distribution
     * @param {boolean} positive if true, the result is always bigger than 0
     * @return {number} random number drawn from a normal distributed
     */
    function normal(mean, std, positive) {
        if (mean === void 0) { mean = 0; }
        if (std === void 0) { std = 1; }
        if (positive === void 0) { positive = false; }
        var n = null;
        while (n === null) {
            var u1 = Math.random();
            var u2 = Math.random();
            var n01 = Math.sqrt(-2. * Math.log(u1)) * Math.cos(2. * Math.PI * u2);
            n = n01 * std + mean;
            if (positive && n <= 0) {
                n = null;
            }
        }
        return n;
    }
    SinglePageFuzzer.normal = normal;
    /**
     * Generate a random number from a poisson distribution https://en.wikipedia.org/wiki/Poisson_distribution
     * @param {number} lambda lambda of the distribution
     * @return {number} random number drawn from a poisson distribution
     */
    function poisson(lambda) {
        var L = Math.exp(-lambda);
        var k = 0;
        var p = 1;
        while (p > L) {
            k += 1;
            p *= Math.random();
        }
        return k - 1;
    }
    SinglePageFuzzer.poisson = poisson;
    /**
     * Stop the Fuzzer
     */
    function stop() {
        if (Context.runner instanceof Runner) {
            Context.runner.stop();
        }
    }
    SinglePageFuzzer.stop = stop;
    /**
     * Class containing the state informations
     */
    var Context = (function () {
        function Context() {
        }
        // active runner
        Context.runner = null;
        return Context;
    }());
    /**
     * Runner
     */
    var Runner = (function () {
        // create a runner and directly start picking element
        function Runner(config) {
            var _this = this;
            this.config = config;
            // minimal time used for actions with dom mutations
            this.minWithMutationTime = 0;
            // maximum time used for actions without dom mutations
            this.maxWithoutMutationTime = 0;
            // time limit for dispaching an event to determin if a function has a javascript handler or not
            this.withoutActionLimit = 0;
            // should the single page fuzzer simulate an offline situation
            this.offline = false;
            // the timeout handler for the on/offline change
            this.lineTimeout = null;
            // determine when to stop. If config.stopAfter == 0, run until stop is called
            this.startTime = performance.now();
            // initalize the mutation ovserver to observe all changes on the page
            this.observer = new MutationObserver(function (mutations) {
                // update the last change time
                _this.lastAction = performance.now();
                if (!_this.hasDOMChanged) {
                    mutations.forEach(function (mutation) {
                        // only register non hidden elements as dom mutations
                        /* tslint:disable:no-string-literal */
                        if (typeof mutation.target['offsetParent'] != 'undefined' && mutation.target['offsetParent'] !== null) {
                            _this.hasDOMChanged = true;
                        }
                    });
                }
            });
            this.observer.observe(document.getElementsByTagName('body')[0], {
                childList: true,
                attributes: true,
                characterData: true,
                subtree: true
            });
            // set the onbeforunload function
            if (config.preventUnload) {
                Context.onbeforeunload = window.onbeforeunload;
                window.onbeforeunload = function () {
                    return 'Are you sure you want to leave the page while the SinglePageFuzzer is running?!';
                };
            }
            if (config.patchXMLHttpRequestSend) {
                this.origXMLHttpRequestSend = XMLHttpRequest.prototype.send;
                // use a wrapper function to keep the scope of the xhr object
                var sendProxy_1 = this.sendProxy.bind(this);
                XMLHttpRequest.prototype.send = function () {
                    var args = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        args[_i - 0] = arguments[_i];
                    }
                    sendProxy_1(this, args);
                };
            }
            // if an on/offline timer is set, initalize timeout
            this.offline = false;
            if (typeof this.config.offline == 'function') {
                if (typeof this.config.online != 'function') {
                    console.warn('there is an offline handler, but no online handler, so the fuzzer goes offline but' +
                        'never online again.');
                }
                this.toggleLine();
            }
            // set the onerror function
            Context.onerror = window.onerror;
            window.onerror = function (message, url, line, col, error) {
                console.error(message, url, line, col, error);
                // call the original error handler
                Context.onerror(message, url, line, col, error);
                // do not prevent error default error handling
                return false;
            };
            // start the fuzzer
            this.startAction();
        }
        // stop and destory the runner
        Runner.prototype.stop = function () {
            // reset the onbeforeunload function
            if (this.config.preventUnload) {
                window.onbeforeunload = Context.onbeforeunload;
            }
            if (this.config.patchXMLHttpRequestSend) {
                XMLHttpRequest.prototype.send = this.origXMLHttpRequestSend;
            }
            // clear the online / offline timeout
            if (this.lineTimeout !== null) {
                clearTimeout(this.lineTimeout);
            }
            // reset the onerror function
            window.onerror = Context.onerror;
            // stop the mutation observer
            this.observer.disconnect();
            // make sure the runner stops
            this.config.stopAfter = -1;
            // remove the runner from the context
            Context.runner = null;
        };
        Runner.prototype.startAction = function () {
            // check if the runner is done
            if (this.config.stopAfter != 0 && this.startTime + this.config.stopAfter * 1000 < performance.now()) {
                return this.stop();
            }
            // reset the active elements array and the style changes
            this.activeElements = [];
            // as long as we dont have timing statistics, only select one node to get more statistics
            var len = 1;
            if (this.withoutActionLimit > 0) {
                // else add more elements with a poisson distribution
                var lambda = typeof this.config.lambda == 'function' ? this.config.lambda(this.startTime) : 1;
                len = Math.max(1, poisson(lambda));
            }
            // find sutable elements
            while (this.activeElements.length < len) {
                // pick an element from the viewport
                var el = this.selectElement();
                // set the value for inputs
                if (el.nodeName == 'INPUT') {
                    // empty the input value
                    el['value'] = '';
                    // generate a random number of chars, in average 16
                    for (var i = poisson(16); i > 0; i -= 1) {
                        el['value'] += this.config.allowedChars[Math.floor(Math.random() * this.config.allowedChars.length)];
                    }
                }
                {
                    var event_1 = void 0;
                    if (typeof this.config.createEvent == 'function') {
                        event_1 = this.config.createEvent();
                    }
                    else {
                        var rng = Math.random();
                        // creat a click event with 60% probability and a dblclick event with 20% probability
                        if (rng < 0.8) {
                            event_1 = document.createEvent('HTMLEvents');
                            event_1.initEvent(rng < 0.6 ? 'click' : 'dblclick', true, true);
                        }
                        else {
                            var keyCode = [
                                27,
                                9,
                                13,
                                32,
                                8,
                                46,
                                38,
                                37,
                                39,
                                40 // down
                            ][Math.floor(Math.random() * 10)];
                            event_1 = document.createEvent('Events');
                            event_1.initEvent('keydown', true, true);
                            event_1['keyCode'] = keyCode;
                            event_1['which'] = keyCode;
                        }
                    }
                    // dispach event to picked element
                    var start_1 = performance.now();
                    el.dispatchEvent(event_1);
                    this.dispatchTime = performance.now() - start_1;
                }
                // if the dispatch time is below the action limit, pick a new element
                if (this.dispatchTime < this.withoutActionLimit) {
                    continue;
                }
                // we found a valid element
                this.activeElements.push(el);
            }
            // reset the dom change tracker
            this.hasDOMChanged = false;
            // wait until all mutations are done
            this.lastAction = performance.now();
            setTimeout(this.allDone.bind(this), 20);
        };
        // check if the browser has finished the action
        Runner.prototype.allDone = function () {
            var elapsed = performance.now() - this.lastAction;
            // if a dom mutation has occured, ore some backround javascript is running, wait for another 20 ms
            if (elapsed >= 20 && elapsed < 25) {
                // only change acceptance and color if only one element is selected, else we cannot map the mutations
                // to the selected element
                if (this.activeElements.length == 1) {
                    // do not reduce the acceptance of the input fields
                    if (this.hasDOMChanged || this.activeElements[0].nodeName == 'INPUT') {
                        // if the dispatch time is smaller than the minimal dispatch of mutated elements time, update it
                        if (this.minWithMutationTime == 0 || this.dispatchTime < this.minWithMutationTime) {
                            this.minWithMutationTime = this.dispatchTime;
                        }
                    }
                    else {
                        // if the dispatch time is bigger than the maximum dispatch time of non mutated elements, update it
                        if (this.dispatchTime > this.maxWithoutMutationTime) {
                            this.maxWithoutMutationTime = this.dispatchTime;
                        }
                    }
                    // if the time limit for dispatch times without mutations has changed, update it
                    var limit = Math.min(this.maxWithoutMutationTime, 0.8 * this.minWithMutationTime);
                    if (limit > this.withoutActionLimit) {
                        console.log("update without action limit to " + limit.toFixed(2) + " ms");
                        this.withoutActionLimit = limit;
                    }
                }
                // start next action
                this.startAction();
            }
            else {
                this.lastAction = performance.now();
                setTimeout(this.allDone.bind(this), 20);
            }
        };
        // select an element from the visible part of the webpage
        Runner.prototype.selectElement = function () {
            // selected element to act on
            var el = null;
            // pick points until a sutable element is found
            while (el === null) {
                // find a random element in viewport
                var x = Math.floor(Math.random() * window.innerWidth);
                var y = Math.floor(Math.random() * window.innerHeight);
                el = document.elementFromPoint(x, y);
                if (
                // if you hit the scrollbar on OSX there is no element ...
                el !== null && (
                // if the selectFilter hook is valid check if the element passes the filter
                typeof this.config.selectFilter != 'function' ||
                    !this.config.selectFilter(x, y, el))) {
                    el = null;
                }
            }
            // the element is valid
            return el;
        };
        // switch from online to offline state ...
        Runner.prototype.toggleLine = function () {
            var _this = this;
            var fn = this.config[this.offline ? 'online' : 'offline'];
            if (typeof fn == 'function') {
                var duration_1 = Math.round(fn());
                this.lineTimeout = setTimeout(function () {
                    _this.offline = !_this.offline;
                    console.log("go " + (_this.offline ? 'offline' : 'online') + " after " + (duration_1 / 1000.).toFixed(2) + " s");
                    _this.toggleLine();
                }, duration_1);
            }
            else {
                this.lineTimeout = null;
            }
        };
        // proxy function for the xhr send function
        Runner.prototype.sendProxy = function (xhr, args) {
            var _this = this;
            // if we are offline, every request fails ...
            if (this.offline) {
                // call the onerror handler, if the it exits, else call the onreadystatechange with xhr.status = 0
                if (typeof xhr.onerror == 'function') {
                    setTimeout(xhr.onerror.bind(xhr, null));
                }
                else if (typeof xhr.onreadystatechange == 'function') {
                    setTimeout(function () {
                        xhr.status = 0;
                        for (var i = 0; i < 5; i += 1) {
                            xhr.readyState = i;
                            xhr.onreadystatechange(null);
                        }
                    });
                }
            }
            else if (typeof this.config.dropRequest == 'function' && this.config.dropRequest(xhr, args)) {
                console.log('drop request');
                // if a timeout handler exits, call the timeout handler
                if (xhr.timeout && typeof xhr.ontimeout == 'function') {
                    setTimeout(function () { return xhr.ontimeout(null); }, xhr.timeout);
                }
            }
            else {
                // do we want to drop the response?
                if (typeof this.config.dropResponse == 'function' && this.config.dropResponse(xhr, args)) {
                    console.log('drop response');
                    // if a timeout handler exits, call the timeout handler
                    if (xhr.timeout && typeof xhr.ontimeout == 'function') {
                        setTimeout(function () { return xhr.ontimeout(null); }, xhr.timeout);
                    }
                    // remove the response handlers to simulate a request loss
                    xhr.onerror = null;
                    xhr.onreadystatechange = null;
                }
                else if (typeof this.config.lag == 'function') {
                    setTimeout(function () { return _this.origXMLHttpRequestSend.apply(xhr, args); }, Math.max(0, this.config.lag(xhr, args)));
                }
                else {
                    this.origXMLHttpRequestSend.apply(xhr, args);
                }
            }
        };
        return Runner;
    }());
})(SinglePageFuzzer || (SinglePageFuzzer = {}));
//# sourceMappingURL=singlepagefuzzer.js.map<commit_msg>fix infinite loop if selectFilter is not provided<commit_after>/**
 * @author Lukas Gamper, lukas.gamper@usystems.ch
 * @copyright uSystems GmbH, www.usystems.ch
 */
var SinglePageFuzzer;
(function (SinglePageFuzzer) {
    'use strict';
    /**
     * Default implementation of the config interface
     */
    var Config = (function () {
        function Config() {
            // run until stop is called
            this.stopAfter = 0;
            this.preventUnload = false;
            this.patchXMLHttpRequestSend = true;
            this.allowedChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
                'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
                'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Y', 'ä', 'ö', 'ü,', 'Ä', 'Ö', 'Ü',
                'ß', 'à', 'ç', 'è', 'ê', 'ë', 'ì', 'î', 'ï', 'ò', 'ó', 'ù', 'ą', 'ć', 'ĉ', 'ę', 'ĝ', 'ĥ', 'ĵ', 'ł', 'ń',
                'œ', 'ś', 'ŝ', 'ŭ', 'ź', 'ż', '+', '%', '&', '/', '\\', '!', '^', '`', '"', '\'', '[', ']', '<', '>', ':',
                '?', ';', '{', '}', '$', ' ', '\t', '\n'];
        }
        return Config;
    }());
    SinglePageFuzzer.Config = Config;
    /**
     * Start the Fuzzer
     * @param {IConfig} config options for the fuzzer
     */
    function start(config) {
        if (config === void 0) { config = new Config(); }
        // make sure the runner has stopped
        stop();
        // create new runner
        Context.runner = new Runner(config);
    }
    SinglePageFuzzer.start = start;
    /**
     * Generate a random number from a normal distribution using the Box-Muller transformation
     * https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform
     * @param {number} mean mean of the distribution
     * @param {number} std standard deviation of the distribution
     * @param {boolean} positive if true, the result is always bigger than 0
     * @return {number} random number drawn from a normal distributed
     */
    function normal(mean, std, positive) {
        if (mean === void 0) { mean = 0; }
        if (std === void 0) { std = 1; }
        if (positive === void 0) { positive = false; }
        var n = null;
        while (n === null) {
            var u1 = Math.random();
            var u2 = Math.random();
            var n01 = Math.sqrt(-2. * Math.log(u1)) * Math.cos(2. * Math.PI * u2);
            n = n01 * std + mean;
            if (positive && n <= 0) {
                n = null;
            }
        }
        return n;
    }
    SinglePageFuzzer.normal = normal;
    /**
     * Generate a random number from a poisson distribution https://en.wikipedia.org/wiki/Poisson_distribution
     * @param {number} lambda lambda of the distribution
     * @return {number} random number drawn from a poisson distribution
     */
    function poisson(lambda) {
        var L = Math.exp(-lambda);
        var k = 0;
        var p = 1;
        while (p > L) {
            k += 1;
            p *= Math.random();
        }
        return k - 1;
    }
    SinglePageFuzzer.poisson = poisson;
    /**
     * Stop the Fuzzer
     */
    function stop() {
        if (Context.runner instanceof Runner) {
            Context.runner.stop();
        }
    }
    SinglePageFuzzer.stop = stop;
    /**
     * Class containing the state informations
     */
    var Context = (function () {
        function Context() {
        }
        // active runner
        Context.runner = null;
        return Context;
    }());
    /**
     * Runner
     */
    var Runner = (function () {
        // create a runner and directly start picking element
        function Runner(config) {
            var _this = this;
            this.config = config;
            // minimal time used for actions with dom mutations
            this.minWithMutationTime = 0;
            // maximum time used for actions without dom mutations
            this.maxWithoutMutationTime = 0;
            // time limit for dispaching an event to determin if a function has a javascript handler or not
            this.withoutActionLimit = 0;
            // should the single page fuzzer simulate an offline situation
            this.offline = false;
            // the timeout handler for the on/offline change
            this.lineTimeout = null;
            // determine when to stop. If config.stopAfter == 0, run until stop is called
            this.startTime = performance.now();
            // initalize the mutation ovserver to observe all changes on the page
            this.observer = new MutationObserver(function (mutations) {
                // update the last change time
                _this.lastAction = performance.now();
                if (!_this.hasDOMChanged) {
                    mutations.forEach(function (mutation) {
                        // only register non hidden elements as dom mutations
                        /* tslint:disable:no-string-literal */
                        if (typeof mutation.target['offsetParent'] != 'undefined' && mutation.target['offsetParent'] !== null) {
                            _this.hasDOMChanged = true;
                        }
                    });
                }
            });
            this.observer.observe(document.getElementsByTagName('body')[0], {
                childList: true,
                attributes: true,
                characterData: true,
                subtree: true
            });
            // set the onbeforunload function
            if (config.preventUnload) {
                Context.onbeforeunload = window.onbeforeunload;
                window.onbeforeunload = function () {
                    return 'Are you sure you want to leave the page while the SinglePageFuzzer is running?!';
                };
            }
            if (config.patchXMLHttpRequestSend) {
                this.origXMLHttpRequestSend = XMLHttpRequest.prototype.send;
                // use a wrapper function to keep the scope of the xhr object
                var sendProxy_1 = this.sendProxy.bind(this);
                XMLHttpRequest.prototype.send = function () {
                    var args = [];
                    for (var _i = 0; _i < arguments.length; _i++) {
                        args[_i - 0] = arguments[_i];
                    }
                    sendProxy_1(this, args);
                };
            }
            // if an on/offline timer is set, initalize timeout
            this.offline = false;
            if (typeof this.config.offline == 'function') {
                if (typeof this.config.online != 'function') {
                    console.warn('there is an offline handler, but no online handler, so the fuzzer goes offline but' +
                        'never online again.');
                }
                this.toggleLine();
            }
            // set the onerror function
            Context.onerror = window.onerror;
            window.onerror = function (message, url, line, col, error) {
                console.error(message, url, line, col, error);
                // call the original error handler
                Context.onerror(message, url, line, col, error);
                // do not prevent error default error handling
                return false;
            };
            // start the fuzzer
            this.startAction();
        }
        // stop and destory the runner
        Runner.prototype.stop = function () {
            // reset the onbeforeunload function
            if (this.config.preventUnload) {
                window.onbeforeunload = Context.onbeforeunload;
            }
            if (this.config.patchXMLHttpRequestSend) {
                XMLHttpRequest.prototype.send = this.origXMLHttpRequestSend;
            }
            // clear the online / offline timeout
            if (this.lineTimeout !== null) {
                clearTimeout(this.lineTimeout);
            }
            // reset the onerror function
            window.onerror = Context.onerror;
            // stop the mutation observer
            this.observer.disconnect();
            // make sure the runner stops
            this.config.stopAfter = -1;
            // remove the runner from the context
            Context.runner = null;
        };
        Runner.prototype.startAction = function () {
            // check if the runner is done
            if (this.config.stopAfter != 0 && this.startTime + this.config.stopAfter * 1000 < performance.now()) {
                return this.stop();
            }
            // reset the active elements array and the style changes
            this.activeElements = [];
            // as long as we dont have timing statistics, only select one node to get more statistics
            var len = 1;
            if (this.withoutActionLimit > 0) {
                // else add more elements with a poisson distribution
                var lambda = typeof this.config.lambda == 'function' ? this.config.lambda(this.startTime) : 1;
                len = Math.max(1, poisson(lambda));
            }
            // find sutable elements
            while (this.activeElements.length < len) {
                // pick an element from the viewport
                var el = this.selectElement();
                // set the value for inputs
                if (el.nodeName == 'INPUT') {
                    // empty the input value
                    el['value'] = '';
                    // generate a random number of chars, in average 16
                    for (var i = poisson(16); i > 0; i -= 1) {
                        el['value'] += this.config.allowedChars[Math.floor(Math.random() * this.config.allowedChars.length)];
                    }
                }
                {
                    var event_1 = void 0;
                    if (typeof this.config.createEvent == 'function') {
                        event_1 = this.config.createEvent();
                    }
                    else {
                        var rng = Math.random();
                        // creat a click event with 60% probability and a dblclick event with 20% probability
                        if (rng < 0.8) {
                            event_1 = document.createEvent('HTMLEvents');
                            event_1.initEvent(rng < 0.6 ? 'click' : 'dblclick', true, true);
                        }
                        else {
                            var keyCode = [
                                27,
                                9,
                                13,
                                32,
                                8,
                                46,
                                38,
                                37,
                                39,
                                40 // down
                            ][Math.floor(Math.random() * 10)];
                            event_1 = document.createEvent('Events');
                            event_1.initEvent('keydown', true, true);
                            event_1['keyCode'] = keyCode;
                            event_1['which'] = keyCode;
                        }
                    }
                    // dispach event to picked element
                    var start_1 = performance.now();
                    el.dispatchEvent(event_1);
                    this.dispatchTime = performance.now() - start_1;
                }
                // if the dispatch time is below the action limit, pick a new element
                if (this.dispatchTime < this.withoutActionLimit) {
                    continue;
                }
                // we found a valid element
                this.activeElements.push(el);
            }
            // reset the dom change tracker
            this.hasDOMChanged = false;
            // wait until all mutations are done
            this.lastAction = performance.now();
            setTimeout(this.allDone.bind(this), 20);
        };
        // check if the browser has finished the action
        Runner.prototype.allDone = function () {
            var elapsed = performance.now() - this.lastAction;
            // if a dom mutation has occured, ore some backround javascript is running, wait for another 20 ms
            if (elapsed >= 20 && elapsed < 25) {
                // only change acceptance and color if only one element is selected, else we cannot map the mutations
                // to the selected element
                if (this.activeElements.length == 1) {
                    // do not reduce the acceptance of the input fields
                    if (this.hasDOMChanged || this.activeElements[0].nodeName == 'INPUT') {
                        // if the dispatch time is smaller than the minimal dispatch of mutated elements time, update it
                        if (this.minWithMutationTime == 0 || this.dispatchTime < this.minWithMutationTime) {
                            this.minWithMutationTime = this.dispatchTime;
                        }
                    }
                    else {
                        // if the dispatch time is bigger than the maximum dispatch time of non mutated elements, update it
                        if (this.dispatchTime > this.maxWithoutMutationTime) {
                            this.maxWithoutMutationTime = this.dispatchTime;
                        }
                    }
                    // if the time limit for dispatch times without mutations has changed, update it
                    var limit = Math.min(this.maxWithoutMutationTime, 0.8 * this.minWithMutationTime);
                    if (limit > this.withoutActionLimit) {
                        console.log("update without action limit to " + limit.toFixed(2) + " ms");
                        this.withoutActionLimit = limit;
                    }
                }
                // start next action
                this.startAction();
            }
            else {
                this.lastAction = performance.now();
                setTimeout(this.allDone.bind(this), 20);
            }
        };
        // select an element from the visible part of the webpage
        Runner.prototype.selectElement = function () {
            // selected element to act on
            var el = null;
            // pick points until a sutable element is found
            while (el === null) {
                // find a random element in viewport
                var x = Math.floor(Math.random() * window.innerWidth);
                var y = Math.floor(Math.random() * window.innerHeight);
                el = document.elementFromPoint(x, y);
                if (
                // if you hit the scrollbar on OSX there is no element ...
                el !== null &&
                // if the selectFilter hook is valid check if the element passes the filter
                typeof this.config.selectFilter != 'function' &&
                !this.config.selectFilter(x, y, el)) {
                    el = null;
                }
            }
            // the element is valid
            return el;
        };
        // switch from online to offline state ...
        Runner.prototype.toggleLine = function () {
            var _this = this;
            var fn = this.config[this.offline ? 'online' : 'offline'];
            if (typeof fn == 'function') {
                var duration_1 = Math.round(fn());
                this.lineTimeout = setTimeout(function () {
                    _this.offline = !_this.offline;
                    console.log("go " + (_this.offline ? 'offline' : 'online') + " after " + (duration_1 / 1000.).toFixed(2) + " s");
                    _this.toggleLine();
                }, duration_1);
            }
            else {
                this.lineTimeout = null;
            }
        };
        // proxy function for the xhr send function
        Runner.prototype.sendProxy = function (xhr, args) {
            var _this = this;
            // if we are offline, every request fails ...
            if (this.offline) {
                // call the onerror handler, if the it exits, else call the onreadystatechange with xhr.status = 0
                if (typeof xhr.onerror == 'function') {
                    setTimeout(xhr.onerror.bind(xhr, null));
                }
                else if (typeof xhr.onreadystatechange == 'function') {
                    setTimeout(function () {
                        xhr.status = 0;
                        for (var i = 0; i < 5; i += 1) {
                            xhr.readyState = i;
                            xhr.onreadystatechange(null);
                        }
                    });
                }
            }
            else if (typeof this.config.dropRequest == 'function' && this.config.dropRequest(xhr, args)) {
                console.log('drop request');
                // if a timeout handler exits, call the timeout handler
                if (xhr.timeout && typeof xhr.ontimeout == 'function') {
                    setTimeout(function () { return xhr.ontimeout(null); }, xhr.timeout);
                }
            }
            else {
                // do we want to drop the response?
                if (typeof this.config.dropResponse == 'function' && this.config.dropResponse(xhr, args)) {
                    console.log('drop response');
                    // if a timeout handler exits, call the timeout handler
                    if (xhr.timeout && typeof xhr.ontimeout == 'function') {
                        setTimeout(function () { return xhr.ontimeout(null); }, xhr.timeout);
                    }
                    // remove the response handlers to simulate a request loss
                    xhr.onerror = null;
                    xhr.onreadystatechange = null;
                }
                else if (typeof this.config.lag == 'function') {
                    setTimeout(function () { return _this.origXMLHttpRequestSend.apply(xhr, args); }, Math.max(0, this.config.lag(xhr, args)));
                }
                else {
                    this.origXMLHttpRequestSend.apply(xhr, args);
                }
            }
        };
        return Runner;
    }());
})(SinglePageFuzzer || (SinglePageFuzzer = {}));
//# sourceMappingURL=singlepagefuzzer.js.map
<|endoftext|>


<commit_before>(function () {
  'use strict';

  var hostRule = [
    /^(www\.)?adf\.(ly|acb\.im|sazlina\.com|animechiby\.com)$/,
    /^[jq]\.gs$/,
    /^go\.(phpnulledscripts|nicoblog-games)\.com$/,
    /^ay\.gy$/,
    /^(chathu|alien)\.apkmania\.co$/,
    /^ksn\.mx$/,
    /^goto\.adflytutor\.com$/,
    /^dl\.apkpro\.net$/,
    /^adf(ly\.itsrinaldo|\.tuhoctoan)\.net$/,
    /^.*\.gamecopyworld\.com$/,
    /^adv\.coder143\.com$/,
    /^(dl|david)\.nhachot\.info$/,
    /^file\.tamteo\.com$/,
    /^(n|u)\.shareme\.in$/,
    /^d?dl\.animesave\.(com|tk)$/,
  ];

  $.register({
    rule: {
      host: hostRule,
      path: /\/locked$/,
      query: /url=([^&]+)/,
    },
    start: function (m) {
      $.resetCookies();
      $.openLink('/' + m.query[1]);
    },
  });

  $.register({
    rule: {
      host: hostRule,
    },
    ready: function () {
      // check if this is ad page
      var h = $.$('#adfly_html'), b = $.$('#home');
      if (!h || !b || h.nodeName !== 'HTML' || b.nodeName !== 'BODY') {
        // this is not a ad page
        return;
      }

      $.removeNodes('iframe');

      // disable cookie check
      unsafeWindow.cookieCheck = $.inject(_.nop);

      h = unsafeWindow.eu;
      if (!h) {
        h = $('#adfly_bar');
        unsafeWindow.close_bar();
        return;
      }
      var a = h.indexOf('!HiTommy'), b = '';
      if (a >= 0) {
        h = h.substring(0, a);
      }
      a = '';
      for (var i = 0; i < h.length; ++i) {
        if (i % 2 === 0) {
          a = a + h.charAt(i);
        } else {
          b = h.charAt(i) + b;
        }
      }
      h = atob(a + b);
      h = h.substr(2);
      if (location.hash) {
        h += location.hash;
      }
      // some sites need Referer header
      $.openLinkWithReferer(h);
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<commit_msg>Fix warning.<commit_after>(function () {
  'use strict';

  var hostRule = [
    /^(www\.)?adf\.(ly|acb\.im|sazlina\.com|animechiby\.com)$/,
    /^[jq]\.gs$/,
    /^go\.(phpnulledscripts|nicoblog-games)\.com$/,
    /^ay\.gy$/,
    /^(chathu|alien)\.apkmania\.co$/,
    /^ksn\.mx$/,
    /^goto\.adflytutor\.com$/,
    /^dl\.apkpro\.net$/,
    /^adf(ly\.itsrinaldo|\.tuhoctoan)\.net$/,
    /^.*\.gamecopyworld\.com$/,
    /^adv\.coder143\.com$/,
    /^(dl|david)\.nhachot\.info$/,
    /^file\.tamteo\.com$/,
    /^(n|u)\.shareme\.in$/,
    /^d?dl\.animesave\.(com|tk)$/,
  ];

  $.register({
    rule: {
      host: hostRule,
      path: /\/locked$/,
      query: /url=([^&]+)/,
    },
    start: function (m) {
      $.resetCookies();
      $.openLink('/' + m.query[1]);
    },
  });

  $.register({
    rule: {
      host: hostRule,
    },
    ready: function () {
      // check if this is ad page
      var h = $.$('#adfly_html'), b = $.$('#home');
      if (!h || !b || h.nodeName !== 'HTML' || b.nodeName !== 'BODY') {
        // this is not a ad page
        return;
      }

      $.removeNodes('iframe');

      // disable cookie check
      unsafeWindow.cookieCheck = $.inject(_.nop);

      h = unsafeWindow.eu;
      if (!h) {
        h = $('#adfly_bar');
        unsafeWindow.close_bar();
        return;
      }
      var a = h.indexOf('!HiTommy');
      if (a >= 0) {
        h = h.substring(0, a);
      }
      a = '';
      b = '';
      for (var i = 0; i < h.length; ++i) {
        if (i % 2 === 0) {
          a = a + h.charAt(i);
        } else {
          b = h.charAt(i) + b;
        }
      }
      h = atob(a + b);
      h = h.substr(2);
      if (location.hash) {
        h += location.hash;
      }
      // some sites need Referer header
      $.openLinkWithReferer(h);
    },
  });

})();

// ex: ts=2 sts=2 sw=2 et
// sublime: tab_size 2; translate_tabs_to_spaces true; detect_indentation false; use_tab_stops true;
// kate: space-indent on; indent-width 2;
<|endoftext|>


<commit_before>import Phaser from 'phaser'

export default class extends Phaser.Sprite {
  constructor ({ game, x, y, asset }) {
    super(game, x, y, asset)
    this.anchor.setTo(0.5)
  }

  update () {
    this.angle += 1
  }
}
<commit_msg>Removed unused sprite<commit_after><|endoftext|>


<commit_before>function GeneratorJs(rowNamespace, functionsNamespace) {
	this.rowNamespace = rowNamespace;
	this.functionsNamespace = functionsNamespace;
};

GeneratorJs.prototype.fromAst = function(ast, select, unwrapAliases) {
	var type = ast.getNodeType();

	if(!this[type])
		throw new Error('Unknown node type: ' + type);

	if (type === 'ColumnIdent' && unwrapAliases && select) {
		var requestedAlias = ast.fragments.join('.');

		for (var i = 0; i < select.columns.length; i++) {
			var c = select.columns[i];

			var name = this.getColumnName(c);
			if (!name) {
				name = 'col_' + i;
			}

			if (!c.alias) {
				continue;
			}

			if (name === requestedAlias) {
				return this.fromAst(c.expression, select, unwrapAliases);
			}
		}
	}

	return this[type](ast, select, unwrapAliases);
};

GeneratorJs.prototype.getColumnName = function(ast) {
	if(ast.alias)
		return ast.alias.name;

	if(ast.expression.getNodeType() === 'ColumnIdent')
		return ast.expression.fragments[ast.expression.fragments.length - 1];

	return null;
};

GeneratorJs.prototype.Select = function(ast) {
	var self = this;
	var args = [this.rowNamespace, this.functionsNamespace];

	var columnNamesArray = [];
	var columnValuesObjectCode = [];

	var valuesArrayFunction;
	var valuesObjectFunction;

	var fromAstUnwrappedBinded = function(childAst) {
		return self.fromAst(childAst, ast, true);
	};

	if(ast.columns) {
		var columnValuesArrayCode = [];

		for(var i = 0; i < ast.columns.length; i++) {
			var c = ast.columns[i];

			var name = '' + (this.getColumnName(c) || i);
			var code = this.fromAst(c.expression, ast);

			columnNamesArray.push(name + '');
			columnValuesArrayCode.push(code);
			columnValuesObjectCode.push(JSON.stringify(name) + ': ' + code);
		}

		valuesArrayFunction = new Function(args, 'return [' + columnValuesArrayCode.join(', ') + '];');
		valuesObjectFunction = new Function(args, 'return {' + columnValuesObjectCode.join(', ') + '};')
	} else {
		// кейс для SELECT * FROM ...
		valuesObjectFunction = function(r) { return r };
		valuesArrayFunction = function(r) { throw new Error('Array-based rows is not dupported in "SELECT * ..." queries') };
	}

	var groupByFunction = null;
	var groupByFunctionJson = null;

	if(ast.groups.length) {
		groupByFunction = new Function(args, 'return [' + ast.groups.map(fromAstUnwrappedBinded).join(', ') + '];');
		groupByFunctionJson = new Function(args, 'return JSON.stringify([' + ast.groups.map(fromAstUnwrappedBinded).join(', ') + ']);');
	}

	var orderByFunction = null;

	if(ast.orders.length)
		orderByFunction = new Function(args, 'return [' + ast.orders.map(fromAstUnwrappedBinded).join(', ') + '];');

	return {
		row: {
			columns: columnNamesArray,
			valuesArray: valuesArrayFunction,
			valuesObject: valuesObjectFunction
		},
		where: ast.where ? new Function(args, 'return ' + fromAstUnwrappedBinded(ast.where) + ';') : null,
		groupBy: groupByFunction,
		groupByJson: groupByFunctionJson,
		orderBy: orderByFunction
	};
};

GeneratorJs.prototype.ColumnIdent = function(ast, select, unwrapAliases) {
	return this.ComplexIdent(ast, select, unwrapAliases);
};

GeneratorJs.prototype.FunctionIdent = function(ast, select, unwrapAliases) {
	return this.functionsNamespace + '[' + ast.fragments.map(JSON.stringify).join('][') + ']';
};

GeneratorJs.prototype.ComplexIdent = function(ast, select, unwrapAliases) {
	this.rowNamespace = 'r';

	var namespace = this.rowNamespace;
	var checks = [];

	var getJsIdent = function(path) {
		return namespace + '[' + path.map(JSON.stringify).join('][') + ']'
	};

	for(var i = 0; i < ast.fragments.length - 1; i++) {
		var segs = ast.fragments.slice(0, i + 1);

		var p = getJsIdent(segs);
		checks.push(p + ' !== null');
		checks.push(p + ' !== undefined');
	}

	if(checks.length)
		return '((' + checks.join(' && ') + ') ? ' + getJsIdent(ast.fragments) + ' : undefined)';
	else
		return getJsIdent(ast.fragments);
};

GeneratorJs.prototype.Number = function(ast) {
	return ast.value + '';
};

GeneratorJs.prototype.String = function(ast) {
	return "'" + ast.value + "'";
};

GeneratorJs.prototype.Call = function(ast, select, unwrapAliases) {
	var n = this.fromAst(ast.function, select, unwrapAliases);
	var a = [];

	for(var i = 0; i < ast.args.length; i++) {
		a.push(this.fromAst(ast.args[i], select, unwrapAliases));
	}

	return n + '(' + a.join(', ') + ')';
};

GeneratorJs.prototype.Order = function(ast, select, unwrapAliases) {
	return this.fromAst(ast.expression, select, unwrapAliases);
};

GeneratorJs.prototype.UnaryOperation = function(ast, select, unwrapAliases) {
	return ast.operator + '' + this.fromAst(ast.right, select, unwrapAliases);
};

GeneratorJs.prototype.BinaryOperation = function(ast, select, unwrapAliases) {
	var map = {
		AND: '&&',
		OR: '||',
		'=': '=='
	};

	var op = map[ast.operator] ? map[ast.operator] : ast.operator;

	return this.fromAst(ast.left, select, unwrapAliases) + ' ' + op + ' ' + this.fromAst(ast.right, select, unwrapAliases);
};

GeneratorJs.prototype.In = function(ast, select, unwrapAliases) {
	var w = [];
	var n = this.fromAst(ast.needle);

	for(var i = 0; i < ast.haystack.length; i++) {
		var e = ast.haystack[i];
		w.push(n + ' == ' + this.fromAst(e, select, unwrapAliases));
	}

	return '(' + w.join(' || ') + ')';
};

GeneratorJs.prototype.Brackets = function(ast, select, unwrapAliases) {
	return '(' + this.fromAst(ast.expression, select, unwrapAliases) + ')';
};

GeneratorJs.prototype.Null = function(ast, select, unwrapAliases) {
	return 'null';
};

exports.GeneratorJs = GeneratorJs;
<commit_msg>Fix: отловлен рекурсивный ресолв альясов<commit_after>function GeneratorJs(rowNamespace, functionsNamespace) {
	this.rowNamespace = rowNamespace;
	this.functionsNamespace = functionsNamespace;
};

GeneratorJs.prototype.fromAst = function(ast, select, unwrapAliases) {
	var type = ast.getNodeType();

	if(!this[type])
		throw new Error('Unknown node type: ' + type);

	if (type === 'ColumnIdent' && unwrapAliases && select) {
		var requestedAlias = ast.fragments.join('.');

		for (var i = 0; i < select.columns.length; i++) {
			var c = select.columns[i];

			var name = this.getColumnName(c);
			if (!name) {
				name = 'col_' + i;
			}

			if (!c.alias) {
				continue;
			}

			if (name === requestedAlias && ast !== c.expression) {
				return this.fromAst(c.expression, select);
			}
		}
	}

	return this[type](ast, select, unwrapAliases);
};

GeneratorJs.prototype.getColumnName = function(ast) {
	if(ast.alias)
		return ast.alias.name;

	if(ast.expression.getNodeType() === 'ColumnIdent')
		return ast.expression.fragments[ast.expression.fragments.length - 1];

	return null;
};

GeneratorJs.prototype.Select = function(ast) {
	var self = this;
	var args = [this.rowNamespace, this.functionsNamespace];

	var columnNamesArray = [];
	var columnValuesObjectCode = [];

	var valuesArrayFunction;
	var valuesObjectFunction;

	var fromAstUnwrappedBinded = function(childAst) {
		return self.fromAst(childAst, ast, true);
	};

	if(ast.columns) {
		var columnValuesArrayCode = [];

		for(var i = 0; i < ast.columns.length; i++) {
			var c = ast.columns[i];

			var name = '' + (this.getColumnName(c) || i);
			var code = this.fromAst(c.expression, ast);

			columnNamesArray.push(name + '');
			columnValuesArrayCode.push(code);
			columnValuesObjectCode.push(JSON.stringify(name) + ': ' + code);
		}

		valuesArrayFunction = new Function(args, 'return [' + columnValuesArrayCode.join(', ') + '];');
		valuesObjectFunction = new Function(args, 'return {' + columnValuesObjectCode.join(', ') + '};')
	} else {
		// кейс для SELECT * FROM ...
		valuesObjectFunction = function(r) { return r };
		valuesArrayFunction = function(r) { throw new Error('Array-based rows is not dupported in "SELECT * ..." queries') };
	}

	var groupByFunction = null;
	var groupByFunctionJson = null;

	if(ast.groups.length) {
		groupByFunction = new Function(args, 'return [' + ast.groups.map(fromAstUnwrappedBinded).join(', ') + '];');
		groupByFunctionJson = new Function(args, 'return JSON.stringify([' + ast.groups.map(fromAstUnwrappedBinded).join(', ') + ']);');
	}

	var orderByFunction = null;

	if(ast.orders.length)
		orderByFunction = new Function(args, 'return [' + ast.orders.map(fromAstUnwrappedBinded).join(', ') + '];');

	return {
		row: {
			columns: columnNamesArray,
			valuesArray: valuesArrayFunction,
			valuesObject: valuesObjectFunction
		},
		where: ast.where ? new Function(args, 'return ' + fromAstUnwrappedBinded(ast.where) + ';') : null,
		groupBy: groupByFunction,
		groupByJson: groupByFunctionJson,
		orderBy: orderByFunction
	};
};

GeneratorJs.prototype.ColumnIdent = function(ast, select, unwrapAliases) {
	return this.ComplexIdent(ast, select, unwrapAliases);
};

GeneratorJs.prototype.FunctionIdent = function(ast, select, unwrapAliases) {
	return this.functionsNamespace + '[' + ast.fragments.map(JSON.stringify).join('][') + ']';
};

GeneratorJs.prototype.ComplexIdent = function(ast, select, unwrapAliases) {
	this.rowNamespace = 'r';

	var namespace = this.rowNamespace;
	var checks = [];

	var getJsIdent = function(path) {
		return namespace + '[' + path.map(JSON.stringify).join('][') + ']'
	};

	for(var i = 0; i < ast.fragments.length - 1; i++) {
		var segs = ast.fragments.slice(0, i + 1);

		var p = getJsIdent(segs);
		checks.push(p + ' !== null');
		checks.push(p + ' !== undefined');
	}

	if(checks.length)
		return '((' + checks.join(' && ') + ') ? ' + getJsIdent(ast.fragments) + ' : undefined)';
	else
		return getJsIdent(ast.fragments);
};

GeneratorJs.prototype.Number = function(ast) {
	return ast.value + '';
};

GeneratorJs.prototype.String = function(ast) {
	return "'" + ast.value + "'";
};

GeneratorJs.prototype.Call = function(ast, select, unwrapAliases) {
	var n = this.fromAst(ast.function, select, unwrapAliases);
	var a = [];

	for(var i = 0; i < ast.args.length; i++) {
		a.push(this.fromAst(ast.args[i], select, unwrapAliases));
	}

	return n + '(' + a.join(', ') + ')';
};

GeneratorJs.prototype.Order = function(ast, select, unwrapAliases) {
	return this.fromAst(ast.expression, select, unwrapAliases);
};

GeneratorJs.prototype.UnaryOperation = function(ast, select, unwrapAliases) {
	return ast.operator + '' + this.fromAst(ast.right, select, unwrapAliases);
};

GeneratorJs.prototype.BinaryOperation = function(ast, select, unwrapAliases) {
	var map = {
		AND: '&&',
		OR: '||',
		'=': '=='
	};

	var op = map[ast.operator] ? map[ast.operator] : ast.operator;

	return this.fromAst(ast.left, select, unwrapAliases) + ' ' + op + ' ' + this.fromAst(ast.right, select, unwrapAliases);
};

GeneratorJs.prototype.In = function(ast, select, unwrapAliases) {
	var w = [];
	var n = this.fromAst(ast.needle);

	for(var i = 0; i < ast.haystack.length; i++) {
		var e = ast.haystack[i];
		w.push(n + ' == ' + this.fromAst(e, select, unwrapAliases));
	}

	return '(' + w.join(' || ') + ')';
};

GeneratorJs.prototype.Brackets = function(ast, select, unwrapAliases) {
	return '(' + this.fromAst(ast.expression, select, unwrapAliases) + ')';
};

GeneratorJs.prototype.Null = function(ast, select, unwrapAliases) {
	return 'null';
};

exports.GeneratorJs = GeneratorJs;
<|endoftext|>


<commit_before>import { Store } from 'consus-core/flux';
import CheckoutStore from './checkout-store';
import CheckinStore from './checkin-store';
import StudentStore from './student-store';
import { createAddress, readAddress } from 'consus-core/identifiers';
import { dueDateToTimestamp } from '../lib/clock';

let items = [];
let itemsByActionId = Object.create(null);

class ItemStore extends Store {

    getFaultyItems() {
        return items.filter(item => item.isFaulty);
    }

    getItems() {
        return items.filter(item => item !== undefined);
    }

    getItemByAddress(address) {
        let result = readAddress(address);
        if (result.type !== 'item') {
            throw new Error('Address is not an item.');
        }
        return items[result.index];
    }

    getItemByActionId(actionId) {
        return itemsByActionId[actionId];
    }

    getOverdueItems() {
        return StudentStore.getStudents().reduce((overdueItems, student) => {
            return overdueItems.concat(student.items.filter(item => {
                item.student = {
                    name: student.name,
                    id: student.id
                };
                return item.timestamp < Math.floor(Date.now() / 1000);
            }));
        }, []);
    }

    deleteItemByAddress(address){
        let result = readAddress(address);
        if (result.type !== 'item') {
            throw new Error('Address is not an item.');
        }
        delete items[result.index];
    }

    getChildrenOfModel(modelAddress) {
        return items.filter(item => item.modelAddress === modelAddress);
    }

}

function checkoutEquipment(equipment, studentId, dueDateTime) {
    equipment.forEach(equip => {
        let address = equip.address;
        let result = readAddress(address);
        if (result.type === 'item') {
            store.getItemByAddress(address).status = 'CHECKED_OUT';
            store.getItemByAddress(address).isCheckedOutTo = studentId;
            let dueTime = dueDateToTimestamp(dueDateTime);
            store.getItemByAddress(address).timestamp = dueTime;
        }
    });
}

function changeItemDueDate(dueDate, itemAddress){
    store.getItemByAddress(itemAddress).timestamp = dueDateToTimestamp(dueDate);
}

const store = new ItemStore();

store.registerHandler('CLEAR_ALL_DATA', () => {
    items = [];
    itemsByActionId = Object.create(null);
});

store.registerHandler('NEW_ITEM', data => {
    let item = {
        address: createAddress(items.length, 'item'),
        modelAddress: data.modelAddress,
        status: 'AVAILABLE',
        isFaulty: false,
        faultHistory: [],
        isCheckedOutTo: null
    };
    itemsByActionId[data.actionId] = item;
    items.push(item);
});

store.registerHandler('NEW_CHECKOUT', data => {
    store.waitFor(CheckoutStore);
    checkoutEquipment(data.equipment, data.studentId, data.timestamp);
});

store.registerHandler('NEW_LONGTERM_CHECKOUT', data => {
    store.waitFor(CheckoutStore);
    checkoutEquipment(data.equipment, data.studentId, data.dueDate);
});

store.registerHandler('CHECKIN', data => {
    store.waitFor(CheckinStore);
    if (typeof CheckinStore.getCheckinByActionId(data.actionId) !== 'object') {
        return;
    }
    store.getItemByAddress(data.itemAddress).status = 'AVAILABLE';
    store.getItemByAddress(data.itemAddress).isCheckedOutTo = null;
});

store.registerHandler('DELETE_ITEM', data => {
    store.deleteItemByAddress(data.itemAddress);
});

store.registerHandler('SAVE_ITEM', data => {
    let result = readAddress(data.itemAddress);
    if (result.type !== 'item' ) {
        throw new Error('Address is not an item.');
    }
    let item = items[result.index];
    if (item.status === 'AVAILABLE') {
        throw new Error('Item is not checked out.');
    }
    if (item.status === 'SAVED') {
        throw new Error('Item is already saved.');
    }
    item.status = 'SAVED';
});

store.registerHandler('RETRIEVE_ITEM', data => {
    let result = readAddress(data.itemAddress);
    if (result.type !== 'item' ) {
        throw new Error('Address is not an item.');
    }
    let item = items[result.index];
    if (item.status !== 'SAVED') {
        throw new Error('Item is not saved.');
    }
    item.status = 'CHECKED_OUT';
});

store.registerHandler('DELETE_MODEL', data => {
    let itemsOfModel = store.getItems().filter(item => item.modelAddress === data.modelAddress);
    itemsOfModel.forEach(item => store.deleteItemByAddress(item.address));
});

store.registerHandler('ADD_ITEM_FAULT', data => {
    store.getItemByAddress(data.itemAddress).isFaulty = true;
    store.getItemByAddress(data.itemAddress).faultHistory.unshift({
        description: data.description,
        timestamp: data.timestamp
    });
});

store.registerHandler('REMOVE_FAULT', data => {
    store.getItemByAddress(data.itemAddress).isFaulty = false;
});

store.registerHandler('CHANGE_ITEM_DUEDATE', data => {
    changeItemDueDate(data.dueDate, data.itemAddress);
});

export default store;
<commit_msg>Fixed a thing<commit_after>import { Store } from 'consus-core/flux';
import CheckoutStore from './checkout-store';
import CheckinStore from './checkin-store';
import StudentStore from './student-store';
import { createAddress, readAddress } from 'consus-core/identifiers';
import { dueDateToTimestamp } from '../lib/clock';

let items = [];
let itemsByActionId = Object.create(null);

class ItemStore extends Store {

    getFaultyItems() {
        return items.filter(item => item.faultHistory.length > 0);
    }

    getItems() {
        return items.filter(item => item !== undefined);
    }

    getItemByAddress(address) {
        let result = readAddress(address);
        if (result.type !== 'item') {
            throw new Error('Address is not an item.');
        }
        return items[result.index];
    }

    getItemByActionId(actionId) {
        return itemsByActionId[actionId];
    }

    getOverdueItems() {
        return StudentStore.getStudents().reduce((overdueItems, student) => {
            return overdueItems.concat(student.items.filter(item => {
                item.student = {
                    name: student.name,
                    id: student.id
                };
                return item.timestamp < Math.floor(Date.now() / 1000);
            }));
        }, []);
    }

    deleteItemByAddress(address){
        let result = readAddress(address);
        if (result.type !== 'item') {
            throw new Error('Address is not an item.');
        }
        delete items[result.index];
    }

    getChildrenOfModel(modelAddress) {
        return items.filter(item => item.modelAddress === modelAddress);
    }

}

function checkoutEquipment(equipment, studentId, dueDateTime) {
    equipment.forEach(equip => {
        let address = equip.address;
        let result = readAddress(address);
        if (result.type === 'item') {
            store.getItemByAddress(address).status = 'CHECKED_OUT';
            store.getItemByAddress(address).isCheckedOutTo = studentId;
            let dueTime = dueDateToTimestamp(dueDateTime);
            store.getItemByAddress(address).timestamp = dueTime;
        }
    });
}

function changeItemDueDate(dueDate, itemAddress){
    store.getItemByAddress(itemAddress).timestamp = dueDateToTimestamp(dueDate);
}

const store = new ItemStore();

store.registerHandler('CLEAR_ALL_DATA', () => {
    items = [];
    itemsByActionId = Object.create(null);
});

store.registerHandler('NEW_ITEM', data => {
    let item = {
        address: createAddress(items.length, 'item'),
        modelAddress: data.modelAddress,
        status: 'AVAILABLE',
        isFaulty: false,
        faultHistory: [],
        isCheckedOutTo: null
    };
    itemsByActionId[data.actionId] = item;
    items.push(item);
});

store.registerHandler('NEW_CHECKOUT', data => {
    store.waitFor(CheckoutStore);
    checkoutEquipment(data.equipment, data.studentId, data.timestamp);
});

store.registerHandler('NEW_LONGTERM_CHECKOUT', data => {
    store.waitFor(CheckoutStore);
    checkoutEquipment(data.equipment, data.studentId, data.dueDate);
});

store.registerHandler('CHECKIN', data => {
    store.waitFor(CheckinStore);
    if (typeof CheckinStore.getCheckinByActionId(data.actionId) !== 'object') {
        return;
    }
    store.getItemByAddress(data.itemAddress).status = 'AVAILABLE';
    store.getItemByAddress(data.itemAddress).isCheckedOutTo = null;
});

store.registerHandler('DELETE_ITEM', data => {
    store.deleteItemByAddress(data.itemAddress);
});

store.registerHandler('SAVE_ITEM', data => {
    let result = readAddress(data.itemAddress);
    if (result.type !== 'item' ) {
        throw new Error('Address is not an item.');
    }
    let item = items[result.index];
    if (item.status === 'AVAILABLE') {
        throw new Error('Item is not checked out.');
    }
    if (item.status === 'SAVED') {
        throw new Error('Item is already saved.');
    }
    item.status = 'SAVED';
});

store.registerHandler('RETRIEVE_ITEM', data => {
    let result = readAddress(data.itemAddress);
    if (result.type !== 'item' ) {
        throw new Error('Address is not an item.');
    }
    let item = items[result.index];
    if (item.status !== 'SAVED') {
        throw new Error('Item is not saved.');
    }
    item.status = 'CHECKED_OUT';
});

store.registerHandler('DELETE_MODEL', data => {
    let itemsOfModel = store.getItems().filter(item => item.modelAddress === data.modelAddress);
    itemsOfModel.forEach(item => store.deleteItemByAddress(item.address));
});

store.registerHandler('ADD_ITEM_FAULT', data => {
    store.getItemByAddress(data.itemAddress).isFaulty = true;
    store.getItemByAddress(data.itemAddress).faultHistory.unshift({
        description: data.description,
        timestamp: data.timestamp
    });
});

store.registerHandler('REMOVE_FAULT', data => {
    store.getItemByAddress(data.itemAddress).isFaulty = false;
});

store.registerHandler('CHANGE_ITEM_DUEDATE', data => {
    changeItemDueDate(data.dueDate, data.itemAddress);
});

export default store;
<|endoftext|>


<commit_before>require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfTokenHeader, bsAlert) {

    avalon.ready(function () {
        //avalon.vmodels.group = null;
        if (avalon.vmodels.group) {
            var vm = avalon.vmodels.group;
        }
        else {

            var vm = avalon.define({
                $id: "group",
                //通用变量
                groupList: [],                 //  用户列表数据项
                previousPage: 0,                 //  之前的页数
                nextPage: 0,                     //   之后的页数
                page: 1,                           //    当前页数
                totalPage: 1,                   //    总页数
                keyword: "",

                getNext: function () {
                    if (!vm.nextPage)
                        return;
                    getPageData(vm.page + 1);
                },
                getPrevious: function () {
                    if (!vm.previousPage)
                        return;
                    getPageData(vm.page - 1);
                },
                getBtnClass: function (btnType) {
                    if (btnType == "next") {
                        return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
                    }
                    else {
                        return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
                    }

                },
                search: function(){
                    getPageData(1);
                },
                getGroupSettingString: function (setting) {
                    return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting]
                },
                showGroupDetailPage: function (groupId) {
                    vm.$fire("up!showGroupDetailPage", groupId);
                }
            });
        }

        getPageData(1);

        function getPageData(page) {
            var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=2";
            if (vm.keyword)
                url += "&keyword=" + vm.keyword;
            $.ajax({
                url: url,
                dataType: "json",
                method: "get",
                success: function (data) {
                    if (!data.code) {
                        vm.groupList = data.data.results;
                        vm.totalPage = data.data.total_page;
                        vm.previousPage = data.data.previous_page;
                        vm.nextPage = data.data.next_page;
                        vm.page = page;
                    }
                    else {
                        bsAlert(data.data);
                    }
                }
            });
        }

    });

    avalon.scan();

});
<commit_msg>[前端-后台]统一分页参数,每页10条记录[CI SKIP]<commit_after>require(["jquery", "avalon", "csrfToken", "bsAlert"], function ($, avalon, csrfTokenHeader, bsAlert) {

    avalon.ready(function () {
        //avalon.vmodels.group = null;
        if (avalon.vmodels.group) {
            var vm = avalon.vmodels.group;
        }
        else {

            var vm = avalon.define({
                $id: "group",
                //通用变量
                groupList: [],                 //  用户列表数据项
                previousPage: 0,                 //  之前的页数
                nextPage: 0,                     //   之后的页数
                page: 1,                           //    当前页数
                totalPage: 1,                   //    总页数
                keyword: "",

                getNext: function () {
                    if (!vm.nextPage)
                        return;
                    getPageData(vm.page + 1);
                },
                getPrevious: function () {
                    if (!vm.previousPage)
                        return;
                    getPageData(vm.page - 1);
                },
                getBtnClass: function (btnType) {
                    if (btnType == "next") {
                        return vm.nextPage ? "btn btn-primary" : "btn btn-primary disabled";
                    }
                    else {
                        return vm.previousPage ? "btn btn-primary" : "btn btn-primary disabled";
                    }

                },
                search: function(){
                    getPageData(1);
                },
                getGroupSettingString: function (setting) {
                    return {0: "允许任何人加入", 1: "提交请求后管理员审核", 2: "不允许任何人加入"}[setting]
                },
                showGroupDetailPage: function (groupId) {
                    vm.$fire("up!showGroupDetailPage", groupId);
                }
            });
        }

        getPageData(1);

        function getPageData(page) {
            var url = "/api/admin/group/?paging=true&page=" + page + "&page_size=10";
            if (vm.keyword)
                url += "&keyword=" + vm.keyword;
            $.ajax({
                url: url,
                dataType: "json",
                method: "get",
                success: function (data) {
                    if (!data.code) {
                        vm.groupList = data.data.results;
                        vm.totalPage = data.data.total_page;
                        vm.previousPage = data.data.previous_page;
                        vm.nextPage = data.data.next_page;
                        vm.page = page;
                    }
                    else {
                        bsAlert(data.data);
                    }
                }
            });
        }

    });

    avalon.scan();

});
<|endoftext|>


<commit_before>import VueRouter from 'vue-router'

import DiagramsOverview from '@/components/zetalayout/overview/WebpageDiagramsOverview'
import MetamodelCodeEditor from '@/components/zetalayout/metamodel/CodeEditor'
import MetamodelGraphicalEditor from '@/components/zetalayout/overview/GraphicalEditor'
import ZetaLayout from '@/components/zetalayout/ZetaLayout'
import AccountLayout from '@/components/accountlayout/AccountLayout'
import SignIn from '@/components/accountlayout/signin/SignIn'
import SignUp from '@/components/accountlayout/signup/signUp'
import PasswordForgot from "@/components/accountlayout/password/forgot/PasswordForgot";
import PasswordChange from "@/components/accountlayout/password/change/PasswordChange";

const isAuthenticated = function() {
    return !!(localStorage.getItem("user-token") || "")
}

const ifNotAuthenticated = (to, from, next) => {
    if (!isAuthenticated()) {
        next();
        return;
    }
    next("/");
};

const ifAuthenticated = (to, from, next) => {
    if (isAuthenticated()) {
        next();
        return;
    }
    next("/account/signIn");
};

const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            redirect: '/zeta/overview'
        },
        {
            path: '/zeta',
            component: ZetaLayout,
            beforeEnter: ifAuthenticated,
            children: [
                {
                    path: 'overview/:id?',
                    component: DiagramsOverview
                },
                {
                    path: 'codeEditor/editor/:id/:dslType',
                    component: MetamodelCodeEditor
                },
                {
                    path: 'metamodel/editor/:id',
                    component: MetamodelGraphicalEditor
                }
            ]
        },
        {
            path: '/account',
            component: AccountLayout,
            children: [
                {
                    path: 'signIn',
                    component: SignIn,
                    beforeEnter: ifNotAuthenticated
                },
                {
                    path: 'signUp',
                    component: SignUp,
                    beforeEnter: ifNotAuthenticated
                },
                {
                    path: 'password/forgot',
                    component: PasswordForgot,
                    beforeEnter: ifNotAuthenticated
                },
                {
                    path: 'password/change',
                    component: PasswordChange,
                    beforeEnter: ifAuthenticated
                }
            ]
        }
    ]
})

export default router
<commit_msg>Adjusted dependency to new dev<commit_after>import VueRouter from 'vue-router'

import DiagramsOverview from '@/components/zetalayout/overview/WebpageDiagramsOverview'
import MetamodelCodeEditor from '@/components/zetalayout/metamodel/code-editor/CodeEditor'
import MetamodelGraphicalEditor from '@/components/zetalayout/overview/GraphicalEditor'
import ZetaLayout from '@/components/zetalayout/ZetaLayout'
import AccountLayout from '@/components/accountlayout/AccountLayout'
import SignIn from '@/components/accountlayout/signin/SignIn'
import SignUp from '@/components/accountlayout/signup/signUp'
import PasswordForgot from "@/components/accountlayout/password/forgot/PasswordForgot";
import PasswordChange from "@/components/accountlayout/password/change/PasswordChange";

const isAuthenticated = function() {
    return !!(localStorage.getItem("user-token") || "")
}

const ifNotAuthenticated = (to, from, next) => {
    if (!isAuthenticated()) {
        next();
        return;
    }
    next("/");
};

const ifAuthenticated = (to, from, next) => {
    if (isAuthenticated()) {
        next();
        return;
    }
    next("/account/signIn");
};

const router = new VueRouter({
    mode: 'history',
    routes: [
        {
            path: '/',
            redirect: '/zeta/overview'
        },
        {
            path: '/zeta',
            component: ZetaLayout,
            beforeEnter: ifAuthenticated,
            children: [
                {
                    path: 'overview/:id?',
                    component: DiagramsOverview
                },
                {
                    path: 'codeEditor/editor/:id/:dslType',
                    component: MetamodelCodeEditor
                },
                {
                    path: 'metamodel/editor/:id',
                    component: MetamodelGraphicalEditor
                }
            ]
        },
        {
            path: '/account',
            component: AccountLayout,
            children: [
                {
                    path: 'signIn',
                    component: SignIn,
                    beforeEnter: ifNotAuthenticated
                },
                {
                    path: 'signUp',
                    component: SignUp,
                    beforeEnter: ifNotAuthenticated
                },
                {
                    path: 'password/forgot',
                    component: PasswordForgot,
                    beforeEnter: ifNotAuthenticated
                },
                {
                    path: 'password/change',
                    component: PasswordChange,
                    beforeEnter: ifAuthenticated
                }
            ]
        }
    ]
})

export default router
<|endoftext|>


<commit_before>(function(Vue){
  var nodesTableTemplate = `

            最新插件版本
            总机器数
            最后心跳在1h前的机器数

            {{ numNodes }}
            {{ numInactiveNodes }}

            机器名
            IP
            Agent版本
            插件版本
            上次心跳
            插件项

            正在获取数据……

            并没有机器，正确的安装 agent 了么？

            {{ n.hostname }}
            {{ n.ip }}
            {{ n['agent-version'] }}

            {{ timeFromNow(n.lastseen) }}

                {{ v }}

                {{ v._metric }}

  `;

  var NodesTable = Vue.extend({
    template: nodesTableTemplate,
    props: ['api-endpoint', 'api-auth'],
    mounted() {
      this.refresh();
    },
    data() {
      return {
        nodes: null,
        pluginVersion: '...',
        numNodes: '...',
        numInactiveNodes: '...',
      }
    },
    methods: {
      _getFetchHeaders() {
        var headers = new Headers();
        if(this.apiAuth) {
          headers.append("Authorization", "Basic " + btoa(this.apiAuth));
        }
        return headers;
      },
      refresh() {
        var opts = {
          method: "GET",
          headers: this._getFetchHeaders(),
          credentials: 'include',
        };

        fetch(this.apiEndpoint, opts).then(resp => resp.json()).then((state) => {
          this.pluginVersion = state['plugin-version'];
          this.numNodes = Object.keys(state['agents']).length;
          this.numInactiveNodes = _.sum(_.map(state.agents, (a) => new Date() / 1000 - a.lastseen > 3600));
          this.nodes = _.map(state.agents, (v, k) => {
            v.pluginDirs = _.sortBy(state['plugin-dirs'][k]);
            v.pluginMetrics = _.sortBy(state['plugin-metrics'][k], v => v._metric);
            return v;
          });
        });
      },
      timeFromNow(ts) {
        return moment(new Date(ts * 1000)).locale('zh-cn').fromNow();
      },
      showMetric(m) {
        alert(JSON.stringify(m, null, 2));
      },
    }
  });

  Vue.component('nodes-table', NodesTable);
})(Vue);
<commit_msg>JavaScript is awesome.<commit_after>(function(Vue){
  var nodesTableTemplate = `

            最新插件版本
            总机器数
            最后心跳在1h前的机器数

            {{ numNodes }}
            {{ numInactiveNodes }}

            机器名
            IP
            Agent版本
            插件版本
            上次心跳
            插件项

            正在获取数据……

            并没有机器，正确的安装 agent 了么？

            {{ n.hostname }}
            {{ n.ip }}
            {{ n['agent-version'] }}

            {{ timeFromNow(n.lastseen) }}

                {{ v }}

                {{ v._metric }}

  `;

  var NodesTable = Vue.extend({
    template: nodesTableTemplate,
    props: ['api-endpoint', 'api-auth'],
    mounted() {
      this.refresh();
    },
    data() {
      return {
        nodes: null,
        pluginVersion: '...',
        numNodes: '...',
        numInactiveNodes: '...',
      }
    },
    methods: {
      _getFetchHeaders() {
        var headers = new Headers();
        if(this.apiAuth) {
          headers.append("Authorization", "Basic " + btoa(this.apiAuth));
        }
        return headers;
      },
      refresh() {
        var opts = {
          method: "GET",
          headers: this._getFetchHeaders(),
          credentials: 'include',
        };

        fetch(this.apiEndpoint, opts).then(resp => resp.json()).then((state) => {
          this.pluginVersion = state['plugin-version'];
          this.numNodes = Object.keys(state['agents']).length;
          this.numInactiveNodes = _.sum(_.map(state.agents, (a) => new Date() / 1000 - a.lastseen > 3600));
          this.nodes = _.map(state.agents, (v, k) => {
            v.pluginDirs = _.sortBy(state['plugin-dirs'][k]);
            v.pluginMetrics = _.sortBy(state['plugin-metrics'][k], v => v._metric);
            return v;
          });
        });
      },
      timeFromNow(ts) {
        return moment(new Date(ts * 1000)).locale('zh-cn').fromNow();
      },
      showMetric(m) {
        alert(JSON.stringify(m, null, 2));
      },
    }
  });

  Vue.component('nodes-table', NodesTable);
})(Vue);
<|endoftext|>


<commit_before>(function(){var container=null;var markers=null;var mousewheel="onwheel"in document.createElement("div")?"wheel":document.onmousewheel!==undefined?"mousewheel":"DOMMouseScroll";function panZoom(opt_options){var self=this;var pz={pan:{},elm:self};opt_options=Object(opt_options);opt_options.zoom=opt_options.zoom||[];var svg=self;while((svg=self.parent).node.tagName.toUpperCase()!=="SVG"){}var rect=new SVG(document.createDocumentFragment()).rect().attr({width:svg.width(),height:svg.height(),fill:"none"}).style("pointer-events","all");self.parent.node.insertBefore(rect.node,self.node);function updateMatrix(){self.attr("transform","matrix("+[pz.transform.scaleX,0,0,pz.transform.scaleY,pz.transform.x,pz.transform.y].join(",")+")")}function pan(e){if(!pz.pan.mousedown){return}var tr=pz.transform=self.transform();var diffX=pz.pan.fPos.x-pz.pan.iPos.x;var diffY=pz.pan.fPos.y-pz.pan.iPos.y;tr.x+=diffX;tr.y+=diffY;pz.pan.iPos=pz.pan.fPos;self.node.dispatchEvent(new CustomEvent("pan",e,tr));updateMatrix()}function zoom(e){var rP=mousePos(e,true);var oX=rP.x;var oY=rP.y;e.deltaY=e.deltaY||e.wheelDeltaY;var d=e.deltaY/1e3;var tr=pz.transform=self.transform();var scale=tr.scaleX+tr.scaleX*d;var scaleD=scale/tr.scaleX;var currentX=tr.x;var currentY=tr.y;var x=scaleD*(currentX-oX)+oX;var y=scaleD*(currentY-oY)+oY;if(scale>opt_options.zoom[1]){scale=opt_options.zoom[1];return}if(scale<opt_options.zoom[0]){scale=opt_options.zoom[0];return}tr.scaleY=tr.scaleX=scale;tr.x=x;tr.y=y;self.node.dispatchEvent(new CustomEvent("zoom",e,tr));updateMatrix();e.preventDefault()}function mousePos(e,rel){var bbox=self.bbox();var abs={x:e.clientX||e.touches[0].pageX,y:e.clientY||e.touches[0].pageY};if(!rel){return abs}return{x:abs.x-bbox.x,y:abs.y-bbox.y}}var EventListeners={mouse_down:function(e){pz.pan.mousedown=true;pz.pan.iPos=mousePos(e)},mouse_up:function(e){pz.pan.mousedown=false;pz.pan.fPos=mousePos(e);pan()},mouse_move:function(e){if(!pz.pan.mousedown){return}pz.pan.fPos=mousePos(e);pan()},mouse_leave:function(e){pz.pan.mousedown=false}};rect.on(mousewheel,zoom).on("mousedown",EventListeners.mouse_down).on("touchstart",EventListeners.mouse_down).on("mousemove",EventListeners.mouse_move).on("touchmove",EventListeners.mouse_move).on("mouseup",EventListeners.mouse_up).on("touchup",EventListeners.mouse_up).on("mouseleave",EventListeners.mouse_leave);self.on(mousewheel,zoom);return pz}SVG.extend(SVG.Element,{panZoom:panZoom})}).call(this);<commit_msg>Updated the minified script<commit_after>(function(){var container=null,markers=null,mousewheel="onwheel"in document.createElement("div")?"wheel":document.onmousewheel!==undefined?"mousewheel":"DOMMouseScroll";function panZoom(opt_options){var self=this;function setPosition(x,y,z){pz.pan.iPos=pz.pan.fPos;pz.transform=self.transform();pz.transform.x=x;pz.transform.y=y;if(typeof z==="number"){pz.zoom(z)}else{updateMatrix()}return pz}function zoom(z){if(typeof z==="number"){pz.transform=self.transform();pz.transform.scaleY=pz.transform.scaleX=z;updateMatrix();return pz}pz.transform=self.transform();pz.transform.scaleY=pz.transform.scaleX=z;updateMatrix();return pz}var pz={pan:{},elm:self,setPosition:setPosition,zoom:zoom};opt_options=Object(opt_options);opt_options.zoom=opt_options.zoom||[];var svg=self;while((svg=self.parent).node.tagName.toUpperCase()!=="SVG"){}var rect=new SVG(document.createDocumentFragment()).rect().attr({width:svg.width(),height:svg.height(),fill:"none"}).style("pointer-events","all");self.parent.node.insertBefore(rect.node,self.node);function updateMatrix(){self.attr("transform","matrix("+[pz.transform.scaleX,0,0,pz.transform.scaleY,pz.transform.x,pz.transform.y].join(",")+")")}function pan(e){if(!pz.pan.mousedown){return}var tr=pz.transform=self.transform();var diffX=pz.pan.fPos.x-pz.pan.iPos.x;var diffY=pz.pan.fPos.y-pz.pan.iPos.y;pz.setPosition(tr.x+diffX,tr.y+diffY);self.node.dispatchEvent(new CustomEvent("pan",e,tr))}function mousePos(e,rel){var bbox=self.parent.node.getBoundingClientRect(),abs={x:e.clientX||e.touches[0].pageX,y:e.clientY||e.touches[0].pageY};if(!rel){return abs}return{x:abs.x-bbox.left,y:abs.y-bbox.top}}function doZoom(e){var rP=mousePos(e,true),oX=rP.x,oY=rP.y;e.deltaY=e.deltaY||e.wheelDeltaY;var d=e.deltaY/1e3,tr=pz.transform=self.transform(),scale=tr.scaleX+tr.scaleX*d,scaleD=scale/tr.scaleX,currentX=tr.x,currentY=tr.y,x=scaleD*(currentX-oX)+oX,y=scaleD*(currentY-oY)+oY;if(scale>opt_options.zoom[1]){scale=opt_options.zoom[1];return}if(scale<opt_options.zoom[0]){scale=opt_options.zoom[0];return}tr.scaleY=tr.scaleX=scale;tr.x=x;tr.y=y;self.node.dispatchEvent(new CustomEvent("zoom",e,tr));updateMatrix();e.preventDefault()}var EventListeners={mouse_down:function(e){pz.pan.mousedown=true;pz.pan.iPos=mousePos(e)},mouse_up:function(e){pz.pan.mousedown=false;pz.pan.fPos=mousePos(e);pan()},mouse_move:function(e){if(!pz.pan.mousedown){return}pz.pan.fPos=mousePos(e);pan()},mouse_leave:function(e){pz.pan.mousedown=false}};rect.on(mousewheel,doZoom).on("mousedown",EventListeners.mouse_down).on("touchstart",EventListeners.mouse_down).on("mousemove",EventListeners.mouse_move).on("touchmove",EventListeners.mouse_move).on("mouseup",EventListeners.mouse_up).on("touchup",EventListeners.mouse_up).on("mouseleave",EventListeners.mouse_leave);self.on(mousewheel,doZoom);return pz}SVG.extend(SVG.Element,{panZoom:panZoom})}).call(this);<|endoftext|>