{"version":3,"sources":["../src/unquote.ts","../src/patterns.ts","../src/htmlToText.ts","../src/htmlToMarkdown.ts","../src/htmlCleaner.ts"],"sourcesContent":["import * as cheerio from \"cheerio\";\nimport type { CheerioAPI } from \"cheerio\";\nimport { marked } from \"marked\";\nimport { patterns } from \"./patterns\";\nimport { htmlToText } from \"./htmlToText\";\nimport { htmlToMarkdown } from \"./htmlToMarkdown\";\nimport { cleanEmailHtml } from \"./htmlCleaner\";\n\nexport interface GetHtmlOptions {\n  /** If true, returns raw HTML without cleaning. Default: false (cleaned). */\n  raw?: boolean;\n}\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype CheerioNode = any;\n\n// Regex for clearing text - compiled once for performance\nconst CLEAR_TEXT_REGEX = /[><\\s\\r\\t\\xa0]+/g;\n\n/**\n * Extract original tag names with their casing from HTML\n */\nfunction extractOriginalTagCasing(html: string): Map<string, string> {\n  const tagMap = new Map<string, string>();\n  const tagRegex = /<\\/?([a-zA-Z][a-zA-Z0-9]*)/g;\n  let match;\n  while ((match = tagRegex.exec(html)) !== null) {\n    const tagName = match[1];\n    const lowerTag = tagName.toLowerCase();\n    // Keep the first occurrence's casing (usually the opening tag)\n    if (!tagMap.has(lowerTag)) {\n      tagMap.set(lowerTag, tagName);\n    }\n  }\n  return tagMap;\n}\n\n/**\n * Restore original tag casing in processed HTML\n */\nfunction restoreTagCasing(\n  html: string,\n  originalCasing: Map<string, string>\n): string {\n  let result = html;\n  for (const [lowerTag, originalTag] of originalCasing) {\n    if (lowerTag !== originalTag) {\n      // Replace opening tags\n      result = result.replace(\n        new RegExp(`<${lowerTag}(\\\\s|>|\\\\/)`, \"gi\"),\n        (match) => `<${originalTag}${match.slice(lowerTag.length + 1)}`\n      );\n      // Replace closing tags\n      result = result.replace(\n        new RegExp(`</${lowerTag}>`, \"gi\"),\n        `</${originalTag}>`\n      );\n    }\n  }\n  return result;\n}\n\n/**\n * Extract inner HTML without the <html><head></head><body> wrapper\n * and convert to self-closing tags like Python's BeautifulSoup\n */\nfunction getInnerHtml($: CheerioAPI, originalHtml: string): string {\n  // Extract original tag casing before cheerio normalizes it\n  const originalCasing = extractOriginalTagCasing(originalHtml);\n\n  // Check if original HTML had html/body/head tags\n  const hadHtmlTag = /<html[\\s>]/i.test(originalHtml);\n  const hadBodyTag = /<body[\\s>]/i.test(originalHtml);\n  const hadHeadTag = /<head[\\s>]/i.test(originalHtml);\n\n  // Extract whitespace patterns from original\n  const htmlBodyWhitespace =\n    originalHtml.match(/<html[^>]*>([\\s]*)<body/i)?.[1] || \"\";\n  const bodyCloseWhitespace =\n    originalHtml.match(/<\\/body>([\\s]*)<\\/html>/i)?.[1] || \"\";\n\n  let html: string;\n  if (hadHtmlTag || hadBodyTag) {\n    // Original had structure, keep it but normalize\n    html = $.html();\n\n    // Remove <head></head> if original didn't have it\n    if (!hadHeadTag) {\n      html = html.replace(/<head><\\/head>/g, \"\");\n    }\n\n    // Restore whitespace between html/body tags\n    if (htmlBodyWhitespace) {\n      html = html.replace(\n        /<html([^>]*)><body/i,\n        `<html$1>${htmlBodyWhitespace}<body`\n      );\n    }\n    if (bodyCloseWhitespace) {\n      html = html.replace(\n        /<\\/body><\\/html>/i,\n        `</body>${bodyCloseWhitespace}</html>`\n      );\n    }\n  } else {\n    // Original was a fragment, extract just body contents\n    html = $(\"body\").html() || \"\";\n  }\n\n  // Convert to self-closing tags like BeautifulSoup\n  html = html.replace(/<br>/gi, \"<br/>\");\n  html = html.replace(/<hr>/gi, \"<hr/>\");\n\n  // Normalize excessive whitespace (more than 4 consecutive newlines) like BeautifulSoup\n  html = html.replace(/\\n{5,}/g, \"\\n\\n\\n\\n\");\n\n  // Restore original tag casing\n  html = restoreTagCasing(html, originalCasing);\n\n  return html.trim();\n}\n\nexport class Unquote {\n  private originalHtml: string | null;\n  private originalText: string | null;\n  private _html: string | null = null;\n  private _cleanHtml: string | null = null;\n  private _text: string | null = null;\n  private _markdown: string | null = null;\n  private _quoteHtml: string | null = null;\n  private _parsed: boolean = false;\n  private _cachedCheerio: CheerioAPI | null = null;\n\n  constructor(html: string | null, text: string | null) {\n    if (!html && !text) {\n      throw new Error(\"You must provide at least one of html or text\");\n    }\n\n    this.originalHtml = html ? html.replace(/\\xa0/g, \" \") : null;\n    this.originalText = text ? text.replace(/\\xa0/g, \" \") : null;\n  }\n\n  /**\n   * Get cached Cheerio instance, creating it on first access\n   */\n  private getCheerio(): CheerioAPI | null {\n    if (!this.originalHtml) return null;\n    if (!this._cachedCheerio) {\n      this._cachedCheerio = cheerio.load(this.originalHtml);\n    }\n    return this._cachedCheerio;\n  }\n\n  /**\n   * Capture HTML of elements before removing them and store as quote\n   */\n  private captureAndRemove($: CheerioAPI, ...elements: CheerioNode[]): void {\n    const captured: string[] = [];\n    for (const el of elements) {\n      if (el && el.length) {\n        captured.push($.html(el));\n        el.remove();\n      }\n    }\n    if (captured.length) {\n      this._quoteHtml = captured.join(\"\");\n    }\n  }\n\n  /**\n   * Get the HTML content without quoted replies.\n   * @param options.raw - If true, returns raw HTML. Default: false (cleaned).\n   */\n  getHtml(options: GetHtmlOptions = {}): string | null {\n    const { raw = false } = options;\n\n    this.ensureParsed();\n\n    if (this._html === null) {\n      if (this.originalHtml) {\n        this._html = this.originalHtml;\n      } else if (this.originalText) {\n        this._html = this.textToHtml(this.originalText);\n      }\n    }\n\n    // Return raw if requested\n    if (raw) {\n      return this._html;\n    }\n\n    // Return cleaned version (cached)\n    if (this._cleanHtml === null && this._html) {\n      this._cleanHtml = cleanEmailHtml(this._html);\n    }\n    return this._cleanHtml;\n  }\n\n  getText(): string | null {\n    this.ensureParsed();\n    if (this._text === null) {\n      if (this.originalText) {\n        this._text = this.originalText;\n      } else if (this.originalHtml) {\n        this._text = htmlToText(this.originalHtml).trim();\n      }\n    }\n    return this._text;\n  }\n\n  getMarkdown(): string | null {\n    this.ensureParsed();\n    if (this._markdown === null) {\n      // Use cleaned HTML for markdown conversion\n      const html = this.getHtml();\n      if (html) {\n        this._markdown = htmlToMarkdown(html).trim();\n      }\n    }\n    return this._markdown;\n  }\n\n  /**\n   * Get the quoted/replied content that was removed.\n   * Returns the HTML of the quoted reply section, or null if no quote was found.\n   * @param options.raw - If true, returns raw HTML. Default: false (cleaned).\n   */\n  getQuote(options: GetHtmlOptions = {}): string | null {\n    const { raw = false } = options;\n    this.ensureParsed();\n    if (!this._quoteHtml) return null;\n    return raw ? this._quoteHtml : cleanEmailHtml(this._quoteHtml);\n  }\n\n  /**\n   * Ensure parse() has been called, calling it if not yet done\n   */\n  private ensureParsed(): void {\n    if (!this._parsed) {\n      this.parse();\n    }\n  }\n\n  private parseHtml($: CheerioAPI): boolean {\n    // Moz (must be before Apple)\n    const moz = $(\"div.moz-cite-prefix\");\n    if (moz.length) {\n      const nextSibling = moz.next('blockquote[type=\"cite\"]');\n      if (nextSibling.length) {\n        this.captureAndRemove($, moz, nextSibling);\n        return true;\n      }\n    }\n\n    // Freshdesk\n    const freshdesk = $(\"div.freshdesk_quote\");\n    if (freshdesk.length) {\n      this.captureAndRemove($, freshdesk);\n      return true;\n    }\n\n    // Front\n    const front = $(\".front-blockquote\");\n    if (front.length) {\n      this.captureAndRemove($, front);\n      return true;\n    }\n\n    // Missive\n    const missive = $(\"div.missive_quote\");\n    if (missive.length) {\n      this.captureAndRemove($, missive);\n      return true;\n    }\n\n    // Outreach\n    const outreach = $(\"div.outreach-quote\");\n    if (outreach.length) {\n      this.captureAndRemove($, outreach);\n      return true;\n    }\n\n    // Hubspot\n    const hubspot = $(\"div.hs_reply\");\n    if (hubspot.length) {\n      this.captureAndRemove($, hubspot);\n      return true;\n    }\n\n    // Spark\n    const spark = $('[name=\"messageReplySection\"]');\n    if (spark.length) {\n      this.captureAndRemove($, spark);\n      return true;\n    }\n\n    // Gmail\n    const gmail = $(\".gmail_attr\");\n    if (gmail.length) {\n      const parent = gmail.parent();\n      const parentClasses = parent.attr(\"class\") || \"\";\n      if (\n        parentClasses.includes(\"gmail_quote_container\") ||\n        parentClasses.includes(\"gmail_quote\")\n      ) {\n        this.captureAndRemove($, parent);\n        return true;\n      }\n    }\n\n    // Another Gmail\n    const gmail2 = $(\"div.gmail_quote\");\n    if (gmail2.length) {\n      const parent = gmail2.parent();\n      const parentClasses = parent.attr(\"class\") || \"\";\n      if (parentClasses.includes(\"gmail_extra\")) {\n        this.captureAndRemove($, parent);\n        return true;\n      }\n    }\n\n    // Gmail, fallback - handle blockquote.gmail_quote inside div.gmail_quote\n    const gmailFallback = $(\"blockquote.gmail_quote\");\n    if (gmailFallback.length) {\n      // Check if blockquote is inside a div.gmail_quote - if so, remove the whole div\n      const parentDiv = gmailFallback.closest(\"div.gmail_quote\");\n      if (parentDiv.length) {\n        this.captureAndRemove($, parentDiv);\n      } else {\n        this.captureAndRemove($, gmailFallback);\n      }\n      return true;\n    }\n\n    // Gmail div without blockquote but with quote content (cleanup empty gmail_quote divs)\n    const gmailDivOnly = $(\"div.gmail_quote\");\n    if (gmailDivOnly.length) {\n      // Remove if it only contains whitespace or is empty after other processing\n      const textContent = gmailDivOnly.text().trim();\n      if (!textContent || gmailDivOnly.children().length === 0) {\n        this.captureAndRemove($, gmailDivOnly);\n        return true;\n      }\n    }\n\n    // Yahoo\n    const yahoo = $(\"div.yahoo_quoted\");\n    if (yahoo.length) {\n      this.captureAndRemove($, yahoo);\n      return true;\n    }\n\n    // Ymail\n    const ymail = $(\"div#ymail_android_signature\");\n    if (ymail.length) {\n      const nextEls = ymail.nextAll().not(\"script, style\");\n      this.captureAndRemove($, ymail, nextEls);\n      return true;\n    }\n\n    // Yahoo quoted mail\n    const ymail2 = $(\"p.yahoo-quoted-begin\");\n    if (ymail2.length) {\n      const nextEls = ymail2.nextAll().not(\"script, style\");\n      this.captureAndRemove($, ymail2, nextEls);\n      return true;\n    }\n\n    // GetFernand.com\n    const fernand = $(\"div.fernand_quote\");\n    if (fernand.length) {\n      this.captureAndRemove($, fernand);\n      return true;\n    }\n\n    // Intercom\n    const intercom = $(\"div.history\");\n    if (intercom.length) {\n      this.captureAndRemove($, intercom);\n      return true;\n    }\n\n    // Reply\n    const reply = $(\"p#reply-intro\");\n    if (reply.length) {\n      const blockquote = reply.next('blockquote[type=\"cite\"]');\n      if (blockquote.length) {\n        this.captureAndRemove($, reply, blockquote);\n        return true;\n      }\n    }\n\n    // MsOffice\n    const msoffice = $(\"div#mail-editor-reference-message-container\");\n    if (msoffice.length) {\n      this.captureAndRemove($, msoffice);\n      return true;\n    }\n\n    // MsOutlook\n    // Find all potential Outlook quote divs by structure, then validate style with regex\n    // This handles spacing variations like \"border-top:solid\" vs \"border-top: solid\"\n    const msoutlookCandidates = $(\"div[style]>p.MsoNormal>b\");\n    let msoutlook: ReturnType<typeof $> | null = null;\n\n    msoutlookCandidates.each((_, el) => {\n      const parentDiv = $(el).parent().parent();\n      const styleAttr = parentDiv.attr(\"style\") || \"\";\n      // Match border:none (or border : none) followed by border-top:solid (or border-top : solid)\n      // Handles spaces before and after colons and semicolons\n      if (/border\\s*:\\s*none\\s*[;,]\\s*border-top\\s*:\\s*solid/i.test(styleAttr)) {\n        msoutlook = $(el);\n        return false; // break the loop\n      }\n    });\n\n    if (msoutlook && $(msoutlook).length) {\n      const msoRoot = $(msoutlook).parent().parent();\n      const style = (msoRoot.attr(\"style\") || \"\")\n        .replace(/cm/g, \"in\")\n        .replace(/pt/g, \"in\")\n        .replace(/mm/g, \"in\");\n\n      // Normalize spaces for the endsWith check:\n      // - Remove spaces around colons and semicolons\n      // - Collapse multiple spaces to single space\n      // - Trim leading/trailing whitespace\n      const normalizedStyle = style\n        .replace(/\\s*:\\s*/g, \":\")\n        .replace(/\\s*;\\s*/g, \";\")\n        .replace(/\\s+/g, \" \")\n        .trim();\n      if (normalizedStyle.endsWith(\" 1.0in;padding:3.0in 0in 0in 0in\")) {\n        let root = msoRoot;\n        const parentContents = msoRoot.parent().children();\n        const htmlElements = parentContents.filter((_, el) =>\n          $.html(el).startsWith(\"<\")\n        );\n\n        if (htmlElements.length === 1) {\n          root = msoRoot.parent();\n        }\n\n        // Capture quote before removing\n        const nextEls = root.nextAll();\n        this._quoteHtml =\n          $.html(root) +\n          nextEls\n            .map((_, el) => $.html(el))\n            .get()\n            .join(\"\");\n        nextEls.remove();\n        root.remove();\n        return true;\n      }\n    }\n\n    // Outlook\n    const outlook = $(\"div#divRplyFwdMsg\");\n    if (outlook.length) {\n      const prevHr = outlook.prevAll(\"hr\").first();\n      if (prevHr.length) {\n        const nextEls = outlook.nextAll();\n        this._quoteHtml =\n          $.html(prevHr) +\n          $.html(outlook) +\n          nextEls\n            .map((_, el) => $.html(el))\n            .get()\n            .join(\"\");\n        nextEls.remove();\n        outlook.remove();\n        prevHr.remove();\n        return true;\n      }\n    }\n\n    // ProtonMail\n    const proton = $(\".protonmail_quote\");\n    if (proton.length) {\n      this.captureAndRemove($, proton);\n      return true;\n    }\n\n    // Trix\n    const trix = $(\"div.trix-content>blockquote\");\n    if (trix.length) {\n      this.captureAndRemove($, trix);\n      return true;\n    }\n\n    // ZMail\n    const zmail = $(\"div.zmail_extra\");\n    if (zmail.length) {\n      const previous = zmail.prev();\n      if (previous.hasClass(\"zmail_extra_hr\")) {\n        this.captureAndRemove($, previous, zmail);\n      } else {\n        this.captureAndRemove($, zmail);\n      }\n      return true;\n    }\n\n    // Zendesk\n    const zendesk = $(\"div.quotedReply>blockquote\");\n    if (zendesk.length) {\n      this.captureAndRemove($, zendesk.parent());\n      return true;\n    }\n\n    // Zoho\n    const zoho = $('div[title=\"beforequote:::\"]');\n    if (zoho.length) {\n      const nextEls = zoho.nextAll();\n      const prevSibling = zoho.prev();\n      const hasPrevSep = prevSibling.text().trim().startsWith(\"---\");\n\n      this._quoteHtml =\n        (hasPrevSep ? $.html(prevSibling) : \"\") +\n        $.html(zoho) +\n        nextEls\n          .map((_, el) => $.html(el))\n          .get()\n          .join(\"\");\n      nextEls.remove();\n      if (hasPrevSep) {\n        prevSibling.remove();\n      }\n      zoho.remove();\n      return true;\n    }\n\n    // Notion\n    const notion = $(\"blockquote.notion-mail-quote\");\n    if (notion.length) {\n      this.captureAndRemove($, notion);\n      return true;\n    }\n\n    // Tutanota\n    const tutanota = $(\"blockquote.tutanota_quote\");\n    if (tutanota.length) {\n      const prevDiv = tutanota.prev(\"div\");\n      if (prevDiv.length) {\n        this.captureAndRemove($, prevDiv, tutanota);\n      } else {\n        this.captureAndRemove($, tutanota);\n      }\n      return true;\n    }\n\n    // Some odd Yahoo ydp\n    const ydp = $('div[class$=\"yahoo_quoted\"]');\n    if (ydp.length) {\n      const id = ydp.attr(\"id\") || \"\";\n      if (id.includes(\"yahoo_quoted\")) {\n        this.captureAndRemove($, ydp);\n        return true;\n      }\n    }\n\n    // QT\n    const qt = $('blockquote[type=\"cite\"]#qt');\n    if (qt.length) {\n      this.captureAndRemove($, qt);\n      return true;\n    }\n\n    // Alimail\n    const alimail = $(\"div.alimail-quote\");\n    if (alimail.length) {\n      const parent = alimail.parent();\n      if (parent.is(\"blockquote\")) {\n        this.captureAndRemove($, parent);\n        return true;\n      }\n    }\n\n    // Some Apple version\n    const apple = $(\n      'html[class*=\"apple-mail\"] blockquote[type=\"cite\"]>div[dir]'\n    );\n    if (apple.length) {\n      const blockquoteParent = apple.parent();\n      let previousSibling = blockquoteParent.prev();\n\n      // Skip text nodes\n      while (previousSibling.length && !previousSibling.is(\"*\")) {\n        previousSibling = previousSibling.prev();\n      }\n\n      if (previousSibling.length && previousSibling.attr(\"dir\")) {\n        const childBlockquote = previousSibling.find(\"blockquote\");\n        if (childBlockquote.length) {\n          this._quoteHtml = $.html(previousSibling) + $.html(blockquoteParent);\n          previousSibling.remove();\n        } else {\n          this._quoteHtml = $.html(blockquoteParent);\n        }\n      } else {\n        this._quoteHtml = $.html(blockquoteParent);\n      }\n\n      blockquoteParent.remove();\n      return true;\n    }\n\n    // Apple interchange\n    const appleIc = $(\"br.Apple-interchange-newline\");\n    if (appleIc.length) {\n      const parent = appleIc.parent();\n      if (parent.is(\"blockquote\")) {\n        this.captureAndRemove($, parent);\n        return true;\n      }\n    }\n\n    // Another apple\n    const apple2 = $('meta[name=\"x-apple-disable-message-reformatting\"]');\n    if (apple2.length) {\n      const blockquote = apple2.closest(\"blockquote\");\n      if (blockquote.length) {\n        const prevDiv = blockquote.prev(\"div\");\n        if (prevDiv.length) {\n          const nestedBlockquote = prevDiv.find('blockquote[type=\"cite\"]');\n          if (nestedBlockquote.length) {\n            this._quoteHtml = $.html(prevDiv) + $.html(blockquote);\n            prevDiv.remove();\n          } else {\n            this._quoteHtml = $.html(blockquote);\n          }\n        } else {\n          this._quoteHtml = $.html(blockquote);\n        }\n        blockquote.remove();\n        return true;\n      }\n    }\n\n    // OneComWebmail\n    const onecom = $(\"div.oneComWebmail-html\");\n    if (onecom.length) {\n      const parent = onecom.parent();\n      if (parent.is(\"blockquote\")) {\n        this.captureAndRemove($, parent);\n      }\n    }\n\n    // NH*\n    const nh = $(\"div.nh_extra\");\n    if (nh.length) {\n      this.captureAndRemove($, nh);\n    }\n\n    // GWP starting classname\n    const gwp = $('div[id^=\"gwp\"]');\n    if (gwp.length) {\n      const parent = gwp.parent();\n      const tagName = parent.prop(\"tagName\") || \"\";\n      if (tagName.includes(\"@\")) {\n        this.captureAndRemove($, parent);\n        return true;\n      }\n    }\n\n    return false;\n  }\n\n  private clearText(text: string): string {\n    return text.replace(CLEAR_TEXT_REGEX, \"\");\n  }\n\n  parse(): boolean {\n    if (this._parsed) return false;\n    this._parsed = true;\n\n    this._text = this.originalText;\n    this._html = this.originalHtml;\n\n    const $ = this.getCheerio();\n\n    if (this._html && $) {\n      if (this.parseHtml($)) {\n        this._html = getInnerHtml($, this.originalHtml!);\n        this._text = htmlToText(this._html).trim();\n        // Reset cached cheerio since HTML changed\n        this._cachedCheerio = null;\n        return true;\n      }\n\n      // Try to locate any class=\"*quote*\" and debug it\n      const quoteElements = $('[class*=\"quote\"]');\n      if (quoteElements.length) {\n        this.quoteFound($);\n      }\n\n      // Try to locate any class=\"*sign*\" and debug it\n      const signElements = $('[class*=\"sign\"]');\n      if (signElements.length) {\n        this.signFound($);\n      }\n    }\n\n    if (!this._text && this._html) {\n      this._text = htmlToText(this._html).trim();\n    }\n\n    // Content based data using regex\n    let match: RegExpMatchArray | null = null;\n    for (const pattern of patterns) {\n      if (this._text) {\n        match = this._text.match(pattern);\n        if (match) {\n          break;\n        }\n      }\n    }\n\n    if (!match) {\n      if (this._text) {\n        this.noPatternsFound(this._text);\n      }\n      return false;\n    }\n\n    // Get the index of the match\n    const matchIndex = this._text!.indexOf(match[0]);\n    this._text = this._text!.substring(0, matchIndex).trim();\n\n    if (this._html) {\n      // Use fresh cheerio load for manipulation after pattern match\n      const $fresh = cheerio.load(this._html);\n      let content = \"\";\n      let matchingTag: CheerioNode | null = null;\n      const lookupText = this.clearText(match[0]);\n\n      // Iterate through all text nodes\n      const textNodes: CheerioNode[] = [];\n      const collectTextNodes = (node: CheerioNode) => {\n        node.contents().each((_: number, el: any) => {\n          const $el = $fresh(el);\n          if (el.type === \"text\") {\n            textNodes.push($el);\n          } else if (el.type === \"tag\") {\n            collectTextNodes($el);\n          }\n        });\n      };\n      collectTextNodes($fresh.root());\n\n      for (const textNode of textNodes) {\n        const currentText = textNode.text();\n        if (!currentText) continue;\n\n        content += this.clearText(currentText);\n\n        if (content.includes(lookupText)) {\n          matchingTag = textNode;\n          break;\n        }\n      }\n\n      if (matchingTag) {\n        // Capture elements after the matching tag's parent before removing\n        const afterElements = matchingTag.parent().nextAll();\n        const capturedAfter: string[] = [];\n        afterElements.each((_: number, el: any) => {\n          capturedAfter.push($fresh.html(el));\n        });\n        afterElements.remove();\n\n        // Also capture and remove the blockquote that follows if present\n        const blockquoteAfter = matchingTag.parent().next(\"blockquote\");\n        if (blockquoteAfter.length) {\n          capturedAfter.push($fresh.html(blockquoteAfter));\n          blockquoteAfter.remove();\n        }\n\n        // Go up from the text node until we find an element that contains ONLY the quote\n        // If findIndex === 0, the element contains only the quote, remove it\n        // If findIndex > 0, the element has other content, keep the previous element\n        let currentTag: CheerioNode | null = matchingTag;\n        let previousTag: CheerioNode | null = null;\n        let found = false;\n        let tagToRemove: CheerioNode | null = null;\n\n        while (currentTag && currentTag.length) {\n          const tagContent = currentTag.text();\n          const clearedContent = this.clearText(tagContent);\n          const findIndex = clearedContent.indexOf(lookupText);\n\n          if (findIndex === 0) {\n            // This element contains only the quote text\n            // Keep traversing up to find the highest element that only contains quote\n            tagToRemove = currentTag;\n            previousTag = currentTag;\n            currentTag = currentTag.parent();\n            found = true;\n          } else if (findIndex > 0) {\n            // This element has other content before the quote\n            // Remove the previous element (which only had quote)\n            if (tagToRemove) {\n              found = true;\n            }\n            break;\n          } else {\n            // Quote not found at all - shouldn't happen\n            break;\n          }\n        }\n\n        if (found && tagToRemove && tagToRemove.length) {\n          // Check if it's not the root\n          const tagName = tagToRemove.prop(\"tagName\");\n          if (\n            tagName &&\n            tagName.toLowerCase() !== \"html\" &&\n            tagName.toLowerCase() !== \"body\"\n          ) {\n            // Capture the quote HTML before removing\n            this._quoteHtml = $fresh.html(tagToRemove) + capturedAfter.join(\"\");\n\n            const parentOfRemoved: CheerioNode | null = tagToRemove.parent();\n            tagToRemove.remove();\n\n            // Clean up empty parent elements\n            let current = parentOfRemoved;\n            while (current && current.length) {\n              const currentTagName = current.prop(\"tagName\");\n              if (\n                !currentTagName ||\n                currentTagName.toLowerCase() === \"html\" ||\n                currentTagName.toLowerCase() === \"body\"\n              ) {\n                break;\n              }\n\n              if (!current.text().trim() && !current.find(\"img\").length) {\n                const nextParent = current.parent();\n                current.remove();\n                current = nextParent;\n              } else {\n                break;\n              }\n            }\n          }\n        } else if (capturedAfter.length) {\n          // If no tag to remove but we captured after elements, store them as quote\n          this._quoteHtml = capturedAfter.join(\"\");\n        }\n\n        this._html = getInnerHtml($fresh, this.originalHtml!);\n      } else {\n        // Rebuild the html from the text\n        this._html = this.textToHtml(this._text);\n      }\n    }\n\n    // Reset cached cheerio since HTML may have changed\n    this._cachedCheerio = null;\n    return true;\n  }\n\n  textToHtml(data: string | null): string | null {\n    if (!data) {\n      return null;\n    }\n\n    return (marked.parse(data, { async: false }) as string).trim();\n  }\n\n  /** Override this method to handle cases when a quote class is found but not processed */\n  protected quoteFound(_$: CheerioAPI): void {\n    // Can be overridden\n  }\n\n  /** Override this method to handle cases when a signature class is found but not processed */\n  protected signFound(_$: CheerioAPI): void {\n    // Can be overridden\n  }\n\n  /** Override this method to handle cases when no patterns matched */\n  protected noPatternsFound(_text: string): void {\n    // Can be overridden\n  }\n}\n\nexport class VerboseUnquote extends Unquote {\n  protected quoteFound($: CheerioAPI): void {\n    console.log(\"Quote found in HTML structure\");\n    console.log($.html().substring(0, 100));\n  }\n\n  protected signFound($: CheerioAPI): void {\n    console.log(\"Signature found in HTML structure\");\n    console.log($.html().substring(0, 100));\n  }\n\n  protected noPatternsFound(text: string): void {\n    console.log(\"No patterns found in text\");\n    console.log(text.substring(0, 100));\n  }\n}\n","/**\n * Regex patterns for detecting email quote headers in various languages and formats\n *\n * @see https://github.com/crisp-oss/email-reply-parser/blob/master/lib/regex.js\n * @see https://github.com/mailgun/talon/blob/master/talon/quotations.py\n */\n\nexport const patterns: RegExp[] = [\n  // English\n  // On DATE, NAME <EMAIL> wrote:\n  /^>*-*\\s*((on|in a message dated)\\s.+\\s.+?(wrote|sent)\\s*:)\\s?-*/im,\n\n  // French\n  /^>*-*\\s*((le)\\s.+\\s.+?(écrit)\\s*:)\\s?/im,\n\n  // Spanish\n  /^>*-*\\s*((el)\\s.+\\s.+?(escribió)\\s*:)\\s?/im,\n\n  // Italian\n  /^>*-*\\s*((il)\\s.+\\s.+?(scritto)\\s*:)\\s?/im,\n\n  // Portuguese\n  /^>*-*\\s*((em)\\s.+\\s.+?(escreveu)\\s*:)\\s?/im,\n\n  // German\n  // Am DATE schrieb NAME <EMAIL>:\n  /^\\s*(am\\s.+\\s)schrieb.+\\s?(\\[|<).+(\\]|>):/im,\n\n  // Dutch\n  // Il DATE, schreef NAME <EMAIL>:\n  /^\\s*(op\\s[\\s\\S]+?(schreef|verzond|geschreven)[\\s\\S]+:)/im,\n\n  // Polish\n  // W dniu DATE, NAME <EMAIL> pisze|napisał:\n  /^\\s*((w\\sdniu|dnia)\\s[\\s\\S]+?(pisze|napisał(\\(a\\))?):)/im,\n\n  // Swedish, Danish\n  // Den DATE skrev NAME <EMAIL>:\n  /^\\s*(den|d.)?\\s?.+\\s?skrev\\s?\".+\"\\s*[\\[|<].+[\\]|>]\\s?:/im,\n\n  // Vietnamese\n  // Vào DATE đã viết NAME <EMAIL>:\n  /^\\s*(vào\\s.+\\sđã viết\\s.+:)/im,\n\n  // Outlook 2019 (no)\n  /^\\s?.+\\s*[\\[|<].+[\\]|>]\\s?skrev følgende den\\s?.+\\s?:/m,\n\n  // Outlook 2019 (cz)\n  /^\\s?dne\\s?.+\\,\\s?.+\\s*[\\[|<].+[\\]|>]\\s?napsal\\(a\\)\\s?:/im,\n\n  // Outlook 2019 (ru)\n  /^\\s?.+\\s?пользователь\\s?\".+\"\\s*[\\[|<].+[\\]|>]\\s?написал\\s?:/im,\n\n  // Outlook 2019 (sk)\n  /^\\s?.+\\s?používateľ\\s?.+\\s*\\([\\[|<].+[\\]|>]\\)\\s?napísal\\s?:/im,\n\n  // Outlook 2019 (sv)\n  /\\s?Den\\s?.+\\s?skrev\\s?\".+\"\\s*[\\[|<].+[\\]|>]\\s?følgende\\s?:/m,\n\n  // Outlook 2019 (tr)\n  /^\\s?\".+\"\\s*[\\[|<].+[\\]|>]\\,\\s?.+\\s?tarihinde şunu yazdı\\s?:/im,\n\n  // Outlook 2019 (hu)\n  /^\\s?.+\\s?időpontban\\s?.+\\s*[\\[|<|(].+[\\]|>|)]\\s?ezt írta\\s?:/im,\n\n  // ----------------------------\n\n  // pe DATE NAME <EMAIL> kirjoitti:\n  /^\\s*(pe\\s.+\\s.+kirjoitti:)/im,\n\n  // > 在 DATE, TIME, NAME 写道：\n  /^(在[\\s\\S]+写道：)/m,\n\n  // NAME <EMAIL> schrieb:\n  /^(.+\\s<.+>\\sschrieb\\s?:)/im,\n\n  // NAME on DATE wrote:\n  /^(.+\\son.*at.*wrote:)/im,\n\n  // \"From: NAME <EMAIL>\" OR \"From : NAME <EMAIL>\" OR \"From : NAME<EMAIL>\"\n  /^\\s*((from|van|de|von|da)\\s?:.+\\s?\\n?\\s*(\\[|<).+(\\]|>))/im,\n\n  // ##########################\n  // # Date starting patterns #\n  // ##########################\n\n  // DATE TIME NAME 작성:\n  /^(20[0-9]{2}\\..+\\s작성:)$/m,\n\n  // DATE TIME、NAME のメッセージ:\n  /^(20[0-9]{2}\\/.+のメッセージ:)/m,\n\n  // 20YY-MM-DD HH:II GMT+01:00 NAME <EMAIL>:\n  /^(20[0-9]{2})-([0-9]{2}).([0-9]{2}).([0-9]{2}):([0-9]{2})\\n?(.*)>:/m,\n\n  // DD.MM.20YY HH:II NAME <EMAIL>\n  /^([0-9]{2}).([0-9]{2}).(20[0-9]{2})(.*)(([0-9]{2}).([0-9]{2}))(.*)\"( *)<(.*)>( *):/m,\n\n  // HH:II, DATE, NAME <EMAIL>:\n  /^[0-9]{2}:[0-9]{2}(.*)[0-9]{4}(.*)\"( *)<(.*)>( *):/m,\n\n  // 02.04.2012 14:20 пользователь \"bob@example.com\" <bob@xxx.mailgun.org> написал:\n  /(\\d+\\/\\d+\\/\\d+|\\d+\\.\\d+\\.\\d+).*\\s\\S+@\\S+:/s,\n\n  // 2014-10-17 11:28 GMT+03:00 Bob <bob@example.com>:\n  /\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}\\s+GMT.*\\s\\S+@\\S+:/is,\n\n  // Thu, 26 Jun 2014 14:00:51 +0400 Bob <bob@example.com>:\n  /\\S{3,10}, \\d\\d? \\S{3,10} 20\\d\\d,? \\d\\d?:\\d\\d(:\\d\\d)?( \\S+){3,6}@\\S+:/,\n\n  // martes, 8 de abril de 2025, 9:56:16 -0400, Alice Bob <alice.b@example.com>:\n  /(lunes|martes|miércoles|miercoles|jueves|viernes|sábado|sabado|domingo),\\s*\\d{1,2}\\s+de\\s+[A-Za-záéíóúñ]+(?:\\s+de)?\\s+20\\d{2},\\s*\\d{1,2}:\\d{2}:\\d{2}\\s+[+-]\\d{4},\\s+.+\\s<[^>]+>:\\s*/is,\n\n  // ############################\n  // # Dash Delimiters patterns #\n  // ############################\n\n  // English\n  // Original Message delimiter\n  new RegExp(\n    `^>?\\\\s*-{3,12}\\\\s*(${[\n      'original message',\n      'reply message',\n      'original text',\n      \"message d'origine\",\n      'original email',\n      'ursprüngliche nachricht',\n      'original meddelelse',\n      'original besked',\n      'original message',\n      'original meddelande',\n      'originalbericht',\n      'originalt meddelande',\n      'originalt melding',\n      'alkuperäinen viesti',\n      'alkuperäinen viesti',\n      'originalna poruka',\n      'originalna správa',\n      'originálna správa',\n      'originální zpráva',\n      'původní zpráva',\n      'antwort nachricht',\n      'oprindelig besked',\n      'oprindelig meddelelse',\n    ].join('|')})\\\\s*-{3,12}\\\\s*`,\n    'im'\n  ),\n];\n","import * as cheerio from \"cheerio\";\n\n/**\n * Simple HTML to text converter\n * Mimics the behavior of Python's html2text library\n */\nexport function htmlToText(html: string): string {\n  const $ = cheerio.load(html);\n\n  // Remove script and style elements\n  $(\"script, style, head\").remove();\n\n  // Handle line breaks\n  $(\"br\").replaceWith(\"\\n\");\n\n  // Handle paragraphs and divs\n  $(\"p, div\").each((_, el) => {\n    const $el = $(el);\n    $el.prepend(\"\\n\");\n    $el.append(\"\\n\");\n  });\n\n  // Handle headers\n  $(\"h1, h2, h3, h4, h5, h6\").each((_, el) => {\n    const $el = $(el);\n    $el.prepend(\"\\n\\n\");\n    $el.append(\"\\n\\n\");\n  });\n\n  // Handle lists\n  $(\"li\").each((_, el) => {\n    const $el = $(el);\n    $el.prepend(\"* \");\n    $el.append(\"\\n\");\n  });\n\n  $(\"ul, ol\").each((_, el) => {\n    const $el = $(el);\n    $el.prepend(\"\\n\");\n    $el.append(\"\\n\");\n  });\n\n  // Handle blockquotes\n  $(\"blockquote\").each((_, el) => {\n    const $el = $(el);\n    const text = $el.text();\n    const quotedText = text\n      .split(\"\\n\")\n      .map((line) => `> ${line}`)\n      .join(\"\\n\");\n    $el.text(quotedText);\n    $el.prepend(\"\\n\");\n    $el.append(\"\\n\");\n  });\n\n  // Handle links - keep the text\n  $(\"a\").each((_, el) => {\n    const $el = $(el);\n    const href = $el.attr(\"href\");\n    const text = $el.text();\n    if (href && text && href !== text) {\n      $el.text(`${text} (${href})`);\n    }\n  });\n\n  // Get text content\n  let text = $.text();\n\n  // Clean up whitespace\n  text = text\n    // Replace multiple spaces with single space\n    .replace(/[ \\t]+/g, \" \")\n    // Replace multiple newlines with double newline\n    .replace(/\\n{3,}/g, \"\\n\\n\")\n    // Trim each line\n    .split(\"\\n\")\n    .map((line) => line.trim())\n    .join(\"\\n\")\n    // Final trim\n    .trim();\n\n  // Escape markdown characters like Python's html2text does\n  // This prevents false pattern matches on content that looks like quote headers\n  text = text\n    // Escape leading dashes (horizontal rules)\n    .replace(/^(---+)/gm, \"\\\\$1\")\n    // Escape leading hash (headers)\n    .replace(/^(#+)/gm, \"\\\\$1\");\n\n  return text;\n}\n","import { NodeHtmlMarkdown } from 'node-html-markdown';\n\n// Factory translator for td/th: adds ' | ' separator between cells in the same row\n// Uses postprocess to trim block-level whitespace (e.g. <p> inside <td>) before the pipe\nconst cellTranslator = (ctx: any) => ({\n  surroundingNewlines: false,\n  postfix: ctx.node.nextElementSibling ? ' | ' : '',\n  postprocess: ({ content }: { content: string }) => content.trim(),\n});\n\n// Cleans up dangling pipes from empty cells in a row\nconst cleanRowPipes = ({ content }: { content: string }) =>\n  content\n    .replace(/ \\|(\\s*\\|)+/g, ' |') // consecutive pipes from empty middle cells\n    .replace(/ \\|\\s*$/, '')          // trailing pipe from empty last cell\n    .replace(/^\\s*\\| /, '');         // leading pipe from empty first cell\n\n// Create instance with custom translators for email HTML\nconst nhm = new NodeHtmlMarkdown(\n  {\n    // Ignore non-content elements\n    ignore: ['head', 'script', 'style', 'meta', 'link'],\n  },\n  {\n    // Custom translators - unwrap table elements (email layout tables)\n    // Single-cell rows render as plain text; multi-cell rows use ' | ' between cells\n    table: { preserveWhitespace: true },\n    thead: {},\n    tbody: {},\n    tr: { postfix: '\\n', postprocess: cleanRowPipes },\n    th: cellTranslator,\n    td: cellTranslator,\n  }\n);\n\n/**\n * Convert HTML to Markdown using node-html-markdown\n * Optimized for email HTML which often uses tables for layout\n */\nexport function htmlToMarkdown(html: string): string {\n  return nhm.translate(html);\n}\n","import * as htmlparser2 from \"htmlparser2\";\n\n/**\n * Clean messy email HTML using a SAX parser.\n * Removes noise/metadata while preserving content.\n *\n * This is faster than Cheerio (no DOM) and safer than Regex (correct parsing).\n */\nexport function cleanEmailHtml(rawHtml: string): string {\n  if (!rawHtml) return \"\";\n\n  let output = \"\";\n  let depth = 0;\n\n  // Track if we're inside tags we want to skip entirely\n  let skipDepth = 0;\n\n  // Tags to skip entirely (with all their content)\n  const skipTags = new Set([\n    \"head\",\n    \"meta\",\n    \"style\",\n    \"script\",\n    \"xml\",\n    \"title\",\n    \"link\",\n    \"o:p\",\n  ]);\n\n  // Void tags (self-closing)\n  const voidTags = new Set([\"img\", \"br\", \"hr\", \"input\", \"meta\", \"link\"]);\n\n  // Check if we have a body tag - if not, capture everything\n  const hasBodyTag = /<body/i.test(rawHtml);\n  let capturing = !hasBodyTag;\n  let insideBody = false;\n\n  const parser = new htmlparser2.Parser(\n    {\n      onopentag(name, attribs) {\n        const lowerName = name.toLowerCase();\n\n        // Handle body tag\n        if (lowerName === \"body\") {\n          capturing = true;\n          insideBody = true;\n          return;\n        }\n\n        // Track skip depth for nested skipped tags\n        if (skipTags.has(lowerName) || lowerName.includes(\":\")) {\n          skipDepth++;\n          return;\n        }\n\n        if (!capturing || skipDepth > 0) return;\n\n        // Build cleaned attributes\n        let newAttribs = \"\";\n\n        for (const [key, value] of Object.entries(attribs)) {\n          const lowerKey = key.toLowerCase();\n\n          // Skip unwanted attributes\n          if (lowerKey === \"class\" || lowerKey === \"lang\") continue;\n          if (lowerKey.startsWith(\"xmlns\")) continue;\n          if (lowerKey.startsWith(\"o:\") || lowerKey.startsWith(\"v:\")) continue;\n          if (lowerKey.startsWith(\"data-\")) continue;\n\n          // Clean style attribute\n          if (lowerKey === \"style\") {\n            const cleanStyle = value\n              .split(\";\")\n              .filter((prop) => {\n                const [p] = prop.split(\":\");\n                const propName = p?.trim().toLowerCase();\n                if (!propName) return false;\n                // Remove MSO and font properties\n                if (propName.startsWith(\"mso-\")) return false;\n                if (propName.startsWith(\"font-\")) return false;\n                if (propName === \"line-height\") return false;\n                if (propName.includes(\"autospace\")) return false;\n                return true;\n              })\n              .join(\";\")\n              .trim();\n\n            if (cleanStyle) {\n              newAttribs += ` style=\"${cleanStyle}\"`;\n            }\n            continue;\n          }\n\n          // Keep other attributes (href, src, id, etc.)\n          const escapedValue = value.replace(/\"/g, \"&quot;\");\n          newAttribs += ` ${key}=\"${escapedValue}\"`;\n        }\n\n        if (voidTags.has(lowerName)) {\n          output += `<${name}${newAttribs} />`;\n        } else {\n          output += `<${name}${newAttribs}>`;\n          depth++;\n        }\n      },\n\n      ontext(text) {\n        if (capturing && skipDepth === 0) {\n          output += text;\n        }\n      },\n\n      onclosetag(name) {\n        const lowerName = name.toLowerCase();\n\n        if (lowerName === \"body\") {\n          capturing = false;\n          insideBody = false;\n          return;\n        }\n\n        // Track skip depth\n        if (skipTags.has(lowerName) || lowerName.includes(\":\")) {\n          if (skipDepth > 0) skipDepth--;\n          return;\n        }\n\n        if (!capturing || skipDepth > 0) return;\n\n        // Don't close void tags\n        if (voidTags.has(lowerName)) return;\n\n        output += `</${name}>`;\n        depth--;\n      },\n\n      oncomment() {\n        // Ignore all comments (including MSO conditionals)\n      },\n    },\n    { decodeEntities: true, xmlMode: false }\n  );\n\n  parser.write(rawHtml);\n  parser.end();\n\n  return output.trim();\n}\n"],"mappings":";AAAA,YAAYA,cAAa;AAEzB,SAAS,cAAc;;;ACKhB,IAAM,WAAqB;AAAA;AAAA;AAAA,EAGhC;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA;AAAA,EAIA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA,EAKA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI;AAAA,IACF,sBAAsB;AAAA,MACpB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,GAAG,CAAC;AAAA,IACX;AAAA,EACF;AACF;;;ACnJA,YAAY,aAAa;AAMlB,SAAS,WAAW,MAAsB;AAC/C,QAAM,IAAY,aAAK,IAAI;AAG3B,IAAE,qBAAqB,EAAE,OAAO;AAGhC,IAAE,IAAI,EAAE,YAAY,IAAI;AAGxB,IAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,OAAO;AAC1B,UAAM,MAAM,EAAE,EAAE;AAChB,QAAI,QAAQ,IAAI;AAChB,QAAI,OAAO,IAAI;AAAA,EACjB,CAAC;AAGD,IAAE,wBAAwB,EAAE,KAAK,CAAC,GAAG,OAAO;AAC1C,UAAM,MAAM,EAAE,EAAE;AAChB,QAAI,QAAQ,MAAM;AAClB,QAAI,OAAO,MAAM;AAAA,EACnB,CAAC;AAGD,IAAE,IAAI,EAAE,KAAK,CAAC,GAAG,OAAO;AACtB,UAAM,MAAM,EAAE,EAAE;AAChB,QAAI,QAAQ,IAAI;AAChB,QAAI,OAAO,IAAI;AAAA,EACjB,CAAC;AAED,IAAE,QAAQ,EAAE,KAAK,CAAC,GAAG,OAAO;AAC1B,UAAM,MAAM,EAAE,EAAE;AAChB,QAAI,QAAQ,IAAI;AAChB,QAAI,OAAO,IAAI;AAAA,EACjB,CAAC;AAGD,IAAE,YAAY,EAAE,KAAK,CAAC,GAAG,OAAO;AAC9B,UAAM,MAAM,EAAE,EAAE;AAChB,UAAMC,QAAO,IAAI,KAAK;AACtB,UAAM,aAAaA,MAChB,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,IAAI,EAAE,EACzB,KAAK,IAAI;AACZ,QAAI,KAAK,UAAU;AACnB,QAAI,QAAQ,IAAI;AAChB,QAAI,OAAO,IAAI;AAAA,EACjB,CAAC;AAGD,IAAE,GAAG,EAAE,KAAK,CAAC,GAAG,OAAO;AACrB,UAAM,MAAM,EAAE,EAAE;AAChB,UAAM,OAAO,IAAI,KAAK,MAAM;AAC5B,UAAMA,QAAO,IAAI,KAAK;AACtB,QAAI,QAAQA,SAAQ,SAASA,OAAM;AACjC,UAAI,KAAK,GAAGA,KAAI,KAAK,IAAI,GAAG;AAAA,IAC9B;AAAA,EACF,CAAC;AAGD,MAAI,OAAO,EAAE,KAAK;AAGlB,SAAO,KAEJ,QAAQ,WAAW,GAAG,EAEtB,QAAQ,WAAW,MAAM,EAEzB,MAAM,IAAI,EACV,IAAI,CAAC,SAAS,KAAK,KAAK,CAAC,EACzB,KAAK,IAAI,EAET,KAAK;AAIR,SAAO,KAEJ,QAAQ,aAAa,MAAM,EAE3B,QAAQ,WAAW,MAAM;AAE5B,SAAO;AACT;;;AC1FA,SAAS,wBAAwB;AAIjC,IAAM,iBAAiB,CAAC,SAAc;AAAA,EACpC,qBAAqB;AAAA,EACrB,SAAS,IAAI,KAAK,qBAAqB,QAAQ;AAAA,EAC/C,aAAa,CAAC,EAAE,QAAQ,MAA2B,QAAQ,KAAK;AAClE;AAGA,IAAM,gBAAgB,CAAC,EAAE,QAAQ,MAC/B,QACG,QAAQ,gBAAgB,IAAI,EAC5B,QAAQ,WAAW,EAAE,EACrB,QAAQ,WAAW,EAAE;AAG1B,IAAM,MAAM,IAAI;AAAA,EACd;AAAA;AAAA,IAEE,QAAQ,CAAC,QAAQ,UAAU,SAAS,QAAQ,MAAM;AAAA,EACpD;AAAA,EACA;AAAA;AAAA;AAAA,IAGE,OAAO,EAAE,oBAAoB,KAAK;AAAA,IAClC,OAAO,CAAC;AAAA,IACR,OAAO,CAAC;AAAA,IACR,IAAI,EAAE,SAAS,MAAM,aAAa,cAAc;AAAA,IAChD,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AACF;AAMO,SAAS,eAAe,MAAsB;AACnD,SAAO,IAAI,UAAU,IAAI;AAC3B;;;ACzCA,YAAY,iBAAiB;AAQtB,SAAS,eAAe,SAAyB;AACtD,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,SAAS;AACb,MAAI,QAAQ;AAGZ,MAAI,YAAY;AAGhB,QAAM,WAAW,oBAAI,IAAI;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAGD,QAAM,WAAW,oBAAI,IAAI,CAAC,OAAO,MAAM,MAAM,SAAS,QAAQ,MAAM,CAAC;AAGrE,QAAM,aAAa,SAAS,KAAK,OAAO;AACxC,MAAI,YAAY,CAAC;AACjB,MAAI,aAAa;AAEjB,QAAM,SAAS,IAAgB;AAAA,IAC7B;AAAA,MACE,UAAU,MAAM,SAAS;AACvB,cAAM,YAAY,KAAK,YAAY;AAGnC,YAAI,cAAc,QAAQ;AACxB,sBAAY;AACZ,uBAAa;AACb;AAAA,QACF;AAGA,YAAI,SAAS,IAAI,SAAS,KAAK,UAAU,SAAS,GAAG,GAAG;AACtD;AACA;AAAA,QACF;AAEA,YAAI,CAAC,aAAa,YAAY,EAAG;AAGjC,YAAI,aAAa;AAEjB,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,GAAG;AAClD,gBAAM,WAAW,IAAI,YAAY;AAGjC,cAAI,aAAa,WAAW,aAAa,OAAQ;AACjD,cAAI,SAAS,WAAW,OAAO,EAAG;AAClC,cAAI,SAAS,WAAW,IAAI,KAAK,SAAS,WAAW,IAAI,EAAG;AAC5D,cAAI,SAAS,WAAW,OAAO,EAAG;AAGlC,cAAI,aAAa,SAAS;AACxB,kBAAM,aAAa,MAChB,MAAM,GAAG,EACT,OAAO,CAAC,SAAS;AAChB,oBAAM,CAAC,CAAC,IAAI,KAAK,MAAM,GAAG;AAC1B,oBAAM,WAAW,GAAG,KAAK,EAAE,YAAY;AACvC,kBAAI,CAAC,SAAU,QAAO;AAEtB,kBAAI,SAAS,WAAW,MAAM,EAAG,QAAO;AACxC,kBAAI,SAAS,WAAW,OAAO,EAAG,QAAO;AACzC,kBAAI,aAAa,cAAe,QAAO;AACvC,kBAAI,SAAS,SAAS,WAAW,EAAG,QAAO;AAC3C,qBAAO;AAAA,YACT,CAAC,EACA,KAAK,GAAG,EACR,KAAK;AAER,gBAAI,YAAY;AACd,4BAAc,WAAW,UAAU;AAAA,YACrC;AACA;AAAA,UACF;AAGA,gBAAM,eAAe,MAAM,QAAQ,MAAM,QAAQ;AACjD,wBAAc,IAAI,GAAG,KAAK,YAAY;AAAA,QACxC;AAEA,YAAI,SAAS,IAAI,SAAS,GAAG;AAC3B,oBAAU,IAAI,IAAI,GAAG,UAAU;AAAA,QACjC,OAAO;AACL,oBAAU,IAAI,IAAI,GAAG,UAAU;AAC/B;AAAA,QACF;AAAA,MACF;AAAA,MAEA,OAAO,MAAM;AACX,YAAI,aAAa,cAAc,GAAG;AAChC,oBAAU;AAAA,QACZ;AAAA,MACF;AAAA,MAEA,WAAW,MAAM;AACf,cAAM,YAAY,KAAK,YAAY;AAEnC,YAAI,cAAc,QAAQ;AACxB,sBAAY;AACZ,uBAAa;AACb;AAAA,QACF;AAGA,YAAI,SAAS,IAAI,SAAS,KAAK,UAAU,SAAS,GAAG,GAAG;AACtD,cAAI,YAAY,EAAG;AACnB;AAAA,QACF;AAEA,YAAI,CAAC,aAAa,YAAY,EAAG;AAGjC,YAAI,SAAS,IAAI,SAAS,EAAG;AAE7B,kBAAU,KAAK,IAAI;AACnB;AAAA,MACF;AAAA,MAEA,YAAY;AAAA,MAEZ;AAAA,IACF;AAAA,IACA,EAAE,gBAAgB,MAAM,SAAS,MAAM;AAAA,EACzC;AAEA,SAAO,MAAM,OAAO;AACpB,SAAO,IAAI;AAEX,SAAO,OAAO,KAAK;AACrB;;;AJlIA,IAAM,mBAAmB;AAKzB,SAAS,yBAAyB,MAAmC;AACnE,QAAM,SAAS,oBAAI,IAAoB;AACvC,QAAM,WAAW;AACjB,MAAI;AACJ,UAAQ,QAAQ,SAAS,KAAK,IAAI,OAAO,MAAM;AAC7C,UAAM,UAAU,MAAM,CAAC;AACvB,UAAM,WAAW,QAAQ,YAAY;AAErC,QAAI,CAAC,OAAO,IAAI,QAAQ,GAAG;AACzB,aAAO,IAAI,UAAU,OAAO;AAAA,IAC9B;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,iBACP,MACA,gBACQ;AACR,MAAI,SAAS;AACb,aAAW,CAAC,UAAU,WAAW,KAAK,gBAAgB;AACpD,QAAI,aAAa,aAAa;AAE5B,eAAS,OAAO;AAAA,QACd,IAAI,OAAO,IAAI,QAAQ,eAAe,IAAI;AAAA,QAC1C,CAAC,UAAU,IAAI,WAAW,GAAG,MAAM,MAAM,SAAS,SAAS,CAAC,CAAC;AAAA,MAC/D;AAEA,eAAS,OAAO;AAAA,QACd,IAAI,OAAO,KAAK,QAAQ,KAAK,IAAI;AAAA,QACjC,KAAK,WAAW;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAMA,SAAS,aAAa,GAAe,cAA8B;AAEjE,QAAM,iBAAiB,yBAAyB,YAAY;AAG5D,QAAM,aAAa,cAAc,KAAK,YAAY;AAClD,QAAM,aAAa,cAAc,KAAK,YAAY;AAClD,QAAM,aAAa,cAAc,KAAK,YAAY;AAGlD,QAAM,qBACJ,aAAa,MAAM,0BAA0B,IAAI,CAAC,KAAK;AACzD,QAAM,sBACJ,aAAa,MAAM,0BAA0B,IAAI,CAAC,KAAK;AAEzD,MAAI;AACJ,MAAI,cAAc,YAAY;AAE5B,WAAO,EAAE,KAAK;AAGd,QAAI,CAAC,YAAY;AACf,aAAO,KAAK,QAAQ,mBAAmB,EAAE;AAAA,IAC3C;AAGA,QAAI,oBAAoB;AACtB,aAAO,KAAK;AAAA,QACV;AAAA,QACA,WAAW,kBAAkB;AAAA,MAC/B;AAAA,IACF;AACA,QAAI,qBAAqB;AACvB,aAAO,KAAK;AAAA,QACV;AAAA,QACA,UAAU,mBAAmB;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,OAAO;AAEL,WAAO,EAAE,MAAM,EAAE,KAAK,KAAK;AAAA,EAC7B;AAGA,SAAO,KAAK,QAAQ,UAAU,OAAO;AACrC,SAAO,KAAK,QAAQ,UAAU,OAAO;AAGrC,SAAO,KAAK,QAAQ,WAAW,UAAU;AAGzC,SAAO,iBAAiB,MAAM,cAAc;AAE5C,SAAO,KAAK,KAAK;AACnB;AAEO,IAAM,UAAN,MAAc;AAAA,EAWnB,YAAY,MAAqB,MAAqB;AARtD,SAAQ,QAAuB;AAC/B,SAAQ,aAA4B;AACpC,SAAQ,QAAuB;AAC/B,SAAQ,YAA2B;AACnC,SAAQ,aAA4B;AACpC,SAAQ,UAAmB;AAC3B,SAAQ,iBAAoC;AAG1C,QAAI,CAAC,QAAQ,CAAC,MAAM;AAClB,YAAM,IAAI,MAAM,+CAA+C;AAAA,IACjE;AAEA,SAAK,eAAe,OAAO,KAAK,QAAQ,SAAS,GAAG,IAAI;AACxD,SAAK,eAAe,OAAO,KAAK,QAAQ,SAAS,GAAG,IAAI;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAgC;AACtC,QAAI,CAAC,KAAK,aAAc,QAAO;AAC/B,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAyB,cAAK,KAAK,YAAY;AAAA,IACtD;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiB,MAAkB,UAA+B;AACxE,UAAM,WAAqB,CAAC;AAC5B,eAAW,MAAM,UAAU;AACzB,UAAI,MAAM,GAAG,QAAQ;AACnB,iBAAS,KAAK,EAAE,KAAK,EAAE,CAAC;AACxB,WAAG,OAAO;AAAA,MACZ;AAAA,IACF;AACA,QAAI,SAAS,QAAQ;AACnB,WAAK,aAAa,SAAS,KAAK,EAAE;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,QAAQ,UAA0B,CAAC,GAAkB;AACnD,UAAM,EAAE,MAAM,MAAM,IAAI;AAExB,SAAK,aAAa;AAElB,QAAI,KAAK,UAAU,MAAM;AACvB,UAAI,KAAK,cAAc;AACrB,aAAK,QAAQ,KAAK;AAAA,MACpB,WAAW,KAAK,cAAc;AAC5B,aAAK,QAAQ,KAAK,WAAW,KAAK,YAAY;AAAA,MAChD;AAAA,IACF;AAGA,QAAI,KAAK;AACP,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,KAAK,eAAe,QAAQ,KAAK,OAAO;AAC1C,WAAK,aAAa,eAAe,KAAK,KAAK;AAAA,IAC7C;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAyB;AACvB,SAAK,aAAa;AAClB,QAAI,KAAK,UAAU,MAAM;AACvB,UAAI,KAAK,cAAc;AACrB,aAAK,QAAQ,KAAK;AAAA,MACpB,WAAW,KAAK,cAAc;AAC5B,aAAK,QAAQ,WAAW,KAAK,YAAY,EAAE,KAAK;AAAA,MAClD;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,cAA6B;AAC3B,SAAK,aAAa;AAClB,QAAI,KAAK,cAAc,MAAM;AAE3B,YAAM,OAAO,KAAK,QAAQ;AAC1B,UAAI,MAAM;AACR,aAAK,YAAY,eAAe,IAAI,EAAE,KAAK;AAAA,MAC7C;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,UAA0B,CAAC,GAAkB;AACpD,UAAM,EAAE,MAAM,MAAM,IAAI;AACxB,SAAK,aAAa;AAClB,QAAI,CAAC,KAAK,WAAY,QAAO;AAC7B,WAAO,MAAM,KAAK,aAAa,eAAe,KAAK,UAAU;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAqB;AAC3B,QAAI,CAAC,KAAK,SAAS;AACjB,WAAK,MAAM;AAAA,IACb;AAAA,EACF;AAAA,EAEQ,UAAU,GAAwB;AAExC,UAAM,MAAM,EAAE,qBAAqB;AACnC,QAAI,IAAI,QAAQ;AACd,YAAM,cAAc,IAAI,KAAK,yBAAyB;AACtD,UAAI,YAAY,QAAQ;AACtB,aAAK,iBAAiB,GAAG,KAAK,WAAW;AACzC,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,YAAY,EAAE,qBAAqB;AACzC,QAAI,UAAU,QAAQ;AACpB,WAAK,iBAAiB,GAAG,SAAS;AAClC,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,EAAE,mBAAmB;AACnC,QAAI,MAAM,QAAQ;AAChB,WAAK,iBAAiB,GAAG,KAAK;AAC9B,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,EAAE,mBAAmB;AACrC,QAAI,QAAQ,QAAQ;AAClB,WAAK,iBAAiB,GAAG,OAAO;AAChC,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,EAAE,oBAAoB;AACvC,QAAI,SAAS,QAAQ;AACnB,WAAK,iBAAiB,GAAG,QAAQ;AACjC,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,EAAE,cAAc;AAChC,QAAI,QAAQ,QAAQ;AAClB,WAAK,iBAAiB,GAAG,OAAO;AAChC,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,EAAE,8BAA8B;AAC9C,QAAI,MAAM,QAAQ;AAChB,WAAK,iBAAiB,GAAG,KAAK;AAC9B,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,EAAE,aAAa;AAC7B,QAAI,MAAM,QAAQ;AAChB,YAAM,SAAS,MAAM,OAAO;AAC5B,YAAM,gBAAgB,OAAO,KAAK,OAAO,KAAK;AAC9C,UACE,cAAc,SAAS,uBAAuB,KAC9C,cAAc,SAAS,aAAa,GACpC;AACA,aAAK,iBAAiB,GAAG,MAAM;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,SAAS,EAAE,iBAAiB;AAClC,QAAI,OAAO,QAAQ;AACjB,YAAM,SAAS,OAAO,OAAO;AAC7B,YAAM,gBAAgB,OAAO,KAAK,OAAO,KAAK;AAC9C,UAAI,cAAc,SAAS,aAAa,GAAG;AACzC,aAAK,iBAAiB,GAAG,MAAM;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,gBAAgB,EAAE,wBAAwB;AAChD,QAAI,cAAc,QAAQ;AAExB,YAAM,YAAY,cAAc,QAAQ,iBAAiB;AACzD,UAAI,UAAU,QAAQ;AACpB,aAAK,iBAAiB,GAAG,SAAS;AAAA,MACpC,OAAO;AACL,aAAK,iBAAiB,GAAG,aAAa;AAAA,MACxC;AACA,aAAO;AAAA,IACT;AAGA,UAAM,eAAe,EAAE,iBAAiB;AACxC,QAAI,aAAa,QAAQ;AAEvB,YAAM,cAAc,aAAa,KAAK,EAAE,KAAK;AAC7C,UAAI,CAAC,eAAe,aAAa,SAAS,EAAE,WAAW,GAAG;AACxD,aAAK,iBAAiB,GAAG,YAAY;AACrC,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,QAAQ,EAAE,kBAAkB;AAClC,QAAI,MAAM,QAAQ;AAChB,WAAK,iBAAiB,GAAG,KAAK;AAC9B,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,EAAE,6BAA6B;AAC7C,QAAI,MAAM,QAAQ;AAChB,YAAM,UAAU,MAAM,QAAQ,EAAE,IAAI,eAAe;AACnD,WAAK,iBAAiB,GAAG,OAAO,OAAO;AACvC,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,EAAE,sBAAsB;AACvC,QAAI,OAAO,QAAQ;AACjB,YAAM,UAAU,OAAO,QAAQ,EAAE,IAAI,eAAe;AACpD,WAAK,iBAAiB,GAAG,QAAQ,OAAO;AACxC,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,EAAE,mBAAmB;AACrC,QAAI,QAAQ,QAAQ;AAClB,WAAK,iBAAiB,GAAG,OAAO;AAChC,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,EAAE,aAAa;AAChC,QAAI,SAAS,QAAQ;AACnB,WAAK,iBAAiB,GAAG,QAAQ;AACjC,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,EAAE,eAAe;AAC/B,QAAI,MAAM,QAAQ;AAChB,YAAM,aAAa,MAAM,KAAK,yBAAyB;AACvD,UAAI,WAAW,QAAQ;AACrB,aAAK,iBAAiB,GAAG,OAAO,UAAU;AAC1C,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,WAAW,EAAE,6CAA6C;AAChE,QAAI,SAAS,QAAQ;AACnB,WAAK,iBAAiB,GAAG,QAAQ;AACjC,aAAO;AAAA,IACT;AAKA,UAAM,sBAAsB,EAAE,0BAA0B;AACxD,QAAI,YAAyC;AAE7C,wBAAoB,KAAK,CAAC,GAAG,OAAO;AAClC,YAAM,YAAY,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO;AACxC,YAAM,YAAY,UAAU,KAAK,OAAO,KAAK;AAG7C,UAAI,qDAAqD,KAAK,SAAS,GAAG;AACxE,oBAAY,EAAE,EAAE;AAChB,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,QAAI,aAAa,EAAE,SAAS,EAAE,QAAQ;AACpC,YAAM,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO;AAC7C,YAAM,SAAS,QAAQ,KAAK,OAAO,KAAK,IACrC,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,IAAI;AAMtB,YAAM,kBAAkB,MACrB,QAAQ,YAAY,GAAG,EACvB,QAAQ,YAAY,GAAG,EACvB,QAAQ,QAAQ,GAAG,EACnB,KAAK;AACR,UAAI,gBAAgB,SAAS,kCAAkC,GAAG;AAChE,YAAI,OAAO;AACX,cAAM,iBAAiB,QAAQ,OAAO,EAAE,SAAS;AACjD,cAAM,eAAe,eAAe;AAAA,UAAO,CAAC,GAAG,OAC7C,EAAE,KAAK,EAAE,EAAE,WAAW,GAAG;AAAA,QAC3B;AAEA,YAAI,aAAa,WAAW,GAAG;AAC7B,iBAAO,QAAQ,OAAO;AAAA,QACxB;AAGA,cAAM,UAAU,KAAK,QAAQ;AAC7B,aAAK,aACH,EAAE,KAAK,IAAI,IACX,QACG,IAAI,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,EACzB,IAAI,EACJ,KAAK,EAAE;AACZ,gBAAQ,OAAO;AACf,aAAK,OAAO;AACZ,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,UAAU,EAAE,mBAAmB;AACrC,QAAI,QAAQ,QAAQ;AAClB,YAAM,SAAS,QAAQ,QAAQ,IAAI,EAAE,MAAM;AAC3C,UAAI,OAAO,QAAQ;AACjB,cAAM,UAAU,QAAQ,QAAQ;AAChC,aAAK,aACH,EAAE,KAAK,MAAM,IACb,EAAE,KAAK,OAAO,IACd,QACG,IAAI,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,EACzB,IAAI,EACJ,KAAK,EAAE;AACZ,gBAAQ,OAAO;AACf,gBAAQ,OAAO;AACf,eAAO,OAAO;AACd,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,SAAS,EAAE,mBAAmB;AACpC,QAAI,OAAO,QAAQ;AACjB,WAAK,iBAAiB,GAAG,MAAM;AAC/B,aAAO;AAAA,IACT;AAGA,UAAM,OAAO,EAAE,6BAA6B;AAC5C,QAAI,KAAK,QAAQ;AACf,WAAK,iBAAiB,GAAG,IAAI;AAC7B,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,EAAE,iBAAiB;AACjC,QAAI,MAAM,QAAQ;AAChB,YAAM,WAAW,MAAM,KAAK;AAC5B,UAAI,SAAS,SAAS,gBAAgB,GAAG;AACvC,aAAK,iBAAiB,GAAG,UAAU,KAAK;AAAA,MAC1C,OAAO;AACL,aAAK,iBAAiB,GAAG,KAAK;AAAA,MAChC;AACA,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,EAAE,4BAA4B;AAC9C,QAAI,QAAQ,QAAQ;AAClB,WAAK,iBAAiB,GAAG,QAAQ,OAAO,CAAC;AACzC,aAAO;AAAA,IACT;AAGA,UAAM,OAAO,EAAE,6BAA6B;AAC5C,QAAI,KAAK,QAAQ;AACf,YAAM,UAAU,KAAK,QAAQ;AAC7B,YAAM,cAAc,KAAK,KAAK;AAC9B,YAAM,aAAa,YAAY,KAAK,EAAE,KAAK,EAAE,WAAW,KAAK;AAE7D,WAAK,cACF,aAAa,EAAE,KAAK,WAAW,IAAI,MACpC,EAAE,KAAK,IAAI,IACX,QACG,IAAI,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC,EACzB,IAAI,EACJ,KAAK,EAAE;AACZ,cAAQ,OAAO;AACf,UAAI,YAAY;AACd,oBAAY,OAAO;AAAA,MACrB;AACA,WAAK,OAAO;AACZ,aAAO;AAAA,IACT;AAGA,UAAM,SAAS,EAAE,8BAA8B;AAC/C,QAAI,OAAO,QAAQ;AACjB,WAAK,iBAAiB,GAAG,MAAM;AAC/B,aAAO;AAAA,IACT;AAGA,UAAM,WAAW,EAAE,2BAA2B;AAC9C,QAAI,SAAS,QAAQ;AACnB,YAAM,UAAU,SAAS,KAAK,KAAK;AACnC,UAAI,QAAQ,QAAQ;AAClB,aAAK,iBAAiB,GAAG,SAAS,QAAQ;AAAA,MAC5C,OAAO;AACL,aAAK,iBAAiB,GAAG,QAAQ;AAAA,MACnC;AACA,aAAO;AAAA,IACT;AAGA,UAAM,MAAM,EAAE,4BAA4B;AAC1C,QAAI,IAAI,QAAQ;AACd,YAAM,KAAK,IAAI,KAAK,IAAI,KAAK;AAC7B,UAAI,GAAG,SAAS,cAAc,GAAG;AAC/B,aAAK,iBAAiB,GAAG,GAAG;AAC5B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,KAAK,EAAE,4BAA4B;AACzC,QAAI,GAAG,QAAQ;AACb,WAAK,iBAAiB,GAAG,EAAE;AAC3B,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,EAAE,mBAAmB;AACrC,QAAI,QAAQ,QAAQ;AAClB,YAAM,SAAS,QAAQ,OAAO;AAC9B,UAAI,OAAO,GAAG,YAAY,GAAG;AAC3B,aAAK,iBAAiB,GAAG,MAAM;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,QAAQ;AAAA,MACZ;AAAA,IACF;AACA,QAAI,MAAM,QAAQ;AAChB,YAAM,mBAAmB,MAAM,OAAO;AACtC,UAAI,kBAAkB,iBAAiB,KAAK;AAG5C,aAAO,gBAAgB,UAAU,CAAC,gBAAgB,GAAG,GAAG,GAAG;AACzD,0BAAkB,gBAAgB,KAAK;AAAA,MACzC;AAEA,UAAI,gBAAgB,UAAU,gBAAgB,KAAK,KAAK,GAAG;AACzD,cAAM,kBAAkB,gBAAgB,KAAK,YAAY;AACzD,YAAI,gBAAgB,QAAQ;AAC1B,eAAK,aAAa,EAAE,KAAK,eAAe,IAAI,EAAE,KAAK,gBAAgB;AACnE,0BAAgB,OAAO;AAAA,QACzB,OAAO;AACL,eAAK,aAAa,EAAE,KAAK,gBAAgB;AAAA,QAC3C;AAAA,MACF,OAAO;AACL,aAAK,aAAa,EAAE,KAAK,gBAAgB;AAAA,MAC3C;AAEA,uBAAiB,OAAO;AACxB,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,EAAE,8BAA8B;AAChD,QAAI,QAAQ,QAAQ;AAClB,YAAM,SAAS,QAAQ,OAAO;AAC9B,UAAI,OAAO,GAAG,YAAY,GAAG;AAC3B,aAAK,iBAAiB,GAAG,MAAM;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,SAAS,EAAE,mDAAmD;AACpE,QAAI,OAAO,QAAQ;AACjB,YAAM,aAAa,OAAO,QAAQ,YAAY;AAC9C,UAAI,WAAW,QAAQ;AACrB,cAAM,UAAU,WAAW,KAAK,KAAK;AACrC,YAAI,QAAQ,QAAQ;AAClB,gBAAM,mBAAmB,QAAQ,KAAK,yBAAyB;AAC/D,cAAI,iBAAiB,QAAQ;AAC3B,iBAAK,aAAa,EAAE,KAAK,OAAO,IAAI,EAAE,KAAK,UAAU;AACrD,oBAAQ,OAAO;AAAA,UACjB,OAAO;AACL,iBAAK,aAAa,EAAE,KAAK,UAAU;AAAA,UACrC;AAAA,QACF,OAAO;AACL,eAAK,aAAa,EAAE,KAAK,UAAU;AAAA,QACrC;AACA,mBAAW,OAAO;AAClB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,UAAM,SAAS,EAAE,wBAAwB;AACzC,QAAI,OAAO,QAAQ;AACjB,YAAM,SAAS,OAAO,OAAO;AAC7B,UAAI,OAAO,GAAG,YAAY,GAAG;AAC3B,aAAK,iBAAiB,GAAG,MAAM;AAAA,MACjC;AAAA,IACF;AAGA,UAAM,KAAK,EAAE,cAAc;AAC3B,QAAI,GAAG,QAAQ;AACb,WAAK,iBAAiB,GAAG,EAAE;AAAA,IAC7B;AAGA,UAAM,MAAM,EAAE,gBAAgB;AAC9B,QAAI,IAAI,QAAQ;AACd,YAAM,SAAS,IAAI,OAAO;AAC1B,YAAM,UAAU,OAAO,KAAK,SAAS,KAAK;AAC1C,UAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,aAAK,iBAAiB,GAAG,MAAM;AAC/B,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,UAAU,MAAsB;AACtC,WAAO,KAAK,QAAQ,kBAAkB,EAAE;AAAA,EAC1C;AAAA,EAEA,QAAiB;AACf,QAAI,KAAK,QAAS,QAAO;AACzB,SAAK,UAAU;AAEf,SAAK,QAAQ,KAAK;AAClB,SAAK,QAAQ,KAAK;AAElB,UAAM,IAAI,KAAK,WAAW;AAE1B,QAAI,KAAK,SAAS,GAAG;AACnB,UAAI,KAAK,UAAU,CAAC,GAAG;AACrB,aAAK,QAAQ,aAAa,GAAG,KAAK,YAAa;AAC/C,aAAK,QAAQ,WAAW,KAAK,KAAK,EAAE,KAAK;AAEzC,aAAK,iBAAiB;AACtB,eAAO;AAAA,MACT;AAGA,YAAM,gBAAgB,EAAE,kBAAkB;AAC1C,UAAI,cAAc,QAAQ;AACxB,aAAK,WAAW,CAAC;AAAA,MACnB;AAGA,YAAM,eAAe,EAAE,iBAAiB;AACxC,UAAI,aAAa,QAAQ;AACvB,aAAK,UAAU,CAAC;AAAA,MAClB;AAAA,IACF;AAEA,QAAI,CAAC,KAAK,SAAS,KAAK,OAAO;AAC7B,WAAK,QAAQ,WAAW,KAAK,KAAK,EAAE,KAAK;AAAA,IAC3C;AAGA,QAAI,QAAiC;AACrC,eAAW,WAAW,UAAU;AAC9B,UAAI,KAAK,OAAO;AACd,gBAAQ,KAAK,MAAM,MAAM,OAAO;AAChC,YAAI,OAAO;AACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,OAAO;AACV,UAAI,KAAK,OAAO;AACd,aAAK,gBAAgB,KAAK,KAAK;AAAA,MACjC;AACA,aAAO;AAAA,IACT;AAGA,UAAM,aAAa,KAAK,MAAO,QAAQ,MAAM,CAAC,CAAC;AAC/C,SAAK,QAAQ,KAAK,MAAO,UAAU,GAAG,UAAU,EAAE,KAAK;AAEvD,QAAI,KAAK,OAAO;AAEd,YAAM,SAAiB,cAAK,KAAK,KAAK;AACtC,UAAI,UAAU;AACd,UAAI,cAAkC;AACtC,YAAM,aAAa,KAAK,UAAU,MAAM,CAAC,CAAC;AAG1C,YAAM,YAA2B,CAAC;AAClC,YAAM,mBAAmB,CAAC,SAAsB;AAC9C,aAAK,SAAS,EAAE,KAAK,CAAC,GAAW,OAAY;AAC3C,gBAAM,MAAM,OAAO,EAAE;AACrB,cAAI,GAAG,SAAS,QAAQ;AACtB,sBAAU,KAAK,GAAG;AAAA,UACpB,WAAW,GAAG,SAAS,OAAO;AAC5B,6BAAiB,GAAG;AAAA,UACtB;AAAA,QACF,CAAC;AAAA,MACH;AACA,uBAAiB,OAAO,KAAK,CAAC;AAE9B,iBAAW,YAAY,WAAW;AAChC,cAAM,cAAc,SAAS,KAAK;AAClC,YAAI,CAAC,YAAa;AAElB,mBAAW,KAAK,UAAU,WAAW;AAErC,YAAI,QAAQ,SAAS,UAAU,GAAG;AAChC,wBAAc;AACd;AAAA,QACF;AAAA,MACF;AAEA,UAAI,aAAa;AAEf,cAAM,gBAAgB,YAAY,OAAO,EAAE,QAAQ;AACnD,cAAM,gBAA0B,CAAC;AACjC,sBAAc,KAAK,CAAC,GAAW,OAAY;AACzC,wBAAc,KAAK,OAAO,KAAK,EAAE,CAAC;AAAA,QACpC,CAAC;AACD,sBAAc,OAAO;AAGrB,cAAM,kBAAkB,YAAY,OAAO,EAAE,KAAK,YAAY;AAC9D,YAAI,gBAAgB,QAAQ;AAC1B,wBAAc,KAAK,OAAO,KAAK,eAAe,CAAC;AAC/C,0BAAgB,OAAO;AAAA,QACzB;AAKA,YAAI,aAAiC;AACrC,YAAI,cAAkC;AACtC,YAAI,QAAQ;AACZ,YAAI,cAAkC;AAEtC,eAAO,cAAc,WAAW,QAAQ;AACtC,gBAAM,aAAa,WAAW,KAAK;AACnC,gBAAM,iBAAiB,KAAK,UAAU,UAAU;AAChD,gBAAM,YAAY,eAAe,QAAQ,UAAU;AAEnD,cAAI,cAAc,GAAG;AAGnB,0BAAc;AACd,0BAAc;AACd,yBAAa,WAAW,OAAO;AAC/B,oBAAQ;AAAA,UACV,WAAW,YAAY,GAAG;AAGxB,gBAAI,aAAa;AACf,sBAAQ;AAAA,YACV;AACA;AAAA,UACF,OAAO;AAEL;AAAA,UACF;AAAA,QACF;AAEA,YAAI,SAAS,eAAe,YAAY,QAAQ;AAE9C,gBAAM,UAAU,YAAY,KAAK,SAAS;AAC1C,cACE,WACA,QAAQ,YAAY,MAAM,UAC1B,QAAQ,YAAY,MAAM,QAC1B;AAEA,iBAAK,aAAa,OAAO,KAAK,WAAW,IAAI,cAAc,KAAK,EAAE;AAElE,kBAAM,kBAAsC,YAAY,OAAO;AAC/D,wBAAY,OAAO;AAGnB,gBAAI,UAAU;AACd,mBAAO,WAAW,QAAQ,QAAQ;AAChC,oBAAM,iBAAiB,QAAQ,KAAK,SAAS;AAC7C,kBACE,CAAC,kBACD,eAAe,YAAY,MAAM,UACjC,eAAe,YAAY,MAAM,QACjC;AACA;AAAA,cACF;AAEA,kBAAI,CAAC,QAAQ,KAAK,EAAE,KAAK,KAAK,CAAC,QAAQ,KAAK,KAAK,EAAE,QAAQ;AACzD,sBAAM,aAAa,QAAQ,OAAO;AAClC,wBAAQ,OAAO;AACf,0BAAU;AAAA,cACZ,OAAO;AACL;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF,WAAW,cAAc,QAAQ;AAE/B,eAAK,aAAa,cAAc,KAAK,EAAE;AAAA,QACzC;AAEA,aAAK,QAAQ,aAAa,QAAQ,KAAK,YAAa;AAAA,MACtD,OAAO;AAEL,aAAK,QAAQ,KAAK,WAAW,KAAK,KAAK;AAAA,MACzC;AAAA,IACF;AAGA,SAAK,iBAAiB;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,WAAW,MAAoC;AAC7C,QAAI,CAAC,MAAM;AACT,aAAO;AAAA,IACT;AAEA,WAAQ,OAAO,MAAM,MAAM,EAAE,OAAO,MAAM,CAAC,EAAa,KAAK;AAAA,EAC/D;AAAA;AAAA,EAGU,WAAW,IAAsB;AAAA,EAE3C;AAAA;AAAA,EAGU,UAAU,IAAsB;AAAA,EAE1C;AAAA;AAAA,EAGU,gBAAgB,OAAqB;AAAA,EAE/C;AACF;AAEO,IAAM,iBAAN,cAA6B,QAAQ;AAAA,EAChC,WAAW,GAAqB;AACxC,YAAQ,IAAI,+BAA+B;AAC3C,YAAQ,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC;AAAA,EACxC;AAAA,EAEU,UAAU,GAAqB;AACvC,YAAQ,IAAI,mCAAmC;AAC/C,YAAQ,IAAI,EAAE,KAAK,EAAE,UAAU,GAAG,GAAG,CAAC;AAAA,EACxC;AAAA,EAEU,gBAAgB,MAAoB;AAC5C,YAAQ,IAAI,2BAA2B;AACvC,YAAQ,IAAI,KAAK,UAAU,GAAG,GAAG,CAAC;AAAA,EACpC;AACF;","names":["cheerio","text"]}