Oliveboard Plus

Enhance Oliveboard UI and functionality.

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Oliveboard Plus
// @namespace    ob-enhancer
// @version      1.2.2
// @author       quantavil
// @description  Enhance Oliveboard UI and functionality.
// @license      MIT
// @match        *://*.oliveboard.in/*
// @run-at       document-start
// ==/UserScript==

(function () {
  'use strict';

  var __defProp = Object.defineProperty;
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
  const ICONS = {
    idle: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 4v12m0 0l-4-4m4 4l4-4M4 20h16"/></svg>`,
    loading: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle class="tb-sp" cx="12" cy="12" r="10" stroke-dasharray="32" stroke-linecap="round"/><path class="tb-x" d="M9 9l6 6M15 9l-6 6"/></svg>`,
    success: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path class="tb-chk" d="M5 13l4 4L19 7"/></svg>`,
    error: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>`
  };
  const STYLES = `
#tb-fab { position:fixed; bottom:24px; right:24px; width:44px; height:44px; border-radius:22px; background:#000; color:#fff; display:grid; place-items:center; cursor:pointer; transition:all .3s cubic-bezier(.25,.8,.25,1); box-shadow:0 4px 12px rgba(0,0,0,.15); z-index:99999; border:1px solid transparent; }
#tb-fab svg { width:20px; height:20px; transition:all .3s; }
#tb-fab[data-s="idle"] { opacity:0.3; }
#tb-fab[data-s="idle"]:hover { opacity:1; box-shadow:0 6px 16px rgba(0,0,0,.25); }
#tb-fab[data-s="idle"]:active { transform:scale(.92); }
#tb-fab[data-s="success"] { background:#fff; color:#000; border-color:#e5e5e5; pointer-events:none; transform:scale(1.1); }
#tb-fab[data-s="error"] { background:#fff; color:#000; border-color:#000; animation:sh .4s; }
#tb-fab::after { content:attr(data-t); position:absolute; right:56px; background:#000; color:#fff; padding:6px 12px; border-radius:6px; font:500 12px/1.2 -apple-system,sans-serif; opacity:0; pointer-events:none; transition:opacity .2s; white-space:nowrap; box-shadow:0 2px 8px rgba(0,0,0,.2); }
#tb-fab:hover::after, #tb-fab[data-s="loading"]::after, #tb-fab[data-s="error"]::after { opacity:1; }
#tb-fab[data-s="idle"]:not(:hover)::after { opacity:0; }
#tb-fab .tb-x { opacity:0; transition:opacity .2s; }
#tb-fab[data-s="loading"]:hover .tb-sp { opacity:0; }
#tb-fab[data-s="loading"]:hover .tb-x { opacity:1; }
#tb-fab[data-s="loading"]:hover::after { content:"Cancel"; }
@keyframes sh { 25%,75%{transform:translateX(-4px)} 50%{transform:translateX(4px)} }
#tb-fab .tb-chk { stroke-dasharray:24; stroke-dashoffset:24; animation:tb-draw .4s forwards .1s; }
@keyframes tb-draw { to { stroke-dashoffset:0; } }
`;
  class DownloaderUI {
    constructor(onStart, onCancel) {
      __publicField(this, "el", document.createElement("div"));
      __publicField(this, "state", "idle");
      __publicField(this, "spinRAF", null);
      __publicField(this, "timer", null);
      this.onStart = onStart;
      this.onCancel = onCancel;
      this.el.id = "tb-fab";
      this.el.onclick = () => {
        if (this.state === "idle" || this.state === "error") {
          this.setState("loading");
          return this.onStart();
        }
        if (this.state === "loading") {
          this.setState("idle");
          return this.onCancel();
        }
      };
      this.setState("idle");
    }
    startSpin() {
      const el = this.el.querySelector(".tb-sp");
      if (!el) return;
      let last = null;
      let angle = 0;
      const tick = (now) => {
        if (last !== null) angle = (angle + (now - last) * 0.36) % 360;
        last = now;
        el.setAttribute("transform", `rotate(${angle} 12 12)`);
        this.spinRAF = requestAnimationFrame(tick);
      };
      this.spinRAF = requestAnimationFrame(tick);
    }
    stopSpin() {
      if (this.spinRAF !== null) {
        cancelAnimationFrame(this.spinRAF);
        this.spinRAF = null;
      }
    }
    setState(s) {
      this.stopSpin();
      if (this.timer) {
        clearTimeout(this.timer);
        this.timer = null;
      }
      this.state = s;
      this.el.dataset.s = s;
      this.el.innerHTML = ICONS[s];
      this.el.dataset.t = { idle: "Download", loading: "Crawling…", success: "Done!", error: "Failed — retry" }[s];
      if (s === "loading") this.startSpin();
    }
    mount() {
      if (!document.getElementById("tb-css")) {
        document.head.insertAdjacentHTML("beforeend", `<style id="tb-css">${STYLES}</style>`);
      }
      document.body.appendChild(this.el);
    }
    updateStatus(m) {
      if (this.state === "loading") this.el.dataset.t = m;
    }
    error(m) {
      this.setState("error");
      if (m) this.el.dataset.t = `Error: ${m}`;
      this.timer = window.setTimeout(() => {
        if (this.state === "error") this.setState("idle");
        this.timer = null;
      }, 5e3);
    }
    finish() {
      this.setState("success");
      this.timer = window.setTimeout(() => {
        if (this.state === "success") this.setState("idle");
        this.timer = null;
      }, 2500);
    }
  }
  function extend(destination) {
    for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i];
      for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) destination[key] = source[key];
      }
    }
    return destination;
  }
  function repeat(character, count) {
    return Array(count + 1).join(character);
  }
  function trimLeadingNewlines(string) {
    return string.replace(/^\n*/, "");
  }
  function trimTrailingNewlines(string) {
    var indexEnd = string.length;
    while (indexEnd > 0 && string[indexEnd - 1] === "\n") indexEnd--;
    return string.substring(0, indexEnd);
  }
  function trimNewlines(string) {
    return trimTrailingNewlines(trimLeadingNewlines(string));
  }
  var blockElements = ["ADDRESS", "ARTICLE", "ASIDE", "AUDIO", "BLOCKQUOTE", "BODY", "CANVAS", "CENTER", "DD", "DIR", "DIV", "DL", "DT", "FIELDSET", "FIGCAPTION", "FIGURE", "FOOTER", "FORM", "FRAMESET", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER", "HGROUP", "HR", "HTML", "ISINDEX", "LI", "MAIN", "MENU", "NAV", "NOFRAMES", "NOSCRIPT", "OL", "OUTPUT", "P", "PRE", "SECTION", "TABLE", "TBODY", "TD", "TFOOT", "TH", "THEAD", "TR", "UL"];
  function isBlock(node) {
    return is(node, blockElements);
  }
  var voidElements = ["AREA", "BASE", "BR", "COL", "COMMAND", "EMBED", "HR", "IMG", "INPUT", "KEYGEN", "LINK", "META", "PARAM", "SOURCE", "TRACK", "WBR"];
  function isVoid(node) {
    return is(node, voidElements);
  }
  function hasVoid(node) {
    return has(node, voidElements);
  }
  var meaningfulWhenBlankElements = ["A", "TABLE", "THEAD", "TBODY", "TFOOT", "TH", "TD", "IFRAME", "SCRIPT", "AUDIO", "VIDEO"];
  function isMeaningfulWhenBlank(node) {
    return is(node, meaningfulWhenBlankElements);
  }
  function hasMeaningfulWhenBlank(node) {
    return has(node, meaningfulWhenBlankElements);
  }
  function is(node, tagNames) {
    return tagNames.indexOf(node.nodeName) >= 0;
  }
  function has(node, tagNames) {
    return node.getElementsByTagName && tagNames.some(function(tagName) {
      return node.getElementsByTagName(tagName).length;
    });
  }
  var markdownEscapes = [[/\\/g, "\\\\"], [/\*/g, "\\*"], [/^-/g, "\\-"], [/^\+ /g, "\\+ "], [/^(=+)/g, "\\$1"], [/^(#{1,6}) /g, "\\$1 "], [/`/g, "\\`"], [/^~~~/g, "\\~~~"], [/\[/g, "\\["], [/\]/g, "\\]"], [/^>/g, "\\>"], [/_/g, "\\_"], [/^(\d+)\. /g, "$1\\. "]];
  function escapeMarkdown(string) {
    return markdownEscapes.reduce(function(accumulator, escape) {
      return accumulator.replace(escape[0], escape[1]);
    }, string);
  }
  var rules$1 = {};
  rules$1.paragraph = {
    filter: "p",
    replacement: function(content) {
      return "\n\n" + content + "\n\n";
    }
  };
  rules$1.lineBreak = {
    filter: "br",
    replacement: function(content, node, options) {
      return options.br + "\n";
    }
  };
  rules$1.heading = {
    filter: ["h1", "h2", "h3", "h4", "h5", "h6"],
    replacement: function(content, node, options) {
      var hLevel = Number(node.nodeName.charAt(1));
      if (options.headingStyle === "setext" && hLevel < 3) {
        var underline = repeat(hLevel === 1 ? "=" : "-", content.length);
        return "\n\n" + content + "\n" + underline + "\n\n";
      } else {
        return "\n\n" + repeat("#", hLevel) + " " + content + "\n\n";
      }
    }
  };
  rules$1.blockquote = {
    filter: "blockquote",
    replacement: function(content) {
      content = trimNewlines(content).replace(/^/gm, "> ");
      return "\n\n" + content + "\n\n";
    }
  };
  rules$1.list = {
    filter: ["ul", "ol"],
    replacement: function(content, node) {
      var parent = node.parentNode;
      if (parent.nodeName === "LI" && parent.lastElementChild === node) {
        return "\n" + content;
      } else {
        return "\n\n" + content + "\n\n";
      }
    }
  };
  rules$1.listItem = {
    filter: "li",
    replacement: function(content, node, options) {
      var prefix = options.bulletListMarker + "   ";
      var parent = node.parentNode;
      if (parent.nodeName === "OL") {
        var start = parent.getAttribute("start");
        var index = Array.prototype.indexOf.call(parent.children, node);
        prefix = (start ? Number(start) + index : index + 1) + ".  ";
      }
      var isParagraph = /\n$/.test(content);
      content = trimNewlines(content) + (isParagraph ? "\n" : "");
      content = content.replace(/\n/gm, "\n" + " ".repeat(prefix.length));
      return prefix + content + (node.nextSibling ? "\n" : "");
    }
  };
  rules$1.indentedCodeBlock = {
    filter: function(node, options) {
      return options.codeBlockStyle === "indented" && node.nodeName === "PRE" && node.firstChild && node.firstChild.nodeName === "CODE";
    },
    replacement: function(content, node, options) {
      return "\n\n    " + node.firstChild.textContent.replace(/\n/g, "\n    ") + "\n\n";
    }
  };
  rules$1.fencedCodeBlock = {
    filter: function(node, options) {
      return options.codeBlockStyle === "fenced" && node.nodeName === "PRE" && node.firstChild && node.firstChild.nodeName === "CODE";
    },
    replacement: function(content, node, options) {
      var className = node.firstChild.getAttribute("class") || "";
      var language = (className.match(/language-(\S+)/) || [null, ""])[1];
      var code = node.firstChild.textContent;
      var fenceChar = options.fence.charAt(0);
      var fenceSize = 3;
      var fenceInCodeRegex = new RegExp("^" + fenceChar + "{3,}", "gm");
      var match;
      while (match = fenceInCodeRegex.exec(code)) {
        if (match[0].length >= fenceSize) {
          fenceSize = match[0].length + 1;
        }
      }
      var fence = repeat(fenceChar, fenceSize);
      return "\n\n" + fence + language + "\n" + code.replace(/\n$/, "") + "\n" + fence + "\n\n";
    }
  };
  rules$1.horizontalRule = {
    filter: "hr",
    replacement: function(content, node, options) {
      return "\n\n" + options.hr + "\n\n";
    }
  };
  rules$1.inlineLink = {
    filter: function(node, options) {
      return options.linkStyle === "inlined" && node.nodeName === "A" && node.getAttribute("href");
    },
    replacement: function(content, node) {
      var href = escapeLinkDestination(node.getAttribute("href"));
      var title = escapeLinkTitle(cleanAttribute(node.getAttribute("title")));
      var titlePart = title ? ' "' + title + '"' : "";
      return "[" + content + "](" + href + titlePart + ")";
    }
  };
  rules$1.referenceLink = {
    filter: function(node, options) {
      return options.linkStyle === "referenced" && node.nodeName === "A" && node.getAttribute("href");
    },
    replacement: function(content, node, options) {
      var href = escapeLinkDestination(node.getAttribute("href"));
      var title = cleanAttribute(node.getAttribute("title"));
      if (title) title = ' "' + escapeLinkTitle(title) + '"';
      var replacement;
      var reference;
      switch (options.linkReferenceStyle) {
        case "collapsed":
          replacement = "[" + content + "][]";
          reference = "[" + content + "]: " + href + title;
          break;
        case "shortcut":
          replacement = "[" + content + "]";
          reference = "[" + content + "]: " + href + title;
          break;
        default:
          var id = this.references.length + 1;
          replacement = "[" + content + "][" + id + "]";
          reference = "[" + id + "]: " + href + title;
      }
      this.references.push(reference);
      return replacement;
    },
    references: [],
    append: function(options) {
      var references = "";
      if (this.references.length) {
        references = "\n\n" + this.references.join("\n") + "\n\n";
        this.references = [];
      }
      return references;
    }
  };
  rules$1.emphasis = {
    filter: ["em", "i"],
    replacement: function(content, node, options) {
      if (!content.trim()) return "";
      return options.emDelimiter + content + options.emDelimiter;
    }
  };
  rules$1.strong = {
    filter: ["strong", "b"],
    replacement: function(content, node, options) {
      if (!content.trim()) return "";
      return options.strongDelimiter + content + options.strongDelimiter;
    }
  };
  rules$1.code = {
    filter: function(node) {
      var hasSiblings = node.previousSibling || node.nextSibling;
      var isCodeBlock = node.parentNode.nodeName === "PRE" && !hasSiblings;
      return node.nodeName === "CODE" && !isCodeBlock;
    },
    replacement: function(content) {
      if (!content) return "";
      content = content.replace(/\r?\n|\r/g, " ");
      var extraSpace = /^`|^ .*?[^ ].* $|`$/.test(content) ? " " : "";
      var delimiter = "`";
      var matches = content.match(/`+/gm) || [];
      while (matches.indexOf(delimiter) !== -1) delimiter = delimiter + "`";
      return delimiter + extraSpace + content + extraSpace + delimiter;
    }
  };
  rules$1.image = {
    filter: "img",
    replacement: function(content, node) {
      var alt = escapeMarkdown(cleanAttribute(node.getAttribute("alt")));
      var src = escapeLinkDestination(node.getAttribute("src") || "");
      var title = cleanAttribute(node.getAttribute("title"));
      var titlePart = title ? ' "' + escapeLinkTitle(title) + '"' : "";
      return src ? "![" + alt + "](" + src + titlePart + ")" : "";
    }
  };
  function cleanAttribute(attribute) {
    return attribute ? attribute.replace(/(\n+\s*)+/g, "\n") : "";
  }
  function escapeLinkDestination(destination) {
    var escaped = destination.replace(/([<>()])/g, "\\$1");
    return escaped.indexOf(" ") >= 0 ? "<" + escaped + ">" : escaped;
  }
  function escapeLinkTitle(title) {
    return title.replace(/"/g, '\\"');
  }
  function Rules(options) {
    this.options = options;
    this._keep = [];
    this._remove = [];
    this.blankRule = {
      replacement: options.blankReplacement
    };
    this.keepReplacement = options.keepReplacement;
    this.defaultRule = {
      replacement: options.defaultReplacement
    };
    this.array = [];
    for (var key in options.rules) this.array.push(options.rules[key]);
  }
  Rules.prototype = {
    add: function(key, rule) {
      this.array.unshift(rule);
    },
    keep: function(filter) {
      this._keep.unshift({
        filter,
        replacement: this.keepReplacement
      });
    },
    remove: function(filter) {
      this._remove.unshift({
        filter,
        replacement: function() {
          return "";
        }
      });
    },
    forNode: function(node) {
      if (node.isBlank) return this.blankRule;
      var rule;
      if (rule = findRule(this.array, node, this.options)) return rule;
      if (rule = findRule(this._keep, node, this.options)) return rule;
      if (rule = findRule(this._remove, node, this.options)) return rule;
      return this.defaultRule;
    },
    forEach: function(fn) {
      for (var i = 0; i < this.array.length; i++) fn(this.array[i], i);
    }
  };
  function findRule(rules2, node, options) {
    for (var i = 0; i < rules2.length; i++) {
      var rule = rules2[i];
      if (filterValue(rule, node, options)) return rule;
    }
    return void 0;
  }
  function filterValue(rule, node, options) {
    var filter = rule.filter;
    if (typeof filter === "string") {
      if (filter === node.nodeName.toLowerCase()) return true;
    } else if (Array.isArray(filter)) {
      if (filter.indexOf(node.nodeName.toLowerCase()) > -1) return true;
    } else if (typeof filter === "function") {
      if (filter.call(rule, node, options)) return true;
    } else {
      throw new TypeError("`filter` needs to be a string, array, or function");
    }
  }
  function collapseWhitespace(options) {
    var element = options.element;
    var isBlock2 = options.isBlock;
    var isVoid2 = options.isVoid;
    var isPre = options.isPre || function(node2) {
      return node2.nodeName === "PRE";
    };
    if (!element.firstChild || isPre(element)) return;
    var prevText = null;
    var keepLeadingWs = false;
    var prev = null;
    var node = next(prev, element, isPre);
    while (node !== element) {
      if (node.nodeType === 3 || node.nodeType === 4) {
        var text = node.data.replace(/[ \r\n\t]+/g, " ");
        if ((!prevText || / $/.test(prevText.data)) && !keepLeadingWs && text[0] === " ") {
          text = text.substr(1);
        }
        if (!text) {
          node = remove(node);
          continue;
        }
        node.data = text;
        prevText = node;
      } else if (node.nodeType === 1) {
        if (isBlock2(node) || node.nodeName === "BR") {
          if (prevText) {
            prevText.data = prevText.data.replace(/ $/, "");
          }
          prevText = null;
          keepLeadingWs = false;
        } else if (isVoid2(node) || isPre(node)) {
          prevText = null;
          keepLeadingWs = true;
        } else if (prevText) {
          keepLeadingWs = false;
        }
      } else {
        node = remove(node);
        continue;
      }
      var nextNode = next(prev, node, isPre);
      prev = node;
      node = nextNode;
    }
    if (prevText) {
      prevText.data = prevText.data.replace(/ $/, "");
      if (!prevText.data) {
        remove(prevText);
      }
    }
  }
  function remove(node) {
    var next2 = node.nextSibling || node.parentNode;
    node.parentNode.removeChild(node);
    return next2;
  }
  function next(prev, current, isPre) {
    if (prev && prev.parentNode === current || isPre(current)) {
      return current.nextSibling || current.parentNode;
    }
    return current.firstChild || current.nextSibling || current.parentNode;
  }
  var root = typeof window !== "undefined" ? window : {};
  function canParseHTMLNatively() {
    var Parser = root.DOMParser;
    var canParse = false;
    try {
      if (new Parser().parseFromString("", "text/html")) {
        canParse = true;
      }
    } catch (e) {
    }
    return canParse;
  }
  function createHTMLParser() {
    var Parser = function() {
    };
    {
      if (shouldUseActiveX()) {
        Parser.prototype.parseFromString = function(string) {
          var doc = new window.ActiveXObject("htmlfile");
          doc.designMode = "on";
          doc.open();
          doc.write(string);
          doc.close();
          return doc;
        };
      } else {
        Parser.prototype.parseFromString = function(string) {
          var doc = document.implementation.createHTMLDocument("");
          doc.open();
          doc.write(string);
          doc.close();
          return doc;
        };
      }
    }
    return Parser;
  }
  function shouldUseActiveX() {
    var useActiveX = false;
    try {
      document.implementation.createHTMLDocument("").open();
    } catch (e) {
      if (root.ActiveXObject) useActiveX = true;
    }
    return useActiveX;
  }
  var HTMLParser = canParseHTMLNatively() ? root.DOMParser : createHTMLParser();
  function RootNode(input, options) {
    var root2;
    if (typeof input === "string") {
      var doc = htmlParser().parseFromString(
        // DOM parsers arrange elements in the <head> and <body>.
        // Wrapping in a custom element ensures elements are reliably arranged in
        // a single element.
        '<x-turndown id="turndown-root">' + input + "</x-turndown>",
        "text/html"
      );
      root2 = doc.getElementById("turndown-root");
    } else {
      root2 = input.cloneNode(true);
    }
    collapseWhitespace({
      element: root2,
      isBlock,
      isVoid,
      isPre: options.preformattedCode ? isPreOrCode : null
    });
    return root2;
  }
  var _htmlParser;
  function htmlParser() {
    _htmlParser = _htmlParser || new HTMLParser();
    return _htmlParser;
  }
  function isPreOrCode(node) {
    return node.nodeName === "PRE" || node.nodeName === "CODE";
  }
  function Node(node, options) {
    node.isBlock = isBlock(node);
    node.isCode = node.nodeName === "CODE" || node.parentNode.isCode;
    node.isBlank = isBlank(node);
    node.flankingWhitespace = flankingWhitespace(node, options);
    return node;
  }
  function isBlank(node) {
    return !isVoid(node) && !isMeaningfulWhenBlank(node) && /^\s*$/i.test(node.textContent) && !hasVoid(node) && !hasMeaningfulWhenBlank(node);
  }
  function flankingWhitespace(node, options) {
    if (node.isBlock || options.preformattedCode && node.isCode) {
      return {
        leading: "",
        trailing: ""
      };
    }
    var edges = edgeWhitespace(node.textContent);
    if (edges.leadingAscii && isFlankedByWhitespace("left", node, options)) {
      edges.leading = edges.leadingNonAscii;
    }
    if (edges.trailingAscii && isFlankedByWhitespace("right", node, options)) {
      edges.trailing = edges.trailingNonAscii;
    }
    return {
      leading: edges.leading,
      trailing: edges.trailing
    };
  }
  function edgeWhitespace(string) {
    var m = string.match(/^(([ \t\r\n]*)(\s*))(?:(?=\S)[\s\S]*\S)?((\s*?)([ \t\r\n]*))$/);
    return {
      leading: m[1],
      // whole string for whitespace-only strings
      leadingAscii: m[2],
      leadingNonAscii: m[3],
      trailing: m[4],
      // empty for whitespace-only strings
      trailingNonAscii: m[5],
      trailingAscii: m[6]
    };
  }
  function isFlankedByWhitespace(side, node, options) {
    var sibling;
    var regExp;
    var isFlanked;
    if (side === "left") {
      sibling = node.previousSibling;
      regExp = / $/;
    } else {
      sibling = node.nextSibling;
      regExp = /^ /;
    }
    if (sibling) {
      if (sibling.nodeType === 3) {
        isFlanked = regExp.test(sibling.nodeValue);
      } else if (options.preformattedCode && sibling.nodeName === "CODE") {
        isFlanked = false;
      } else if (sibling.nodeType === 1 && !isBlock(sibling)) {
        isFlanked = regExp.test(sibling.textContent);
      }
    }
    return isFlanked;
  }
  var reduce = Array.prototype.reduce;
  function TurndownService(options) {
    if (!(this instanceof TurndownService)) return new TurndownService(options);
    var defaults = {
      rules: rules$1,
      headingStyle: "setext",
      hr: "* * *",
      bulletListMarker: "*",
      codeBlockStyle: "indented",
      fence: "```",
      emDelimiter: "_",
      strongDelimiter: "**",
      linkStyle: "inlined",
      linkReferenceStyle: "full",
      br: "  ",
      preformattedCode: false,
      blankReplacement: function(content, node) {
        return node.isBlock ? "\n\n" : "";
      },
      keepReplacement: function(content, node) {
        return node.isBlock ? "\n\n" + node.outerHTML + "\n\n" : node.outerHTML;
      },
      defaultReplacement: function(content, node) {
        return node.isBlock ? "\n\n" + content + "\n\n" : content;
      }
    };
    this.options = extend({}, defaults, options);
    this.rules = new Rules(this.options);
  }
  TurndownService.prototype = {
    /**
     * The entry point for converting a string or DOM node to Markdown
     * @public
     * @param {String|HTMLElement} input The string or DOM node to convert
     * @returns A Markdown representation of the input
     * @type String
     */
    turndown: function(input) {
      if (!canConvert(input)) {
        throw new TypeError(input + " is not a string, or an element/document/fragment node.");
      }
      if (input === "") return "";
      var output = process.call(this, new RootNode(input, this.options));
      return postProcess.call(this, output);
    },
    /**
     * Add one or more plugins
     * @public
     * @param {Function|Array} plugin The plugin or array of plugins to add
     * @returns The Turndown instance for chaining
     * @type Object
     */
    use: function(plugin) {
      if (Array.isArray(plugin)) {
        for (var i = 0; i < plugin.length; i++) this.use(plugin[i]);
      } else if (typeof plugin === "function") {
        plugin(this);
      } else {
        throw new TypeError("plugin must be a Function or an Array of Functions");
      }
      return this;
    },
    /**
     * Adds a rule
     * @public
     * @param {String} key The unique key of the rule
     * @param {Object} rule The rule
     * @returns The Turndown instance for chaining
     * @type Object
     */
    addRule: function(key, rule) {
      this.rules.add(key, rule);
      return this;
    },
    /**
     * Keep a node (as HTML) that matches the filter
     * @public
     * @param {String|Array|Function} filter The unique key of the rule
     * @returns The Turndown instance for chaining
     * @type Object
     */
    keep: function(filter) {
      this.rules.keep(filter);
      return this;
    },
    /**
     * Remove a node that matches the filter
     * @public
     * @param {String|Array|Function} filter The unique key of the rule
     * @returns The Turndown instance for chaining
     * @type Object
     */
    remove: function(filter) {
      this.rules.remove(filter);
      return this;
    },
    /**
     * Escapes Markdown syntax
     * @public
     * @param {String} string The string to escape
     * @returns A string with Markdown syntax escaped
     * @type String
     */
    escape: function(string) {
      return escapeMarkdown(string);
    }
  };
  function process(parentNode) {
    var self = this;
    return reduce.call(parentNode.childNodes, function(output, node) {
      node = new Node(node, self.options);
      var replacement = "";
      if (node.nodeType === 3) {
        replacement = node.isCode ? node.nodeValue : self.escape(node.nodeValue);
      } else if (node.nodeType === 1) {
        replacement = replacementForNode.call(self, node);
      }
      return join(output, replacement);
    }, "");
  }
  function postProcess(output) {
    var self = this;
    this.rules.forEach(function(rule) {
      if (typeof rule.append === "function") {
        output = join(output, rule.append(self.options));
      }
    });
    return output.replace(/^[\t\r\n]+/, "").replace(/[\t\r\n\s]+$/, "");
  }
  function replacementForNode(node) {
    var rule = this.rules.forNode(node);
    var content = process.call(this, node);
    var whitespace = node.flankingWhitespace;
    if (whitespace.leading || whitespace.trailing) content = content.trim();
    return whitespace.leading + rule.replacement(content, node, this.options) + whitespace.trailing;
  }
  function join(output, replacement) {
    var s1 = trimTrailingNewlines(output);
    var s2 = trimLeadingNewlines(replacement);
    var nls = Math.max(output.length - s1.length, replacement.length - s2.length);
    var separator = "\n\n".substring(0, nls);
    return s1 + separator + s2;
  }
  function canConvert(input) {
    return input != null && (typeof input === "string" || input.nodeType && (input.nodeType === 1 || input.nodeType === 9 || input.nodeType === 11));
  }
  var highlightRegExp = /highlight-(?:text|source)-([a-z0-9]+)/;
  function highlightedCodeBlock(turndownService) {
    turndownService.addRule("highlightedCodeBlock", {
      filter: function(node) {
        var firstChild = node.firstChild;
        return node.nodeName === "DIV" && highlightRegExp.test(node.className) && firstChild && firstChild.nodeName === "PRE";
      },
      replacement: function(content, node, options) {
        var className = node.className || "";
        var language = (className.match(highlightRegExp) || [null, ""])[1];
        return "\n\n" + options.fence + language + "\n" + node.firstChild.textContent + "\n" + options.fence + "\n\n";
      }
    });
  }
  function strikethrough(turndownService) {
    turndownService.addRule("strikethrough", {
      filter: ["del", "s", "strike"],
      replacement: function(content) {
        return "~" + content + "~";
      }
    });
  }
  var indexOf = Array.prototype.indexOf;
  var every = Array.prototype.every;
  var rules = {};
  rules.tableCell = {
    filter: ["th", "td"],
    replacement: function(content, node) {
      return cell(content, node);
    }
  };
  rules.tableRow = {
    filter: "tr",
    replacement: function(content, node) {
      var borderCells = "";
      var alignMap = { left: ":--", right: "--:", center: ":-:" };
      if (isHeadingRow(node)) {
        for (var i = 0; i < node.childNodes.length; i++) {
          var border = "---";
          var align = (node.childNodes[i].getAttribute("align") || "").toLowerCase();
          if (align) border = alignMap[align] || border;
          borderCells += cell(border, node.childNodes[i]);
        }
      }
      return "\n" + content + (borderCells ? "\n" + borderCells : "");
    }
  };
  rules.table = {
    // Only convert tables with a heading row.
    // Tables with no heading row are kept using `keep` (see below).
    filter: function(node) {
      return node.nodeName === "TABLE" && isHeadingRow(node.rows[0]);
    },
    replacement: function(content) {
      content = content.replace("\n\n", "\n");
      return "\n\n" + content + "\n\n";
    }
  };
  rules.tableSection = {
    filter: ["thead", "tbody", "tfoot"],
    replacement: function(content) {
      return content;
    }
  };
  function isHeadingRow(tr) {
    var parentNode = tr.parentNode;
    return parentNode.nodeName === "THEAD" || parentNode.firstChild === tr && (parentNode.nodeName === "TABLE" || isFirstTbody(parentNode)) && every.call(tr.childNodes, function(n) {
      return n.nodeName === "TH";
    });
  }
  function isFirstTbody(element) {
    var previousSibling = element.previousSibling;
    return element.nodeName === "TBODY" && (!previousSibling || previousSibling.nodeName === "THEAD" && /^\s*$/i.test(previousSibling.textContent));
  }
  function cell(content, node) {
    var index = indexOf.call(node.parentNode.childNodes, node);
    var prefix = " ";
    if (index === 0) prefix = "| ";
    return prefix + content + " |";
  }
  function tables(turndownService) {
    turndownService.keep(function(node) {
      return node.nodeName === "TABLE" && !isHeadingRow(node.rows[0]);
    });
    for (var key in rules) turndownService.addRule(key, rules[key]);
  }
  function taskListItems(turndownService) {
    turndownService.addRule("taskListItems", {
      filter: function(node) {
        return node.type === "checkbox" && node.parentNode.nodeName === "LI";
      },
      replacement: function(content, node) {
        return (node.checked ? "[x]" : "[ ]") + " ";
      }
    });
  }
  function gfm(turndownService) {
    turndownService.use([
      highlightedCodeBlock,
      strikethrough,
      tables,
      taskListItems
    ]);
  }
  let instance = null;
  function getTurndownService() {
    if (!instance) {
      instance = new TurndownService({
        headingStyle: "atx",
        bulletListMarker: "-",
        codeBlockStyle: "fenced"
      });
      instance.use(gfm);
      instance.addRule("fractions", {
        filter: function(node) {
          if (node.nodeName === "DIV") {
            const el = node;
            const style = el.getAttribute("style") || "";
            if (style.includes("inline-block") && style.includes("vertical-align: middle")) {
              const spans = Array.from(el.children).filter((n) => n.nodeName === "SPAN");
              if (spans.length >= 2) {
                return true;
              }
            }
          }
          return false;
        },
        replacement: function(_content, node) {
          var _a, _b;
          const el = node;
          const spans = Array.from(el.children).filter((n) => n.nodeName === "SPAN");
          let num = ((_a = spans[0].textContent) == null ? void 0 : _a.trim()) || "";
          let den = ((_b = spans[spans.length - 1].textContent) == null ? void 0 : _b.trim()) || "";
          return ` (${num}/${den}) `;
        }
      });
    }
    return instance;
  }
  function fixImageUrls(html) {
    return html.replace(/src=["'](?:\/)?(oliveimg\/[^"']+)["']/gi, 'src="https://u1.oliveboard.in/exams/solution/$1"');
  }
  function extractCurrentQuestion(fallbackIndex) {
    var _a;
    let activeBlock = null;
    const blocks = Array.from(document.querySelectorAll(".singleqid, .paneqid"));
    let domIndex = 0;
    for (let i = 0; i < blocks.length; i++) {
      const style = window.getComputedStyle(blocks[i]);
      if (style.display !== "none") {
        activeBlock = blocks[i];
        domIndex = i + 1;
        break;
      }
    }
    if (!activeBlock) return null;
    const sectionEl = document.querySelector(".ddn-select");
    const sectionName = ((_a = sectionEl == null ? void 0 : sectionEl.textContent) == null ? void 0 : _a.trim()) || "Unknown Section";
    try {
      const paneTxt = activeBlock.querySelector(".panetxt .eqt") || activeBlock.querySelector(".panetxt");
      const directionsHtml = paneTxt ? fixImageUrls(paneTxt.innerHTML.trim()) + "<br><br>" : "";
      const qblock = activeBlock.querySelector(".qblock .eqt") || activeBlock.querySelector(".qblock");
      const questionHtml = directionsHtml + (qblock ? fixImageUrls(qblock.innerHTML.trim()) : "");
      const options = [];
      const optionBlocks = activeBlock.querySelectorAll(".opt");
      optionBlocks.forEach((optBlock) => {
        var _a2;
        const labelEl = optBlock.querySelector(".left");
        const textEl = optBlock.querySelector(".rightopt .eqt") || optBlock.querySelector(".rightopt");
        const label = labelEl ? ((_a2 = labelEl.textContent) == null ? void 0 : _a2.trim()) || "" : "";
        const html = textEl ? fixImageUrls(textEl.innerHTML.trim()) : "";
        const isCorrect = optBlock.classList.contains("correct");
        if (label || html) {
          options.push({ label, html, isCorrect });
        }
      });
      const solblock = activeBlock.querySelector(".solutiontxt .eqt") || activeBlock.querySelector(".solutiontxt");
      const solutionHtml = solblock ? fixImageUrls(solblock.innerHTML.trim()) : "";
      return {
        index: domIndex || fallbackIndex,
        sectionName,
        questionHtml,
        options,
        solutionHtml
      };
    } catch (err) {
      console.error(`[OB+] Error parsing question block`, err);
      return null;
    }
  }
  function formatQuestion(q, displayIndex) {
    const td = getTurndownService();
    let markdown = `### Q${displayIndex}

`;
    markdown += `${td.turndown(q.questionHtml)}

`;
    q.options.forEach((opt) => {
      const optionMark = opt.isCorrect ? `**[Correct]** ` : ``;
      const optionMarkdown = td.turndown(opt.html).replace(/\n/g, " ");
      markdown += `- **${opt.label}**: ${optionMark}${optionMarkdown}
`;
    });
    markdown += `
`;
    if (q.solutionHtml) {
      markdown += `**Solution:**

`;
      markdown += `${td.turndown(q.solutionHtml)}

`;
    }
    return markdown;
  }
  class Crawler {
    constructor(onUpdate, onComplete, onError) {
      __publicField(this, "isCancelled", false);
      __publicField(this, "questionsData", /* @__PURE__ */ new Map());
      __publicField(this, "currentIndex", 1);
      this.onUpdate = onUpdate;
      this.onComplete = onComplete;
      this.onError = onError;
    }
    sleep(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }
    cancel() {
      this.isCancelled = true;
    }
    hashString(str) {
      let hash = 5381;
      for (let i = 0; i < str.length; i++) {
        hash = (hash << 5) + hash + str.charCodeAt(i) | 0;
      }
      return hash.toString(36);
    }
    parseSectionMap() {
      const sections = [];
      const sectionBoxes = document.querySelectorAll(".question-map .box");
      sectionBoxes.forEach((box) => {
        var _a;
        const nameEl = box.querySelector("p b") || box.querySelector("p");
        const name = ((_a = nameEl == null ? void 0 : nameEl.textContent) == null ? void 0 : _a.trim()) || "Unknown Section";
        const qSpans = box.querySelectorAll(".map-qno");
        const questionIndices = [];
        qSpans.forEach((span) => {
          const onclick = span.getAttribute("onclick") || "";
          const match = onclick.match(/goToQuestion\((\d+)\)/);
          if (match) {
            questionIndices.push(parseInt(match[1], 10));
          }
        });
        if (questionIndices.length > 0) {
          sections.push({ name, questionIndices });
        }
      });
      return sections;
    }
    navigateToQuestion(globalIndex) {
      const span = document.querySelector(`.map-qno.q-${globalIndex}`);
      if (span) {
        span.click();
      }
    }
    async start() {
      this.isCancelled = false;
      this.questionsData.clear();
      this.currentIndex = 1;
      const sections = this.parseSectionMap();
      if (sections.length === 0) {
        await this.linearCrawl();
        return;
      }
      const totalQuestions = sections.reduce((sum, s) => sum + s.questionIndices.length, 0);
      let processedCount = 0;
      for (const section of sections) {
        if (this.isCancelled) break;
        this.onUpdate(`Section: ${section.name}`);
        await this.sleep(50);
        if (this.isCancelled) break;
        for (const globalIdx of section.questionIndices) {
          if (this.isCancelled) break;
          processedCount++;
          this.onUpdate(`${section.name} — Q${processedCount}/${totalQuestions}`);
          this.navigateToQuestion(globalIdx);
          await this.sleep(10);
          if (this.isCancelled) break;
          const qData = extractCurrentQuestion(this.currentIndex);
          if (!qData) {
            await this.sleep(50);
            if (this.isCancelled) break;
            const retry = extractCurrentQuestion(this.currentIndex);
            if (!retry) continue;
            this.addQuestion(retry, section.name);
          } else {
            this.addQuestion(qData, section.name);
          }
        }
      }
      if (this.isCancelled) {
        this.onUpdate("Cancelled.");
        return;
      }
      if (this.questionsData.size === 0) {
        this.onError("No questions found.");
        return;
      }
      this.onUpdate("Generating Markdown...");
      const md = this.generateMarkdown(sections);
      this.onComplete(md);
    }
    addQuestion(qData, sectionName) {
      const textContent = qData.questionHtml.replace(/<[^>]*>/g, "").trim();
      const signature = this.hashString(textContent);
      if (!this.questionsData.has(signature)) {
        qData.sectionName = sectionName;
        this.questionsData.set(signature, qData);
        this.currentIndex++;
      }
    }
    async linearCrawl() {
      let sameQuestionCount = 0;
      let consecutiveNulls = 0;
      let lastSignature = "";
      while (!this.isCancelled) {
        this.onUpdate(`Extracting Q${this.currentIndex}...`);
        await this.sleep(10);
        if (this.isCancelled) break;
        const qData = extractCurrentQuestion(this.currentIndex);
        if (!qData) {
          consecutiveNulls++;
          if (consecutiveNulls > 3) {
            this.onUpdate("No questions found on page.");
            break;
          }
          const nextBtn2 = Array.from(document.querySelectorAll("button.btn-prenext")).find((btn) => {
            var _a;
            return (_a = btn.textContent) == null ? void 0 : _a.includes("Next");
          });
          if (nextBtn2 && !nextBtn2.disabled && nextBtn2.style.display !== "none") {
            nextBtn2.click();
            await this.sleep(50);
          } else {
            break;
          }
          continue;
        }
        consecutiveNulls = 0;
        const textContent = qData.questionHtml.replace(/<[^>]*>/g, "").trim();
        const signature = this.hashString(textContent);
        if (signature === lastSignature) {
          sameQuestionCount++;
          if (sameQuestionCount > 3) {
            this.onUpdate(`Reached the end or stuck.`);
            break;
          }
        } else {
          sameQuestionCount = 0;
          lastSignature = signature;
          if (!this.questionsData.has(signature)) {
            this.questionsData.set(signature, qData);
            this.currentIndex++;
          } else {
            break;
          }
        }
        const nextBtn = Array.from(document.querySelectorAll("button.btn-prenext")).find((btn) => {
          var _a;
          return (_a = btn.textContent) == null ? void 0 : _a.includes("Next");
        });
        if (nextBtn && !nextBtn.disabled && nextBtn.style.display !== "none") {
          nextBtn.click();
          await this.sleep(50);
        } else {
          break;
        }
      }
      if (this.isCancelled) {
        this.onUpdate("Cancelled.");
        return;
      }
      if (this.questionsData.size === 0) {
        this.onError("No questions found.");
        return;
      }
      this.onUpdate("Generating Markdown...");
      const md = this.generateMarkdown([]);
      this.onComplete(md);
    }
    generateMarkdown(sections) {
      let markdown = `# Oliveboard Exam

`;
      if (sections.length > 0) {
        const grouped = /* @__PURE__ */ new Map();
        for (const section of sections) {
          if (!grouped.has(section.name)) {
            grouped.set(section.name, []);
          }
        }
        for (const q of this.questionsData.values()) {
          const sectionName = q.sectionName || "Unknown Section";
          if (!grouped.has(sectionName)) {
            grouped.set(sectionName, []);
          }
          grouped.get(sectionName).push(q);
        }
        for (const [sectionName, questions] of grouped) {
          if (questions.length === 0) continue;
          markdown += `## ${sectionName}

`;
          let sectionQNo = 1;
          for (const q of questions) {
            markdown += formatQuestion(q, sectionQNo) + `---

`;
            sectionQNo++;
          }
        }
      } else {
        let displayIndex = 1;
        for (const q of this.questionsData.values()) {
          markdown += formatQuestion(q, displayIndex) + `---

`;
          displayIndex++;
        }
      }
      return markdown;
    }
  }
  function downloadFile(content, filename) {
    const blob = new Blob([content], { type: "text/markdown;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  }
  function enableCopyAndRightClick() {
    const style = document.createElement("style");
    style.textContent = `
        * {
            -webkit-user-select: text !important;
            -moz-user-select: text !important;
            -ms-user-select: text !important;
            user-select: text !important;
        }
    `;
    (document.head || document.documentElement).appendChild(style);
    const events = ["contextmenu", "copy", "cut", "paste", "selectstart"];
    events.forEach((evt) => {
      window.addEventListener(evt, (e) => {
        e.stopPropagation();
      }, true);
    });
  }
  function onReady(fn) {
    if (document.readyState === "loading") {
      document.addEventListener("DOMContentLoaded", fn);
    } else {
      fn();
    }
  }
  const selectorsToHide = [
    "#sec-update",
    "#rightcol",
    // Usually contains sidebars
    ".obadcard",
    // Deals & Offers ads section
    '.limenuitem:has(a[href*="refer"])',
    '.limenuitem:has(a[href*="testimonials"])',
    '.limenuitem:has(a[href*="edge/?c=1851"])',
    '.limenuitem:has(a[href*="buypayu/validity"])',
    // Zendesk chat widget
    '[data-garden-id="buttons.icon_button"][aria-label="Open messaging window"]',
    ".sc-1w3tvxe-0",
    // Chat widget wrapper
    'iframe[title="Close message"]',
    'iframe[title="Message from company"]',
    'iframe[title="Number of unread messages"]',
    'iframe[title="Messaging window"]',
    "iframe#launcher",
    'iframe[title^="Button to launch messaging window"]'
  ];
  function hideElements() {
    selectorsToHide.forEach((selector) => {
      document.querySelectorAll(selector).forEach((el) => {
        el.style.display = "none";
      });
    });
    document.querySelectorAll('div[style*="z-index: 999999"]').forEach((el) => {
      if (el.style.position === "fixed" && el.querySelector("iframe")) {
        el.style.display = "none";
      }
    });
  }
  function modifyLinks() {
    document.querySelectorAll('a[onclick^="openwin"]').forEach((a) => {
      const onclick = a.getAttribute("onclick") || "";
      const match = onclick.match(/openwin\(['"]([^'"]+)['"]/);
      if (match && match[1]) {
        a.setAttribute("href", match[1]);
        a.setAttribute("target", "_blank");
        a.removeAttribute("onclick");
      }
    });
  }
  function interceptViewSolutions() {
    const script = document.createElement("script");
    script.textContent = `
        // Poison Zendesk widget globals so it never initializes
        const noop = function() { return noop; };
        noop.setLocale = noop; noop.identify = noop; noop.hide = noop;
        noop.show = noop; noop.activate = noop; noop.on = noop;
        ['zE', '$zopim', 'zEACLoaded'].forEach(key => {
            Object.defineProperty(window, key, {
                get: () => noop,
                set: () => {},  // silently ignore page's attempts to redefine
                configurable: true
            });
        });

        // Override openwin — getter always returns our version, setter silently absorbs
        const openwinOverride = function(url, name) { window.open(url, '_blank'); };
        Object.defineProperty(window, 'openwin', {
            get: () => openwinOverride,
            set: () => {},  // silently ignore page's attempts to redefine
            configurable: true
        });
    `;
    document.documentElement.appendChild(script);
    script.remove();
  }
  const COPY_SVG = '<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>';
  const CHECK_SVG = '<path d="M20 6L9 17l-5-5"></path>';
  function ensureCopyButton() {
    var _a;
    const headerCols = document.querySelectorAll(".solheader-col");
    if (headerCols.length === 0) return;
    const headerCol = headerCols[0];
    if (headerCol.querySelector(".copy-md-btn")) return;
    const btnWrapper = document.createElement("div");
    btnWrapper.className = "copy-md-btn";
    btnWrapper.title = "Copy Markdown";
    btnWrapper.innerHTML = `
        <button type="button" class="button btn-save-qn" style="display:flex;align-items:center;justify-content:center;margin-left:10px;">
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                ${COPY_SVG}
            </svg>
        </button>
    `;
    btnWrapper.onclick = async () => {
      const q = extractCurrentQuestion(1);
      if (!q) return;
      const md = formatQuestion(q, q.index);
      try {
        await navigator.clipboard.writeText(md);
        const svg = btnWrapper.querySelector("svg");
        if (svg) {
          svg.innerHTML = CHECK_SVG;
          setTimeout(() => {
            svg.innerHTML = COPY_SVG;
          }, 2e3);
        }
      } catch (err) {
        console.error("[OB+] Clipboard write failed:", err);
      }
    };
    const saveQs = headerCol.querySelector(".save-qs");
    if (saveQs) {
      (_a = saveQs.parentNode) == null ? void 0 : _a.insertBefore(btnWrapper, saveQs);
    } else {
      headerCol.appendChild(btnWrapper);
    }
  }
  function initDownloader() {
    let activeCrawler = null;
    const ui = new DownloaderUI(
      () => {
        activeCrawler = new Crawler(
          (msg) => ui.updateStatus(msg),
          (md) => {
            ui.finish();
            downloadFile(md, "Oliveboard_Questions.md");
          },
          (errMsg) => ui.error(errMsg)
        );
        activeCrawler.start();
      },
      () => activeCrawler == null ? void 0 : activeCrawler.cancel()
    );
    onReady(() => ui.mount());
  }
  function runMutationHandlers() {
    hideElements();
    modifyLinks();
    ensureCopyButton();
  }
  function init() {
    try {
      enableCopyAndRightClick();
    } catch (e) {
      console.error("[OB+]", e);
    }
    try {
      interceptViewSolutions();
    } catch (e) {
      console.error("[OB+]", e);
    }
    try {
      initDownloader();
    } catch (e) {
      console.error("[OB+]", e);
    }
    onReady(runMutationHandlers);
    let pending = false;
    const observer = new MutationObserver(() => {
      if (pending) return;
      pending = true;
      requestAnimationFrame(() => {
        runMutationHandlers();
        pending = false;
      });
    });
    observer.observe(document.documentElement, { childList: true, subtree: true });
  }
  init();

})();