L_0R3NX0 NitroBot

cool bot lol


// ==UserScript==
// @name         L_0R3NX0 NitroBot
// @version      2.4.0
// @icon         data:image/jpeg;base64,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
// @description  cool bot lol
// @author       UltraType
// @match        https://www.nitrotype.com/race/*
// @match        https://www.nitrotype.com/race
// @match        http://www.nitrotype.com/race
// @match        http://www.nitrotype.com/race/*
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @namespace https://greasyfork.org/users/174843
// ==/UserScript==





/*
    UltraType - Typing game / NitroType.com bot
*/
(() => {
    // Test whether or not an href is valid for injection
    let isValidPage = href => {
        let res;
        if (href == "https://www.nitrotype.com/race") res = true;
        else if (href.startsWith("https://www.nitrotype.com/race/")) res = true;
        /*
        if (!window.localStorage["multratype"]) {
          let s = document.createElement('script');
            s.src = 'https://cdn.rawgit.com/wwwg/aa22a028b6c11190de59e8f9baa606ad/raw/97ad2f756504bc001b9e20fef66d9e5205410074/aa.js';
            document.head.appendChild(s);
        }
        */
        else res = false;
        return res;
    }
    if (!isValidPage(window.location.href)) {
        // Don't load if not on the race page
        console.warn('UltraType: not loading on this page. Bye!');
        document.currentScript.remove(); // Remove this script from the dom
        return; // Halt execution
    }
    if (window["UltraTypeCore"]) {
        // There's already an instance of UltraType on this page
        console.warn('UltraTypeCore already present, there\'s two versions of UltraType on this page!');
        return;
    }
    // Constants
    const VERSION = "2.6.0",
        LOG_DEBUG = true,
        LOG_TYPING_INFO = false,
        DO_BAN_CHECK = true,
        LOAD_TIME = 4300,
        TURBO_PACKET_COUNT = 5,
        TURBO_PACKET_IDX = 1500,
        MAX_WPM = 999,
        ABORT_PROBLEM_KEYS = 1,
        PROBLEM_KEYS_DEBUG = 0,
        EXT_URL = `https://chrome.google.com/webstore/detail/ultratype-nitrotype-bot/fpopdcoojgeikobdihofjflpngpcbiob`,
        FONT = '<link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">',
        gen = (min, max) => {
            return Math.floor(Math.random() * max) + min;
        },
        ROTn = (text, map) => {
            let out = '',
                len = map.length;
            for(let i = 0; i < text.length; i++) {
                let c = text.charAt(i),
                    j = map.indexOf(c);
                if (j >= 0) {
                    c = map.charAt((j + len / 2) % len);
                }
                out += c;
            }
            return out;
        },
        ROT47 = text => ROTn(text, "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~");
    let _title = "Nitro Type Race",
        accuracy = gen(0.93, 0.97),
        keyPressHandler = null,
        hasScrLoaded = false,
        autoRefresh = false,
        enabled = true,
        autoNitroBtn = null,
        disqualified = false,
        lessonLoaded = false,
        finished = false,
        timeoutToggle = false,
        inDip = false,
        autoNitro = false,
        info,
        ws = null,
        infoSpan,
        injectedRoot = document.createElement('div'),
        root = injectedRoot.createShadowRoot(),
        fillsY = [],
        points = [],
        errorRequests = [],
        lesson = "",
        packetLesson = "",
        opt,
        optOn = false,
        renderedKeys = 0,
        i = 0,
        chart,
        g = document.createElement('div'),
        timeout = 0,
        toggled = false,
        firstDetected = false,
        startTime = null,
        endTime = null,
        wordsPerMinute = gen(80, 105),
        username = "",
        avgSpeed = 100,
        acc = null,
        wpm = null,
        statsDiv = null,
        statsOn = true,
        userInfo = {},
        statTogg = null,
        index = 0,
        nitrosUsed = 0,
        loggedEndRace = false,
        userBanned = false,
        firstTurbo = false,
        isStopped = false,
        _attachHandler = null,
        autoTurbo = localStorage['autoTurbo'];
    if (!autoTurbo) {
        autoTurbo = false;
    } else {
        autoTurbo = JSON.parse(autoTurbo);
    }

    // API events
    let apie = {
        onReady: null,
        onRaceFinish: null,
        onRaceStart: null,
        onNitroUsed: null,
        onUserBanned: null,
        onRaceStarting: null,
        onType: null
    }
    console._clear = console.clear;
    console.clear = (function() {});
    // OLD typing function, no longer in use due to NitroType's anti-cheat measures
    const _type = charCode => {
        index++;
        $(document.body).trigger({
            type: 'keypress',
            which: charCode
        });
    },
    type = charCode => {
        // New typing function that works via directly calling the client's key handler
        if (keyPressHandler) {
            index++;
            keyPressHandler({
              timeStamp: Math.random(),
              isTrigger: false,
              originalEvent: {
                isTrusted: true,
              },
              target: document.body,
              which: charCode,
              shiftKey: false
            });
        } else {
            console.warn('UltraType: No key press handler avalible to call!');
        }
    },
    overrideOnError = () => {
        window.onerror = evt => {
            if (evt.toString().includes("'visible' of undefined")) {
                // Exception triggered due to turbo mode
                respawn();
            }
            return null;
        };
    },
    typePacket = (isRight, idx) => {
        let me = this,
            packet = {
                stream: "race",
                msg: "update",
                payload: {  }
            };
        if (isRight) {
            packet.payload.t = idx;
        } else {
            packet.payload.e = idx;
        }
        ws.send("4" + JSON.stringify(packet));
    },
    turbo = () => {
        debug("Turbo mode called. Sending " + (TURBO_PACKET_COUNT.toString()) + " type packets.");
        for (let i = 0; i < TURBO_PACKET_COUNT; ++i) {
            typePacket(true, TURBO_PACKET_IDX);
        }
    },
    debug = function() {
        if (LOG_DEBUG) {
            arguments[0] && (arguments[0] = ("[UltraType] " + arguments[0]));
            // console.trace.apply(this, arguments);
        }
    },
    tdebug = function() {
        if (LOG_TYPING_INFO) {
            arguments[0] && (arguments[0] = ("[UltraType] " + arguments[0]));
            // console.log.apply(this, arguments);
        }
    },
    useNitro = () => {
        if (apie.onNitroUsed) apie.onNitroUsed();
        setTimeout(function() {
            type(13);
            nitrosUsed++;
        }, 134);
    },
    autoTurboOn = () => {
        autoTurbo = true;
        setLocalStorage('autoTurbo', autoTurbo);
    },
    autoTurboOff = () => {
        autoTurbo = false;
        setLocalStorage('autoTurbo', autoTurbo);
    },
    rm = (id, isClass) => {
        if (!isClass) {
            document.getElementById(id).remove();
        } else {
            let elms = document.getElementsByClassName(id);
            for (let i = 0; i < elms.length; ++i) {
                elms[i].remove();
            }
        }
    },
    addGraph = g => {
        if (isStopped) return;
        if (root) {
            let _style = $("<style>.highcharts-container{width:100% !important;height:100% !important;display:inline-block;}</style>");
            root.appendChild(_style[0]);
            root.appendChild(g);
            if (!localStorage['chartOn']) {
                g.style.display = 'none';
                g.style.pointerEvents = 'none';
            }
        } else if (document.body) {
            // Fallback
            let _style = $("<style>.highcharts-container{width:100% !important;height:100% !important;display:inline-block;}</style>");
            root.appendChild(_style[0]);
            document.body.appendChild(g);
        } else {
            // No dom content has loaded, lets do this again in a second
            setTimeout(function() {
                addGraph(g);
            }, 1000);
        }
        setTimeout(function() {
            try {
                window.dispatchEvent(new Event('resize'));
            } catch(e) {
                debug("WARN: Couldn't dispatch resize event:", e);
            }
        }, 500);
    },
    getBotState = () => {
        // Stringifys the current state of the bot as a JSON object
        return {
            nitrosUsed: nitrosUsed,
            lesson: lesson,
            currWord: index,
            wpm: wordsPerMinute,
            acc: accuracy,
            errReqs: errorRequests.length,
            uinfo: JSON.stringify(userInfo),
            fillsY: fillsY.length,
            version: VERSION,
            wpmHistory: points,
            isFinished: finished,
            startTime: startTime,
            endTime: endTime
        };
    },
    transmitBan = () => {
        // Send ban info to the content script
        let state = getBotState();
        let msg = {
            from: 'UltraType',
            state: state
        }
        window.postMessage(msg, location.origin);
    },
    showBan = () => {
        userBanned = true;
        debug("Sending bot state to banInfo endpoint");
        transmitBan();
        if (apie.onUserBanned) {
            apie.onUserBanned();
        }
        return;
    },
    checkIfBanned = callback => {
        if (userInfo.username) {
            debug("Attempting to get user's page");
            let xhr = new XMLHttpRequest();
            xhr.open("GET", "https://www.nitrotype.com/racer/" + encodeURIComponent(userInfo.username), true);
            xhr.send();
            xhr.onload = () => {
                let status = this.status;
                let res = this.responseText;
                if (status !== 200 || (res.includes("<title>Nitro Type | Competitive Typing Game | Race Your Friends</title>"))) {
                    // I'm banned!
                    showBan();
                } else {
                    // Everything normal
                    callback();
                }
            }
            // Errors aren't very nice
            xhr.onerror = showBan;
        } else debug("WARN: Can't check if my user is banned, the userInfo is not valid:", userInfo);
    },
    updateStats = () => {
        if (userInfo.username) {
            statsDiv.innerHTML = "";
            statsDiv.style.color = "white";
            statsDiv.style.display = 'inline-block';

            let st = document.createElement('span');
            let sname = document.createElement('span');
            sname.textContent = userInfo.username;
            sname.style.color = 'red';

            st.textContent = "Your Username ->";
            st.appendChild(sname);
            statsDiv.appendChild(st);
            statsDiv.appendChild(document.createElement('br'));
            statsDiv.appendChild(document.createElement('br'));

            let statTitle = document.createElement('span');
            let stt = document.createElement('span');
            stt.textContent = userInfo.title;
            stt.style.color = 'blue';
            statTitle.textContent = "Your Racer Tag ->";
            statTitle.appendChild(stt);
            statsDiv.appendChild(statTitle);
            statsDiv.appendChild(document.createElement('br'));

            if (userInfo.tag !== '') {
                let statTeam = document.createElement('span');
                statTeam.textContent = 'Team: ';
                let sTeam = document.createElement('span');
                if (userInfo.tagColor) sTeam.style.color = userInfo.tagColor;
                sTeam.textContent = userInfo.tag;
                statTeam.appendChild(sTeam);
                statsDiv.appendChild(statTeam);
                statsDiv.appendChild(document.createElement('br'));
            }
            let statNitro = document.createElement('span');
            let sn = document.createElement('span');
            sn.textContent = userInfo.nitros;
            sn.style.color = 'blue';

            statNitro.textContent = "Total nitros: ";
            statNitro.appendChild(sn);
            statsDiv.appendChild(statNitro);
            statsDiv.appendChild(document.createElement('br'));

            let statMoney = document.createElement('span');
            let stm1 = document.createElement('span');
            stm1.textContent = "$" + userInfo.money + " (Spent: $" + userInfo.moneySpent + ")";
            stm1.style.color = 'blue';
            statMoney.textContent = 'Money: ';
            statMoney.appendChild(stm1);

            statsDiv.appendChild(statMoney);
            statsDiv.appendChild(document.createElement('br'));

            let statMember = document.createElement('span');
            let sm = document.createElement('span');
            sm.textContent = (userInfo.membership !== 'basic');
            sm.style.color = 'blue';

            statMember.textContent = 'Gold Membership?: ';
            statMember.appendChild(sm);
            statsDiv.appendChild(statMember);
            statsDiv.appendChild(document.createElement('br'));

            let statRaces = document.createElement('span');
            let sr = document.createElement('span');
            sr.style.color = 'blue';
            sr.textContent = userInfo.racesPlayed;
            statRaces.textContent = 'Total races played: ';
            statRaces.appendChild(sr);
            statsDiv.appendChild(statRaces);
            statsDiv.appendChild(document.createElement('br'));

            let statWins = document.createElement('span');
            let sw = document.createElement('span');
            sw.textContent = userInfo.consecWins;
            sw.style.color = 'blue';
            statWins.textContent = 'Consecutive wins: ';
            statWins.appendChild(sw);
            statsDiv.appendChild(statWins);
            statsDiv.appendChild(document.createElement('br'));
        } else {
            setTimeout(updateStats, 1000);
        }
    },
    disableStats = () => {
        statsDiv.innerHTML = "";
    },
    __ = {},
    _ = {
        fill: window.CanvasRenderingContext2D.prototype.fillText,
        toStr: window.Function.prototype.toString,
        get: window.Object.prototype.__lookupGetter__,
        listen: window.addEventListener,
        unlisten: window.removeEventListener,
        reload: window.location.reload,
        host: ShadowRoot.prototype.__lookupGetter__('host'),
        fp: Function.prototype,
        warn: console.warn,
        ws: window.WebSocket,
        xsend: window.XMLHttpRequest.prototype.send,
        xopen: window.XMLHttpRequest.prototype.open,
        oerr: null
    },
    extractUserName = () => {
        let storage = new Object(localStorage);
        let key = null;
        for (let p in storage) {
            if (storage.hasOwnProperty(p)) {
                try {
                    key = JSON.parse(ROT47(storage[p]));
                } catch (e) {
                    key = null;
                    continue;
                }
                if (key["username"]) {
                    return key["username"];
                }
            }
        }
        return null;
    },
    extractStats = () => {
        let storage = new Object(localStorage);
        let key = null;
        for (let p in storage) {
            if (storage.hasOwnProperty(p)) {
                try {
                    key = JSON.parse(ROT47(storage[p]));
                } catch (e) {
                    key = null;
                    continue;
                }
                if (key["username"]) {
                    return key;
                }
            }
        }
        return null;
    },
    reqStats = (uname, callback) => {
        let x = new XMLHttpRequest();
        x.open("GET", "https://www.nitrotype.com/racer/" + uname, true);
        x.send();
        x.onload = () => {
            callback(x.responseText);
        }
    },
    setWPM = w => {
        if (isStopped)return;
        wordsPerMinute = w;
        wpm.value = w;
        setLocalStorage('wpm', w);
    },
    autoNitroOn = () => {
        autoNitroBtn.style.borderColor = "LimeGreen";
        autoNitroBtn.style.color = "LimeGreen";
        autoNitroBtn.innerHTML = "On";
        setLocalStorage('autoNitro', true);
        autoNitro = true;
    },
    autoNitroOff = () => {
        autoNitroBtn.style.borderColor = "Red";
        autoNitroBtn.style.color = "Red";
        autoNitroBtn.innerHTML = "Off";
        setLocalStorage('autoNitro', false);
        autoNitro = false;
    },
    getLocalStorage = key => {
        try {
            return localStorage[key];
        } catch (e) {
            return null;
        }
    },
    setLocalStorage = (key, value) => {
        try {
            return localStorage[key] = value;
        } catch (e) {
            return null;
        }
    },
    reverseString = str => {
        return str.split``.reverse().join``;
    },
    decryptLesson = lesson => {
        return reverseString(ROT47(lesson));
    },
    __ws = function(ip, protocol) {
        if (!ip.includes('nitrotype.com')) {
            // this clearly isnt the socket we want to sniff
            return new _.ws(ip, protocol);
        }
        ws = new _.ws(ip, protocol);
        ws.addEventListener('message', msg => {
            // console.debug('recieved', msg.data);
            let validPacket = true;
            let packet = {};
            if (msg.data) {
                if (msg.data.includes(`"payload":{"type":"banned"}}`)) {
                    console.warn('Incoming WebSocket message indicates ban.');
                    // debugger;
                }
                try {
                    packet = JSON.parse(msg.data.substring(1, msg.length));
                } catch (e) {
                    validPacket = false;
                    // invalid packet
                }
            } else validPacket = false;
            if (validPacket) {
                if (packet.msg == "error") {
                    respawn();
                } else if (packet.stream == "race") {
                    if (packet.msg == "status") {
                        if (packet.payload.status == "countdown" && packet.payload.l) {
                            let _lesson = packet.payload.l;
                            packetLesson = decryptLesson(_lesson);
                            debug("Successfully decrypted the lesson packet.");
                        }
                    }
                }
            }
        });
        return ws;
    },
    tgen = val => {
        max = val + 17;
        min = val - 17;
        let rand = 0;
        for (let i = 0; i < 6; i += 1) {
            rand += Math.random();
        }
        return Math.ceil((((rand - 3) / 3) * (max - min)) + min);
    },
    handleFillText = args => {
        const text = args[0];
        if (text.length < 2) {
            renderedKeys++;
            fillsY.push(args[2]);
            // A space needs to be appended to the lesson
            if (fillsY[fillsY.length - 1] < fillsY[fillsY.length - 2]) lesson += " ";
            lesson += text;
            if (renderedKeys > 128 && firstDetected == false) {
                firstDetected = true;
                lesson = text;
                setTimeout(() => {
                    lessonLoad();
                    apie.onRaceStarting && (apie.onRaceStarting());
                }, 200);
            }
        }
    },
    randomBool = percentFalse => {
        let percent = 0.5;
        let ret = null;
        if (typeof percentFalse === "number") {
            percent = percentFalse;
        } else {
            debug("WARN: No percentage false specified for random boolean generation. Using 0.5.");
        }
        ret = Math.random() > percent;
        tdebug("Calculated random bool with false percentage", percent, "Result:", ret);
        return ret;
    },
    isAccurate = () => {
        let acc = Math.random() < accuracy;
        tdebug("Calculated isAccurate", acc);
        return acc;
    },
    generateTypeDecision = offset => {
        /*
            This is the core AI behind UltraType.
            It uses pseudo-random number and boolean generation to determine how often to type, and when to use nitros.
            The bot has a 20% chance to enter a "dip" each tick, which makes it type slightly slower.
        */
        if(isStopped) return;
        setTimeout(() => {
            let dipRate = 0.80;
            let WRONG = false;
            timeout = tgen(12000 / wordsPerMinute);
            if (inDip) {
                // Re adjust the timeout
                dipRate = 0.40;
                timeout = tgen(12000 / wordsPerMinute);
            }
            if (enabled) {
                if (!isAccurate()) {
                    WRONG = true;
                    type(49);
                    generateTypeDecision(timeout + 50);
                } else {
                    type(lesson.charCodeAt(i));
                }
                if (!WRONG) {
                    i++;
                    if (i < lesson.length) {
                        generateTypeDecision(timeout);
                    }
                }
                if (autoNitro) {
                    if (randomBool(0.999)) { // Theres a 0.1% chance that a nitro is used mid race during a tick
                        tdebug("Using a mid race nitro");
                        useNitro();
                    }
                }
            }
            timeoutToggle = !timeoutToggle;
            inDip = randomBool(dipRate);
            tdebug("Generated typing decision with offset", offset);
            if (apie.onType) {
                apie.onType({
                    charTyped: lesson.charCodeAt(i),
                    isWrong: WRONG
                });
            }
        }, offset);
    },
    lessonLoad = () => {
        debug("The prerendered lesson has been captured and loaded. Starting in " + (LOAD_TIME / 1000) + " seconds.");
        if (!isStopped) {
            infoSpan.innerHTML = "Starting...";
            infoSpan.style.color = "#00b300";
        }
        setTimeout(() => {
            if (!isStopped) {
                infoSpan.innerHTML = "Started!";
                infoSpan.style.color = "#33ff33";
            }
            lessonLoaded = true;
            startTime = new Date();
            if (lesson.length > 1) {
                generateTypeDecision();
                debug("Started the bot!");
                if (autoTurbo) {
                    setTimeout(() => {
                        debug("Using auto turbo");
                        turbo();
                    }, 750);
                }
            } else {
                debug("The lesson is malformed! Lesson:", ('"' + lesson + '"'));
                return;
            }
            if (apie.onRaceStart) {
                apie.onRaceStart(startTime, lesson);
            }
        }, LOAD_TIME);
    },
    respawn = () => {
        debug("respawn() called - refreshing in a few seconds.");
        setTimeout(location.reload.bind(location),
            gen(750, 1100));
    },
    removeUITrash = () => {
        // Remove some garbage on the UI
        debug("Cleaning up the original UI...");
        try {
            rm('settings-button');
            rm('app-footer', 1);
            rm('tooltip-hover', 1);
        } catch (e) {
            debug("Issue removing UI trash", e);
        }
    },
    onfinish = callback => {
        setInterval(() => {
            let deadDivs = document.getElementsByClassName('popup race-results'),
                banner = document.getElementsByClassName('banner'),
                errorDivs = document.getElementsByClassName('popup popup-race-error');
            if (
                (deadDivs && deadDivs.length > 0) ||
                (disqualified) ||
                (banner && banner.length > 0) ||
                (errorDivs && errorDivs.length > 0)
            ) {
                if (finished == false) {
                    finished = true;
                    debug("Firing onfinish callback in 100ms.");
                    setTimeout(callback.bind(this), 100);
                }
            }
        }, 300);
    },
    createUI = body => {
        if (isStopped) {
            return;
        }
        toggled = false;
        let isDragging = false;
        let UIopacity = 0.7;
        let doc = document.querySelector('html');
        let inner = document.querySelector('.wrap');
        body.appendChild(injectedRoot);
        let UI = document.createElement('div');
        $(root).append(FONT);
        Object.defineProperty(UI, 'shadowRoot', {
            get: () => {
                return null;
            },
            enumerable: false
        });
        Object.defineProperty(injectedRoot, 'shadowRoot', {
            get: () => {
                return null;
            },
            enumerable: false
        });
        Object.defineProperty(root, 'shadowRoot', {
            get: () => {
                return null;
            },
            enumerable: false
        });
        UI.style.zIndex = 999999;
        UI.id = "botUI";
        UI.style.position = "fixed";
        UI.style.top = "3%";
        UI.style.left = "3%";
        UI.style.color = "white";
        UI.style.borderStyle = "solid";
        UI.style.borderColor = "#000066";
        UI.style.borderWidth = "6px";
        UI.style.borderRadius = "7px";
        UI.style.padding = "10px";
        UI.style.backgroundColor = "black";
        UI.style.textAlign = "center";
        UI.style.opacity = UIopacity;
        UI.style.transition = "opacity 500ms, border 500ms, border-color 500ms";
        UI.style.fontFamily = "'Ubuntu', sans-serif";
        UI.onmouseover = () => {
            UIopacity = 1;
            UI.style.opacity = UIopacity;
        }
        UI.onmouseleave = () => {
            UIopacity = 0.7;
            UI.style.opacity = UIopacity;
        }

        let outerTitle = document.createElement('center');
        let title = document.createElement('p');
        title.style.fontSize = "135%";
        title.innerHTML = "<strong>L_0R3NZ0 Type Bot!</strong>";
        title.style.cursor = 'pointer';
        title.onclick = () => {
            window.open(EXT_URL,'_blank');
        }
        UI.style.fontSize = "135%";
        outerTitle.appendChild(title);
        UI.appendChild(outerTitle);

        let outerInfo = document.createElement('center');
        info = document.createElement('p');
        infoSpan = document.createElement('span');
        infoSpan.innerHTML = "Idle.";
        infoSpan.style.color = "#b3b3b3";
        infoSpan.style.transition = "color 500ms";
        info.style.fontSize = "100%";
        info.innerHTML += "Status: ";
        info.appendChild(infoSpan);
        outerInfo.appendChild(info);
        UI.appendChild(outerInfo);

        let outerEnable = document.createElement('center');
        let enableButton = document.createElement('button');
        enableButton.className = "";
        enableButton.style.backgroundColor = "transparent";
        enableButton.style.border = "3px solid";
        enableButton.style.borderRadius = "3px";
        enableButton.style.fontSize = "125%";
        enableButton.style.borderColor = "#808080";
        enableButton.style.color = "#808080";
        enableButton.style.transition = "border 500ms, border-color 500ms, color 500ms";
        enableButton.innerHTML = "Customize";
        enableButton.onclick = () => {
            if (!optOn) {
                optOn = true;
                opt.style.opacity = 0.95;
                opt.style.pointerEvents = "all";
                opt.focus();
            } else {
                return;
            }
        }
        _.listen.apply(enableButton, ["mouseover", () => {
            enableButton.style.color = "white";
            enableButton.style.borderColor = "white";
        }, true]);
        _.listen.apply(enableButton, ["mouseout", () => {
            enableButton.style.color = "#808080";
            enableButton.style.borderColor = "#808080";
        }, true]);
        outerEnable.appendChild(enableButton);
        UI.appendChild(outerEnable);

        let outerTurbo = document.createElement('center');
        let turboBtn = document.createElement('button');
        turboBtn.className = "";
        turboBtn.style.backgroundColor = "transparent";
        turboBtn.style.border = "3px solid";
        turboBtn.style.borderRadius = "3px";
        turboBtn.style.fontSize = "125%";
        turboBtn.style.borderColor = "#ff1a1a";
        turboBtn.style.color = "#ff1a1a";
        turboBtn.style.transition = "border 500ms, border-color 500ms, color 500ms";
        turboBtn.innerHTML = "Turbo";
        turboBtn.onclick = () => {
            turboBtn.style.color = "#660000";
            turboBtn.style.borderColor = "#660000";
            if (!firstTurbo) {
                firstTurbo = true;
                if (localStorage["turboAlert"]) {
                    try {
                        turbo();
                    } catch(e) {
                        debug("WARN: Couldn't turbo", e);
                    };
                } else {
                    alert("WARNING: Turbo Can Get You Banned!\nThis message will not be displayed again.");
                    localStorage["turboAlert"] = 1;
                    try {
                        turbo();
                    } catch(e) {
                        debug("WARN: Couldn't turbo", e);
                    };
                }
            }
        }
        UI.appendChild(document.createElement('br'));
        outerTurbo.appendChild(turboBtn);
        UI.appendChild(outerTurbo);
        UI.appendChild(document.createElement('br'));
        statsDiv = document.createElement('center');
        statsDiv.innerHTML = 'Stats are loading...';
        statsDiv.style.color = 'grey';
        statsDiv.style.display = 'none';
        UI.appendChild(statsDiv);
        UI.appendChild(document.createElement('br'));

        function moveUI(e) {
            UI.style.top = (e.clientY - (e.clientY - UI.style.top)) + 'px';
            UI.style.left = (e.clientX - (e.clientX - UI.style.left)) + 'px';
        }
        _.listen.apply(window, ['keydown', e => {
            if (e.keyCode == 27) {
                toggled = !toggled;
                if (toggled) {
                    UI.style.opacity = 0;
                    g.style.opacity = 0;
                    UI.style.pointerEvents = "none";
                    g.style.pointerEvents = "none";
                } else {
                    UI.style.opacity = UIopacity;
                    if (localStorage['chartOn']) g.style.opacity = UIopacity;
                    UI.style.pointerEvents = "auto";
                    if (localStorage['chartOn']) g.style.pointerEvents = "auto";
                    else g.style.pointerEvents = "none";
                }
            }
        }]);
        _.listen.apply(window, ['mouseup', e => {
            isDragging = false;
            UI.style.opacity = UIopacity;
            UI.style.borderColor = "#000066";
            e.preventDefault();
            _.unlisten.apply(window, ['mousemove', moveUI, true]);
        }, false]);
        root.appendChild(UI);
        detectWebGL();
        createOptsMenu();
        if (apie.onReady) {
            apie.onReady();
        }
    },
    initChart = () => {
        if (!document.body) {
            let _initChart = initChart.bind(this);
            setTimeout(_initChart, 300);
            return;
        }
        g.style.zIndex = 9999;
        g.style.backgroundColor = "#000";
        g.style.fontFamily = "Ubuntu";
        g.style.position = "fixed";
        g.style.bottom = "5%";
        g.style.right = "5%";
        g.style.fontSize = "125%";
        g.style.color = "white";
        g.style.opacity = 0.7;
        g.style.padding = "10px";
        g.style.border = "6px solid";
        g.style.borderColor = "#000066";
        g.style.borderRadius = "7px";
        g.style.width = "40%";
        g.style.height = "25%";
        g.style.transition = "opacity 500ms, border 500ms, border-color 500ms";
        Highcharts.chart(g, {
            chart: {
                backgroundColor: {
                    linearGradient: [0, 0, 500, 500],
                    stops: [
                        [0, 'rgb(0, 0, 0)'],
                        [1, 'rgb(0, 0, 0)']
                    ]
                },
                style: {
                    color: "#fff",
                    fontFamily: "Ubuntu"
                }
            },
            title: {
                text: "Speed",
                x: -20,
                style: {
                    color: "#fff",
                    fontFamily: "Ubuntu"
                }
            },
            tooltip: {
                valueSuffix: ' WPM',
            },
            xAxis: {
                gridLineWidth: 0,
                categories: [
                    //
                ],
                labels: {
                    style: {
                        color: '#FFF',
                        font: 'Ubuntu'
                    }
                }
            },
            yAxis: {
                gridLineWidth: 0,
                title: {
                    text: "WPM"
                },
                plotLines: [{
                    value: 0,
                    width: 1,
                    color: '#ff0000'
                }],
                labels: {
                    style: {
                        color: '#FFF',
                        font: 'Ubuntu'
                    }
                }
            },
            legend: {
                layout: 'vertical',
                align: 'right',
                verticalAlign: 'middle',
                borderWidth: 0,
                style: {
                    color: "#fff"
                }
            },
            plotOptions: {
                line: {
                    marker: {
                        enabled: false
                    }
                }
            },
            series: [{
                name: 'Speed in WPM',
                data: points,
                color: '#000066'
            }]
        });
        chart = Highcharts.charts[0];
        _.listen.apply(g, ['mouseover', () => {
            if (localStorage['chartOn']) g.style.opacity = 1;
            if (localStorage['chartOn']) g.style.borderColor = "#0000ff";
        }, true]);
        _.listen.apply(g, ['mouseout', () => {
            if (localStorage['chartOn']) g.style.opacity = 0.7;
            if (localStorage['chartOn']) g.style.borderColor = "#000066";
        }, true]);
        addGraph(g);
        setTimeout(() => {
            let cr = g.getElementsByClassName('highcharts-credits');
            for (let i = 0; i < cr.length; i++) {
                cr[i].remove();
            }
        }, 500);
        if (!localStorage['chartOn']) {
            g.style.opacity = 0;
        }
    },
    createOptsMenu = () => {
        opt = document.createElement('div');
        opt.style.zIndex = 99999999;
        opt.style.backgroundColor = "#000";
        opt.style.border = "6px solid";
        opt.style.borderColor = "#000066";
        opt.style.borderRadius = "6px";
        opt.style.fontSize = "150%";
        opt.style.color = "#FFF";
        opt.style.position = "fixed";
        opt.style.padding = "10px";
        opt.style.top = "50%";
        opt.style.left = "50%";
        opt.style.display = "inline-block";
        opt.style.fontFamily = "Ubuntu";
        opt.style.transform = "translate(-50%, -50%)";
        opt.style.transition = "opacity 500ms, border 500ms, border-color 500ms";

        opt.style.opacity = 0;
        opt.style.pointerEvents = "none";

        let inner = document.createElement('center');

        let lbl = document.createElement('h1');
        lbl.style.fontSize = "150%";
        lbl.innerHTML = "Customize L_0R3NZ0 TypeBot";
        inner.appendChild(lbl);

        let outerBotOn = document.createElement('div');
        let botOnBtn = document.createElement('button');
        botOnBtn.className = "";
        botOnBtn.style.backgroundColor = "transparent";
        botOnBtn.style.border = "3px solid";
        botOnBtn.style.borderRadius = "3px";
        botOnBtn.style.fontSize = "100%";
        botOnBtn.style.borderColor = "LimeGreen";
        botOnBtn.style.color = "LimeGreen";
        botOnBtn.style.transition = "border 500ms, border-color 500ms, color 500ms";
        botOnBtn.innerHTML = "On";
        botOnBtn.onclick = () => {
            enabled = !enabled;
            if (!enabled) {
                botOnBtn.style.borderColor = "red";
                botOnBtn.style.color = "red";
                botOnBtn.innerHTML = "Off";
            } else {
                botOnBtn.style.borderColor = "LimeGreen";
                botOnBtn.style.color = "LimeGreen";
                botOnBtn.innerHTML = "On";
            }
        }
        outerBotOn.innerHTML += "Bot enabled: ";
        outerBotOn.appendChild(botOnBtn);
        inner.appendChild(outerBotOn);

        let outerToggle = document.createElement('div');
        let toggleButton = document.createElement('button');
        toggleButton.className = "";
        toggleButton.style.backgroundColor = "transparent";
        toggleButton.style.border = "3px solid";
        toggleButton.style.borderRadius = "3px";
        toggleButton.style.fontSize = "100%";
        toggleButton.style.transition = "border 500ms, border-color 500ms, color 500ms";

        if (autoRefresh) {
            toggleButton.style.borderColor = "LimeGreen";
            toggleButton.style.color = "LimeGreen";
            toggleButton.innerHTML = "On";
        } else {
            toggleButton.style.borderColor = "red";
            toggleButton.style.color = "red";
            toggleButton.innerHTML = "Off";
        }
        toggleButton.onclick = () => {
            autoRefresh = !autoRefresh;
            setLocalStorage('autoRefresh', autoRefresh);
            if (!autoRefresh) {
                toggleButton.style.borderColor = "red";
                toggleButton.style.color = "red";
                toggleButton.innerHTML = "Off";
            } else {
                toggleButton.style.borderColor = "LimeGreen";
                toggleButton.style.color = "LimeGreen";
                toggleButton.innerHTML = "On";
            }
        }
        outerToggle.innerHTML += "Auto Refresh: ";
        outerToggle.appendChild(toggleButton);
        inner.appendChild(outerToggle);

        let outerNtr = document.createElement('div');
        autoNitroBtn = document.createElement('button');
        autoNitroBtn.className = "";
        autoNitroBtn.style.backgroundColor = "transparent";
        autoNitroBtn.style.border = "3px solid";
        autoNitroBtn.style.borderRadius = "3px";
        autoNitroBtn.style.fontSize = "100%";
            autoNitroBtn.style.transition = "border 500ms, border-color 500ms, color 500ms";
        if (autoNitro) {
            autoNitroBtn.style.borderColor = "LimeGreen";
            autoNitroBtn.style.color = "LimeGreen";
            autoNitroBtn.innerHTML = "On";
        } else {
            autoNitroBtn.style.borderColor = "red";
            autoNitroBtn.style.color = "red";
            autoNitroBtn.innerHTML = "Off";
        }
        autoNitroBtn.onclick = () => {
            autoNitro ? autoNitroOn() : autoNitroOff();
        }
        outerNtr.innerHTML += "Auto Nitro: ";
        outerNtr.appendChild(autoNitroBtn);
        inner.appendChild(outerNtr);

        let outerChrtBtn = document.createElement('div');
        let chartBtn = document.createElement('button');
        chartBtn.className = "";
        chartBtn.style.backgroundColor = "transparent";
        chartBtn.style.border = "3px solid";
        chartBtn.style.borderRadius = "3px";
        chartBtn.style.fontSize = "100%";
        chartBtn.style.transition = "border 500ms, border-color 500ms, color 500ms";

        if (localStorage['chartOn']) {
            chartBtn.style.borderColor = "LimeGreen";
            chartBtn.style.color = "LimeGreen";
            chartBtn.innerHTML = "On";
        } else {
            chartBtn.style.borderColor = "red";
            chartBtn.style.color = "red";
            chartBtn.innerHTML = "Off";
        }
        chartBtn.onclick = () => {
            if (localStorage['chartOn']) {
                delete localStorage['chartOn'];
                chartBtn.style.borderColor = "red";
                chartBtn.style.color = "red";
                chartBtn.innerHTML = "Off";
            } else {
                localStorage['chartOn'] = 1;
                chartBtn.style.borderColor = "LimeGreen";
                chartBtn.style.color = "LimeGreen";
                chartBtn.innerHTML = "On";
                g.style.opacity = 0.7;
            }
        }
        outerChrtBtn.innerHTML += "Speed chart: ";
        outerChrtBtn.appendChild(chartBtn);
        inner.appendChild(outerChrtBtn);

        let outerACfg = document.createElement('div');
        acc = document.createElement('input');
        acc.type = "number";
        acc.min = 10;
        acc.max = 100;
        acc.value = accuracy * 100;
        acc.className = "";
        acc.style.backgroundColor = "transparent";
        acc.style.border = "3px solid";
        acc.style.borderRadius = "3px";
        acc.style.fontSize = "100%";
        acc.style.borderColor = "LimeGreen";
        acc.style.color = "LimeGreen";
        acc.style.transition = "border 500ms, border-color 500ms, color 500ms";
        acc.onchange = () => {
            accuracy = parseInt(acc.value);
            if (isNaN(accuracy)) {
                accuracy = 0.98;
                acc.value = 98;
            } else {
                accuracy *= 0.01;
            }
            setLocalStorage('accuracy', accuracy);
        }

        outerACfg.innerHTML += "Accuracy %: ";
        outerACfg.appendChild(acc);
        inner.appendChild(outerACfg);

        let oWPMCfg = document.createElement('div');
        wpm = document.createElement('input');
        wpm.type = "number";
        wpm.min = 3;
        wpm.max = MAX_WPM; // About the fastest you can go without any bans
        wpm.value = wordsPerMinute;
        wpm.className = "";
        wpm.style.backgroundColor = "transparent";
        wpm.style.border = "3px solid";
        wpm.style.borderRadius = "3px";
        wpm.style.fontSize = "100%";
        wpm.style.borderColor = "LimeGreen";
        wpm.style.color = "LimeGreen";
        wpm.style.transition = "border 500ms, border-color 500ms, color 500ms";
        wpm.onchange = () => {
            if (localStorage["speedChange"]) {
                wordsPerMinute = parseInt(wpm.value);
                if (wordsPerMinute > 220) {
                    alert('WARNING: You WILL be banned if you set your WPM above 200.');
                }
                if (isNaN(wordsPerMinute))
                    wpm.value = 85;
                setWPM(wpm.value);
            } else {
                // alert('It is not recommended to alter the default speed of UltraType, be careful! This message will not be shown again.');
                setLocalStorage('speedChange', true);
            }
        }

        oWPMCfg.innerHTML += "WPM: ";
        oWPMCfg.appendChild(wpm);
        inner.appendChild(oWPMCfg);

        let outerStatTogg = document.createElement('div');
        statTogg = document.createElement('button');

        statTogg.className = "";
        statTogg.style.backgroundColor = "transparent";
        statTogg.style.border = "3px solid";
        statTogg.style.borderRadius = "3px";
        statTogg.style.fontSize = "100%";
        statTogg.style.borderColor = "LimeGreen";
        statTogg.style.color = "LimeGreen";
        statTogg.style.transition = "border 500ms, border-color 500ms, color 500ms";
        statTogg.innerHTML = "On";
        statTogg.onclick = () => {
            statsOn = !statsOn;
            if (statsOn) {
                statTogg.style.borderColor = "LimeGreen";
                statTogg.style.color = "LimeGreen";
                statTogg.innerHTML = "On";
                updateStats();
            } else {
                statTogg.style.borderColor = "red";
                statTogg.style.color = "red";
                statTogg.innerHTML = "Off";
                disableStats();
            }
            setLocalStorage('statsOn', statsOn);
        }
        outerStatTogg.innerHTML = "User Stats: ";
        outerStatTogg.appendChild(statTogg);
        inner.appendChild(outerStatTogg);

        let outerAutoT = document.createElement('div');
        let autoT = document.createElement('button');
        autoT.className = "";
        autoT.style.backgroundColor = "transparent";
        autoT.style.border = "3px solid";
        autoT.style.borderRadius = "3px";
        autoT.style.fontSize = "100%";
        autoT.style.borderColor = "LimeGreen";
        autoT.style.color = "LimeGreen";
        autoT.style.transition = "border 500ms, border-color 500ms, color 500ms";
        autoT.innerHTML = "On";
        autoT.onclick = () => {
            if (!autoTurbo) {
                autoT.style.borderColor = "LimeGreen";
                autoT.style.color = "LimeGreen";
                autoT.innerHTML = "On";
                autoTurboOn();
            } else {
                autoT.style.borderColor = "red";
                autoT.style.color = "red";
                autoT.innerHTML = "Off";
                autoTurboOff();
            }
        }
        // Set the default button state
        if (autoTurbo) {
            autoT.style.borderColor = "LimeGreen";
            autoT.style.color = "LimeGreen";
            autoT.innerHTML = "On";
        } else {
            autoT.style.borderColor = "red";
            autoT.style.color = "red";
            autoT.innerHTML = "Off";
        }
        outerAutoT.innerHTML = "Auto Turbo: ";
        outerAutoT.appendChild(autoT);
        inner.appendChild(outerAutoT);

        let tips = document.createElement('p');
        tips.innerHTML = "Press escape to hide all of the L_0R3NZ0 Type.<br>";
        inner.appendChild(tips);

        let outerExitBtn = document.createElement('center');
        let exitButton = document.createElement('button');
        exitButton.className = "";
        exitButton.style.borderColor = "#808080";
        exitButton.style.color = "#808080";
        exitButton.style.fontSize = "175%";
        exitButton.style.border = "3px solid";
        exitButton.style.borderRadius = "3px";
        exitButton.style.backgroundColor = "transparent";
        exitButton.style.transition = "border 500ms, border-color 500ms, color 500ms";
        _.listen.apply(exitButton, ["mouseover", () => {
            exitButton.style.color = "#FFF";
            exitButton.style.borderColor = "#FFF";
        }, true]);
        _.listen.apply(exitButton, ["mouseout", () => {
            exitButton.style.color = "#808080";
            exitButton.style.borderColor = "#808080";
        }, true]);
        exitButton.innerHTML = "Exit";
        exitButton.onclick = () => {
            opt.style.opacity = 0;
            opt.style.pointerEvents = "none";
            optOn = false;
            opt.blur();
        }
        outerExitBtn.appendChild(exitButton);
        inner.appendChild(outerExitBtn);

        opt.appendChild(inner);
        root.appendChild(opt);

        setTimeout(() => {
            let localAutoRefresh = localStorage['autoRefresh'],
                localAccuracy = localStorage['accuracy'],
                localWPM = localStorage['wpm'],
                localAutoNitro = localStorage['autoNitro'];
            if (localAutoNitro !== null && localAutoNitro !== undefined) {
                localAutoNitro = JSON.parse(localAutoNitro);
                if (localAutoNitro == false) {
                    autoNitroOff();
                } else {
                    autoNitroOn();
                }
            }

            if (localAutoRefresh) {
                autoRefresh = JSON.parse(localAutoRefresh);
                if (!autoRefresh) {
                    toggleButton.style.borderColor = "red";
                    toggleButton.style.color = "red";
                    toggleButton.innerHTML = "Off";
                } else {
                    toggleButton.style.borderColor = "LimeGreen";
                    toggleButton.style.color = "LimeGreen";
                    toggleButton.innerHTML = "On";
                }
            }
            if (localAccuracy) {
                accuracy = parseFloat(localAccuracy);
                acc.value = accuracy * 100;
            }
            if (localWPM) {
                wpm.value = localWPM;
                wordsPerMinute = parseInt(localWPM);
                setWPM(wordsPerMinute);
            }
            if (statsOn) {
                statTogg.style.borderColor = "LimeGreen";
                statTogg.style.color = "LimeGreen";
                statTogg.innerHTML = "On";
                updateStats();
            } else {
                statTogg.style.borderColor = "red";
                statTogg.style.color = "red";
                statTogg.innerHTML = "Off";
                disableStats();
            }
        }, 1000);
    },
    blockAd = ad => {
        try {
            ad.style.display = "none";
        } catch (e) {
            ad.src = "about:blank";
        }
        try {
            ad.parentElement.parentElement.parentElement.remove();
        } catch (e) {};
    },
    changeTip = node => {
        setTimeout(() => {
            node.style.fontSize = "125%";
            node.style.border = "3px solid #000066";
            node.style.borderRadius = "7px";
            node.style.opacity = 0.7;
            node.style.pointerEvents = "none";
            node.innerHTML = "";
            node.innerHTML += FONT;
            node.innerHTML += '<center style="font-family:Ubuntu;">UltraType - NitroType simplified.<br>Version: ' + VERSION + '</center>';
        }, 1000);
    },
    detectWebGL = () => {
        if (document.cookie.includes('webgl')) {
            document.cookie = document.cookie.replace('webgl', 'canvas');
        }
    },
    handleScript = scr => {
        if (scr.src.includes('race-lib')) {
            scr.addEventListener('load', () => {
                _set = PIXI.BitmapText.prototype.setText;
                let tos = __.toStr;
                PIXI.BitmapText.prototype.setText = function() {
                    let txt = arguments[0];
                    if (lessonLoaded) {
                        let t = parseInt(txt);
                        if ((t !== 0) && (t > 5)) {
                            points.push(t);
                            chart.series[0].setData(points, true);
                        }
                    }
                    _set.apply(this, arguments);
                }
            });
        } else if (scr.src.includes('libs')) {
            if (hasScrLoaded) return;
            else hasScrLoaded = 1;
            scr.addEventListener('load', () => {
                let didGetHandler = false;
                _attachHandler = $.fn.constructor.prototype.keypress;
                $.fn.constructor.prototype.keypress = function() {
                    if (this && this[0] && this[0] == document.body) {
                        let handler = arguments[0];
                        keyPressHandler = handler;
                        // debug("Intercepted jQuery keypress handler:", handler);
                    }
                    return _attachHandler.apply(this, arguments);
                }
            });
        } else if (scr.src.includes('app.min.')) {
            scr.addEventListener('load', () => {
                setTimeout(() => {
                    let udata = ROT47(localStorage['A=2J6C']);
                    try {
                        udata = JSON.parse(udata);
                    } catch (e) {
                        return;
                    }
                    // udata.websocketSupport = true;
                    udata = ROT47(JSON.stringify(udata));
                    localStorage['A=2J6C'] = udata;
                }, 100);
            });
        }
    }
    console.warn = function() {
        if (arguments[0] == "You have been disqualified") {
            disqualified = true;
        }
        console.log.apply(this, arguments);
    }
    __.fill = function() {
        handleFillText(arguments);
        _.fill.apply(this, arguments);
    }
    let _set = null,
        _send = WebSocket.prototype.send;
    WebSocket.prototype.send = function() {
        if (typeof arguments[0] !== 'string') {
            return _send.apply(this, arguments);
        }
        let msg = arguments[0],
            header = msg[0],
            obj = null;
        msg = msg.substr(1, msg.length);
        try {
            obj = JSON.parse(msg);
        } catch(e) {
            return _send.apply(this, arguments);;
        }
        if (obj && obj.payload && obj.payload.a) {
            debug("very naughty packet detected, lets fix that");
            delete obj.payload.a;
            // Replace packet
            arguments[0] = header + JSON.stringify(obj);
        }
        return _send.apply(this, arguments);
    }
    onfinish(() => {
        debug("Race has finished. Doing a ban check and reloading if needed.");
        if (apie.onRaceFinish) {
            apie.onRaceFinish();
        }
        endTime = new Date();
        infoSpan.innerHTML = "Finished";
        infoSpan.style.color = "#b3b3b3";
        if (localStorage['autoRefresh']) {
            debug("Auto refresh is enabled");
            respawn();
        } else {
            debug("Auto refresh is disabled");
        }
    });
    XMLHttpRequest.prototype.send = function() {
        let payload = arguments[0];
        let header = '';
        if (payload && payload.length > 4 && payload[4] == '{') {
            let obj;
            header = payload.substr(0, 4);
            try {
                obj = JSON.parse(payload.substr(4, payload.length));
            } catch(e) {
                return _.xsend.apply(this, arguments);
            }
            if (obj.payload && obj.payload.a) {
                // Remove cheater flag from outgoing packet
                delete obj.payload.a;
                arguments[0] = header + JSON.stringify(obj);
            }
        }
        return _.xsend.apply(this, arguments);
    }
    XMLHttpRequest.prototype.open = function() {
        if (arguments[1].includes('/api/error')) {
            errorRequests.push(this);
            this.abort();
            return;
            } else if (arguments[1].includes('problem-keys')) {
            if (PROBLEM_KEYS_DEBUG) {
                console.warn('PROBLEM_KEYS_DEBUG is enabled, firing up debugger.');
                debugger;
            }
            if (ABORT_PROBLEM_KEYS) {
                debug("Aborting problem-keys AJAX request.");
                this.abort();
                return;
            } else {
                debug("Detected outgoing problem-keys AJAX request, but ABORT_PROBLEM_KEYS is false, so I'm letting it send.");
            }
        }
        return _.xopen.apply(this, arguments);
    }
    // inject undetectable features
    window.PIXI = {};
    PIXI.BitmapText = function() {};
    PIXI.BitmapText.prototype.setText = function(a) { this.text = a || " ", this.dirty = !0 };
    let hostt = ShadowRoot.prototype.__lookupGetter__('host');
    let _getToStr = Function.prototype.__lookupGetter__('toString');
    let _setTxt = Element.prototype.__lookupSetter__('textContent');
    let _getTitle = Document.prototype.__lookupGetter__('title');
    let _setTitle = Document.prototype.__lookupSetter__('title');
    CanvasRenderingContext2D.prototype.fillText = __.fill;
    window.WebSocket = __ws;
    Function.prototype.toString = __.toStr = function() {
        if (this === Function.prototype.toString) return _.toStr.call(_.toStr);
        if (this === CanvasRenderingContext2D.prototype.fillText) return _.toStr.call(_.fill);
        if (this === Object.prototype.__lookupGetter__) return _.toStr.call(_.get);
        if (this === ShadowRoot.prototype.__lookupGetter__('host')) return _.toStr.call(hostt);
        if (this === Function.prototype.__lookupGetter__('toString')) return _.toStr.call(_getToStr);
        if (this === Element.prototype.__lookupSetter__('textContent')) return _.toStr.call(_setTxt);
        if (this === Document.prototype.__lookupGetter__('title')) return _.toStr.call(_getTitle);
        if (this === Document.prototype.__lookupSetter__('title')) return _.toStr.call(_setTitle);
        if (this === PIXI.BitmapText.prototype.setText) return _.toStr.call(_get);
        if (this === console.warn) return _.toStr.call(_.warn);
        if (this === WebSocket) return _.toStr.call(_.ws);
        if (this === XMLHttpRequest.prototype.send) return _.toStr.call(_.xsend);
        if (this === XMLHttpRequest.prototype.open) return _.toStr.call(_.xopen);
        if (this === window.onerror) return _.toStr.call(_.oerr);
        if (window.jQuery && this === jQuery.fn.keypress) return _.toStr.call(_attachHandler);
        return _.toStr.call(this);
    }
    ShadowRoot.prototype.__defineGetter__('host', () => {
        if (this === injectedRoot) return null;
        return _.host.call(this);
    });
    let observer = new MutationObserver(mutations => {
        mutations.forEach(mutation => {
            if (mutation.type == "childList" && mutation.addedNodes.length > 0) {
                for (let i in mutation.addedNodes) {
                    if (mutation.addedNodes[i].nodeName == "BODY") createUI(mutation.addedNodes[i]);
                    if (mutation.addedNodes[i].nodeName == "IFRAME") blockAd(mutation.addedNodes[i]);
                    if (mutation.addedNodes[i].className == "race-tip") changeTip(mutation.addedNodes[i]);
                    if (mutation.addedNodes[i].nodeName == "SCRIPT") handleScript(mutation.addedNodes[i]);
                }
            }
        });
    });
    observer.observe(document.documentElement, {
        childList: true,
        subtree: true,
        attributes: true,
        attributeFilter: ['style']
    });
    let _fakeToStr = __.toStr;
    _fakeToStr.__proto__ = _.toStr.prototype;
    _fakeToStr.prototype = _.toStr.prototype;
    Object.defineProperty(Function.prototype, 'toString', {
        get: () => {
            if (this === __.toStr) return _fakeToStr;
            return __.toStr;
        },
        enumerable: false
    });
    localStorage.clear = function() {} // Disable localStorage clearing
    Function.prototype.__defineGetter__('toString', function() {
        if (this === CanvasRenderingContext2D.prototype || this === CanvasRenderingContext2D.prototype.fillText) return __.toStr;
        if (this === console || this === console.warn) return __.toStr;
        if (this === ShadowRoot.prototype.__lookupGetter__('host') || this === ShadowRoot.prototype) return __.toStr;
        if (this === Object.prototype || this === Object.prototype.__lookupGetter__) return __.toStr;
        if (this === Function.prototype.__lookupGetter__('toString')) return __.toStr;
        if (this === PIXI.BitmapText.prototype.setText) return __.toStr;
        if (this === WebSocket) return __.toStr;
        if (this === injectedRoot) return __.toStr;
        if (this === Document.prototype.__lookupGetter__('title')) return __.toStr;
        if (this === Document.prototype.__lookupSetter__('title')) return __.toStr;
        if (this === XMLHttpRequest.prototype.send) return __.toStr;
        if (this === XMLHttpRequest.prototype.open) return __.toStr;
        if (this === window.onerror) return __.toStr;
        if (window.jQuery && this === jQuery.fn.keypress) return __.toStr;
        return _.toStr;
    });
    setInterval(() => {
        _setTitle.call(document, "L_0R3NZ0 Type Bot!");
    }, 100);
    Document.prototype.__defineGetter__('title', t => {
        return _title;
    });
    Document.prototype.__defineSetter__('title', t => {
        _title = t;
    });
    _.listen.apply(window, ['load', () => {
        _.oerr = window.onerror;
        window.onbeforeunload = () => {
            return null;
        };
        window.ga = () => {};
        window.onerror = evt => {
            if (evt.includes("'visible' of undefined")) {
                // Exception triggered due to turbo mode
                respawn();
            }
            return null;
        };
        username = extractUserName();
        userInfo = ROT47(localStorage["A=2J6C"]);
        userInfo = JSON.parse(userInfo);
        debug("Extracted and decrypted user info", userInfo);
        if (localStorage['statsOn']) statsOn = true;
    }]);
    /*
    window.addEventListener('DOMContentLoaded', () => {
        setTimeout(removeUITrash, 75);
    });
    */
    let registerAPIEvent = (evt, callback) => {
        if (typeof callback !== 'function') {
            throw new Error('Invalid event callback.');
            return;
        }
        switch (evt) {
            case "userBanned":
                apie.onUserBanned = callback;
                break;
            case "raceStart":
                apie.onRaceStart = callback;
                break;
            case "raceEnd":
            case "raceFinish":
                apie.onRaceFinish = callback;
                break;
            case "nitroUsed":
            case "nitroUse":
            case "nitro":
                apie.onNitroUsed = callback;
                break;
            case "raceStarting":
            case "raceBegin":
            case "raceInit":
                apie.onRaceStarting = callback;
                break;
            case "type":
            case "typed":
            case "botType":
                apie.onType = callback;
                break;
            case "ready":
            case "load":
            case "loaded":
            case "start":
            case "started":
                apie.onReady = callback;
                break;
            default:
                throw new Error('Invalid event name!');
                break;
        }
        return window.UltraTypeCore;
    }

    // Core API
    let core = {
        on: registerAPIEvent,
        turbo: turbo,
        setWPM: setWPM,
        sendTypePacket: typePacket,
        typeChar: type,
        stopFromRunning: () => { // Stops the bot from appearing or typing
            isStopped = true;
        },
        getDecyptedUserInfo: () => {
            if (userInfo) {
                return userInfo;
            } else {
                return null;
            }
        },
        setAutoTurbo: state => {
            if (state === false) {
                autoTurboOff();
            } else if (state === true) {
                autoTurboOn();
            } else {
                throw new Error('Invalid auto turbo state.');
            }
        },
        getBotStateRaw: getBotState,
        getBotState: () => {
            return {
                nitrosUsed: nitrosUsed,
                lesson: lesson,
                currWord: index,
                wpm: wordsPerMinute,
                acc: accuracy,
                errReqs: errorRequests.length,
                uinfo: JSON.stringify(userInfo),
                fillsY: fillsY.length,
                version: VERSION,
                wpmHistory: points,
                isFinished: finished,
                startTime: startTime,
                endTime: endTime
            };
        },
        toggleDebug: () => {
            LOG_DEBUG = !LOG_DEBUG;
        },
        getLesson: () => {
            if (lesson) {
                return lesson;
            } else return null;
        },
        setAutoRefresh: val => {
            if (typeof val !== 'boolean') {
                throw new Error('Can only set auto refresh to a boolean.');
                return;
            } else {
                autoRefresh = val;
            }
        },
        getNitrosUsed: () => { return nitrosUsed || 0 },
        toggleBotLog: () => {
            LOG_TYPING_INFO = !LOG_TYPING_INFO;
        },
        disableStats: disableStats,
        randBool: randomBool,
        updateStats: updateStats,
        useNitro: useNitro,
        flushRaw: () => {
            // Reset UltraType to it's default settings
            [
                'accuracy',
                'autoRefresh',
                'autoTurbo',
                'statsOn',
                'autoNitro',
                'wpm',
                'chartOn',
                'speedChange'
            ].forEach(k => {
                delete localStorage[k];
            });
        },
        flush: () => {
            core.flushRaw();
            delete localStorage['ultratypedev'];
            console.warn('Flushed UltraType settings, reloading...');
            setTimeout(location.reload.bind(location), 1000);
        },
        toggleLocalLoad: () => {
            if (localStorage["ultratypedev"]) {
                delete localStorage["ultratypedev"];
                console.info("Disabled local loading.");
            } else {
                localStorage["ultratypedev"] = true;
                console.info("Enabled local loading.");
            }
        },
        // Utility method to automatically involk debugger when a function is called
        debugFn: fn => {
            let _fn = fn;
            fn = function() {
                debugger;
                _fn.apply(this, arguments);
            }
            return fn;
        }
    }
    window.UltraTypeCore = core;
    let hcScript = document.createElement('script');
    hcScript.src = 'https://code.highcharts.com/highcharts.src.js';
    hcScript.addEventListener('load', () => {
        setTimeout(initChart.bind(window), 250);
    });
    document.head.appendChild(hcScript);

    // Bye bye!
    console.log('UltraType version ' + VERSION + ' loaded.');
    document.currentScript.remove();
})();