<commit_before>/**
 *
 * This test is needing all three files to be present
 *  - testSendData.js      : the main entry point to the test case
 *  - SendDataConnector.js : logic that handles the connection & data sending parts
 *  - SendDataTCPServer.js : logic that handles the server endpoint for connections & data receiving/replying for the test
 *
 * In this test case we try connecting to the remote peer and send N-bytes of data (where N should be big amount)
 * If the sending fails in midway, the logic will do reconnection to the same peer and send any remaining bytes until the whole N-bytes are sent over
 * We measure the time it takes to send the data and report that back.
 *
 * If specified the sending is done multiple times for each peer.
 *
 * Note that we don't want to sent the data both ways, and for this reason the server is not simply echoing back the data sent,
 * but actually only sends verifications on getting some predefined amount of data, currently the amount is specified as 10000 bytes
 */

var net = require('net');
var events = require('events');

function SendDataConnector(rounds,dataAmount,reTryTimeout,reTryMaxCount,dataTimeOut) {
    this.roundsToDo         = rounds;
    this.doneRounds         = 0;
    this.toSendDataAmount   = dataAmount;
    this.reTryTimeout       = reTryTimeout;
    this.reTryMaxCount      = reTryMaxCount;
    this.dataTimeOut        = dataTimeOut;
    this.clientSocket       = null;
    this.reTryTimer         = null;
    this.receivedCounter    = 0;
    this.tryRounds          = 0;
    this.resultArray        = [];
    this.connectionCount    = 0;
}

SendDataConnector.prototype = new events.EventEmitter;

SendDataConnector.prototype.Start = function(peer) {
    this.peer = peer;
    this.stopped = false;
    //reset the values to make sure they are clean when we start
    this.startTime = new Date();
    this.endTime = new Date();
    this.endReason ="";
    this.doneRounds         = 0;
    this.receivedCounter    = 0;
    this.tryRounds          = 0;
    this.resultArray        = [];
    this.connectionCount    = 0;

    this.ReStart(peer);
}

SendDataConnector.prototype.ReStart = function(peer) {
    this.peer = peer;
    if(!this.peer){
        return;
    }

    // make sure any previous connections are really out
    if(this.clientSocket != null) {
        console.log("CLIENT closeClientSocket");
        this.clientSocket.end()
        this.clientSocket = null;
    }

    Mobile('Disconnect').callNative(this.peer.peerIdentifier, function () {
        console.log("Disconnected by Mobile call");
    });

    console.log('Connect[' + this.tryRounds + '] to : ' + this.peer.peerIdentifier + 'Available: '  + this.peer.peerAvailable);
    this.doConnect(this.peer);
}

SendDataConnector.prototype.Stop = function(peer) {
    console.log("CLIENT Stop now");
    this.stopped = true;
    if(this.reTryTimer != null) {
        console.log("Stop retry timer");
        clearTimeout(this.reTryTimer);
        this.reTryTimer = null;
    }

    if (this.dataTimerId != null) {
        console.log("Stop data retrieving timer");
        clearTimeout(this.dataTimerId);
        this.dataTimerId = null;
    }

    //Closing Client socket, will also close connection
    if(this.clientSocket != null) {
        console.log("CLIENT closeClientSocket");
        this.clientSocket.end();
        this.clientSocket = null;
    }

    if(!this.peer){
        return;
    }
    Mobile('Disconnect').callNative(this.peer.peerIdentifier, function () {
        console.log("Disconnected by Mobile call");
    });
}

SendDataConnector.prototype.doConnect = function(peer) {
    var self = this;

    if(this.stopped){
        return;
    }

    if(!this.peer){
        return;
    }

    console.log("do connect now");
    this.connectionCount++;

    Mobile('Connect').callNative(peer.peerIdentifier, function (err, port) {
        console.log("CLIENT connected to " + port + ", error: " + err);

        if (err != null && err.length > 0) {
            console.log("CLIENT Can not Connect: " + err);
            self.endReason = err;
            self.tryAgain();

        } else if (port > 0) {
            console.log("CLIENT starting client ");

            self.clientSocket = net.connect(port, function () {
                // self.toSendDataAmount is the wanted amount of data in bytes.
                // The size of a single character is in a string is 2 bytes.
                // Below, the wanted amount of data is generated so that an array is
                // filled with integers that is turned into a string. For example,
                // a loop two times would generate something like: [1, 2].toString() -> '1,2'.
                // The size of that example string would be 3 * 2 = 6 bytes, because
                // a comma is entered between array values.
                console.log('CLIENT now sending ' + (self.toSendDataAmount - self.receivedCounter) + ' bytes of data');
                var numbers = [];
                // The right length for the array is calculated below by first splitting
                // the byte amount by two, which gives the amount of characters we need.
                // Number one is added, to even the fact that comma doesn't get appended
                // after the last character. Then, the number is split by two, because
                // each number in the array results also in one additional comma in the
                // resulting string.
                for (var i = 0; i < ((((self.toSendDataAmount - self.receivedCounter) / 2) + 1) / 2); i++) {
                    numbers[i] = Math.floor(Math.random() * 10);
                }
                self.resetDataTimeout(peer);
                self.clientSocket.write(numbers.toString());
            });
            self.clientSocket.on('data', function (data) {

                if (data.toString().trim()  == 'ACK') {
                    self.receivedCounter = self.receivedCounter + 10000;
                    self.resetDataTimeout(peer);
                }

                console.log('CLIENT is data received : ' + self.receivedCounter);

                if(self.receivedCounter >= self.toSendDataAmount){
                    if (self.dataTimerId != null) {
                        clearTimeout(self.dataTimerId);
                        self.dataTimerId = null;
                    }

                    self.endReason = "OK";
                    console.log('got all data for this round');

                    //we only reset the value once we have gotten all data, so any re-connect will sent only missing data
                    self.receivedCounter = 0;
                    self.oneRoundDoneNow();
                }
            });
            self.clientSocket.on('close', function () {
                console.log('CLIENT is closed');
            });

            self.clientSocket.on('error', function (ex) {
                console.log("CLIENT got error : " + ex);
                //just making sure that if we get error while disconnecting
                // we are then not calling the tryAgain twice
                if(!self.disconnecting) {
                    self.tryAgain();
                }
            });
        }else{
            console.log("Port in invalid : " + port);
            if(!self.disconnecting) {
                self.tryAgain();
            }
        }
    });
}

SendDataConnector.prototype.resetDataTimeout = function(peer) {
    var self = this;
    if (self.dataTimerId != null) {
        clearTimeout(self.dataTimerId);
        self.dataTimerId = null;
    }

    if(self.dataTimeOut) {
        self.dataTimerId = setTimeout(function () {
            console.log('Receiving data timeout now');
            self.endReason = "DATA-TIMEOUT";

            self.disconnecting = true;
            //Closing Client socket, will also close connection
            if(self.clientSocket != null) {
                console.log("CLIENT closeClientSocket");
                self.clientSocket.end();
                self.clientSocket.destroy();
                self.clientSocket = null;
            }
            self.tryAgain();
            self.disconnecting = false;
            console.log("----------------- closeClientSocket");

        }, self.dataTimeOut);
    }
}

SendDataConnector.prototype.tryAgain = function() {
    var self = this;

    if(this.stopped){
        return;
    }

    if(self.reTryTimer != null){
        return;
    }

    //Closing Client socket, will also close connection
    if(this.clientSocket != null) {
        console.log("CLIENT closeClientSocket");
        this.clientSocket.end();
        this.clientSocket = null;
    }

    this.tryRounds++;
    if(this.tryRounds >= self.reTryMaxCount) {
        this.oneRoundDoneNow();
        return;
    }

    console.log("tryAgain afer: " + self.reTryTimeout + " ms.");
    //lets try again after a short while
    self.reTryTimer = setTimeout(function () {

        if(!self.peer){
            return;
        }

        console.log("re-try now : " + self.peer.peerIdentifier);
        self.reTryTimer = null
        self.ReStart(self.peer);
    }, self.reTryTimeout);
}

SendDataConnector.prototype.oneRoundDoneNow = function() {
    this.Stop();

    if(!this.peer){
        return;
    }

    this.endTime = new Date();
    var responseTime = this.endTime - this.startTime;
    this.resultArray.push({"name":this.peer.peerIdentifier,"time":responseTime,"result":this.endReason,"connections":this.connectionCount,"tryCount":this.peer.tryCount});

    this.emit('debug','round[' +this.doneRounds + '] time: ' + responseTime + ' ms, rnd: ' + this.connectionCount + ', ex: ' + this.endReason);

    this.doneRounds++;
    if(this.roundsToDo > this.doneRounds){
        this.tryRounds = 0;
        this.receivedCounter = 0;

        //reset the values to make sure they are clean when we start new round
        this.startTime = new Date();
        this.endTime = new Date();
        this.endReason ="";
        this.connectionCount = 0;
        this.stopped = false;
        this.ReStart(this.peer);
        return;
    }

    //if we get this far, then we are done
    this.weAreDoneNow();
}

SendDataConnector.prototype.getCurrentTest = function() {
    if(!this.peer){
        return;
    }

    return {"connections":this.peer.tryCount, "name":this.peer.peerIdentifier,"time":0,"result":"Fail"};
}

SendDataConnector.prototype.getResultArray = function() {
    return this.resultArray;
}

SendDataConnector.prototype.weAreDoneNow = function() {
    this.Stop();

    //reset these for next peer test
    this.tryRounds = 0;
    this.startTime = new Date();
    this.endTime = new Date();
    this.endReason ="";
    this.connectionCount = 0;

    var tmpArr = this.resultArray;
    this.resultArray = [];
    this.peer = null;
    this.emit('done', JSON.stringify(tmpArr));
}

module.exports = SendDataConnector;
<commit_msg>Take into account the given retry timeout.<commit_after>/**
 *
 * This test is needing all three files to be present
 *  - testSendData.js      : the main entry point to the test case
 *  - SendDataConnector.js : logic that handles the connection & data sending parts
 *  - SendDataTCPServer.js : logic that handles the server endpoint for connections & data receiving/replying for the test
 *
 * In this test case we try connecting to the remote peer and send N-bytes of data (where N should be big amount)
 * If the sending fails in midway, the logic will do reconnection to the same peer and send any remaining bytes until the whole N-bytes are sent over
 * We measure the time it takes to send the data and report that back.
 *
 * If specified the sending is done multiple times for each peer.
 *
 * Note that we don't want to sent the data both ways, and for this reason the server is not simply echoing back the data sent,
 * but actually only sends verifications on getting some predefined amount of data, currently the amount is specified as 10000 bytes
 */

