/**
 * Battle log
 *
 * An exercise in minimalism! This is a dependency of the client, which
 * requires IE9+ and uses Preact, and the replay player, which requires
 * IE7+ and uses jQuery. Therefore, this has to be compatible with IE7+
 * and use the DOM directly!
 *
 * Special thanks to PPK for QuirksMode.org, one of the few resources
 * available for how to do web development in these conditions.
 *
 * @author Guangcong Luo <guangcongluo@gmail.com>
 * @license MIT
 */ var BattleLog = (function () {
    function BattleLog(elem, scene, innerElem) {
        var _this = this;
        this.elem = void 0;
        this.innerElem = void 0;
        this.scene = null;
        this.preemptElem = null;
        this.atBottom = true;
        this.skippedLines = false;
        this.className = void 0;
        this.battleParser = null;
        this.joinLeave = null;
        this.lastRename = null;
        this.perspective = -1;
        this.onScroll = function () {
            var distanceFromBottom =
                _this.elem.scrollHeight -
                _this.elem.scrollTop -
                _this.elem.clientHeight;
            _this.atBottom = distanceFromBottom < 30;
        };
        this.elem = elem;
        if (!innerElem) {
            elem.setAttribute("role", "log");
            elem.innerHTML = "";
            innerElem = document.createElement("div");
            innerElem.className = "inner message-log";
            elem.appendChild(innerElem);
        }
        this.innerElem = innerElem;
        if (scene) {
            this.scene = scene;
            var preemptElem = document.createElement("div");
            preemptElem.className = "inner-preempt message-log";
            elem.appendChild(preemptElem);
            this.preemptElem = preemptElem;
            this.battleParser = new BattleTextParser();
        }
        this.className = elem.className;
        elem.onscroll = this.onScroll;
    }
    var _proto = BattleLog.prototype;
    _proto.reset = function reset() {
        this.innerElem.innerHTML = "";
        this.atBottom = true;
        this.skippedLines = false;
    };
    _proto.destroy = function destroy() {
        this.elem.onscroll = null;
    };
    _proto.addSeekEarlierButton = function addSeekEarlierButton() {
        var _this2 = this;
        if (this.skippedLines) return;
        this.skippedLines = true;
        var el = document.createElement("div");
        el.className = "chat";
        el.innerHTML =
            '<button class="button earlier-button"><i class="fa fa-caret-up"></i><br />Earlier messages</button>';
        var button = el.getElementsByTagName("button")[0];
        button == null
            ? void 0
            : button.addEventListener == null
            ? void 0
            : button.addEventListener("click", function (e) {
                  var _this2$scene;
                  e.preventDefault();
                  (_this2$scene = _this2.scene) == null
                      ? void 0
                      : _this2$scene.battle.seekTurn(
                            _this2.scene.battle.turn - 100
                        );
              });
        this.addNode(el);
    };
    _proto.add = function add(args, kwArgs, preempt) {
        var _this$scene,
            _this$scene2,
            _window$app,
            _window$app$ignore,
            _window$app2,
            _window$app2$rooms,
            _this$scene3;
        if (kwArgs != null && kwArgs.silent) return;
        if ((_this$scene = this.scene) != null && _this$scene.battle.seeking) {
            var battle = this.scene.battle;
            if (battle.stepQueue.length > 2000) {
                if (
                    battle.seeking === Infinity
                        ? battle.currentStep < battle.stepQueue.length - 2000
                        : battle.turn < battle.seeking - 100
                ) {
                    this.addSeekEarlierButton();
                    return;
                }
            }
        }
        var divClass = "chat";
        var divHTML = "";
        var noNotify;
        if (!["join", "j", "leave", "l"].includes(args[0]))
            this.joinLeave = null;
        if (!["name", "n"].includes(args[0])) this.lastRename = null;
        switch (args[0]) {
            case "chat":
            case "c":
            case "c:":
                var _battle =
                    (_this$scene2 = this.scene) == null
                        ? void 0
                        : _this$scene2.battle;
                var name;
                var message;
                if (args[0] === "c:") {
                    name = args[2];
                    message = args[3];
                } else {
                    name = args[1];
                    message = args[2];
                }
                var rank = name.charAt(0);
                if (
                    _battle != null &&
                    _battle.ignoreSpects &&
                    " +".includes(rank)
                )
                    return;
                if (_battle != null && _battle.ignoreOpponent) {
                    if (
                        "\u2605\u2606".includes(rank) &&
                        toUserid(name) !== app.user.get("userid")
                    )
                        return;
                }
                if (
                    (_window$app = window.app) != null &&
                    (_window$app$ignore = _window$app.ignore) != null &&
                    _window$app$ignore[toUserid(name)] &&
                    " +\u2605\u2606".includes(rank)
                )
                    return;
                var isHighlighted =
                    (_window$app2 = window.app) == null
                        ? void 0
                        : (_window$app2$rooms = _window$app2.rooms) == null
                        ? void 0
                        : _window$app2$rooms[_battle.roomid].getHighlight(
                              message
                          );
                var _this$parseChatMessag = this.parseChatMessage(
                    message,
                    name,
                    "",
                    isHighlighted
                );
                divClass = _this$parseChatMessag[0];
                divHTML = _this$parseChatMessag[1];
                noNotify = _this$parseChatMessag[2];
                if (!noNotify && isHighlighted) {
                    var notifyTitle =
                        "Mentioned by " + name + " in " + _battle.roomid;
                    app.rooms[_battle.roomid].notifyOnce(
                        notifyTitle,
                        '"' + message + '"',
                        "highlight"
                    );
                }
                break;

            case "join":
            case "j":
            case "leave":
            case "l": {
                var user = BattleTextParser.parseNameParts(args[1]);
                if (
                    _battle != null &&
                    _battle.ignoreSpects &&
                    " +".includes(user.group)
                )
                    return;
                var formattedUser = user.group + user.name;
                var isJoin = args[0].charAt(0) === "j";
                if (!this.joinLeave) {
                    this.joinLeave = {
                        joins: [],
                        leaves: [],
                        element: document.createElement("div"),
                    };
                    this.joinLeave.element.className = "chat";
                }

                if (isJoin && this.joinLeave.leaves.includes(formattedUser)) {
                    this.joinLeave.leaves.splice(
                        this.joinLeave.leaves.indexOf(formattedUser),
                        1
                    );
                } else {
                    this.joinLeave[isJoin ? "joins" : "leaves"].push(
                        formattedUser
                    );
                }

                var buf = "";
                if (this.joinLeave.joins.length) {
                    buf += this.textList(this.joinLeave.joins) + " joined";
                }
                if (this.joinLeave.leaves.length) {
                    if (this.joinLeave.joins.length) buf += "; ";
                    buf += this.textList(this.joinLeave.leaves) + " left";
                }
                this.joinLeave.element.innerHTML =
                    "<small>" + BattleLog.escapeHTML(buf) + "</small>";
                (preempt ? this.preemptElem : this.innerElem).appendChild(
                    this.joinLeave.element
                );
                return;
            }

            case "name":
            case "n": {
                var _user = BattleTextParser.parseNameParts(args[1]);
                if (toID(args[2]) === toID(_user.name)) return;
                if (
                    !this.lastRename ||
                    toID(this.lastRename.to) !== toID(_user.name)
                ) {
                    this.lastRename = {
                        from: args[2],
                        to: "",
                        element: document.createElement("div"),
                    };
                    this.lastRename.element.className = "chat";
                }
                this.lastRename.to = _user.group + _user.name;
                this.lastRename.element.innerHTML =
                    "<small>" +
                    BattleLog.escapeHTML(this.lastRename.to) +
                    " renamed from " +
                    BattleLog.escapeHTML(this.lastRename.from) +
                    ".</small>";
                (preempt ? this.preemptElem : this.innerElem).appendChild(
                    this.lastRename.element
                );
                return;
            }

            case "chatmsg":
            case "":
                divHTML = BattleLog.escapeHTML(args[1]);
                break;

            case "chatmsg-raw":
            case "raw":
            case "html":
                divHTML = BattleLog.sanitizeHTML(args[1]);
                break;

            case "uhtml":
            case "uhtmlchange":
                this.changeUhtml(args[1], args[2], args[0] === "uhtml");
                return ["", ""];

            case "error":
            case "inactive":
            case "inactiveoff":
                divClass = "chat message-error";
                divHTML = BattleLog.escapeHTML(args[1]);
                break;

            case "bigerror":
                this.message(
                    '<div class="broadcast-red">' +
                        BattleLog.escapeHTML(args[1]).replace(/\|/g, "<br />") +
                        "</div>"
                );
                return;

            case "pm":
                divHTML =
                    "<strong>" +
                    BattleLog.escapeHTML(args[1]) +
                    ':</strong> <span class="message-pm"><i style="cursor:pointer" onclick="selectTab(\'lobby\');rooms.lobby.popupOpen(\'' +
                    BattleLog.escapeHTML(args[2], true) +
                    "')\">(Private to " +
                    BattleLog.escapeHTML(args[3]) +
                    ")</i> " +
                    BattleLog.parseMessage(args[4]) +
                    "</span>";
                break;

            case "askreg":
                this.addDiv(
                    "chat",
                    '<div class="broadcast-blue"><b>Register an account to protect your ladder rating!</b><br /><button name="register" value="' +
                        BattleLog.escapeHTML(args[1]) +
                        '"><b>Register</b></button></div>'
                );
                return;

            case "unlink": {
                var _user2 = toID(args[2]) || toID(args[1]);
                this.unlinkChatFrom(_user2);
                if (args[2]) {
                    var lineCount = parseInt(args[3], 10);
                    this.hideChatFrom(_user2, true, lineCount);
                }
                return;
            }

            case "hidelines": {
                var _user3 = toID(args[2]);
                this.unlinkChatFrom(_user3);
                if (args[1] !== "unlink") {
                    var _lineCount = parseInt(args[3], 10);
                    this.hideChatFrom(_user3, args[1] === "hide", _lineCount);
                }
                return;
            }

            case "debug":
                divClass = "debug";
                divHTML =
                    '<div class="chat"><small style="color:#999">[DEBUG] ' +
                    BattleLog.escapeHTML(args[1]) +
                    ".</small></div>";
                break;

            case "notify":
                var title = args[1];
                var body = args[2];
                var roomid =
                    (_this$scene3 = this.scene) == null
                        ? void 0
                        : _this$scene3.battle.roomid;
                if (!roomid) break;
                app.rooms[roomid].notifyOnce(title, body, "highlight");
                break;

            case "seed":
            case "choice":
            case ":":
            case "timer":
            case "t:":
            case "J":
            case "L":
            case "N":
            case "spectator":
            case "spectatorleave":
            case "initdone":
                return;

            default:
                this.addBattleMessage(args, kwArgs);
                return;
        }
        if (divHTML) this.addDiv(divClass, divHTML, preempt);
    };
    _proto.addBattleMessage = function addBattleMessage(args, kwArgs) {
        switch (args[0]) {
            case "warning":
                this.message(
                    "<strong>Warning:</strong> " + BattleLog.escapeHTML(args[1])
                );
                this.message(
                    'Bug? Report it to <a href="http://www.smogon.com/forums/showthread.php?t=3453192">the replay viewer\'s Smogon thread</a>'
                );
                if (this.scene) this.scene.wait(1000);
                return;

            case "variation":
                this.addDiv(
                    "",
                    "<small>Variation: <em>" +
                        BattleLog.escapeHTML(args[1]) +
                        "</em></small>"
                );
                break;

            case "rule":
                var ruleArgs = args[1].split(": ");
                this.addDiv(
                    "",
                    "<small><em>" +
                        BattleLog.escapeHTML(ruleArgs[0]) +
                        (ruleArgs[1] ? ":" : "") +
                        "</em> " +
                        BattleLog.escapeHTML(ruleArgs[1] || "") +
                        "</small>"
                );
                break;

            case "rated":
                this.addDiv(
                    "rated",
                    "<strong>" +
                        (BattleLog.escapeHTML(args[1]) || "Rated battle") +
                        "</strong>"
                );
                break;

            case "tier":
                this.addDiv(
                    "",
                    "<small>Format:</small> <br /><strong>" +
                        BattleLog.escapeHTML(args[1]) +
                        "</strong>"
                );
                break;

            case "turn":
                var h2elem = document.createElement("h2");
                h2elem.className = "battle-history";
                var turnMessage;
                if (this.battleParser) {
                    turnMessage = this.battleParser.parseArgs(args, {}).trim();
                    if (
                        !turnMessage.startsWith("==") ||
                        !turnMessage.endsWith("==")
                    ) {
                        throw new Error("Turn message must be a heading.");
                    }
                    turnMessage = turnMessage.slice(2, -2).trim();
                    this.battleParser.curLineSection = "break";
                } else {
                    turnMessage = "Turn " + args[1];
                }
                h2elem.innerHTML = BattleLog.escapeHTML(turnMessage);
                this.addSpacer();
                this.addNode(h2elem);
                break;

            default:
                var line = null;
                if (this.battleParser) {
                    line = this.battleParser.parseArgs(
                        args,
                        kwArgs || {},
                        true
                    );
                }
                if (line === null) {
                    this.addDiv(
                        "chat message-error",
                        "Unrecognized: |" + BattleLog.escapeHTML(args.join("|"))
                    );
                    return;
                }
                if (!line) return;
                this.message.apply(this, this.parseLogMessage(line));
                break;
        }
    };
    _proto.textList = function textList(list) {
        var message = "";
        var listNoDuplicates = [];
        for (var _i2 = 0, _list2 = list; _i2 < _list2.length; _i2++) {
            var user = _list2[_i2];
            if (!listNoDuplicates.includes(user)) listNoDuplicates.push(user);
        }
        list = listNoDuplicates;

        if (list.length === 1) return list[0];
        if (list.length === 2) return list[0] + " and " + list[1];
        for (var i = 0; i < list.length - 1; i++) {
            if (i >= 5) {
                return message + "and " + (list.length - 5) + " others";
            }
            message += list[i] + ", ";
        }
        return message + "and " + list[list.length - 1];
        return message;
    };
    _proto.parseLogMessage = function parseLogMessage(message) {
        var messages = message.split("\n").map(function (line) {
            line = BattleLog.escapeHTML(line);
            line = line.replace(/\*\*(.*)\*\*/, "<strong>$1</strong>");
            line = line.replace(
                /\|\|([^\|]*)\|\|([^\|]*)\|\|/,
                '<abbr title="$1">$2</abbr>'
            );
            if (line.startsWith("  "))
                line = "<small>" + line.trim() + "</small>";
            return line;
        });
        return [
            messages.join("<br />"),
            messages
                .filter(function (line) {
                    return !line.startsWith("<small>[");
                })
                .join("<br />"),
        ];
    };
    _proto.message = function message(_message) {
        var sceneMessage =
            arguments.length > 1 && arguments[1] !== undefined
                ? arguments[1]
                : _message;
        if (this.scene) this.scene.message(sceneMessage);
        this.addDiv("battle-history", _message);
    };
    _proto.addNode = function addNode(node, preempt) {
        (preempt ? this.preemptElem : this.innerElem).appendChild(node);
        if (this.atBottom) {
            this.elem.scrollTop = this.elem.scrollHeight;
        }
    };
    _proto.updateScroll = function updateScroll() {
        if (this.atBottom) {
            this.elem.scrollTop = this.elem.scrollHeight;
        }
    };
    _proto.addDiv = function addDiv(className, innerHTML, preempt) {
        var el = document.createElement("div");
        el.className = className;
        el.innerHTML = innerHTML;
        this.addNode(el, preempt);
    };
    _proto.prependDiv = function prependDiv(className, innerHTML, preempt) {
        var el = document.createElement("div");
        el.className = className;
        el.innerHTML = innerHTML;
        if (this.innerElem.childNodes.length) {
            this.innerElem.insertBefore(el, this.innerElem.childNodes[0]);
        } else {
            this.innerElem.appendChild(el);
        }
        this.updateScroll();
    };
    _proto.addSpacer = function addSpacer() {
        this.addDiv("spacer battle-history", "<br />");
    };
    _proto.changeUhtml = function changeUhtml(id, htmlSrc, forceAdd) {
        id = toID(id);
        var classContains = " uhtml-" + id + " ";
        var elements = [];
        for (
            var _i4 = 0, _ref2 = this.innerElem.childNodes;
            _i4 < _ref2.length;
            _i4++
        ) {
            var node = _ref2[_i4];
            if (
                node.className &&
                (" " + node.className + " ").includes(classContains)
            ) {
                elements.push(node);
            }
        }
        if (this.preemptElem) {
            for (
                var _i6 = 0, _ref4 = this.preemptElem.childNodes;
                _i6 < _ref4.length;
                _i6++
            ) {
                var _node = _ref4[_i6];
                if (
                    _node.className &&
                    (" " + _node.className + " ").includes(classContains)
                ) {
                    elements.push(_node);
                }
            }
        }
        if (htmlSrc && elements.length && !forceAdd) {
            for (var _i8 = 0; _i8 < elements.length; _i8++) {
                var element = elements[_i8];
                element.innerHTML = BattleLog.sanitizeHTML(htmlSrc);
            }
            this.updateScroll();
            return;
        }
        for (var _i10 = 0; _i10 < elements.length; _i10++) {
            var _element = elements[_i10];
            _element.parentElement.removeChild(_element);
        }
        if (!htmlSrc) return;
        if (forceAdd) {
            this.addDiv("notice uhtml-" + id, BattleLog.sanitizeHTML(htmlSrc));
        } else {
            this.prependDiv(
                "notice uhtml-" + id,
                BattleLog.sanitizeHTML(htmlSrc)
            );
        }
    };
    _proto.hideChatFrom = function hideChatFrom(userid) {
        var showRevealButton =
            arguments.length > 1 && arguments[1] !== undefined
                ? arguments[1]
                : true;
        var lineCount =
            arguments.length > 2 && arguments[2] !== undefined
                ? arguments[2]
                : 0;
        var classStart = "chat chatmessage-" + userid + " ";
        var nodes = [];
        for (
            var _i12 = 0, _ref6 = this.innerElem.childNodes;
            _i12 < _ref6.length;
            _i12++
        ) {
            var node = _ref6[_i12];
            if (
                node.className &&
                (node.className + " ").startsWith(classStart)
            ) {
                nodes.push(node);
            }
        }
        if (this.preemptElem) {
            for (
                var _i14 = 0, _ref8 = this.preemptElem.childNodes;
                _i14 < _ref8.length;
                _i14++
            ) {
                var _node2 = _ref8[_i14];
                if (
                    _node2.className &&
                    (_node2.className + " ").startsWith(classStart)
                ) {
                    nodes.push(_node2);
                }
            }
        }
        if (lineCount) nodes = nodes.slice(-lineCount);
        for (var _i16 = 0, _nodes2 = nodes; _i16 < _nodes2.length; _i16++) {
            var _node3 = _nodes2[_i16];
            _node3.style.display = "none";
            _node3.className = "revealed " + _node3.className;
        }
        if (!nodes.length || !showRevealButton) return;
        var button = document.createElement("button");
        button.name = "toggleMessages";
        button.value = userid;
        button.className = "subtle";
        button.innerHTML =
            "<small>(" +
            nodes.length +
            " line" +
            (nodes.length > 1 ? "s" : "") +
            " from " +
            userid +
            " hidden)</small>";
        var lastNode = nodes[nodes.length - 1];
        lastNode.appendChild(document.createTextNode(" "));
        lastNode.appendChild(button);
    };
    BattleLog.unlinkNodeList = function unlinkNodeList(nodeList, classStart) {
        for (var _i18 = 0, _ref10 = nodeList; _i18 < _ref10.length; _i18++) {
            var node = _ref10[_i18];
            if (
                node.className &&
                (node.className + " ").startsWith(classStart)
            ) {
                var linkList = node.getElementsByTagName("a");

                for (var i = linkList.length - 1; i >= 0; i--) {
                    var linkNode = linkList[i];
                    var parent = linkNode.parentElement;
                    if (!parent) continue;
                    for (
                        var _i20 = 0, _ref12 = linkNode.childNodes;
                        _i20 < _ref12.length;
                        _i20++
                    ) {
                        var childNode = _ref12[_i20];
                        parent.insertBefore(childNode, linkNode);
                    }
                    parent.removeChild(linkNode);
                }
            }
        }
    };
    _proto.unlinkChatFrom = function unlinkChatFrom(userid) {
        var classStart = "chat chatmessage-" + userid + " ";
        var innerNodeList = this.innerElem.childNodes;
        BattleLog.unlinkNodeList(innerNodeList, classStart);

        if (this.preemptElem) {
            var preemptNodeList = this.preemptElem.childNodes;
            BattleLog.unlinkNodeList(preemptNodeList, classStart);
        }
    };
    _proto.preemptCatchup = function preemptCatchup() {
        if (!this.preemptElem.firstChild) return;
        this.innerElem.appendChild(this.preemptElem.firstChild);
    };
    BattleLog.escapeFormat = function escapeFormat(formatid) {
        var atIndex = formatid.indexOf("@@@");
        if (atIndex >= 0) {
            return (
                this.escapeFormat(formatid.slice(0, atIndex)) +
                "<br />Custom rules: " +
                this.escapeHTML(formatid.slice(atIndex + 3))
            );
        }
        if (window.BattleFormats && BattleFormats[formatid]) {
            return this.escapeHTML(BattleFormats[formatid].name);
        }
        if (window.NonBattleGames && NonBattleGames[formatid]) {
            return this.escapeHTML(NonBattleGames[formatid]);
        }
        return this.escapeHTML(formatid);
    };
    BattleLog.escapeHTML = function escapeHTML(str, jsEscapeToo) {
        if (typeof str !== "string") return "";
        str = str
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;");
        if (jsEscapeToo) str = str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
        return str;
    };
    BattleLog.unescapeHTML = function unescapeHTML(str) {
        str = str ? "" + str : "";
        return str
            .replace(/&quot;/g, '"')
            .replace(/&gt;/g, ">")
            .replace(/&lt;/g, "<")
            .replace(/&amp;/g, "&");
    };
    BattleLog.hashColor = function hashColor(name) {
        return "color:" + this.usernameColor(name) + ";";
    };
    BattleLog.usernameColor = function usernameColor(name) {
        if (this.colorCache[name]) return this.colorCache[name];
        var hash;
        if (Config.customcolors[name]) {
            hash = MD5(Config.customcolors[name]);
        } else {
            hash = MD5(name);
        }
        var H = parseInt(hash.substr(4, 4), 16) % 360;
        var S = (parseInt(hash.substr(0, 4), 16) % 50) + 40;
        var L = Math.floor((parseInt(hash.substr(8, 4), 16) % 20) + 30);

        var _this$HSLToRGB = this.HSLToRGB(H, S, L),
            R = _this$HSLToRGB.R,
            G = _this$HSLToRGB.G,
            B = _this$HSLToRGB.B;
        var lum = R * R * R * 0.2126 + G * G * G * 0.7152 + B * B * B * 0.0722;

        var HLmod = (lum - 0.2) * -150;
        if (HLmod > 18) HLmod = (HLmod - 18) * 2.5;
        else if (HLmod < 0) HLmod = (HLmod - 0) / 3;
        else HLmod = 0;

        var Hdist = Math.min(Math.abs(180 - H), Math.abs(240 - H));
        if (Hdist < 15) {
            HLmod += (15 - Hdist) / 3;
        }

        L += HLmod;

        var _this$HSLToRGB2 = this.HSLToRGB(H, S, L),
            r = _this$HSLToRGB2.R,
            g = _this$HSLToRGB2.G,
            b = _this$HSLToRGB2.B;
        var toHex = function (x) {
            var hex = Math.round(x * 255).toString(16);
            return hex.length === 1 ? "0" + hex : hex;
        };
        this.colorCache[name] = "#" + toHex(r) + toHex(g) + toHex(b);
        return this.colorCache[name];
    };
    BattleLog.HSLToRGB = function HSLToRGB(H, S, L) {
        var C = ((100 - Math.abs(2 * L - 100)) * S) / 100 / 100;
        var X = C * (1 - Math.abs(((H / 60) % 2) - 1));
        var m = L / 100 - C / 2;

        var R1;
        var G1;
        var B1;
        switch (Math.floor(H / 60)) {
            case 1:
                R1 = X;
                G1 = C;
                B1 = 0;
                break;
            case 2:
                R1 = 0;
                G1 = C;
                B1 = X;
                break;
            case 3:
                R1 = 0;
                G1 = X;
                B1 = C;
                break;
            case 4:
                R1 = X;
                G1 = 0;
                B1 = C;
                break;
            case 5:
                R1 = C;
                G1 = 0;
                B1 = X;
                break;
            case 0:
            default:
                R1 = C;
                G1 = X;
                B1 = 0;
                break;
        }
        var R = R1 + m;
        var G = G1 + m;
        var B = B1 + m;
        return { R: R, G: G, B: B };
    };
    BattleLog.prefs = function prefs(name) {
        var _window$Storage;

        if ((_window$Storage = window.Storage) != null && _window$Storage.prefs)
            return Storage.prefs(name);

        if (window.PS) return PS.prefs[name];
        return undefined;
    };
    _proto.parseChatMessage = function parseChatMessage(
        message,
        name,
        timestamp,
        isHighlighted
    ) {
        var _BattleLog$prefs, _window$app3, _window$app3$user, _window$PS;
        var showMe = !(
            (_BattleLog$prefs = BattleLog.prefs("chatformatting")) != null &&
            _BattleLog$prefs.hideme
        );
        var group = " ";
        if (!/[A-Za-z0-9]/.test(name.charAt(0))) {
            group = name.charAt(0);
            name = name.substr(1);
        }
        var colorStyle =
            ' style="color:' + BattleLog.usernameColor(toID(name)) + '"';
        var clickableName =
            "<small>" +
            BattleLog.escapeHTML(group) +
            '</small><span class="username" data-name="' +
            BattleLog.escapeHTML(name) +
            '">' +
            BattleLog.escapeHTML(name) +
            "</span>";
        var hlClass = isHighlighted ? " highlighted" : "";
        var isMine =
            ((_window$app3 = window.app) == null
                ? void 0
                : (_window$app3$user = _window$app3.user) == null
                ? void 0
                : _window$app3$user.get("name")) === name ||
            ((_window$PS = window.PS) == null
                ? void 0
                : _window$PS.user.name) === name;
        var mineClass = isMine ? " mine" : "";

        var cmd = "";
        var target = "";
        if (message.charAt(0) === "/") {
            if (message.charAt(1) === "/") {
                message = message.slice(1);
            } else {
                var spaceIndex = message.indexOf(" ");
                cmd =
                    spaceIndex >= 0
                        ? message.slice(1, spaceIndex)
                        : message.slice(1);
                if (spaceIndex >= 0) target = message.slice(spaceIndex + 1);
            }
        }

        switch (cmd) {
            case "me":
            case "mee":
                var parsedMessage = BattleLog.parseMessage(" " + target);
                if (cmd === "mee") parsedMessage = parsedMessage.slice(1);
                if (!showMe) {
                    return [
                        "chat chatmessage-" + toID(name) + hlClass + mineClass,
                        timestamp +
                            "<strong" +
                            colorStyle +
                            ">" +
                            clickableName +
                            ":</strong> <em>/me" +
                            parsedMessage +
                            "</em>",
                    ];
                }
                return [
                    "chat chatmessage-" + toID(name) + hlClass + mineClass,
                    timestamp +
                        "<em><i><strong" +
                        colorStyle +
                        ">&bull; " +
                        clickableName +
                        "</strong>" +
                        parsedMessage +
                        "</i></em>",
                ];

            case "invite":
                var roomid = toRoomid(target);
                return [
                    "chat",
                    timestamp +
                        "<em>" +
                        clickableName +
                        ' invited you to join the room "' +
                        roomid +
                        '"</em>\' +\n\t\t\t\t\'<div class="notice"><button name="joinRoom" value="' +
                        roomid +
                        '">Join ' +
                        roomid +
                        "</button></div>",
                ];

            case "announce":
                return [
                    "chat chatmessage-" + toID(name) + hlClass + mineClass,
                    timestamp +
                        "<strong" +
                        colorStyle +
                        ">" +
                        clickableName +
                        ':</strong> <span class="message-announce">' +
                        BattleLog.parseMessage(target) +
                        "</span>",
                ];

            case "log":
                return [
                    "chat chatmessage-" + toID(name) + hlClass + mineClass,
                    timestamp +
                        '<span class="message-log">' +
                        BattleLog.parseMessage(target) +
                        "</span>",
                ];

            case "data-pokemon":
            case "data-item":
            case "data-ability":
            case "data-move":
                return [
                    "chat message-error",
                    "[outdated code no longer supported]",
                ];
            case "text":
                return ["chat", BattleLog.parseMessage(target)];
            case "error":
                return ["chat message-error", formatText(target, true)];
            case "html":
                return [
                    "chat chatmessage-" + toID(name) + hlClass + mineClass,
                    timestamp +
                        "<strong" +
                        colorStyle +
                        ">" +
                        clickableName +
                        ":</strong> <em>" +
                        BattleLog.sanitizeHTML(target) +
                        "</em>",
                ];

            case "uhtml":
            case "uhtmlchange":
                var parts = target.split(",");
                var htmlSrc = parts.slice(1).join(",").trim();
                this.changeUhtml(parts[0], htmlSrc, cmd === "uhtml");
                return ["", ""];
            case "raw":
                return ["chat", BattleLog.sanitizeHTML(target)];
            case "nonotify":
                return ["chat", BattleLog.sanitizeHTML(target), true];
            default:
                if (!name) {
                    return [
                        "chat" + hlClass,
                        timestamp +
                            "<em>" +
                            BattleLog.parseMessage(message) +
                            "</em>",
                    ];
                }
                return [
                    "chat chatmessage-" + toID(name) + hlClass + mineClass,
                    timestamp +
                        "<strong" +
                        colorStyle +
                        ">" +
                        clickableName +
                        ":</strong> <em>" +
                        BattleLog.parseMessage(message) +
                        "</em>",
                ];
        }
    };
    BattleLog.parseMessage = function parseMessage(str) {
        var isTrusted =
            arguments.length > 1 && arguments[1] !== undefined
                ? arguments[1]
                : false;

        if (str.substr(0, 3) === ">> " || str.substr(0, 4) === ">>> ")
            return this.escapeHTML(str);

        if (str.substr(0, 3) === "<< ") return this.escapeHTML(str);
        str = formatText(str, isTrusted);

        var options = BattleLog.prefs("chatformatting") || {};

        if (options.hidelinks) {
            str = str.replace(/<a[^>]*>/g, "<u>").replace(/<\/a>/g, "</u>");
        }
        if (options.hidespoiler) {
            str = str.replace(
                /<span class="spoiler">/g,
                '<span class="spoiler spoiler-shown">'
            );
        }
        if (options.hidegreentext) {
            str = str.replace(/<span class="greentext">/g, "<span>");
        }

        return str;
    };
    BattleLog.initSanitizeHTML = function initSanitizeHTML() {
        var _this3 = this;
        if (this.tagPolicy) return;
        if (!("html4" in window)) {
            throw new Error("sanitizeHTML requires caja");
        }

        Object.assign(html4.ELEMENTS, {
            marquee: 0,
            blink: 0,
            psicon: html4.eflags["OPTIONAL_ENDTAG"] | html4.eflags["EMPTY"],
            username: 0,
            spotify: 0,
            youtube: 0,
            twitch: 0,
        });

        Object.assign(html4.ATTRIBS, {
            "marquee::behavior": 0,
            "marquee::bgcolor": 0,
            "marquee::direction": 0,
            "marquee::height": 0,
            "marquee::hspace": 0,
            "marquee::loop": 0,
            "marquee::scrollamount": 0,
            "marquee::scrolldelay": 0,
            "marquee::truespeed": 0,
            "marquee::vspace": 0,
            "marquee::width": 0,
            "psicon::pokemon": 0,
            "psicon::item": 0,
            "psicon::type": 0,
            "psicon::category": 0,
            "username::name": 0,
            "form::data-submitsend": 0,
            "div::data-server": 0,
            "button::data-send": 0,
            "form::data-delimiter": 0,
            "button::data-delimiter": 0,
            "*::aria-label": 0,
            "*::aria-hidden": 0,
        });

        this.tagPolicy = function (tagName, attribs) {
            if (html4.ELEMENTS[tagName] & html4.eflags["UNSAFE"]) {
                return;
            }

            function getAttrib(key) {
                for (var i = 0; i < attribs.length - 1; i += 2) {
                    if (attribs[i] === key) {
                        return attribs[i + 1];
                    }
                }
                return undefined;
            }
            function setAttrib(key, value) {
                for (var i = 0; i < attribs.length - 1; i += 2) {
                    if (attribs[i] === key) {
                        attribs[i + 1] = value;
                        return;
                    }
                }
                attribs.push(key, value);
            }
            function deleteAttrib(key) {
                for (var i = 0; i < attribs.length - 1; i += 2) {
                    if (attribs[i] === key) {
                        attribs.splice(i, 2);
                        return;
                    }
                }
            }

            var dataUri = "";
            var targetReplace = false;

            if (tagName === "a") {
                if (getAttrib("target") === "replace") {
                    targetReplace = true;
                }
            } else if (tagName === "img") {
                var src = getAttrib("src") || "";
                if (src.startsWith("data:image/")) {
                    dataUri = src;
                }
                if (src.startsWith("//")) {
                    if (
                        location.protocol !== "http:" &&
                        location.protocol !== "https:"
                    ) {
                        setAttrib("src", "https:" + src);
                    }
                }
            } else if (tagName === "twitch") {
                var _exec;

                var _src = getAttrib("src") || "";
                var channelId =
                    (_exec = /(https?:\/\/)?twitch.tv\/([A-Za-z0-9]+)/i.exec(
                        _src
                    )) == null
                        ? void 0
                        : _exec[2];
                var height = parseInt(getAttrib("height") || "", 10) || 400;
                var width = parseInt(getAttrib("width") || "", 10) || 340;
                return {
                    tagName: "iframe",
                    attribs: [
                        "src",
                        "https://player.twitch.tv/?channel=" +
                            channelId +
                            "&parent=" +
                            location.hostname +
                            "&autoplay=false",
                        "allowfullscreen",
                        "true",
                        "height",
                        "" + height,
                        "width",
                        "" + width,
                    ],
                };
            } else if (tagName === "username") {
                tagName = "strong";
                var color = _this3.usernameColor(toID(getAttrib("name")));
                var style = getAttrib("style");
                setAttrib("style", style + ";color:" + color);
            } else if (tagName === "spotify") {
                var _exec2;

                var _src2 = getAttrib("src") || "";
                var songId =
                    (_exec2 = /(?:\?v=|\/track\/)([A-Za-z0-9]+)/.exec(_src2)) ==
                    null
                        ? void 0
                        : _exec2[1];

                return {
                    tagName: "iframe",
                    attribs: [
                        "src",
                        "https://open.spotify.com/embed/track/" + songId,
                        "width",
                        "300",
                        "height",
                        "380",
                        "frameborder",
                        "0",
                        "allowtransparency",
                        "true",
                        "allow",
                        "encrypted-media",
                    ],
                };
            } else if (tagName === "youtube") {
                var _exec3, _exec4;

                var _src3 = getAttrib("src") || "";

                var _width = "320";
                var _height = "200";
                if (window.innerWidth >= 400) {
                    _width = "400";
                    _height = "225";
                }
                var videoId =
                    (_exec3 = /(?:\?v=|\/embed\/)([A-Za-z0-9_\-]+)/.exec(
                        _src3
                    )) == null
                        ? void 0
                        : _exec3[1];
                if (!videoId)
                    return {
                        tagName: "img",
                        attribs: ["alt", "invalid src for <youtube>"],
                    };

                var time =
                    (_exec4 = /(?:\?|&)(?:t|start)=([0-9]+)/.exec(_src3)) ==
                    null
                        ? void 0
                        : _exec4[1];
                _this3.players.push(null);
                var idx = _this3.players.length;
                _this3.initYoutubePlayer(idx);
                return {
                    tagName: "iframe",
                    attribs: [
                        "id",
                        "youtube-iframe-" + idx,
                        "width",
                        _width,
                        "height",
                        _height,
                        "src",
                        "https://www.youtube.com/embed/" +
                            videoId +
                            "?enablejsapi=1&playsinline=1" +
                            (time ? "&start=" + time : ""),
                        "frameborder",
                        "0",
                        "allow",
                        "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",
                        "allowfullscreen",
                        "allowfullscreen",
                    ],
                };
            } else if (tagName === "psicon") {
                var iconType = null;
                var iconValue = null;
                for (var i = 0; i < attribs.length - 1; i += 2) {
                    if (
                        attribs[i] === "pokemon" ||
                        attribs[i] === "item" ||
                        attribs[i] === "type" ||
                        attribs[i] === "category"
                    ) {
                        var _attribs$slice = attribs.slice(i, i + 2);
                        iconType = _attribs$slice[0];
                        iconValue = _attribs$slice[1];
                        break;
                    }
                }
                tagName = "span";

                if (iconType) {
                    var className = getAttrib("class");
                    var _style = getAttrib("style");

                    if (iconType === "pokemon") {
                        setAttrib(
                            "class",
                            "picon" + (className ? " " + className : "")
                        );
                        setAttrib(
                            "style",
                            Dex.getPokemonIcon(iconValue) +
                                (_style ? "; " + _style : "")
                        );
                    } else if (iconType === "item") {
                        setAttrib(
                            "class",
                            "itemicon" + (className ? " " + className : "")
                        );
                        setAttrib(
                            "style",
                            Dex.getItemIcon(iconValue) +
                                (_style ? "; " + _style : "")
                        );
                    } else if (iconType === "type") {
                        tagName = Dex.getTypeIcon(iconValue).slice(1, -3);
                    } else if (iconType === "category") {
                        tagName = Dex.getCategoryIcon(iconValue).slice(1, -3);
                    }
                }
            }

            attribs = html.sanitizeAttribs(
                tagName,
                attribs,
                function (urlData) {
                    if (
                        urlData.scheme_ === "geo" ||
                        urlData.scheme_ === "sms" ||
                        urlData.scheme_ === "tel"
                    )
                        return null;
                    return urlData;
                }
            );

            if (dataUri && tagName === "img") {
                setAttrib("src", dataUri);
            }
            if (
                tagName === "a" ||
                (tagName === "form" && !getAttrib("data-submitsend"))
            ) {
                if (targetReplace) {
                    setAttrib("data-target", "replace");
                    deleteAttrib("target");
                } else {
                    setAttrib("target", "_blank");
                }
                if (tagName === "a") {
                    setAttrib("rel", "noopener");
                }
            }
            return { tagName: tagName, attribs: attribs };
        };
    };
    BattleLog.localizeTime = function localizeTime(full, date, time, timezone) {
        var _Intl;
        var parsedTime = new Date(
            date + "T" + time + (timezone || "Z").toUpperCase()
        );

        if (!parsedTime.getTime()) return full;

        var formattedTime;

        if ((_Intl = window.Intl) != null && _Intl.DateTimeFormat) {
            formattedTime = new Intl.DateTimeFormat(undefined, {
                month: "long",
                day: "numeric",
                hour: "numeric",
                minute: "numeric",
            }).format(parsedTime);
        } else {
            formattedTime = parsedTime.toLocaleString();
        }
        return "<time>" + BattleLog.escapeHTML(formattedTime) + "</time>";
    };
    BattleLog.sanitizeHTML = function sanitizeHTML(input) {
        if (typeof input !== "string") return "";

        this.initSanitizeHTML();

        input = input.replace(
            /<username([^>]*)>([^<]*)<\/username>/gi,
            function (match, attrs, username) {
                if (/\bname\s*=\s*"/.test(attrs)) return match;
                var escapedUsername = username
                    .replace(/"/g, "&quot;")
                    .replace(/>/g, "&gt;");
                return (
                    "<username" +
                    attrs +
                    ' name="' +
                    escapedUsername +
                    '">' +
                    username +
                    "</username>"
                );
            }
        );

        var sanitized = html.sanitizeWithPolicy(input, this.tagPolicy);

        return sanitized.replace(
            /<time>\s*([+-]?\d{4,}-\d{2}-\d{2})[T ](\d{2}:\d{2}(?::\d{2}(?:\.\d{3})?)?)(Z|[+-]\d{2}:\d{2})?\s*<\/time>/gi,
            this.localizeTime
        );
    };
    BattleLog.initYoutubePlayer = function initYoutubePlayer(idx) {
        var _this4 = this;
        var id = "youtube-iframe-" + idx;
        var loadPlayer = function () {
            if (!$("#" + id).length) return;
            var player = new window.YT.Player(id, {
                events: {
                    onStateChange: function (event) {
                        if (event.data === window.YT.PlayerState.PLAYING) {
                            for (
                                var _i22 = 0,
                                    _BattleLog$players2 = BattleLog.players;
                                _i22 < _BattleLog$players2.length;
                                _i22++
                            ) {
                                var curPlayer = _BattleLog$players2[_i22];
                                if (player === curPlayer) continue;
                                curPlayer == null
                                    ? void 0
                                    : curPlayer.pauseVideo == null
                                    ? void 0
                                    : curPlayer.pauseVideo();
                            }
                        }
                    },
                },
            });
            _this4.players[idx - 1] = player;
        };

        this.ensureYoutube().then(function () {
            setTimeout(function () {
                return loadPlayer();
            }, 300);
        });
    };
    BattleLog.ensureYoutube = function ensureYoutube() {
        if (this.ytLoading) return this.ytLoading;

        this.ytLoading = new Promise(function (resolve) {
            var el = document.createElement("script");
            el.type = "text/javascript";
            el.async = true;
            el.src = "https://youtube.com/iframe_api";
            el.onload = function () {
                var loopCheck = function () {
                    var _window$YT;
                    if (
                        !((_window$YT = window.YT) != null && _window$YT.Player)
                    ) {
                        setTimeout(function () {
                            return loopCheck();
                        }, 300);
                    } else {
                        resolve();
                    }
                };
                loopCheck();
            };
            document.body.appendChild(el);
        });
        return this.ytLoading;
    };
    BattleLog.createReplayFile = function createReplayFile(room) {
        var battle = room.battle;
        var replayid = room.id;
        if (replayid) {
            replayid = replayid.slice(7);
            if (Config.server.id !== "showdown") {
                if (!Config.server.registered) {
                    replayid = "unregisteredserver-" + replayid;
                } else {
                    replayid = Config.server.id + "-" + replayid;
                }
            }
        } else {
            replayid = room.fragment;
        }
        battle.seekTurn(Infinity);
        var buf = "<!DOCTYPE html>\n";
        buf += '<meta charset="utf-8" />\n';
        buf += "<!-- version 1 -->\n";
        buf +=
            "<title>" +
            BattleLog.escapeHTML(battle.tier) +
            " replay: " +
            BattleLog.escapeHTML(battle.p1.name) +
            " vs. " +
            BattleLog.escapeHTML(battle.p2.name) +
            "</title>\n";
        buf += "<style>\n";
        buf +=
            "html,body {font-family:Verdana, sans-serif;font-size:10pt;margin:0;padding:0;}body{padding:12px 0;} .battle-log {font-family:Verdana, sans-serif;font-size:10pt;} .battle-log-inline {border:1px solid #AAAAAA;background:#EEF2F5;color:black;max-width:640px;margin:0 auto 80px;padding-bottom:5px;} .battle-log .inner {padding:4px 8px 0px 8px;} .battle-log .inner-preempt {padding:0 8px 4px 8px;} .battle-log .inner-after {margin-top:0.5em;} .battle-log h2 {margin:0.5em -8px;padding:4px 8px;border:1px solid #AAAAAA;background:#E0E7EA;border-left:0;border-right:0;font-family:Verdana, sans-serif;font-size:13pt;} .battle-log .chat {vertical-align:middle;padding:3px 0 3px 0;font-size:8pt;} .battle-log .chat strong {color:#40576A;} .battle-log .chat em {padding:1px 4px 1px 3px;color:#000000;font-style:normal;} .chat.mine {background:rgba(0,0,0,0.05);margin-left:-8px;margin-right:-8px;padding-left:8px;padding-right:8px;} .spoiler {color:#BBBBBB;background:#BBBBBB;padding:0px 3px;} .spoiler:hover, .spoiler:active, .spoiler-shown {color:#000000;background:#E2E2E2;padding:0px 3px;} .spoiler a {color:#BBBBBB;} .spoiler:hover a, .spoiler:active a, .spoiler-shown a {color:#2288CC;} .chat code, .chat .spoiler:hover code, .chat .spoiler:active code, .chat .spoiler-shown code {border:1px solid #C0C0C0;background:#EEEEEE;color:black;padding:0 2px;} .chat .spoiler code {border:1px solid #CCCCCC;background:#CCCCCC;color:#CCCCCC;} .battle-log .rated {padding:3px 4px;} .battle-log .rated strong {color:white;background:#89A;padding:1px 4px;border-radius:4px;} .spacer {margin-top:0.5em;} .message-announce {background:#6688AA;color:white;padding:1px 4px 2px;} .message-announce a, .broadcast-green a, .broadcast-blue a, .broadcast-red a {color:#DDEEFF;} .broadcast-green {background-color:#559955;color:white;padding:2px 4px;} .broadcast-blue {background-color:#6688AA;color:white;padding:2px 4px;} .infobox {border:1px solid #6688AA;padding:2px 4px;} .infobox-limited {max-height:200px;overflow:auto;overflow-x:hidden;} .broadcast-red {background-color:#AA5544;color:white;padding:2px 4px;} .message-learn-canlearn {font-weight:bold;color:#228822;text-decoration:underline;} .message-learn-cannotlearn {font-weight:bold;color:#CC2222;text-decoration:underline;} .message-effect-weak {font-weight:bold;color:#CC2222;} .message-effect-resist {font-weight:bold;color:#6688AA;} .message-effect-immune {font-weight:bold;color:#666666;} .message-learn-list {margin-top:0;margin-bottom:0;} .message-throttle-notice, .message-error {color:#992222;} .message-overflow, .chat small.message-overflow {font-size:0pt;} .message-overflow::before {font-size:9pt;content:'...';} .subtle {color:#3A4A66;}\n";
        buf += "</style>\n";
        buf +=
            '<div class="wrapper replay-wrapper" style="max-width:1180px;margin:0 auto">\n';
        buf +=
            '<input type="hidden" name="replayid" value="' +
            replayid +
            '" />\n';
        buf +=
            '<div class="battle"></div><div class="battle-log"></div><div class="replay-controls"></div><div class="replay-controls-2"></div>\n';
        buf +=
            '<h1 style="font-weight:normal;text-align:center"><strong>' +
            BattleLog.escapeHTML(battle.tier) +
            '</strong><br /><a href="http://' +
            Config.routes.users +
            "/" +
            toID(battle.p1.name) +
            '" class="subtle" target="_blank">' +
            BattleLog.escapeHTML(battle.p1.name) +
            '</a> vs. <a href="http://' +
            Config.routes.users +
            "/" +
            toID(battle.p2.name) +
            '" class="subtle" target="_blank">' +
            BattleLog.escapeHTML(battle.p2.name) +
            "</a></h1>\n";
        buf +=
            '<script type="text/plain" class="battle-log-data">' +
            battle.stepQueue.join("\n").replace(/\//g, "\\/") +
            "</script>\n";
        buf += "</div>\n";
        buf +=
            '<div class="battle-log battle-log-inline"><div class="inner">' +
            battle.scene.log.elem.innerHTML +
            "</div></div>\n";
        buf += "</div>\n";
        buf += "<script>\n";
        buf +=
            "let daily = Math.floor(Date.now()/1000/60/60/24);document.write('<script src=\"https://" +
            Config.routes.client +
            "/js/replay-embed.js?version'+daily+'\"></'+'script>');\n";
        buf += "</script>\n";
        return buf;
    };
    BattleLog.createReplayFileHref = function createReplayFileHref(room) {
        return (
            "data:text/plain;base64," +
            encodeURIComponent(
                btoa(
                    unescape(
                        encodeURIComponent(BattleLog.createReplayFile(room))
                    )
                )
            )
        );
    };
    return BattleLog;
})();
BattleLog.colorCache = {};
BattleLog.interstice = (function () {
    var whitelist = Config.whitelist;
    var patterns = whitelist.map(function (entry) {
        return new RegExp(
            "^(https?:)?//([A-Za-z0-9-]*\\.)?" +
                entry.replace(/\./g, "\\.") +
                "(/.*)?",
            "i"
        );
    });
    return {
        isWhitelisted: function (uri) {
            if (uri[0] === "/" && uri[1] !== "/") {
                return true;
            }
            for (var _i24 = 0; _i24 < patterns.length; _i24++) {
                var pattern = patterns[_i24];
                if (pattern.test(uri)) return true;
            }
            return false;
        },
        getURI: function (uri) {
            return (
                "http://" +
                Config.routes.root +
                "/interstice?uri=" +
                encodeURIComponent(uri)
            );
        },
    };
})();
BattleLog.players = [];
BattleLog.ytLoading = null;
BattleLog.tagPolicy = null;
//# sourceMappingURL=battle-log.js.map