var net = require('net');
var events = require('events');

function SendDataConnector(rounds,dataAmount,reTryTimeout,reTryMaxCount,dataTimeOut) {
    this.roundsToDo         = rounds;
    this.doneRounds         = 0;
    this.toSendDataAmount   = dataAmount;
    this.reTryTimeout       = reTryTimeout;
    this.reTryMaxCount      = reTryMaxCount;
    this.dataTimeOut        = dataTimeOut;
    this.clientSocket       = null;
    this.reTryTimer         = null;
    this.receivedCounter    = 0;
    this.tryRounds          = 0;
    this.resultArray        = [];
    this.connectionCount    = 0;
}

SendDataConnector.prototype = new events.EventEmitter;

SendDataConnector.prototype.Start = function(peer) {
    this.peer = peer;
    this.stopped = false;
    //reset the values to make sure they are clean when we start
    this.startTime = new Date();
    this.endTime = new Date();
    this.endReason ="";
    this.doneRounds         = 0;
    this.receivedCounter    = 0;
    this.tryRounds          = 0;
    this.resultArray        = [];
    this.connectionCount    = 0;

    this.ReStart(peer);
}

SendDataConnector.prototype.ReStart = function(peer) {
    this.peer = peer;
    if(!this.peer){
        return;
    }

    // make sure any previous connections are really out
    if(this.clientSocket != null) {
        console.log("CLIENT closeClientSocket");
        this.clientSocket.end()
        this.clientSocket = null;
    }

    var self = this;
    setTimeout(function () {
        Mobile('Disconnect').callNative(self.peer.peerIdentifier, function () {
            console.log('Connect (retry count ' + self.tryRounds + ') to peer ' +
                         self.peer.peerIdentifier + ' with availability status: '  +
                         self.peer.peerAvailable);
            self.doConnect(self.peer);
        });
    }, self.reTryTimeout);
}

SendDataConnector.prototype.Stop = function(peer) {
    console.log("CLIENT Stop now");
    this.stopped = true;
    if(this.reTryTimer != null) {
        console.log("Stop retry timer");
        clearTimeout(this.reTryTimer);
        this.reTryTimer = null;
    }

    if (this.dataTimerId != null) {
        console.log("Stop data retrieving timer");
        clearTimeout(this.dataTimerId);
        this.dataTimerId = null;
    }

    //Closing Client socket, will also close connection
    if(this.clientSocket != null) {
        console.log("CLIENT closeClientSocket");
        this.clientSocket.end();
        this.clientSocket = null;
    }
}

SendDataConnector.prototype.doConnect = function(peer) {
    var self = this;

    if(this.stopped){
        return;
    }

    if(!this.peer){
        return;
    }

    console.log("do connect now");
    this.connectionCount++;

    Mobile('Connect').callNative(peer.peerIdentifier, function (err, port) {
        console.log("CLIENT connected to " + port + ", error: " + err);

        if (err != null && err.length > 0) {
            console.log("CLIENT Can not Connect: " + err);
            self.endReason = err;
            self.tryAgain();

        } else if (port > 0) {
            console.log("CLIENT starting client ");

            self.clientSocket = net.connect(port, function () {
                // self.toSendDataAmount is the wanted amount of data in bytes.
                // The size of a single character is in a string is 2 bytes.
                // Below, the wanted amount of data is generated so that an array is
                // filled with integers that is turned into a string. For example,
                // a loop two times would generate something like: [1, 2].toString() -> '1,2'.
                // The size of that example string would be 3 * 2 = 6 bytes, because
                // a comma is entered between array values.
                console.log('CLIENT now sending ' + (self.toSendDataAmount - self.receivedCounter) + ' bytes of data');
                var numbers = [];
                // The right length for the array is calculated below by first splitting
                // the byte amount by two, which gives the amount of characters we need.
                // Number one is added, to even the fact that comma doesn't get appended
                // after the last character. Then, the number is split by two, because
                // each number in the array results also in one additional comma in the
                // resulting string.
                for (var i = 0; i < ((((self.toSendDataAmount - self.receivedCounter) / 2) + 1) / 2); i++) {
                    numbers[i] = Math.floor(Math.random() * 10);
                }
                self.resetDataTimeout(peer);
                self.clientSocket.write(numbers.toString());
            });
            self.clientSocket.on('data', function (data) {

                if (data.toString().trim()  == 'ACK') {
                    self.receivedCounter = self.receivedCounter + 10000;
                    self.resetDataTimeout(peer);
                }

                console.log('CLIENT is data received : ' + self.receivedCounter);

                if(self.receivedCounter >= self.toSendDataAmount){
                    if (self.dataTimerId != null) {
                        clearTimeout(self.dataTimerId);
                        self.dataTimerId = null;
                    }

                    self.endReason = "OK";
                    console.log('got all data for this round');

                    //we only reset the value once we have gotten all data, so any re-connect will sent only missing data
                    self.receivedCounter = 0;
                    self.oneRoundDoneNow();
                }
            });
            self.clientSocket.on('close', function () {
                console.log('CLIENT is closed');
            });

            self.clientSocket.on('error', function (ex) {
                console.log("CLIENT got error : " + ex);
                //just making sure that if we get error while disconnecting
                // we are then not calling the tryAgain twice
                if(!self.disconnecting) {
                    self.tryAgain();
                }
            });
        }else{
            console.log("Port in invalid : " + port);
            if(!self.disconnecting) {
                self.tryAgain();
            }
        }
    });
}

SendDataConnector.prototype.resetDataTimeout = function(peer) {
    var self = this;
    if (self.dataTimerId != null) {
        clearTimeout(self.dataTimerId);
        self.dataTimerId = null;
    }

    if(self.dataTimeOut) {
        self.dataTimerId = setTimeout(function () {
            console.log('Receiving data timeout now');
            self.endReason = "DATA-TIMEOUT";

            self.disconnecting = true;
            //Closing Client socket, will also close connection
            if(self.clientSocket != null) {
                console.log("CLIENT closeClientSocket");
                self.clientSocket.end();
                self.clientSocket.destroy();
                self.clientSocket = null;
            }
            self.tryAgain();
            self.disconnecting = false;
            console.log("----------------- closeClientSocket");

        }, self.dataTimeOut);
    }
}

SendDataConnector.prototype.tryAgain = function() {
    var self = this;

    if(this.stopped){
        return;
    }

    if(self.reTryTimer != null){
        return;
    }

    //Closing Client socket, will also close connection
    if(this.clientSocket != null) {
        console.log("CLIENT closeClientSocket");
        this.clientSocket.end();
        this.clientSocket = null;
    }

    this.tryRounds++;
    if(this.tryRounds >= self.reTryMaxCount) {
        this.oneRoundDoneNow();
        return;
    }

    console.log("tryAgain afer: " + self.reTryTimeout + " ms.");
    //lets try again after a short while
    self.reTryTimer = setTimeout(function () {

        if(!self.peer){
            return;
        }

        console.log("re-try now : " + self.peer.peerIdentifier);
        self.reTryTimer = null
        self.ReStart(self.peer);
    }, self.reTryTimeout);
}

SendDataConnector.prototype.oneRoundDoneNow = function() {
    this.Stop();

    if(!this.peer){
        return;
    }

    this.endTime = new Date();
    var responseTime = this.endTime - this.startTime;
    this.resultArray.push({"name":this.peer.peerIdentifier,"time":responseTime,"result":this.endReason,"connections":this.connectionCount,"tryCount":this.peer.tryCount});

    this.emit('debug','round[' +this.doneRounds + '] time: ' + responseTime + ' ms, rnd: ' + this.connectionCount + ', ex: ' + this.endReason);

    this.doneRounds++;
    if(this.roundsToDo > this.doneRounds){
        this.tryRounds = 0;
        this.receivedCounter = 0;

        //reset the values to make sure they are clean when we start new round
        this.startTime = new Date();
        this.endTime = new Date();
        this.endReason ="";
        this.connectionCount = 0;
        this.stopped = false;
        this.ReStart(this.peer);
        return;
    }

    //if we get this far, then we are done
    this.weAreDoneNow();
}

SendDataConnector.prototype.getCurrentTest = function() {
    if(!this.peer){
        return;
    }

    return {"connections":this.peer.tryCount, "name":this.peer.peerIdentifier,"time":0,"result":"Fail"};
}

SendDataConnector.prototype.getResultArray = function() {
    return this.resultArray;
}

SendDataConnector.prototype.weAreDoneNow = function() {
    this.Stop();

    //reset these for next peer test
    this.tryRounds = 0;
    this.startTime = new Date();
    this.endTime = new Date();
    this.endReason ="";
    this.connectionCount = 0;

    var tmpArr = this.resultArray;
    this.resultArray = [];
    this.peer = null;
    this.emit('done', JSON.stringify(tmpArr));
}

module.exports = SendDataConnector;
<|endoftext|>


<commit_before>module.exports = {
  env: {
    browser: true,
    commonjs: true,
    es6: true,
    node: true,
  },
  extends: [
    'airbnb-base',
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
  },
  parserOptions: {
    ecmaVersion: 2018,
  },
  rules: {
      'indent': [2, 4],
      'no-underscore-dangle': 'off',
      'camelcase': 'off',
      'no-unused-vars': 'off'
  },
};
<commit_msg>fixup! feat(build): Add jest for test<commit_after>module.exports = {
    env: {
        browser: true,
        commonjs: true,
        es6: true,
        node: true,
    },
    extends: [
        'airbnb-base',
    ],
    globals: {
        Atomics: 'readonly',
        SharedArrayBuffer: 'readonly',
    },
    parserOptions: {
        ecmaVersion: 2018,
    },
    rules: {
        'indent': [2, 4],
        'no-underscore-dangle': 'off',
        'camelcase': 'off',
        'no-unused-vars': 'off'
    },
    overrides: [
        {
            files: [
                "**/*.test.js",
                "**/*.spec.js",
                "**/*.spec.jsx"
            ],
            env: {
                jest: true
            }
        }
    ]
};
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2018 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
module.exports = {
    env: {
        es6: true,
        node: true,
        commonjs: true,
        jasmine: true,
        jest: true,
        browser: true
    },
    parser: "@typescript-eslint/parser",
    parserOptions: {
        ecmaVersion: 2018,
        sourceType: "module"
    },
    extends: [
        "plugin:@typescript-eslint/recommended",
        "plugin:jest/recommended",
        "prettier/@typescript-eslint",
        "plugin:promise/recommended",
        "plugin:prettier/recommended",
        "eslint:recommended"
    ],
    plugins: ["promise", "jest"],
    rules: {
        indent: "off",
        quotes: "off",
        "no-empty": "off",
        "linebreak-style": ["error", "unix"],
        semi: ["error", "always"],
        "default-case": "error",
        "no-use-before-define": "off",
        "consistent-return": "off",
        "no-lonely-if": "error",
        "no-console": "error",
        "valid-jsdoc": "off",
        eqeqeq: "error",
        "guard-for-in": "error",
        "no-caller": "error",
        "no-extend-native": "error",
        "no-extra-bind": "error",
        "no-loop-func": "error",
        "no-magic-numbers": "off",
        "no-new": "error",
        "no-new-func": "error",
        "no-proto": "error",
        "no-throw-literal": "error",
        "no-unmodified-loop-condition": "error",
        "no-unused-expressions": "error",
        "no-useless-call": "error",
        "no-useless-concat": "error",
        "prefer-promise-reject-errors": "error",
        "vars-on-top": "error",
        "no-catch-shadow": "error",
        "no-shadow": "off",
        "no-undefined": "off",
        "global-require": "error",
        "no-mixed-requires": "error",
        "no-path-concat": "error",
        "no-sync": "off",
        "no-useless-computed-key": "error",
        "no-useless-constructor": "error",
        "no-var": "error",
        "object-shorthand": "error",
        "prefer-arrow-callback": "error",
        "prefer-const": "error",
        "prefer-destructuring": "off",
        "prefer-template": "error",
        "prefer-spread": "error",
        "promise/always-return": "off",
        "promise/no-return-wrap": "error",
        "promise/param-names": "error",
        "promise/catch-or-return": "error",
        "promise/no-native": "off",
        "promise/no-nesting": "error",
        "promise/no-promise-in-callback": "warn",
        "promise/no-callback-in-promise": "warn",
        "promise/avoid-new": "error",
        "promise/no-new-statics": "off",
        "promise/no-return-in-finally": "off",
        "promise/valid-params": "off",
        "@typescript-eslint/no-use-before-define": ["error", { "functions": false }],
        "@typescript-eslint/no-namespace": "off",
    },
    overrides: [
        {
            files: ["*.js"],
            rules: {
                "@typescript-eslint/adjacent-overload-signatures": "off",
                "@typescript-eslint/array-type": "off",
                "@typescript-eslint/ban-types": "off",
                camelcase: "off",
                "@typescript-eslint/camelcase": "off",
                "@typescript-eslint/class-name-casing": "off",
                "@typescript-eslint/explicit-function-return-type": "off",
                "@typescript-eslint/explicit-member-accessibility": "off",
                indent: "off",
                "@typescript-eslint/indent": "off",
                "@typescript-eslint/interface-name-prefix": "off",
                "@typescript-eslint/member-delimiter-style": "off",
                "@typescript-eslint/no-angle-bracket-type-assertion": "off",
                "no-array-constructor": "off",
                "@typescript-eslint/no-array-constructor": "off",
                "@typescript-eslint/no-empty-interface": "off",
                "@typescript-eslint/no-explicit-any": "off",
                "@typescript-eslint/no-inferrable-types": "off",
                "@typescript-eslint/no-misused-new": "off",
                "@typescript-eslint/no-non-null-assertion": "off",
                "@typescript-eslint/no-object-literal-type-assertion": "off",
                "@typescript-eslint/no-parameter-properties": "off",
                "@typescript-eslint/no-triple-slash-reference": "off",
                "no-unused-vars": "off",
                "@typescript-eslint/no-unused-vars": "off",
                "@typescript-eslint/no-use-before-define": "off",
                "@typescript-eslint/no-var-requires": "off",
                "@typescript-eslint/prefer-interface": "off",
                "@typescript-eslint/prefer-namespace-keyword": "off",
                "@typescript-eslint/type-annotation-spacing": "off",
                // jest rules
                "jest/no-alias-methods": "off",
                "jest/no-disabled-tests": "off",
                "jest/no-focused-tests": "off",
                "jest/no-identical-title": "off",
                "jest/no-jest-import": "off",
                "jest/no-jasmine-globals": "off",
                "jest/no-test-prefixes": "off",
                "jest/valid-describe": "off",
                "jest/valid-expect": "off",
                "jest/valid-expect-in-promise": "off"
            }
        },
        {
            files: ["*.ts"],
            rules: {
                "no-useless-constructor": "off",
                "no-redeclare": "off",
                "@typescript-eslint/no-parameter-properties": "off",
                "@typescript-eslint/no-explicit-any": "off",
                "@typescript-eslint/explicit-function-return-type": ["error", {
                    allowExpressions: true
                }]
            }
        },
        {
            files: ["*Test.ts"],
            rules: { "@typescript-eslint/explicit-function-return-type": "off" }
        }
    ],
    globals: { define: false },
    root: true
};
<commit_msg>[JS] Remove conflicting eslint rules with prettier<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2018 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
module.exports = {
    env: {
        es6: true,
        node: true,
        commonjs: true,
        jasmine: true,
        jest: true,
        browser: true
    },
    parser: "@typescript-eslint/parser",
    parserOptions: {
        ecmaVersion: 2018,
        sourceType: "module"
    },
    extends: [ // order matters. Later entries override earlier entries when conflicts arise
        "eslint:recommended",
        "plugin:promise/recommended",
        "plugin:prettier/recommended",
        "plugin:@typescript-eslint/recommended",
        "plugin:jest/recommended",
        "prettier/@typescript-eslint"
    ],
    plugins: ["promise", "jest"],
    rules: {
        indent: "off",
        quotes: "off",
        "no-empty": "off",
        "no-extra-semi": "off",
        "no-mixed-spaces-and-tabs": "off",
        "no-unexpected-multiline": "off",
        "default-case": "error",
        "no-use-before-define": "off",
        "consistent-return": "off",
        "no-lonely-if": "error",
        "no-console": "error",
        "valid-jsdoc": "off",
        eqeqeq: "error",
        "guard-for-in": "error",
        "no-caller": "error",
        "no-extend-native": "error",
        "no-extra-bind": "error",
        "no-loop-func": "error",
        "no-magic-numbers": "off",
        "no-new": "error",
        "no-new-func": "error",
        "no-proto": "error",
        "no-throw-literal": "error",
        "no-unmodified-loop-condition": "error",
        "no-unused-expressions": "error",
        "no-useless-call": "error",
        "no-useless-concat": "error",
        "prefer-promise-reject-errors": "error",
        "vars-on-top": "error",
        "no-catch-shadow": "error",
        "no-shadow": "off",
        "no-undefined": "off",
        "global-require": "error",
        "no-mixed-requires": "error",
        "no-path-concat": "error",
        "no-sync": "off",
        "no-useless-computed-key": "error",
        "no-useless-constructor": "error",
        "no-var": "error",
        "object-shorthand": "error",
        "prefer-const": "error",
        "prefer-destructuring": "off",
        "prefer-template": "error",
        "prefer-spread": "error",
        "promise/always-return": "off",
        "promise/no-return-wrap": "error",
        "promise/param-names": "error",
        "promise/catch-or-return": "error",
        "promise/no-native": "off",
        "promise/no-nesting": "error",
        "promise/no-promise-in-callback": "warn",
        "promise/no-callback-in-promise": "warn",
        "promise/avoid-new": "error",
        "promise/no-new-statics": "off",
        "promise/no-return-in-finally": "off",
        "promise/valid-params": "off",
        "@typescript-eslint/no-use-before-define": ["error", { "functions": false }],
        "@typescript-eslint/no-namespace": "off",
    },
    overrides: [
        {
            files: ["*.js"],
            rules: {
                "@typescript-eslint/adjacent-overload-signatures": "off",
                "@typescript-eslint/array-type": "off",
                "@typescript-eslint/ban-types": "off",
                camelcase: "off",
                "@typescript-eslint/camelcase": "off",
                "@typescript-eslint/class-name-casing": "off",
                "@typescript-eslint/explicit-function-return-type": "off",
                "@typescript-eslint/explicit-member-accessibility": "off",
                indent: "off",
                "@typescript-eslint/indent": "off",
                "@typescript-eslint/interface-name-prefix": "off",
                "@typescript-eslint/member-delimiter-style": "off",
                "@typescript-eslint/no-angle-bracket-type-assertion": "off",
                "no-array-constructor": "off",
                "@typescript-eslint/no-array-constructor": "off",
                "@typescript-eslint/no-empty-interface": "off",
                "@typescript-eslint/no-explicit-any": "off",
                "@typescript-eslint/no-inferrable-types": "off",
                "@typescript-eslint/no-misused-new": "off",
                "@typescript-eslint/no-non-null-assertion": "off",
                "@typescript-eslint/no-object-literal-type-assertion": "off",
                "@typescript-eslint/no-parameter-properties": "off",
                "@typescript-eslint/no-triple-slash-reference": "off",
                "no-unused-vars": "off",
                "@typescript-eslint/no-unused-vars": "off",
                "@typescript-eslint/no-use-before-define": "off",
                "@typescript-eslint/no-var-requires": "off",
                "@typescript-eslint/prefer-interface": "off",
                "@typescript-eslint/prefer-namespace-keyword": "off",
                "@typescript-eslint/type-annotation-spacing": "off",
                // jest rules
                "jest/no-alias-methods": "off",
                "jest/no-disabled-tests": "off",
                "jest/no-focused-tests": "off",
                "jest/no-identical-title": "off",
                "jest/no-jest-import": "off",
                "jest/no-jasmine-globals": "off",
                "jest/no-test-prefixes": "off",
                "jest/valid-describe": "off",
                "jest/valid-expect": "off",
                "jest/valid-expect-in-promise": "off"
            }
        },
        {
            files: ["*.ts"],
            rules: {
                "no-useless-constructor": "off",
                "no-redeclare": "off",
                "@typescript-eslint/no-parameter-properties": "off",
                "@typescript-eslint/no-explicit-any": "off",
                "@typescript-eslint/explicit-function-return-type": ["error", {
                    allowExpressions: true
                }]
            }
        },
        {
            files: ["*Test.ts"],
            rules: { "@typescript-eslint/explicit-function-return-type": "off" }
        }
    ],
    globals: { define: false },
    root: true
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2013-2016 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true */
/* globals define: false */

(function (f, define) {
    'use strict';
    define([
        './window.assert',
        './window.logger',
        './vendor/kendo/kendo.button',
        './vendor/kendo/kendo.window'
    ], f);
})(function () {

    'use strict';

    (function ($, undefined) {

        var kendo = window.kendo;
        var ui = kendo.ui;
        var Button = ui.Button;
        var Window = ui.Window;
        var assert = window.assert;
        var logger = new window.Logger('kidoju.widgets.messagebox');
        var UNDEFINED = 'undefined';
        var NS = '.kendoMessageBox';
        var CLICK = 'click';
        var CLOSE = 'close';
        var COMMAND = 'command';
        var HASH = '#';
        var TYPE = {
            ERROR: 'error',
            INFO: 'info',
            WARNING: 'warning'
        };
        var CONTENT_TEMPLATE = '
' +
            '
#: message #
' +
            '
';
        var BUTTONS_TEMPLATE = '
' +
            '# for (var i = 0; i < buttons.length; i++) { #' +
            '<button type="button" data-role="button" data-command="#: buttons[i].command #" class="#: buttons[i].class || \'\' #" data-image-url="#: buttons[i].imageUrl || \'\' #">#: buttons[i].text #</button>' +
            '# } #' +
            '
';

        /*********************************************************************************
         * Helpers
         *********************************************************************************/

        /**
         * Build a random hex string of length characters
         * @param length
         * @returns {string}
         */
        function randomString(length) {
            var s = new Array(length + 1).join('x');
            return s.replace(/x/g, function (c) {
                /* jshint -W016 */
                return (Math.random() * 16|0).toString(16);
                /* jshint +W016 */
            });
        }

        /*********************************************************************************
         * Widget
         *********************************************************************************/

        /**
         * MessageBox Widget
         */
        var MessageBox = Window.extend({

            init: function (element, options) {
                var that = this;
                Window.fn.init.call(that, element, options);
                logger.debug('widget initialized');
                // For an unexplained reason, buttons are not updated
                that.options.buttons = $.isArray(options.buttons) ? options.buttons : that.options.buttons;
                // We need the following statement otherwise $(element).data('kendoMessageBox') instanceof kendo.ui.Window (and not kendo.ui.MessageBox)
                $(element).data('kendoMessageBox', that);
                that._layout();
                that._bindButtons(true);
            },

            /**
             * Options
             */
            options: {
                name: 'MessageBox',
                type: TYPE.INFO,
                title: 'Information',
                message: 'Hello World!',
                buttons: [
                    { command: 'ok', text: 'OK', class: 'k-primary', imageUrl: 'https://cdn.kidoju.com/images/o_collection/svg/office/ok.svg' },
                    { command: 'cancel', text: 'Cancel' }
                ],
                buttonsTemplate: BUTTONS_TEMPLATE,
                contentTemplate: CONTENT_TEMPLATE,
                height: 125,
                width: 400,
                modal: true,
                resizable: false,
                visible: false,
                messages: {
                    error: 'Error',
                    info: 'Information',
                    warning: 'Warning'
                }
            },

            /**
             * Type for convenience
             */
            type: {
                error: TYPE.ERROR,
                info: TYPE.INFO,
                warning: TYPE.WARNING
            },

            /**
             * Layout
             * @private
             */
            _layout: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                // Add message
                element.append(kendo.template(options.contentTemplate)({ type: options.type, message: options.message }));
                // Add buttons
                element.append(kendo.template(options.buttonsTemplate)({ buttons: options.buttons }));
                kendo.init(element); // required to display buttons with data-image-url
                // Add widget class
                element.addClass('k-action-window');
            },

            /**
             * Bind buttons
             * @param enable
             * @private
             */
            _bindButtons: function (enable) {
                var that = this;
                var buttons = that.element.find('button');
                $.each(buttons, function (index, buttonElement) {
                    var buttonWidget = $(buttonElement).data('kendoButton');
                    // We should have Kendo UI Button widgets after calling the kendo.init method in this._layout
                    assert.instanceof(Button, buttonWidget, kendo.format(assert.messages.instanceof.default, 'buttonWidget', 'kendo.ui.Button'));
                    if (enable) {
                        buttonWidget.unbind(CLICK);
                        buttonWidget.bind(CLICK, $.proxy(that._onButtonClick, that));
                    } else {
                        buttonWidget.destroy();
                    }
                });
            },

            /**
             * Button click handler
             * @param e
             * @private
             */
            _onButtonClick: function (e) {
                assert.isPlainObject(e, kendo.format(assert.messages.isPlainObject.default, 'e'));
                assert.instanceof(Button, e.sender, kendo.format(assert.messages.instanceof.default, 'e.sender', 'kendo.ui.Button'));
                assert.instanceof(MessageBox, this, kendo.format(assert.messages.instanceof.default, 'this', 'MessageBox'));
                var button = $(e.sender.element);
                // Store the command which can be read in a close event handler
                this.command = button.attr(kendo.attr(COMMAND));
                this.close();
            },

            /**
             * Open messagebox
             */
            open: function() {

                // Erase the command before a new close
                this.command = undefined;

                // Center and open the message box
                this.center();
                Window.fn.open.call(this);

            },

            /**
             * Destroy
             */
            destroy: function () {
                var that = this;
                var element = that.element;
                that._bindButtons(false);
                element.find('*').off();
                element.off().empty();
                Window.fn.destroy.call(that);
            }

        });

        ui.plugin(MessageBox);

        var ID = 'alert_' + randomString(6);

        /*********************************************************************************
         * kendo.alert function
         *********************************************************************************/

        /**
         * A shortcut function to display an alert dialog
         * @param options
         * @returns {*}
         */
        kendo.alert = function (options) {

            var dfd = $.Deferred();
            var messageBox = null;

            // If an alert dialog already exists, remove it.
            var element = $(HASH + ID);
            if (element.length > 0) {
                messageBox = element.data('kendoMessageBox');
                if (messageBox instanceof kendo.ui.MessageBox) {
                    messageBox.destroy();
                }
            }

            // Add a div to the html document for the alert dialog.
            $(document.body).append(kendo.format('

', ID));

            // Create the message box
            messageBox = $(HASH + ID).kendoMessageBox(options).data('kendoMessageBox');

            // Bind the close event
            messageBox.bind(CLOSE, function (e) {
                dfd.resolve({ command: this.command });
            });

            // Display the message box
            messageBox.open();

            return dfd.promise();
        };

    })(window.jQuery);

    return window.kendo;

}, typeof define === 'function' && define.amd ? define : function (_, f) { 'use strict'; f(); });
<commit_msg>Fixed jshint and jscs issues<commit_after>/**
 * Copyright (c) 2013-2016 Memba Sarl. All rights reserved.
 * Sources at https://github.com/Memba
 */

/* jshint browser: true, jquery: true */
/* globals define: false */

(function (f, define) {
    'use strict';
    define([
        './window.assert',
        './window.logger',
        './vendor/kendo/kendo.button',
        './vendor/kendo/kendo.window'
    ], f);
})(function () {

    'use strict';

    (function ($, undefined) {

        var kendo = window.kendo;
        var ui = kendo.ui;
        var Button = ui.Button;
        var Window = ui.Window;
        var assert = window.assert;
        var logger = new window.Logger('kidoju.widgets.messagebox');
        var UNDEFINED = 'undefined';
        var NS = '.kendoMessageBox';
        var CLICK = 'click';
        var CLOSE = 'close';
        var COMMAND = 'command';
        var HASH = '#';
        var TYPE = {
            ERROR: 'error',
            INFO: 'info',
            WARNING: 'warning'
        };
        var CONTENT_TEMPLATE = '
' +
            '
#: message #
' +
            '
';
        var BUTTONS_TEMPLATE = '
' +
            '# for (var i = 0; i < buttons.length; i++) { #' +
            '<button type="button" data-role="button" data-command="#: buttons[i].command #" class="#: buttons[i].class || \'\' #" data-image-url="#: buttons[i].imageUrl || \'\' #">#: buttons[i].text #</button>' +
            '# } #' +
            '
';

        /*********************************************************************************
         * Helpers
         *********************************************************************************/

        /**
         * Build a random hex string of length characters
         * @param length
         * @returns {string}
         */
        function randomString(length) {
            var s = new Array(length + 1).join('x');
            return s.replace(/x/g, function (c) {
                /* jshint -W016 */
                return (Math.random() * 16|0).toString(16);
                /* jshint +W016 */
            });
        }

        /*********************************************************************************
         * Widget
         *********************************************************************************/

        /**
         * MessageBox Widget
         */
        var MessageBox = Window.extend({

            init: function (element, options) {
                var that = this;
                Window.fn.init.call(that, element, options);
                logger.debug('widget initialized');
                // For an unexplained reason, buttons are not updated
                that.options.buttons = $.isArray(options.buttons) ? options.buttons : that.options.buttons;
                // We need the following statement otherwise $(element).data('kendoMessageBox') instanceof kendo.ui.Window (and not kendo.ui.MessageBox)
                $(element).data('kendoMessageBox', that);
                that._layout();
                that._bindButtons(true);
            },

            /**
             * Options
             */
            options: {
                name: 'MessageBox',
                type: TYPE.INFO,
                title: 'Information',
                message: 'Hello World!',
                buttons: [
                    { command: 'ok', text: 'OK', class: 'k-primary', imageUrl: 'https://cdn.kidoju.com/images/o_collection/svg/office/ok.svg' },
                    { command: 'cancel', text: 'Cancel' }
                ],
                buttonsTemplate: BUTTONS_TEMPLATE,
                contentTemplate: CONTENT_TEMPLATE,
                height: 125,
                width: 400,
                modal: true,
                resizable: false,
                visible: false,
                messages: {
                    error: 'Error',
                    info: 'Information',
                    warning: 'Warning'
                }
            },

            /**
             * Type for convenience
             */
            type: {
                error: TYPE.ERROR,
                info: TYPE.INFO,
                warning: TYPE.WARNING
            },

            /**
             * Layout
             * @private
             */
            _layout: function () {
                var that = this;
                var element = that.element;
                var options = that.options;
                // Add message
                element.append(kendo.template(options.contentTemplate)({ type: options.type, message: options.message }));
                // Add buttons
                element.append(kendo.template(options.buttonsTemplate)({ buttons: options.buttons }));
                kendo.init(element); // required to display buttons with data-image-url
                // Add widget class
                element.addClass('k-action-window');
            },

            /**
             * Bind buttons
             * @param enable
             * @private
             */
            _bindButtons: function (enable) {
                var that = this;
                var buttons = that.element.find('button');
                $.each(buttons, function (index, buttonElement) {
                    var buttonWidget = $(buttonElement).data('kendoButton');
                    // We should have Kendo UI Button widgets after calling the kendo.init method in this._layout
                    assert.instanceof(Button, buttonWidget, kendo.format(assert.messages.instanceof.default, 'buttonWidget', 'kendo.ui.Button'));
                    if (enable) {
                        buttonWidget.unbind(CLICK);
                        buttonWidget.bind(CLICK, $.proxy(that._onButtonClick, that));
                    } else {
                        buttonWidget.destroy();
                    }
                });
            },

            /**
             * Button click handler
             * @param e
             * @private
             */
            _onButtonClick: function (e) {
                assert.isPlainObject(e, kendo.format(assert.messages.isPlainObject.default, 'e'));
                assert.instanceof(Button, e.sender, kendo.format(assert.messages.instanceof.default, 'e.sender', 'kendo.ui.Button'));
                assert.instanceof(MessageBox, this, kendo.format(assert.messages.instanceof.default, 'this', 'MessageBox'));
                var button = $(e.sender.element);
                // Store the command which can be read in a close event handler
                this.command = button.attr(kendo.attr(COMMAND));
                this.close();
            },

            /**
             * Open messagebox
             */
            open: function () {

                // Erase the command before a new close
                this.command = undefined;

                // Center and open the message box
                this.center();
                Window.fn.open.call(this);

            },

            /**
             * Destroy
             */
            destroy: function () {
                var that = this;
                var element = that.element;
                that._bindButtons(false);
                element.find('*').off();
                element.off().empty();
                Window.fn.destroy.call(that);
            }

        });

        ui.plugin(MessageBox);

        var ID = 'alert_' + randomString(6);

        /*********************************************************************************
         * kendo.alert function
         *********************************************************************************/

        /**
         * A shortcut function to display an alert dialog
         * @param options
         * @returns {*}
         */
        kendo.alert = function (options) {

            var dfd = $.Deferred();
            var messageBox = null;

            // If an alert dialog already exists, remove it.
            var element = $(HASH + ID);
            if (element.length > 0) {
                messageBox = element.data('kendoMessageBox');
                if (messageBox instanceof kendo.ui.MessageBox) {
                    messageBox.destroy();
                }
            }

            // Add a div to the html document for the alert dialog.
            $(document.body).append(kendo.format('

', ID));

            // Create the message box
            messageBox = $(HASH + ID).kendoMessageBox(options).data('kendoMessageBox');

            // Bind the close event
            messageBox.bind(CLOSE, function (e) {
                dfd.resolve({ command: this.command });
            });

            // Display the message box
            messageBox.open();

            return dfd.promise();
        };

    })(window.jQuery);

    return window.kendo;

}, typeof define === 'function' && define.amd ? define : function (_, f) { 'use strict'; f(); });
<|endoftext|>


<commit_before>(function () {
	'use strict';
	window.changelogLog = {
		'2.0.0': [
			'Revamped the UI',
			'Rewrote the entire extension',
			'Added the CRM-API for more features',
			'Added a stylesheet element',
			'Added the ability to only show certain nodes on specified websites and/or content types',
			'Added the ability to reposition nodes',
			'Made it possible to delete or export selected nodes',
			'Added compatability with Grease/Tamper-Monkey UserScripts',
			'Added compatability with UserStylesheets',
			'Added the ability to connect a script/stylesheet to a local editor',
			'Now uses the better CodeMirror editor'
		],
		'2.0.4': [
			'Scripts that use the Chrome API are now transferred over to using the crmAPI.chrome API',
			'More clearly reflects a script created by you and what that means (all permissions)',
			'Keeps track of info of local nodes as well now',
			'Allows the editing of the version number'
		],
		'2.0.5': [
			'Fixed a bug that caused scripts to not run when the catch errors option was on'
		],
		'2.0.6': [
			'Added a docs button on script-edit page',
			'Shows a warning when using the deprecated direct chrome API (use crmAPI.chrome instead)',
			'Fixed a bug that occurred on saving',
		],
		'2.0.7': [
			'Fixed json parser bug that sometimes occurred on loading page',
			'Code cleanup and dead code removal',
			'Node instances are now all shown',
			'Fixed some bugs related to scripts not running in their own context'
		],
		'2.0.8': [
			'Fixed some nodes missing IDs after creation',
			'Fixed error that occurred on backgroundpage when running any script'
		],
		'2.0.9': [
			'Fixed bug with buttons no longer working'
		],
		'2.0.10': [
			'Fixed a bug in the crmAPI.GM.GM_notification function'
		],
		'2.0.11': [
			'Fixed the Â character appearing in the editors',
			'Added an indicator for when the exporting field is slow',
			'Added/removed permissions are updated instantly',
			'Fixed userscript installation page',
			'Fixed unsafewindow permission',
			'No longer enables userscript installation if TamperMonkey is already installed'
		],
		'2.0.12': [
			'Added background.runScript, background.runSelf and background.addKeyboardListener functions to crmAPI',
			'Rewrote crmAPI file and fixed some of its bugs',
			'Cleaned up and structured logs on background file console'
		],
		'2.0.13': [
			'Fixed GM_xmlhttpRequest error (thanks to bumaociyuan for the report)'
		],
		'2.0.14': [
			'Added a remove button for libraries (thanks to robinchew for the suggestion)'
		]
	};
}());<commit_msg>updated changelog<commit_after>(function () {
	'use strict';
	window.changelogLog = {
		'2.0.0': [
			'Revamped the UI',
			'Rewrote the entire extension',
			'Added the CRM-API for more features',
			'Added a stylesheet element',
			'Added the ability to only show certain nodes on specified websites and/or content types',
			'Added the ability to reposition nodes',
			'Made it possible to delete or export selected nodes',
			'Added compatability with Grease/Tamper-Monkey UserScripts',
			'Added compatability with UserStylesheets',
			'Added the ability to connect a script/stylesheet to a local editor',
			'Now uses the better CodeMirror editor'
		],
		'2.0.4': [
			'Scripts that use the Chrome API are now transferred over to using the crmAPI.chrome API',
			'More clearly reflects a script created by you and what that means (all permissions)',
			'Keeps track of info of local nodes as well now',
			'Allows the editing of the version number'
		],
		'2.0.5': [
			'Fixed a bug that caused scripts to not run when the catch errors option was on'
		],
		'2.0.6': [
			'Added a docs button on script-edit page',
			'Shows a warning when using the deprecated direct chrome API (use crmAPI.chrome instead)',
			'Fixed a bug that occurred on saving',
		],
		'2.0.7': [
			'Fixed json parser bug that sometimes occurred on loading page',
			'Code cleanup and dead code removal',
			'Node instances are now all shown',
			'Fixed some bugs related to scripts not running in their own context'
		],
		'2.0.8': [
			'Fixed some nodes missing IDs after creation',
			'Fixed error that occurred on backgroundpage when running any script'
		],
		'2.0.9': [
			'Fixed bug with buttons no longer working'
		],
		'2.0.10': [
			'Fixed a bug in the crmAPI.GM.GM_notification function'
		],
		'2.0.11': [
			'Fixed the Â character appearing in the editors',
			'Added an indicator for when the exporting field is slow',
			'Added/removed permissions are updated instantly',
			'Fixed userscript installation page',
			'Fixed unsafewindow permission',
			'No longer enables userscript installation if TamperMonkey is already installed'
		],
		'2.0.12': [
			'Added background.runScript, background.runSelf and background.addKeyboardListener functions to crmAPI',
			'Rewrote crmAPI file and fixed some of its bugs',
			'Cleaned up and structured logs on background file console'
		],
		'2.0.13': [
			'Fixed GM_xmlhttpRequest error (thanks to bumaociyuan for the report)'
		],
		'2.0.14': [
			'Added a remove button for libraries (thanks to robinchew for the suggestion)',
			'Fixed some bugs related to background-pages'
		]
	};
}());<|endoftext|>


<commit_before>/*
👋 Hi! This file was autogenerated by tslint-to-eslint-config.
https://github.com/typescript-eslint/tslint-to-eslint-config

It represents the closest reasonable ESLint configuration to this
project's original TSLint configuration.

We recommend eventually switching this configuration to extend from
the recommended rulesets in typescript-eslint.
https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md

Happy linting! 💖
*/
module.exports = {
    "env": {
        "browser": true,
        "es6": true
    },
    "extends": [
        "prettier",
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "project": "tsconfig.json",
        "sourceType": "module"
    },
    "plugins": [
        "eslint-plugin-jsdoc",
        "@typescript-eslint",
        "@typescript-eslint/tslint"
    ],
    "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended"
    ],
    "rules": {
        "@typescript-eslint/adjacent-overload-signatures": "error",
        "@typescript-eslint/consistent-type-assertions": "error",
        "@typescript-eslint/member-delimiter-style": "error",
        "@typescript-eslint/no-floating-promises": "error",
        "@typescript-eslint/no-var-requires": "error",
        "@typescript-eslint/prefer-namespace-keyword": "error",
        "@typescript-eslint/semi": "error",
        "@typescript-eslint/type-annotation-spacing": "error",
        "brace-style": [
            "error",
            "1tbs",
            { "allowSingleLine": true }
        ],
        "computed-property-spacing": ["error", "never"],
        "curly": "error",
        "eol-last": "error",
        "eqeqeq": [
            "error",
            "smart"
        ],
        "id-denylist": [
            "error",
            "any",
            "Number",
            "number",
            "String",
            "string",
            "Boolean",
            "boolean",
            "Undefined",
            "undefined"
        ],
        "id-match": "error",
        "indent": [
            "error",
            4,
            {
                "SwitchCase": 1,
                "MemberExpression": "off",
                "ignoredNodes": ["ConditionalExpression"]
            }
        ],
        "jsdoc/check-alignment": "error",
        "jsdoc/require-asterisk-prefix": "error",
        "linebreak-style": [
            "error",
            "unix"
        ],
        "no-caller": "error",
        "no-cond-assign": "error",
        "no-debugger": "error",
        "no-eval": "error",
        // Using the typescript-eslint version of this rule because of class
        // properties, which are not yet supported in ESLint.  For more info,
        // see: https://github.com/typescript-eslint/typescript-eslint/issues/491
        "@typescript-eslint/no-invalid-this": "error",
        "no-multiple-empty-lines": [
            "error",
            {
                "max": 3
            }
        ],
        "no-new-wrappers": "error",
        "no-tabs": "error",
        "no-trailing-spaces": "error",
        "no-undef-init": "error",
        "no-unsafe-finally": "error",
        "no-unused-labels": "error",
        "no-var": "error",
        "one-var": [
            "error",
            "never"
        ],
        "prefer-arrow-callback": [
            "error",
            { "allowNamedFunctions": true }
        ],
        "space-before-function-paren": [
            "error",
            "never"
        ],
        "use-isnan": "error",
        "@typescript-eslint/tslint/config": [
            "error",
            {
                "rules": {
                    "file-header": [
                        true,
                        "[Cc]opyright ([(][Cc][)])?\\s*\\d{4}"
                    ],
                    "import-spacing": true,
                    "whitespace": [
                        true,
                        "check-branch",
                        "check-decl",
                        "check-operator",
                        "check-separator"
                    ]
                }
            }
        ]
    },
    "overrides": [
        {
            "files": ["*.test.ts", "*.test.tsx"],
            // since test files are not part of tsconfig.json,
            // parserOptions.project must be unset
            "parserOptions": {
                "project": null,
            },
            "rules": {
                // rules that depend on type information (and therefore
                // parserOptions.project)
                "@typescript-eslint/no-floating-promises": "off",
                "@typescript-eslint/tslint/config": "off",
            }
        }
    ]
};
<commit_msg>Suppress recommended rules that still have errors.<commit_after>/*
👋 Hi! This file was autogenerated by tslint-to-eslint-config.
https://github.com/typescript-eslint/tslint-to-eslint-config

It represents the closest reasonable ESLint configuration to this
project's original TSLint configuration.

We recommend eventually switching this configuration to extend from
the recommended rulesets in typescript-eslint.
https://github.com/typescript-eslint/tslint-to-eslint-config/blob/master/docs/FAQs.md

Happy linting! 💖
*/
module.exports = {
    "env": {
        "browser": true,
        "es6": true
    },
    "extends": [
        "prettier",
    ],
    "parser": "@typescript-eslint/parser",
    "parserOptions": {
        "project": "tsconfig.json",
        "sourceType": "module"
    },
    "plugins": [
        "eslint-plugin-jsdoc",
        "@typescript-eslint",
        "@typescript-eslint/tslint"
    ],
    "extends": [
        "eslint:recommended",
        "plugin:@typescript-eslint/recommended"
    ],
    "rules": {
        // Recommended rules with errors
        // TODO: Fix these and re-enable them

        "@typescript-eslint/ban-types": "off", // 35 errors
        "@typescript-eslint/explicit-module-boundary-types": "off", // 2074 warnings
        "@typescript-eslint/no-empty-function": "off", // 14 errors
        "@typescript-eslint/no-empty-interface": "off", // 45 errors
        "@typescript-eslint/no-explicit-any": "off", // 535 warnings
        "@typescript-eslint/no-namespace": "off", // 1 error
        "@typescript-eslint/no-this-alias": "off", // 4 errors
        "@typescript-eslint/no-unused-vars": "off", // 675 warnings
        "@typescript-eslint/triple-slash-reference": "off", // 1 error

        "no-case-declarations": "off", // 3 errors
        "no-constant-condition": "off", // 1 error
        "no-empty": "off", // 30 errors
        "no-empty-pattern": "off", // 1 error
        "no-fallthrough": "off", // 3 errors
        "no-misleading-character-class": "off", // 2 errors
        "no-prototype-builtins": "off", // 8 errors
        "no-self-assign": "off", // 2 errors
        "no-useless-escape": "off", // 24 errors
        "prefer-const": "off", // 6 errors
        "prefer-spread": "off", // 7 errors

        //==============================================================

        "@typescript-eslint/adjacent-overload-signatures": "error",
        "@typescript-eslint/consistent-type-assertions": "error",
        "@typescript-eslint/member-delimiter-style": "error",
        "@typescript-eslint/no-floating-promises": "error",
        "@typescript-eslint/no-var-requires": "error",
        "@typescript-eslint/prefer-namespace-keyword": "error",
        "@typescript-eslint/semi": "error",
        "@typescript-eslint/type-annotation-spacing": "error",
        "brace-style": [
            "error",
            "1tbs",
            { "allowSingleLine": true }
        ],
        "computed-property-spacing": ["error", "never"],
        "curly": "error",
        "eol-last": "error",
        "eqeqeq": [
            "error",
            "smart"
        ],
        "id-denylist": [
            "error",
            "any",
            "Number",
            "number",
            "String",
            "string",
            "Boolean",
            "boolean",
            "Undefined",
            "undefined"
        ],
        "id-match": "error",
        "indent": [
            "error",
            4,
            {
                "SwitchCase": 1,
                "MemberExpression": "off",
                "ignoredNodes": ["ConditionalExpression"]
            }
        ],
        "jsdoc/check-alignment": "error",
        "jsdoc/require-asterisk-prefix": "error",
        "linebreak-style": [
            "error",
            "unix"
        ],
        "no-caller": "error",
        "no-cond-assign": "error",
        "no-debugger": "error",
        "no-eval": "error",
        // Using the typescript-eslint version of this rule because of class
        // properties, which are not yet supported in ESLint.  For more info,
        // see: https://github.com/typescript-eslint/typescript-eslint/issues/491
        "@typescript-eslint/no-invalid-this": "error",
        "no-multiple-empty-lines": [
            "error",
            {
                "max": 3
            }
        ],
        "no-new-wrappers": "error",
        "no-tabs": "error",
        "no-trailing-spaces": "error",
        "no-undef-init": "error",
        "no-unsafe-finally": "error",
        "no-unused-labels": "error",
        "no-var": "error",
        "one-var": [
            "error",
            "never"
        ],
        "prefer-arrow-callback": [
            "error",
            { "allowNamedFunctions": true }
        ],
        "space-before-function-paren": [
            "error",
            "never"
        ],
        "use-isnan": "error",
        "@typescript-eslint/tslint/config": [
            "error",
            {
                "rules": {
                    "file-header": [
                        true,
                        "[Cc]opyright ([(][Cc][)])?\\s*\\d{4}"
                    ],
                    "import-spacing": true,
                    "whitespace": [
                        true,
                        "check-branch",
                        "check-decl",
                        "check-operator",
                        "check-separator"
                    ]
                }
            }
        ]
    },
    "overrides": [
        {
            "files": ["*.test.ts", "*.test.tsx"],
            // since test files are not part of tsconfig.json,
            // parserOptions.project must be unset
            "parserOptions": {
                "project": null,
            },
            "rules": {
                // rules that depend on type information (and therefore
                // parserOptions.project)
                "@typescript-eslint/no-floating-promises": "off",
                "@typescript-eslint/tslint/config": "off",
            }
        }
    ]
};
<|endoftext|>


<commit_before>'use strict';

const Immutable = require('immutable');
const _ = require('lodash');
const DataStore = require('./DataStore');

const setterMethods = ['upsert', 'insert', 'update', 'delete', 'deleteAll'];

function NoopClass() {}
const excluded = Object.getOwnPropertyNames(NoopClass.prototype);

const resetOptimisticState = (self) => {
  self.__stable = true;
  self.__undo = false;
  self.__optimistic = false;
};

const buildClassFunctions = (classObj, context) => {
  const obj = classObj.prototype;
  const self = context;
  Object.getOwnPropertyNames(obj).forEach(function (functionName) {
    if (excluded.indexOf(functionName) === -1) {
      // create optimistic/fail/success functions
      self[functionName + 'Optimistic'] = (payload) => {
        self.__optimistic = true;
        self.__undo = false;
        self.__stable = false;
        self[functionName](payload);
        resetOptimisticState(self);
      };
      self[functionName + 'Success'] = (payload) => {
        self.__optimistic = false;
        self.__undo = false;
        self.__stable = false;
        self[functionName](payload);
        resetOptimisticState(self);
      };
      self[functionName + 'Undo'] = (payload) => {
        self.__optimistic = false;
        self.__undo = true;
        self.__stable = false;
        self[functionName](payload);
        resetOptimisticState(self);
      };
    }
  });
};

const handleUndo = (id, context, m) => {
  const self = context;
  if (m === 'deleteAll') {
    self._optimisticData = Immutable.Map(self._data);
  }
  else if (self._data.has(id)) {
    self._optimisticData = self._optimisticData.set(id, self._data.get(id));
  } else {
    self._optimisticData = self._optimisticData.delete(id);
  }
};

const handleSuccess = (id, context, m) => {
  const self = context;
  if (m === 'deleteAll') {
    self._data = Immutable.Map();
  }
  else if (self._optimisticData.has(id)) {
    self._data = self._data.set(id, self._optimisticData.get(id));
  } else {
    self._data = self._data.delete(id);
  }
};

class OptimisticDataStore extends DataStore {

  constructor(classObj) {
    this._optimisticData = Immutable.Map();
    this._data = Immutable.Map();
    this.__stable = true;
    classObj.getAll = OptimisticDataStore.getAll;
    classObj.get = OptimisticDataStore.get;
    buildClassFunctions(classObj, this);
    // build setter wrappers:
    const self = this;
    setterMethods.forEach((m) => {
      self[m] = (id, data, path) => {
        let selfData;
        let toReturn = true;
        if (self.__stable) {
          toReturn = super[m](id, data, path);
          selfData = self._data;
          self._data = self._optimisticData;
          toReturn = toReturn && super[m](id, data, path);
          self._optimisticData = self._data;
          self._data = selfData;
        }
        else if (self.__optimistic) {
          selfData = self._data;
          self._data = self._optimisticData;
          toReturn = super[m](id, data, path);
          self._optimisticData = self._data;
          self._data = selfData;
        }
        else if (self.__undo) {
          handleUndo(id, self, m);
        }
        else {
          handleSuccess(id, self, m);
        }
        return toReturn;
      };
    });
  }

  static get(id, missingValue) {
    const value = this.getState()._optimisticData.get(id + '', missingValue);
    return value && value.toJS ? value.toJS() : value;
  }

  static getAll() {
    return Object.keys(this.getState()._optimisticData.toJS()).map(id => {
      return this.get(id);
    });
  }

}

module.exports = OptimisticDataStore;
<commit_msg>[web] minor fixes in OptimisticDataStore<commit_after>'use strict';

const Immutable = require('immutable');
const _ = require('lodash');
const DataStore = require('./DataStore');

const setterMethods = ['upsert', 'insert', 'update', 'delete', 'deleteAll'];

function NoopClass() {}
const excluded = Object.getOwnPropertyNames(NoopClass.prototype);

const resetOptimisticState = (self) => {
  self.__stable = true;
  self.__undo = false;
  self.__optimistic = false;
};

const buildClassFunctions = (classObj, context) => {
  const obj = classObj.prototype;
  const self = context;
  Object.getOwnPropertyNames(obj).forEach(function (functionName) {
    if (excluded.indexOf(functionName) === -1) {
      // create optimistic/fail/success functions
      self[functionName + 'Optimistic'] = (payload) => {
        self.__optimistic = true;
        self.__undo = false;
        self.__stable = false;
        self[functionName](payload);
        resetOptimisticState(self);
      };
      self[functionName + 'Success'] = (payload) => {
        self.__optimistic = false;
        self.__undo = false;
        self.__stable = false;
        self[functionName](payload);
        resetOptimisticState(self);
      };
      self[functionName + 'Undo'] = (payload) => {
        self.__optimistic = false;
        self.__undo = true;
        self.__stable = false;
        self[functionName](payload);
        resetOptimisticState(self);
      };
    }
  });
};

const handleUndo = (id, context, m) => {
  const self = context;
  if (m === 'deleteAll') {
    self._optimisticData = Immutable.Map(self._data);
  }
  else if (self._data.has(id)) {
    self._optimisticData = self._optimisticData.set(id, self._data.get(id));
  } else {
    self._optimisticData = self._optimisticData.delete(id);
  }
};

const handleSuccess = (id, context, m) => {
  const self = context;
  if (m === 'deleteAll') {
    self._data = Immutable.Map();
  }
  else if (self._optimisticData.has(id)) {
    self._data = self._data.set(id, self._optimisticData.get(id));
  } else {
    self._data = self._data.delete(id);
  }
};

class OptimisticDataStore extends DataStore {

  constructor(classObj) {
    this._optimisticData = Immutable.Map();
    this._data = Immutable.Map();
    this.__stable = true;
    classObj.getAll = OptimisticDataStore.getAll;
    classObj.get = OptimisticDataStore.get;
    buildClassFunctions(classObj, this);
    // build setter wrappers:
    const self = this;
    setterMethods.forEach((m) => {
      self[m] = (id, data, path) => {
        id = typeof id === 'undefined' ? id : (id + '');
        let selfData;
        let toReturn = true;
        if (self.__stable) {
          toReturn = super[m](id, data, path);
          selfData = self._data;
          self._data = self._optimisticData;
          toReturn = toReturn && super[m](id, data, path);
          self._optimisticData = self._data;
          self._data = selfData;
        }
        else if (self.__optimistic) {
          selfData = self._data;
          self._data = self._optimisticData;
          toReturn = super[m](id, data, path);
          self._optimisticData = self._data;
          self._data = selfData;
        }
        else if (self.__undo) {
          handleUndo(id, self, m);
        }
        else {
          handleSuccess(id, self, m);
        }
        return toReturn;
      };
    });
  }

  static get(id, missingValue) {
    const value = this.getState()._optimisticData.get(id + '', missingValue);
    return value && value.toJS ? value.toJS() : value;
  }

  static getAll() {
    return Object.keys(this.getState()._optimisticData.toJS()).map(id => {
      return this.get(id);
    });
  }

}

module.exports = OptimisticDataStore;
<|endoftext|>


<commit_before>define(function(require){
	var _ = require('underscore')
		, Listener = require('./listener')
		, is_touch_device = require('../is_touch')
		, now = require('./now');

	/*
	 * adds and removes listeners from the stack
	 *
	 * function add(definitions): add listener, see ./binder.js for more details and options
	 *
	 * definitions = {
	 *		handle: 'listener name',
	 *		on: listener type (click, keypressed, various shortcuts)
	 * }
	 *
	 */

	var listenerStack = [] // holds all active listeners
		, baseTime = 0;

	return {
		// get latency (time since last reset)
		getLatency: function(){
			return now() - baseTime;
		},

		// reset timer
		resetTimer: function(){
			baseTime = now();
		},

		// add listeners
		add: function(definitions){
			if (!definitions){
				throw new Error('Missing input element. Could not add input listener');
			}

			var interfaceObj = this;
			// make sure definitions is set as an array
			var definitionsArr = _.isArray(definitions) ? definitions : [definitions];

			// for each definitions object create a listener
			_.forEach(definitionsArr,function(definition){
				// if this listener is targeted specificaly at a touch\!touch device
				if (!_.isUndefined(definition.touch)) {
					// if needed, skip this listener
					if (is_touch_device && !definition.touch) {
						return true;
					}
					if (!is_touch_device && definition.touch) {
						return true;
					}
				}

				var listener = new Listener(definition, interfaceObj);
				listenerStack.push(listener);
			});

		},

		// remove listeners
		remove: function(handleList){
			handleList = _.isArray(handleList ) ? handleList  : [handleList ];

			// go through the listener stack and remove any listeners that fit the handle list
			// note that we do this in reverse so that the index does not change
			for (var i = listenerStack.length - 1; i >= 0 ; i--){
				var listener = listenerStack[i];

				if (_.indexOf(listener.handle, handleList) != -1){
					listener.off();
					listenerStack.splice(i,1);
				}
			}
		},

		// remove all listeners
		destroy: function(){
			// destroy each listener
			_.invoke(listenerStack,'destroy');

			// empty stack
			listenerStack = [];
		}
	};
});<commit_msg>fix(interface): removeInput works again<commit_after>define(function(require){
	var _ = require('underscore')
		, Listener = require('./listener')
		, is_touch_device = require('../is_touch')
		, now = require('./now');

	/*
	 * adds and removes listeners from the stack
	 *
	 * function add(definitions): add listener, see ./binder.js for more details and options
	 *
	 * definitions = {
	 *		handle: 'listener name',
	 *		on: listener type (click, keypressed, various shortcuts)
	 * }
	 *
	 */

	var listenerStack = [] // holds all active listeners
		, baseTime = 0;

	return {
		// get latency (time since last reset)
		getLatency: function(){
			return now() - baseTime;
		},

		// reset timer
		resetTimer: function(){
			baseTime = now();
		},

		// add listeners
		add: function(definitions){
			if (!definitions){
				throw new Error('Missing input element. Could not add input listener');
			}

			var interfaceObj = this;
			// make sure definitions is set as an array
			var definitionsArr = _.isArray(definitions) ? definitions : [definitions];

			// for each definitions object create a listener
			_.forEach(definitionsArr,function(definition){
				// if this listener is targeted specificaly at a touch\!touch device
				if (!_.isUndefined(definition.touch)) {
					// if needed, skip this listener
					if (is_touch_device && !definition.touch) {
						return true;
					}
					if (!is_touch_device && definition.touch) {
						return true;
					}
				}

				var listener = new Listener(definition, interfaceObj);
				listenerStack.push(listener);
			});

		},

		// remove listeners
		remove: function(handleList){
			handleList = _.isArray(handleList ) ? handleList  : [handleList ];

			// go through the listener stack and remove any listeners that fit the handle list
			// note that we do this in reverse so that the index does not change
			for (var i = listenerStack.length - 1; i >= 0 ; i--){
				var listener = listenerStack[i];
				if (_.indexOf(handleList,listener.handle) != -1){
					listener.off();
					listenerStack.splice(i,1);
				}
			}
		},

		// remove all listeners
		destroy: function(){
			// destroy each listener
			_.invoke(listenerStack,'destroy');

			// empty stack
			listenerStack = [];
		}
	};
});<|endoftext|>


<commit_before>/**
 * View for "video view"
 * @module views/views/VideoViewView
 */

var VideoChatView = require("./VideoChatView");

var VideoViewView = {

	initialize: function( options ){

	},

	/**
	* Renders the "video" view
	*/
	render: function(){

		this.activeTimeout;
		$('#playback').append("

");

		this.videoChatView = new VideoChatView();
		$('#room').append( this.videoChatView.$el );
		this.videoChatView.render();
		$('#plugpro-videochat').css({
			"right": "15px"
		});

		$('body').addClass('plugpro-video');

		$('.app-right').css({
			"right": ($('.app-right').width() * -1) + "px"
		});

		$('body, #playback-container').on( "mousemove", this.makeActive.bind(this) );

		API.on( API.ADVANCE, this.updateArtwork.bind(this) );

		this.makeActive();
		this.updateArtwork();
	},

	makeActive: function( event ){
		$('body').removeClass('inactive');
		if( this.activeTimeout ){
			clearTimeout( this.activeTimeout );
		}

		this.activeTimeout = setTimeout( this.makeInactive.bind(this), 2000 );
	},

	makeInactive: function(){
		$('body').addClass('inactive');
	},

	updateArtwork: function(){
		var songInfo = API.getMedia();

		if( songInfo.image.indexOf('sndcdn') !== -1 ){
			var artFile = songInfo.image.replace( '-large', '-t500x500' );
			$('#video-cover').css({
				"background-image": "url('"+ artFile +"')"
			});
		}else{
			$('#video-cover').css({
				"background-image": "none"
			});
		}
	}

};

module.exports = VideoViewView;<commit_msg>Move chat DOM styling to VideoChatView<commit_after>/**
 * View for "video view"
 * @module views/views/VideoViewView
 */

var VideoChatView = require("./VideoChatView");

var VideoViewView = {

	initialize: function( options ){

	},

	/**
	* Renders the "video" view
	*/
	render: function(){

		this.activeTimeout;
		$('body').addClass('plugpro-video');

		$('#playback').append("

");

		this.videoChatView = new VideoChatView();
		$('#room').append( this.videoChatView.$el );
		this.videoChatView.render();
		this.videoChatView.minimizeChat();

		$('body, #playback-container').on( "mousemove", this.makeActive.bind(this) );

		API.on( API.ADVANCE, this.updateArtwork.bind(this) );

		this.makeActive();
		this.updateArtwork();
	},

	makeActive: function( event ){
		$('body').removeClass('inactive');
		if( this.activeTimeout ){
			clearTimeout( this.activeTimeout );
		}

		this.activeTimeout = setTimeout( this.makeInactive.bind(this), 2000 );
	},

	makeInactive: function(){
		$('body').addClass('inactive');
	},

	updateArtwork: function(){
		var songInfo = API.getMedia();

		if( songInfo.image.indexOf('sndcdn') !== -1 ){
			var artFile = songInfo.image.replace( '-large', '-t500x500' );
			$('#video-cover').css({
				"background-image": "url('"+ artFile +"')"
			});
		}else{
			$('#video-cover').css({
				"background-image": "none"
			});
		}
	}

};

module.exports = VideoViewView;<|endoftext|>


<commit_before>module.exports = {
	extends: [
    'airbnb',
    'poi-plugin',
    'prettier',
    'prettier/react',
  ],
	plugins: [
		'react',
		'jsx-a11y',
    'import',
    'prettier',
	],
	env: {
		browser: true,
		es6: true,
    node: true,
    jest: true,
	},
  parser: 'babel-eslint',
	rules: {
		'semi': ['error', 'never'],
		'import/no-unresolved': [2, { 'ignore': ['views/.*'] }],
    'react/jsx-filename-extension': 'off',
    'no-underscore-dangle': 'off',
    'import/extensions': ['error', { 'es': 'never' }],
    'import/no-extraneous-dependencies': 'off',
    'comma-dangle': ['error', 'always-multiline'],
    'no-confusing-arrow': ['error', {'allowParens': true}],
    'no-confusing-arrow': 'off',
    'no-console': 'off',
    'prettier/prettier': 'error',
    'react/static-property-placement': 'off',
    'react/destructuring-assignment': 'off',
    'react/jsx-props-no-spreading': 'off',
	},
}
<commit_msg>chore: format<commit_after>module.exports = {
  extends: ['airbnb', 'poi-plugin', 'prettier', 'prettier/react'],
  plugins: ['react', 'jsx-a11y', 'import', 'prettier'],
  env: {
    browser: true,
    es6: true,
    node: true,
    jest: true,
  },
  parser: 'babel-eslint',
  rules: {
    semi: ['error', 'never'],
    'import/no-unresolved': [2, { ignore: ['views/.*'] }],
    'react/jsx-filename-extension': 'off',
    'no-underscore-dangle': 'off',
    'import/extensions': ['error', { es: 'never' }],
    'import/no-extraneous-dependencies': 'off',
    'comma-dangle': ['error', 'always-multiline'],
    'no-confusing-arrow': ['error', { allowParens: true }],
    'no-confusing-arrow': 'off',
    'no-console': 'off',
    'prettier/prettier': 'error',
    'react/static-property-placement': 'off',
    'react/destructuring-assignment': 'off',
    'react/jsx-props-no-spreading': 'off',
  },
}
<|endoftext|>


<commit_before>import $ from 'jquery';
import 'select2';
import { isNumeric } from '@utils';

const { api_geo_url, api_adresse_url } = gon.autocomplete || {};

const language = {
  errorLoading: function () {
    return 'Les résultats ne peuvent pas être chargés.';
  },
  inputTooLong: function (args) {
    var overChars = args.input.length - args.maximum;

    return 'Supprimez ' + overChars + ' caractère' + (overChars > 1 ? 's' : '');
  },
  inputTooShort: function (args) {
    var remainingChars = args.minimum - args.input.length;

    return (
      'Saisissez au moins ' +
      remainingChars +
      ' caractère' +
      (remainingChars > 1 ? 's' : '')
    );
  },
  loadingMore: function () {
    return 'Chargement de résultats supplémentaires…';
  },
  maximumSelected: function (args) {
    return (
      'Vous pouvez seulement sélectionner ' +
      args.maximum +
      ' élément' +
      (args.maximum > 1 ? 's' : '')
    );
  },
  noResults: function () {
    return 'Aucun résultat trouvé';
  },
  searching: function () {
    return 'Recherche en cours…';
  },
  removeAllItems: function () {
    return 'Supprimer tous les éléments';
  }
};

const baseOptions = {
  language,
  width: '100%'
};

const baseAjaxOptions = {
  delay: 250,
  timeout: 10 * 1000, // 10 sec
  cache: true,
  data({ term: nom }) {
    return {
      nom,
      fields: 'nom,code'
    };
  },
  processResults(data) {
    return {
      results: data.map(({ nom }) => ({ id: nom, text: nom }))
    };
  }
};

const regionsOptions = {
  ...baseOptions,
  minimumInputLength: 2,
  ajax: { url: `${api_geo_url}/regions`, ...baseAjaxOptions }
};

const communesOptions = {
  ...baseOptions,
  minimumInputLength: 2,
  ajax: { url: `${api_geo_url}/communes`, ...baseAjaxOptions }
};

const etranger99 = { id: '99 - Étranger', text: '99 - Étranger' };
const departementsOptions = {
  ...baseOptions,
  minimumInputLength: 1,
  ajax: {
    ...baseAjaxOptions,
    url: `${api_geo_url}/departements`,
    data({ term }) {
      const data = { fields: 'nom,code' };

      if (isNumeric(term)) {
        data.code = term.trim().padStart(2, '0');
      } else {
        data.nom = term;
      }

      return data;
    },
    processResults(data) {
      return {
        results: data
          .map(({ nom, code }) => ({
            id: `${code} - ${nom}`,
            text: `${code} - ${nom}`
          }))
          .concat([etranger99])
      };
    }
  }
};

const adresseOptions = {
  ...baseOptions,
  minimumInputLength: 2,
  ajax: {
    ...baseAjaxOptions,
    url: `${api_adresse_url}/search`,
    data({ term: q }) {
      return {
        q,
        limit: 5
      };
    },
    processResults(data) {
      let r = data.features.map(({ properties: { label }, geometry }) => ({
        id: label,
        text: label,
        geometry
      }));
      // Allow the user to select an arbitrary address missing from the results,
      // by adding the plain-text query to the list of results.
      r.unshift({ id: data.query, text: data.query });
      return {
        results: r
      };
    }
  }
};

const templateOption = ({ text }) =>
  $(
    `<span class="custom-select2-option"><span class="icon person"></span>${text}</span>`
  );

addEventListener('ds:page:update', () => {
  $('select.select2').select2(baseOptions);
  $('select.select2.departements').select2(departementsOptions);
  $('select.select2.regions').select2(regionsOptions);
  $('select.select2.communes').select2(communesOptions);
  $('select.select2.adresse').select2(adresseOptions);

  $('.columns-form select.select2-limited').select2({
    width: '300px',
    placeholder: 'Sélectionnez des colonnes',
    maximumSelectionLength: '5'
  });

  $('.recipients-form select.select2-limited').select2({
    language,
    width: '300px',
    placeholder: 'Sélectionnez des instructeurs',
    maximumSelectionLength: '30'
  });

  $('select.select2-limited.select-instructeurs').select2({
    language,
    dropdownParent: $('.instructeur-wrapper'),
    placeholder: 'Saisir l’adresse email de l’instructeur',
    tags: true,
    tokenSeparators: [',', ' '],
    templateResult: templateOption,
    templateSelection: templateOption
  });
});
<commit_msg>remove unused select2 code<commit_after>import $ from 'jquery';
import 'select2';

const language = {
  errorLoading: function () {
    return 'Les résultats ne peuvent pas être chargés.';
  },
  inputTooLong: function (args) {
    var overChars = args.input.length - args.maximum;

    return 'Supprimez ' + overChars + ' caractère' + (overChars > 1 ? 's' : '');
  },
  inputTooShort: function (args) {
    var remainingChars = args.minimum - args.input.length;

    return (
      'Saisissez au moins ' +
      remainingChars +
      ' caractère' +
      (remainingChars > 1 ? 's' : '')
    );
  },
  loadingMore: function () {
    return 'Chargement de résultats supplémentaires…';
  },
  maximumSelected: function (args) {
    return (
      'Vous pouvez seulement sélectionner ' +
      args.maximum +
      ' élément' +
      (args.maximum > 1 ? 's' : '')
    );
  },
  noResults: function () {
    return 'Aucun résultat trouvé';
  },
  searching: function () {
    return 'Recherche en cours…';
  },
  removeAllItems: function () {
    return 'Supprimer tous les éléments';
  }
};

const baseOptions = {
  language,
  width: '100%'
};

const templateOption = ({ text }) =>
  $(
    `<span class="custom-select2-option"><span class="icon person"></span>${text}</span>`
  );

addEventListener('ds:page:update', () => {
  $('select.select2').select2(baseOptions);

  $('.columns-form select.select2-limited').select2({
    width: '300px',
    placeholder: 'Sélectionnez des colonnes',
    maximumSelectionLength: '5'
  });

  $('.recipients-form select.select2-limited').select2({
    language,
    width: '300px',
    placeholder: 'Sélectionnez des instructeurs',
    maximumSelectionLength: '30'
  });

  $('select.select2-limited.select-instructeurs').select2({
    language,
    dropdownParent: $('.instructeur-wrapper'),
    placeholder: 'Saisir l’adresse email de l’instructeur',
    tags: true,
    tokenSeparators: [',', ' '],
    templateResult: templateOption,
    templateSelection: templateOption
  });
});
<|endoftext|>


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

    return ["$http", "$location", "api", function($http, $location, api) {
		return {

			restrict: "A",

            template: '

',

			link: function(scope, element, attrs) {
				scope.showShareUrl = false;
				scope.shareUrl = null;

				if(attrs.sharelink) {
					var data = {"longUrl": 'http://'+window.location.host+'/'+attrs.sharelink};
				}
				else {
					var data = {"longUrl": window.location.href};
				}
				$http.post('https://www.googleapis.com/urlshortener/v1/url', data, {withCredentials: false}).then(function(response) {
					scope.shareUrl = response.data.id.replace("http://goo.gl/", "http://isaacphysics.org/s/");
				}).catch(function() {
					// Fail silently
				});

                scope.getShareLink = function() {
	                scope.showShareUrl = !scope.showShareUrl;
	                if (scope.showShareUrl) {
	                	api.logger.log({
		                	type: "SHOW_SHARE_URL",
		                	shortURL : scope.shareUrl,
		                });
	                }
                };
			}
		};
	}]
});<commit_msg>Generate share link asynchronously. Hopefully fixes #280.<commit_after>/**
 * Copyright 2014 Nick Rogers
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 *
 * You may obtain a copy of the License at
 * 		http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
define([], function() {

    return ["$http", "$location", "api", "$timeout", function($http, $location, api, $timeout) {
		return {

			restrict: "A",

            template: '

',

			link: function(scope, element, attrs) {
				scope.showShareUrl = false;
				scope.shareUrl = null;

				$timeout(function() {
					// Do this asynchronously so that window.location has a chance to update first.

					if(attrs.sharelink) {
						var data = {"longUrl": 'http://'+window.location.host+'/'+attrs.sharelink};
					}
					else {
						var data = {"longUrl": window.location.href};
					}
					$http.post('https://www.googleapis.com/urlshortener/v1/url', data, {withCredentials: false}).then(function(response) {
						scope.shareUrl = response.data.id.replace("http://goo.gl/", "http://isaacphysics.org/s/");
					}).catch(function() {
						// Fail silently
					});
				});

                scope.getShareLink = function() {
	                scope.showShareUrl = !scope.showShareUrl;
	                if (scope.showShareUrl) {
	                	api.logger.log({
		                	type: "SHOW_SHARE_URL",
		                	shortURL : scope.shareUrl,
		                });
	                }
                };
			}
		};
	}]
});<|endoftext|>