makethisbetter 1.13.2 → 1.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"makethisbetter.cjs","sources":["../src/widget/shadow.ts","../src/widget/tab.ts","../src/widget/frustration-prompt.ts","../src/widget/dim-overlay.ts","../src/widget/scroll-lock.ts","../src/annotate/toolbar.ts","../src/annotate/overlay.ts","../src/annotate/highlighter.ts","../src/annotate/pin.ts","../src/styles.ts","../src/annotate/draw.ts","../src/annotate/session.ts","../src/context/dom-utils.ts","../src/popup/keyboard-inset.ts","../src/popup/sheet.ts","../src/annotate/draw-note-bar.ts","../src/popup/comment.ts","../src/api/client.ts","../src/popup/clarify.ts","../src/popup/success.ts","../node_modules/html-to-image/es/util.js","../node_modules/html-to-image/es/clone-pseudos.js","../node_modules/html-to-image/es/mimes.js","../node_modules/html-to-image/es/dataurl.js","../node_modules/html-to-image/es/clone-node.js","../node_modules/html-to-image/es/embed-resources.js","../node_modules/html-to-image/es/embed-images.js","../node_modules/html-to-image/es/apply-style.js","../node_modules/html-to-image/es/embed-webfonts.js","../node_modules/html-to-image/es/index.js","../src/screenshot/crop.ts","../src/screenshot/capture.ts","../src/context/error-source.ts","../src/context/console.ts","../src/context/history-patch.ts","../src/context/breadcrumbs.ts","../src/context/frustration-state.ts","../src/context/frustration.ts","../src/context/collector.ts","../src/widget/payload.ts","../src/widget/anon-id.ts","../src/i18n/en.ts","../src/i18n/zh-CN.ts","../src/i18n/ja.ts","../src/i18n/ko.ts","../src/i18n/es.ts","../src/i18n/fr.ts","../src/i18n/de.ts","../src/i18n/index.ts","../src/record/session.ts","../src/record/control-bar.ts","../src/widget/recording-manager.ts","../src/widget/controller.ts","../src/index.ts"],"sourcesContent":["import cssText from '../styles/widget.css?inline'\nimport type { MakeThisBetterConfig } from '../types'\n\nexport class ShadowContainer {\n // Readable so a component can mark the host with its own presence and have\n // :host(...) rules react — the only way CSS inside the shadow tree can be\n // told which components are currently mounted.\n readonly host: HTMLElement\n readonly root: ShadowRoot\n\n constructor(theme: MakeThisBetterConfig['theme'] = 'auto') {\n this.host = document.createElement('div')\n this.host.id = 'mtb-widget-host'\n this.host.style.cssText = 'position:fixed;top:0;left:0;width:0;height:0;overflow:visible;z-index:2147483646;'\n this.host.setAttribute('data-mtb-theme', theme)\n document.body.appendChild(this.host)\n\n this.root = this.host.attachShadow({ mode: 'open' })\n\n const style = document.createElement('style')\n style.textContent = cssText\n this.root.appendChild(style)\n }\n\n el<T extends HTMLElement = HTMLElement>(tag: string, className?: string): T {\n const el = document.createElement(tag) as T\n if (className) el.className = className\n return el\n }\n\n append(...nodes: Node[]): void {\n for (const n of nodes) this.root.appendChild(n)\n }\n\n remove(...nodes: Node[]): void {\n for (const n of nodes) {\n if (n.parentNode === this.root) this.root.removeChild(n)\n }\n }\n\n destroy(): void {\n // host.remove() is a safe no-op if the host is already detached — e.g.\n // when Turbo swapped document.body on navigation. removeChild(host) would\n // throw NotFoundError there, aborting re-init and dropping the widget.\n this.host.remove()\n }\n}\n","import type { ShadowContainer } from './shadow'\nimport type { I18nMessages } from '../i18n'\n\nexport class FeedbackTab {\n private el: HTMLButtonElement\n private onClick: () => void\n private idleLabel: string\n private activeLabel: string\n private customText?: string\n private active = false\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n position: 'left' | 'right',\n onClick: () => void,\n customText?: string,\n ) {\n this.onClick = onClick\n this.customText = customText\n this.el = shadow.el<HTMLButtonElement>('button', 'mtb-tab')\n if (position === 'left') this.el.classList.add('left')\n this.idleLabel = customText ?? messages.tab\n this.activeLabel = messages.toolbar.exit\n this.setLabel(this.idleLabel)\n this.el.addEventListener('click', onClick)\n shadow.append(this.el)\n }\n\n private setLabel(label: string): void {\n this.el.textContent = label\n this.el.setAttribute('aria-label', label)\n }\n\n setMessages(messages: I18nMessages): void {\n this.idleLabel = this.customText ?? messages.tab\n this.activeLabel = messages.toolbar.exit\n this.setLabel(this.active ? this.activeLabel : this.idleLabel)\n }\n\n setActive(active: boolean): void {\n this.active = active\n this.el.classList.toggle('active', active)\n this.setLabel(active ? this.activeLabel : this.idleLabel)\n }\n\n destroy(): void {\n this.el.removeEventListener('click', this.onClick)\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from './shadow'\nimport type { I18nMessages } from '../i18n'\n\nconst FRUSTRATION_DISMISS_MS = 8000\n\nexport interface FrustrationPromptHandlers {\n onTell: () => void\n // The reporter clicked Dismiss — a deliberate refusal.\n onDismiss: () => void\n // Nobody touched the card and it faded out on its own. Kept separate from\n // onDismiss because \"did not notice\" is not \"said no\": treating the two the\n // same suppressed every later prompt for the session.\n onAutoHide: () => void\n}\n\nexport class FrustrationPromptCard {\n private el: HTMLDivElement\n private autoHideTimer: ReturnType<typeof setTimeout> | null = null\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n handlers: FrustrationPromptHandlers,\n ) {\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-frustration-prompt')\n this.el.innerHTML = `\n <div class=\"mtb-frustration-icon\">&#9888;&#65039;</div>\n <span class=\"mtb-frustration-text\">${messages.frustration.prompt}</span>\n <div class=\"mtb-frustration-actions\">\n <button class=\"mtb-frustration-tell\">${messages.frustration.action}</button>\n <button class=\"mtb-frustration-dismiss\">${messages.frustration.dismiss}</button>\n </div>\n `\n\n this.el.querySelector('.mtb-frustration-tell')!.addEventListener('click', handlers.onTell)\n this.el.querySelector('.mtb-frustration-dismiss')!.addEventListener('click', handlers.onDismiss)\n\n shadow.append(this.el)\n this.autoHideTimer = setTimeout(handlers.onAutoHide, FRUSTRATION_DISMISS_MS)\n }\n\n destroy(): void {\n // Clearing matters on the engagement path too: without it, a card destroyed\n // by \"Tell us\" still fired its auto-hide 8s later.\n if (this.autoHideTimer) {\n clearTimeout(this.autoHideTimer)\n this.autoHideTimer = null\n }\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from './shadow'\n\n// Full-screen scrim shown behind the comment popup. Clicking it resets the\n// widget, mirroring the design's dim-to-dismiss behaviour.\nexport class DimOverlay {\n private el: HTMLDivElement\n private onClick: () => void\n\n constructor(shadow: ShadowContainer, onClick: () => void) {\n this.onClick = onClick\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-dim mtb-dim-clickable')\n this.el.addEventListener('click', this.onClick)\n shadow.append(this.el)\n }\n\n destroy(): void {\n this.el.removeEventListener('click', this.onClick)\n this.el.remove()\n }\n}\n","/**\n * Freezes the host page while a finger is annotating.\n *\n * Two reasons this exists, both of them touch problems. `touch-action: none`\n * is what makes freehand drawing possible at all on a touch screen —\n * otherwise the browser claims the gesture as a pan and never delivers the\n * pointermove stream. `overflow: hidden` then stops the page sliding under a\n * half-drawn stroke, which would leave the annotation pointing at whatever\n * scrolled into its place.\n *\n * A mouse has neither problem, so the desktop keeps scrolling as it always\n * has. Taking that away would be an unasked-for change to the one path that\n * already worked.\n *\n * The host page is not ours, so its own inline values are saved and put back\n * verbatim. Writing '' on unlock would silently delete a style the page set.\n */\nexport class ScrollLock {\n private locked = false\n private prevOverflow = ''\n private prevTouchAction = ''\n\n // No matchMedia means no evidence of a touch device — assume a mouse and\n // leave the host page alone.\n private isTouchPointer(): boolean {\n return window.matchMedia?.('(pointer: coarse)').matches ?? false\n }\n\n lock(): void {\n if (this.locked || !this.isTouchPointer()) return\n this.locked = true\n this.prevOverflow = document.body.style.overflow\n this.prevTouchAction = document.body.style.touchAction\n document.body.style.overflow = 'hidden'\n document.body.style.touchAction = 'none'\n }\n\n unlock(): void {\n if (!this.locked) return\n this.locked = false\n document.body.style.overflow = this.prevOverflow\n document.body.style.touchAction = this.prevTouchAction\n }\n\n isLocked(): boolean {\n return this.locked\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\n\nexport type ToolbarMode = 'markup' | 'record'\n\nexport class AnnotationToolbar {\n private el: HTMLDivElement\n // The capsule, which is what gets measured and dimmed. hintTextEl is only the\n // words inside it — dimming that instead would leave the capsule around them\n // at full strength, and shrink the region counted as \"under the pointer\".\n private hintBarEl: HTMLDivElement\n private hintTextEl!: HTMLSpanElement\n private host: HTMLElement\n private markupBtn!: HTMLButtonElement\n private recordBtn!: HTMLButtonElement\n private messages: I18nMessages\n private currentMode: ToolbarMode = 'markup'\n\n // The hint sits over the page and carries nothing to click, so it steps back\n // while the pointer is on top of it and comes forward again the moment the\n // pointer leaves. Nothing else about the page's movement affects it.\n //\n // This is a hover affordance, and touch has no hover — but a tap still emits\n // a compatibility move wherever the finger landed, which would dim the hint\n // for no reason. Restricting to a real mouse makes it a no-op on a phone.\n private handlePointerMove = (e: PointerEvent): void => {\n if (e.pointerType !== 'mouse') return\n\n const rect = this.hintBarEl.getBoundingClientRect()\n const inside =\n e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom\n\n this.hintBarEl.classList.toggle('mtb-hint-bar--under-pointer', inside)\n }\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n onExit: () => void,\n onModeChange?: (mode: ToolbarMode) => void,\n ) {\n this.messages = messages\n\n // Two siblings, not one element. A fixed-position child is laid out against\n // its nearest transformed ancestor rather than the viewport, and the bar is\n // transformed both at rest and by its entry animation — so a hint nested\n // inside it could never be centred on the page.\n this.hintBarEl = shadow.el<HTMLDivElement>('div', 'mtb-hint-bar')\n this.hintBarEl.innerHTML = `<span class=\"mtb-toolbar-hint\">${messages.toolbar.hint}</span>`\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-toolbar')\n this.el.innerHTML = this.buildHTML(messages)\n shadow.append(this.hintBarEl, this.el)\n\n // Lets the CSS retire the tab for exactly as long as this bar is up. Keyed\n // to the bar's own lifetime rather than to the tab's active state: the tab\n // is still active while a clarification card is open, and by then the bar\n // is gone — hiding it there would leave no way out at all.\n this.host = shadow.host\n this.host.setAttribute('data-mtb-toolbar', '')\n\n this.hintTextEl = this.hintBarEl.querySelector('.mtb-toolbar-hint')!\n this.markupBtn = this.el.querySelector('.mtb-toolbar-mode-markup')!\n this.recordBtn = this.el.querySelector('.mtb-toolbar-mode-record')!\n\n this.markupBtn.addEventListener('click', () => {\n this.setMode('markup')\n onModeChange?.('markup')\n })\n this.recordBtn.addEventListener('click', () => {\n this.setMode('record')\n onModeChange?.('record')\n })\n this.el.querySelector('.mtb-exit-btn')!.addEventListener('click', onExit)\n\n document.addEventListener('pointermove', this.handlePointerMove as EventListener)\n }\n\n private buildHTML(m: I18nMessages): string {\n return `\n <div class=\"mtb-toolbar-modes\">\n <button class=\"mtb-toolbar-mode-btn mtb-toolbar-mode-markup active\" aria-label=\"${m.toolbar.markup}\" title=\"${m.toolbar.markup}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"7\"/><line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"/><line x1=\"3\" y1=\"12\" x2=\"7\" y2=\"12\"/><line x1=\"17\" y1=\"12\" x2=\"21\" y2=\"12\"/></svg><span class=\"mtb-toolbar-label\">${m.toolbar.markup}</span>\n </button>\n <button class=\"mtb-toolbar-mode-btn mtb-toolbar-mode-record\" aria-label=\"${m.toolbar.record}\" title=\"${m.toolbar.record}\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><circle cx=\"12\" cy=\"12\" r=\"4\" fill=\"currentColor\" stroke=\"none\"/></svg><span class=\"mtb-toolbar-label\">${m.toolbar.record}</span>\n </button>\n </div>\n <span class=\"mtb-toolbar-sep\"></span>\n <button class=\"mtb-exit-btn\" aria-label=\"${m.toolbar.exit}\" title=\"${m.toolbar.exit}\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg><span class=\"mtb-toolbar-label\">${m.toolbar.exit}</span>\n </button>\n `\n }\n\n setMode(mode: ToolbarMode): void {\n this.currentMode = mode\n if (mode === 'markup') {\n this.markupBtn.classList.add('active')\n this.recordBtn.classList.remove('active')\n this.hintTextEl.textContent = this.messages.toolbar.hint\n } else {\n this.markupBtn.classList.remove('active')\n this.recordBtn.classList.add('active')\n this.hintTextEl.textContent = this.messages.toolbar.hintRecord\n }\n }\n\n getMode(): ToolbarMode {\n return this.currentMode\n }\n\n destroy(): void {\n document.removeEventListener('pointermove', this.handlePointerMove as EventListener)\n this.host.removeAttribute('data-mtb-toolbar')\n this.hintBarEl.remove()\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\n\nexport interface OverlayHandlers {\n onPointerDown: (e: PointerEvent) => void\n onPointerMove: (e: PointerEvent) => void\n onPointerUp: (e: PointerEvent) => void\n onPointerCancel: (e: PointerEvent) => void\n}\n\n/**\n * The annotation surface. Runs on pointer events only — never mouse events.\n *\n * Mouse listeners are deliberately absent. Touch browsers replay a tap as\n * pointerdown/up followed by compatibility mousedown/up/click, so listening to\n * both would run the annotation logic twice for one tap and drop two pins.\n * Pointer events already cover mouse and stylus, so the desktop loses nothing.\n */\nexport class AnnotationOverlay {\n private overlayEl: HTMLDivElement\n private dimEl: HTMLDivElement\n private handlers: OverlayHandlers\n private onPointerDown: (e: Event) => void\n private onPointerMove: (e: Event) => void\n private onPointerUp: (e: Event) => void\n private onPointerCancel: (e: Event) => void\n\n constructor(shadow: ShadowContainer, handlers: OverlayHandlers) {\n this.handlers = handlers\n\n this.overlayEl = shadow.el<HTMLDivElement>('div', 'mtb-overlay')\n\n this.onPointerDown = (e) => {\n const pe = e as PointerEvent\n if (!pe.isPrimary) return\n // Capture keeps a stroke alive when the finger crosses the overlay edge.\n // Without it, a drag that leaves the surface silently stops mid-line.\n try {\n this.overlayEl.setPointerCapture(pe.pointerId)\n } catch {\n // Thrown when the pointer is already gone. The stroke can still run\n // uncaptured, so this is not worth aborting the gesture over.\n }\n this.handlers.onPointerDown(pe)\n }\n\n this.onPointerMove = (e) => {\n const pe = e as PointerEvent\n if (!pe.isPrimary) return\n this.handlers.onPointerMove(pe)\n }\n\n this.onPointerUp = (e) => {\n const pe = e as PointerEvent\n if (!pe.isPrimary) return\n this.releaseCapture(pe.pointerId)\n this.handlers.onPointerUp(pe)\n }\n\n // Replaces the old mouseleave path. The browser fires this when it takes\n // the gesture away from us — a system gesture, or the page going\n // background — which is exactly when a half-drawn stroke should end.\n this.onPointerCancel = (e) => {\n const pe = e as PointerEvent\n // A palm or second finger can be cancelled on its own. That pointer never\n // reached the handlers, so acting on its cancel would cut short a stroke\n // the primary finger is still drawing.\n if (!pe.isPrimary) return\n this.releaseCapture(pe.pointerId)\n this.handlers.onPointerCancel(pe)\n }\n\n this.overlayEl.addEventListener('pointerdown', this.onPointerDown)\n this.overlayEl.addEventListener('pointermove', this.onPointerMove)\n this.overlayEl.addEventListener('pointerup', this.onPointerUp)\n this.overlayEl.addEventListener('pointercancel', this.onPointerCancel)\n shadow.append(this.overlayEl)\n\n this.dimEl = shadow.el<HTMLDivElement>('div', 'mtb-dim')\n shadow.append(this.dimEl)\n }\n\n private releaseCapture(pointerId: number): void {\n try {\n this.overlayEl.releasePointerCapture(pointerId)\n } catch {\n // Already released, or the pointer is gone. Nothing to undo.\n }\n }\n\n destroy(): void {\n this.overlayEl.removeEventListener('pointerdown', this.onPointerDown)\n this.overlayEl.removeEventListener('pointermove', this.onPointerMove)\n this.overlayEl.removeEventListener('pointerup', this.onPointerUp)\n this.overlayEl.removeEventListener('pointercancel', this.onPointerCancel)\n this.overlayEl.remove()\n this.dimEl.remove()\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\n\nexport class ElementHighlighter {\n private highlightEl: HTMLDivElement\n private tooltipEl: HTMLDivElement\n\n constructor(shadow: ShadowContainer) {\n this.highlightEl = shadow.el<HTMLDivElement>('div', 'mtb-highlight')\n this.tooltipEl = shadow.el<HTMLDivElement>('div', 'mtb-highlight-tooltip')\n this.hide()\n shadow.append(this.highlightEl, this.tooltipEl)\n }\n\n highlight(el: Element): void {\n const rect = el.getBoundingClientRect()\n this.highlightEl.style.top = `${rect.top - 2}px`\n this.highlightEl.style.left = `${rect.left - 2}px`\n this.highlightEl.style.width = `${rect.width + 4}px`\n this.highlightEl.style.height = `${rect.height + 4}px`\n this.highlightEl.style.display = 'block'\n this.showTooltip(el, rect)\n }\n\n private showTooltip(el: Element, rect: DOMRect): void {\n this.tooltipEl.textContent = getElementName(el)\n const below = rect.top < 30\n this.tooltipEl.classList.toggle('below', below)\n this.tooltipEl.style.left = `${rect.left + rect.width / 2}px`\n this.tooltipEl.style.top = below ? `${rect.bottom + 8}px` : `${rect.top - 8}px`\n this.tooltipEl.style.display = 'block'\n }\n\n select(): void {\n this.highlightEl.classList.add('selected')\n this.tooltipEl.style.display = 'none'\n }\n\n hide(): void {\n this.highlightEl.style.display = 'none'\n this.highlightEl.classList.remove('selected')\n this.tooltipEl.style.display = 'none'\n }\n\n destroy(): void {\n this.highlightEl.remove()\n this.tooltipEl.remove()\n }\n}\n\n// textContent counts the source of <style> and <script> children as text. A\n// page with an inline stylesheet in its header therefore names that header\n// after its own CSS, and that name travels into the pin, the report, and the\n// triage prompt. Only what a reader would see counts.\nconst UNRENDERED = /^(script|style|noscript|template)$/i\n\nfunction renderedText(el: Element, limit = 80): string {\n let out = ''\n for (const node of Array.from(el.childNodes)) {\n if (out.length >= limit) break\n\n if (node.nodeType === 3) {\n out += node.nodeValue ?? ''\n } else if (node instanceof Element && !UNRENDERED.test(node.tagName)) {\n out += renderedText(node, limit - out.length)\n }\n }\n return out\n}\n\nexport function getElementName(el: Element): string {\n if (el instanceof HTMLElement) {\n const label = el.getAttribute('aria-label')\n if (label) return label\n\n const title = el.getAttribute('title')\n if (title) return title\n\n const text = renderedText(el).trim().slice(0, 40)\n if (text) return text\n\n const placeholder = (el as HTMLInputElement).placeholder\n if (placeholder) return placeholder\n\n const alt = (el as HTMLImageElement).alt\n if (alt) return alt\n\n const dataMark = el.getAttribute('data-mark')\n if (dataMark) return dataMark\n }\n return el.tagName.toLowerCase()\n}\n\nexport function getCssSelector(el: Element): string {\n const parts: string[] = []\n let current: Element | null = el\n while (current && current !== document.body && parts.length < 5) {\n let selector = current.tagName.toLowerCase()\n if (current.id) {\n selector = `#${current.id}`\n parts.unshift(selector)\n break\n }\n const classNames = Array.from(current.classList)\n .filter(c => !c.startsWith('mtb-'))\n .slice(0, 2)\n .join('.')\n if (classNames) selector += `.${classNames}`\n\n const parent = current.parentElement\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n c => c.tagName === current!.tagName,\n )\n if (siblings.length > 1) {\n const idx = siblings.indexOf(current) + 1\n selector += `:nth-of-type(${idx})`\n }\n }\n\n parts.unshift(selector)\n current = current.parentElement\n }\n return parts.join(' > ')\n}\n","import type { ShadowContainer } from '../widget/shadow'\n\nexport class PinMarker {\n private pins: HTMLDivElement[] = []\n private shadow: ShadowContainer\n\n constructor(shadow: ShadowContainer) {\n this.shadow = shadow\n }\n\n addPin(x: number, y: number): void {\n const pin = this.shadow.el<HTMLDivElement>('div', 'mtb-pin')\n pin.style.top = `${y}px`\n pin.style.left = `${x}px`\n this.shadow.append(pin)\n this.pins.push(pin)\n }\n\n clearAll(): void {\n for (const pin of this.pins) pin.remove()\n this.pins = []\n }\n\n destroy(): void {\n this.clearAll()\n }\n}\n","export const BRAND_COLOR = '#059669'\n// Same green as BRAND_COLOR, in the form shadows need. Derived once so a brand\n// change cannot leave the shadows on the old colour.\nconst BRAND_RGB = '5,150,105'\n\nexport function brandAlpha(alpha: number): string {\n return `rgba(${BRAND_RGB},${alpha})`\n}\n\nexport const FONT_STACK = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif'\n\nexport const DRAW_STROKE = {\n color: BRAND_COLOR,\n width: '3.5',\n linecap: 'round',\n linejoin: 'round',\n filter: `drop-shadow(0 1px 2px ${brandAlpha(0.35)})`,\n} as const\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { Annotation } from '../types'\nimport { DRAW_STROKE } from '../styles'\n\ntype Point = [number, number]\n\ninterface Stroke {\n path: SVGPathElement\n d: string\n points: Point[]\n}\n\nexport class DrawLayer {\n private svg: SVGSVGElement\n private currentPath: SVGPathElement | null = null\n private currentPoints: Point[] = []\n private isDrawing = false\n private committed: Stroke[] = []\n private redoStack: { d: string; points: Point[] }[] = []\n\n constructor(shadow: ShadowContainer) {\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n this.svg.setAttribute('class', 'mtb-draw-svg')\n shadow.append(this.svg)\n }\n\n startDraw(x: number, y: number): void {\n this.isDrawing = true\n this.currentPoints = [[x, y]]\n this.currentPath = this.createPath()\n this.svg.appendChild(this.currentPath)\n }\n\n continueDraw(x: number, y: number): void {\n if (!this.isDrawing || !this.currentPath) return\n this.currentPoints.push([x, y])\n this.currentPath.setAttribute('d', buildPathD(this.currentPoints))\n }\n\n // Commits the in-progress stroke to the undo stack and clears the redo stack.\n // Callers decide whether the stroke has enough points before committing.\n commitStroke(): boolean {\n if (!this.isDrawing || !this.currentPath) return false\n this.isDrawing = false\n this.committed.push({ path: this.currentPath, d: buildPathD(this.currentPoints), points: this.currentPoints })\n this.redoStack = []\n this.currentPath = null\n this.currentPoints = []\n return true\n }\n\n cancelCurrentDraw(): void {\n this.currentPath?.remove()\n this.currentPath = null\n this.isDrawing = false\n this.currentPoints = []\n }\n\n undo(): boolean {\n const stroke = this.committed.pop()\n if (!stroke) return false\n stroke.path.remove()\n this.redoStack.push({ d: stroke.d, points: stroke.points })\n return true\n }\n\n redo(): boolean {\n const entry = this.redoStack.pop()\n if (!entry) return false\n const path = this.createPath()\n path.setAttribute('d', entry.d)\n this.svg.appendChild(path)\n this.committed.push({ path, d: entry.d, points: entry.points })\n return true\n }\n\n canUndo(): boolean {\n return this.committed.length > 0\n }\n\n canRedo(): boolean {\n return this.redoStack.length > 0\n }\n\n hasStrokes(): boolean {\n return this.committed.length > 0\n }\n\n getAnnotation(): Annotation | null {\n if (this.committed.length === 0) return null\n const points = this.committed.flatMap(s => s.points)\n const [cx, cy] = center(points)\n return {\n type: 'draw',\n x: cx,\n y: cy,\n drawPath: this.committed.map(s => s.d).join(' '),\n }\n }\n\n clearAll(): void {\n while (this.svg.firstChild) this.svg.removeChild(this.svg.firstChild)\n this.currentPath = null\n this.isDrawing = false\n this.currentPoints = []\n this.committed = []\n this.redoStack = []\n }\n\n isCurrentlyDrawing(): boolean {\n return this.isDrawing\n }\n\n getCurrentPointCount(): number {\n return this.currentPoints.length\n }\n\n destroy(): void {\n this.svg.remove()\n }\n\n private createPath(): SVGPathElement {\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n path.setAttribute('fill', 'none')\n path.setAttribute('stroke', DRAW_STROKE.color)\n path.setAttribute('stroke-width', DRAW_STROKE.width)\n path.setAttribute('stroke-linecap', DRAW_STROKE.linecap)\n path.setAttribute('stroke-linejoin', DRAW_STROKE.linejoin)\n path.setAttribute('style', `filter:${DRAW_STROKE.filter}`)\n return path\n }\n}\n\nfunction buildPathD(points: Point[]): string {\n if (points.length === 0) return ''\n const [fx, fy] = points[0]\n let d = `M ${fx} ${fy}`\n for (let i = 1; i < points.length; i++) {\n const [x, y] = points[i]\n d += ` L ${x} ${y}`\n }\n return d\n}\n\nfunction center(points: Point[]): Point {\n const xs = points.map(p => p[0])\n const ys = points.map(p => p[1])\n const cx = (Math.min(...xs) + Math.max(...xs)) / 2\n const cy = (Math.min(...ys) + Math.max(...ys)) / 2\n return [cx, cy]\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { Annotation } from '../types'\nimport { AnnotationOverlay } from './overlay'\nimport { ElementHighlighter, getElementName, getCssSelector } from './highlighter'\nimport { PinMarker } from './pin'\nimport { DrawLayer } from './draw'\n\nconst DRAW_MIN_POINTS = 5\n\ninterface SessionHandlers {\n onPin: (annotation: Annotation, targetName: string) => void\n onDrawStroke: () => void\n}\n\nexport class AnnotationSession {\n private overlay: AnnotationOverlay\n private highlighter: ElementHighlighter\n private pinMarker: PinMarker\n private drawLayer: DrawLayer\n private interactionActive = true\n private pendingHighlightFrame: number | null = null\n private lastMoveX = 0\n private lastMoveY = 0\n\n constructor(\n shadow: ShadowContainer,\n private messages: I18nMessages,\n private handlers: SessionHandlers,\n ) {\n this.highlighter = new ElementHighlighter(shadow)\n this.pinMarker = new PinMarker(shadow)\n this.drawLayer = new DrawLayer(shadow)\n this.overlay = new AnnotationOverlay(shadow, {\n onPointerDown: (e) => this.handlePointerDown(e),\n onPointerMove: (e) => this.handlePointerMove(e),\n onPointerUp: (e) => this.handlePointerUp(e),\n // Previously mouseleave. The overlay now captures the pointer, so a\n // stroke no longer ends by wandering off the surface — only by the\n // browser taking the gesture away, which is what pointercancel means.\n onPointerCancel: () => {\n if (this.drawLayer.isCurrentlyDrawing()) this.finishStroke()\n this.cancelPendingHighlight()\n this.highlighter.hide()\n },\n })\n }\n\n private handlePointerDown(e: PointerEvent): void {\n e.preventDefault()\n this.drawLayer.startDraw(e.clientX, e.clientY)\n }\n\n private handlePointerMove(e: PointerEvent): void {\n if (this.drawLayer.isCurrentlyDrawing()) {\n this.cancelPendingHighlight()\n this.drawLayer.continueDraw(e.clientX, e.clientY)\n this.highlighter.hide()\n return\n }\n\n this.lastMoveX = e.clientX\n this.lastMoveY = e.clientY\n if (this.pendingHighlightFrame !== null) return\n this.pendingHighlightFrame = requestAnimationFrame(() => {\n this.pendingHighlightFrame = null\n this.updateHighlight()\n })\n }\n\n private updateHighlight(): void {\n if (!this.interactionActive || this.drawLayer.isCurrentlyDrawing() || this.drawSessionActive()) return\n const underEl = getElementUnder(this.lastMoveX, this.lastMoveY)\n if (underEl) this.highlighter.highlight(underEl)\n else this.highlighter.hide()\n }\n\n private cancelPendingHighlight(): void {\n if (this.pendingHighlightFrame === null) return\n cancelAnimationFrame(this.pendingHighlightFrame)\n this.pendingHighlightFrame = null\n }\n\n private handlePointerUp(e: PointerEvent): void {\n if (!this.drawLayer.isCurrentlyDrawing()) return\n this.finishStroke(e)\n }\n\n // A drag past the point threshold becomes a freehand stroke and opens the\n // draw note bar; a tap on an element becomes a pin. Stray taps while a\n // drawing already exists are ignored so they don't hijack the draw flow.\n private finishStroke(e?: PointerEvent): void {\n if (this.drawLayer.getCurrentPointCount() >= DRAW_MIN_POINTS) {\n this.drawLayer.commitStroke()\n this.highlighter.hide()\n this.handlers.onDrawStroke()\n return\n }\n\n this.drawLayer.cancelCurrentDraw()\n if (this.drawLayer.hasStrokes() || !e) return\n\n const underEl = getElementUnder(e.clientX, e.clientY)\n const targetName = underEl ? getElementName(underEl) : this.messages.annotation.element\n const rect = underEl?.getBoundingClientRect()\n const annotation: Annotation = {\n type: 'pin',\n x: e.clientX,\n y: e.clientY,\n targetSelector: underEl ? getCssSelector(underEl) : undefined,\n targetText: underEl?.textContent?.trim().slice(0, 200) ?? '',\n targetName,\n targetRect: rect ? { top: rect.top, left: rect.left, width: rect.width, height: rect.height, bottom: rect.bottom } : undefined,\n }\n this.pinMarker.addPin(e.clientX, e.clientY)\n this.highlighter.select()\n this.handlers.onPin(annotation, targetName)\n }\n\n undoDraw(): void {\n this.drawLayer.undo()\n }\n\n redoDraw(): void {\n this.drawLayer.redo()\n }\n\n canUndoDraw(): boolean {\n return this.drawLayer.canUndo()\n }\n\n canRedoDraw(): boolean {\n return this.drawLayer.canRedo()\n }\n\n hasDrawStrokes(): boolean {\n return this.drawLayer.hasStrokes()\n }\n\n private drawSessionActive(): boolean {\n return this.drawLayer.hasStrokes() || this.drawLayer.canRedo()\n }\n\n getDrawAnnotation(): Annotation | null {\n return this.drawLayer.getAnnotation()\n }\n\n clearDraw(): void {\n this.drawLayer.clearAll()\n }\n\n dismissInteraction(): void {\n if (!this.interactionActive) return\n this.interactionActive = false\n this.cancelPendingHighlight()\n this.overlay.destroy()\n }\n\n hideHighlight(): void {\n this.highlighter.hide()\n }\n\n destroy(): void {\n this.dismissInteraction()\n this.highlighter.destroy()\n this.pinMarker.destroy()\n this.drawLayer.destroy()\n }\n}\n\n// Skips the widget host via elementsFromPoint instead of toggling its\n// display — hiding the host on every mousemove flickered the toolbar.\nfunction getElementUnder(x: number, y: number): Element | null {\n return document.elementsFromPoint(x, y).find(el => el.id !== 'mtb-widget-host') ?? null\n}\n","const WIDGET_HOST_ID = 'mtb-widget-host'\n\nexport function isWidgetElement(el: Element): boolean {\n const host = document.getElementById(WIDGET_HOST_ID)\n if (!host) return false\n return host === el || host.contains(el)\n}\n\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;')\n}\n","/**\n * How much of the window the software keyboard is covering.\n *\n * A `position: fixed` sheet gets no help from the browser here — the built-in\n * \"scroll the focused field into view\" only moves elements that are in the\n * document flow, so on iOS the keyboard simply covers the sheet.\n *\n * The two platforms hide the keyboard in different places, and this one\n * formula covers both. iOS keeps the layout viewport at full height and\n * shrinks (and shifts) the visual viewport, so the difference is the keyboard.\n * Android resizes the layout viewport itself, so `innerHeight` shrinks too and\n * the difference falls out to zero — which is the right answer there, because\n * the bottom of the window is already above the keyboard.\n *\n * `offsetTop` matters as much as `height`: iOS shifts the visual viewport up\n * as well as shrinking it, and ignoring the shift leaves the sheet floating\n * exactly that far off, with a strip of page showing beneath it.\n */\nexport class KeyboardInset {\n private onChange: ((inset: number) => void) | null = null\n private handler = (): void => {\n this.onChange?.(this.current())\n }\n\n current(): number {\n const vp = window.visualViewport\n if (!vp) return 0\n return Math.max(0, Math.round(window.innerHeight - (vp.height + vp.offsetTop)))\n }\n\n observe(onChange: (inset: number) => void): void {\n const vp = window.visualViewport\n if (!vp) return\n this.onChange = onChange\n vp.addEventListener('resize', this.handler)\n // Scroll fires for the shift-up on iOS, which resize alone does not report.\n vp.addEventListener('scroll', this.handler)\n }\n\n stop(): void {\n const vp = window.visualViewport\n this.onChange = null\n if (!vp) return\n vp.removeEventListener('resize', this.handler)\n vp.removeEventListener('scroll', this.handler)\n }\n}\n","import { KeyboardInset } from './keyboard-inset'\n\n/**\n * Matches the `max-width: 480px` block in widget.css, where every panel that\n * holds a text field stops being a card anchored near the annotation and\n * becomes a bottom sheet.\n */\nexport const SHEET_MAX_WIDTH = 480\n\nexport function isSheetViewport(): boolean {\n return window.innerWidth <= SHEET_MAX_WIDTH\n}\n\n/**\n * Hands a panel's geometry to the stylesheet on narrow screens, and keeps it\n * clear of the software keyboard.\n *\n * Two jobs that have to live together. The panels each position themselves\n * with inline `left`/`top`, which would beat the media query and drag the sheet\n * back into a floating card — so the inline values have to be cleared, not just\n * overridden. And a `position: fixed` sheet gets no help from the browser's\n * scroll-into-view, which only moves elements in the document flow, so the\n * keyboard simply covers it unless something lifts it.\n *\n * Shared by the comment popup, the clarify card, and the draw note bar: all\n * three carry a text field, and all three are the last thing between a reporter\n * and a submitted report.\n */\nexport class SheetLayout {\n private inset = new KeyboardInset()\n\n constructor(private el: HTMLElement) {}\n\n /** Returns true when this took over layout, i.e. the caller should not position. */\n apply(): boolean {\n if (!isSheetViewport()) return false\n\n this.el.style.left = ''\n this.el.style.top = ''\n this.el.style.maxHeight = ''\n this.lift(this.inset.current())\n this.inset.observe((px) => this.lift(px))\n return true\n }\n\n release(): void {\n this.inset.stop()\n }\n\n private lift(inset: number): void {\n this.el.style.bottom = inset > 0 ? `${inset}px` : ''\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport { escapeHtml } from '../context/dom-utils'\nimport { SheetLayout } from '../popup/sheet'\n\ninterface DrawNoteBarOptions {\n messages: I18nMessages\n onUndo: () => void\n onRedo: () => void\n onCancel: () => void\n onSubmit: (note: string) => void\n}\n\nexport class DrawNoteBar {\n private el: HTMLDivElement\n private sheet: SheetLayout\n private input!: HTMLInputElement\n private undoBtn!: HTMLButtonElement\n private redoBtn!: HTMLButtonElement\n private submitBtn!: HTMLButtonElement\n private errorEl!: HTMLDivElement\n private onSubmit: (note: string) => void\n private submitLabel: string\n private loading = false\n\n constructor(shadow: ShadowContainer, opts: DrawNoteBarOptions) {\n this.onSubmit = opts.onSubmit\n this.submitLabel = opts.messages.draw.submit\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-draw-bar')\n this.el.innerHTML = this.buildHTML(opts.messages)\n shadow.append(this.el)\n // The bar carries a text field and sits flush to the bottom on a phone,\n // which is exactly where the keyboard lands.\n this.sheet = new SheetLayout(this.el)\n this.sheet.apply()\n\n this.input = this.el.querySelector('.mtb-draw-input')!\n this.undoBtn = this.el.querySelector('.mtb-draw-undo')!\n this.redoBtn = this.el.querySelector('.mtb-draw-redo')!\n this.submitBtn = this.el.querySelector('.mtb-draw-submit')!\n this.errorEl = this.el.querySelector('.mtb-draw-error')!\n\n this.undoBtn.addEventListener('click', opts.onUndo)\n this.redoBtn.addEventListener('click', opts.onRedo)\n this.el.querySelector('.mtb-draw-cancel')!.addEventListener('click', opts.onCancel)\n this.submitBtn.addEventListener('click', () => this.submit())\n this.input.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n this.submit()\n }\n })\n\n this.input.focus()\n }\n\n private buildHTML(m: I18nMessages): string {\n return `\n <input class=\"mtb-draw-input\" type=\"text\" placeholder=\"${escapeHtml(m.draw.note_placeholder)}\" />\n <button class=\"mtb-draw-icon-btn mtb-draw-undo\" type=\"button\" title=\"${escapeHtml(m.draw.undo)}\" aria-label=\"${escapeHtml(m.draw.undo)}\" disabled>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 14L4 9l5-5\"/><path d=\"M4 9h11a5 5 0 0 1 0 10h-1\"/></svg>\n </button>\n <button class=\"mtb-draw-icon-btn mtb-draw-redo\" type=\"button\" title=\"${escapeHtml(m.draw.redo)}\" aria-label=\"${escapeHtml(m.draw.redo)}\" disabled>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 14l5-5-5-5\"/><path d=\"M20 9H9a5 5 0 0 0 0 10h1\"/></svg>\n </button>\n <span class=\"mtb-draw-sep\"></span>\n <button class=\"mtb-draw-cancel\" type=\"button\">${escapeHtml(m.draw.cancel)}</button>\n <button class=\"mtb-draw-submit\" type=\"button\">${escapeHtml(m.draw.submit)}</button>\n <div class=\"mtb-draw-error\" role=\"alert\" hidden></div>\n `\n }\n\n setUndoRedo(canUndo: boolean, canRedo: boolean): void {\n this.undoBtn.disabled = !canUndo || this.loading\n this.redoBtn.disabled = !canRedo || this.loading\n }\n\n setLoading(loading: boolean): void {\n this.loading = loading\n this.input.disabled = loading\n this.submitBtn.disabled = loading\n this.undoBtn.disabled = loading || this.undoBtn.disabled\n this.redoBtn.disabled = loading || this.redoBtn.disabled\n if (loading) {\n this.submitBtn.classList.add('loading')\n this.submitBtn.innerHTML = `<span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span>`\n this.errorEl.hidden = true\n this.errorEl.textContent = ''\n } else {\n this.submitBtn.classList.remove('loading')\n this.submitBtn.textContent = this.submitLabel\n }\n }\n\n setError(message: string): void {\n this.errorEl.textContent = message\n this.errorEl.hidden = false\n }\n\n private submit(): void {\n if (this.loading) return\n this.onSubmit(this.input.value.trim())\n }\n\n destroy(): void {\n this.sheet.release()\n this.el.remove()\n }\n}\n\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { TargetRect } from '../types'\nimport { escapeHtml } from '../context/dom-utils'\nimport { SheetLayout } from './sheet'\n\ninterface PopupOptions {\n targetName: string\n x: number\n y: number\n targetRect?: TargetRect\n onSubmit: (description: string) => void\n onClose: () => void\n onMyFeedback?: () => void\n messages: I18nMessages\n position?: 'left' | 'right'\n}\n\nexport class CommentPopup {\n private el: HTMLDivElement\n private sheet: SheetLayout\n private textarea!: HTMLTextAreaElement\n private submitBtn!: HTMLButtonElement\n private errorEl!: HTMLDivElement\n private onSubmit: (description: string) => void\n private onClose: () => void\n private submitLabel: string\n private loading = false\n private messages: I18nMessages\n private selectedQuickOption: string | null = null\n\n constructor(shadow: ShadowContainer, opts: PopupOptions) {\n this.onSubmit = opts.onSubmit\n this.onClose = opts.onClose\n this.submitLabel = opts.messages.popup.submit\n this.messages = opts.messages\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-popup')\n this.el.innerHTML = this.buildHTML(opts)\n shadow.append(this.el)\n this.sheet = new SheetLayout(this.el)\n\n this.textarea = this.el.querySelector('.mtb-textarea')!\n this.submitBtn = this.el.querySelector('.mtb-submit-btn')!\n\n this.positionPopup(opts.x, opts.y, opts.targetRect, opts.position ?? 'right')\n this.bindEvents(opts.messages)\n if (opts.onMyFeedback) {\n this.el.querySelector('.mtb-my-feedback')!.addEventListener('click', opts.onMyFeedback)\n }\n this.textarea.focus()\n }\n\n private buildHTML(opts: PopupOptions): string {\n const m = opts.messages\n const quickOpts = m.popup.quickOptions\n .map(\n o => `\n <button class=\"mtb-quick-option\" data-quick=\"${escapeHtml(o.label)}\">\n <span class=\"mtb-quick-option-emoji\">${o.emoji}</span>\n <span>${escapeHtml(o.label)}</span>\n </button>`,\n )\n .join('')\n\n return `\n <div class=\"mtb-popup-header\">\n <div class=\"mtb-popup-icon\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#059669\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/>\n </svg>\n </div>\n <span class=\"mtb-popup-title\">${m.popup.about} \"${escapeHtml(opts.targetName)}\"</span>\n <button class=\"mtb-popup-close\" aria-label=\"Close\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n <div class=\"mtb-popup-body\">\n <div class=\"mtb-quick-options\">\n ${quickOpts}\n </div>\n <div class=\"mtb-textarea-wrap\">\n <textarea class=\"mtb-textarea\" placeholder=\"${escapeHtml(m.popup.placeholder)}\"></textarea>\n </div>\n <div class=\"mtb-popup-error\" role=\"alert\"></div>\n <div class=\"mtb-popup-actions\">\n <button class=\"mtb-cancel-btn\" type=\"button\">${escapeHtml(m.popup.cancel)}</button>\n <button class=\"mtb-submit-btn\" type=\"button\" disabled>${escapeHtml(m.popup.submit)}</button>\n </div>\n ${opts.onMyFeedback ? `<button class=\"mtb-my-feedback\" type=\"button\">${escapeHtml(m.popup.my_feedback)}</button>` : ''}\n </div>\n `\n }\n\n\n\n private positionPopup(x: number, y: number, targetRect: TargetRect | undefined, tabPosition: 'left' | 'right'): void {\n if (this.sheet.apply()) return\n\n const vw = window.innerWidth\n const vh = window.innerHeight\n const margin = 12\n const gap = 8\n const tabWidth = 32\n const popupW = Math.min(320, vw - 2 * margin - tabWidth)\n const popupH = this.el.offsetHeight || 260\n const minLeft = margin + (tabPosition === 'left' ? tabWidth : 0)\n const maxRight = vw - margin - (tabPosition === 'right' ? tabWidth : 0)\n\n let left: number\n let top: number\n\n // Anchoring to the element only helps while the element is small enough to\n // point at. A click on empty space lands on whatever section or body spans\n // the page, and its rect says nothing about where the user clicked: the top\n // edge is off-screen, so the popup flips, and the left edge is 0, so it\n // lands in the bottom-left corner however far right the click was.\n const anchorIsInformative =\n targetRect && targetRect.width < vw * 0.6 && targetRect.height < vh * 0.6\n\n if (targetRect && anchorIsInformative) {\n left = targetRect.left\n top = targetRect.bottom + gap\n\n if (top + popupH > vh - margin) {\n top = targetRect.top - popupH - gap\n }\n if (top < margin) {\n top = Math.min(targetRect.bottom + gap, vh - popupH - margin)\n }\n } else {\n left = x + 12\n top = y + 12\n }\n\n if (left + popupW > maxRight) {\n left = maxRight - popupW\n }\n if (left < minLeft) left = minLeft\n if (top < margin) top = margin\n\n this.el.style.left = `${left}px`\n this.el.style.top = `${top}px`\n this.el.style.maxHeight = `${vh - top - margin}px`\n }\n\n private bindEvents(messages: I18nMessages): void {\n this.el.querySelector('.mtb-popup-close')!.addEventListener('click', () => this.onClose())\n this.el.querySelector('.mtb-cancel-btn')!.addEventListener('click', () => this.onClose())\n this.errorEl = this.el.querySelector('.mtb-popup-error')!\n\n this.el.querySelectorAll('.mtb-quick-option').forEach(btn => {\n btn.addEventListener('click', () => {\n const label = (btn as HTMLElement).dataset['quick'] ?? ''\n\n if (this.textarea.value.trim().length === 0) {\n this.textarea.value = label\n this.updateSubmitState()\n this.submit()\n return\n }\n\n this.selectedQuickOption = label\n this.el.querySelectorAll('.mtb-quick-option').forEach(option => {\n option.classList.toggle('selected', option === btn)\n })\n })\n })\n\n this.textarea.addEventListener('input', () => this.updateSubmitState())\n\n this.textarea.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n this.submit()\n }\n })\n\n this.submitBtn.addEventListener('click', () => this.submit())\n }\n\n private updateSubmitState(): void {\n const hasText = this.textarea.value.trim().length > 0\n this.submitBtn.classList.toggle('ready', hasText && !this.loading)\n this.submitBtn.disabled = !hasText || this.loading\n this.errorEl.hidden = true\n this.errorEl.textContent = ''\n }\n\n private submit(): void {\n const text = this.textarea.value.trim()\n if (!text || this.loading) return\n const description = this.selectedQuickOption ? `[${this.selectedQuickOption}] ${text}` : text\n this.onSubmit(description)\n }\n\n setLoading(loading: boolean): void {\n this.loading = loading\n if (loading) {\n this.submitBtn.classList.add('loading')\n this.submitBtn.innerHTML = `<span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span>`\n this.textarea.disabled = true\n } else {\n this.submitBtn.classList.remove('loading')\n this.submitBtn.textContent = this.submitLabel\n this.textarea.disabled = false\n }\n this.updateSubmitState()\n }\n\n setError(message: string): void {\n this.errorEl.textContent = message\n this.errorEl.hidden = false\n }\n\n releaseElement(): HTMLDivElement {\n // Ownership of the element passes to the caller, which means destroy() will\n // never run for this instance. Stop observing here or the listener outlives\n // the popup and keeps writing `bottom` on an element it no longer manages.\n this.sheet.release()\n return this.el\n }\n\n destroy(): void {\n this.sheet.release()\n this.el.remove()\n }\n}\n","import type {\n FeedbackPayload,\n FeedbackResponse,\n SubmissionSessionResponse,\n ClarifyResponse,\n ClarifyMessage,\n} from '../types'\n\nexport interface ClarifyStreamResult {\n messages: ClarifyMessage[]\n done: boolean\n failed?: boolean\n}\n\n// Carries the HTTP status so callers can tell a retryable failure from a terminal\n// one (e.g. 409 = the submission session is no longer accepting a finalize, which\n// retrying can never fix). The message stays `HTTP <status>` for compatibility.\nexport class ApiError extends Error {\n readonly status: number\n\n constructor(status: number) {\n super(`HTTP ${status}`)\n this.name = 'ApiError'\n this.status = status\n }\n}\n\nexport function isTerminalConflict(error: unknown): boolean {\n return error instanceof ApiError && error.status === 409\n}\n\nconst DEFAULT_API_URL = 'https://makethisbetter.dev/api/v1'\n\nexport class ApiClient {\n private apiUrl: string\n private projectKey: string\n private retryDelayMs: number\n private userToken?: string\n private userTokenFn?: () => Promise<string>\n\n constructor(projectKey: string, apiUrl?: string, retryDelayMs = 1000, userToken?: string, userTokenFn?: () => Promise<string>) {\n this.projectKey = projectKey\n this.apiUrl = (apiUrl ?? DEFAULT_API_URL).replace(/\\/$/, '')\n this.retryDelayMs = retryDelayMs\n this.userToken = userToken\n this.userTokenFn = userTokenFn\n }\n\n async resolveUserToken(): Promise<string | undefined> {\n if (this.userTokenFn) return this.userTokenFn()\n return this.userToken\n }\n\n private async authHeaders(contentType?: string): Promise<Record<string, string>> {\n const headers: Record<string, string> = { 'X-Project-Key': this.projectKey }\n const token = await this.resolveUserToken()\n if (token) headers['X-User-Token'] = token\n if (contentType) headers['Content-Type'] = contentType\n return headers\n }\n\n private async submissionHeaders(token: string, contentType?: string): Promise<Record<string, string>> {\n const headers = await this.authHeaders(contentType)\n headers['X-Submission-Token'] = token\n return headers\n }\n\n async createSubmissionSession(payload: FeedbackPayload, screenshot: Blob | null): Promise<SubmissionSessionResponse> {\n const submissionToken = generateSubmissionToken()\n const form = new FormData()\n form.append('feedback[description]', payload.description)\n form.append('feedback[page_url]', payload.page_url)\n form.append('feedback[user_agent]', payload.user_agent)\n form.append('feedback[browser]', payload.browser)\n form.append('feedback[os]', payload.os)\n form.append('feedback[screen_width]', String(payload.screen_width))\n form.append('feedback[screen_height]', String(payload.screen_height))\n form.append('feedback[console_errors]', JSON.stringify(payload.console_errors))\n form.append('feedback[annotations]', JSON.stringify(payload.annotations))\n\n if (payload.target_element) {\n form.append('feedback[target_element]', JSON.stringify(payload.target_element))\n }\n if (payload.user_id) form.append('feedback[user_id]', payload.user_id)\n if (payload.reporter_external_id) form.append('feedback[reporter_external_id]', payload.reporter_external_id)\n if (payload.reporter_email) form.append('feedback[reporter_email]', payload.reporter_email)\n if (payload.user_email) form.append('feedback[user_email]', payload.user_email)\n if (payload.user_name) form.append('feedback[user_name]', payload.user_name)\n\n if (payload.breadcrumbs && payload.breadcrumbs.length > 0) {\n form.append('feedback[breadcrumbs]', JSON.stringify(payload.breadcrumbs))\n }\n\n if (payload.recording_events && payload.recording_events.length > 0) {\n const json = JSON.stringify(payload.recording_events)\n const blob = new Blob([json], { type: 'application/json' })\n form.append('feedback[recording]', blob, 'interaction-replay.json')\n form.append('feedback[recording_duration]', String(payload.recording_duration ?? 0))\n }\n\n if (screenshot) {\n const ext = screenshot.type === 'image/jpeg' ? 'jpg' : 'png'\n form.append('feedback[screenshot]', screenshot, `screenshot.${ext}`)\n }\n\n const headers = await this.authHeaders()\n headers['X-Submission-Token'] = submissionToken\n // One key per submission, reused across retries: if the first POST\n // reached the server but the response was lost, the retry must not\n // create a second feedback.\n headers['X-Idempotency-Key'] = generateIdempotencyKey()\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions`, {\n method: 'POST',\n headers,\n body: form,\n })\n const body = await res.json() as {\n submission_session: Omit<SubmissionSessionResponse, 'token'> & { token?: string }\n }\n return { ...body.submission_session, token: submissionToken }\n }\n\n async createIdentityToken(reporterExternalId: string): Promise<{ identity_token: string; board_url: string } | null> {\n const headers = await this.authHeaders('application/json')\n try {\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/identity_tokens`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ reporter_external_id: reporterExternalId }),\n })\n return await res.json()\n } catch {\n return null\n }\n }\n\n async updateReporter(feedbackId: string, email: string, identityToken: string): Promise<boolean> {\n const headers = await this.authHeaders('application/json')\n headers['X-Identity-Token'] = identityToken\n try {\n await this.fetchWithRetry(`${this.apiUrl}/widget/feedbacks/${feedbackId}/reporter`, {\n method: 'PATCH',\n headers,\n body: JSON.stringify({ reporter: { email } }),\n })\n return true\n } catch {\n return false\n }\n }\n\n async startClarification(submissionSessionId: string, token: string, message?: string): Promise<ClarifyResponse> {\n const body: Record<string, string | boolean> = {}\n if (message) body.message = message\n return this.requestClarification(submissionSessionId, token, body)\n }\n\n async retryClarification(submissionSessionId: string, token: string): Promise<ClarifyResponse> {\n return this.requestClarification(submissionSessionId, token, { retry: true })\n }\n\n private async requestClarification(\n submissionSessionId: string,\n token: string,\n body: Record<string, string | boolean>,\n ): Promise<ClarifyResponse> {\n const headers = await this.submissionHeaders(token, 'application/json')\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/clarification`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n })\n const response = await res.json() as { clarification: ClarifyResponse }\n return response.clarification\n }\n\n async getClarification(submissionSessionId: string, token: string): Promise<ClarifyResponse> {\n const headers = await this.submissionHeaders(token)\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/clarification`, {\n method: 'GET',\n headers,\n })\n const response = await res.json() as { clarification: ClarifyResponse }\n return response.clarification\n }\n\n // Streams a clarification turn over SSE. Calls onDelta for each token and\n // resolves with the committed result. Throws if the server doesn't stream\n // (e.g. old backend returns JSON) so the caller can fall back to polling.\n async streamClarification(\n submissionSessionId: string,\n token: string,\n onDelta: (text: string) => void,\n signal?: AbortSignal,\n ): Promise<ClarifyStreamResult> {\n const headers = await this.submissionHeaders(token, 'application/json')\n headers['Accept'] = 'text/event-stream'\n\n const res = await fetch(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/clarification`, {\n method: 'POST',\n headers,\n body: JSON.stringify({}),\n signal,\n })\n\n const contentType = res.headers.get('Content-Type') ?? ''\n if (!res.ok || !res.body || !contentType.includes('text/event-stream')) {\n throw new Error('clarify stream unavailable')\n }\n\n return consumeSse(res.body, onDelta)\n }\n\n async finalizeSubmissionSession(submissionSessionId: string, token: string): Promise<FeedbackResponse> {\n const headers = await this.submissionHeaders(token)\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/feedback`, {\n method: 'POST',\n headers,\n })\n const response = await res.json() as { feedback: FeedbackResponse }\n return response.feedback\n }\n\n async abandonSubmissionSession(submissionSessionId: string, token: string): Promise<void> {\n const headers = await this.submissionHeaders(token)\n await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}`, {\n method: 'DELETE',\n headers,\n })\n }\n\n private async fetchWithRetry(url: string, init: RequestInit, retries = 1): Promise<Response> {\n let res: Response\n try {\n res = await fetch(url, init)\n } catch (err) {\n if (retries > 0) {\n await delay(this.retryDelayMs)\n return this.fetchWithRetry(url, init, retries - 1)\n }\n throw err\n }\n\n if (res.ok) return res\n if (res.status >= 500 && retries > 0) {\n await delay(this.retryDelayMs)\n return this.fetchWithRetry(url, init, retries - 1)\n }\n throw new ApiError(res.status)\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve()\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nasync function consumeSse(\n body: ReadableStream<Uint8Array>,\n onDelta: (text: string) => void,\n): Promise<ClarifyStreamResult> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let result: ClarifyStreamResult | null = null\n\n const flush = (raw: string): void => {\n // Each SSE record is \"event: <name>\\n data: <json>\". Parse event + data.\n const eventLine = raw.split('\\n').find(l => l.startsWith('event:'))\n const dataLine = raw.split('\\n').find(l => l.startsWith('data:'))\n if (!dataLine) return\n const event = eventLine?.slice(6).trim()\n const payload = JSON.parse(dataLine.slice(5).trim())\n if (event === 'delta' && typeof payload.text === 'string') {\n onDelta(payload.text)\n } else if (event === 'done') {\n result = {\n messages: Array.isArray(payload.messages) ? payload.messages : [],\n done: payload.done !== false,\n failed: payload.error === true,\n }\n }\n }\n\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n let sep: number\n while ((sep = buffer.indexOf('\\n\\n')) !== -1) {\n const record = buffer.slice(0, sep)\n buffer = buffer.slice(sep + 2)\n try { flush(record) } catch { /* skip malformed record */ }\n }\n }\n\n buffer += decoder.decode()\n if (buffer.trim()) {\n try { flush(buffer) } catch { /* handled by the missing done check below */ }\n }\n if (!result) throw new Error('clarify stream ended before done')\n\n return result\n}\n\nfunction generateIdempotencyKey(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`\n}\n\nfunction generateSubmissionToken(): string {\n if (typeof crypto === 'undefined' || typeof crypto.getRandomValues !== 'function') {\n throw new Error('Secure random generation is unavailable')\n }\n\n const bytes = crypto.getRandomValues(new Uint8Array(32))\n return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('')\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { ApiClient, ClarifyStreamResult } from '../api/client'\nimport { isTerminalConflict } from '../api/client'\nimport type { ClarifyMessage, ClarifyResponse } from '../types'\nimport { escapeHtml } from '../context/dom-utils'\nimport { SheetLayout } from './sheet'\n\nconst POLL_INTERVAL_MS = 2000\n// Give up polling after this long with no assistant reply so the card never spins\n// forever (e.g. a backend job that silently died). This is the queued path — the\n// answer is being generated by a job, not streamed — so it needs room for queue wait\n// plus generation. The 12s deadline on the streaming request is a different budget:\n// there, silence means the stream itself is stuck.\nconst POLL_TIMEOUT_MS = 45000\n\ninterface ClarifyCardOptions {\n submissionSessionId: string\n submissionToken: string\n apiClient: ApiClient\n messages: I18nMessages\n onFinalize: () => Promise<void> | void\n element?: HTMLDivElement\n position?: 'left' | 'right'\n x?: number\n y?: number\n preloadedResult?: ClarifyStreamResult\n pendingClarification?: Promise<ClarifyStreamResult | null>\n}\n\nconst CARD_WIDTH = 346\nconst CARD_HEIGHT = 270\n\nexport class ClarifyCard {\n private el: HTMLDivElement\n private sheet: SheetLayout\n private messagesEl!: HTMLDivElement\n private inputEl!: HTMLTextAreaElement\n private sendBtn!: HTMLButtonElement\n private pollTimer: ReturnType<typeof setInterval> | null = null\n private pollDeadline = 0\n private streamingBubble: HTMLDivElement | null = null\n private submissionSessionId: string\n private submissionToken: string\n private apiClient: ApiClient\n private onFinalize: () => Promise<void> | void\n private i18n: I18nMessages\n private lastMessages: ClarifyMessage[] = []\n private done = false\n private sending = false\n private finalizing = false\n private destroyed = false\n private unrecoverable = false\n\n private preloadedResult?: ClarifyStreamResult\n private pendingClarification?: Promise<ClarifyStreamResult | null>\n\n constructor(shadow: ShadowContainer, opts: ClarifyCardOptions) {\n this.submissionSessionId = opts.submissionSessionId\n this.submissionToken = opts.submissionToken\n this.apiClient = opts.apiClient\n this.onFinalize = opts.onFinalize\n this.i18n = opts.messages\n this.preloadedResult = opts.preloadedResult\n this.pendingClarification = opts.pendingClarification\n\n const existingElement = opts.element\n this.el = existingElement ?? shadow.el<HTMLDivElement>('div', 'mtb-clarify')\n this.el.className = existingElement ? 'mtb-clarify mtb-clarify-continuation' : 'mtb-clarify'\n this.el.innerHTML = this.buildHTML(opts.messages)\n this.sheet = new SheetLayout(this.el)\n if (!existingElement) {\n shadow.append(this.el)\n this.positionCard(opts.x, opts.y, opts.position ?? 'right')\n } else {\n // A continuation inherits the comment popup's element, and with it the\n // sheet layout that popup was using — but the class just changed from\n // .mtb-popup to .mtb-clarify, so the sheet rules stop matching and the\n // cleared inline offsets leave a fixed element with nowhere to sit.\n // Re-applying binds the new class to the same geometry and re-attaches\n // the keyboard tracking the released popup gave up.\n this.sheet.apply()\n }\n\n this.messagesEl = this.el.querySelector('.mtb-clarify-messages')!\n this.bindEvents()\n this.startConversation()\n }\n\n // Anchors the card near the annotation point, clamped to the viewport so it\n // never overflows a screen edge (mirrors CommentPopup.positionPopup).\n private positionCard(x: number | undefined, y: number | undefined, tabPosition: 'left' | 'right'): void {\n if (this.sheet.apply()) return\n\n const vw = window.innerWidth\n const vh = window.innerHeight\n const margin = 12\n const tabWidth = 32\n const cardW = Math.min(CARD_WIDTH, vw - 2 * margin - tabWidth)\n const cardH = this.el.offsetHeight || CARD_HEIGHT\n const minLeft = margin + (tabPosition === 'left' ? tabWidth : 0)\n const maxRight = vw - margin - (tabPosition === 'right' ? tabWidth : 0)\n\n if (x === undefined || y === undefined) {\n const centeredLeft = Math.max(minLeft, (vw - cardW) / 2)\n this.el.style.left = `${Math.min(centeredLeft, maxRight - cardW)}px`\n this.el.style.top = `${Math.max(margin, (vh - cardH) / 2)}px`\n this.el.style.maxHeight = `${vh - 2 * margin}px`\n return\n }\n\n let left = x + 12\n let top = y + 12\n if (left + cardW > maxRight) left = x - cardW - 12\n if (left + cardW > maxRight) left = maxRight - cardW\n if (left < minLeft) left = minLeft\n if (top + cardH > vh - margin) top = vh - cardH - margin\n if (top < margin) top = margin\n\n this.el.style.left = `${left}px`\n this.el.style.top = `${top}px`\n this.el.style.maxHeight = `${vh - top - margin}px`\n }\n\n private buildHTML(m: I18nMessages): string {\n return `\n <div class=\"mtb-clarify-header\">\n <span class=\"mtb-clarify-icon\">\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 3l1.6 5.4L19 10l-5.4 1.6L12 17l-1.6-5.4L5 10l5.4-1.6L12 3z\"/>\n </svg>\n </span>\n <div class=\"mtb-clarify-titles\">\n <div class=\"mtb-clarify-title\">${escapeHtml(m.clarify.title)}</div>\n <div class=\"mtb-clarify-subtitle\">${escapeHtml(m.clarify.subtitle)}</div>\n </div>\n <button class=\"mtb-clarify-close\" type=\"button\" title=\"${escapeHtml(m.clarify.skip)}\" aria-label=\"${escapeHtml(m.clarify.skip)}\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n <div class=\"mtb-clarify-messages\"></div>\n <div class=\"mtb-clarify-footer\">${this.buildConversationControls(m)}</div>\n `\n }\n\n private buildConversationControls(m: I18nMessages): string {\n return `\n <textarea class=\"mtb-clarify-input\" rows=\"1\" placeholder=\"${escapeHtml(m.clarify.placeholder)}\"></textarea>\n <div class=\"mtb-clarify-actions\">\n <button class=\"mtb-clarify-skip\" type=\"button\">${escapeHtml(m.clarify.skip)}</button>\n <button class=\"mtb-clarify-send\" type=\"button\" disabled>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n <span>${escapeHtml(m.clarify.send)}</span>\n </button>\n </div>\n `\n }\n\n private bindEvents(): void {\n this.el.querySelector('.mtb-clarify-close')!.addEventListener('click', () => this.skipAndFinalize())\n this.bindConversationControls()\n }\n\n private bindConversationControls(): void {\n this.inputEl = this.el.querySelector('.mtb-clarify-input')!\n this.sendBtn = this.el.querySelector('.mtb-clarify-send')!\n this.el.querySelector('.mtb-clarify-skip')!.addEventListener('click', () => this.skipAndFinalize())\n\n this.inputEl.addEventListener('input', () => {\n this.sendBtn.disabled = !this.inputEl.value.trim()\n })\n\n this.inputEl.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n this.sendMessage()\n }\n })\n\n this.sendBtn.addEventListener('click', () => this.sendMessage())\n }\n\n private skipAndFinalize(): void {\n this.stopPolling()\n void this.finalize()\n }\n\n private async startConversation(): Promise<void> {\n if (this.preloadedResult) {\n this.applyResult(this.preloadedResult)\n return\n }\n\n if (this.pendingClarification) {\n this.showThinking()\n try {\n const result = await this.pendingClarification\n if (this.destroyed) return\n if (result) {\n if (!this.applyResult(result)) this.startPolling()\n } else {\n await this.runInitialTurnViaPolling()\n }\n } catch {\n if (this.destroyed) return\n await this.runInitialTurnViaPolling()\n }\n return\n }\n\n this.showThinking()\n await this.runInitialTurn()\n }\n\n private async sendMessage(): Promise<void> {\n const text = this.inputEl.value.trim()\n if (!text || this.sending) return\n\n this.sending = true\n this.inputEl.disabled = true\n this.sendBtn.disabled = true\n this.stopPolling()\n\n this.appendMessage({ role: 'user', content: text })\n this.inputEl.value = ''\n this.showThinking()\n this.clearError()\n\n try {\n await this.runAnswerTurn(text)\n } catch {\n if (this.destroyed) return\n this.renderConversation(this.lastMessages, false)\n this.inputEl.value = text\n this.showError()\n } finally {\n this.sending = false\n this.inputEl.disabled = false\n this.sendBtn.disabled = !this.inputEl.value.trim()\n this.inputEl.focus()\n }\n }\n\n // Streams the assistant reply; falls back to POST + polling if the backend\n // doesn't support SSE (older server) or the stream errors mid-flight.\n private async runInitialTurn(): Promise<void> {\n try {\n const result = await this.apiClient.streamClarification(\n this.submissionSessionId,\n this.submissionToken,\n (text) => this.appendStreamDelta(text),\n )\n if (this.destroyed) return\n this.endStreamingBubble()\n if (!this.applyResult(result)) this.startPolling()\n } catch {\n if (this.destroyed) return\n this.endStreamingBubble()\n await this.runInitialTurnViaPolling()\n }\n }\n\n private async runInitialTurnViaPolling(): Promise<void> {\n try {\n const res = await this.apiClient.startClarification(\n this.submissionSessionId,\n this.submissionToken,\n )\n if (this.destroyed) return\n if (!this.applyResult(res)) this.startPolling()\n } catch {\n if (this.destroyed) return\n this.handleFailure()\n }\n }\n\n private async runAnswerTurn(message: string): Promise<void> {\n const res = await this.apiClient.startClarification(\n this.submissionSessionId,\n this.submissionToken,\n message,\n )\n if (this.destroyed) return\n if (!this.applyResult(res)) this.startPolling()\n }\n\n private showError(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n const error = document.createElement('div')\n error.className = 'mtb-clarify-error'\n error.textContent = this.i18n.error.submit\n footer.prepend(error)\n }\n\n private clearError(): void {\n this.el.querySelector('.mtb-clarify-error')?.remove()\n }\n\n private appendStreamDelta(text: string): void {\n if (!this.streamingBubble) {\n this.removeThinking()\n this.streamingBubble = document.createElement('div')\n this.streamingBubble.className = 'mtb-clarify-bubble mtb-clarify-ai'\n this.messagesEl.appendChild(this.streamingBubble)\n }\n this.streamingBubble.textContent = (this.streamingBubble.textContent ?? '') + text\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private endStreamingBubble(): void {\n this.streamingBubble = null\n }\n\n private startPolling(): void {\n this.stopPolling()\n this.pollDeadline = Date.now() + POLL_TIMEOUT_MS\n this.pollTimer = setInterval(() => this.poll(), POLL_INTERVAL_MS)\n }\n\n private stopPolling(): void {\n if (this.pollTimer !== null) {\n clearInterval(this.pollTimer)\n this.pollTimer = null\n }\n }\n\n private async poll(): Promise<void> {\n if (Date.now() > this.pollDeadline) {\n this.stopPolling()\n this.handleFailure()\n return\n }\n try {\n const res = await this.apiClient.getClarification(\n this.submissionSessionId,\n this.submissionToken,\n )\n if (this.destroyed) return\n if (this.applyResult(res)) this.stopPolling()\n } catch {\n if (this.destroyed) return\n this.stopPolling()\n this.handleFailure()\n }\n }\n\n private handleDone(): void {\n if (this.done) return\n this.done = true\n this.stopPolling()\n this.removeThinking()\n this.showFinalizeButton()\n }\n\n private handleFailure(): void {\n if (this.done) return\n this.done = true\n this.stopPolling()\n this.removeThinking()\n this.showClarificationFailureActions()\n }\n\n private showClarificationFailureActions(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `\n <div class=\"mtb-clarify-error\">${escapeHtml(this.i18n.clarify.error)}</div>\n <div class=\"mtb-clarify-actions\">\n <button class=\"mtb-clarify-fallback\" type=\"button\">${escapeHtml(this.i18n.clarify.send_feedback)}</button>\n <button class=\"mtb-clarify-retry\" type=\"button\">${escapeHtml(this.i18n.clarify.retry)}</button>\n </div>\n `\n footer.querySelector('.mtb-clarify-fallback')!.addEventListener('click', () => this.skipAndFinalize())\n footer.querySelector('.mtb-clarify-retry')!.addEventListener('click', () => {\n if (!this.destroyed) void this.retryClarification()\n })\n }\n\n private async retryClarification(): Promise<void> {\n if (this.sending || this.destroyed) return\n\n this.sending = true\n this.done = false\n this.showConversationControls()\n this.inputEl.disabled = true\n this.sendBtn.disabled = true\n this.renderConversation(this.lastMessages, false)\n\n try {\n const snapshot = await this.apiClient.getClarification(this.submissionSessionId, this.submissionToken)\n if (this.destroyed) return\n let result = snapshot\n // Each server status needs a different move. `processing` means a job is\n // already running for this session, so kicking off another turn would\n // duplicate it — fall through to polling instead. `awaiting_response` means\n // the assistant already asked its question and the server is waiting on the\n // reporter; applyResult hands the card back to them rather than polling for\n // a state only a human reply can change.\n if (snapshot.status === 'failed') {\n result = await this.apiClient.retryClarification(this.submissionSessionId, this.submissionToken)\n } else if (snapshot.status === 'idle') {\n result = await this.apiClient.startClarification(this.submissionSessionId, this.submissionToken)\n }\n if (this.destroyed) return\n if (!this.applyResult(result)) {\n this.showConversationControls()\n this.startPolling()\n }\n } catch {\n if (this.destroyed) return\n this.handleFailure()\n } finally {\n this.sending = false\n }\n }\n\n private showConversationControls(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = this.buildConversationControls(this.i18n)\n this.bindConversationControls()\n }\n\n // Returns true when the exchange has settled — the caller uses that to decide\n // whether it still needs to poll.\n private applyResult(result: ClarifyStreamResult | ClarifyResponse): boolean {\n this.renderConversation(result.messages, result.done)\n const status = 'status' in result ? result.status : undefined\n const failed = 'status' in result ? result.status === 'failed' : result.failed === true\n if (failed) {\n this.handleFailure()\n return true\n }\n if (result.done) {\n this.handleDone()\n return true\n }\n if (status === 'awaiting_response') {\n // The ball is in the reporter's court: polling here would spin until the\n // deadline and then show a failure card for a perfectly healthy session.\n this.stopPolling()\n this.removeThinking()\n this.enableInput()\n return true\n }\n return false\n }\n\n private enableInput(): void {\n if (!this.el.contains(this.inputEl)) this.showConversationControls()\n this.inputEl.disabled = false\n this.sendBtn.disabled = !this.inputEl.value.trim()\n }\n\n private showFinalizeButton(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `\n <button class=\"mtb-clarify-send-feedback\" type=\"button\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n <span>${escapeHtml(this.i18n.clarify.send_feedback)}</span>\n </button>\n `\n footer.querySelector('.mtb-clarify-send-feedback')!.addEventListener('click', () => {\n if (!this.destroyed) void this.finalize()\n })\n }\n\n private async finalize(): Promise<void> {\n if (this.finalizing || this.destroyed || this.unrecoverable) return\n\n this.finalizing = true\n this.el.querySelectorAll<HTMLButtonElement>('button').forEach(button => { button.disabled = true })\n try {\n await this.onFinalize()\n } catch (error) {\n if (this.destroyed) return\n this.finalizing = false\n this.clearError()\n // A 409 means the server will never accept this session again (it expired\n // past its retention window, or was already finalized/abandoned). Offering\n // Retry there just loops the reporter through the same generic error, so say\n // what happened and what to do instead.\n if (isTerminalConflict(error)) {\n this.showUnrecoverable()\n return\n }\n this.showFinalizeRetry()\n }\n }\n\n private showUnrecoverable(): void {\n this.unrecoverable = true\n this.stopPolling()\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `<div class=\"mtb-clarify-error\">${escapeHtml(this.i18n.clarify.expired)}</div>`\n }\n\n // Renders the reason and the retry together: replacing the footer wholesale is\n // what used to discard the error message showError() had just prepended, so the\n // reporter saw a bare Retry button with no explanation.\n private showFinalizeRetry(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `\n <div class=\"mtb-clarify-error\">${escapeHtml(this.i18n.error.submit)}</div>\n <button class=\"mtb-clarify-send-feedback mtb-clarify-retry\" type=\"button\">${escapeHtml(this.i18n.clarify.retry)}</button>\n `\n footer.querySelector('.mtb-clarify-retry')!.addEventListener('click', () => {\n if (!this.destroyed) void this.finalize()\n })\n }\n\n private renderConversation(messages: ClarifyMessage[], done: boolean): void {\n this.lastMessages = messages\n this.renderMessages(messages)\n const last = messages[messages.length - 1]\n if (!done && (!last || last.role === 'user')) this.showThinking()\n }\n\n private renderMessages(messages: ClarifyMessage[]): void {\n this.messagesEl.innerHTML = ''\n for (const msg of messages) {\n this.appendMessage(msg)\n }\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private appendMessage(msg: ClarifyMessage): void {\n const bubble = document.createElement('div')\n bubble.className = msg.role === 'user' ? 'mtb-clarify-bubble mtb-clarify-user' : 'mtb-clarify-bubble mtb-clarify-ai'\n bubble.textContent = msg.content\n this.messagesEl.appendChild(bubble)\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private showThinking(): void {\n if (this.messagesEl.querySelector('.mtb-clarify-thinking')) return\n const dots = document.createElement('div')\n dots.className = 'mtb-clarify-bubble mtb-clarify-ai mtb-clarify-thinking'\n dots.innerHTML = '<span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span>'\n this.messagesEl.appendChild(dots)\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private removeThinking(): void {\n this.messagesEl.querySelector('.mtb-clarify-thinking')?.remove()\n }\n\n destroy(): void {\n this.destroyed = true\n this.stopPolling()\n this.sheet.release()\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport { BRAND_COLOR } from '../styles'\n\nconst SUCCESS_AUTO_CLOSE_MS = 5000\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport interface SuccessCardOptions {\n skipFollowup?: boolean\n emailCapture?: {\n onSubmit: (email: string) => Promise<boolean>\n }\n}\n\nexport class SuccessCard {\n private el: HTMLDivElement\n private messages: I18nMessages\n\n constructor(shadow: ShadowContainer, messages: I18nMessages, onClose: () => void, onViewFeedback?: () => void, options?: SuccessCardOptions) {\n this.messages = messages\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-success')\n this.el.style.right = '20px'\n this.el.style.bottom = '20px'\n\n const title = options?.skipFollowup ? messages.success.title_no_ai : messages.success.title\n const msg = options?.skipFollowup ? messages.success.message_no_ai : messages.success.message\n\n const viewLink = onViewFeedback\n ? `<button class=\"mtb-view-feedback-link\">${messages.success.view_feedback} <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14M12 5l7 7-7 7\"/></svg></button>`\n : ''\n\n const emailCapture = options?.emailCapture\n ? `\n <div class=\"mtb-email-capture\">\n <div class=\"mtb-email-prompt\">${messages.success.email_prompt}</div>\n <div class=\"mtb-email-row\">\n <input class=\"mtb-email-input\" type=\"email\" placeholder=\"${messages.success.email_placeholder}\">\n <button class=\"mtb-email-submit\">${messages.success.email_submit}</button>\n </div>\n <div class=\"mtb-email-error\" hidden>${messages.success.email_error}</div>\n </div>`\n : ''\n\n this.el.innerHTML = `\n <div class=\"mtb-success-icon\">\n <svg width=\"23\" height=\"23\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${BRAND_COLOR}\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n </div>\n <div class=\"mtb-success-title\">${title}</div>\n <div class=\"mtb-success-msg\">${msg}</div>\n ${emailCapture}\n ${viewLink}\n <button class=\"mtb-close-link\">${messages.success.close}</button>\n `\n shadow.append(this.el)\n this.el.querySelector('.mtb-close-link')!.addEventListener('click', onClose)\n\n if (onViewFeedback) {\n this.el.querySelector('.mtb-view-feedback-link')!.addEventListener('click', onViewFeedback)\n }\n\n if (options?.emailCapture) {\n this.bindEmailCapture(options.emailCapture.onSubmit)\n } else {\n setTimeout(() => onClose(), SUCCESS_AUTO_CLOSE_MS)\n }\n }\n\n private bindEmailCapture(onSubmit: (email: string) => Promise<boolean>): void {\n const input = this.el.querySelector<HTMLInputElement>('.mtb-email-input')!\n const submit = this.el.querySelector<HTMLButtonElement>('.mtb-email-submit')!\n const error = this.el.querySelector<HTMLDivElement>('.mtb-email-error')!\n\n const handle = async () => {\n const email = input.value.trim()\n if (!EMAIL_PATTERN.test(email)) {\n input.classList.add('mtb-email-invalid')\n return\n }\n input.classList.remove('mtb-email-invalid')\n error.hidden = true\n submit.disabled = true\n\n const saved = await onSubmit(email)\n if (saved) {\n this.el.querySelector('.mtb-email-capture')!.innerHTML =\n `<div class=\"mtb-email-saved\">${this.messages.success.email_saved}</div>`\n } else {\n error.hidden = false\n submit.disabled = false\n }\n }\n\n submit.addEventListener('click', handle)\n input.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') handle()\n })\n }\n\n destroy(): void {\n this.el.remove()\n }\n}\n","export function resolveUrl(url, baseUrl) {\n // url is absolute already\n if (url.match(/^[a-z]+:\\/\\//i)) {\n return url;\n }\n // url is absolute already, without protocol\n if (url.match(/^\\/\\//)) {\n return window.location.protocol + url;\n }\n // dataURI, mailto:, tel:, etc.\n if (url.match(/^[a-z]+:/i)) {\n return url;\n }\n const doc = document.implementation.createHTMLDocument();\n const base = doc.createElement('base');\n const a = doc.createElement('a');\n doc.head.appendChild(base);\n doc.body.appendChild(a);\n if (baseUrl) {\n base.href = baseUrl;\n }\n a.href = url;\n return a.href;\n}\nexport const uuid = (() => {\n // generate uuid for className of pseudo elements.\n // We should not use GUIDs, otherwise pseudo elements sometimes cannot be captured.\n let counter = 0;\n // ref: http://stackoverflow.com/a/6248722/2519373\n const random = () => \n // eslint-disable-next-line no-bitwise\n `0000${((Math.random() * 36 ** 4) << 0).toString(36)}`.slice(-4);\n return () => {\n counter += 1;\n return `u${random()}${counter}`;\n };\n})();\nexport function delay(ms) {\n return (args) => new Promise((resolve) => {\n setTimeout(() => resolve(args), ms);\n });\n}\nexport function toArray(arrayLike) {\n const arr = [];\n for (let i = 0, l = arrayLike.length; i < l; i++) {\n arr.push(arrayLike[i]);\n }\n return arr;\n}\nlet styleProps = null;\nexport function getStyleProperties(options = {}) {\n if (styleProps) {\n return styleProps;\n }\n if (options.includeStyleProperties) {\n styleProps = options.includeStyleProperties;\n return styleProps;\n }\n styleProps = toArray(window.getComputedStyle(document.documentElement));\n return styleProps;\n}\nfunction px(node, styleProperty) {\n const win = node.ownerDocument.defaultView || window;\n const val = win.getComputedStyle(node).getPropertyValue(styleProperty);\n return val ? parseFloat(val.replace('px', '')) : 0;\n}\nfunction getNodeWidth(node) {\n const leftBorder = px(node, 'border-left-width');\n const rightBorder = px(node, 'border-right-width');\n return node.clientWidth + leftBorder + rightBorder;\n}\nfunction getNodeHeight(node) {\n const topBorder = px(node, 'border-top-width');\n const bottomBorder = px(node, 'border-bottom-width');\n return node.clientHeight + topBorder + bottomBorder;\n}\nexport function getImageSize(targetNode, options = {}) {\n const width = options.width || getNodeWidth(targetNode);\n const height = options.height || getNodeHeight(targetNode);\n return { width, height };\n}\nexport function getPixelRatio() {\n let ratio;\n let FINAL_PROCESS;\n try {\n FINAL_PROCESS = process;\n }\n catch (e) {\n // pass\n }\n const val = FINAL_PROCESS && FINAL_PROCESS.env\n ? FINAL_PROCESS.env.devicePixelRatio\n : null;\n if (val) {\n ratio = parseInt(val, 10);\n if (Number.isNaN(ratio)) {\n ratio = 1;\n }\n }\n return ratio || window.devicePixelRatio || 1;\n}\n// @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size\nconst canvasDimensionLimit = 16384;\nexport function checkCanvasDimensions(canvas) {\n if (canvas.width > canvasDimensionLimit ||\n canvas.height > canvasDimensionLimit) {\n if (canvas.width > canvasDimensionLimit &&\n canvas.height > canvasDimensionLimit) {\n if (canvas.width > canvas.height) {\n canvas.height *= canvasDimensionLimit / canvas.width;\n canvas.width = canvasDimensionLimit;\n }\n else {\n canvas.width *= canvasDimensionLimit / canvas.height;\n canvas.height = canvasDimensionLimit;\n }\n }\n else if (canvas.width > canvasDimensionLimit) {\n canvas.height *= canvasDimensionLimit / canvas.width;\n canvas.width = canvasDimensionLimit;\n }\n else {\n canvas.width *= canvasDimensionLimit / canvas.height;\n canvas.height = canvasDimensionLimit;\n }\n }\n}\nexport function canvasToBlob(canvas, options = {}) {\n if (canvas.toBlob) {\n return new Promise((resolve) => {\n canvas.toBlob(resolve, options.type ? options.type : 'image/png', options.quality ? options.quality : 1);\n });\n }\n return new Promise((resolve) => {\n const binaryString = window.atob(canvas\n .toDataURL(options.type ? options.type : undefined, options.quality ? options.quality : undefined)\n .split(',')[1]);\n const len = binaryString.length;\n const binaryArray = new Uint8Array(len);\n for (let i = 0; i < len; i += 1) {\n binaryArray[i] = binaryString.charCodeAt(i);\n }\n resolve(new Blob([binaryArray], {\n type: options.type ? options.type : 'image/png',\n }));\n });\n}\nexport function createImage(url) {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n img.decode().then(() => {\n requestAnimationFrame(() => resolve(img));\n });\n };\n img.onerror = reject;\n img.crossOrigin = 'anonymous';\n img.decoding = 'async';\n img.src = url;\n });\n}\nexport async function svgToDataURL(svg) {\n return Promise.resolve()\n .then(() => new XMLSerializer().serializeToString(svg))\n .then(encodeURIComponent)\n .then((html) => `data:image/svg+xml;charset=utf-8,${html}`);\n}\nexport async function nodeToDataURL(node, width, height) {\n const xmlns = 'http://www.w3.org/2000/svg';\n const svg = document.createElementNS(xmlns, 'svg');\n const foreignObject = document.createElementNS(xmlns, 'foreignObject');\n svg.setAttribute('width', `${width}`);\n svg.setAttribute('height', `${height}`);\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n foreignObject.setAttribute('width', '100%');\n foreignObject.setAttribute('height', '100%');\n foreignObject.setAttribute('x', '0');\n foreignObject.setAttribute('y', '0');\n foreignObject.setAttribute('externalResourcesRequired', 'true');\n svg.appendChild(foreignObject);\n foreignObject.appendChild(node);\n return svgToDataURL(svg);\n}\nexport const isInstanceOfElement = (node, instance) => {\n if (node instanceof instance)\n return true;\n const nodePrototype = Object.getPrototypeOf(node);\n if (nodePrototype === null)\n return false;\n return (nodePrototype.constructor.name === instance.name ||\n isInstanceOfElement(nodePrototype, instance));\n};\n//# sourceMappingURL=util.js.map","import { uuid, getStyleProperties } from './util';\nfunction formatCSSText(style) {\n const content = style.getPropertyValue('content');\n return `${style.cssText} content: '${content.replace(/'|\"/g, '')}';`;\n}\nfunction formatCSSProperties(style, options) {\n return getStyleProperties(options)\n .map((name) => {\n const value = style.getPropertyValue(name);\n const priority = style.getPropertyPriority(name);\n return `${name}: ${value}${priority ? ' !important' : ''};`;\n })\n .join(' ');\n}\nfunction getPseudoElementStyle(className, pseudo, style, options) {\n const selector = `.${className}:${pseudo}`;\n const cssText = style.cssText\n ? formatCSSText(style)\n : formatCSSProperties(style, options);\n return document.createTextNode(`${selector}{${cssText}}`);\n}\nfunction clonePseudoElement(nativeNode, clonedNode, pseudo, options) {\n const style = window.getComputedStyle(nativeNode, pseudo);\n const content = style.getPropertyValue('content');\n if (content === '' || content === 'none') {\n return;\n }\n const className = uuid();\n try {\n clonedNode.className = `${clonedNode.className} ${className}`;\n }\n catch (err) {\n return;\n }\n const styleElement = document.createElement('style');\n styleElement.appendChild(getPseudoElementStyle(className, pseudo, style, options));\n clonedNode.appendChild(styleElement);\n}\nexport function clonePseudoElements(nativeNode, clonedNode, options) {\n clonePseudoElement(nativeNode, clonedNode, ':before', options);\n clonePseudoElement(nativeNode, clonedNode, ':after', options);\n}\n//# sourceMappingURL=clone-pseudos.js.map","const WOFF = 'application/font-woff';\nconst JPEG = 'image/jpeg';\nconst mimes = {\n woff: WOFF,\n woff2: WOFF,\n ttf: 'application/font-truetype',\n eot: 'application/vnd.ms-fontobject',\n png: 'image/png',\n jpg: JPEG,\n jpeg: JPEG,\n gif: 'image/gif',\n tiff: 'image/tiff',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n};\nfunction getExtension(url) {\n const match = /\\.([^./]*?)$/g.exec(url);\n return match ? match[1] : '';\n}\nexport function getMimeType(url) {\n const extension = getExtension(url).toLowerCase();\n return mimes[extension] || '';\n}\n//# sourceMappingURL=mimes.js.map","function getContentFromDataUrl(dataURL) {\n return dataURL.split(/,/)[1];\n}\nexport function isDataUrl(url) {\n return url.search(/^(data:)/) !== -1;\n}\nexport function makeDataUrl(content, mimeType) {\n return `data:${mimeType};base64,${content}`;\n}\nexport async function fetchAsDataURL(url, init, process) {\n const res = await fetch(url, init);\n if (res.status === 404) {\n throw new Error(`Resource \"${res.url}\" not found`);\n }\n const blob = await res.blob();\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = reject;\n reader.onloadend = () => {\n try {\n resolve(process({ res, result: reader.result }));\n }\n catch (error) {\n reject(error);\n }\n };\n reader.readAsDataURL(blob);\n });\n}\nconst cache = {};\nfunction getCacheKey(url, contentType, includeQueryParams) {\n let key = url.replace(/\\?.*/, '');\n if (includeQueryParams) {\n key = url;\n }\n // font resource\n if (/ttf|otf|eot|woff2?/i.test(key)) {\n key = key.replace(/.*\\//, '');\n }\n return contentType ? `[${contentType}]${key}` : key;\n}\nexport async function resourceToDataURL(resourceUrl, contentType, options) {\n const cacheKey = getCacheKey(resourceUrl, contentType, options.includeQueryParams);\n if (cache[cacheKey] != null) {\n return cache[cacheKey];\n }\n // ref: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache\n if (options.cacheBust) {\n // eslint-disable-next-line no-param-reassign\n resourceUrl += (/\\?/.test(resourceUrl) ? '&' : '?') + new Date().getTime();\n }\n let dataURL;\n try {\n const content = await fetchAsDataURL(resourceUrl, options.fetchRequestInit, ({ res, result }) => {\n if (!contentType) {\n // eslint-disable-next-line no-param-reassign\n contentType = res.headers.get('Content-Type') || '';\n }\n return getContentFromDataUrl(result);\n });\n dataURL = makeDataUrl(content, contentType);\n }\n catch (error) {\n dataURL = options.imagePlaceholder || '';\n let msg = `Failed to fetch resource: ${resourceUrl}`;\n if (error) {\n msg = typeof error === 'string' ? error : error.message;\n }\n if (msg) {\n console.warn(msg);\n }\n }\n cache[cacheKey] = dataURL;\n return dataURL;\n}\n//# sourceMappingURL=dataurl.js.map","import { clonePseudoElements } from './clone-pseudos';\nimport { createImage, toArray, isInstanceOfElement, getStyleProperties, } from './util';\nimport { getMimeType } from './mimes';\nimport { resourceToDataURL } from './dataurl';\nasync function cloneCanvasElement(canvas) {\n const dataURL = canvas.toDataURL();\n if (dataURL === 'data:,') {\n return canvas.cloneNode(false);\n }\n return createImage(dataURL);\n}\nasync function cloneVideoElement(video, options) {\n if (video.currentSrc) {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n canvas.width = video.clientWidth;\n canvas.height = video.clientHeight;\n ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n const dataURL = canvas.toDataURL();\n return createImage(dataURL);\n }\n const poster = video.poster;\n const contentType = getMimeType(poster);\n const dataURL = await resourceToDataURL(poster, contentType, options);\n return createImage(dataURL);\n}\nasync function cloneIFrameElement(iframe, options) {\n var _a;\n try {\n if ((_a = iframe === null || iframe === void 0 ? void 0 : iframe.contentDocument) === null || _a === void 0 ? void 0 : _a.body) {\n return (await cloneNode(iframe.contentDocument.body, options, true));\n }\n }\n catch (_b) {\n // Failed to clone iframe\n }\n return iframe.cloneNode(false);\n}\nasync function cloneSingleNode(node, options) {\n if (isInstanceOfElement(node, HTMLCanvasElement)) {\n return cloneCanvasElement(node);\n }\n if (isInstanceOfElement(node, HTMLVideoElement)) {\n return cloneVideoElement(node, options);\n }\n if (isInstanceOfElement(node, HTMLIFrameElement)) {\n return cloneIFrameElement(node, options);\n }\n return node.cloneNode(isSVGElement(node));\n}\nconst isSlotElement = (node) => node.tagName != null && node.tagName.toUpperCase() === 'SLOT';\nconst isSVGElement = (node) => node.tagName != null && node.tagName.toUpperCase() === 'SVG';\nasync function cloneChildren(nativeNode, clonedNode, options) {\n var _a, _b;\n if (isSVGElement(clonedNode)) {\n return clonedNode;\n }\n let children = [];\n if (isSlotElement(nativeNode) && nativeNode.assignedNodes) {\n children = toArray(nativeNode.assignedNodes());\n }\n else if (isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n ((_a = nativeNode.contentDocument) === null || _a === void 0 ? void 0 : _a.body)) {\n children = toArray(nativeNode.contentDocument.body.childNodes);\n }\n else {\n children = toArray(((_b = nativeNode.shadowRoot) !== null && _b !== void 0 ? _b : nativeNode).childNodes);\n }\n if (children.length === 0 ||\n isInstanceOfElement(nativeNode, HTMLVideoElement)) {\n return clonedNode;\n }\n await children.reduce((deferred, child) => deferred\n .then(() => cloneNode(child, options))\n .then((clonedChild) => {\n if (clonedChild) {\n clonedNode.appendChild(clonedChild);\n }\n }), Promise.resolve());\n return clonedNode;\n}\nfunction cloneCSSStyle(nativeNode, clonedNode, options) {\n const targetStyle = clonedNode.style;\n if (!targetStyle) {\n return;\n }\n const sourceStyle = window.getComputedStyle(nativeNode);\n if (sourceStyle.cssText) {\n targetStyle.cssText = sourceStyle.cssText;\n targetStyle.transformOrigin = sourceStyle.transformOrigin;\n }\n else {\n getStyleProperties(options).forEach((name) => {\n let value = sourceStyle.getPropertyValue(name);\n if (name === 'font-size' && value.endsWith('px')) {\n const reducedFont = Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1;\n value = `${reducedFont}px`;\n }\n if (isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n name === 'display' &&\n value === 'inline') {\n value = 'block';\n }\n if (name === 'd' && clonedNode.getAttribute('d')) {\n value = `path(${clonedNode.getAttribute('d')})`;\n }\n targetStyle.setProperty(name, value, sourceStyle.getPropertyPriority(name));\n });\n }\n}\nfunction cloneInputValue(nativeNode, clonedNode) {\n if (isInstanceOfElement(nativeNode, HTMLTextAreaElement)) {\n clonedNode.innerHTML = nativeNode.value;\n }\n if (isInstanceOfElement(nativeNode, HTMLInputElement)) {\n clonedNode.setAttribute('value', nativeNode.value);\n }\n}\nfunction cloneSelectValue(nativeNode, clonedNode) {\n if (isInstanceOfElement(nativeNode, HTMLSelectElement)) {\n const clonedSelect = clonedNode;\n const selectedOption = Array.from(clonedSelect.children).find((child) => nativeNode.value === child.getAttribute('value'));\n if (selectedOption) {\n selectedOption.setAttribute('selected', '');\n }\n }\n}\nfunction decorate(nativeNode, clonedNode, options) {\n if (isInstanceOfElement(clonedNode, Element)) {\n cloneCSSStyle(nativeNode, clonedNode, options);\n clonePseudoElements(nativeNode, clonedNode, options);\n cloneInputValue(nativeNode, clonedNode);\n cloneSelectValue(nativeNode, clonedNode);\n }\n return clonedNode;\n}\nasync function ensureSVGSymbols(clone, options) {\n const uses = clone.querySelectorAll ? clone.querySelectorAll('use') : [];\n if (uses.length === 0) {\n return clone;\n }\n const processedDefs = {};\n for (let i = 0; i < uses.length; i++) {\n const use = uses[i];\n const id = use.getAttribute('xlink:href');\n if (id) {\n const exist = clone.querySelector(id);\n const definition = document.querySelector(id);\n if (!exist && definition && !processedDefs[id]) {\n // eslint-disable-next-line no-await-in-loop\n processedDefs[id] = (await cloneNode(definition, options, true));\n }\n }\n }\n const nodes = Object.values(processedDefs);\n if (nodes.length) {\n const ns = 'http://www.w3.org/1999/xhtml';\n const svg = document.createElementNS(ns, 'svg');\n svg.setAttribute('xmlns', ns);\n svg.style.position = 'absolute';\n svg.style.width = '0';\n svg.style.height = '0';\n svg.style.overflow = 'hidden';\n svg.style.display = 'none';\n const defs = document.createElementNS(ns, 'defs');\n svg.appendChild(defs);\n for (let i = 0; i < nodes.length; i++) {\n defs.appendChild(nodes[i]);\n }\n clone.appendChild(svg);\n }\n return clone;\n}\nexport async function cloneNode(node, options, isRoot) {\n if (!isRoot && options.filter && !options.filter(node)) {\n return null;\n }\n return Promise.resolve(node)\n .then((clonedNode) => cloneSingleNode(clonedNode, options))\n .then((clonedNode) => cloneChildren(node, clonedNode, options))\n .then((clonedNode) => decorate(node, clonedNode, options))\n .then((clonedNode) => ensureSVGSymbols(clonedNode, options));\n}\n//# sourceMappingURL=clone-node.js.map","import { resolveUrl } from './util';\nimport { getMimeType } from './mimes';\nimport { isDataUrl, makeDataUrl, resourceToDataURL } from './dataurl';\nconst URL_REGEX = /url\\((['\"]?)([^'\"]+?)\\1\\)/g;\nconst URL_WITH_FORMAT_REGEX = /url\\([^)]+\\)\\s*format\\(([\"']?)([^\"']+)\\1\\)/g;\nconst FONT_SRC_REGEX = /src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g;\nfunction toRegex(url) {\n // eslint-disable-next-line no-useless-escape\n const escaped = url.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g, '\\\\$1');\n return new RegExp(`(url\\\\(['\"]?)(${escaped})(['\"]?\\\\))`, 'g');\n}\nexport function parseURLs(cssText) {\n const urls = [];\n cssText.replace(URL_REGEX, (raw, quotation, url) => {\n urls.push(url);\n return raw;\n });\n return urls.filter((url) => !isDataUrl(url));\n}\nexport async function embed(cssText, resourceURL, baseURL, options, getContentFromUrl) {\n try {\n const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL;\n const contentType = getMimeType(resourceURL);\n let dataURL;\n if (getContentFromUrl) {\n const content = await getContentFromUrl(resolvedURL);\n dataURL = makeDataUrl(content, contentType);\n }\n else {\n dataURL = await resourceToDataURL(resolvedURL, contentType, options);\n }\n return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`);\n }\n catch (error) {\n // pass\n }\n return cssText;\n}\nfunction filterPreferredFontFormat(str, { preferredFontFormat }) {\n return !preferredFontFormat\n ? str\n : str.replace(FONT_SRC_REGEX, (match) => {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || [];\n if (!format) {\n return '';\n }\n if (format === preferredFontFormat) {\n return `src: ${src};`;\n }\n }\n });\n}\nexport function shouldEmbed(url) {\n return url.search(URL_REGEX) !== -1;\n}\nexport async function embedResources(cssText, baseUrl, options) {\n if (!shouldEmbed(cssText)) {\n return cssText;\n }\n const filteredCSSText = filterPreferredFontFormat(cssText, options);\n const urls = parseURLs(filteredCSSText);\n return urls.reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText));\n}\n//# sourceMappingURL=embed-resources.js.map","import { embedResources } from './embed-resources';\nimport { toArray, isInstanceOfElement } from './util';\nimport { isDataUrl, resourceToDataURL } from './dataurl';\nimport { getMimeType } from './mimes';\nasync function embedProp(propName, node, options) {\n var _a;\n const propValue = (_a = node.style) === null || _a === void 0 ? void 0 : _a.getPropertyValue(propName);\n if (propValue) {\n const cssString = await embedResources(propValue, null, options);\n node.style.setProperty(propName, cssString, node.style.getPropertyPriority(propName));\n return true;\n }\n return false;\n}\nasync function embedBackground(clonedNode, options) {\n ;\n (await embedProp('background', clonedNode, options)) ||\n (await embedProp('background-image', clonedNode, options));\n (await embedProp('mask', clonedNode, options)) ||\n (await embedProp('-webkit-mask', clonedNode, options)) ||\n (await embedProp('mask-image', clonedNode, options)) ||\n (await embedProp('-webkit-mask-image', clonedNode, options));\n}\nasync function embedImageNode(clonedNode, options) {\n const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement);\n if (!(isImageElement && !isDataUrl(clonedNode.src)) &&\n !(isInstanceOfElement(clonedNode, SVGImageElement) &&\n !isDataUrl(clonedNode.href.baseVal))) {\n return;\n }\n const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal;\n const dataURL = await resourceToDataURL(url, getMimeType(url), options);\n await new Promise((resolve, reject) => {\n clonedNode.onload = resolve;\n clonedNode.onerror = options.onImageErrorHandler\n ? (...attributes) => {\n try {\n resolve(options.onImageErrorHandler(...attributes));\n }\n catch (error) {\n reject(error);\n }\n }\n : reject;\n const image = clonedNode;\n if (image.decode) {\n image.decode = resolve;\n }\n if (image.loading === 'lazy') {\n image.loading = 'eager';\n }\n if (isImageElement) {\n clonedNode.srcset = '';\n clonedNode.src = dataURL;\n }\n else {\n clonedNode.href.baseVal = dataURL;\n }\n });\n}\nasync function embedChildren(clonedNode, options) {\n const children = toArray(clonedNode.childNodes);\n const deferreds = children.map((child) => embedImages(child, options));\n await Promise.all(deferreds).then(() => clonedNode);\n}\nexport async function embedImages(clonedNode, options) {\n if (isInstanceOfElement(clonedNode, Element)) {\n await embedBackground(clonedNode, options);\n await embedImageNode(clonedNode, options);\n await embedChildren(clonedNode, options);\n }\n}\n//# sourceMappingURL=embed-images.js.map","export function applyStyle(node, options) {\n const { style } = node;\n if (options.backgroundColor) {\n style.backgroundColor = options.backgroundColor;\n }\n if (options.width) {\n style.width = `${options.width}px`;\n }\n if (options.height) {\n style.height = `${options.height}px`;\n }\n const manual = options.style;\n if (manual != null) {\n Object.keys(manual).forEach((key) => {\n style[key] = manual[key];\n });\n }\n return node;\n}\n//# sourceMappingURL=apply-style.js.map","import { toArray } from './util';\nimport { fetchAsDataURL } from './dataurl';\nimport { shouldEmbed, embedResources } from './embed-resources';\nconst cssFetchCache = {};\nasync function fetchCSS(url) {\n let cache = cssFetchCache[url];\n if (cache != null) {\n return cache;\n }\n const res = await fetch(url);\n const cssText = await res.text();\n cache = { url, cssText };\n cssFetchCache[url] = cache;\n return cache;\n}\nasync function embedFonts(data, options) {\n let cssText = data.cssText;\n const regexUrl = /url\\([\"']?([^\"')]+)[\"']?\\)/g;\n const fontLocs = cssText.match(/url\\([^)]+\\)/g) || [];\n const loadFonts = fontLocs.map(async (loc) => {\n let url = loc.replace(regexUrl, '$1');\n if (!url.startsWith('https://')) {\n url = new URL(url, data.url).href;\n }\n return fetchAsDataURL(url, options.fetchRequestInit, ({ result }) => {\n cssText = cssText.replace(loc, `url(${result})`);\n return [loc, result];\n });\n });\n return Promise.all(loadFonts).then(() => cssText);\n}\nfunction parseCSS(source) {\n if (source == null) {\n return [];\n }\n const result = [];\n const commentsRegex = /(\\/\\*[\\s\\S]*?\\*\\/)/gi;\n // strip out comments\n let cssText = source.replace(commentsRegex, '');\n // eslint-disable-next-line prefer-regex-literals\n const keyframesRegex = new RegExp('((@.*?keyframes [\\\\s\\\\S]*?){([\\\\s\\\\S]*?}\\\\s*?)})', 'gi');\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const matches = keyframesRegex.exec(cssText);\n if (matches === null) {\n break;\n }\n result.push(matches[0]);\n }\n cssText = cssText.replace(keyframesRegex, '');\n const importRegex = /@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi;\n // to match css & media queries together\n const combinedCSSRegex = '((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]' +\n '*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})';\n // unified regex\n const unifiedRegex = new RegExp(combinedCSSRegex, 'gi');\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let matches = importRegex.exec(cssText);\n if (matches === null) {\n matches = unifiedRegex.exec(cssText);\n if (matches === null) {\n break;\n }\n else {\n importRegex.lastIndex = unifiedRegex.lastIndex;\n }\n }\n else {\n unifiedRegex.lastIndex = importRegex.lastIndex;\n }\n result.push(matches[0]);\n }\n return result;\n}\nasync function getCSSRules(styleSheets, options) {\n const ret = [];\n const deferreds = [];\n // First loop inlines imports\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray(sheet.cssRules || []).forEach((item, index) => {\n if (item.type === CSSRule.IMPORT_RULE) {\n let importIndex = index + 1;\n const url = item.href;\n const deferred = fetchCSS(url)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) => parseCSS(cssText).forEach((rule) => {\n try {\n sheet.insertRule(rule, rule.startsWith('@import')\n ? (importIndex += 1)\n : sheet.cssRules.length);\n }\n catch (error) {\n console.error('Error inserting rule from remote css', {\n rule,\n error,\n });\n }\n }))\n .catch((e) => {\n console.error('Error loading remote css', e.toString());\n });\n deferreds.push(deferred);\n }\n });\n }\n catch (e) {\n const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0];\n if (sheet.href != null) {\n deferreds.push(fetchCSS(sheet.href)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) => parseCSS(cssText).forEach((rule) => {\n inline.insertRule(rule, inline.cssRules.length);\n }))\n .catch((err) => {\n console.error('Error loading remote stylesheet', err);\n }));\n }\n console.error('Error inlining remote css file', e);\n }\n }\n });\n return Promise.all(deferreds).then(() => {\n // Second loop parses rules\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray(sheet.cssRules || []).forEach((item) => {\n ret.push(item);\n });\n }\n catch (e) {\n console.error(`Error while reading CSS rules from ${sheet.href}`, e);\n }\n }\n });\n return ret;\n });\n}\nfunction getWebFontRules(cssRules) {\n return cssRules\n .filter((rule) => rule.type === CSSRule.FONT_FACE_RULE)\n .filter((rule) => shouldEmbed(rule.style.getPropertyValue('src')));\n}\nasync function parseWebFontRules(node, options) {\n if (node.ownerDocument == null) {\n throw new Error('Provided element is not within a Document');\n }\n const styleSheets = toArray(node.ownerDocument.styleSheets);\n const cssRules = await getCSSRules(styleSheets, options);\n return getWebFontRules(cssRules);\n}\nfunction normalizeFontFamily(font) {\n return font.trim().replace(/[\"']/g, '');\n}\nfunction getUsedFonts(node) {\n const fonts = new Set();\n function traverse(node) {\n const fontFamily = node.style.fontFamily || getComputedStyle(node).fontFamily;\n fontFamily.split(',').forEach((font) => {\n fonts.add(normalizeFontFamily(font));\n });\n Array.from(node.children).forEach((child) => {\n if (child instanceof HTMLElement) {\n traverse(child);\n }\n });\n }\n traverse(node);\n return fonts;\n}\nexport async function getWebFontCSS(node, options) {\n const rules = await parseWebFontRules(node, options);\n const usedFonts = getUsedFonts(node);\n const cssTexts = await Promise.all(rules\n .filter((rule) => usedFonts.has(normalizeFontFamily(rule.style.fontFamily)))\n .map((rule) => {\n const baseUrl = rule.parentStyleSheet\n ? rule.parentStyleSheet.href\n : null;\n return embedResources(rule.cssText, baseUrl, options);\n }));\n return cssTexts.join('\\n');\n}\nexport async function embedWebFonts(clonedNode, options) {\n const cssText = options.fontEmbedCSS != null\n ? options.fontEmbedCSS\n : options.skipFonts\n ? null\n : await getWebFontCSS(clonedNode, options);\n if (cssText) {\n const styleNode = document.createElement('style');\n const sytleContent = document.createTextNode(cssText);\n styleNode.appendChild(sytleContent);\n if (clonedNode.firstChild) {\n clonedNode.insertBefore(styleNode, clonedNode.firstChild);\n }\n else {\n clonedNode.appendChild(styleNode);\n }\n }\n}\n//# sourceMappingURL=embed-webfonts.js.map","import { cloneNode } from './clone-node';\nimport { embedImages } from './embed-images';\nimport { applyStyle } from './apply-style';\nimport { embedWebFonts, getWebFontCSS } from './embed-webfonts';\nimport { getImageSize, getPixelRatio, createImage, canvasToBlob, nodeToDataURL, checkCanvasDimensions, } from './util';\nexport async function toSvg(node, options = {}) {\n const { width, height } = getImageSize(node, options);\n const clonedNode = (await cloneNode(node, options, true));\n await embedWebFonts(clonedNode, options);\n await embedImages(clonedNode, options);\n applyStyle(clonedNode, options);\n const datauri = await nodeToDataURL(clonedNode, width, height);\n return datauri;\n}\nexport async function toCanvas(node, options = {}) {\n const { width, height } = getImageSize(node, options);\n const svg = await toSvg(node, options);\n const img = await createImage(svg);\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n const ratio = options.pixelRatio || getPixelRatio();\n const canvasWidth = options.canvasWidth || width;\n const canvasHeight = options.canvasHeight || height;\n canvas.width = canvasWidth * ratio;\n canvas.height = canvasHeight * ratio;\n if (!options.skipAutoScale) {\n checkCanvasDimensions(canvas);\n }\n canvas.style.width = `${canvasWidth}`;\n canvas.style.height = `${canvasHeight}`;\n if (options.backgroundColor) {\n context.fillStyle = options.backgroundColor;\n context.fillRect(0, 0, canvas.width, canvas.height);\n }\n context.drawImage(img, 0, 0, canvas.width, canvas.height);\n return canvas;\n}\nexport async function toPixelData(node, options = {}) {\n const { width, height } = getImageSize(node, options);\n const canvas = await toCanvas(node, options);\n const ctx = canvas.getContext('2d');\n return ctx.getImageData(0, 0, width, height).data;\n}\nexport async function toPng(node, options = {}) {\n const canvas = await toCanvas(node, options);\n return canvas.toDataURL();\n}\nexport async function toJpeg(node, options = {}) {\n const canvas = await toCanvas(node, options);\n return canvas.toDataURL('image/jpeg', options.quality || 1);\n}\nexport async function toBlob(node, options = {}) {\n const canvas = await toCanvas(node, options);\n const blob = await canvasToBlob(canvas);\n return blob;\n}\nexport async function getFontEmbedCSS(node, options = {}) {\n return getWebFontCSS(node, options);\n}\n//# sourceMappingURL=index.js.map","import type { Annotation } from '../types'\nimport { parsePathPolylines } from './capture'\n\nexport interface CropRect {\n x: number\n y: number\n width: number\n height: number\n}\n\ninterface Bounds {\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\nconst MIN_CROP_WIDTH = 400\nconst MIN_CROP_HEIGHT = 300\nconst PADDING_PX = 150\nconst PADDING_RATIO = 0.3\nconst SKIP_CROP_RATIO = 0.85\n\nexport function getAnnotationBounds(annotations: Annotation[]): Bounds | null {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n\n for (const ann of annotations) {\n if (ann.type === 'pin') {\n minX = Math.min(minX, ann.x)\n minY = Math.min(minY, ann.y)\n maxX = Math.max(maxX, ann.x)\n maxY = Math.max(maxY, ann.y)\n if (ann.targetRect) {\n const r = ann.targetRect\n minX = Math.min(minX, r.left)\n minY = Math.min(minY, r.top)\n maxX = Math.max(maxX, r.left + r.width)\n maxY = Math.max(maxY, r.bottom)\n }\n } else if (ann.type === 'draw' && ann.drawPath) {\n for (const polyline of parsePathPolylines(ann.drawPath)) {\n for (const [x, y] of polyline) {\n minX = Math.min(minX, x)\n minY = Math.min(minY, y)\n maxX = Math.max(maxX, x)\n maxY = Math.max(maxY, y)\n }\n }\n }\n }\n\n if (!isFinite(minX) || !isFinite(minY)) return null\n return { minX, minY, maxX, maxY }\n}\n\nexport function computeCropRegion(\n annotations: Annotation[],\n viewportWidth: number,\n viewportHeight: number,\n): CropRect | null {\n const bounds = getAnnotationBounds(annotations)\n if (!bounds) return null\n\n const padX = Math.max(PADDING_PX, viewportWidth * PADDING_RATIO)\n const padY = Math.max(PADDING_PX, viewportHeight * PADDING_RATIO)\n\n let x = bounds.minX - padX\n let y = bounds.minY - padY\n let w = (bounds.maxX - bounds.minX) + padX * 2\n let h = (bounds.maxY - bounds.minY) + padY * 2\n\n if (w < MIN_CROP_WIDTH) {\n x -= (MIN_CROP_WIDTH - w) / 2\n w = MIN_CROP_WIDTH\n }\n if (h < MIN_CROP_HEIGHT) {\n y -= (MIN_CROP_HEIGHT - h) / 2\n h = MIN_CROP_HEIGHT\n }\n\n x = Math.max(0, x)\n y = Math.max(0, y)\n w = Math.min(w, viewportWidth - x)\n h = Math.min(h, viewportHeight - y)\n\n if (w >= viewportWidth * SKIP_CROP_RATIO && h >= viewportHeight * SKIP_CROP_RATIO) {\n return null\n }\n\n return {\n x: Math.round(x),\n y: Math.round(y),\n width: Math.round(w),\n height: Math.round(h),\n }\n}\n\nexport function cropCanvas(source: HTMLCanvasElement, rect: CropRect): HTMLCanvasElement {\n const cropped = document.createElement('canvas')\n cropped.width = rect.width\n cropped.height = rect.height\n const ctx = cropped.getContext('2d')\n if (ctx) {\n ctx.drawImage(source, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height)\n }\n return cropped\n}\n\nexport async function cropDataUrl(dataUrl: string, rect: CropRect): Promise<string> {\n const image = await loadImageForCrop(dataUrl)\n if (!image) return dataUrl\n const canvas = document.createElement('canvas')\n canvas.width = rect.width\n canvas.height = rect.height\n const ctx = canvas.getContext('2d')\n if (!ctx) return dataUrl\n ctx.drawImage(image, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height)\n return canvas.toDataURL('image/jpeg', 0.85)\n}\n\nfunction loadImageForCrop(dataUrl: string): Promise<HTMLImageElement | null> {\n return new Promise(resolve => {\n const img = new Image()\n img.onload = () => resolve(img)\n img.onerror = () => resolve(null)\n img.src = dataUrl\n })\n}\n","import { toJpeg } from 'html-to-image'\nimport type { Annotation } from '../types'\nimport { BRAND_COLOR, FONT_STACK, brandAlpha } from '../styles'\nimport { computeCropRegion, cropCanvas } from './crop'\n\ninterface CaptureMetrics {\n left: number\n top: number\n width: number\n height: number\n}\n\n// Capture at CSS pixels (pixelRatio 1) as JPEG to keep the upload small: on\n// retina screens the default devicePixelRatio would quadruple the pixel count,\n// and the model downscales past ~1568px anyway.\n//\n// Annotations are baked onto the captured bitmap with canvas 2D afterwards —\n// never mounted into the live page — so the capture leaves the page visually\n// untouched no matter how long the DOM snapshot takes.\nexport async function captureScreenshot(annotations: Annotation[] = []): Promise<Blob | null> {\n try {\n const captureMetrics = getCaptureMetrics(document.body)\n const dataUrl = await toJpeg(document.body, {\n quality: 0.85,\n pixelRatio: 1,\n backgroundColor: '#ffffff',\n skipFonts: true,\n skipAutoScale: false,\n filter: (node) => {\n if (node instanceof HTMLElement && node.id === 'mtb-widget-host') return false\n return true\n },\n })\n if (annotations.length > 0) {\n const annotated = await bakeAnnotations(dataUrl, annotations, captureMetrics)\n if (annotated) return annotated\n }\n return dataUrlToBlob(dataUrl)\n } catch {\n return null\n }\n}\n\nasync function bakeAnnotations(\n dataUrl: string,\n annotations: Annotation[],\n captureMetrics: CaptureMetrics,\n): Promise<Blob | null> {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) return null\n\n const image = await loadImage(dataUrl)\n if (!image) return null\n\n canvas.width = image.naturalWidth || window.innerWidth\n canvas.height = image.naturalHeight || window.innerHeight\n ctx.drawImage(image, 0, 0)\n const scaleX = canvas.width / captureMetrics.width\n const scaleY = canvas.height / captureMetrics.height\n\n let pinIndex = 0\n for (const annotation of annotations) {\n if (annotation.type === 'draw' && annotation.drawPath) {\n drawStroke(ctx, annotation.drawPath, captureMetrics, scaleX, scaleY)\n } else if (annotation.type === 'pin') {\n drawPin(\n ctx,\n (annotation.x - captureMetrics.left) * scaleX,\n (annotation.y - captureMetrics.top) * scaleY,\n ++pinIndex,\n )\n }\n }\n\n const cropRect = computeCropRegion(annotations, window.innerWidth, window.innerHeight)\n if (cropRect) {\n const left = Math.max(0, Math.round((cropRect.x - captureMetrics.left) * scaleX))\n const top = Math.max(0, Math.round((cropRect.y - captureMetrics.top) * scaleY))\n const right = Math.min(canvas.width, Math.round((cropRect.x + cropRect.width - captureMetrics.left) * scaleX))\n const bottom = Math.min(canvas.height, Math.round((cropRect.y + cropRect.height - captureMetrics.top) * scaleY))\n const scaled = {\n x: left,\n y: top,\n width: right - left,\n height: bottom - top,\n }\n return canvasToJpegBlob(cropCanvas(canvas, scaled))\n }\n\n return canvasToJpegBlob(canvas)\n}\n\nfunction drawStroke(\n ctx: CanvasRenderingContext2D,\n drawPath: string,\n captureMetrics: CaptureMetrics,\n scaleX: number,\n scaleY: number,\n): void {\n ctx.save()\n ctx.strokeStyle = BRAND_COLOR\n ctx.lineWidth = 3.5\n ctx.lineCap = 'round'\n ctx.lineJoin = 'round'\n ctx.shadowColor = brandAlpha(0.35)\n ctx.shadowOffsetY = 1\n ctx.shadowBlur = 2\n for (const points of parsePathPolylines(drawPath)) {\n if (points.length === 0) continue\n ctx.beginPath()\n ctx.moveTo(\n (points[0][0] - captureMetrics.left) * scaleX,\n (points[0][1] - captureMetrics.top) * scaleY,\n )\n for (let i = 1; i < points.length; i++) {\n ctx.lineTo(\n (points[i][0] - captureMetrics.left) * scaleX,\n (points[i][1] - captureMetrics.top) * scaleY,\n )\n }\n ctx.stroke()\n }\n ctx.restore()\n}\n\nfunction getCaptureMetrics(node: HTMLElement): CaptureMetrics {\n const rect = node.getBoundingClientRect()\n const style = window.getComputedStyle(node)\n const borderWidth = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth)\n const borderHeight = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth)\n\n return {\n left: rect.left,\n top: rect.top,\n width: node.clientWidth + (Number.isFinite(borderWidth) ? borderWidth : 0) || window.innerWidth,\n height: node.clientHeight + (Number.isFinite(borderHeight) ? borderHeight : 0) || window.innerHeight,\n }\n}\n\nfunction drawPin(ctx: CanvasRenderingContext2D, x: number, y: number, index: number): void {\n ctx.save()\n ctx.shadowColor = brandAlpha(0.45)\n ctx.shadowOffsetY = 2\n ctx.shadowBlur = 8\n ctx.fillStyle = BRAND_COLOR\n ctx.beginPath()\n ctx.arc(x, y, 11, 0, Math.PI * 2)\n ctx.fill()\n ctx.shadowColor = 'transparent'\n ctx.lineWidth = 2\n ctx.strokeStyle = '#ffffff'\n ctx.stroke()\n ctx.fillStyle = '#ffffff'\n ctx.font = `700 10px ${FONT_STACK}`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(String(index), x, y)\n ctx.restore()\n}\n\n// The draw layer only ever emits M/L polyline commands (see buildPathD in\n// annotate/draw.ts); anything else in the string is ignored.\nexport function parsePathPolylines(drawPath: string): Array<Array<[number, number]>> {\n const polylines: Array<Array<[number, number]>> = []\n let current: Array<[number, number]> | null = null\n const tokens = drawPath.match(/[ML]\\s*[-\\d.]+\\s+[-\\d.]+/g) ?? []\n for (const token of tokens) {\n const [x, y] = token.slice(1).trim().split(/\\s+/).map(Number)\n if (Number.isNaN(x) || Number.isNaN(y)) continue\n if (token[0] === 'M') {\n current = [[x, y]]\n polylines.push(current)\n } else if (current) {\n current.push([x, y])\n }\n }\n return polylines\n}\n\nfunction loadImage(dataUrl: string): Promise<HTMLImageElement | null> {\n return new Promise(resolve => {\n const image = new Image()\n image.onload = () => resolve(image)\n image.onerror = () => resolve(null)\n image.src = dataUrl\n })\n}\n\nfunction canvasToJpegBlob(canvas: HTMLCanvasElement): Promise<Blob | null> {\n return new Promise(resolve => {\n try {\n canvas.toBlob(blob => resolve(blob), 'image/jpeg', 0.85)\n } catch {\n resolve(null)\n }\n })\n}\n\nfunction dataUrlToBlob(dataUrl: string): Blob {\n const [header, data] = dataUrl.split(',')\n const mime = header.match(/:(.*?);/)?.[1] ?? 'image/png'\n const binary = atob(data)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return new Blob([bytes], { type: mime })\n}\n","export interface ErrorSourceEvent {\n message: string\n source?: string\n line?: number\n col?: number\n error?: unknown\n}\n\ntype ErrorListener = (event: ErrorSourceEvent) => void\n\nclass ErrorSource {\n private listeners = new Set<ErrorListener>()\n private originalOnError: OnErrorEventHandler | null = null\n private installedOnError: OnErrorEventHandler | null = null\n private rejectionHandler: ((e: PromiseRejectionEvent) => void) | null = null\n private hooked = false\n\n subscribe(listener: ErrorListener): () => void {\n this.listeners.add(listener)\n this.hook()\n return () => {\n this.listeners.delete(listener)\n if (this.listeners.size === 0) this.unhook()\n }\n }\n\n private hook(): void {\n if (this.hooked) return\n this.hooked = true\n\n this.originalOnError = window.onerror\n this.installedOnError = (msg, source, line, col, error) => {\n this.emit({ message: String(msg), source, line, col, error })\n if (this.originalOnError) {\n return this.originalOnError.call(window, msg, source, line, col, error)\n }\n return false\n }\n window.onerror = this.installedOnError\n\n this.rejectionHandler = (e: PromiseRejectionEvent) => {\n const reason = e.reason instanceof Error ? e.reason.message : String(e.reason)\n this.emit({ message: `Unhandled rejection: ${reason}` })\n }\n window.addEventListener('unhandledrejection', this.rejectionHandler)\n }\n\n private unhook(): void {\n if (!this.hooked) return\n this.hooked = false\n // Only restore if nothing replaced our handler meanwhile — restoring\n // the stale snapshot would clobber a handler the page installed later.\n if (window.onerror === this.installedOnError) {\n window.onerror = this.originalOnError\n }\n this.installedOnError = null\n this.originalOnError = null\n if (this.rejectionHandler) {\n window.removeEventListener('unhandledrejection', this.rejectionHandler)\n this.rejectionHandler = null\n }\n }\n\n private emit(event: ErrorSourceEvent): void {\n for (const listener of this.listeners) listener(event)\n }\n}\n\nexport const errorSource = new ErrorSource()\n","import { errorSource, type ErrorSourceEvent } from './error-source'\n\nconst MAX_CONSOLE_ERRORS = 20\n\nexport class ConsoleErrorCollector {\n private errors: string[] = []\n private unsubscribe: (() => void) | null = null\n\n start(): void {\n if (this.unsubscribe) return\n this.unsubscribe = errorSource.subscribe((e) => this.record(e))\n }\n\n private record(e: ErrorSourceEvent): void {\n const location = e.line != null ? ` (${e.line}:${e.col ?? 0})` : ''\n this.addError(`${e.message}${location}`)\n }\n\n private addError(msg: string): void {\n if (this.errors.length >= MAX_CONSOLE_ERRORS) return\n if (!this.errors.includes(msg)) {\n this.errors.push(msg)\n }\n }\n\n getErrors(): string[] {\n return [...this.errors]\n }\n\n stop(): void {\n this.unsubscribe?.()\n this.unsubscribe = null\n }\n}\n","// Single owner of the history.pushState / replaceState patch.\n//\n// Two collectors (breadcrumbs and frustration) both need to know when an SPA\n// navigates. When each wrapped history itself, teardown could only restore the\n// native function if it happened to be the outermost wrapper — so tearing them\n// down in install order (FIFO teardown of a LIFO stack) left one dead wrapper\n// behind per cycle, and Turbo Drive reinstalls on every visit. Refcounting one\n// wrapper here makes the install order irrelevant: the patch goes on when the\n// first listener subscribes and comes off when the last one unsubscribes.\n\ntype NavListener = () => void\n\nconst listeners = new Set<NavListener>()\n\nlet nativePushState: History['pushState'] | null = null\nlet nativeReplaceState: History['replaceState'] | null = null\nlet installedPushState: History['pushState'] | null = null\nlet installedReplaceState: History['replaceState'] | null = null\nlet popstateHandler: (() => void) | null = null\n\n// Subscribes to pushState, replaceState and popstate. Returns an unsubscribe\n// function; calling it twice is harmless.\nexport function onHistoryNavigation(listener: NavListener): () => void {\n listeners.add(listener)\n install()\n\n let released = false\n return () => {\n if (released) return\n released = true\n listeners.delete(listener)\n if (listeners.size === 0) uninstall()\n }\n}\n\nfunction notify(): void {\n // Copy first: a listener may unsubscribe (or subscribe) while being notified.\n for (const listener of [...listeners]) {\n try { listener() } catch { /* never propagate into the host page */ }\n }\n}\n\nfunction install(): void {\n if (installedPushState) return\n\n popstateHandler = () => notify()\n window.addEventListener('popstate', popstateHandler)\n\n // Snapshot the raw functions and invoke them with .call — binding would hand\n // back a different function object on uninstall, so the host page would never\n // get its own pushState identity back and each cycle would add a bind layer.\n nativePushState = history.pushState\n nativeReplaceState = history.replaceState\n const pushOrig = nativePushState\n const replaceOrig = nativeReplaceState\n\n installedPushState = function (data: unknown, unused: string, url?: string | URL | null) {\n pushOrig.call(history, data, unused, url)\n notify()\n }\n installedReplaceState = function (data: unknown, unused: string, url?: string | URL | null) {\n replaceOrig.call(history, data, unused, url)\n notify()\n }\n history.pushState = installedPushState\n history.replaceState = installedReplaceState\n}\n\nfunction uninstall(): void {\n if (popstateHandler) {\n window.removeEventListener('popstate', popstateHandler)\n popstateHandler = null\n }\n // Only restore if nothing (e.g. an SPA router) re-wrapped the functions\n // after us — restoring the stale snapshot would discard their wrapper.\n if (nativePushState && history.pushState === installedPushState) {\n history.pushState = nativePushState\n }\n if (nativeReplaceState && history.replaceState === installedReplaceState) {\n history.replaceState = nativeReplaceState\n }\n nativePushState = null\n nativeReplaceState = null\n installedPushState = null\n installedReplaceState = null\n}\n","import { errorSource, type ErrorSourceEvent } from './error-source'\nimport { getCssSelector, getElementName } from '../annotate/highlighter'\nimport { isWidgetElement } from './dom-utils'\nimport { onHistoryNavigation } from './history-patch'\nimport type { Breadcrumb } from '../types'\n\nconst MAX_BREADCRUMBS = 20\n\nexport class BreadcrumbCollector {\n private breadcrumbs: Breadcrumb[] = []\n private active = false\n private unsubscribeErrors: (() => void) | null = null\n private boundClickHandler: (e: MouseEvent) => void\n private boundChangeHandler: (e: Event) => void\n private unsubscribeNavigation: (() => void) | null = null\n private lastUrl = ''\n\n constructor() {\n this.boundClickHandler = (e: MouseEvent) => this.handleClick(e)\n this.boundChangeHandler = (e: Event) => this.handleChange(e)\n }\n\n start(): void {\n if (this.active) return\n this.active = true\n this.lastUrl = location.href\n document.addEventListener('click', this.boundClickHandler, { capture: true, passive: true })\n document.addEventListener('change', this.boundChangeHandler, { capture: true, passive: true })\n this.unsubscribeErrors = errorSource.subscribe((e) => this.recordError(e))\n this.unsubscribeNavigation = onHistoryNavigation(() => this.handleNavigation())\n }\n\n stop(): void {\n if (!this.active) return\n this.active = false\n document.removeEventListener('click', this.boundClickHandler, true)\n document.removeEventListener('change', this.boundChangeHandler, true)\n this.unsubscribeErrors?.()\n this.unsubscribeErrors = null\n this.unsubscribeNavigation?.()\n this.unsubscribeNavigation = null\n }\n\n getBreadcrumbs(): Breadcrumb[] {\n return [...this.breadcrumbs]\n }\n\n private add(crumb: Breadcrumb): void {\n this.breadcrumbs.push(crumb)\n if (this.breadcrumbs.length > MAX_BREADCRUMBS) {\n this.breadcrumbs.shift()\n }\n }\n\n private handleClick(e: MouseEvent): void {\n const target = e.target as Element | null\n if (!target) return\n if (isWidgetElement(target)) return\n\n try {\n this.add({\n type: 'ui',\n category: 'ui.click',\n timestamp: Date.now(),\n message: getElementName(target),\n data: { selector: getCssSelector(target) },\n })\n } catch { /* never propagate into host page */ }\n }\n\n private handleChange(e: Event): void {\n const target = e.target as Element | null\n if (!target) return\n if (isWidgetElement(target)) return\n\n try {\n const input = target as HTMLInputElement\n const field = input.name || input.placeholder || target.getAttribute('aria-label') || target.tagName\n this.add({\n type: 'ui',\n category: 'ui.input',\n timestamp: Date.now(),\n message: field,\n data: { field },\n })\n } catch { /* never propagate into host page */ }\n }\n\n private recordError(e: ErrorSourceEvent): void {\n this.add({\n type: 'console',\n category: 'console.error',\n timestamp: Date.now(),\n message: e.message,\n data: { message: e.message },\n })\n }\n\n private handleNavigation(): void {\n if (!this.active) return\n const from = this.lastUrl\n const to = location.href\n if (from === to) return\n this.lastUrl = to\n this.add({\n type: 'navigation',\n category: 'navigation',\n timestamp: Date.now(),\n message: `${from} → ${to}`,\n data: { from, to },\n })\n }\n\n}\n","// Frustration state that must outlive a single page visit.\n//\n// The detector and the widget controller are both rebuilt from scratch on every\n// Turbo Drive navigation (see src/index.ts), which used to reset all of this.\n// The consequences were: `rapid_navigation` could never fire (it needs 3\n// timestamps within 5s but each visit contributed at most one), the 60s cooldown\n// was bypassed by navigating, an already-reported error page re-prompted on\n// revisit, and a reporter's explicit \"Dismiss\" did not survive one visit.\n//\n// sessionStorage is the right scope — this is per-tab, per-visit-series state,\n// not a long-lived identity like mtb_anon_id. Writes are best-effort: Safari\n// private mode and storage-partitioned iframes throw, so an in-memory copy backs\n// every read (it covers the current page at least).\n\nconst STORAGE_KEY = 'mtb_frustration_state'\n// Keeps a long browsing session from growing the stored payload without bound.\nconst MAX_ERROR_PAGE_URLS = 20\n\nexport interface FrustrationState {\n navTimestamps: number[]\n cooldownUntil: number\n errorPageUrls: string[]\n dismissedByUser: boolean\n}\n\nlet memoryState: FrustrationState | null = null\n\n// Every return path goes through normalize(), which rebuilds the arrays. Callers\n// own their copy and mutate it in place (the detector pushes onto navTimestamps),\n// so handing out a shared array would let one caller corrupt the stored state.\nexport function loadFrustrationState(): FrustrationState {\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n if (!raw) return normalize(memoryState)\n return normalize(JSON.parse(raw))\n } catch {\n return normalize(memoryState)\n }\n}\n\nexport function saveFrustrationState(state: FrustrationState): void {\n const normalized = normalize(state)\n memoryState = normalized\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(normalized))\n } catch {\n // sessionStorage unavailable — the in-memory copy covers this page\n }\n}\n\nexport function isFrustrationDismissed(): boolean {\n return loadFrustrationState().dismissedByUser\n}\n\n// Records a real refusal (the reporter clicked Dismiss), which suppresses\n// proactive prompts for the rest of the tab session. An auto-hide must never\n// call this — the 60s cooldown is what rate-limits an ignored prompt.\nexport function markFrustrationDismissed(): void {\n saveFrustrationState({ ...loadFrustrationState(), dismissedByUser: true })\n}\n\nexport function clearFrustrationState(): void {\n memoryState = null\n try {\n window.sessionStorage.removeItem(STORAGE_KEY)\n } catch {\n // nothing to clear\n }\n}\n\nfunction normalize(value: unknown): FrustrationState {\n const raw = (value ?? {}) as Partial<Record<keyof FrustrationState, unknown>>\n return {\n navTimestamps: Array.isArray(raw.navTimestamps)\n ? raw.navTimestamps.filter((t): t is number => typeof t === 'number')\n : [],\n cooldownUntil: typeof raw.cooldownUntil === 'number' ? raw.cooldownUntil : 0,\n errorPageUrls: Array.isArray(raw.errorPageUrls)\n ? raw.errorPageUrls.filter((u): u is string => typeof u === 'string').slice(-MAX_ERROR_PAGE_URLS)\n : [],\n dismissedByUser: raw.dismissedByUser === true,\n }\n}\n","import { errorSource } from './error-source'\nimport { isWidgetElement } from './dom-utils'\nimport { onHistoryNavigation } from './history-patch'\nimport { loadFrustrationState, saveFrustrationState } from './frustration-state'\n\nexport type FrustrationSignal =\n | 'rage_click'\n | 'dead_click'\n | 'rapid_navigation'\n | 'form_failure'\n | 'error_page'\n | 'dead_click_dom'\n\nexport interface FrustrationEvent {\n signal: FrustrationSignal\n target?: string\n detail?: string\n timestamp: number\n}\n\ninterface ClickRecord {\n target: EventTarget | null\n time: number\n}\n\nconst RAGE_CLICK_THRESHOLD = 3\nconst RAGE_CLICK_WINDOW_MS = 1000\nconst RAPID_NAV_THRESHOLD = 3\nconst RAPID_NAV_WINDOW_MS = 5000\nconst FORM_CHECK_DELAY_MS = 500\nconst DEAD_CLICK_DOM_DELAY_MS = 500\nconst ERROR_PAGE_CHECK_DELAY_MS = 300\n\nconst INTERACTIVE_TAGS = new Set([\n 'A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'LABEL', 'SUMMARY', 'DETAILS',\n])\n\nconst INTERACTIVE_ROLES = new Set([\n 'button', 'link', 'checkbox', 'radio', 'tab', 'menuitem', 'option',\n 'switch', 'textbox', 'combobox', 'listbox', 'slider', 'spinbutton',\n])\n\nconst ERROR_PAGE_PATTERNS = [\n '404', '500', 'not found', 'page not found',\n 'server error', 'internal server error',\n]\n\nexport class FrustrationDetector {\n private clickHistory: ClickRecord[] = []\n private onFrustration: (event: FrustrationEvent) => void\n private boundClickHandler: (e: MouseEvent) => void\n private unsubscribeErrors: (() => void) | null = null\n private active = false\n private errorCount = 0\n private deadClickCount = 0\n private cooldownUntil = 0\n private static readonly COOLDOWN_MS = 60_000\n\n private navTimestamps: number[] = []\n private unsubscribeNavigation: (() => void) | null = null\n private boundPageLeaveHandler: (() => void) | null = null\n private lastNavigationAt = -1\n private boundSubmitHandler: ((e: Event) => void) | null = null\n private boundInvalidHandler: ((e: Event) => void) | null = null\n private recentSubmitForms = new WeakSet<HTMLFormElement>()\n private errorPageUrls = new Set<string>()\n private domObserver: MutationObserver | null = null\n private pendingDomChecks = 0\n private lastMutationAt = -1\n\n constructor(onFrustration: (event: FrustrationEvent) => void) {\n this.onFrustration = onFrustration\n this.boundClickHandler = (e: MouseEvent) => this.handleClick(e)\n }\n\n start(): void {\n if (this.active) return\n this.active = true\n this.restoreState()\n document.addEventListener('click', this.boundClickHandler, true)\n this.unsubscribeErrors = errorSource.subscribe((_e) => {\n this.errorCount++\n })\n\n this.startNavigationTracking()\n this.startFormTracking()\n this.checkErrorPage()\n }\n\n stop(): void {\n if (!this.active) return\n this.active = false\n document.removeEventListener('click', this.boundClickHandler, true)\n this.unsubscribeErrors?.()\n this.unsubscribeErrors = null\n this.clickHistory = []\n\n this.stopNavigationTracking()\n this.stopFormTracking()\n this.errorPageUrls.clear()\n\n this.disconnectDomObserver()\n }\n\n private startNavigationTracking(): void {\n this.unsubscribeNavigation = onHistoryNavigation(() => this.handleNavigation())\n\n // A click that starts a full-page navigation (checkout, OAuth, external\n // link, download, window.location assignment) leaves the DOM untouched\n // while the browser tears the page down, which is indistinguishable from a\n // dead click by mutation alone. Recording when the page starts leaving lets\n // checkDeadClickDom acquit those clicks. Both events are needed: browsers\n // skip beforeunload when nothing registered an unload prompt, and Safari\n // reaches bfcache via pagehide only.\n this.boundPageLeaveHandler = () => this.noteNavigationStarted()\n window.addEventListener('beforeunload', this.boundPageLeaveHandler)\n window.addEventListener('pagehide', this.boundPageLeaveHandler)\n }\n\n private stopNavigationTracking(): void {\n this.unsubscribeNavigation?.()\n this.unsubscribeNavigation = null\n this.navTimestamps = []\n\n if (this.boundPageLeaveHandler) {\n window.removeEventListener('beforeunload', this.boundPageLeaveHandler)\n window.removeEventListener('pagehide', this.boundPageLeaveHandler)\n this.boundPageLeaveHandler = null\n }\n this.lastNavigationAt = -1\n }\n\n private noteNavigationStarted(): void {\n this.lastNavigationAt = Date.now()\n }\n\n // Rehydrates the state a Turbo Drive visit would otherwise reset. Without this,\n // a fresh detector on every page starts with an empty nav history (so\n // `rapid_navigation` can never reach its 3-in-5s threshold), no cooldown, and no\n // memory of which error pages it already reported.\n private restoreState(): void {\n const stored = loadFrustrationState()\n this.navTimestamps = stored.navTimestamps\n this.cooldownUntil = stored.cooldownUntil\n this.errorPageUrls = new Set(stored.errorPageUrls)\n }\n\n private persistState(): void {\n const stored = loadFrustrationState()\n saveFrustrationState({\n ...stored,\n navTimestamps: this.navTimestamps,\n cooldownUntil: this.cooldownUntil,\n errorPageUrls: [...this.errorPageUrls],\n })\n }\n\n private startFormTracking(): void {\n this.boundSubmitHandler = (e: Event) => this.handleFormSubmit(e)\n this.boundInvalidHandler = (e: Event) => this.handleFormInvalid(e)\n document.addEventListener('submit', this.boundSubmitHandler, true)\n document.addEventListener('invalid', this.boundInvalidHandler, true)\n }\n\n private stopFormTracking(): void {\n if (this.boundSubmitHandler) {\n document.removeEventListener('submit', this.boundSubmitHandler, true)\n this.boundSubmitHandler = null\n }\n if (this.boundInvalidHandler) {\n document.removeEventListener('invalid', this.boundInvalidHandler, true)\n this.boundInvalidHandler = null\n }\n }\n\n private handleClick(e: MouseEvent): void {\n const target = e.target as Element | null\n if (!target) return\n\n if (isWidgetElement(target)) return\n this.trackFormSubmitIntent(target)\n\n const now = Date.now()\n this.clickHistory.push({ target, time: now })\n\n const cutoff = now - RAGE_CLICK_WINDOW_MS\n this.clickHistory = this.clickHistory.filter(r => r.time > cutoff)\n\n const sameTargetClicks = this.clickHistory.filter(r => r.target === target)\n if (sameTargetClicks.length >= RAGE_CLICK_THRESHOLD) {\n this.clickHistory = []\n this.emitHighPriority({\n signal: 'rage_click',\n target: describeElement(target),\n timestamp: now,\n })\n return\n }\n\n if (!this.isInteractive(target)) {\n this.deadClickCount++\n if (this.deadClickCount >= 3 && this.errorCount > 0) {\n this.deadClickCount = 0\n this.errorCount = 0\n this.emitIfReady({\n signal: 'dead_click',\n target: describeElement(target),\n timestamp: now,\n })\n }\n }\n\n this.checkDeadClickDom(target, now)\n }\n\n private handleNavigation(): void {\n const now = Date.now()\n this.noteNavigationStarted()\n this.navTimestamps.push(now)\n const cutoff = now - RAPID_NAV_WINDOW_MS\n this.navTimestamps = this.navTimestamps.filter(t => t > cutoff)\n if (this.navTimestamps.length >= RAPID_NAV_THRESHOLD) {\n this.navTimestamps = []\n this.emitIfReady({\n signal: 'rapid_navigation',\n timestamp: now,\n })\n }\n this.persistState()\n setTimeout(() => {\n if (this.active) this.checkErrorPage()\n }, ERROR_PAGE_CHECK_DELAY_MS)\n }\n\n private handleFormSubmit(e: Event): void {\n const form = e.target\n if (!(form instanceof HTMLFormElement)) return\n if (isWidgetElement(form)) return\n\n this.rememberSubmitAttempt(form)\n\n setTimeout(() => {\n if (!this.active) return\n if (form.querySelector('[aria-invalid=\"true\"], .is-invalid')) {\n this.emitIfReady({\n signal: 'form_failure',\n target: describeElement(form),\n timestamp: Date.now(),\n })\n }\n }, FORM_CHECK_DELAY_MS)\n }\n\n private trackFormSubmitIntent(target: Element): void {\n const control = target.closest('button, input')\n if (!(control instanceof HTMLButtonElement || control instanceof HTMLInputElement)) return\n if (control.type !== 'submit' && control.type !== 'image') return\n if (!control.form || isWidgetElement(control.form)) return\n\n this.rememberSubmitAttempt(control.form)\n }\n\n private rememberSubmitAttempt(form: HTMLFormElement): void {\n this.recentSubmitForms.add(form)\n setTimeout(() => {\n this.recentSubmitForms.delete(form)\n }, FORM_CHECK_DELAY_MS)\n }\n\n private handleFormInvalid(e: Event): void {\n const el = e.target as Element | null\n if (!el) return\n if (isWidgetElement(el)) return\n const form = el.closest('form')\n if (!form || !this.recentSubmitForms.has(form)) return\n this.emitIfReady({\n signal: 'form_failure',\n target: describeElement(form),\n timestamp: Date.now(),\n })\n }\n\n private checkErrorPage(): void {\n const url = location.href\n if (this.errorPageUrls.has(url)) return\n\n const title = document.title.toLowerCase()\n if (ERROR_PAGE_PATTERNS.some(p => title.includes(p))) {\n this.errorPageUrls.add(url)\n this.emitHighPriority({\n signal: 'error_page',\n detail: document.title,\n timestamp: Date.now(),\n })\n return\n }\n\n const candidates = document.querySelectorAll(\n 'h1, h2, [class*=\"error\"], [class*=\"not-found\"], [id*=\"error\"], [id*=\"not-found\"]'\n )\n for (const el of candidates) {\n const text = el.textContent ?? ''\n if (text.length < 200 && ERROR_PAGE_PATTERNS.some(p => text.toLowerCase().includes(p))) {\n this.errorPageUrls.add(url)\n this.emitHighPriority({\n signal: 'error_page',\n detail: text.trim().slice(0, 60),\n timestamp: Date.now(),\n })\n return\n }\n }\n }\n\n // One shared observer for all in-flight dead-click checks, connected only\n // while at least one check is pending — a full-page observer per click was\n // too heavy on mutation-busy pages.\n private checkDeadClickDom(target: Element, clickTime: number): void {\n if (!this.looksInteractive(target)) return\n\n this.pendingDomChecks++\n this.ensureDomObserver()\n\n setTimeout(() => {\n this.pendingDomChecks--\n const mutated = this.lastMutationAt >= clickTime\n // A navigation that began at or after the click means the click worked;\n // the page just left before it could mutate anything.\n const navigated = this.lastNavigationAt >= clickTime\n if (this.pendingDomChecks === 0) this.disconnectDomObserver()\n\n if (!mutated && !navigated && this.active) {\n this.emitIfReady({\n signal: 'dead_click_dom',\n target: describeElement(target),\n timestamp: clickTime,\n })\n }\n }, DEAD_CLICK_DOM_DELAY_MS)\n }\n\n private ensureDomObserver(): void {\n if (this.domObserver) return\n this.domObserver = new MutationObserver(() => {\n this.lastMutationAt = Date.now()\n })\n this.domObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n })\n }\n\n private disconnectDomObserver(): void {\n this.domObserver?.disconnect()\n this.domObserver = null\n }\n\n private looksInteractive(el: Element): boolean {\n const style = window.getComputedStyle(el)\n if (style.cursor === 'pointer') return true\n\n if (el.classList) {\n for (const cls of el.classList) {\n const lower = cls.toLowerCase()\n if (lower.includes('btn') || lower.includes('button')) return true\n }\n }\n\n return false\n }\n\n private isInteractive(el: Element): boolean {\n if (INTERACTIVE_TAGS.has(el.tagName)) return true\n\n const role = el.getAttribute('role')\n if (role && INTERACTIVE_ROLES.has(role)) return true\n\n if (el.hasAttribute('onclick') || el.hasAttribute('tabindex')) return true\n if ((el as HTMLElement).contentEditable === 'true') return true\n\n const style = window.getComputedStyle(el)\n if (style.cursor === 'pointer') return true\n\n const parent = el.closest('a, button, [role=\"button\"], [role=\"link\"], label')\n if (parent) return true\n\n return false\n }\n\n\n private emitIfReady(event: FrustrationEvent): void {\n const now = Date.now()\n if (now < this.cooldownUntil) return\n this.cooldownUntil = now + FrustrationDetector.COOLDOWN_MS\n this.persistState()\n this.onFrustration(event)\n }\n\n private emitHighPriority(event: FrustrationEvent): void {\n this.cooldownUntil = Date.now() + FrustrationDetector.COOLDOWN_MS\n this.persistState()\n this.onFrustration(event)\n }\n}\n\nfunction describeElement(el: Element): string {\n const tag = el.tagName.toLowerCase()\n const id = el.id ? `#${el.id}` : ''\n const cls = el.className && typeof el.className === 'string'\n ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : ''\n const text = el.textContent?.trim().slice(0, 30) ?? ''\n return `<${tag}${id}${cls}>${text ? ` \"${text}\"` : ''}`\n}\n","export interface PageContext {\n page_url: string\n user_agent: string\n browser: string\n os: string\n screen_width: number\n screen_height: number\n}\n\nexport function collectPageContext(): PageContext {\n return {\n page_url: window.location.href,\n user_agent: navigator.userAgent,\n browser: detectBrowser(),\n os: detectOS(),\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n }\n}\n\nfunction detectBrowser(): string {\n const ua = navigator.userAgent\n if (/Edg\\//.test(ua)) return `Edge ${ua.match(/Edg\\/(\\S+)/)?.[1] ?? ''}`\n if (/OPR\\//.test(ua)) return `Opera ${ua.match(/OPR\\/(\\S+)/)?.[1] ?? ''}`\n if (/Chrome\\//.test(ua)) return `Chrome ${ua.match(/Chrome\\/(\\S+)/)?.[1] ?? ''}`\n if (/Safari\\//.test(ua) && /Version\\//.test(ua)) return `Safari ${ua.match(/Version\\/(\\S+)/)?.[1] ?? ''}`\n if (/Firefox\\//.test(ua)) return `Firefox ${ua.match(/Firefox\\/(\\S+)/)?.[1] ?? ''}`\n return 'Unknown'\n}\n\nfunction detectOS(): string {\n const ua = navigator.userAgent\n if (/Windows NT 10/.test(ua)) return 'Windows 10/11'\n if (/Windows NT/.test(ua)) return 'Windows'\n if (/Mac OS X 10_15|macOS 1[56789]/.test(ua)) return 'macOS'\n if (/Mac OS X/.test(ua)) return 'macOS'\n if (/Android/.test(ua)) return `Android ${ua.match(/Android (\\d+)/)?.[1] ?? ''}`\n if (/iPhone|iPad|iPod/.test(ua)) return 'iOS'\n if (/Linux/.test(ua)) return 'Linux'\n return 'Unknown'\n}\n","import type { PageContext } from '../context/collector'\nimport type { Annotation, Breadcrumb, FeedbackPayload, MakeThisBetterConfig } from '../types'\nimport type { RecordingResult } from '../record/session'\n\nexport function buildPayload(\n description: string,\n pageContext: PageContext,\n consoleErrors: string[],\n annotation: Annotation | null,\n user: MakeThisBetterConfig['user'],\n recording?: RecordingResult,\n anonId?: string,\n anonEmail?: string,\n breadcrumbs?: Breadcrumb[],\n): FeedbackPayload {\n return {\n description,\n ...pageContext,\n console_errors: consoleErrors,\n annotations: annotation ? [annotation] : [],\n target_element: annotation?.targetSelector\n ? {\n selector: annotation.targetSelector,\n text: annotation.targetText ?? '',\n name: annotation.targetName ?? '',\n }\n : undefined,\n user_id: user?.id,\n user_email: user?.email,\n user_name: user?.name,\n reporter_external_id: user ? undefined : anonId,\n reporter_email: user ? undefined : anonEmail,\n recording_events: recording?.events,\n recording_duration: recording?.duration,\n breadcrumbs,\n }\n}\n","const STORAGE_KEY = 'mtb_anon_id'\nconst EMAIL_KEY = 'mtb_reporter_email'\nconst BOARD_URL_KEY = 'mtb_board_url'\n\nlet memoryId: string | null = null\nlet memoryEmail: string | null = null\nlet memoryBoardUrl: string | null = null\n\nexport function getAnonId(): string {\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY)\n if (stored?.startsWith('anon_')) return stored\n const id = generateAnonId()\n window.localStorage.setItem(STORAGE_KEY, id)\n return id\n } catch {\n memoryId ??= generateAnonId()\n return memoryId\n }\n}\n\nexport function getStoredReporterEmail(): string | undefined {\n try {\n return window.localStorage.getItem(EMAIL_KEY) ?? undefined\n } catch {\n return memoryEmail ?? undefined\n }\n}\n\nexport function rememberReporterEmail(email: string): void {\n memoryEmail = email\n try {\n window.localStorage.setItem(EMAIL_KEY, email)\n } catch {\n // localStorage unavailable — the in-memory copy covers this session\n }\n}\n\nexport function getCachedBoardUrl(): string | undefined {\n try {\n return window.localStorage.getItem(BOARD_URL_KEY) ?? undefined\n } catch {\n return memoryBoardUrl ?? undefined\n }\n}\n\nexport function cacheBoardUrl(url: string): void {\n memoryBoardUrl = url\n try {\n window.localStorage.setItem(BOARD_URL_KEY, url)\n } catch {\n // localStorage unavailable — the in-memory copy covers this session\n }\n}\n\nfunction generateAnonId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return `anon_${crypto.randomUUID()}`\n }\n const random = `${Date.now().toString(16)}-${Math.random().toString(16).slice(2, 10)}`\n return `anon_${random}`\n}\n","export default {\n tab: 'Feedback',\n toolbar: {\n markup: 'Mark up',\n record: 'Record',\n hint: 'Click to comment, drag to draw',\n hintRecord: 'Recording your screen',\n exit: 'Exit',\n },\n popup: {\n about: 'About',\n placeholder: 'Describe the issue or suggestion...',\n submit: 'Submit',\n cancel: 'Cancel',\n my_feedback: 'My feedback',\n quickOptions: [\n { emoji: '🐛', label: \"Something's broken\" },\n { emoji: '💡', label: 'I have a suggestion' },\n { emoji: '🤔', label: \"I'm confused\" },\n ],\n },\n success: {\n title: 'Sent — thanks!',\n message: 'Your note and captured technical context are on their way to the team. You’ll hear back when it’s resolved.',\n title_no_ai: \"Thanks! We've received your feedback.\",\n message_no_ai: \"The team will take it from here. You'll hear back when it's resolved.\",\n view_feedback: 'View my feedback',\n close: 'Close',\n email_prompt: \"Want updates? Leave your email and we'll let you know when it's resolved.\",\n email_placeholder: 'you@example.com',\n email_submit: 'Notify me',\n email_saved: \"You'll get an email when it's resolved.\",\n email_error: \"Couldn't save your email. Please try again.\",\n },\n error: {\n submit: 'Failed to submit. Please try again.',\n },\n pet: {\n bubble: 'Need help?',\n },\n frustration: {\n prompt: 'Something not working? Tell us.',\n action: 'Annotate',\n dismiss: 'Dismiss',\n },\n annotation: {\n drawing: 'Drawing',\n element: 'element',\n },\n draw: {\n note_placeholder: 'Add a note to your drawing',\n undo: 'Undo',\n redo: 'Redo',\n cancel: 'Cancel',\n submit: 'Submit',\n },\n record: {\n stop: 'Stop',\n timer_label: 'Recording',\n max_reached: 'Maximum recording time reached',\n replay_label: 'screen-recording.json',\n play: 'Play recording',\n close: 'Close',\n preview_unavailable: 'Preview unavailable',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Sharpening your feedback',\n thinking: 'Thinking...',\n placeholder: 'Type your answer — or skip the question',\n send: 'Send',\n send_feedback: 'Send feedback',\n skip: 'Skip & send',\n retry: 'Retry',\n error: 'AI clarification failed. Please try again.',\n expired: 'This feedback session expired before it could be sent. Please close the widget and submit again.',\n },\n}\n","export default {\n tab: '反馈',\n toolbar: {\n markup: '标注',\n record: '录屏',\n hint: '点击评论,拖动绘制',\n hintRecord: '正在录制屏幕',\n exit: '退出',\n },\n popup: {\n about: '关于',\n placeholder: '描述问题或建议...',\n submit: '提交',\n cancel: '取消',\n my_feedback: '我的反馈',\n quickOptions: [\n { emoji: '🐛', label: '出问题了' },\n { emoji: '💡', label: '我有一个建议' },\n { emoji: '🤔', label: '我有点困惑' },\n ],\n },\n success: {\n title: '已发送,感谢!',\n message: '您的反馈和采集到的技术上下文正在发送给团队。问题解决后,您会收到通知。',\n title_no_ai: '感谢!我们已收到您的反馈。',\n message_no_ai: '接下来由团队处理。问题解决后,您会收到通知。',\n view_feedback: '查看我的反馈',\n close: '关闭',\n email_prompt: '想了解进展?留下邮箱,问题解决后我们会通知您。',\n email_placeholder: 'you@example.com',\n email_submit: '通知我',\n email_saved: '问题解决后您会收到邮件通知。',\n email_error: '邮箱保存失败,请重试。',\n },\n error: {\n submit: '提交失败,请重试。',\n },\n pet: {\n bubble: '需要帮助吗?',\n },\n frustration: {\n prompt: '遇到问题了?告诉我们。',\n action: '标注',\n dismiss: '关闭',\n },\n annotation: {\n drawing: '绘制',\n element: '元素',\n },\n draw: {\n note_placeholder: '给你的绘制添加说明',\n undo: '撤销',\n redo: '重做',\n cancel: '取消',\n submit: '提交',\n },\n record: {\n stop: '停止',\n timer_label: '录制中',\n max_reached: '已达到最长录制时间',\n replay_label: 'screen-recording.json',\n play: '播放录屏',\n close: '关闭',\n preview_unavailable: '暂无法预览',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: '正在完善你的反馈',\n thinking: '思考中...',\n placeholder: '输入回答,或跳过问题',\n send: '发送',\n send_feedback: '发送反馈',\n skip: '跳过并发送',\n retry: '重试',\n error: 'AI 澄清失败,请重试。',\n expired: '这条反馈在发送前已过期。请关闭组件后重新提交。',\n },\n}\n","export default {\n tab: 'フィードバック',\n toolbar: {\n markup: 'マークアップ',\n record: '録画',\n hint: 'クリックでコメント、ドラッグで描画',\n hintRecord: '画面を録画中',\n exit: '終了',\n },\n popup: {\n about: '概要',\n placeholder: '問題や提案を入力してください...',\n submit: '送信',\n cancel: 'キャンセル',\n my_feedback: '自分のフィードバック',\n quickOptions: [\n { emoji: '🐛', label: '不具合があります' },\n { emoji: '💡', label: '提案があります' },\n { emoji: '🤔', label: 'わかりにくいです' },\n ],\n },\n success: {\n title: '送信しました。ありがとうございます!',\n message: 'ご意見と取得した技術情報をチームに送信しました。解決次第お知らせします。',\n title_no_ai: 'ありがとうございます!フィードバックを受け付けました。',\n message_no_ai: 'チームが対応します。解決次第お知らせします。',\n view_feedback: 'フィードバックを確認',\n close: '閉じる',\n email_prompt: '進捗を知りたい場合は、メールアドレスをご記入ください。解決次第お知らせします。',\n email_placeholder: 'you@example.com',\n email_submit: '通知を受け取る',\n email_saved: '解決次第メールでお知らせします。',\n email_error: 'メールアドレスを保存できませんでした。もう一度お試しください。',\n },\n error: {\n submit: '送信に失敗しました。もう一度お試しください。',\n },\n pet: {\n bubble: 'お困りですか?',\n },\n frustration: {\n prompt: 'うまくいかないことがありますか?お知らせください。',\n action: '注釈',\n dismiss: '閉じる',\n },\n annotation: {\n drawing: '描画',\n element: '要素',\n },\n draw: {\n note_placeholder: '描画にメモを追加',\n undo: '元に戻す',\n redo: 'やり直す',\n cancel: 'キャンセル',\n submit: '送信',\n },\n record: {\n stop: '停止',\n timer_label: '録画中',\n max_reached: '最大記録時間に達しました',\n replay_label: 'screen-recording.json',\n play: '録画を再生',\n close: '閉じる',\n preview_unavailable: 'プレビューは利用できません',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'フィードバックを整えています',\n thinking: '考え中...',\n placeholder: '回答を入力、または質問をスキップ',\n send: '送信',\n send_feedback: 'フィードバックを送信',\n skip: 'スキップして送信',\n retry: '再試行',\n error: 'AIによる確認に失敗しました。もう一度お試しください。',\n expired: 'このフィードバックは送信される前に有効期限が切れました。ウィジェットを閉じて、もう一度送信してください。',\n },\n}\n","export default {\n tab: '피드백',\n toolbar: {\n markup: '마크업',\n record: '녹화',\n hint: '클릭하여 댓글, 드래그하여 그리기',\n hintRecord: '화면 녹화 중',\n exit: '나가기',\n },\n popup: {\n about: '정보',\n placeholder: '문제 또는 제안 사항을 설명해 주세요...',\n submit: '제출',\n cancel: '취소',\n my_feedback: '내 피드백',\n quickOptions: [\n { emoji: '🐛', label: '문제가 있어요' },\n { emoji: '💡', label: '제안이 있어요' },\n { emoji: '🤔', label: '헷갈려요' },\n ],\n },\n success: {\n title: '전송되었습니다. 감사합니다!',\n message: '피드백과 수집된 기술 정보가 팀에 전달되었습니다. 해결되면 알려드리겠습니다.',\n title_no_ai: '감사합니다! 피드백을 접수했습니다.',\n message_no_ai: '팀에서 처리합니다. 해결되면 알려드리겠습니다.',\n view_feedback: '내 피드백 보기',\n close: '닫기',\n email_prompt: '진행 상황이 궁금하신가요? 이메일을 남겨주시면 해결 시 알려드립니다.',\n email_placeholder: 'you@example.com',\n email_submit: '알림 받기',\n email_saved: '해결되면 이메일로 알려드립니다.',\n email_error: '이메일을 저장하지 못했습니다. 다시 시도해 주세요.',\n },\n error: {\n submit: '제출에 실패했습니다. 다시 시도해 주세요.',\n },\n pet: {\n bubble: '도움이 필요하신가요?',\n },\n frustration: {\n prompt: '문제가 있으신가요? 알려 주세요.',\n action: '주석',\n dismiss: '닫기',\n },\n annotation: {\n drawing: '그리기',\n element: '요소',\n },\n draw: {\n note_placeholder: '그림에 메모 추가',\n undo: '실행 취소',\n redo: '다시 실행',\n cancel: '취소',\n submit: '보내기',\n },\n record: {\n stop: '중지',\n timer_label: '녹화 중',\n max_reached: '최대 녹화 시간에 도달했습니다',\n replay_label: 'screen-recording.json',\n play: '녹화 재생',\n close: '닫기',\n preview_unavailable: '미리보기를 사용할 수 없습니다',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: '피드백을 다듬는 중',\n thinking: '생각 중...',\n placeholder: '답변을 입력하거나 질문을 건너뛰세요',\n send: '보내기',\n send_feedback: '피드백 보내기',\n skip: '건너뛰고 보내기',\n retry: '재시도',\n error: 'AI 확인에 실패했습니다. 다시 시도해 주세요.',\n expired: '이 피드백 세션은 전송되기 전에 만료되었습니다. 위젯을 닫고 다시 보내 주세요.',\n },\n}\n","export default {\n tab: 'Comentarios',\n toolbar: {\n markup: 'Anotar',\n record: 'Grabar',\n hint: 'Clic para comentar, arrastrar para dibujar',\n hintRecord: 'Grabando pantalla',\n exit: 'Salir',\n },\n popup: {\n about: 'Acerca de',\n placeholder: 'Describe el problema o sugerencia...',\n submit: 'Enviar',\n cancel: 'Cancelar',\n my_feedback: 'Mis comentarios',\n quickOptions: [\n { emoji: '🐛', label: 'Algo no funciona' },\n { emoji: '💡', label: 'Tengo una sugerencia' },\n { emoji: '🤔', label: 'Estoy confundido' },\n ],\n },\n success: {\n title: 'Enviado, ¡gracias!',\n message: 'Tu nota y el contexto técnico capturado se han enviado al equipo. Te avisaremos cuando se resuelva.',\n title_no_ai: '¡Gracias! Hemos recibido tu comentario.',\n message_no_ai: 'El equipo se encargará a partir de aquí. Te avisaremos cuando se resuelva.',\n view_feedback: 'Ver mis comentarios',\n close: 'Cerrar',\n email_prompt: '¿Quieres novedades? Deja tu correo y te avisaremos cuando se resuelva.',\n email_placeholder: 'tu@ejemplo.com',\n email_submit: 'Avisarme',\n email_saved: 'Recibirás un correo cuando se resuelva.',\n email_error: 'No se pudo guardar tu correo. Inténtalo de nuevo.',\n },\n error: {\n submit: 'Error al enviar. Por favor, inténtalo de nuevo.',\n },\n pet: {\n bubble: '¿Necesitas ayuda?',\n },\n frustration: {\n prompt: '¿Algo no funciona? Cuéntanos.',\n action: 'Anotar',\n dismiss: 'Cerrar',\n },\n annotation: {\n drawing: 'Dibujo',\n element: 'elemento',\n },\n draw: {\n note_placeholder: 'Añade una nota a tu dibujo',\n undo: 'Deshacer',\n redo: 'Rehacer',\n cancel: 'Cancelar',\n submit: 'Enviar',\n },\n record: {\n stop: 'Detener',\n timer_label: 'Grabando',\n max_reached: 'Tiempo máximo de grabación alcanzado',\n replay_label: 'screen-recording.json',\n play: 'Reproducir grabación',\n close: 'Cerrar',\n preview_unavailable: 'Vista previa no disponible',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Afinando tus comentarios',\n thinking: 'Pensando...',\n placeholder: 'Escribe tu respuesta — u omite la pregunta',\n send: 'Enviar',\n send_feedback: 'Enviar comentario',\n skip: 'Omitir y enviar',\n retry: 'Reintentar',\n error: 'No se pudo completar la aclaración con IA. Inténtalo de nuevo.',\n expired: 'Esta sesión de comentarios caducó antes de poder enviarse. Cierra el widget y envíalo de nuevo.',\n },\n}\n","export default {\n tab: 'Avis',\n toolbar: {\n markup: 'Annoter',\n record: 'Enregistrer',\n hint: 'Cliquer pour commenter, glisser pour dessiner',\n hintRecord: \"Enregistrement de l'écran\",\n exit: 'Quitter',\n },\n popup: {\n about: 'À propos',\n placeholder: 'Décrivez le problème ou votre suggestion...',\n submit: 'Envoyer',\n cancel: 'Annuler',\n my_feedback: 'Mes avis',\n quickOptions: [\n { emoji: '🐛', label: 'Quelque chose ne fonctionne pas' },\n { emoji: '💡', label: \"J'ai une suggestion\" },\n { emoji: '🤔', label: 'Je suis perplexe' },\n ],\n },\n success: {\n title: 'Envoyé, merci !',\n message: 'Votre message et le contexte technique collecté ont été transmis à l’équipe. Vous serez informé(e) dès que ce sera résolu.',\n title_no_ai: 'Merci ! Nous avons bien reçu votre avis.',\n message_no_ai: \"L’équipe prend le relais. Vous serez informé(e) dès que ce sera résolu.\",\n view_feedback: 'Voir mes avis',\n close: 'Fermer',\n email_prompt: \"Envie de suivre l'avancement ? Laissez votre e-mail et nous vous préviendrons une fois résolu.\",\n email_placeholder: 'vous@exemple.com',\n email_submit: 'Me prévenir',\n email_saved: 'Vous recevrez un e-mail une fois résolu.',\n email_error: \"Impossible d'enregistrer votre e-mail. Veuillez réessayer.\",\n },\n error: {\n submit: \"Échec de l'envoi. Veuillez réessayer.\",\n },\n pet: {\n bubble: \"Besoin d'aide ?\",\n },\n frustration: {\n prompt: 'Un problème ? Dites-le-nous.',\n action: 'Annoter',\n dismiss: 'Fermer',\n },\n annotation: {\n drawing: 'Dessin',\n element: 'élément',\n },\n draw: {\n note_placeholder: 'Ajoutez une note à votre dessin',\n undo: 'Annuler',\n redo: 'Rétablir',\n cancel: 'Annuler',\n submit: 'Envoyer',\n },\n record: {\n stop: 'Arrêter',\n timer_label: 'Enregistrement',\n max_reached: \"Durée maximale d'enregistrement atteinte\",\n replay_label: 'screen-recording.json',\n play: \"Lire l'enregistrement\",\n close: 'Fermer',\n preview_unavailable: 'Aperçu indisponible',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Affinement de votre retour',\n thinking: 'Réflexion...',\n placeholder: 'Saisissez votre réponse — ou ignorez la question',\n send: 'Envoyer',\n send_feedback: 'Envoyer le retour',\n skip: 'Ignorer et envoyer',\n retry: 'Réessayer',\n error: 'La clarification par IA a échoué. Réessayez.',\n expired: 'Cette session de retour a expiré avant d\\'avoir pu être envoyée. Fermez le widget et renvoyez-la.',\n },\n}\n","export default {\n tab: 'Feedback',\n toolbar: {\n markup: 'Markieren',\n record: 'Aufnehmen',\n hint: 'Klicken zum Kommentieren, ziehen zum Zeichnen',\n hintRecord: 'Bildschirm wird aufgenommen',\n exit: 'Beenden',\n },\n popup: {\n about: 'Info',\n placeholder: 'Beschreiben Sie das Problem oder Ihren Vorschlag...',\n submit: 'Absenden',\n cancel: 'Abbrechen',\n my_feedback: 'Mein Feedback',\n quickOptions: [\n { emoji: '🐛', label: 'Etwas funktioniert nicht' },\n { emoji: '💡', label: 'Ich habe einen Vorschlag' },\n { emoji: '🤔', label: 'Ich bin verwirrt' },\n ],\n },\n success: {\n title: 'Gesendet, vielen Dank!',\n message: 'Ihre Nachricht und der erfasste technische Kontext wurden an das Team gesendet. Sie werden benachrichtigt, sobald das Problem gelöst ist.',\n title_no_ai: 'Vielen Dank! Wir haben Ihr Feedback erhalten.',\n message_no_ai: 'Das Team übernimmt ab hier. Sie werden benachrichtigt, sobald das Problem gelöst ist.',\n view_feedback: 'Mein Feedback ansehen',\n close: 'Schließen',\n email_prompt: 'Updates gewünscht? Hinterlassen Sie Ihre E-Mail und wir melden uns, sobald es gelöst ist.',\n email_placeholder: 'sie@beispiel.de',\n email_submit: 'Benachrichtigen',\n email_saved: 'Sie erhalten eine E-Mail, sobald es gelöst ist.',\n email_error: 'E-Mail konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.',\n },\n error: {\n submit: 'Senden fehlgeschlagen. Bitte versuchen Sie es erneut.',\n },\n pet: {\n bubble: 'Brauchen Sie Hilfe?',\n },\n frustration: {\n prompt: 'Etwas funktioniert nicht? Sagen Sie es uns.',\n action: 'Kommentieren',\n dismiss: 'Schließen',\n },\n annotation: {\n drawing: 'Zeichnung',\n element: 'Element',\n },\n draw: {\n note_placeholder: 'Fügen Sie Ihrer Zeichnung eine Notiz hinzu',\n undo: 'Rückgängig',\n redo: 'Wiederholen',\n cancel: 'Abbrechen',\n submit: 'Absenden',\n },\n record: {\n stop: 'Stopp',\n timer_label: 'Aufnahme',\n max_reached: 'Maximale Aufnahmedauer erreicht',\n replay_label: 'screen-recording.json',\n play: 'Aufnahme abspielen',\n close: 'Schließen',\n preview_unavailable: 'Vorschau nicht verfügbar',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Wir schärfen dein Feedback',\n thinking: 'Einen Moment...',\n placeholder: 'Antwort eingeben — oder Frage überspringen',\n send: 'Senden',\n send_feedback: 'Feedback senden',\n skip: 'Überspringen & senden',\n retry: 'Erneut versuchen',\n error: 'Die KI-Klärung ist fehlgeschlagen. Bitte erneut versuchen.',\n expired: 'Diese Feedback-Sitzung ist abgelaufen, bevor sie gesendet werden konnte. Bitte schließe das Widget und sende erneut.',\n },\n}\n","import en from './en'\nimport zhCN from './zh-CN'\nimport ja from './ja'\nimport ko from './ko'\nimport es from './es'\nimport fr from './fr'\nimport de from './de'\n\nexport type I18nMessages = typeof en\n\nconst locales: Record<string, I18nMessages> = {\n en,\n 'zh-CN': zhCN,\n ja,\n ko,\n es,\n fr,\n de,\n}\n\nexport function getMessages(locale: string): I18nMessages {\n if (locales[locale]) return locales[locale]\n const lang = locale.split('-')[0]\n if (locales[lang]) return locales[lang]\n return locales['en']\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { RecordingOptions } from '../types'\n\ntype RRWebEvent = Record<string, unknown>\ntype StopFn = () => void\n\ninterface RRWebRecordOptions {\n emit: (event: RRWebEvent) => void\n maskAllInputs: boolean\n blockClass: string\n maskTextClass: string\n}\n\ninterface RRWebRecordFn {\n (options: RRWebRecordOptions): StopFn\n addCustomEvent: (tag: string, payload: Record<string, unknown>) => void\n}\n\nexport interface RecordingResult {\n events: RRWebEvent[]\n duration: number\n}\n\nconst MAX_DURATION_S = 60\n// rrweb's own defaults for opting an element out of a replay. Named here so the\n// README can document them and so the values stay in one place.\nexport const BLOCK_CLASS = 'rr-block'\nexport const MASK_TEXT_CLASS = 'rr-mask'\n// Pinned version + SRI: this script executes on customers' pages, so a\n// floating tag or unverified content would be a supply-chain hole. Bumping\n// the version requires recomputing the hash from the exact CDN file:\n// curl -sL <url> | openssl dgst -sha384 -binary | openssl base64 -A\n// Must stay on @rrweb/record's static /umd/ build: the `rrweb` package ships\n// no UMD in 2.x (its dist files are ESM and throw \"Unexpected token 'export'\"\n// in a classic script tag), and jsDelivr's auto-minified files are unsafe for\n// SRI because their hash changes when jsDelivr upgrades its minifier.\nconst RRWEB_CDN = 'https://cdn.jsdelivr.net/npm/@rrweb/record@2.1.0/umd/record.min.js'\nconst RRWEB_SRI = 'sha384-MrD66HBNSykaP2N95+6hQCFlF5oH2tvL3TD/zyvHNkP/sAFWZx98DX9MEDy8MdVT'\n\nlet rrwebLoaded: Promise<RRWebRecordFn> | null = null\n\nfunction loadRrweb(): Promise<RRWebRecordFn> {\n if (rrwebLoaded) return rrwebLoaded\n rrwebLoaded = loadViaImport().catch(() => loadViaCdn())\n return rrwebLoaded\n}\n\nasync function loadViaImport(): Promise<RRWebRecordFn> {\n const mod = await import('@rrweb/record')\n return mod.record as unknown as RRWebRecordFn\n}\n\ninterface RRWebGlobals {\n rrwebRecord?: { record: RRWebRecordFn }\n rrweb?: { record: RRWebRecordFn }\n}\n\nfunction findGlobalRecord(): RRWebRecordFn | undefined {\n const win = globalThis as unknown as Window & RRWebGlobals\n return win.rrwebRecord?.record ?? win.rrweb?.record\n}\n\nfunction loadViaCdn(): Promise<RRWebRecordFn> {\n return new Promise((resolve, reject) => {\n const existing = findGlobalRecord()\n if (existing) { resolve(existing); return }\n const script = document.createElement('script')\n script.src = RRWEB_CDN\n script.integrity = RRWEB_SRI\n script.crossOrigin = 'anonymous'\n script.onload = () => {\n const record = findGlobalRecord()\n if (record) resolve(record)\n else reject(new Error('rrweb record global not found after script load'))\n }\n script.onerror = () => reject(new Error('Failed to load rrweb from CDN'))\n document.head.appendChild(script)\n })\n}\n\nexport class RecordSession {\n private events: RRWebEvent[] = []\n private stopFn: StopFn | null = null\n private startedAt = 0\n private timer: ReturnType<typeof setTimeout> | null = null\n private clickHandler: ((e: MouseEvent) => void) | null = null\n private shadow: ShadowContainer\n private onMaxReached?: () => void\n private options: RecordingOptions\n private stopped = false\n private destroyed = false\n\n constructor(shadow: ShadowContainer, onMaxReached?: () => void, options: RecordingOptions = {}) {\n this.shadow = shadow\n this.onMaxReached = onMaxReached\n this.options = options\n }\n\n async start(): Promise<void> {\n const record = await loadRrweb()\n\n // A cold dynamic import takes hundreds of milliseconds, and the reporter can\n // cancel the replay inside that window. Without this guard the resumed start()\n // would attach a recorder, a document click listener and a 60s timer that no\n // live object holds a handle to — rrweb would then serialize every mutation of\n // the host page for the rest of the session, after an explicit cancel.\n if (this.destroyed) return\n\n this.startedAt = Date.now()\n this.stopped = false\n\n this.stopFn = record({\n emit: (event: RRWebEvent) => {\n if (!this.stopped) this.events.push(event)\n },\n // Default to masking every input value, not just password fields (rrweb's\n // own default). A replay is captured from whatever page the reporter happens\n // to be on, which may be a checkout or a 2FA prompt, and nothing downstream\n // scrubs it. Customers who need real values in replays must opt in.\n maskAllInputs: this.options.maskAllInputs ?? true,\n blockClass: BLOCK_CLASS,\n maskTextClass: MASK_TEXT_CLASS,\n })\n\n this.clickHandler = (e: MouseEvent) => {\n this.showClickRipple(e.clientX, e.clientY)\n record.addCustomEvent?.('mtb-click', {\n x: e.clientX,\n y: e.clientY,\n target: e.target instanceof HTMLElement ? e.target.tagName : '',\n })\n }\n document.addEventListener('click', this.clickHandler, true)\n\n this.timer = setTimeout(() => {\n this.onMaxReached?.()\n }, MAX_DURATION_S * 1000)\n }\n\n stop(): RecordingResult {\n this.stopped = true\n this.stopFn?.()\n this.stopFn = null\n this.cleanupTimer()\n this.cleanupClickHandler()\n\n return {\n events: this.events,\n duration: this.getDuration(),\n }\n }\n\n getDuration(): number {\n if (this.startedAt === 0) return 0\n return Math.max(1, Math.round((Date.now() - this.startedAt) / 1000))\n }\n\n destroy(): void {\n this.destroyed = true\n this.stopped = true\n this.stopFn?.()\n this.stopFn = null\n this.cleanupTimer()\n this.cleanupClickHandler()\n this.events = []\n this.startedAt = 0\n }\n\n private cleanupTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer)\n this.timer = null\n }\n }\n\n private cleanupClickHandler(): void {\n if (this.clickHandler) {\n document.removeEventListener('click', this.clickHandler, true)\n this.clickHandler = null\n }\n }\n\n private showClickRipple(x: number, y: number): void {\n const ripple = this.shadow.el<HTMLDivElement>('div', 'mtb-click-ripple')\n ripple.style.left = `${x}px`\n ripple.style.top = `${y}px`\n this.shadow.append(ripple)\n ripple.addEventListener('animationend', () => ripple.remove())\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\n\nexport class RecordControlBar {\n private el: HTMLDivElement\n private timerEl!: HTMLSpanElement\n private intervalId: ReturnType<typeof setInterval> | null = null\n private getDuration: () => number\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n getDuration: () => number,\n onStop: () => void,\n ) {\n this.getDuration = getDuration\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-record-bar')\n this.el.innerHTML = `\n <span class=\"mtb-record-dot\"></span>\n <span class=\"mtb-record-timer\">00:00</span>\n <button class=\"mtb-record-stop\" type=\"button\">${messages.record.stop}</button>\n `\n shadow.append(this.el)\n\n this.timerEl = this.el.querySelector('.mtb-record-timer')!\n this.el.querySelector('.mtb-record-stop')!.addEventListener('click', onStop)\n\n this.intervalId = setInterval(() => this.updateTimer(), 1000)\n }\n\n private updateTimer(): void {\n const secs = this.getDuration()\n const mm = String(Math.floor(secs / 60)).padStart(2, '0')\n const ss = String(secs % 60).padStart(2, '0')\n this.timerEl.textContent = `${mm}:${ss}`\n }\n\n destroy(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId)\n this.intervalId = null\n }\n this.el.remove()\n }\n}\n","import { RecordSession } from '../record/session'\nimport type { RecordingResult } from '../record/session'\nimport { RecordControlBar } from '../record/control-bar'\nimport type { ShadowContainer } from './shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { RecordingOptions } from '../types'\n\nexport type { RecordingResult }\n\nexport class RecordingManager {\n private session: RecordSession | null = null\n private bar: RecordControlBar | null = null\n private result: RecordingResult | null = null\n\n async start(\n shadow: ShadowContainer,\n messages: I18nMessages,\n onStop: () => void,\n options: RecordingOptions = {},\n ): Promise<void> {\n this.session = new RecordSession(shadow, onStop, options)\n this.bar = new RecordControlBar(\n shadow,\n messages,\n () => this.session?.getDuration() ?? 0,\n onStop,\n )\n await this.session.start()\n }\n\n stop(): RecordingResult | null {\n if (!this.session) return null\n this.result = this.session.stop()\n this.teardownUI()\n return this.result\n }\n\n getRecording(): RecordingResult | null {\n return this.result\n }\n\n destroy(): void {\n this.teardownUI()\n this.result = null\n }\n\n private teardownUI(): void {\n this.session?.destroy()\n this.session = null\n this.bar?.destroy()\n this.bar = null\n }\n}\n","import { ShadowContainer } from './shadow'\nimport { FeedbackTab } from './tab'\nimport { FrustrationPromptCard } from './frustration-prompt'\nimport { DimOverlay } from './dim-overlay'\nimport { ScrollLock } from './scroll-lock'\nimport { AnnotationToolbar } from '../annotate/toolbar'\nimport type { ToolbarMode } from '../annotate/toolbar'\nimport { AnnotationSession } from '../annotate/session'\nimport { DrawNoteBar } from '../annotate/draw-note-bar'\nimport { CommentPopup } from '../popup/comment'\nimport { ClarifyCard } from '../popup/clarify'\nimport { SuccessCard } from '../popup/success'\nimport type { SuccessCardOptions } from '../popup/success'\nimport { captureScreenshot } from '../screenshot/capture'\nimport { ConsoleErrorCollector } from '../context/console'\nimport { BreadcrumbCollector } from '../context/breadcrumbs'\nimport { FrustrationDetector } from '../context/frustration'\nimport { isFrustrationDismissed, markFrustrationDismissed } from '../context/frustration-state'\nimport { collectPageContext } from '../context/collector'\nimport type { PageContext } from '../context/collector'\nimport { ApiClient } from '../api/client'\nimport type { ClarifyStreamResult } from '../api/client'\nimport { buildPayload } from './payload'\nimport { cacheBoardUrl, getAnonId, getCachedBoardUrl, getStoredReporterEmail, rememberReporterEmail } from './anon-id'\nimport { getMessages } from '../i18n'\nimport { RecordingManager } from './recording-manager'\nimport type { MakeThisBetterConfig, Annotation, SubmissionSessionResponse, TargetRect } from '../types'\n\nconst SPECULATIVE_CLARIFY_TIMEOUT_MS = 3000\n// How long a clarification stream may stay silent before it becomes retryable.\n// Measured between tokens, not from the start, so a long answer is not cut off.\nconst CLARIFY_SILENCE_TIMEOUT_MS = 12000\n\ntype Mode = 'idle' | 'annotating' | 'recording' | 'drawing' | 'popup' | 'clarifying'\ntype Via = 'pin' | 'draw' | 'record'\n\ninterface SubmittingUi {\n setLoading: (loading: boolean) => void\n setError: (message: string) => void\n}\n\n// A browser SDK has no build-time environment, so \"is a developer watching?\"\n// has to be inferred. Loopback and the .local/.test dev TLDs are where an\n// integrator runs; anything else is somebody's live site.\nfunction isLocalHost(): boolean {\n const { hostname } = window.location\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '[::1]' ||\n hostname.endsWith('.localhost') ||\n hostname.endsWith('.local') ||\n hostname.endsWith('.test')\n )\n}\n\nexport class WidgetController {\n private config: MakeThisBetterConfig\n private shadow!: ShadowContainer\n private tab: FeedbackTab | null = null\n private toolbar: AnnotationToolbar | null = null\n private session: AnnotationSession | null = null\n private scrollLock = new ScrollLock()\n private drawBar: DrawNoteBar | null = null\n private dim: DimOverlay | null = null\n private popup: CommentPopup | null = null\n private clarify: ClarifyCard | null = null\n private success: SuccessCard | null = null\n private frustrationPrompt: FrustrationPromptCard | null = null\n private apiClient: ApiClient\n private consoleCollector: ConsoleErrorCollector\n private breadcrumbCollector: BreadcrumbCollector\n private frustrationDetector: FrustrationDetector | null = null\n private messages: ReturnType<typeof getMessages>\n private mode: Mode = 'idle'\n private via: Via = 'pin'\n private currentAnnotation: Annotation | null = null\n private submittingUi: SubmittingUi | null = null\n private lastPopupPos: { x: number; y: number } | null = null\n private recordingManager: RecordingManager | null = null\n private activeSubmission: SubmissionSessionResponse | null = null\n private submissionAttempt = 0\n private lastHandoff: { feedbackId?: string; boardUrl?: string; identityToken?: string } = {}\n\n constructor(config: MakeThisBetterConfig) {\n this.config = config\n this.messages = getMessages(config.locale ?? document.documentElement.lang ?? 'en')\n this.apiClient = new ApiClient(config.projectKey, config.apiUrl, undefined, config.userToken, config.userTokenFn)\n this.consoleCollector = new ConsoleErrorCollector()\n this.consoleCollector.start()\n this.breadcrumbCollector = new BreadcrumbCollector()\n this.breadcrumbCollector.start()\n this.buildUI()\n\n if (config.frustrationDetection !== false) {\n this.frustrationDetector = new FrustrationDetector(() => this.handleFrustration())\n this.frustrationDetector.start()\n }\n\n document.addEventListener('keydown', this.handleKeydown, true)\n }\n\n // Escape only acts while the widget is in an active state; idle/clarifying\n // fall through untouched so the host page's own Escape handling still works.\n private handleKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n\n switch (this.mode) {\n case 'annotating':\n case 'popup':\n event.preventDefault()\n event.stopPropagation()\n this.exitAll()\n break\n case 'drawing':\n event.preventDefault()\n event.stopPropagation()\n this.cancelDraw()\n break\n case 'recording':\n event.preventDefault()\n event.stopPropagation()\n this.handleRecordStop()\n break\n default:\n break\n }\n }\n\n private buildUI(): void {\n this.shadow = new ShadowContainer(this.config.theme ?? 'auto')\n\n if (this.config.entryMode === 'api') {\n // Nothing is reachable until the host wires up open(), and silence would\n // look identical to a broken install. But 'api' is a supported setting,\n // so a warning on every production page load would be a third-party SDK\n // shouting at customers who did nothing wrong — say it only where an\n // integrator is watching.\n if (isLocalHost()) {\n console.warn(\n '[MakeThisBetter] entryMode: \"api\" renders no launcher. ' +\n 'Call MakeThisBetter.open() from your own UI, or use showLauncher().',\n )\n }\n return\n }\n\n this.mountTab()\n }\n\n private mountTab(): void {\n if (this.tab) return\n this.tab = new FeedbackTab(\n this.shadow,\n this.messages,\n this.config.position ?? 'right',\n () => this.handleTabClick(),\n this.config.tabText,\n )\n }\n\n /** Opens annotation mode. Idempotent: a second call while open does nothing. */\n open(): void {\n if (this.mode !== 'idle') return\n this.dismissFrustrationPrompt()\n this.enterAnnotationMode()\n }\n\n close(): void {\n if (this.mode === 'idle') return\n this.exitAll()\n }\n\n showLauncher(): void {\n this.mountTab()\n this.tab?.setActive(this.mode !== 'idle')\n }\n\n hideLauncher(): void {\n this.tab?.destroy()\n this.tab = null\n }\n\n // Takes effect for anything opened afterwards. Components already on screen keep\n // the language they were opened in rather than being re-rendered underneath a\n // reporter who may be mid-sentence.\n setLocale(locale: string): void {\n this.config.locale = locale\n this.messages = getMessages(locale)\n this.tab?.setMessages(this.messages)\n }\n\n private handleTabClick(): void {\n if (this.mode === 'idle') {\n this.dismissFrustrationPrompt()\n this.enterAnnotationMode()\n } else {\n this.exitAll()\n }\n }\n\n private handleFrustration(): void {\n if (this.mode !== 'idle' || this.frustrationPrompt || isFrustrationDismissed()) return\n\n this.frustrationPrompt = new FrustrationPromptCard(this.shadow, this.messages, {\n onTell: () => {\n this.dismissFrustrationPrompt()\n this.enterAnnotationMode()\n },\n onDismiss: () => {\n markFrustrationDismissed()\n this.dismissFrustrationPrompt()\n },\n // An unnoticed card is not a refusal, so it must not suppress later\n // prompts. The detector's own 60s cooldown does the rate limiting.\n onAutoHide: () => this.dismissFrustrationPrompt(),\n })\n }\n\n private dismissFrustrationPrompt(): void {\n this.frustrationPrompt?.destroy()\n this.frustrationPrompt = null\n }\n\n private enterAnnotationMode(): void {\n this.mode = 'annotating'\n this.tab?.setActive(true)\n this.scrollLock.lock()\n\n this.toolbar = new AnnotationToolbar(\n this.shadow,\n this.messages,\n () => this.exitAll(),\n (mode: ToolbarMode) => this.handleToolbarModeChange(mode),\n )\n this.session = this.createSession()\n }\n\n private createSession(): AnnotationSession {\n return new AnnotationSession(this.shadow, this.messages, {\n onPin: (annotation, targetName) => {\n this.currentAnnotation = annotation\n this.via = 'pin'\n this.showPopup(annotation.x, annotation.y, targetName, annotation.targetRect)\n },\n onDrawStroke: () => this.handleDrawStroke(),\n })\n }\n\n private handleToolbarModeChange(mode: ToolbarMode): void {\n if (this.mode === 'clarifying') {\n this.toolbar?.setMode(this.via === 'record' ? 'record' : 'markup')\n return\n }\n\n if (mode === 'record') {\n if (this.mode === 'recording') return\n\n this.mode = 'recording'\n this.currentAnnotation = null\n this.teardownDraw()\n this.session?.destroy()\n this.session = null\n // Recording exists to capture the user reproducing something, which\n // usually means scrolling. The annotation freeze must not carry over.\n this.scrollLock.unlock()\n this.recordingManager = new RecordingManager()\n this.recordingManager.start(\n this.shadow,\n this.messages,\n this.handleRecordStop,\n this.config.recording ?? {},\n ).catch((error) => {\n // rrweb failed to load (network / SRI mismatch) — fall back to markup\n console.warn('[MakeThisBetter] Interaction replay unavailable, falling back to markup:', error)\n if (this.mode !== 'recording') return\n this.toolbar?.setMode('markup')\n this.handleToolbarModeChange('markup')\n })\n } else {\n this.recordingManager?.destroy()\n this.recordingManager = null\n this.teardownDraw()\n if (!this.session) this.session = this.createSession()\n this.scrollLock.lock()\n this.mode = 'annotating'\n }\n }\n\n private handleRecordStop = (): void => {\n if (!this.recordingManager) return\n this.recordingManager.stop()\n this.via = 'record'\n this.showPopup(window.innerWidth / 2, window.innerHeight / 2, this.messages.record.timer_label)\n }\n\n private handleDrawStroke(): void {\n if (this.mode !== 'drawing') {\n this.mode = 'drawing'\n this.drawBar = new DrawNoteBar(this.shadow, {\n messages: this.messages,\n onUndo: () => this.handleDrawUndoRedo('undo'),\n onRedo: () => this.handleDrawUndoRedo('redo'),\n onCancel: () => this.cancelDraw(),\n onSubmit: (note) => this.handleDrawSubmit(note),\n })\n }\n this.refreshDrawBar()\n }\n\n private handleDrawUndoRedo(action: 'undo' | 'redo'): void {\n if (action === 'undo') this.session?.undoDraw()\n else this.session?.redoDraw()\n this.refreshDrawBar()\n }\n\n private refreshDrawBar(): void {\n if (!this.session) return\n this.drawBar?.setUndoRedo(this.session.canUndoDraw(), this.session.canRedoDraw())\n }\n\n private cancelDraw(): void {\n this.session?.clearDraw()\n this.teardownDraw()\n this.mode = 'annotating'\n }\n\n private teardownDraw(): void {\n this.drawBar?.destroy()\n this.drawBar = null\n }\n\n private handleDrawSubmit(note: string): void {\n const annotation = this.session?.getDrawAnnotation()\n if (!annotation) {\n this.cancelDraw()\n return\n }\n this.currentAnnotation = annotation\n this.via = 'draw'\n this.session?.dismissInteraction()\n this.submittingUi = this.drawBar\n void this.handleSubmit(note || this.messages.annotation.drawing)\n }\n\n private showPopup(x: number, y: number, targetName: string, targetRect?: TargetRect): void {\n this.mode = 'popup'\n this.lastPopupPos = { x, y }\n this.teardownDraw()\n this.session?.dismissInteraction()\n this.popup?.destroy()\n this.popup = null\n this.dim?.destroy()\n this.dim = null\n this.dim = new DimOverlay(this.shadow, () => this.exitAll())\n\n this.popup = new CommentPopup(this.shadow, {\n targetName,\n x,\n y,\n targetRect,\n messages: this.messages,\n onSubmit: (description) => this.handleSubmit(description),\n onClose: () => this.exitAll(),\n onMyFeedback: this.buildMyFeedbackHandler(),\n position: this.config.position ?? 'right',\n })\n this.submittingUi = this.popup\n }\n\n private buildMyFeedbackHandler(): (() => void) | undefined {\n if (this.config.user) return undefined\n if (!getCachedBoardUrl()) return undefined\n\n return async () => {\n const exchange = await this.apiClient.createIdentityToken(getAnonId())\n if (!exchange?.identity_token || !exchange.board_url) return\n cacheBoardUrl(exchange.board_url)\n window.open(`${exchange.board_url}?identity=${encodeURIComponent(exchange.identity_token)}`, '_blank')\n }\n }\n\n private async handleSubmit(description: string): Promise<void> {\n const ui = this.submittingUi\n if (!ui) return\n const submissionAttempt = ++this.submissionAttempt\n ui.setLoading(true)\n await waitForPaint()\n const annotation = this.currentAnnotation\n const recording = this.recordingManager?.getRecording() ?? undefined\n\n const [screenshot, pageContext] = await Promise.all([\n captureScreenshot(annotation ? [annotation] : []),\n Promise.resolve(collectPageContext()),\n ])\n\n const payload = buildPayload(\n description,\n pageContext,\n this.consoleCollector.getErrors(),\n annotation,\n this.config.user,\n recording,\n this.config.user ? undefined : getAnonId(),\n this.config.user ? undefined : getStoredReporterEmail(),\n this.breadcrumbCollector.getBreadcrumbs(),\n )\n\n try {\n const submission = await this.apiClient.createSubmissionSession(payload, screenshot)\n if (submissionAttempt !== this.submissionAttempt) {\n await this.apiClient.abandonSubmissionSession(submission.id, submission.token).catch(() => {})\n return\n }\n this.activeSubmission = submission\n await this.speculativeClarify(submission, this.lastPopupPos, submissionAttempt)\n } catch {\n if (submissionAttempt !== this.submissionAttempt) return\n ui.setLoading(false)\n ui.setError(this.messages.error.submit)\n }\n }\n\n private async speculativeClarify(\n submission: SubmissionSessionResponse,\n pos: { x: number; y: number } | null,\n submissionAttempt: number,\n ): Promise<void> {\n if (!submission.ai_clarify_available) {\n const element = this.teardownSubmittingUi(true)\n this.showClarify(submission, pos, {\n element,\n preloadedResult: { messages: [], done: true },\n })\n return\n }\n\n // A stream the server accepts but never terminates would leave the card showing\n // its thinking state forever, with no retry and no way to skip. The deadline\n // measures silence rather than total time: a stream still delivering tokens is\n // making progress and is left alone, however long the answer turns out to be.\n const controller = new AbortController()\n let silenceTimer = setTimeout(() => controller.abort(), CLARIFY_SILENCE_TIMEOUT_MS)\n const resetSilenceTimer = () => {\n clearTimeout(silenceTimer)\n silenceTimer = setTimeout(() => controller.abort(), CLARIFY_SILENCE_TIMEOUT_MS)\n }\n const clarifyPromise = this.apiClient.streamClarification(\n submission.id,\n submission.token,\n resetSilenceTimer,\n controller.signal,\n ).catch(() => null).finally(() => clearTimeout(silenceTimer))\n\n const timeoutPromise = new Promise<null>(resolve =>\n setTimeout(() => resolve(null), SPECULATIVE_CLARIFY_TIMEOUT_MS),\n )\n\n const result = await Promise.race([clarifyPromise, timeoutPromise])\n\n if (submissionAttempt !== this.submissionAttempt) return\n\n const element = this.teardownSubmittingUi(true)\n\n if (result) {\n this.showClarify(submission, pos, { element, preloadedResult: result })\n } else {\n this.showClarify(submission, pos, { element, pendingClarification: clarifyPromise })\n }\n }\n\n private teardownSubmittingUi(preservePopup = false): HTMLDivElement | undefined {\n const popupElement = preservePopup ? this.popup?.releaseElement() : undefined\n // The freeze exists to hold the target still under a pin. This is where the\n // session — and with it the pin — goes away, so it is also where the host\n // page gets its scrolling back. Submitting never reaches exitAll, so\n // relying on that alone would strand every reporter who actually sends\n // something on an unscrollable page.\n this.scrollLock.unlock()\n this.teardownDraw()\n if (!popupElement) this.popup?.destroy()\n this.popup = null\n this.dim?.destroy()\n this.dim = null\n this.session?.hideHighlight()\n this.session?.destroy()\n this.session = null\n this.recordingManager?.destroy()\n this.recordingManager = null\n this.submittingUi = null\n return popupElement\n }\n\n private showClarify(\n submission: SubmissionSessionResponse,\n pos: { x: number; y: number } | null,\n speculative?: {\n element?: HTMLDivElement\n preloadedResult?: ClarifyStreamResult\n pendingClarification?: Promise<ClarifyStreamResult | null>\n },\n ): void {\n this.mode = 'clarifying'\n this.tab?.setActive(true)\n this.clarify = new ClarifyCard(this.shadow, {\n submissionSessionId: submission.id,\n submissionToken: submission.token,\n apiClient: this.apiClient,\n messages: this.messages,\n element: speculative?.element,\n position: this.config.position ?? 'right',\n x: pos?.x,\n y: pos?.y,\n onFinalize: () => this.finalizeSubmission(),\n preloadedResult: speculative?.preloadedResult,\n pendingClarification: speculative?.pendingClarification,\n })\n }\n\n private async finalizeSubmission(): Promise<void> {\n const submission = this.activeSubmission\n if (!submission) throw new Error('No active submission session')\n const submissionAttempt = this.submissionAttempt\n\n const feedback = await this.apiClient.finalizeSubmissionSession(submission.id, submission.token)\n if (submissionAttempt !== this.submissionAttempt || this.activeSubmission !== submission) return\n\n this.activeSubmission = null\n this.lastHandoff = {\n feedbackId: feedback.id,\n boardUrl: feedback.board_url,\n identityToken: feedback.identity_token,\n }\n if (feedback.board_url) cacheBoardUrl(feedback.board_url)\n this.clarify?.destroy()\n this.clarify = null\n this.toolbar?.destroy()\n this.toolbar = null\n this.showSuccess({ skipFollowup: submission.ai_clarify_available === false })\n }\n\n private showSuccess(options?: SuccessCardOptions): void {\n this.mode = 'idle'\n this.tab?.setActive(false)\n this.success = new SuccessCard(this.shadow, this.messages, () => {\n this.success?.destroy()\n this.success = null\n }, this.buildViewFeedbackHandler(), { ...options, emailCapture: this.buildEmailCapture() })\n }\n\n private buildEmailCapture(): { onSubmit: (email: string) => Promise<boolean> } | undefined {\n if (this.config.user) return undefined\n const { feedbackId, identityToken } = this.lastHandoff\n if (!feedbackId || !identityToken) return undefined\n if (getStoredReporterEmail()) return undefined\n\n return {\n onSubmit: async (email: string) => {\n const saved = await this.apiClient.updateReporter(feedbackId, email, identityToken)\n if (saved) rememberReporterEmail(email)\n return saved\n },\n }\n }\n\n private buildViewFeedbackHandler(): (() => void) | undefined {\n const { boardUrl, identityToken } = this.lastHandoff\n if (!boardUrl) return undefined\n\n if (identityToken) {\n return () => {\n window.open(`${boardUrl}?identity=${encodeURIComponent(identityToken)}`, '_blank')\n }\n }\n\n if (this.config.userToken || this.config.userTokenFn) {\n return async () => {\n const token = await this.apiClient.resolveUserToken()\n if (token) window.open(`${boardUrl}?identity=${encodeURIComponent(token)}`, '_blank')\n }\n }\n\n return undefined\n }\n\n private exitAll(): void {\n this.submissionAttempt += 1\n const submission = this.activeSubmission\n this.activeSubmission = null\n if (submission) {\n void this.apiClient.abandonSubmissionSession(submission.id, submission.token).catch(() => {})\n }\n this.mode = 'idle'\n this.via = 'pin'\n this.tab?.setActive(false)\n // Before anything else that can throw: leaving the host page unscrollable\n // is the one failure here the user cannot recover from without a reload.\n this.scrollLock.unlock()\n this.teardownDraw()\n this.toolbar?.destroy()\n this.toolbar = null\n this.session?.hideHighlight()\n this.session?.destroy()\n this.session = null\n this.dim?.destroy()\n this.dim = null\n this.popup?.destroy()\n this.popup = null\n this.clarify?.destroy()\n this.clarify = null\n this.currentAnnotation = null\n this.submittingUi = null\n this.recordingManager?.destroy()\n this.recordingManager = null\n }\n\n destroy(): void {\n document.removeEventListener('keydown', this.handleKeydown, true)\n this.exitAll()\n this.consoleCollector.stop()\n this.breadcrumbCollector.stop()\n this.frustrationDetector?.stop()\n this.dismissFrustrationPrompt()\n this.clarify?.destroy()\n this.success?.destroy()\n this.tab?.destroy()\n this.recordingManager?.destroy()\n this.shadow.destroy()\n }\n}\n\nfunction waitForPaint(): Promise<void> {\n return new Promise<void>((r) => requestAnimationFrame(() => setTimeout(r, 0)))\n}\n","import { WidgetController } from './widget/controller'\nimport type { MakeThisBetterConfig } from './types'\n\nlet instance: WidgetController | null = null\nlet lastConfig: MakeThisBetterConfig | null = null\n\nconst MakeThisBetter = {\n init(config: MakeThisBetterConfig): void {\n if (instance) {\n instance.destroy()\n instance = null\n }\n lastConfig = config\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n instance = new WidgetController(config)\n })\n } else {\n instance = new WidgetController(config)\n }\n },\n\n destroy(): void {\n instance?.destroy()\n instance = null\n lastConfig = null\n },\n\n setLocale(locale: string): void {\n if (lastConfig) lastConfig.locale = locale\n instance?.setLocale(locale)\n },\n\n /**\n * Opens annotation mode from the host's own UI. Pair with\n * `entryMode: 'api'` to replace the docked tab entirely, which is the only\n * good answer on a phone where a permanent floating control is in the way.\n */\n open(): void {\n instance?.open()\n },\n\n close(): void {\n instance?.close()\n },\n\n showLauncher(): void {\n instance?.showLauncher()\n },\n\n hideLauncher(): void {\n instance?.hideLauncher()\n },\n}\n\nexport { MakeThisBetter }\nexport type { MakeThisBetterConfig }\n\nif (typeof window !== 'undefined') {\n (window as Window & { MakeThisBetter?: typeof MakeThisBetter }).MakeThisBetter = MakeThisBetter\n\n document.addEventListener('turbo:load', () => {\n const host = document.getElementById('mtb-widget-host')\n if (lastConfig && (!host || !host.shadowRoot)) {\n instance?.destroy()\n host?.remove()\n instance = new WidgetController(lastConfig)\n }\n })\n}\n"],"names":["ShadowContainer","theme","style","cssText","tag","className","el","nodes","n","FeedbackTab","shadow","messages","position","onClick","customText","label","active","FRUSTRATION_DISMISS_MS","FrustrationPromptCard","handlers","DimOverlay","ScrollLock","AnnotationToolbar","onExit","onModeChange","e","rect","inside","m","mode","AnnotationOverlay","pe","pointerId","ElementHighlighter","getElementName","below","UNRENDERED","renderedText","limit","out","node","title","text","placeholder","alt","dataMark","getCssSelector","parts","current","selector","classNames","c","parent","siblings","idx","PinMarker","x","y","pin","BRAND_COLOR","BRAND_RGB","brandAlpha","alpha","FONT_STACK","DRAW_STROKE","DrawLayer","buildPathD","stroke","entry","path","points","s","cx","cy","center","fx","fy","d","i","xs","p","ys","DRAW_MIN_POINTS","AnnotationSession","underEl","getElementUnder","targetName","annotation","WIDGET_HOST_ID","isWidgetElement","host","escapeHtml","KeyboardInset","vp","onChange","SHEET_MAX_WIDTH","isSheetViewport","SheetLayout","px","inset","DrawNoteBar","opts","canUndo","canRedo","loading","message","CommentPopup","quickOpts","o","targetRect","tabPosition","vw","vh","margin","gap","tabWidth","popupW","popupH","minLeft","maxRight","left","top","anchorIsInformative","btn","option","hasText","description","ApiError","status","isTerminalConflict","error","DEFAULT_API_URL","ApiClient","projectKey","apiUrl","retryDelayMs","userToken","userTokenFn","contentType","headers","token","payload","screenshot","submissionToken","generateSubmissionToken","form","json","blob","ext","generateIdempotencyKey","reporterExternalId","feedbackId","email","identityToken","submissionSessionId","body","onDelta","signal","res","consumeSse","url","init","retries","err","delay","ms","resolve","reader","decoder","buffer","result","flush","raw","eventLine","l","dataLine","event","done","value","sep","record","bytes","byte","POLL_INTERVAL_MS","POLL_TIMEOUT_MS","CARD_WIDTH","CARD_HEIGHT","ClarifyCard","existingElement","cardW","cardH","centeredLeft","footer","snapshot","button","last","msg","bubble","dots","SUCCESS_AUTO_CLOSE_MS","EMAIL_PATTERN","SuccessCard","onClose","onViewFeedback","options","viewLink","emailCapture","onSubmit","input","submit","handle","resolveUrl","baseUrl","doc","base","a","uuid","counter","random","toArray","arrayLike","arr","styleProps","getStyleProperties","styleProperty","val","getNodeWidth","leftBorder","rightBorder","getNodeHeight","topBorder","bottomBorder","getImageSize","targetNode","width","height","getPixelRatio","ratio","FINAL_PROCESS","canvasDimensionLimit","checkCanvasDimensions","canvas","createImage","reject","img","svgToDataURL","svg","html","nodeToDataURL","xmlns","foreignObject","isInstanceOfElement","instance","nodePrototype","formatCSSText","content","formatCSSProperties","name","priority","getPseudoElementStyle","pseudo","clonePseudoElement","nativeNode","clonedNode","styleElement","clonePseudoElements","WOFF","JPEG","mimes","getExtension","match","getMimeType","extension","getContentFromDataUrl","dataURL","isDataUrl","makeDataUrl","mimeType","fetchAsDataURL","process","cache","getCacheKey","includeQueryParams","key","resourceToDataURL","resourceUrl","cacheKey","cloneCanvasElement","cloneVideoElement","video","ctx","poster","cloneIFrameElement","iframe","_a","cloneNode","cloneSingleNode","isSVGElement","isSlotElement","cloneChildren","_b","children","deferred","child","clonedChild","cloneCSSStyle","targetStyle","sourceStyle","cloneInputValue","cloneSelectValue","clonedSelect","selectedOption","decorate","ensureSVGSymbols","clone","uses","processedDefs","id","exist","definition","ns","defs","isRoot","URL_REGEX","URL_WITH_FORMAT_REGEX","FONT_SRC_REGEX","toRegex","escaped","parseURLs","urls","quotation","embed","resourceURL","baseURL","getContentFromUrl","resolvedURL","filterPreferredFontFormat","str","preferredFontFormat","src","format","shouldEmbed","embedResources","filteredCSSText","css","embedProp","propName","propValue","cssString","embedBackground","embedImageNode","isImageElement","attributes","image","embedChildren","deferreds","embedImages","applyStyle","manual","cssFetchCache","fetchCSS","embedFonts","data","regexUrl","loadFonts","loc","parseCSS","source","commentsRegex","keyframesRegex","matches","importRegex","combinedCSSRegex","unifiedRegex","getCSSRules","styleSheets","ret","sheet","item","index","importIndex","metadata","rule","inline","getWebFontRules","cssRules","parseWebFontRules","normalizeFontFamily","font","getUsedFonts","fonts","traverse","getWebFontCSS","rules","usedFonts","embedWebFonts","styleNode","sytleContent","toSvg","toCanvas","context","canvasWidth","canvasHeight","toJpeg","MIN_CROP_WIDTH","MIN_CROP_HEIGHT","PADDING_PX","PADDING_RATIO","SKIP_CROP_RATIO","getAnnotationBounds","annotations","minX","minY","maxX","maxY","ann","r","polyline","parsePathPolylines","computeCropRegion","viewportWidth","viewportHeight","bounds","padX","padY","w","h","cropCanvas","cropped","captureScreenshot","captureMetrics","getCaptureMetrics","dataUrl","annotated","bakeAnnotations","dataUrlToBlob","loadImage","scaleX","scaleY","pinIndex","drawStroke","drawPin","cropRect","right","bottom","scaled","canvasToJpegBlob","drawPath","borderWidth","borderHeight","polylines","tokens","header","mime","binary","ErrorSource","listener","line","col","reason","errorSource","MAX_CONSOLE_ERRORS","ConsoleErrorCollector","location","listeners","nativePushState","nativeReplaceState","installedPushState","installedReplaceState","popstateHandler","onHistoryNavigation","install","released","uninstall","notify","pushOrig","replaceOrig","unused","MAX_BREADCRUMBS","BreadcrumbCollector","crumb","target","field","from","to","STORAGE_KEY","memoryState","loadFrustrationState","normalize","saveFrustrationState","state","normalized","isFrustrationDismissed","markFrustrationDismissed","t","u","RAGE_CLICK_THRESHOLD","RAGE_CLICK_WINDOW_MS","RAPID_NAV_THRESHOLD","RAPID_NAV_WINDOW_MS","FORM_CHECK_DELAY_MS","DEAD_CLICK_DOM_DELAY_MS","ERROR_PAGE_CHECK_DELAY_MS","INTERACTIVE_TAGS","INTERACTIVE_ROLES","ERROR_PAGE_PATTERNS","_FrustrationDetector","onFrustration","_e","stored","now","cutoff","describeElement","control","candidates","clickTime","mutated","navigated","cls","lower","role","FrustrationDetector","collectPageContext","detectBrowser","detectOS","ua","buildPayload","pageContext","consoleErrors","user","recording","anonId","anonEmail","breadcrumbs","EMAIL_KEY","BOARD_URL_KEY","memoryId","memoryEmail","memoryBoardUrl","getAnonId","generateAnonId","getStoredReporterEmail","rememberReporterEmail","getCachedBoardUrl","cacheBoardUrl","en","zhCN","ja","ko","es","fr","de","locales","getMessages","locale","lang","MAX_DURATION_S","BLOCK_CLASS","MASK_TEXT_CLASS","RRWEB_CDN","RRWEB_SRI","rrwebLoaded","loadRrweb","loadViaImport","loadViaCdn","findGlobalRecord","win","existing","script","RecordSession","onMaxReached","ripple","RecordControlBar","getDuration","onStop","secs","mm","ss","RecordingManager","SPECULATIVE_CLARIFY_TIMEOUT_MS","CLARIFY_SILENCE_TIMEOUT_MS","isLocalHost","hostname","WidgetController","config","note","action","exchange","ui","submissionAttempt","waitForPaint","submission","pos","element","controller","silenceTimer","resetSilenceTimer","clarifyPromise","timeoutPromise","preservePopup","popupElement","speculative","feedback","saved","boardUrl","lastConfig","MakeThisBetter"],"mappings":"iq1BAGO,MAAMA,EAAgB,CAO3B,YAAYC,EAAuC,OAAQ,CACzD,KAAK,KAAO,SAAS,cAAc,KAAK,EACxC,KAAK,KAAK,GAAK,kBACf,KAAK,KAAK,MAAM,QAAU,oFAC1B,KAAK,KAAK,aAAa,iBAAkBA,CAAK,EAC9C,SAAS,KAAK,YAAY,KAAK,IAAI,EAEnC,KAAK,KAAO,KAAK,KAAK,aAAa,CAAE,KAAM,OAAQ,EAEnD,MAAMC,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,YAAcC,GACpB,KAAK,KAAK,YAAYD,CAAK,CAC7B,CAEA,GAAwCE,EAAaC,EAAuB,CAC1E,MAAMC,EAAK,SAAS,cAAcF,CAAG,EACrC,OAAIC,MAAc,UAAYA,GACvBC,CACT,CAEA,UAAUC,EAAqB,CAC7B,UAAWC,KAAKD,EAAO,KAAK,KAAK,YAAYC,CAAC,CAChD,CAEA,UAAUD,EAAqB,CAC7B,UAAWC,KAAKD,EACVC,EAAE,aAAe,KAAK,MAAM,KAAK,KAAK,YAAYA,CAAC,CAE3D,CAEA,SAAgB,CAId,KAAK,KAAK,OAAA,CACZ,CACF,CC3CO,MAAMC,EAAY,CAQvB,YACEC,EACAC,EACAC,EACAC,EACAC,EACA,CARF,KAAQ,OAAS,GASf,KAAK,QAAUD,EACf,KAAK,WAAaC,EAClB,KAAK,GAAKJ,EAAO,GAAsB,SAAU,SAAS,EACtDE,IAAa,QAAQ,KAAK,GAAG,UAAU,IAAI,MAAM,EACrD,KAAK,UAAYE,GAAcH,EAAS,IACxC,KAAK,YAAcA,EAAS,QAAQ,KACpC,KAAK,SAAS,KAAK,SAAS,EAC5B,KAAK,GAAG,iBAAiB,QAASE,CAAO,EACzCH,EAAO,OAAO,KAAK,EAAE,CACvB,CAEQ,SAASK,EAAqB,CACpC,KAAK,GAAG,YAAcA,EACtB,KAAK,GAAG,aAAa,aAAcA,CAAK,CAC1C,CAEA,YAAYJ,EAA8B,CACxC,KAAK,UAAY,KAAK,YAAcA,EAAS,IAC7C,KAAK,YAAcA,EAAS,QAAQ,KACpC,KAAK,SAAS,KAAK,OAAS,KAAK,YAAc,KAAK,SAAS,CAC/D,CAEA,UAAUK,EAAuB,CAC/B,KAAK,OAASA,EACd,KAAK,GAAG,UAAU,OAAO,SAAUA,CAAM,EACzC,KAAK,SAASA,EAAS,KAAK,YAAc,KAAK,SAAS,CAC1D,CAEA,SAAgB,CACd,KAAK,GAAG,oBAAoB,QAAS,KAAK,OAAO,EACjD,KAAK,GAAG,OAAA,CACV,CACF,CC/CA,MAAMC,GAAyB,IAYxB,MAAMC,EAAsB,CAIjC,YACER,EACAC,EACAQ,EACA,CANF,KAAQ,cAAsD,KAO5D,KAAK,GAAKT,EAAO,GAAmB,MAAO,wBAAwB,EACnE,KAAK,GAAG,UAAY;AAAA;AAAA,2CAEmBC,EAAS,YAAY,MAAM;AAAA;AAAA,+CAEvBA,EAAS,YAAY,MAAM;AAAA,kDACxBA,EAAS,YAAY,OAAO;AAAA;AAAA,MAI1E,KAAK,GAAG,cAAc,uBAAuB,EAAG,iBAAiB,QAASQ,EAAS,MAAM,EACzF,KAAK,GAAG,cAAc,0BAA0B,EAAG,iBAAiB,QAASA,EAAS,SAAS,EAE/FT,EAAO,OAAO,KAAK,EAAE,EACrB,KAAK,cAAgB,WAAWS,EAAS,WAAYF,EAAsB,CAC7E,CAEA,SAAgB,CAGV,KAAK,gBACP,aAAa,KAAK,aAAa,EAC/B,KAAK,cAAgB,MAEvB,KAAK,GAAG,OAAA,CACV,CACF,CC9CO,MAAMG,EAAW,CAItB,YAAYV,EAAyBG,EAAqB,CACxD,KAAK,QAAUA,EACf,KAAK,GAAKH,EAAO,GAAmB,MAAO,2BAA2B,EACtE,KAAK,GAAG,iBAAiB,QAAS,KAAK,OAAO,EAC9CA,EAAO,OAAO,KAAK,EAAE,CACvB,CAEA,SAAgB,CACd,KAAK,GAAG,oBAAoB,QAAS,KAAK,OAAO,EACjD,KAAK,GAAG,OAAA,CACV,CACF,CCFO,MAAMW,EAAW,CAAjB,aAAA,CACL,KAAQ,OAAS,GACjB,KAAQ,aAAe,GACvB,KAAQ,gBAAkB,EAAA,CAIlB,gBAA0B,CAChC,OAAO,OAAO,aAAa,mBAAmB,EAAE,SAAW,EAC7D,CAEA,MAAa,CACP,KAAK,QAAU,CAAC,KAAK,mBACzB,KAAK,OAAS,GACd,KAAK,aAAe,SAAS,KAAK,MAAM,SACxC,KAAK,gBAAkB,SAAS,KAAK,MAAM,YAC3C,SAAS,KAAK,MAAM,SAAW,SAC/B,SAAS,KAAK,MAAM,YAAc,OACpC,CAEA,QAAe,CACR,KAAK,SACV,KAAK,OAAS,GACd,SAAS,KAAK,MAAM,SAAW,KAAK,aACpC,SAAS,KAAK,MAAM,YAAc,KAAK,gBACzC,CAEA,UAAoB,CAClB,OAAO,KAAK,MACd,CACF,CC1CO,MAAMC,EAAkB,CA8B7B,YACEZ,EACAC,EACAY,EACAC,EACA,CAxBF,KAAQ,YAA2B,SASnC,KAAQ,kBAAqBC,GAA0B,CACrD,GAAIA,EAAE,cAAgB,QAAS,OAE/B,MAAMC,EAAO,KAAK,UAAU,sBAAA,EACtBC,EACJF,EAAE,SAAWC,EAAK,MAAQD,EAAE,SAAWC,EAAK,OAASD,EAAE,SAAWC,EAAK,KAAOD,EAAE,SAAWC,EAAK,OAElG,KAAK,UAAU,UAAU,OAAO,8BAA+BC,CAAM,CACvE,EAQE,KAAK,SAAWhB,EAMhB,KAAK,UAAYD,EAAO,GAAmB,MAAO,cAAc,EAChE,KAAK,UAAU,UAAY,kCAAkCC,EAAS,QAAQ,IAAI,UAElF,KAAK,GAAKD,EAAO,GAAmB,MAAO,aAAa,EACxD,KAAK,GAAG,UAAY,KAAK,UAAUC,CAAQ,EAC3CD,EAAO,OAAO,KAAK,UAAW,KAAK,EAAE,EAMrC,KAAK,KAAOA,EAAO,KACnB,KAAK,KAAK,aAAa,mBAAoB,EAAE,EAE7C,KAAK,WAAa,KAAK,UAAU,cAAc,mBAAmB,EAClE,KAAK,UAAY,KAAK,GAAG,cAAc,0BAA0B,EACjE,KAAK,UAAY,KAAK,GAAG,cAAc,0BAA0B,EAEjE,KAAK,UAAU,iBAAiB,QAAS,IAAM,CAC7C,KAAK,QAAQ,QAAQ,EACrBc,IAAe,QAAQ,CACzB,CAAC,EACD,KAAK,UAAU,iBAAiB,QAAS,IAAM,CAC7C,KAAK,QAAQ,QAAQ,EACrBA,IAAe,QAAQ,CACzB,CAAC,EACD,KAAK,GAAG,cAAc,eAAe,EAAG,iBAAiB,QAASD,CAAM,EAExE,SAAS,iBAAiB,cAAe,KAAK,iBAAkC,CAClF,CAEQ,UAAUK,EAAyB,CACzC,MAAO;AAAA;AAAA,0FAE+EA,EAAE,QAAQ,MAAM,YAAYA,EAAE,QAAQ,MAAM;AAAA,2XACqPA,EAAE,QAAQ,MAAM;AAAA;AAAA,mFAExTA,EAAE,QAAQ,MAAM,YAAYA,EAAE,QAAQ,MAAM;AAAA,qPACsHA,EAAE,QAAQ,MAAM;AAAA;AAAA;AAAA;AAAA,iDAIpNA,EAAE,QAAQ,IAAI,YAAYA,EAAE,QAAQ,IAAI;AAAA;AAAA;AAAA,gDAGzCA,EAAE,QAAQ,IAAI;AAAA;AAAA,KAG5D,CAEA,QAAQC,EAAyB,CAC/B,KAAK,YAAcA,EACfA,IAAS,UACX,KAAK,UAAU,UAAU,IAAI,QAAQ,EACrC,KAAK,UAAU,UAAU,OAAO,QAAQ,EACxC,KAAK,WAAW,YAAc,KAAK,SAAS,QAAQ,OAEpD,KAAK,UAAU,UAAU,OAAO,QAAQ,EACxC,KAAK,UAAU,UAAU,IAAI,QAAQ,EACrC,KAAK,WAAW,YAAc,KAAK,SAAS,QAAQ,WAExD,CAEA,SAAuB,CACrB,OAAO,KAAK,WACd,CAEA,SAAgB,CACd,SAAS,oBAAoB,cAAe,KAAK,iBAAkC,EACnF,KAAK,KAAK,gBAAgB,kBAAkB,EAC5C,KAAK,UAAU,OAAA,EACf,KAAK,GAAG,OAAA,CACV,CACF,CCvGO,MAAMC,EAAkB,CAS7B,YAAYpB,EAAyBS,EAA2B,CAC9D,KAAK,SAAWA,EAEhB,KAAK,UAAYT,EAAO,GAAmB,MAAO,aAAa,EAE/D,KAAK,cAAiBe,GAAM,CAC1B,MAAMM,EAAKN,EACX,GAAKM,EAAG,UAGR,IAAI,CACF,KAAK,UAAU,kBAAkBA,EAAG,SAAS,CAC/C,MAAQ,CAGR,CACA,KAAK,SAAS,cAAcA,CAAE,EAChC,EAEA,KAAK,cAAiBN,GAAM,CAC1B,MAAMM,EAAKN,EACNM,EAAG,WACR,KAAK,SAAS,cAAcA,CAAE,CAChC,EAEA,KAAK,YAAeN,GAAM,CACxB,MAAMM,EAAKN,EACNM,EAAG,YACR,KAAK,eAAeA,EAAG,SAAS,EAChC,KAAK,SAAS,YAAYA,CAAE,EAC9B,EAKA,KAAK,gBAAmBN,GAAM,CAC5B,MAAMM,EAAKN,EAINM,EAAG,YACR,KAAK,eAAeA,EAAG,SAAS,EAChC,KAAK,SAAS,gBAAgBA,CAAE,EAClC,EAEA,KAAK,UAAU,iBAAiB,cAAe,KAAK,aAAa,EACjE,KAAK,UAAU,iBAAiB,cAAe,KAAK,aAAa,EACjE,KAAK,UAAU,iBAAiB,YAAa,KAAK,WAAW,EAC7D,KAAK,UAAU,iBAAiB,gBAAiB,KAAK,eAAe,EACrErB,EAAO,OAAO,KAAK,SAAS,EAE5B,KAAK,MAAQA,EAAO,GAAmB,MAAO,SAAS,EACvDA,EAAO,OAAO,KAAK,KAAK,CAC1B,CAEQ,eAAesB,EAAyB,CAC9C,GAAI,CACF,KAAK,UAAU,sBAAsBA,CAAS,CAChD,MAAQ,CAER,CACF,CAEA,SAAgB,CACd,KAAK,UAAU,oBAAoB,cAAe,KAAK,aAAa,EACpE,KAAK,UAAU,oBAAoB,cAAe,KAAK,aAAa,EACpE,KAAK,UAAU,oBAAoB,YAAa,KAAK,WAAW,EAChE,KAAK,UAAU,oBAAoB,gBAAiB,KAAK,eAAe,EACxE,KAAK,UAAU,OAAA,EACf,KAAK,MAAM,OAAA,CACb,CACF,CC/FO,MAAMC,EAAmB,CAI9B,YAAYvB,EAAyB,CACnC,KAAK,YAAcA,EAAO,GAAmB,MAAO,eAAe,EACnE,KAAK,UAAYA,EAAO,GAAmB,MAAO,uBAAuB,EACzE,KAAK,KAAA,EACLA,EAAO,OAAO,KAAK,YAAa,KAAK,SAAS,CAChD,CAEA,UAAUJ,EAAmB,CAC3B,MAAMoB,EAAOpB,EAAG,sBAAA,EAChB,KAAK,YAAY,MAAM,IAAM,GAAGoB,EAAK,IAAM,CAAC,KAC5C,KAAK,YAAY,MAAM,KAAO,GAAGA,EAAK,KAAO,CAAC,KAC9C,KAAK,YAAY,MAAM,MAAQ,GAAGA,EAAK,MAAQ,CAAC,KAChD,KAAK,YAAY,MAAM,OAAS,GAAGA,EAAK,OAAS,CAAC,KAClD,KAAK,YAAY,MAAM,QAAU,QACjC,KAAK,YAAYpB,EAAIoB,CAAI,CAC3B,CAEQ,YAAYpB,EAAaoB,EAAqB,CACpD,KAAK,UAAU,YAAcQ,EAAe5B,CAAE,EAC9C,MAAM6B,EAAQT,EAAK,IAAM,GACzB,KAAK,UAAU,UAAU,OAAO,QAASS,CAAK,EAC9C,KAAK,UAAU,MAAM,KAAO,GAAGT,EAAK,KAAOA,EAAK,MAAQ,CAAC,KACzD,KAAK,UAAU,MAAM,IAAMS,EAAQ,GAAGT,EAAK,OAAS,CAAC,KAAO,GAAGA,EAAK,IAAM,CAAC,KAC3E,KAAK,UAAU,MAAM,QAAU,OACjC,CAEA,QAAe,CACb,KAAK,YAAY,UAAU,IAAI,UAAU,EACzC,KAAK,UAAU,MAAM,QAAU,MACjC,CAEA,MAAa,CACX,KAAK,YAAY,MAAM,QAAU,OACjC,KAAK,YAAY,UAAU,OAAO,UAAU,EAC5C,KAAK,UAAU,MAAM,QAAU,MACjC,CAEA,SAAgB,CACd,KAAK,YAAY,OAAA,EACjB,KAAK,UAAU,OAAA,CACjB,CACF,CAMA,MAAMU,GAAa,sCAEnB,SAASC,GAAa/B,EAAagC,EAAQ,GAAY,CACrD,IAAIC,EAAM,GACV,UAAWC,KAAQ,MAAM,KAAKlC,EAAG,UAAU,EAAG,CAC5C,GAAIiC,EAAI,QAAUD,EAAO,MAErBE,EAAK,WAAa,EACpBD,GAAOC,EAAK,WAAa,GAChBA,aAAgB,SAAW,CAACJ,GAAW,KAAKI,EAAK,OAAO,IACjED,GAAOF,GAAaG,EAAMF,EAAQC,EAAI,MAAM,EAEhD,CACA,OAAOA,CACT,CAEO,SAASL,EAAe5B,EAAqB,CAClD,GAAIA,aAAc,YAAa,CAC7B,MAAMS,EAAQT,EAAG,aAAa,YAAY,EAC1C,GAAIS,EAAO,OAAOA,EAElB,MAAM0B,EAAQnC,EAAG,aAAa,OAAO,EACrC,GAAImC,EAAO,OAAOA,EAElB,MAAMC,EAAOL,GAAa/B,CAAE,EAAE,OAAO,MAAM,EAAG,EAAE,EAChD,GAAIoC,EAAM,OAAOA,EAEjB,MAAMC,EAAerC,EAAwB,YAC7C,GAAIqC,EAAa,OAAOA,EAExB,MAAMC,EAAOtC,EAAwB,IACrC,GAAIsC,EAAK,OAAOA,EAEhB,MAAMC,EAAWvC,EAAG,aAAa,WAAW,EAC5C,GAAIuC,EAAU,OAAOA,CACvB,CACA,OAAOvC,EAAG,QAAQ,YAAA,CACpB,CAEO,SAASwC,GAAexC,EAAqB,CAClD,MAAMyC,EAAkB,CAAA,EACxB,IAAIC,EAA0B1C,EAC9B,KAAO0C,GAAWA,IAAY,SAAS,MAAQD,EAAM,OAAS,GAAG,CAC/D,IAAIE,EAAWD,EAAQ,QAAQ,YAAA,EAC/B,GAAIA,EAAQ,GAAI,CACdC,EAAW,IAAID,EAAQ,EAAE,GACzBD,EAAM,QAAQE,CAAQ,EACtB,KACF,CACA,MAAMC,EAAa,MAAM,KAAKF,EAAQ,SAAS,EAC5C,OAAOG,GAAK,CAACA,EAAE,WAAW,MAAM,CAAC,EACjC,MAAM,EAAG,CAAC,EACV,KAAK,GAAG,EACPD,IAAYD,GAAY,IAAIC,CAAU,IAE1C,MAAME,EAASJ,EAAQ,cACvB,GAAII,EAAQ,CACV,MAAMC,EAAW,MAAM,KAAKD,EAAO,QAAQ,EAAE,OAC3CD,GAAKA,EAAE,UAAYH,EAAS,OAAA,EAE9B,GAAIK,EAAS,OAAS,EAAG,CACvB,MAAMC,EAAMD,EAAS,QAAQL,CAAO,EAAI,EACxCC,GAAY,gBAAgBK,CAAG,GACjC,CACF,CAEAP,EAAM,QAAQE,CAAQ,EACtBD,EAAUA,EAAQ,aACpB,CACA,OAAOD,EAAM,KAAK,KAAK,CACzB,CCzHO,MAAMQ,EAAU,CAIrB,YAAY7C,EAAyB,CAHrC,KAAQ,KAAyB,CAAA,EAI/B,KAAK,OAASA,CAChB,CAEA,OAAO8C,EAAWC,EAAiB,CACjC,MAAMC,EAAM,KAAK,OAAO,GAAmB,MAAO,SAAS,EAC3DA,EAAI,MAAM,IAAM,GAAGD,CAAC,KACpBC,EAAI,MAAM,KAAO,GAAGF,CAAC,KACrB,KAAK,OAAO,OAAOE,CAAG,EACtB,KAAK,KAAK,KAAKA,CAAG,CACpB,CAEA,UAAiB,CACf,UAAWA,KAAO,KAAK,KAAMA,EAAI,OAAA,EACjC,KAAK,KAAO,CAAA,CACd,CAEA,SAAgB,CACd,KAAK,SAAA,CACP,CACF,CC1BO,MAAMC,EAAc,UAGrBC,GAAY,YAEX,SAASC,EAAWC,EAAuB,CAChD,MAAO,QAAQF,EAAS,IAAIE,CAAK,GACnC,CAEO,MAAMC,GAAa,oEAEbC,EAAc,CACzB,MAAOL,EACP,MAAO,MACP,QAAS,QACT,SAAU,QACV,OAAQ,yBAAyBE,EAAW,GAAI,CAAC,GACnD,ECLO,MAAMI,EAAU,CAQrB,YAAYvD,EAAyB,CANrC,KAAQ,YAAqC,KAC7C,KAAQ,cAAyB,CAAA,EACjC,KAAQ,UAAY,GACpB,KAAQ,UAAsB,CAAA,EAC9B,KAAQ,UAA8C,CAAA,EAGpD,KAAK,IAAM,SAAS,gBAAgB,6BAA8B,KAAK,EACvE,KAAK,IAAI,aAAa,QAAS,cAAc,EAC7CA,EAAO,OAAO,KAAK,GAAG,CACxB,CAEA,UAAU8C,EAAWC,EAAiB,CACpC,KAAK,UAAY,GACjB,KAAK,cAAgB,CAAC,CAACD,EAAGC,CAAC,CAAC,EAC5B,KAAK,YAAc,KAAK,WAAA,EACxB,KAAK,IAAI,YAAY,KAAK,WAAW,CACvC,CAEA,aAAaD,EAAWC,EAAiB,CACnC,CAAC,KAAK,WAAa,CAAC,KAAK,cAC7B,KAAK,cAAc,KAAK,CAACD,EAAGC,CAAC,CAAC,EAC9B,KAAK,YAAY,aAAa,IAAKS,GAAW,KAAK,aAAa,CAAC,EACnE,CAIA,cAAwB,CACtB,MAAI,CAAC,KAAK,WAAa,CAAC,KAAK,YAAoB,IACjD,KAAK,UAAY,GACjB,KAAK,UAAU,KAAK,CAAE,KAAM,KAAK,YAAa,EAAGA,GAAW,KAAK,aAAa,EAAG,OAAQ,KAAK,cAAe,EAC7G,KAAK,UAAY,CAAA,EACjB,KAAK,YAAc,KACnB,KAAK,cAAgB,CAAA,EACd,GACT,CAEA,mBAA0B,CACxB,KAAK,aAAa,OAAA,EAClB,KAAK,YAAc,KACnB,KAAK,UAAY,GACjB,KAAK,cAAgB,CAAA,CACvB,CAEA,MAAgB,CACd,MAAMC,EAAS,KAAK,UAAU,IAAA,EAC9B,OAAKA,GACLA,EAAO,KAAK,OAAA,EACZ,KAAK,UAAU,KAAK,CAAE,EAAGA,EAAO,EAAG,OAAQA,EAAO,OAAQ,EACnD,IAHa,EAItB,CAEA,MAAgB,CACd,MAAMC,EAAQ,KAAK,UAAU,IAAA,EAC7B,GAAI,CAACA,EAAO,MAAO,GACnB,MAAMC,EAAO,KAAK,WAAA,EAClB,OAAAA,EAAK,aAAa,IAAKD,EAAM,CAAC,EAC9B,KAAK,IAAI,YAAYC,CAAI,EACzB,KAAK,UAAU,KAAK,CAAE,KAAAA,EAAM,EAAGD,EAAM,EAAG,OAAQA,EAAM,MAAA,CAAQ,EACvD,EACT,CAEA,SAAmB,CACjB,OAAO,KAAK,UAAU,OAAS,CACjC,CAEA,SAAmB,CACjB,OAAO,KAAK,UAAU,OAAS,CACjC,CAEA,YAAsB,CACpB,OAAO,KAAK,UAAU,OAAS,CACjC,CAEA,eAAmC,CACjC,GAAI,KAAK,UAAU,SAAW,EAAG,OAAO,KACxC,MAAME,EAAS,KAAK,UAAU,QAAQC,GAAKA,EAAE,MAAM,EAC7C,CAACC,EAAIC,CAAE,EAAIC,GAAOJ,CAAM,EAC9B,MAAO,CACL,KAAM,OACN,EAAGE,EACH,EAAGC,EACH,SAAU,KAAK,UAAU,OAASF,EAAE,CAAC,EAAE,KAAK,GAAG,CAAA,CAEnD,CAEA,UAAiB,CACf,KAAO,KAAK,IAAI,YAAY,KAAK,IAAI,YAAY,KAAK,IAAI,UAAU,EACpE,KAAK,YAAc,KACnB,KAAK,UAAY,GACjB,KAAK,cAAgB,CAAA,EACrB,KAAK,UAAY,CAAA,EACjB,KAAK,UAAY,CAAA,CACnB,CAEA,oBAA8B,CAC5B,OAAO,KAAK,SACd,CAEA,sBAA+B,CAC7B,OAAO,KAAK,cAAc,MAC5B,CAEA,SAAgB,CACd,KAAK,IAAI,OAAA,CACX,CAEQ,YAA6B,CACnC,MAAMF,EAAO,SAAS,gBAAgB,6BAA8B,MAAM,EAC1E,OAAAA,EAAK,aAAa,OAAQ,MAAM,EAChCA,EAAK,aAAa,SAAUL,EAAY,KAAK,EAC7CK,EAAK,aAAa,eAAgBL,EAAY,KAAK,EACnDK,EAAK,aAAa,iBAAkBL,EAAY,OAAO,EACvDK,EAAK,aAAa,kBAAmBL,EAAY,QAAQ,EACzDK,EAAK,aAAa,QAAS,UAAUL,EAAY,MAAM,EAAE,EAClDK,CACT,CACF,CAEA,SAASH,GAAWI,EAAyB,CAC3C,GAAIA,EAAO,SAAW,EAAG,MAAO,GAChC,KAAM,CAACK,EAAIC,CAAE,EAAIN,EAAO,CAAC,EACzB,IAAIO,EAAI,KAAKF,CAAE,IAAIC,CAAE,GACrB,QAASE,EAAI,EAAGA,EAAIR,EAAO,OAAQQ,IAAK,CACtC,KAAM,CAACtB,EAAGC,CAAC,EAAIa,EAAOQ,CAAC,EACvBD,GAAK,MAAMrB,CAAC,IAAIC,CAAC,EACnB,CACA,OAAOoB,CACT,CAEA,SAASH,GAAOJ,EAAwB,CACtC,MAAMS,EAAKT,EAAO,IAAIU,GAAKA,EAAE,CAAC,CAAC,EACzBC,EAAKX,EAAO,IAAIU,GAAKA,EAAE,CAAC,CAAC,EACzBR,GAAM,KAAK,IAAI,GAAGO,CAAE,EAAI,KAAK,IAAI,GAAGA,CAAE,GAAK,EAC3CN,GAAM,KAAK,IAAI,GAAGQ,CAAE,EAAI,KAAK,IAAI,GAAGA,CAAE,GAAK,EACjD,MAAO,CAACT,EAAIC,CAAE,CAChB,CC9IA,MAAMS,GAAkB,EAOjB,MAAMC,EAAkB,CAU7B,YACEzE,EACQC,EACAQ,EACR,CAFQ,KAAA,SAAAR,EACA,KAAA,SAAAQ,EARV,KAAQ,kBAAoB,GAC5B,KAAQ,sBAAuC,KAC/C,KAAQ,UAAY,EACpB,KAAQ,UAAY,EAOlB,KAAK,YAAc,IAAIc,GAAmBvB,CAAM,EAChD,KAAK,UAAY,IAAI6C,GAAU7C,CAAM,EACrC,KAAK,UAAY,IAAIuD,GAAUvD,CAAM,EACrC,KAAK,QAAU,IAAIoB,GAAkBpB,EAAQ,CAC3C,cAAgBe,GAAM,KAAK,kBAAkBA,CAAC,EAC9C,cAAgBA,GAAM,KAAK,kBAAkBA,CAAC,EAC9C,YAAcA,GAAM,KAAK,gBAAgBA,CAAC,EAI1C,gBAAiB,IAAM,CACjB,KAAK,UAAU,mBAAA,QAA2B,aAAA,EAC9C,KAAK,uBAAA,EACL,KAAK,YAAY,KAAA,CACnB,CAAA,CACD,CACH,CAEQ,kBAAkBA,EAAuB,CAC/CA,EAAE,eAAA,EACF,KAAK,UAAU,UAAUA,EAAE,QAASA,EAAE,OAAO,CAC/C,CAEQ,kBAAkBA,EAAuB,CAC/C,GAAI,KAAK,UAAU,qBAAsB,CACvC,KAAK,uBAAA,EACL,KAAK,UAAU,aAAaA,EAAE,QAASA,EAAE,OAAO,EAChD,KAAK,YAAY,KAAA,EACjB,MACF,CAEA,KAAK,UAAYA,EAAE,QACnB,KAAK,UAAYA,EAAE,QACf,KAAK,wBAA0B,OACnC,KAAK,sBAAwB,sBAAsB,IAAM,CACvD,KAAK,sBAAwB,KAC7B,KAAK,gBAAA,CACP,CAAC,EACH,CAEQ,iBAAwB,CAC9B,GAAI,CAAC,KAAK,mBAAqB,KAAK,UAAU,mBAAA,GAAwB,KAAK,oBAAqB,OAChG,MAAM2D,EAAUC,GAAgB,KAAK,UAAW,KAAK,SAAS,EAC1DD,EAAS,KAAK,YAAY,UAAUA,CAAO,EAC1C,KAAK,YAAY,KAAA,CACxB,CAEQ,wBAA+B,CACjC,KAAK,wBAA0B,OACnC,qBAAqB,KAAK,qBAAqB,EAC/C,KAAK,sBAAwB,KAC/B,CAEQ,gBAAgB3D,EAAuB,CACxC,KAAK,UAAU,sBACpB,KAAK,aAAaA,CAAC,CACrB,CAKQ,aAAaA,EAAwB,CAC3C,GAAI,KAAK,UAAU,qBAAA,GAA0ByD,GAAiB,CAC5D,KAAK,UAAU,aAAA,EACf,KAAK,YAAY,KAAA,EACjB,KAAK,SAAS,aAAA,EACd,MACF,CAGA,GADA,KAAK,UAAU,kBAAA,EACX,KAAK,UAAU,WAAA,GAAgB,CAACzD,EAAG,OAEvC,MAAM2D,EAAUC,GAAgB5D,EAAE,QAASA,EAAE,OAAO,EAC9C6D,EAAaF,EAAUlD,EAAekD,CAAO,EAAI,KAAK,SAAS,WAAW,QAC1E1D,EAAO0D,GAAS,sBAAA,EAChBG,EAAyB,CAC7B,KAAM,MACN,EAAG9D,EAAE,QACL,EAAGA,EAAE,QACL,eAAgB2D,EAAUtC,GAAesC,CAAO,EAAI,OACpD,WAAYA,GAAS,aAAa,KAAA,EAAO,MAAM,EAAG,GAAG,GAAK,GAC1D,WAAAE,EACA,WAAY5D,EAAO,CAAE,IAAKA,EAAK,IAAK,KAAMA,EAAK,KAAM,MAAOA,EAAK,MAAO,OAAQA,EAAK,OAAQ,OAAQA,EAAK,QAAW,MAAA,EAEvH,KAAK,UAAU,OAAOD,EAAE,QAASA,EAAE,OAAO,EAC1C,KAAK,YAAY,OAAA,EACjB,KAAK,SAAS,MAAM8D,EAAYD,CAAU,CAC5C,CAEA,UAAiB,CACf,KAAK,UAAU,KAAA,CACjB,CAEA,UAAiB,CACf,KAAK,UAAU,KAAA,CACjB,CAEA,aAAuB,CACrB,OAAO,KAAK,UAAU,QAAA,CACxB,CAEA,aAAuB,CACrB,OAAO,KAAK,UAAU,QAAA,CACxB,CAEA,gBAA0B,CACxB,OAAO,KAAK,UAAU,WAAA,CACxB,CAEQ,mBAA6B,CACnC,OAAO,KAAK,UAAU,WAAA,GAAgB,KAAK,UAAU,QAAA,CACvD,CAEA,mBAAuC,CACrC,OAAO,KAAK,UAAU,cAAA,CACxB,CAEA,WAAkB,CAChB,KAAK,UAAU,SAAA,CACjB,CAEA,oBAA2B,CACpB,KAAK,oBACV,KAAK,kBAAoB,GACzB,KAAK,uBAAA,EACL,KAAK,QAAQ,QAAA,EACf,CAEA,eAAsB,CACpB,KAAK,YAAY,KAAA,CACnB,CAEA,SAAgB,CACd,KAAK,mBAAA,EACL,KAAK,YAAY,QAAA,EACjB,KAAK,UAAU,QAAA,EACf,KAAK,UAAU,QAAA,CACjB,CACF,CAIA,SAASD,GAAgB7B,EAAWC,EAA2B,CAC7D,OAAO,SAAS,kBAAkBD,EAAGC,CAAC,EAAE,KAAKnD,GAAMA,EAAG,KAAO,iBAAiB,GAAK,IACrF,CC9KA,MAAMkF,GAAiB,kBAEhB,SAASC,EAAgBnF,EAAsB,CACpD,MAAMoF,EAAO,SAAS,eAAeF,EAAc,EACnD,OAAKE,EACEA,IAASpF,GAAMoF,EAAK,SAASpF,CAAE,EADpB,EAEpB,CAEO,SAASqF,EAAWjD,EAAsB,CAC/C,OAAOA,EACJ,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,EACtB,QAAQ,KAAM,QAAQ,CAC3B,CCGO,MAAMkD,EAAc,CAApB,aAAA,CACL,KAAQ,SAA6C,KACrD,KAAQ,QAAU,IAAY,CAC5B,KAAK,WAAW,KAAK,SAAS,CAChC,CAAA,CAEA,SAAkB,CAChB,MAAMC,EAAK,OAAO,eAClB,OAAKA,EACE,KAAK,IAAI,EAAG,KAAK,MAAM,OAAO,aAAeA,EAAG,OAASA,EAAG,UAAU,CAAC,EAD9D,CAElB,CAEA,QAAQC,EAAyC,CAC/C,MAAMD,EAAK,OAAO,eACbA,IACL,KAAK,SAAWC,EAChBD,EAAG,iBAAiB,SAAU,KAAK,OAAO,EAE1CA,EAAG,iBAAiB,SAAU,KAAK,OAAO,EAC5C,CAEA,MAAa,CACX,MAAMA,EAAK,OAAO,eAClB,KAAK,SAAW,KACXA,IACLA,EAAG,oBAAoB,SAAU,KAAK,OAAO,EAC7CA,EAAG,oBAAoB,SAAU,KAAK,OAAO,EAC/C,CACF,CCvCO,MAAME,GAAkB,IAExB,SAASC,IAA2B,CACzC,OAAO,OAAO,YAAcD,EAC9B,CAiBO,MAAME,CAAY,CAGvB,YAAoB3F,EAAiB,CAAjB,KAAA,GAAAA,EAFpB,KAAQ,MAAQ,IAAIsF,EAEkB,CAGtC,OAAiB,CACf,OAAKI,GAAA,GAEL,KAAK,GAAG,MAAM,KAAO,GACrB,KAAK,GAAG,MAAM,IAAM,GACpB,KAAK,GAAG,MAAM,UAAY,GAC1B,KAAK,KAAK,KAAK,MAAM,QAAA,CAAS,EAC9B,KAAK,MAAM,QAASE,GAAO,KAAK,KAAKA,CAAE,CAAC,EACjC,IAPwB,EAQjC,CAEA,SAAgB,CACd,KAAK,MAAM,KAAA,CACb,CAEQ,KAAKC,EAAqB,CAChC,KAAK,GAAG,MAAM,OAASA,EAAQ,EAAI,GAAGA,CAAK,KAAO,EACpD,CACF,CCvCO,MAAMC,EAAY,CAYvB,YAAY1F,EAAyB2F,EAA0B,CAF/D,KAAQ,QAAU,GAGhB,KAAK,SAAWA,EAAK,SACrB,KAAK,YAAcA,EAAK,SAAS,KAAK,OAEtC,KAAK,GAAK3F,EAAO,GAAmB,MAAO,cAAc,EACzD,KAAK,GAAG,UAAY,KAAK,UAAU2F,EAAK,QAAQ,EAChD3F,EAAO,OAAO,KAAK,EAAE,EAGrB,KAAK,MAAQ,IAAIuF,EAAY,KAAK,EAAE,EACpC,KAAK,MAAM,MAAA,EAEX,KAAK,MAAQ,KAAK,GAAG,cAAc,iBAAiB,EACpD,KAAK,QAAU,KAAK,GAAG,cAAc,gBAAgB,EACrD,KAAK,QAAU,KAAK,GAAG,cAAc,gBAAgB,EACrD,KAAK,UAAY,KAAK,GAAG,cAAc,kBAAkB,EACzD,KAAK,QAAU,KAAK,GAAG,cAAc,iBAAiB,EAEtD,KAAK,QAAQ,iBAAiB,QAASI,EAAK,MAAM,EAClD,KAAK,QAAQ,iBAAiB,QAASA,EAAK,MAAM,EAClD,KAAK,GAAG,cAAc,kBAAkB,EAAG,iBAAiB,QAASA,EAAK,QAAQ,EAClF,KAAK,UAAU,iBAAiB,QAAS,IAAM,KAAK,QAAQ,EAC5D,KAAK,MAAM,iBAAiB,UAAY5E,GAAqB,CACvDA,EAAE,aAAeA,EAAE,UAAY,KAC/BA,EAAE,MAAQ,SAAW,CAACA,EAAE,WAC1BA,EAAE,eAAA,EACF,KAAK,OAAA,EAET,CAAC,EAED,KAAK,MAAM,MAAA,CACb,CAEQ,UAAUG,EAAyB,CACzC,MAAO;AAAA,+DACoD+D,EAAW/D,EAAE,KAAK,gBAAgB,CAAC;AAAA,6EACrB+D,EAAW/D,EAAE,KAAK,IAAI,CAAC,iBAAiB+D,EAAW/D,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA,6EAG/D+D,EAAW/D,EAAE,KAAK,IAAI,CAAC,iBAAiB+D,EAAW/D,EAAE,KAAK,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA,sDAItF+D,EAAW/D,EAAE,KAAK,MAAM,CAAC;AAAA,sDACzB+D,EAAW/D,EAAE,KAAK,MAAM,CAAC;AAAA;AAAA,KAG7E,CAEA,YAAY0E,EAAkBC,EAAwB,CACpD,KAAK,QAAQ,SAAW,CAACD,GAAW,KAAK,QACzC,KAAK,QAAQ,SAAW,CAACC,GAAW,KAAK,OAC3C,CAEA,WAAWC,EAAwB,CACjC,KAAK,QAAUA,EACf,KAAK,MAAM,SAAWA,EACtB,KAAK,UAAU,SAAWA,EAC1B,KAAK,QAAQ,SAAWA,GAAW,KAAK,QAAQ,SAChD,KAAK,QAAQ,SAAWA,GAAW,KAAK,QAAQ,SAC5CA,GACF,KAAK,UAAU,UAAU,IAAI,SAAS,EACtC,KAAK,UAAU,UAAY,0FAC3B,KAAK,QAAQ,OAAS,GACtB,KAAK,QAAQ,YAAc,KAE3B,KAAK,UAAU,UAAU,OAAO,SAAS,EACzC,KAAK,UAAU,YAAc,KAAK,YAEtC,CAEA,SAASC,EAAuB,CAC9B,KAAK,QAAQ,YAAcA,EAC3B,KAAK,QAAQ,OAAS,EACxB,CAEQ,QAAe,CACjB,KAAK,SACT,KAAK,SAAS,KAAK,MAAM,MAAM,MAAM,CACvC,CAEA,SAAgB,CACd,KAAK,MAAM,QAAA,EACX,KAAK,GAAG,OAAA,CACV,CACF,CC5FO,MAAMC,EAAa,CAaxB,YAAYhG,EAAyB2F,EAAoB,CAJzD,KAAQ,QAAU,GAElB,KAAQ,oBAAqC,KAG3C,KAAK,SAAWA,EAAK,SACrB,KAAK,QAAUA,EAAK,QACpB,KAAK,YAAcA,EAAK,SAAS,MAAM,OACvC,KAAK,SAAWA,EAAK,SAErB,KAAK,GAAK3F,EAAO,GAAmB,MAAO,WAAW,EACtD,KAAK,GAAG,UAAY,KAAK,UAAU2F,CAAI,EACvC3F,EAAO,OAAO,KAAK,EAAE,EACrB,KAAK,MAAQ,IAAIuF,EAAY,KAAK,EAAE,EAEpC,KAAK,SAAW,KAAK,GAAG,cAAc,eAAe,EACrD,KAAK,UAAY,KAAK,GAAG,cAAc,iBAAiB,EAExD,KAAK,cAAcI,EAAK,EAAGA,EAAK,EAAGA,EAAK,WAAYA,EAAK,UAAY,OAAO,EAC5E,KAAK,WAAWA,EAAK,QAAQ,EACzBA,EAAK,cACP,KAAK,GAAG,cAAc,kBAAkB,EAAG,iBAAiB,QAASA,EAAK,YAAY,EAExF,KAAK,SAAS,MAAA,CAChB,CAEQ,UAAUA,EAA4B,CAC5C,MAAMzE,EAAIyE,EAAK,SACTM,EAAY/E,EAAE,MAAM,aACvB,IACCgF,GAAK;AAAA,uDAC0CjB,EAAWiB,EAAE,KAAK,CAAC;AAAA,iDACzBA,EAAE,KAAK;AAAA,kBACtCjB,EAAWiB,EAAE,KAAK,CAAC;AAAA,kBAAA,EAG9B,KAAK,EAAE,EAEV,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAO6BhF,EAAE,MAAM,KAAK,KAAK+D,EAAWU,EAAK,UAAU,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YASzEM,CAAS;AAAA;AAAA;AAAA,wDAGmChB,EAAW/D,EAAE,MAAM,WAAW,CAAC;AAAA;AAAA;AAAA;AAAA,yDAI9B+D,EAAW/D,EAAE,MAAM,MAAM,CAAC;AAAA,kEACjB+D,EAAW/D,EAAE,MAAM,MAAM,CAAC;AAAA;AAAA,UAElFyE,EAAK,aAAe,iDAAiDV,EAAW/D,EAAE,MAAM,WAAW,CAAC,YAAc,EAAE;AAAA;AAAA,KAG5H,CAIQ,cAAc4B,EAAWC,EAAWoD,EAAoCC,EAAqC,CACnH,GAAI,KAAK,MAAM,QAAS,OAExB,MAAMC,EAAK,OAAO,WACZC,EAAK,OAAO,YACZC,EAAS,GACTC,EAAM,EACNC,EAAW,GACXC,EAAS,KAAK,IAAI,IAAKL,EAAK,EAAIE,EAASE,CAAQ,EACjDE,EAAS,KAAK,GAAG,cAAgB,IACjCC,EAAUL,GAAUH,IAAgB,OAASK,EAAW,GACxDI,EAAWR,EAAKE,GAAUH,IAAgB,QAAUK,EAAW,GAErE,IAAIK,EACAC,EAOJ,MAAMC,GACJb,GAAcA,EAAW,MAAQE,EAAK,IAAOF,EAAW,OAASG,EAAK,GAEpEH,GAAca,IAChBF,EAAOX,EAAW,KAClBY,EAAMZ,EAAW,OAASK,EAEtBO,EAAMJ,EAASL,EAAKC,IACtBQ,EAAMZ,EAAW,IAAMQ,EAASH,GAE9BO,EAAMR,IACRQ,EAAM,KAAK,IAAIZ,EAAW,OAASK,EAAKF,EAAKK,EAASJ,CAAM,KAG9DO,EAAOhE,EAAI,GACXiE,EAAMhE,EAAI,IAGR+D,EAAOJ,EAASG,IAClBC,EAAOD,EAAWH,GAEhBI,EAAOF,IAASE,EAAOF,GACvBG,EAAMR,IAAQQ,EAAMR,GAExB,KAAK,GAAG,MAAM,KAAO,GAAGO,CAAI,KAC5B,KAAK,GAAG,MAAM,IAAM,GAAGC,CAAG,KAC1B,KAAK,GAAG,MAAM,UAAY,GAAGT,EAAKS,EAAMR,CAAM,IAChD,CAEQ,WAAWtG,EAA8B,CAC/C,KAAK,GAAG,cAAc,kBAAkB,EAAG,iBAAiB,QAAS,IAAM,KAAK,SAAS,EACzF,KAAK,GAAG,cAAc,iBAAiB,EAAG,iBAAiB,QAAS,IAAM,KAAK,SAAS,EACxF,KAAK,QAAU,KAAK,GAAG,cAAc,kBAAkB,EAEvD,KAAK,GAAG,iBAAiB,mBAAmB,EAAE,QAAQgH,GAAO,CAC3DA,EAAI,iBAAiB,QAAS,IAAM,CAClC,MAAM5G,EAAS4G,EAAoB,QAAQ,OAAY,GAEvD,GAAI,KAAK,SAAS,MAAM,KAAA,EAAO,SAAW,EAAG,CAC3C,KAAK,SAAS,MAAQ5G,EACtB,KAAK,kBAAA,EACL,KAAK,OAAA,EACL,MACF,CAEA,KAAK,oBAAsBA,EAC3B,KAAK,GAAG,iBAAiB,mBAAmB,EAAE,QAAQ6G,GAAU,CAC9DA,EAAO,UAAU,OAAO,WAAYA,IAAWD,CAAG,CACpD,CAAC,CACH,CAAC,CACH,CAAC,EAED,KAAK,SAAS,iBAAiB,QAAS,IAAM,KAAK,mBAAmB,EAEtE,KAAK,SAAS,iBAAiB,UAAY,GAAqB,CAC1D,EAAE,aAAe,EAAE,UAAY,KAC/B,EAAE,MAAQ,SAAW,CAAC,EAAE,WAC1B,EAAE,eAAA,EACF,KAAK,OAAA,EAET,CAAC,EAED,KAAK,UAAU,iBAAiB,QAAS,IAAM,KAAK,QAAQ,CAC9D,CAEQ,mBAA0B,CAChC,MAAME,EAAU,KAAK,SAAS,MAAM,KAAA,EAAO,OAAS,EACpD,KAAK,UAAU,UAAU,OAAO,QAASA,GAAW,CAAC,KAAK,OAAO,EACjE,KAAK,UAAU,SAAW,CAACA,GAAW,KAAK,QAC3C,KAAK,QAAQ,OAAS,GACtB,KAAK,QAAQ,YAAc,EAC7B,CAEQ,QAAe,CACrB,MAAMnF,EAAO,KAAK,SAAS,MAAM,KAAA,EACjC,GAAI,CAACA,GAAQ,KAAK,QAAS,OAC3B,MAAMoF,EAAc,KAAK,oBAAsB,IAAI,KAAK,mBAAmB,KAAKpF,CAAI,GAAKA,EACzF,KAAK,SAASoF,CAAW,CAC3B,CAEA,WAAWtB,EAAwB,CACjC,KAAK,QAAUA,EACXA,GACF,KAAK,UAAU,UAAU,IAAI,SAAS,EACtC,KAAK,UAAU,UAAY,0FAC3B,KAAK,SAAS,SAAW,KAEzB,KAAK,UAAU,UAAU,OAAO,SAAS,EACzC,KAAK,UAAU,YAAc,KAAK,YAClC,KAAK,SAAS,SAAW,IAE3B,KAAK,kBAAA,CACP,CAEA,SAASC,EAAuB,CAC9B,KAAK,QAAQ,YAAcA,EAC3B,KAAK,QAAQ,OAAS,EACxB,CAEA,gBAAiC,CAI/B,YAAK,MAAM,QAAA,EACJ,KAAK,EACd,CAEA,SAAgB,CACd,KAAK,MAAM,QAAA,EACX,KAAK,GAAG,OAAA,CACV,CACF,CCrNO,MAAMsB,WAAiB,KAAM,CAGlC,YAAYC,EAAgB,CAC1B,MAAM,QAAQA,CAAM,EAAE,EACtB,KAAK,KAAO,WACZ,KAAK,OAASA,CAChB,CACF,CAEO,SAASC,GAAmBC,EAAyB,CAC1D,OAAOA,aAAiBH,IAAYG,EAAM,SAAW,GACvD,CAEA,MAAMC,GAAkB,oCAEjB,MAAMC,EAAU,CAOrB,YAAYC,EAAoBC,EAAiBC,EAAe,IAAMC,EAAoBC,EAAqC,CAC7H,KAAK,WAAaJ,EAClB,KAAK,QAAUC,GAAUH,IAAiB,QAAQ,MAAO,EAAE,EAC3D,KAAK,aAAeI,EACpB,KAAK,UAAYC,EACjB,KAAK,YAAcC,CACrB,CAEA,MAAM,kBAAgD,CACpD,OAAI,KAAK,YAAoB,KAAK,YAAA,EAC3B,KAAK,SACd,CAEA,MAAc,YAAYC,EAAuD,CAC/E,MAAMC,EAAkC,CAAE,gBAAiB,KAAK,UAAA,EAC1DC,EAAQ,MAAM,KAAK,iBAAA,EACzB,OAAIA,IAAOD,EAAQ,cAAc,EAAIC,GACjCF,IAAaC,EAAQ,cAAc,EAAID,GACpCC,CACT,CAEA,MAAc,kBAAkBC,EAAeF,EAAuD,CACpG,MAAMC,EAAU,MAAM,KAAK,YAAYD,CAAW,EAClD,OAAAC,EAAQ,oBAAoB,EAAIC,EACzBD,CACT,CAEA,MAAM,wBAAwBE,EAA0BC,EAA6D,CACnH,MAAMC,EAAkBC,GAAA,EAClBC,EAAO,IAAI,SAwBjB,GAvBAA,EAAK,OAAO,wBAAyBJ,EAAQ,WAAW,EACxDI,EAAK,OAAO,qBAAsBJ,EAAQ,QAAQ,EAClDI,EAAK,OAAO,uBAAwBJ,EAAQ,UAAU,EACtDI,EAAK,OAAO,oBAAqBJ,EAAQ,OAAO,EAChDI,EAAK,OAAO,eAAgBJ,EAAQ,EAAE,EACtCI,EAAK,OAAO,yBAA0B,OAAOJ,EAAQ,YAAY,CAAC,EAClEI,EAAK,OAAO,0BAA2B,OAAOJ,EAAQ,aAAa,CAAC,EACpEI,EAAK,OAAO,2BAA4B,KAAK,UAAUJ,EAAQ,cAAc,CAAC,EAC9EI,EAAK,OAAO,wBAAyB,KAAK,UAAUJ,EAAQ,WAAW,CAAC,EAEpEA,EAAQ,gBACVI,EAAK,OAAO,2BAA4B,KAAK,UAAUJ,EAAQ,cAAc,CAAC,EAE5EA,EAAQ,SAASI,EAAK,OAAO,oBAAqBJ,EAAQ,OAAO,EACjEA,EAAQ,sBAAsBI,EAAK,OAAO,iCAAkCJ,EAAQ,oBAAoB,EACxGA,EAAQ,gBAAgBI,EAAK,OAAO,2BAA4BJ,EAAQ,cAAc,EACtFA,EAAQ,YAAYI,EAAK,OAAO,uBAAwBJ,EAAQ,UAAU,EAC1EA,EAAQ,WAAWI,EAAK,OAAO,sBAAuBJ,EAAQ,SAAS,EAEvEA,EAAQ,aAAeA,EAAQ,YAAY,OAAS,GACtDI,EAAK,OAAO,wBAAyB,KAAK,UAAUJ,EAAQ,WAAW,CAAC,EAGtEA,EAAQ,kBAAoBA,EAAQ,iBAAiB,OAAS,EAAG,CACnE,MAAMK,EAAO,KAAK,UAAUL,EAAQ,gBAAgB,EAC9CM,EAAO,IAAI,KAAK,CAACD,CAAI,EAAG,CAAE,KAAM,mBAAoB,EAC1DD,EAAK,OAAO,sBAAuBE,EAAM,yBAAyB,EAClEF,EAAK,OAAO,+BAAgC,OAAOJ,EAAQ,oBAAsB,CAAC,CAAC,CACrF,CAEA,GAAIC,EAAY,CACd,MAAMM,EAAMN,EAAW,OAAS,aAAe,MAAQ,MACvDG,EAAK,OAAO,uBAAwBH,EAAY,cAAcM,CAAG,EAAE,CACrE,CAEA,MAAMT,EAAU,MAAM,KAAK,YAAA,EAC3B,OAAAA,EAAQ,oBAAoB,EAAII,EAIhCJ,EAAQ,mBAAmB,EAAIU,GAAA,EASxB,CAAE,IAHI,MALD,MAAM,KAAK,eAAe,GAAG,KAAK,MAAM,uCAAwC,CAC1F,OAAQ,OACR,QAAAV,EACA,KAAMM,CAAA,CACP,GACsB,KAAA,GAGN,mBAAoB,MAAOF,CAAA,CAC9C,CAEA,MAAM,oBAAoBO,EAA2F,CACnH,MAAMX,EAAU,MAAM,KAAK,YAAY,kBAAkB,EACzD,GAAI,CAMF,OAAO,MALK,MAAM,KAAK,eAAe,GAAG,KAAK,MAAM,0BAA2B,CAC7E,OAAQ,OACR,QAAAA,EACA,KAAM,KAAK,UAAU,CAAE,qBAAsBW,EAAoB,CAAA,CAClE,GACgB,KAAA,CACnB,MAAQ,CACN,OAAO,IACT,CACF,CAEA,MAAM,eAAeC,EAAoBC,EAAeC,EAAyC,CAC/F,MAAMd,EAAU,MAAM,KAAK,YAAY,kBAAkB,EACzDA,EAAQ,kBAAkB,EAAIc,EAC9B,GAAI,CACF,aAAM,KAAK,eAAe,GAAG,KAAK,MAAM,qBAAqBF,CAAU,YAAa,CAClF,OAAQ,QACR,QAAAZ,EACA,KAAM,KAAK,UAAU,CAAE,SAAU,CAAE,MAAAa,CAAA,EAAS,CAAA,CAC7C,EACM,EACT,MAAQ,CACN,MAAO,EACT,CACF,CAEA,MAAM,mBAAmBE,EAA6Bd,EAAenC,EAA4C,CAC/G,MAAMkD,EAAyC,CAAA,EAC/C,OAAIlD,MAAc,QAAUA,GACrB,KAAK,qBAAqBiD,EAAqBd,EAAOe,CAAI,CACnE,CAEA,MAAM,mBAAmBD,EAA6Bd,EAAyC,CAC7F,OAAO,KAAK,qBAAqBc,EAAqBd,EAAO,CAAE,MAAO,GAAM,CAC9E,CAEA,MAAc,qBACZc,EACAd,EACAe,EAC0B,CAC1B,MAAMhB,EAAU,MAAM,KAAK,kBAAkBC,EAAO,kBAAkB,EAOtE,OADiB,MALL,MAAM,KAAK,eAAe,GAAG,KAAK,MAAM,wCAAwCc,CAAmB,iBAAkB,CAC/H,OAAQ,OACR,QAAAf,EACA,KAAM,KAAK,UAAUgB,CAAI,CAAA,CAC1B,GAC0B,KAAA,GACX,aAClB,CAEA,MAAM,iBAAiBD,EAA6Bd,EAAyC,CAC3F,MAAMD,EAAU,MAAM,KAAK,kBAAkBC,CAAK,EAMlD,OADiB,MAJL,MAAM,KAAK,eAAe,GAAG,KAAK,MAAM,wCAAwCc,CAAmB,iBAAkB,CAC/H,OAAQ,MACR,QAAAf,CAAA,CACD,GAC0B,KAAA,GACX,aAClB,CAKA,MAAM,oBACJe,EACAd,EACAgB,EACAC,EAC8B,CAC9B,MAAMlB,EAAU,MAAM,KAAK,kBAAkBC,EAAO,kBAAkB,EACtED,EAAQ,OAAY,oBAEpB,MAAMmB,EAAM,MAAM,MAAM,GAAG,KAAK,MAAM,wCAAwCJ,CAAmB,iBAAkB,CACjH,OAAQ,OACR,QAAAf,EACA,KAAM,KAAK,UAAU,EAAE,EACvB,OAAAkB,CAAA,CACD,EAEKnB,EAAcoB,EAAI,QAAQ,IAAI,cAAc,GAAK,GACvD,GAAI,CAACA,EAAI,IAAM,CAACA,EAAI,MAAQ,CAACpB,EAAY,SAAS,mBAAmB,EACnE,MAAM,IAAI,MAAM,4BAA4B,EAG9C,OAAOqB,GAAWD,EAAI,KAAMF,CAAO,CACrC,CAEA,MAAM,0BAA0BF,EAA6Bd,EAA0C,CACrG,MAAMD,EAAU,MAAM,KAAK,kBAAkBC,CAAK,EAMlD,OADiB,MAJL,MAAM,KAAK,eAAe,GAAG,KAAK,MAAM,wCAAwCc,CAAmB,YAAa,CAC1H,OAAQ,OACR,QAAAf,CAAA,CACD,GAC0B,KAAA,GACX,QAClB,CAEA,MAAM,yBAAyBe,EAA6Bd,EAA8B,CACxF,MAAMD,EAAU,MAAM,KAAK,kBAAkBC,CAAK,EAClD,MAAM,KAAK,eAAe,GAAG,KAAK,MAAM,wCAAwCc,CAAmB,GAAI,CACrG,OAAQ,SACR,QAAAf,CAAA,CACD,CACH,CAEA,MAAc,eAAeqB,EAAaC,EAAmBC,EAAU,EAAsB,CAC3F,IAAIJ,EACJ,GAAI,CACFA,EAAM,MAAM,MAAME,EAAKC,CAAI,CAC7B,OAASE,EAAK,CACZ,GAAID,EAAU,EACZ,aAAME,GAAM,KAAK,YAAY,EACtB,KAAK,eAAeJ,EAAKC,EAAMC,EAAU,CAAC,EAEnD,MAAMC,CACR,CAEA,GAAIL,EAAI,GAAI,OAAOA,EACnB,GAAIA,EAAI,QAAU,KAAOI,EAAU,EACjC,aAAME,GAAM,KAAK,YAAY,EACtB,KAAK,eAAeJ,EAAKC,EAAMC,EAAU,CAAC,EAEnD,MAAM,IAAInC,GAAS+B,EAAI,MAAM,CAC/B,CACF,CAEA,SAASM,GAAMC,EAA2B,CACxC,OAAIA,GAAM,EAAU,QAAQ,QAAA,EACrB,IAAI,QAAQC,GAAW,WAAWA,EAASD,CAAE,CAAC,CACvD,CAEA,eAAeN,GACbJ,EACAC,EAC8B,CAC9B,MAAMW,EAASZ,EAAK,UAAA,EACda,EAAU,IAAI,YACpB,IAAIC,EAAS,GACTC,EAAqC,KAEzC,MAAMC,EAASC,GAAsB,CAEnC,MAAMC,EAAYD,EAAI,MAAM;AAAA,CAAI,EAAE,KAAKE,GAAKA,EAAE,WAAW,QAAQ,CAAC,EAC5DC,EAAWH,EAAI,MAAM;AAAA,CAAI,EAAE,KAAKE,GAAKA,EAAE,WAAW,OAAO,CAAC,EAChE,GAAI,CAACC,EAAU,OACf,MAAMC,EAAQH,GAAW,MAAM,CAAC,EAAE,KAAA,EAC5BhC,EAAU,KAAK,MAAMkC,EAAS,MAAM,CAAC,EAAE,MAAM,EAC/CC,IAAU,SAAW,OAAOnC,EAAQ,MAAS,SAC/Ce,EAAQf,EAAQ,IAAI,EACXmC,IAAU,SACnBN,EAAS,CACP,SAAU,MAAM,QAAQ7B,EAAQ,QAAQ,EAAIA,EAAQ,SAAW,CAAA,EAC/D,KAAMA,EAAQ,OAAS,GACvB,OAAQA,EAAQ,QAAU,EAAA,EAGhC,EAEA,OAAS,CACP,KAAM,CAAE,KAAAoC,EAAM,MAAAC,CAAA,EAAU,MAAMX,EAAO,KAAA,EACrC,GAAIU,EAAM,MACVR,GAAUD,EAAQ,OAAOU,EAAO,CAAE,OAAQ,GAAM,EAChD,IAAIC,EACJ,MAAQA,EAAMV,EAAO,QAAQ;AAAA;AAAA,CAAM,KAAO,IAAI,CAC5C,MAAMW,EAASX,EAAO,MAAM,EAAGU,CAAG,EAClCV,EAASA,EAAO,MAAMU,EAAM,CAAC,EAC7B,GAAI,CAAER,EAAMS,CAAM,CAAE,MAAQ,CAA8B,CAC5D,CACF,CAGA,GADAX,GAAUD,EAAQ,OAAA,EACdC,EAAO,OACT,GAAI,CAAEE,EAAMF,CAAM,CAAE,MAAQ,CAAgD,CAE9E,GAAI,CAACC,EAAQ,MAAM,IAAI,MAAM,kCAAkC,EAE/D,OAAOA,CACT,CAEA,SAASrB,IAAiC,CACxC,OAAI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WACzD,OAAO,WAAA,EAET,GAAG,KAAK,IAAA,EAAM,SAAS,EAAE,CAAC,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,CAAC,EAC9E,CAEA,SAASL,IAAkC,CACzC,GAAI,OAAO,OAAW,KAAe,OAAO,OAAO,iBAAoB,WACrE,MAAM,IAAI,MAAM,yCAAyC,EAG3D,MAAMqC,EAAQ,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC,EACvD,OAAO,MAAM,KAAKA,EAAOC,GAAQA,EAAK,SAAS,EAAE,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,KAAK,EAAE,CAC9E,CCvTA,MAAMC,GAAmB,IAMnBC,GAAkB,KAgBlBC,GAAa,IACbC,GAAc,IAEb,MAAMC,EAAY,CAwBvB,YAAYjL,EAAyB2F,EAA0B,CAlB/D,KAAQ,UAAmD,KAC3D,KAAQ,aAAe,EACvB,KAAQ,gBAAyC,KAMjD,KAAQ,aAAiC,CAAA,EACzC,KAAQ,KAAO,GACf,KAAQ,QAAU,GAClB,KAAQ,WAAa,GACrB,KAAQ,UAAY,GACpB,KAAQ,cAAgB,GAMtB,KAAK,oBAAsBA,EAAK,oBAChC,KAAK,gBAAkBA,EAAK,gBAC5B,KAAK,UAAYA,EAAK,UACtB,KAAK,WAAaA,EAAK,WACvB,KAAK,KAAOA,EAAK,SACjB,KAAK,gBAAkBA,EAAK,gBAC5B,KAAK,qBAAuBA,EAAK,qBAEjC,MAAMuF,EAAkBvF,EAAK,QAC7B,KAAK,GAAKuF,GAAmBlL,EAAO,GAAmB,MAAO,aAAa,EAC3E,KAAK,GAAG,UAAYkL,EAAkB,uCAAyC,cAC/E,KAAK,GAAG,UAAY,KAAK,UAAUvF,EAAK,QAAQ,EAChD,KAAK,MAAQ,IAAIJ,EAAY,KAAK,EAAE,EAC/B2F,EAUH,KAAK,MAAM,MAAA,GATXlL,EAAO,OAAO,KAAK,EAAE,EACrB,KAAK,aAAa2F,EAAK,EAAGA,EAAK,EAAGA,EAAK,UAAY,OAAO,GAW5D,KAAK,WAAa,KAAK,GAAG,cAAc,uBAAuB,EAC/D,KAAK,WAAA,EACL,KAAK,kBAAA,CACP,CAIQ,aAAa7C,EAAuBC,EAAuBqD,EAAqC,CACtG,GAAI,KAAK,MAAM,QAAS,OAExB,MAAMC,EAAK,OAAO,WACZC,EAAK,OAAO,YACZC,EAAS,GACTE,EAAW,GACX0E,EAAQ,KAAK,IAAIJ,GAAY1E,EAAK,EAAIE,EAASE,CAAQ,EACvD2E,EAAQ,KAAK,GAAG,cAAgBJ,GAChCpE,EAAUL,GAAUH,IAAgB,OAASK,EAAW,GACxDI,EAAWR,EAAKE,GAAUH,IAAgB,QAAUK,EAAW,GAErE,GAAI3D,IAAM,QAAaC,IAAM,OAAW,CACtC,MAAMsI,EAAe,KAAK,IAAIzE,GAAUP,EAAK8E,GAAS,CAAC,EACvD,KAAK,GAAG,MAAM,KAAO,GAAG,KAAK,IAAIE,EAAcxE,EAAWsE,CAAK,CAAC,KAChE,KAAK,GAAG,MAAM,IAAM,GAAG,KAAK,IAAI5E,GAASD,EAAK8E,GAAS,CAAC,CAAC,KACzD,KAAK,GAAG,MAAM,UAAY,GAAG9E,EAAK,EAAIC,CAAM,KAC5C,MACF,CAEA,IAAIO,EAAOhE,EAAI,GACXiE,EAAMhE,EAAI,GACV+D,EAAOqE,EAAQtE,IAAUC,EAAOhE,EAAIqI,EAAQ,IAC5CrE,EAAOqE,EAAQtE,IAAUC,EAAOD,EAAWsE,GAC3CrE,EAAOF,IAASE,EAAOF,GACvBG,EAAMqE,EAAQ9E,EAAKC,IAAQQ,EAAMT,EAAK8E,EAAQ7E,GAC9CQ,EAAMR,IAAQQ,EAAMR,GAExB,KAAK,GAAG,MAAM,KAAO,GAAGO,CAAI,KAC5B,KAAK,GAAG,MAAM,IAAM,GAAGC,CAAG,KAC1B,KAAK,GAAG,MAAM,UAAY,GAAGT,EAAKS,EAAMR,CAAM,IAChD,CAEQ,UAAUrF,EAAyB,CACzC,MAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2CAQgC+D,EAAW/D,EAAE,QAAQ,KAAK,CAAC;AAAA,8CACxB+D,EAAW/D,EAAE,QAAQ,QAAQ,CAAC;AAAA;AAAA,iEAEX+D,EAAW/D,EAAE,QAAQ,IAAI,CAAC,iBAAiB+D,EAAW/D,EAAE,QAAQ,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAO9F,KAAK,0BAA0BA,CAAC,CAAC;AAAA,KAEvE,CAEQ,0BAA0BA,EAAyB,CACzD,MAAO;AAAA,kEACuD+D,EAAW/D,EAAE,QAAQ,WAAW,CAAC;AAAA;AAAA,yDAE1C+D,EAAW/D,EAAE,QAAQ,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAMjE+D,EAAW/D,EAAE,QAAQ,IAAI,CAAC;AAAA;AAAA;AAAA,KAI1C,CAEQ,YAAmB,CACzB,KAAK,GAAG,cAAc,oBAAoB,EAAG,iBAAiB,QAAS,IAAM,KAAK,iBAAiB,EACnG,KAAK,yBAAA,CACP,CAEQ,0BAAiC,CACvC,KAAK,QAAU,KAAK,GAAG,cAAc,oBAAoB,EACzD,KAAK,QAAU,KAAK,GAAG,cAAc,mBAAmB,EACxD,KAAK,GAAG,cAAc,mBAAmB,EAAG,iBAAiB,QAAS,IAAM,KAAK,iBAAiB,EAElG,KAAK,QAAQ,iBAAiB,QAAS,IAAM,CAC3C,KAAK,QAAQ,SAAW,CAAC,KAAK,QAAQ,MAAM,KAAA,CAC9C,CAAC,EAED,KAAK,QAAQ,iBAAiB,UAAYH,GAAqB,CACzDA,EAAE,aAAeA,EAAE,UAAY,KAC/BA,EAAE,MAAQ,SAAW,CAACA,EAAE,WAC1BA,EAAE,eAAA,EACF,KAAK,YAAA,EAET,CAAC,EAED,KAAK,QAAQ,iBAAiB,QAAS,IAAM,KAAK,aAAa,CACjE,CAEQ,iBAAwB,CAC9B,KAAK,YAAA,EACA,KAAK,SAAA,CACZ,CAEA,MAAc,mBAAmC,CAC/C,GAAI,KAAK,gBAAiB,CACxB,KAAK,YAAY,KAAK,eAAe,EACrC,MACF,CAEA,GAAI,KAAK,qBAAsB,CAC7B,KAAK,aAAA,EACL,GAAI,CACF,MAAMiJ,EAAS,MAAM,KAAK,qBAC1B,GAAI,KAAK,UAAW,OAChBA,EACG,KAAK,YAAYA,CAAM,QAAQ,aAAA,EAEpC,MAAM,KAAK,yBAAA,CAEf,MAAQ,CACN,GAAI,KAAK,UAAW,OACpB,MAAM,KAAK,yBAAA,CACb,CACA,MACF,CAEA,KAAK,aAAA,EACL,MAAM,KAAK,eAAA,CACb,CAEA,MAAc,aAA6B,CACzC,MAAMhI,EAAO,KAAK,QAAQ,MAAM,KAAA,EAChC,GAAI,GAACA,GAAQ,KAAK,SAElB,MAAK,QAAU,GACf,KAAK,QAAQ,SAAW,GACxB,KAAK,QAAQ,SAAW,GACxB,KAAK,YAAA,EAEL,KAAK,cAAc,CAAE,KAAM,OAAQ,QAASA,EAAM,EAClD,KAAK,QAAQ,MAAQ,GACrB,KAAK,aAAA,EACL,KAAK,WAAA,EAEL,GAAI,CACF,MAAM,KAAK,cAAcA,CAAI,CAC/B,MAAQ,CACN,GAAI,KAAK,UAAW,OACpB,KAAK,mBAAmB,KAAK,aAAc,EAAK,EAChD,KAAK,QAAQ,MAAQA,EACrB,KAAK,UAAA,CACP,QAAA,CACE,KAAK,QAAU,GACf,KAAK,QAAQ,SAAW,GACxB,KAAK,QAAQ,SAAW,CAAC,KAAK,QAAQ,MAAM,KAAA,EAC5C,KAAK,QAAQ,MAAA,CACf,EACF,CAIA,MAAc,gBAAgC,CAC5C,GAAI,CACF,MAAMgI,EAAS,MAAM,KAAK,UAAU,oBAClC,KAAK,oBACL,KAAK,gBACJhI,GAAS,KAAK,kBAAkBA,CAAI,CAAA,EAEvC,GAAI,KAAK,UAAW,OACpB,KAAK,mBAAA,EACA,KAAK,YAAYgI,CAAM,QAAQ,aAAA,CACtC,MAAQ,CACN,GAAI,KAAK,UAAW,OACpB,KAAK,mBAAA,EACL,MAAM,KAAK,yBAAA,CACb,CACF,CAEA,MAAc,0BAA0C,CACtD,GAAI,CACF,MAAMZ,EAAM,MAAM,KAAK,UAAU,mBAC/B,KAAK,oBACL,KAAK,eAAA,EAEP,GAAI,KAAK,UAAW,OACf,KAAK,YAAYA,CAAG,QAAQ,aAAA,CACnC,MAAQ,CACN,GAAI,KAAK,UAAW,OACpB,KAAK,cAAA,CACP,CACF,CAEA,MAAc,cAAcrD,EAAgC,CAC1D,MAAMqD,EAAM,MAAM,KAAK,UAAU,mBAC/B,KAAK,oBACL,KAAK,gBACLrD,CAAA,EAEE,KAAK,WACJ,KAAK,YAAYqD,CAAG,QAAQ,aAAA,CACnC,CAEQ,WAAkB,CACxB,MAAMkC,EAAS,KAAK,GAAG,cAAc,qBAAqB,EACpD9D,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,oBAClBA,EAAM,YAAc,KAAK,KAAK,MAAM,OACpC8D,EAAO,QAAQ9D,CAAK,CACtB,CAEQ,YAAmB,CACzB,KAAK,GAAG,cAAc,oBAAoB,GAAG,OAAA,CAC/C,CAEQ,kBAAkBxF,EAAoB,CACvC,KAAK,kBACR,KAAK,eAAA,EACL,KAAK,gBAAkB,SAAS,cAAc,KAAK,EACnD,KAAK,gBAAgB,UAAY,oCACjC,KAAK,WAAW,YAAY,KAAK,eAAe,GAElD,KAAK,gBAAgB,aAAe,KAAK,gBAAgB,aAAe,IAAMA,EAC9E,KAAK,WAAW,UAAY,KAAK,WAAW,YAC9C,CAEQ,oBAA2B,CACjC,KAAK,gBAAkB,IACzB,CAEQ,cAAqB,CAC3B,KAAK,YAAA,EACL,KAAK,aAAe,KAAK,IAAA,EAAQ8I,GACjC,KAAK,UAAY,YAAY,IAAM,KAAK,KAAA,EAAQD,EAAgB,CAClE,CAEQ,aAAoB,CACtB,KAAK,YAAc,OACrB,cAAc,KAAK,SAAS,EAC5B,KAAK,UAAY,KAErB,CAEA,MAAc,MAAsB,CAClC,GAAI,KAAK,MAAQ,KAAK,aAAc,CAClC,KAAK,YAAA,EACL,KAAK,cAAA,EACL,MACF,CACA,GAAI,CACF,MAAMzB,EAAM,MAAM,KAAK,UAAU,iBAC/B,KAAK,oBACL,KAAK,eAAA,EAEP,GAAI,KAAK,UAAW,OAChB,KAAK,YAAYA,CAAG,QAAQ,YAAA,CAClC,MAAQ,CACN,GAAI,KAAK,UAAW,OACpB,KAAK,YAAA,EACL,KAAK,cAAA,CACP,CACF,CAEQ,YAAmB,CACrB,KAAK,OACT,KAAK,KAAO,GACZ,KAAK,YAAA,EACL,KAAK,eAAA,EACL,KAAK,mBAAA,EACP,CAEQ,eAAsB,CACxB,KAAK,OACT,KAAK,KAAO,GACZ,KAAK,YAAA,EACL,KAAK,eAAA,EACL,KAAK,gCAAA,EACP,CAEQ,iCAAwC,CAC9C,MAAMkC,EAAS,KAAK,GAAG,cAAc,qBAAqB,EAC1DA,EAAO,UAAY;AAAA,uCACgBrG,EAAW,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA;AAAA,6DAEbA,EAAW,KAAK,KAAK,QAAQ,aAAa,CAAC;AAAA,0DAC9CA,EAAW,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA;AAAA,MAGzFqG,EAAO,cAAc,uBAAuB,EAAG,iBAAiB,QAAS,IAAM,KAAK,iBAAiB,EACrGA,EAAO,cAAc,oBAAoB,EAAG,iBAAiB,QAAS,IAAM,CACrE,KAAK,WAAgB,KAAK,mBAAA,CACjC,CAAC,CACH,CAEA,MAAc,oBAAoC,CAChD,GAAI,OAAK,SAAW,KAAK,WAEzB,MAAK,QAAU,GACf,KAAK,KAAO,GACZ,KAAK,yBAAA,EACL,KAAK,QAAQ,SAAW,GACxB,KAAK,QAAQ,SAAW,GACxB,KAAK,mBAAmB,KAAK,aAAc,EAAK,EAEhD,GAAI,CACF,MAAMC,EAAW,MAAM,KAAK,UAAU,iBAAiB,KAAK,oBAAqB,KAAK,eAAe,EACrG,GAAI,KAAK,UAAW,OACpB,IAAIvB,EAASuB,EAYb,GALIA,EAAS,SAAW,SACtBvB,EAAS,MAAM,KAAK,UAAU,mBAAmB,KAAK,oBAAqB,KAAK,eAAe,EACtFuB,EAAS,SAAW,SAC7BvB,EAAS,MAAM,KAAK,UAAU,mBAAmB,KAAK,oBAAqB,KAAK,eAAe,GAE7F,KAAK,UAAW,OACf,KAAK,YAAYA,CAAM,IAC1B,KAAK,yBAAA,EACL,KAAK,aAAA,EAET,MAAQ,CACN,GAAI,KAAK,UAAW,OACpB,KAAK,cAAA,CACP,QAAA,CACE,KAAK,QAAU,EACjB,EACF,CAEQ,0BAAiC,CACvC,MAAMsB,EAAS,KAAK,GAAG,cAAc,qBAAqB,EAC1DA,EAAO,UAAY,KAAK,0BAA0B,KAAK,IAAI,EAC3D,KAAK,yBAAA,CACP,CAIQ,YAAYtB,EAAwD,CAC1E,KAAK,mBAAmBA,EAAO,SAAUA,EAAO,IAAI,EACpD,MAAM1C,EAAS,WAAY0C,EAASA,EAAO,OAAS,OAEpD,OADe,WAAYA,EAASA,EAAO,SAAW,SAAWA,EAAO,SAAW,KAEjF,KAAK,cAAA,EACE,IAELA,EAAO,MACT,KAAK,WAAA,EACE,IAEL1C,IAAW,qBAGb,KAAK,YAAA,EACL,KAAK,eAAA,EACL,KAAK,YAAA,EACE,IAEF,EACT,CAEQ,aAAoB,CACrB,KAAK,GAAG,SAAS,KAAK,OAAO,QAAQ,yBAAA,EAC1C,KAAK,QAAQ,SAAW,GACxB,KAAK,QAAQ,SAAW,CAAC,KAAK,QAAQ,MAAM,KAAA,CAC9C,CAEQ,oBAA2B,CACjC,MAAMgE,EAAS,KAAK,GAAG,cAAc,qBAAqB,EAC1DA,EAAO,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAMPrG,EAAW,KAAK,KAAK,QAAQ,aAAa,CAAC;AAAA;AAAA,MAGvDqG,EAAO,cAAc,4BAA4B,EAAG,iBAAiB,QAAS,IAAM,CAC7E,KAAK,WAAgB,KAAK,SAAA,CACjC,CAAC,CACH,CAEA,MAAc,UAA0B,CACtC,GAAI,OAAK,YAAc,KAAK,WAAa,KAAK,eAE9C,MAAK,WAAa,GAClB,KAAK,GAAG,iBAAoC,QAAQ,EAAE,QAAQE,GAAU,CAAEA,EAAO,SAAW,EAAK,CAAC,EAClG,GAAI,CACF,MAAM,KAAK,WAAA,CACb,OAAShE,EAAO,CACd,GAAI,KAAK,UAAW,OAOpB,GANA,KAAK,WAAa,GAClB,KAAK,WAAA,EAKDD,GAAmBC,CAAK,EAAG,CAC7B,KAAK,kBAAA,EACL,MACF,CACA,KAAK,kBAAA,CACP,EACF,CAEQ,mBAA0B,CAChC,KAAK,cAAgB,GACrB,KAAK,YAAA,EACL,MAAM8D,EAAS,KAAK,GAAG,cAAc,qBAAqB,EAC1DA,EAAO,UAAY,kCAAkCrG,EAAW,KAAK,KAAK,QAAQ,OAAO,CAAC,QAC5F,CAKQ,mBAA0B,CAChC,MAAMqG,EAAS,KAAK,GAAG,cAAc,qBAAqB,EAC1DA,EAAO,UAAY;AAAA,uCACgBrG,EAAW,KAAK,KAAK,MAAM,MAAM,CAAC;AAAA,kFACSA,EAAW,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,MAEjHqG,EAAO,cAAc,oBAAoB,EAAG,iBAAiB,QAAS,IAAM,CACrE,KAAK,WAAgB,KAAK,SAAA,CACjC,CAAC,CACH,CAEQ,mBAAmBrL,EAA4BsK,EAAqB,CAC1E,KAAK,aAAetK,EACpB,KAAK,eAAeA,CAAQ,EAC5B,MAAMwL,EAAOxL,EAASA,EAAS,OAAS,CAAC,EACrC,CAACsK,IAAS,CAACkB,GAAQA,EAAK,OAAS,cAAc,aAAA,CACrD,CAEQ,eAAexL,EAAkC,CACvD,KAAK,WAAW,UAAY,GAC5B,UAAWyL,KAAOzL,EAChB,KAAK,cAAcyL,CAAG,EAExB,KAAK,WAAW,UAAY,KAAK,WAAW,YAC9C,CAEQ,cAAcA,EAA2B,CAC/C,MAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,UAAYD,EAAI,OAAS,OAAS,sCAAwC,oCACjFC,EAAO,YAAcD,EAAI,QACzB,KAAK,WAAW,YAAYC,CAAM,EAClC,KAAK,WAAW,UAAY,KAAK,WAAW,YAC9C,CAEQ,cAAqB,CAC3B,GAAI,KAAK,WAAW,cAAc,uBAAuB,EAAG,OAC5D,MAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,UAAY,yDACjBA,EAAK,UAAY,0FACjB,KAAK,WAAW,YAAYA,CAAI,EAChC,KAAK,WAAW,UAAY,KAAK,WAAW,YAC9C,CAEQ,gBAAuB,CAC7B,KAAK,WAAW,cAAc,uBAAuB,GAAG,OAAA,CAC1D,CAEA,SAAgB,CACd,KAAK,UAAY,GACjB,KAAK,YAAA,EACL,KAAK,MAAM,QAAA,EACX,KAAK,GAAG,OAAA,CACV,CACF,CC5iBA,MAAMC,GAAwB,IACxBC,GAAgB,6BASf,MAAMC,EAAY,CAIvB,YAAY/L,EAAyBC,EAAwB+L,EAAqBC,EAA6BC,EAA8B,CAC3I,KAAK,SAAWjM,EAChB,KAAK,GAAKD,EAAO,GAAmB,MAAO,aAAa,EACxD,KAAK,GAAG,MAAM,MAAQ,OACtB,KAAK,GAAG,MAAM,OAAS,OAEvB,MAAM+B,EAAQmK,GAAS,aAAejM,EAAS,QAAQ,YAAcA,EAAS,QAAQ,MAChFyL,EAAMQ,GAAS,aAAejM,EAAS,QAAQ,cAAgBA,EAAS,QAAQ,QAEhFkM,EAAWF,EACb,0CAA0ChM,EAAS,QAAQ,aAAa,sMACxE,GAEEmM,EAAeF,GAAS,aAC1B;AAAA;AAAA,wCAEgCjM,EAAS,QAAQ,YAAY;AAAA;AAAA,qEAEAA,EAAS,QAAQ,iBAAiB;AAAA,6CAC1DA,EAAS,QAAQ,YAAY;AAAA;AAAA,8CAE5BA,EAAS,QAAQ,WAAW;AAAA,cAElE,GAEJ,KAAK,GAAG,UAAY;AAAA;AAAA,8EAEsDgD,CAAW;AAAA;AAAA;AAAA;AAAA,uCAIlDlB,CAAK;AAAA,qCACP2J,CAAG;AAAA,QAChCU,CAAY;AAAA,QACZD,CAAQ;AAAA,uCACuBlM,EAAS,QAAQ,KAAK;AAAA,MAEzDD,EAAO,OAAO,KAAK,EAAE,EACrB,KAAK,GAAG,cAAc,iBAAiB,EAAG,iBAAiB,QAASgM,CAAO,EAEvEC,GACF,KAAK,GAAG,cAAc,yBAAyB,EAAG,iBAAiB,QAASA,CAAc,EAGxFC,GAAS,aACX,KAAK,iBAAiBA,EAAQ,aAAa,QAAQ,EAEnD,WAAW,IAAMF,EAAA,EAAWH,EAAqB,CAErD,CAEQ,iBAAiBQ,EAAqD,CAC5E,MAAMC,EAAQ,KAAK,GAAG,cAAgC,kBAAkB,EAClEC,EAAS,KAAK,GAAG,cAAiC,mBAAmB,EACrE/E,EAAQ,KAAK,GAAG,cAA8B,kBAAkB,EAEhEgF,EAAS,SAAY,CACzB,MAAM1D,EAAQwD,EAAM,MAAM,KAAA,EAC1B,GAAI,CAACR,GAAc,KAAKhD,CAAK,EAAG,CAC9BwD,EAAM,UAAU,IAAI,mBAAmB,EACvC,MACF,CACAA,EAAM,UAAU,OAAO,mBAAmB,EAC1C9E,EAAM,OAAS,GACf+E,EAAO,SAAW,GAEJ,MAAMF,EAASvD,CAAK,EAEhC,KAAK,GAAG,cAAc,oBAAoB,EAAG,UAC3C,gCAAgC,KAAK,SAAS,QAAQ,WAAW,UAEnEtB,EAAM,OAAS,GACf+E,EAAO,SAAW,GAEtB,EAEAA,EAAO,iBAAiB,QAASC,CAAM,EACvCF,EAAM,iBAAiB,UAAYhC,GAAU,CACvCA,EAAM,MAAQ,SAASkC,EAAA,CAC7B,CAAC,CACH,CAEA,SAAgB,CACd,KAAK,GAAG,OAAA,CACV,CACF,CCvGO,SAASC,GAAWnD,EAAKoD,EAAS,CAErC,GAAIpD,EAAI,MAAM,eAAe,EACzB,OAAOA,EAGX,GAAIA,EAAI,MAAM,OAAO,EACjB,OAAO,OAAO,SAAS,SAAWA,EAGtC,GAAIA,EAAI,MAAM,WAAW,EACrB,OAAOA,EAEX,MAAMqD,EAAM,SAAS,eAAe,mBAAkB,EAChDC,EAAOD,EAAI,cAAc,MAAM,EAC/BE,EAAIF,EAAI,cAAc,GAAG,EAC/B,OAAAA,EAAI,KAAK,YAAYC,CAAI,EACzBD,EAAI,KAAK,YAAYE,CAAC,EAClBH,IACAE,EAAK,KAAOF,GAEhBG,EAAE,KAAOvD,EACFuD,EAAE,IACb,CACO,MAAMC,IAAQ,IAAM,CAGvB,IAAIC,EAAU,EAEd,MAAMC,EAAS,IAEf,QAAS,KAAK,OAAM,EAAK,IAAM,GAAM,GAAG,SAAS,EAAE,CAAC,GAAG,MAAM,EAAE,EAC/D,MAAO,KACHD,GAAW,EACJ,IAAIC,GAAQ,GAAGD,CAAO,GAErC,GAAC,EAMM,SAASE,EAAQC,EAAW,CAC/B,MAAMC,EAAM,CAAA,EACZ,QAAS/I,EAAI,EAAGgG,EAAI8C,EAAU,OAAQ9I,EAAIgG,EAAGhG,IACzC+I,EAAI,KAAKD,EAAU9I,CAAC,CAAC,EAEzB,OAAO+I,CACX,CACA,IAAIC,EAAa,KACV,SAASC,GAAmBnB,EAAU,GAAI,CAC7C,OAAIkB,IAGAlB,EAAQ,wBACRkB,EAAalB,EAAQ,uBACdkB,IAEXA,EAAaH,EAAQ,OAAO,iBAAiB,SAAS,eAAe,CAAC,EAC/DG,GACX,CACA,SAAS5H,EAAG1D,EAAMwL,EAAe,CAE7B,MAAMC,GADMzL,EAAK,cAAc,aAAe,QAC9B,iBAAiBA,CAAI,EAAE,iBAAiBwL,CAAa,EACrE,OAAOC,EAAM,WAAWA,EAAI,QAAQ,KAAM,EAAE,CAAC,EAAI,CACrD,CACA,SAASC,GAAa1L,EAAM,CACxB,MAAM2L,EAAajI,EAAG1D,EAAM,mBAAmB,EACzC4L,EAAclI,EAAG1D,EAAM,oBAAoB,EACjD,OAAOA,EAAK,YAAc2L,EAAaC,CAC3C,CACA,SAASC,GAAc7L,EAAM,CACzB,MAAM8L,EAAYpI,EAAG1D,EAAM,kBAAkB,EACvC+L,EAAerI,EAAG1D,EAAM,qBAAqB,EACnD,OAAOA,EAAK,aAAe8L,EAAYC,CAC3C,CACO,SAASC,GAAaC,EAAY7B,EAAU,GAAI,CACnD,MAAM8B,EAAQ9B,EAAQ,OAASsB,GAAaO,CAAU,EAChDE,EAAS/B,EAAQ,QAAUyB,GAAcI,CAAU,EACzD,MAAO,CAAE,MAAAC,EAAO,OAAAC,CAAM,CAC1B,CACO,SAASC,IAAgB,CAC5B,IAAIC,EACAC,EACJ,GAAI,CACAA,EAAgB,OACpB,MACU,CAEV,CACA,MAAMb,EAAMa,GAAiBA,EAAc,IACrCA,EAAc,IAAI,iBAClB,KACN,OAAIb,IACAY,EAAQ,SAASZ,EAAK,EAAE,EACpB,OAAO,MAAMY,CAAK,IAClBA,EAAQ,IAGTA,GAAS,OAAO,kBAAoB,CAC/C,CAEA,MAAME,EAAuB,MACtB,SAASC,GAAsBC,EAAQ,EACtCA,EAAO,MAAQF,GACfE,EAAO,OAASF,KACZE,EAAO,MAAQF,GACfE,EAAO,OAASF,EACZE,EAAO,MAAQA,EAAO,QACtBA,EAAO,QAAUF,EAAuBE,EAAO,MAC/CA,EAAO,MAAQF,IAGfE,EAAO,OAASF,EAAuBE,EAAO,OAC9CA,EAAO,OAASF,GAGfE,EAAO,MAAQF,GACpBE,EAAO,QAAUF,EAAuBE,EAAO,MAC/CA,EAAO,MAAQF,IAGfE,EAAO,OAASF,EAAuBE,EAAO,OAC9CA,EAAO,OAASF,GAG5B,CAqBO,SAASG,EAAYlF,EAAK,CAC7B,OAAO,IAAI,QAAQ,CAACM,EAAS6E,IAAW,CACpC,MAAMC,EAAM,IAAI,MAChBA,EAAI,OAAS,IAAM,CACfA,EAAI,SAAS,KAAK,IAAM,CACpB,sBAAsB,IAAM9E,EAAQ8E,CAAG,CAAC,CAC5C,CAAC,CACL,EACAA,EAAI,QAAUD,EACdC,EAAI,YAAc,YAClBA,EAAI,SAAW,QACfA,EAAI,IAAMpF,CACd,CAAC,CACL,CACO,eAAeqF,GAAaC,EAAK,CACpC,OAAO,QAAQ,QAAO,EACjB,KAAK,IAAM,IAAI,gBAAgB,kBAAkBA,CAAG,CAAC,EACrD,KAAK,kBAAkB,EACvB,KAAMC,GAAS,oCAAoCA,CAAI,EAAE,CAClE,CACO,eAAeC,GAAchN,EAAMkM,EAAOC,EAAQ,CACrD,MAAMc,EAAQ,6BACRH,EAAM,SAAS,gBAAgBG,EAAO,KAAK,EAC3CC,EAAgB,SAAS,gBAAgBD,EAAO,eAAe,EACrE,OAAAH,EAAI,aAAa,QAAS,GAAGZ,CAAK,EAAE,EACpCY,EAAI,aAAa,SAAU,GAAGX,CAAM,EAAE,EACtCW,EAAI,aAAa,UAAW,OAAOZ,CAAK,IAAIC,CAAM,EAAE,EACpDe,EAAc,aAAa,QAAS,MAAM,EAC1CA,EAAc,aAAa,SAAU,MAAM,EAC3CA,EAAc,aAAa,IAAK,GAAG,EACnCA,EAAc,aAAa,IAAK,GAAG,EACnCA,EAAc,aAAa,4BAA6B,MAAM,EAC9DJ,EAAI,YAAYI,CAAa,EAC7BA,EAAc,YAAYlN,CAAI,EACvB6M,GAAaC,CAAG,CAC3B,CACO,MAAMK,EAAsB,CAACnN,EAAMoN,IAAa,CACnD,GAAIpN,aAAgBoN,EAChB,MAAO,GACX,MAAMC,EAAgB,OAAO,eAAerN,CAAI,EAChD,OAAIqN,IAAkB,KACX,GACHA,EAAc,YAAY,OAASD,EAAS,MAChDD,EAAoBE,EAAeD,CAAQ,CACnD,EC9LA,SAASE,GAAc5P,EAAO,CAC1B,MAAM6P,EAAU7P,EAAM,iBAAiB,SAAS,EAChD,MAAO,GAAGA,EAAM,OAAO,cAAc6P,EAAQ,QAAQ,OAAQ,EAAE,CAAC,IACpE,CACA,SAASC,GAAoB9P,EAAO0M,EAAS,CACzC,OAAOmB,GAAmBnB,CAAO,EAC5B,IAAKqD,GAAS,CACf,MAAM/E,EAAQhL,EAAM,iBAAiB+P,CAAI,EACnCC,EAAWhQ,EAAM,oBAAoB+P,CAAI,EAC/C,MAAO,GAAGA,CAAI,KAAK/E,CAAK,GAAGgF,EAAW,cAAgB,EAAE,GAC5D,CAAC,EACI,KAAK,GAAG,CACjB,CACA,SAASC,GAAsB9P,EAAW+P,EAAQlQ,EAAO0M,EAAS,CAC9D,MAAM3J,EAAW,IAAI5C,CAAS,IAAI+P,CAAM,GAClCjQ,EAAUD,EAAM,QAChB4P,GAAc5P,CAAK,EACnB8P,GAAoB9P,EAAO0M,CAAO,EACxC,OAAO,SAAS,eAAe,GAAG3J,CAAQ,IAAI9C,CAAO,GAAG,CAC5D,CACA,SAASkQ,GAAmBC,EAAYC,EAAYH,EAAQxD,EAAS,CACjE,MAAM1M,EAAQ,OAAO,iBAAiBoQ,EAAYF,CAAM,EAClDL,EAAU7P,EAAM,iBAAiB,SAAS,EAChD,GAAI6P,IAAY,IAAMA,IAAY,OAC9B,OAEJ,MAAM1P,EAAYmN,GAAI,EACtB,GAAI,CACA+C,EAAW,UAAY,GAAGA,EAAW,SAAS,IAAIlQ,CAAS,EAC/D,MACY,CACR,MACJ,CACA,MAAMmQ,EAAe,SAAS,cAAc,OAAO,EACnDA,EAAa,YAAYL,GAAsB9P,EAAW+P,EAAQlQ,EAAO0M,CAAO,CAAC,EACjF2D,EAAW,YAAYC,CAAY,CACvC,CACO,SAASC,GAAoBH,EAAYC,EAAY3D,EAAS,CACjEyD,GAAmBC,EAAYC,EAAY,UAAW3D,CAAO,EAC7DyD,GAAmBC,EAAYC,EAAY,SAAU3D,CAAO,CAChE,CCzCA,MAAM8D,GAAO,wBACPC,GAAO,aACPC,GAAQ,CACV,KAAMF,GACN,MAAOA,GACP,IAAK,4BACL,IAAK,gCACL,IAAK,YACL,IAAKC,GACL,KAAMA,GACN,IAAK,YACL,KAAM,aACN,IAAK,gBACL,KAAM,YACV,EACA,SAASE,GAAa7G,EAAK,CACvB,MAAM8G,EAAQ,gBAAgB,KAAK9G,CAAG,EACtC,OAAO8G,EAAQA,EAAM,CAAC,EAAI,EAC9B,CACO,SAASC,EAAY/G,EAAK,CAC7B,MAAMgH,EAAYH,GAAa7G,CAAG,EAAE,YAAW,EAC/C,OAAO4G,GAAMI,CAAS,GAAK,EAC/B,CCtBA,SAASC,GAAsBC,EAAS,CACpC,OAAOA,EAAQ,MAAM,GAAG,EAAE,CAAC,CAC/B,CACO,SAASC,EAAUnH,EAAK,CAC3B,OAAOA,EAAI,OAAO,UAAU,IAAM,EACtC,CACO,SAASoH,GAAYrB,EAASsB,EAAU,CAC3C,MAAO,QAAQA,CAAQ,WAAWtB,CAAO,EAC7C,CACO,eAAeuB,GAAetH,EAAKC,EAAMsH,EAAS,CACrD,MAAMzH,EAAM,MAAM,MAAME,EAAKC,CAAI,EACjC,GAAIH,EAAI,SAAW,IACf,MAAM,IAAI,MAAM,aAAaA,EAAI,GAAG,aAAa,EAErD,MAAMX,EAAO,MAAMW,EAAI,KAAI,EAC3B,OAAO,IAAI,QAAQ,CAACQ,EAAS6E,IAAW,CACpC,MAAM5E,EAAS,IAAI,WACnBA,EAAO,QAAU4E,EACjB5E,EAAO,UAAY,IAAM,CACrB,GAAI,CACAD,EAAQiH,EAAQ,CAAE,IAAAzH,EAAK,OAAQS,EAAO,MAAM,CAAE,CAAC,CACnD,OACOrC,EAAO,CACViH,EAAOjH,CAAK,CAChB,CACJ,EACAqC,EAAO,cAAcpB,CAAI,CAC7B,CAAC,CACL,CACA,MAAMqI,EAAQ,CAAA,EACd,SAASC,GAAYzH,EAAKtB,EAAagJ,EAAoB,CACvD,IAAIC,EAAM3H,EAAI,QAAQ,OAAQ,EAAE,EAChC,OAAI0H,IACAC,EAAM3H,GAGN,sBAAsB,KAAK2H,CAAG,IAC9BA,EAAMA,EAAI,QAAQ,OAAQ,EAAE,GAEzBjJ,EAAc,IAAIA,CAAW,IAAIiJ,CAAG,GAAKA,CACpD,CACO,eAAeC,GAAkBC,EAAanJ,EAAakE,EAAS,CACvE,MAAMkF,EAAWL,GAAYI,EAAanJ,EAAakE,EAAQ,kBAAkB,EACjF,GAAI4E,EAAMM,CAAQ,GAAK,KACnB,OAAON,EAAMM,CAAQ,EAGrBlF,EAAQ,YAERiF,IAAgB,KAAK,KAAKA,CAAW,EAAI,IAAM,KAAO,IAAI,KAAI,EAAG,QAAO,GAE5E,IAAIX,EACJ,GAAI,CACA,MAAMnB,EAAU,MAAMuB,GAAeO,EAAajF,EAAQ,iBAAkB,CAAC,CAAE,IAAA9C,EAAK,OAAAY,MAC3EhC,IAEDA,EAAcoB,EAAI,QAAQ,IAAI,cAAc,GAAK,IAE9CmH,GAAsBvG,CAAM,EACtC,EACDwG,EAAUE,GAAYrB,EAASrH,CAAW,CAC9C,OACOR,EAAO,CACVgJ,EAAUtE,EAAQ,kBAAoB,GACtC,IAAIR,EAAM,6BAA6ByF,CAAW,GAC9C3J,IACAkE,EAAM,OAAOlE,GAAU,SAAWA,EAAQA,EAAM,SAEhDkE,GACA,QAAQ,KAAKA,CAAG,CAExB,CACA,OAAAoF,EAAMM,CAAQ,EAAIZ,EACXA,CACX,CCtEA,eAAea,GAAmB9C,EAAQ,CACtC,MAAMiC,EAAUjC,EAAO,UAAS,EAChC,OAAIiC,IAAY,SACLjC,EAAO,UAAU,EAAK,EAE1BC,EAAYgC,CAAO,CAC9B,CACA,eAAec,GAAkBC,EAAOrF,EAAS,CAC7C,GAAIqF,EAAM,WAAY,CAClB,MAAMhD,EAAS,SAAS,cAAc,QAAQ,EACxCiD,EAAMjD,EAAO,WAAW,IAAI,EAClCA,EAAO,MAAQgD,EAAM,YACrBhD,EAAO,OAASgD,EAAM,aACoBC,GAAI,UAAUD,EAAO,EAAG,EAAGhD,EAAO,MAAOA,EAAO,MAAM,EAChG,MAAMiC,EAAUjC,EAAO,UAAS,EAChC,OAAOC,EAAYgC,CAAO,CAC9B,CACA,MAAMiB,EAASF,EAAM,OACfvJ,EAAcqI,EAAYoB,CAAM,EAChCjB,EAAU,MAAMU,GAAkBO,EAAQzJ,EAAakE,CAAO,EACpE,OAAOsC,EAAYgC,CAAO,CAC9B,CACA,eAAekB,GAAmBC,EAAQzF,EAAS,CAC/C,IAAI0F,EACJ,GAAI,CACA,GAAK,GAAAA,EAAqDD,GAAO,mBAAqB,MAAQC,IAAO,SAAkBA,EAAG,KACtH,OAAQ,MAAMC,EAAUF,EAAO,gBAAgB,KAAMzF,EAAS,EAAI,CAE1E,MACW,CAEX,CACA,OAAOyF,EAAO,UAAU,EAAK,CACjC,CACA,eAAeG,GAAgBhQ,EAAMoK,EAAS,CAC1C,OAAI+C,EAAoBnN,EAAM,iBAAiB,EACpCuP,GAAmBvP,CAAI,EAE9BmN,EAAoBnN,EAAM,gBAAgB,EACnCwP,GAAkBxP,EAAMoK,CAAO,EAEtC+C,EAAoBnN,EAAM,iBAAiB,EACpC4P,GAAmB5P,EAAMoK,CAAO,EAEpCpK,EAAK,UAAUiQ,GAAajQ,CAAI,CAAC,CAC5C,CACA,MAAMkQ,GAAiBlQ,GAASA,EAAK,SAAW,MAAQA,EAAK,QAAQ,YAAW,IAAO,OACjFiQ,GAAgBjQ,GAASA,EAAK,SAAW,MAAQA,EAAK,QAAQ,YAAW,IAAO,MACtF,eAAemQ,GAAcrC,EAAYC,EAAY3D,EAAS,CAC1D,IAAI0F,EAAIM,EACR,GAAIH,GAAalC,CAAU,EACvB,OAAOA,EAEX,IAAIsC,EAAW,CAAA,EAWf,OAVIH,GAAcpC,CAAU,GAAKA,EAAW,cACxCuC,EAAWlF,EAAQ2C,EAAW,eAAe,EAExCX,EAAoBW,EAAY,iBAAiB,IACpD,GAAAgC,EAAKhC,EAAW,mBAAqB,MAAQgC,IAAO,SAAkBA,EAAG,MAC3EO,EAAWlF,EAAQ2C,EAAW,gBAAgB,KAAK,UAAU,EAG7DuC,EAAWlF,IAAUiF,EAAKtC,EAAW,cAAgB,MAAQsC,IAAO,OAASA,EAAKtC,GAAY,UAAU,EAExGuC,EAAS,SAAW,GACpBlD,EAAoBW,EAAY,gBAAgB,GAGpD,MAAMuC,EAAS,OAAO,CAACC,EAAUC,IAAUD,EACtC,KAAK,IAAMP,EAAUQ,EAAOnG,CAAO,CAAC,EACpC,KAAMoG,GAAgB,CACnBA,GACAzC,EAAW,YAAYyC,CAAW,CAE1C,CAAC,EAAG,QAAQ,SAAS,EACdzC,CACX,CACA,SAAS0C,GAAc3C,EAAYC,EAAY3D,EAAS,CACpD,MAAMsG,EAAc3C,EAAW,MAC/B,GAAI,CAAC2C,EACD,OAEJ,MAAMC,EAAc,OAAO,iBAAiB7C,CAAU,EAClD6C,EAAY,SACZD,EAAY,QAAUC,EAAY,QAClCD,EAAY,gBAAkBC,EAAY,iBAG1CpF,GAAmBnB,CAAO,EAAE,QAASqD,GAAS,CAC1C,IAAI/E,EAAQiI,EAAY,iBAAiBlD,CAAI,EACzCA,IAAS,aAAe/E,EAAM,SAAS,IAAI,IAE3CA,EAAQ,GADY,KAAK,MAAM,WAAWA,EAAM,UAAU,EAAGA,EAAM,OAAS,CAAC,CAAC,CAAC,EAAI,EAC7D,MAEtByE,EAAoBW,EAAY,iBAAiB,GACjDL,IAAS,WACT/E,IAAU,WACVA,EAAQ,SAER+E,IAAS,KAAOM,EAAW,aAAa,GAAG,IAC3CrF,EAAQ,QAAQqF,EAAW,aAAa,GAAG,CAAC,KAEhD2C,EAAY,YAAYjD,EAAM/E,EAAOiI,EAAY,oBAAoBlD,CAAI,CAAC,CAC9E,CAAC,CAET,CACA,SAASmD,GAAgB9C,EAAYC,EAAY,CACzCZ,EAAoBW,EAAY,mBAAmB,IACnDC,EAAW,UAAYD,EAAW,OAElCX,EAAoBW,EAAY,gBAAgB,GAChDC,EAAW,aAAa,QAASD,EAAW,KAAK,CAEzD,CACA,SAAS+C,GAAiB/C,EAAYC,EAAY,CAC9C,GAAIZ,EAAoBW,EAAY,iBAAiB,EAAG,CACpD,MAAMgD,EAAe/C,EACfgD,EAAiB,MAAM,KAAKD,EAAa,QAAQ,EAAE,KAAMP,GAAUzC,EAAW,QAAUyC,EAAM,aAAa,OAAO,CAAC,EACrHQ,GACAA,EAAe,aAAa,WAAY,EAAE,CAElD,CACJ,CACA,SAASC,GAASlD,EAAYC,EAAY3D,EAAS,CAC/C,OAAI+C,EAAoBY,EAAY,OAAO,IACvC0C,GAAc3C,EAAYC,EAAY3D,CAAO,EAC7C6D,GAAoBH,EAAYC,EAAY3D,CAAO,EACnDwG,GAAgB9C,EAAYC,CAAU,EACtC8C,GAAiB/C,EAAYC,CAAU,GAEpCA,CACX,CACA,eAAekD,GAAiBC,EAAO9G,EAAS,CAC5C,MAAM+G,EAAOD,EAAM,iBAAmBA,EAAM,iBAAiB,KAAK,EAAI,CAAA,EACtE,GAAIC,EAAK,SAAW,EAChB,OAAOD,EAEX,MAAME,EAAgB,CAAA,EACtB,QAAS9O,EAAI,EAAGA,EAAI6O,EAAK,OAAQ7O,IAAK,CAElC,MAAM+O,EADMF,EAAK7O,CAAC,EACH,aAAa,YAAY,EACxC,GAAI+O,EAAI,CACJ,MAAMC,EAAQJ,EAAM,cAAcG,CAAE,EAC9BE,EAAa,SAAS,cAAcF,CAAE,EACxC,CAACC,GAASC,GAAc,CAACH,EAAcC,CAAE,IAEzCD,EAAcC,CAAE,EAAK,MAAMtB,EAAUwB,EAAYnH,EAAS,EAAI,EAEtE,CACJ,CACA,MAAMrM,EAAQ,OAAO,OAAOqT,CAAa,EACzC,GAAIrT,EAAM,OAAQ,CACd,MAAMyT,EAAK,+BACL1E,EAAM,SAAS,gBAAgB0E,EAAI,KAAK,EAC9C1E,EAAI,aAAa,QAAS0E,CAAE,EAC5B1E,EAAI,MAAM,SAAW,WACrBA,EAAI,MAAM,MAAQ,IAClBA,EAAI,MAAM,OAAS,IACnBA,EAAI,MAAM,SAAW,SACrBA,EAAI,MAAM,QAAU,OACpB,MAAM2E,EAAO,SAAS,gBAAgBD,EAAI,MAAM,EAChD1E,EAAI,YAAY2E,CAAI,EACpB,QAASnP,EAAI,EAAGA,EAAIvE,EAAM,OAAQuE,IAC9BmP,EAAK,YAAY1T,EAAMuE,CAAC,CAAC,EAE7B4O,EAAM,YAAYpE,CAAG,CACzB,CACA,OAAOoE,CACX,CACO,eAAenB,EAAU/P,EAAMoK,EAASsH,EAAQ,CACnD,MAAI,CAACA,GAAUtH,EAAQ,QAAU,CAACA,EAAQ,OAAOpK,CAAI,EAC1C,KAEJ,QAAQ,QAAQA,CAAI,EACtB,KAAM+N,GAAeiC,GAAgBjC,EAAY3D,CAAO,CAAC,EACzD,KAAM2D,GAAeoC,GAAcnQ,EAAM+N,EAAY3D,CAAO,CAAC,EAC7D,KAAM2D,GAAeiD,GAAShR,EAAM+N,EAAY3D,CAAO,CAAC,EACxD,KAAM2D,GAAekD,GAAiBlD,EAAY3D,CAAO,CAAC,CACnE,CCnLA,MAAMuH,GAAY,6BACZC,GAAwB,8CACxBC,GAAiB,qDACvB,SAASC,GAAQtK,EAAK,CAElB,MAAMuK,EAAUvK,EAAI,QAAQ,2BAA4B,MAAM,EAC9D,OAAO,IAAI,OAAO,iBAAiBuK,CAAO,cAAe,GAAG,CAChE,CACO,SAASC,GAAUrU,EAAS,CAC/B,MAAMsU,EAAO,CAAA,EACb,OAAAtU,EAAQ,QAAQgU,GAAW,CAACvJ,EAAK8J,EAAW1K,KACxCyK,EAAK,KAAKzK,CAAG,EACNY,EACV,EACM6J,EAAK,OAAQzK,GAAQ,CAACmH,EAAUnH,CAAG,CAAC,CAC/C,CACO,eAAe2K,GAAMxU,EAASyU,EAAaC,EAASjI,EAASkI,EAAmB,CACnF,GAAI,CACA,MAAMC,EAAcF,EAAU1H,GAAWyH,EAAaC,CAAO,EAAID,EAC3DlM,EAAcqI,EAAY6D,CAAW,EAC3C,IAAI1D,EACJ,OAAI4D,IAKA5D,EAAU,MAAMU,GAAkBmD,EAAarM,EAAakE,CAAO,GAEhEzM,EAAQ,QAAQmU,GAAQM,CAAW,EAAG,KAAK1D,CAAO,IAAI,CACjE,MACc,CAEd,CACA,OAAO/Q,CACX,CACA,SAAS6U,GAA0BC,EAAK,CAAE,oBAAAC,GAAuB,CAC7D,OAAQA,EAEFD,EAAI,QAAQZ,GAAiBvD,GAAU,CAErC,OAAa,CACT,KAAM,CAACqE,EAAG,CAAIC,CAAM,EAAIhB,GAAsB,KAAKtD,CAAK,GAAK,CAAA,EAC7D,GAAI,CAACsE,EACD,MAAO,GAEX,GAAIA,IAAWF,EACX,MAAO,QAAQC,CAAG,GAE1B,CACJ,CAAC,EAZCF,CAaV,CACO,SAASI,GAAYrL,EAAK,CAC7B,OAAOA,EAAI,OAAOmK,EAAS,IAAM,EACrC,CACO,eAAemB,GAAenV,EAASiN,EAASR,EAAS,CAC5D,GAAI,CAACyI,GAAYlV,CAAO,EACpB,OAAOA,EAEX,MAAMoV,EAAkBP,GAA0B7U,EAASyM,CAAO,EAElE,OADa4H,GAAUe,CAAe,EAC1B,OAAO,CAACzC,EAAU9I,IAAQ8I,EAAS,KAAM0C,GAAQb,GAAMa,EAAKxL,EAAKoD,EAASR,CAAO,CAAC,EAAG,QAAQ,QAAQ2I,CAAe,CAAC,CACrI,CC5DA,eAAeE,EAAUC,EAAUlT,EAAMoK,EAAS,CAC9C,IAAI0F,EACJ,MAAMqD,GAAarD,EAAK9P,EAAK,SAAW,MAAQ8P,IAAO,OAAS,OAASA,EAAG,iBAAiBoD,CAAQ,EACrG,GAAIC,EAAW,CACX,MAAMC,EAAY,MAAMN,GAAeK,EAAW,KAAM/I,CAAO,EAC/D,OAAApK,EAAK,MAAM,YAAYkT,EAAUE,EAAWpT,EAAK,MAAM,oBAAoBkT,CAAQ,CAAC,EAC7E,EACX,CACA,MAAO,EACX,CACA,eAAeG,GAAgBtF,EAAY3D,EAAS,CAE/C,MAAM6I,EAAU,aAAclF,EAAY3D,CAAO,GAC7C,MAAM6I,EAAU,mBAAoBlF,EAAY3D,CAAO,EAC3D,MAAM6I,EAAU,OAAQlF,EAAY3D,CAAO,GACvC,MAAM6I,EAAU,eAAgBlF,EAAY3D,CAAO,GACnD,MAAM6I,EAAU,aAAclF,EAAY3D,CAAO,GACjD,MAAM6I,EAAU,qBAAsBlF,EAAY3D,CAAO,CAClE,CACA,eAAekJ,GAAevF,EAAY3D,EAAS,CAC/C,MAAMmJ,EAAiBpG,EAAoBY,EAAY,gBAAgB,EACvE,GAAI,EAAEwF,GAAkB,CAAC5E,EAAUZ,EAAW,GAAG,IAC7C,EAAEZ,EAAoBY,EAAY,eAAe,GAC7C,CAACY,EAAUZ,EAAW,KAAK,OAAO,GACtC,OAEJ,MAAMvG,EAAM+L,EAAiBxF,EAAW,IAAMA,EAAW,KAAK,QACxDW,EAAU,MAAMU,GAAkB5H,EAAK+G,EAAY/G,CAAG,EAAG4C,CAAO,EACtE,MAAM,IAAI,QAAQ,CAACtC,EAAS6E,IAAW,CACnCoB,EAAW,OAASjG,EACpBiG,EAAW,QAAU3D,EAAQ,oBACvB,IAAIoJ,IAAe,CACjB,GAAI,CACA1L,EAAQsC,EAAQ,oBAAoB,GAAGoJ,CAAU,CAAC,CACtD,OACO9N,EAAO,CACViH,EAAOjH,CAAK,CAChB,CACJ,EACEiH,EACN,MAAM8G,EAAQ1F,EACV0F,EAAM,SACNA,EAAM,OAAS3L,GAEf2L,EAAM,UAAY,SAClBA,EAAM,QAAU,SAEhBF,GACAxF,EAAW,OAAS,GACpBA,EAAW,IAAMW,GAGjBX,EAAW,KAAK,QAAUW,CAElC,CAAC,CACL,CACA,eAAegF,GAAc3F,EAAY3D,EAAS,CAE9C,MAAMuJ,EADWxI,EAAQ4C,EAAW,UAAU,EACnB,IAAKwC,GAAUqD,GAAYrD,EAAOnG,CAAO,CAAC,EACrE,MAAM,QAAQ,IAAIuJ,CAAS,EAAE,KAAK,IAAM5F,CAAU,CACtD,CACO,eAAe6F,GAAY7F,EAAY3D,EAAS,CAC/C+C,EAAoBY,EAAY,OAAO,IACvC,MAAMsF,GAAgBtF,EAAY3D,CAAO,EACzC,MAAMkJ,GAAevF,EAAY3D,CAAO,EACxC,MAAMsJ,GAAc3F,EAAY3D,CAAO,EAE/C,CCvEO,SAASyJ,GAAW7T,EAAMoK,EAAS,CACtC,KAAM,CAAE,MAAA1M,CAAK,EAAKsC,EACdoK,EAAQ,kBACR1M,EAAM,gBAAkB0M,EAAQ,iBAEhCA,EAAQ,QACR1M,EAAM,MAAQ,GAAG0M,EAAQ,KAAK,MAE9BA,EAAQ,SACR1M,EAAM,OAAS,GAAG0M,EAAQ,MAAM,MAEpC,MAAM0J,EAAS1J,EAAQ,MACvB,OAAI0J,GAAU,MACV,OAAO,KAAKA,CAAM,EAAE,QAAS3E,GAAQ,CACjCzR,EAAMyR,CAAG,EAAI2E,EAAO3E,CAAG,CAC3B,CAAC,EAEEnP,CACX,CCfA,MAAM+T,GAAgB,CAAA,EACtB,eAAeC,GAASxM,EAAK,CACzB,IAAIwH,EAAQ+E,GAAcvM,CAAG,EAC7B,GAAIwH,GAAS,KACT,OAAOA,EAGX,MAAMrR,EAAU,MADJ,MAAM,MAAM6J,CAAG,GACD,KAAI,EAC9B,OAAAwH,EAAQ,CAAE,IAAAxH,EAAK,QAAA7J,CAAO,EACtBoW,GAAcvM,CAAG,EAAIwH,EACdA,CACX,CACA,eAAeiF,GAAWC,EAAM9J,EAAS,CACrC,IAAIzM,EAAUuW,EAAK,QACnB,MAAMC,EAAW,8BAEXC,GADWzW,EAAQ,MAAM,eAAe,GAAK,CAAA,GACxB,IAAI,MAAO0W,GAAQ,CAC1C,IAAI7M,EAAM6M,EAAI,QAAQF,EAAU,IAAI,EACpC,OAAK3M,EAAI,WAAW,UAAU,IAC1BA,EAAM,IAAI,IAAIA,EAAK0M,EAAK,GAAG,EAAE,MAE1BpF,GAAetH,EAAK4C,EAAQ,iBAAkB,CAAC,CAAE,OAAAlC,MACpDvK,EAAUA,EAAQ,QAAQ0W,EAAK,OAAOnM,CAAM,GAAG,EACxC,CAACmM,EAAKnM,CAAM,EACtB,CACL,CAAC,EACD,OAAO,QAAQ,IAAIkM,CAAS,EAAE,KAAK,IAAMzW,CAAO,CACpD,CACA,SAAS2W,GAASC,EAAQ,CACtB,GAAIA,GAAU,KACV,MAAO,CAAA,EAEX,MAAMrM,EAAS,CAAA,EACTsM,EAAgB,uBAEtB,IAAI7W,EAAU4W,EAAO,QAAQC,EAAe,EAAE,EAE9C,MAAMC,EAAiB,IAAI,OAAO,mDAAoD,IAAI,EAE1F,OAAa,CACT,MAAMC,EAAUD,EAAe,KAAK9W,CAAO,EAC3C,GAAI+W,IAAY,KACZ,MAEJxM,EAAO,KAAKwM,EAAQ,CAAC,CAAC,CAC1B,CACA/W,EAAUA,EAAQ,QAAQ8W,EAAgB,EAAE,EAC5C,MAAME,EAAc,yCAEdC,EAAmB,6GAGnBC,EAAe,IAAI,OAAOD,EAAkB,IAAI,EAEtD,OAAa,CACT,IAAIF,EAAUC,EAAY,KAAKhX,CAAO,EACtC,GAAI+W,IAAY,KAAM,CAElB,GADAA,EAAUG,EAAa,KAAKlX,CAAO,EAC/B+W,IAAY,KACZ,MAGAC,EAAY,UAAYE,EAAa,SAE7C,MAEIA,EAAa,UAAYF,EAAY,UAEzCzM,EAAO,KAAKwM,EAAQ,CAAC,CAAC,CAC1B,CACA,OAAOxM,CACX,CACA,eAAe4M,GAAYC,EAAa3K,EAAS,CAC7C,MAAM4K,EAAM,CAAA,EACNrB,EAAY,CAAA,EAElB,OAAAoB,EAAY,QAASE,GAAU,CAC3B,GAAI,aAAcA,EACd,GAAI,CACA9J,EAAQ8J,EAAM,UAAY,CAAA,CAAE,EAAE,QAAQ,CAACC,EAAMC,IAAU,CACnD,GAAID,EAAK,OAAS,QAAQ,YAAa,CACnC,IAAIE,EAAcD,EAAQ,EAC1B,MAAM3N,EAAM0N,EAAK,KACX5E,EAAW0D,GAASxM,CAAG,EACxB,KAAM6N,GAAapB,GAAWoB,EAAUjL,CAAO,CAAC,EAChD,KAAMzM,GAAY2W,GAAS3W,CAAO,EAAE,QAAS2X,GAAS,CACvD,GAAI,CACAL,EAAM,WAAWK,EAAMA,EAAK,WAAW,SAAS,EACzCF,GAAe,EAChBH,EAAM,SAAS,MAAM,CAC/B,OACOvP,EAAO,CACV,QAAQ,MAAM,uCAAwC,CAClD,KAAA4P,EACA,MAAA5P,CACpC,CAAiC,CACL,CACJ,CAAC,CAAC,EACG,MAAOzG,GAAM,CACd,QAAQ,MAAM,2BAA4BA,EAAE,SAAQ,CAAE,CAC1D,CAAC,EACD0U,EAAU,KAAKrD,CAAQ,CAC3B,CACJ,CAAC,CACL,OACOrR,EAAG,CACN,MAAMsW,EAASR,EAAY,KAAM,GAAM,EAAE,MAAQ,IAAI,GAAK,SAAS,YAAY,CAAC,EAC5EE,EAAM,MAAQ,MACdtB,EAAU,KAAKK,GAASiB,EAAM,IAAI,EAC7B,KAAMI,GAAapB,GAAWoB,EAAUjL,CAAO,CAAC,EAChD,KAAMzM,GAAY2W,GAAS3W,CAAO,EAAE,QAAS2X,GAAS,CACvDC,EAAO,WAAWD,EAAMC,EAAO,SAAS,MAAM,CAClD,CAAC,CAAC,EACG,MAAO5N,GAAQ,CAChB,QAAQ,MAAM,kCAAmCA,CAAG,CACxD,CAAC,CAAC,EAEN,QAAQ,MAAM,iCAAkC1I,CAAC,CACrD,CAER,CAAC,EACM,QAAQ,IAAI0U,CAAS,EAAE,KAAK,KAE/BoB,EAAY,QAASE,GAAU,CAC3B,GAAI,aAAcA,EACd,GAAI,CACA9J,EAAQ8J,EAAM,UAAY,CAAA,CAAE,EAAE,QAASC,GAAS,CAC5CF,EAAI,KAAKE,CAAI,CACjB,CAAC,CACL,OACOjW,EAAG,CACN,QAAQ,MAAM,sCAAsCgW,EAAM,IAAI,GAAIhW,CAAC,CACvE,CAER,CAAC,EACM+V,EACV,CACL,CACA,SAASQ,GAAgBC,EAAU,CAC/B,OAAOA,EACF,OAAQH,GAASA,EAAK,OAAS,QAAQ,cAAc,EACrD,OAAQA,GAASzC,GAAYyC,EAAK,MAAM,iBAAiB,KAAK,CAAC,CAAC,CACzE,CACA,eAAeI,GAAkB1V,EAAMoK,EAAS,CAC5C,GAAIpK,EAAK,eAAiB,KACtB,MAAM,IAAI,MAAM,2CAA2C,EAE/D,MAAM+U,EAAc5J,EAAQnL,EAAK,cAAc,WAAW,EACpDyV,EAAW,MAAMX,GAAYC,EAAa3K,CAAO,EACvD,OAAOoL,GAAgBC,CAAQ,CACnC,CACA,SAASE,GAAoBC,EAAM,CAC/B,OAAOA,EAAK,KAAI,EAAG,QAAQ,QAAS,EAAE,CAC1C,CACA,SAASC,GAAa7V,EAAM,CACxB,MAAM8V,EAAQ,IAAI,IAClB,SAASC,EAAS/V,EAAM,EACDA,EAAK,MAAM,YAAc,iBAAiBA,CAAI,EAAE,YACxD,MAAM,GAAG,EAAE,QAAS4V,GAAS,CACpCE,EAAM,IAAIH,GAAoBC,CAAI,CAAC,CACvC,CAAC,EACD,MAAM,KAAK5V,EAAK,QAAQ,EAAE,QAASuQ,GAAU,CACrCA,aAAiB,aACjBwF,EAASxF,CAAK,CAEtB,CAAC,CACL,CACA,OAAAwF,EAAS/V,CAAI,EACN8V,CACX,CACO,eAAeE,GAAchW,EAAMoK,EAAS,CAC/C,MAAM6L,EAAQ,MAAMP,GAAkB1V,EAAMoK,CAAO,EAC7C8L,EAAYL,GAAa7V,CAAI,EASnC,OARiB,MAAM,QAAQ,IAAIiW,EAC9B,OAAQX,GAASY,EAAU,IAAIP,GAAoBL,EAAK,MAAM,UAAU,CAAC,CAAC,EAC1E,IAAKA,GAAS,CACf,MAAM1K,EAAU0K,EAAK,iBACfA,EAAK,iBAAiB,KACtB,KACN,OAAOxC,GAAewC,EAAK,QAAS1K,EAASR,CAAO,CACxD,CAAC,CAAC,GACc,KAAK;AAAA,CAAI,CAC7B,CACO,eAAe+L,GAAcpI,EAAY3D,EAAS,CACrD,MAAMzM,EAAUyM,EAAQ,cAAgB,KAClCA,EAAQ,aACRA,EAAQ,UACJ,KACA,MAAM4L,GAAcjI,EAAY3D,CAAO,EACjD,GAAIzM,EAAS,CACT,MAAMyY,EAAY,SAAS,cAAc,OAAO,EAC1CC,EAAe,SAAS,eAAe1Y,CAAO,EACpDyY,EAAU,YAAYC,CAAY,EAC9BtI,EAAW,WACXA,EAAW,aAAaqI,EAAWrI,EAAW,UAAU,EAGxDA,EAAW,YAAYqI,CAAS,CAExC,CACJ,CCtMO,eAAeE,GAAMtW,EAAMoK,EAAU,GAAI,CAC5C,KAAM,CAAE,MAAA8B,EAAO,OAAAC,CAAM,EAAKH,GAAahM,EAAMoK,CAAO,EAC9C2D,EAAc,MAAMgC,EAAU/P,EAAMoK,EAAS,EAAI,EACvD,aAAM+L,GAAcpI,EAAY3D,CAAO,EACvC,MAAMwJ,GAAY7F,EAAY3D,CAAO,EACrCyJ,GAAW9F,EAAY3D,CAAO,EACd,MAAM4C,GAAce,EAAY7B,EAAOC,CAAM,CAEjE,CACO,eAAeoK,GAASvW,EAAMoK,EAAU,GAAI,CAC/C,KAAM,CAAE,MAAA8B,EAAO,OAAAC,CAAM,EAAKH,GAAahM,EAAMoK,CAAO,EAC9C0C,EAAM,MAAMwJ,GAAMtW,EAAMoK,CAAO,EAC/BwC,EAAM,MAAMF,EAAYI,CAAG,EAC3BL,EAAS,SAAS,cAAc,QAAQ,EACxC+J,EAAU/J,EAAO,WAAW,IAAI,EAChCJ,EAAQjC,EAAQ,YAAcgC,GAAa,EAC3CqK,EAAcrM,EAAQ,aAAe8B,EACrCwK,EAAetM,EAAQ,cAAgB+B,EAC7C,OAAAM,EAAO,MAAQgK,EAAcpK,EAC7BI,EAAO,OAASiK,EAAerK,EAC1BjC,EAAQ,eACToC,GAAsBC,CAAM,EAEhCA,EAAO,MAAM,MAAQ,GAAGgK,CAAW,GACnChK,EAAO,MAAM,OAAS,GAAGiK,CAAY,GACjCtM,EAAQ,kBACRoM,EAAQ,UAAYpM,EAAQ,gBAC5BoM,EAAQ,SAAS,EAAG,EAAG/J,EAAO,MAAOA,EAAO,MAAM,GAEtD+J,EAAQ,UAAU5J,EAAK,EAAG,EAAGH,EAAO,MAAOA,EAAO,MAAM,EACjDA,CACX,CAWO,eAAekK,GAAO3W,EAAMoK,EAAU,GAAI,CAE7C,OADe,MAAMmM,GAASvW,EAAMoK,CAAO,GAC7B,UAAU,aAAcA,EAAQ,SAAW,CAAC,CAC9D,CCjCA,MAAMwM,EAAiB,IACjBC,EAAkB,IAClBC,GAAa,IACbC,GAAgB,GAChBC,GAAkB,IAEjB,SAASC,GAAoBC,EAA0C,CAC5E,IAAIC,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KAEX,UAAWC,KAAOL,EAChB,GAAIK,EAAI,OAAS,OAKf,GAJAJ,EAAO,KAAK,IAAIA,EAAMI,EAAI,CAAC,EAC3BH,EAAO,KAAK,IAAIA,EAAMG,EAAI,CAAC,EAC3BF,EAAO,KAAK,IAAIA,EAAME,EAAI,CAAC,EAC3BD,EAAO,KAAK,IAAIA,EAAMC,EAAI,CAAC,EACvBA,EAAI,WAAY,CAClB,MAAMC,EAAID,EAAI,WACdJ,EAAO,KAAK,IAAIA,EAAMK,EAAE,IAAI,EAC5BJ,EAAO,KAAK,IAAIA,EAAMI,EAAE,GAAG,EAC3BH,EAAO,KAAK,IAAIA,EAAMG,EAAE,KAAOA,EAAE,KAAK,EACtCF,EAAO,KAAK,IAAIA,EAAME,EAAE,MAAM,CAChC,UACSD,EAAI,OAAS,QAAUA,EAAI,SACpC,UAAWE,KAAYC,GAAmBH,EAAI,QAAQ,EACpD,SAAW,CAACvW,EAAGC,CAAC,IAAKwW,EACnBN,EAAO,KAAK,IAAIA,EAAMnW,CAAC,EACvBoW,EAAO,KAAK,IAAIA,EAAMnW,CAAC,EACvBoW,EAAO,KAAK,IAAIA,EAAMrW,CAAC,EACvBsW,EAAO,KAAK,IAAIA,EAAMrW,CAAC,EAM/B,MAAI,CAAC,SAASkW,CAAI,GAAK,CAAC,SAASC,CAAI,EAAU,KACxC,CAAE,KAAAD,EAAM,KAAAC,EAAM,KAAAC,EAAM,KAAAC,CAAA,CAC7B,CAEO,SAASK,GACdT,EACAU,EACAC,EACiB,CACjB,MAAMC,EAASb,GAAoBC,CAAW,EAC9C,GAAI,CAACY,EAAQ,OAAO,KAEpB,MAAMC,EAAO,KAAK,IAAIjB,GAAYc,EAAgBb,EAAa,EACzDiB,EAAO,KAAK,IAAIlB,GAAYe,EAAiBd,EAAa,EAEhE,IAAI/V,EAAI8W,EAAO,KAAOC,EAClB9W,EAAI6W,EAAO,KAAOE,EAClBC,EAAKH,EAAO,KAAOA,EAAO,KAAQC,EAAO,EACzCG,EAAKJ,EAAO,KAAOA,EAAO,KAAQE,EAAO,EAgB7C,OAdIC,EAAIrB,IACN5V,IAAM4V,EAAiBqB,GAAK,EAC5BA,EAAIrB,GAEFsB,EAAIrB,IACN5V,IAAM4V,EAAkBqB,GAAK,EAC7BA,EAAIrB,GAGN7V,EAAI,KAAK,IAAI,EAAGA,CAAC,EACjBC,EAAI,KAAK,IAAI,EAAGA,CAAC,EACjBgX,EAAI,KAAK,IAAIA,EAAGL,EAAgB5W,CAAC,EACjCkX,EAAI,KAAK,IAAIA,EAAGL,EAAiB5W,CAAC,EAE9BgX,GAAKL,EAAgBZ,IAAmBkB,GAAKL,EAAiBb,GACzD,KAGF,CACL,EAAG,KAAK,MAAMhW,CAAC,EACf,EAAG,KAAK,MAAMC,CAAC,EACf,MAAO,KAAK,MAAMgX,CAAC,EACnB,OAAQ,KAAK,MAAMC,CAAC,CAAA,CAExB,CAEO,SAASC,GAAW5D,EAA2BrV,EAAmC,CACvF,MAAMkZ,EAAU,SAAS,cAAc,QAAQ,EAC/CA,EAAQ,MAAQlZ,EAAK,MACrBkZ,EAAQ,OAASlZ,EAAK,OACtB,MAAMwQ,EAAM0I,EAAQ,WAAW,IAAI,EACnC,OAAI1I,GACFA,EAAI,UAAU6E,EAAQrV,EAAK,EAAGA,EAAK,EAAGA,EAAK,MAAOA,EAAK,OAAQ,EAAG,EAAGA,EAAK,MAAOA,EAAK,MAAM,EAEvFkZ,CACT,CC1FA,eAAsBC,GAAkBnB,EAA4B,GAA0B,CAC5F,GAAI,CACF,MAAMoB,EAAiBC,GAAkB,SAAS,IAAI,EAChDC,EAAU,MAAM7B,GAAO,SAAS,KAAM,CAC1C,QAAS,IACT,WAAY,EACZ,gBAAiB,UACjB,UAAW,GACX,cAAe,GACf,OAAS3W,GACH,EAAAA,aAAgB,aAAeA,EAAK,KAAO,kBAEjD,CACD,EACD,GAAIkX,EAAY,OAAS,EAAG,CAC1B,MAAMuB,EAAY,MAAMC,GAAgBF,EAAStB,EAAaoB,CAAc,EAC5E,GAAIG,EAAW,OAAOA,CACxB,CACA,OAAOE,GAAcH,CAAO,CAC9B,MAAQ,CACN,OAAO,IACT,CACF,CAEA,eAAeE,GACbF,EACAtB,EACAoB,EACsB,CACtB,MAAM7L,EAAS,SAAS,cAAc,QAAQ,EACxCiD,EAAMjD,EAAO,WAAW,IAAI,EAClC,GAAI,CAACiD,EAAK,OAAO,KAEjB,MAAM+D,EAAQ,MAAMmF,GAAUJ,CAAO,EACrC,GAAI,CAAC/E,EAAO,OAAO,KAEnBhH,EAAO,MAAQgH,EAAM,cAAgB,OAAO,WAC5ChH,EAAO,OAASgH,EAAM,eAAiB,OAAO,YAC9C/D,EAAI,UAAU+D,EAAO,EAAG,CAAC,EACzB,MAAMoF,EAASpM,EAAO,MAAQ6L,EAAe,MACvCQ,EAASrM,EAAO,OAAS6L,EAAe,OAE9C,IAAIS,EAAW,EACf,UAAWhW,KAAcmU,EACnBnU,EAAW,OAAS,QAAUA,EAAW,SAC3CiW,GAAWtJ,EAAK3M,EAAW,SAAUuV,EAAgBO,EAAQC,CAAM,EAC1D/V,EAAW,OAAS,OAC7BkW,GACEvJ,GACC3M,EAAW,EAAIuV,EAAe,MAAQO,GACtC9V,EAAW,EAAIuV,EAAe,KAAOQ,EACtC,EAAEC,CAAA,EAKR,MAAMG,EAAWvB,GAAkBT,EAAa,OAAO,WAAY,OAAO,WAAW,EACrF,GAAIgC,EAAU,CACZ,MAAMlU,EAAO,KAAK,IAAI,EAAG,KAAK,OAAOkU,EAAS,EAAIZ,EAAe,MAAQO,CAAM,CAAC,EAC1E5T,EAAM,KAAK,IAAI,EAAG,KAAK,OAAOiU,EAAS,EAAIZ,EAAe,KAAOQ,CAAM,CAAC,EACxEK,EAAQ,KAAK,IAAI1M,EAAO,MAAO,KAAK,OAAOyM,EAAS,EAAIA,EAAS,MAAQZ,EAAe,MAAQO,CAAM,CAAC,EACvGO,EAAS,KAAK,IAAI3M,EAAO,OAAQ,KAAK,OAAOyM,EAAS,EAAIA,EAAS,OAASZ,EAAe,KAAOQ,CAAM,CAAC,EACzGO,EAAS,CACb,EAAGrU,EACH,EAAGC,EACH,MAAOkU,EAAQnU,EACf,OAAQoU,EAASnU,CAAA,EAEnB,OAAOqU,GAAiBnB,GAAW1L,EAAQ4M,CAAM,CAAC,CACpD,CAEA,OAAOC,GAAiB7M,CAAM,CAChC,CAEA,SAASuM,GACPtJ,EACA6J,EACAjB,EACAO,EACAC,EACM,CACNpJ,EAAI,KAAA,EACJA,EAAI,YAAcvO,EAClBuO,EAAI,UAAY,IAChBA,EAAI,QAAU,QACdA,EAAI,SAAW,QACfA,EAAI,YAAcrO,EAAW,GAAI,EACjCqO,EAAI,cAAgB,EACpBA,EAAI,WAAa,EACjB,UAAW5N,KAAU4V,GAAmB6B,CAAQ,EAC9C,GAAIzX,EAAO,SAAW,EACtB,CAAA4N,EAAI,UAAA,EACJA,EAAI,QACD5N,EAAO,CAAC,EAAE,CAAC,EAAIwW,EAAe,MAAQO,GACtC/W,EAAO,CAAC,EAAE,CAAC,EAAIwW,EAAe,KAAOQ,CAAA,EAExC,QAASxW,EAAI,EAAGA,EAAIR,EAAO,OAAQQ,IACjCoN,EAAI,QACD5N,EAAOQ,CAAC,EAAE,CAAC,EAAIgW,EAAe,MAAQO,GACtC/W,EAAOQ,CAAC,EAAE,CAAC,EAAIgW,EAAe,KAAOQ,CAAA,EAG1CpJ,EAAI,OAAA,EAENA,EAAI,QAAA,CACN,CAEA,SAAS6I,GAAkBvY,EAAmC,CAC5D,MAAMd,EAAOc,EAAK,sBAAA,EACZtC,EAAQ,OAAO,iBAAiBsC,CAAI,EACpCwZ,EAAc,WAAW9b,EAAM,eAAe,EAAI,WAAWA,EAAM,gBAAgB,EACnF+b,EAAe,WAAW/b,EAAM,cAAc,EAAI,WAAWA,EAAM,iBAAiB,EAE1F,MAAO,CACL,KAAMwB,EAAK,KACX,IAAKA,EAAK,IACV,MAAOc,EAAK,aAAe,OAAO,SAASwZ,CAAW,EAAIA,EAAc,IAAM,OAAO,WACrF,OAAQxZ,EAAK,cAAgB,OAAO,SAASyZ,CAAY,EAAIA,EAAe,IAAM,OAAO,WAAA,CAE7F,CAEA,SAASR,GAAQvJ,EAA+B1O,EAAWC,EAAWkU,EAAqB,CACzFzF,EAAI,KAAA,EACJA,EAAI,YAAcrO,EAAW,GAAI,EACjCqO,EAAI,cAAgB,EACpBA,EAAI,WAAa,EACjBA,EAAI,UAAYvO,EAChBuO,EAAI,UAAA,EACJA,EAAI,IAAI1O,EAAGC,EAAG,GAAI,EAAG,KAAK,GAAK,CAAC,EAChCyO,EAAI,KAAA,EACJA,EAAI,YAAc,cAClBA,EAAI,UAAY,EAChBA,EAAI,YAAc,UAClBA,EAAI,OAAA,EACJA,EAAI,UAAY,UAChBA,EAAI,KAAO,YAAYnO,EAAU,GACjCmO,EAAI,UAAY,SAChBA,EAAI,aAAe,SACnBA,EAAI,SAAS,OAAOyF,CAAK,EAAGnU,EAAGC,CAAC,EAChCyO,EAAI,QAAA,CACN,CAIO,SAASgI,GAAmB6B,EAAkD,CACnF,MAAMG,EAA4C,CAAA,EAClD,IAAIlZ,EAA0C,KAC9C,MAAMmZ,EAASJ,EAAS,MAAM,2BAA2B,GAAK,CAAA,EAC9D,UAAWnT,KAASuT,EAAQ,CAC1B,KAAM,CAAC3Y,EAAGC,CAAC,EAAImF,EAAM,MAAM,CAAC,EAAE,KAAA,EAAO,MAAM,KAAK,EAAE,IAAI,MAAM,EACxD,OAAO,MAAMpF,CAAC,GAAK,OAAO,MAAMC,CAAC,IACjCmF,EAAM,CAAC,IAAM,KACf5F,EAAU,CAAC,CAACQ,EAAGC,CAAC,CAAC,EACjByY,EAAU,KAAKlZ,CAAO,GACbA,GACTA,EAAQ,KAAK,CAACQ,EAAGC,CAAC,CAAC,EAEvB,CACA,OAAOyY,CACT,CAEA,SAASd,GAAUJ,EAAmD,CACpE,OAAO,IAAI,QAAQ1Q,GAAW,CAC5B,MAAM2L,EAAQ,IAAI,MAClBA,EAAM,OAAS,IAAM3L,EAAQ2L,CAAK,EAClCA,EAAM,QAAU,IAAM3L,EAAQ,IAAI,EAClC2L,EAAM,IAAM+E,CACd,CAAC,CACH,CAEA,SAASc,GAAiB7M,EAAiD,CACzE,OAAO,IAAI,QAAQ3E,GAAW,CAC5B,GAAI,CACF2E,EAAO,OAAO9F,GAAQmB,EAAQnB,CAAI,EAAG,aAAc,GAAI,CACzD,MAAQ,CACNmB,EAAQ,IAAI,CACd,CACF,CAAC,CACH,CAEA,SAAS6Q,GAAcH,EAAuB,CAC5C,KAAM,CAACoB,EAAQ1F,CAAI,EAAIsE,EAAQ,MAAM,GAAG,EAClCqB,EAAOD,EAAO,MAAM,SAAS,IAAI,CAAC,GAAK,YACvCE,EAAS,KAAK5F,CAAI,EAClBrL,EAAQ,IAAI,WAAWiR,EAAO,MAAM,EAC1C,QAASxX,EAAI,EAAGA,EAAIwX,EAAO,OAAQxX,IACjCuG,EAAMvG,CAAC,EAAIwX,EAAO,WAAWxX,CAAC,EAEhC,OAAO,IAAI,KAAK,CAACuG,CAAK,EAAG,CAAE,KAAMgR,EAAM,CACzC,CCtMA,MAAME,EAAY,CAAlB,aAAA,CACE,KAAQ,cAAgB,IACxB,KAAQ,gBAA8C,KACtD,KAAQ,iBAA+C,KACvD,KAAQ,iBAAgE,KACxE,KAAQ,OAAS,EAAA,CAEjB,UAAUC,EAAqC,CAC7C,YAAK,UAAU,IAAIA,CAAQ,EAC3B,KAAK,KAAA,EACE,IAAM,CACX,KAAK,UAAU,OAAOA,CAAQ,EAC1B,KAAK,UAAU,OAAS,QAAQ,OAAA,CACtC,CACF,CAEQ,MAAa,CACf,KAAK,SACT,KAAK,OAAS,GAEd,KAAK,gBAAkB,OAAO,QAC9B,KAAK,iBAAmB,CAACpQ,EAAK2K,EAAQ0F,EAAMC,EAAKxU,KAC/C,KAAK,KAAK,CAAE,QAAS,OAAOkE,CAAG,EAAG,OAAA2K,EAAQ,KAAA0F,EAAM,IAAAC,EAAK,MAAAxU,EAAO,EACxD,KAAK,gBACA,KAAK,gBAAgB,KAAK,OAAQkE,EAAK2K,EAAQ0F,EAAMC,EAAKxU,CAAK,EAEjE,IAET,OAAO,QAAU,KAAK,iBAEtB,KAAK,iBAAoBzG,GAA6B,CACpD,MAAMkb,EAASlb,EAAE,kBAAkB,MAAQA,EAAE,OAAO,QAAU,OAAOA,EAAE,MAAM,EAC7E,KAAK,KAAK,CAAE,QAAS,wBAAwBkb,CAAM,GAAI,CACzD,EACA,OAAO,iBAAiB,qBAAsB,KAAK,gBAAgB,EACrE,CAEQ,QAAe,CAChB,KAAK,SACV,KAAK,OAAS,GAGV,OAAO,UAAY,KAAK,mBAC1B,OAAO,QAAU,KAAK,iBAExB,KAAK,iBAAmB,KACxB,KAAK,gBAAkB,KACnB,KAAK,mBACP,OAAO,oBAAoB,qBAAsB,KAAK,gBAAgB,EACtE,KAAK,iBAAmB,MAE5B,CAEQ,KAAK3R,EAA+B,CAC1C,UAAWwR,KAAY,KAAK,UAAWA,EAASxR,CAAK,CACvD,CACF,CAEO,MAAM4R,GAAc,IAAIL,GClEzBM,GAAqB,GAEpB,MAAMC,EAAsB,CAA5B,aAAA,CACL,KAAQ,OAAmB,CAAA,EAC3B,KAAQ,YAAmC,IAAA,CAE3C,OAAc,CACR,KAAK,cACT,KAAK,YAAcF,GAAY,UAAWnb,GAAM,KAAK,OAAOA,CAAC,CAAC,EAChE,CAEQ,OAAOA,EAA2B,CACxC,MAAMsb,EAAWtb,EAAE,MAAQ,KAAO,KAAKA,EAAE,IAAI,IAAIA,EAAE,KAAO,CAAC,IAAM,GACjE,KAAK,SAAS,GAAGA,EAAE,OAAO,GAAGsb,CAAQ,EAAE,CACzC,CAEQ,SAAS3Q,EAAmB,CAC9B,KAAK,OAAO,QAAUyQ,IACrB,KAAK,OAAO,SAASzQ,CAAG,GAC3B,KAAK,OAAO,KAAKA,CAAG,CAExB,CAEA,WAAsB,CACpB,MAAO,CAAC,GAAG,KAAK,MAAM,CACxB,CAEA,MAAa,CACX,KAAK,cAAA,EACL,KAAK,YAAc,IACrB,CACF,CCrBA,MAAM4Q,MAAgB,IAEtB,IAAIC,EAA+C,KAC/CC,EAAqD,KACrDC,EAAkD,KAClDC,EAAwD,KACxDC,EAAuC,KAIpC,SAASC,GAAoBd,EAAmC,CACrEQ,EAAU,IAAIR,CAAQ,EACtBe,GAAA,EAEA,IAAIC,EAAW,GACf,MAAO,IAAM,CACPA,IACJA,EAAW,GACXR,EAAU,OAAOR,CAAQ,EACrBQ,EAAU,OAAS,GAAGS,GAAA,EAC5B,CACF,CAEA,SAASC,GAAe,CAEtB,UAAWlB,IAAY,CAAC,GAAGQ,CAAS,EAClC,GAAI,CAAER,EAAA,CAAW,MAAQ,CAA2C,CAExE,CAEA,SAASe,IAAgB,CACvB,GAAIJ,EAAoB,OAExBE,EAAkB,IAAMK,EAAA,EACxB,OAAO,iBAAiB,WAAYL,CAAe,EAKnDJ,EAAkB,QAAQ,UAC1BC,EAAqB,QAAQ,aAC7B,MAAMS,EAAWV,EACXW,EAAcV,EAEpBC,EAAqB,SAAUzG,EAAemH,EAAgB7T,EAA2B,CACvF2T,EAAS,KAAK,QAASjH,EAAMmH,EAAQ7T,CAAG,EACxC0T,EAAA,CACF,EACAN,EAAwB,SAAU1G,EAAemH,EAAgB7T,EAA2B,CAC1F4T,EAAY,KAAK,QAASlH,EAAMmH,EAAQ7T,CAAG,EAC3C0T,EAAA,CACF,EACA,QAAQ,UAAYP,EACpB,QAAQ,aAAeC,CACzB,CAEA,SAASK,IAAkB,CACrBJ,IACF,OAAO,oBAAoB,WAAYA,CAAe,EACtDA,EAAkB,MAIhBJ,GAAmB,QAAQ,YAAcE,IAC3C,QAAQ,UAAYF,GAElBC,GAAsB,QAAQ,eAAiBE,IACjD,QAAQ,aAAeF,GAEzBD,EAAkB,KAClBC,EAAqB,KACrBC,EAAqB,KACrBC,EAAwB,IAC1B,CC/EA,MAAMU,GAAkB,GAEjB,MAAMC,EAAoB,CAS/B,aAAc,CARd,KAAQ,YAA4B,CAAA,EACpC,KAAQ,OAAS,GACjB,KAAQ,kBAAyC,KAGjD,KAAQ,sBAA6C,KACrD,KAAQ,QAAU,GAGhB,KAAK,kBAAqBtc,GAAkB,KAAK,YAAYA,CAAC,EAC9D,KAAK,mBAAsBA,GAAa,KAAK,aAAaA,CAAC,CAC7D,CAEA,OAAc,CACR,KAAK,SACT,KAAK,OAAS,GACd,KAAK,QAAU,SAAS,KACxB,SAAS,iBAAiB,QAAS,KAAK,kBAAmB,CAAE,QAAS,GAAM,QAAS,GAAM,EAC3F,SAAS,iBAAiB,SAAU,KAAK,mBAAoB,CAAE,QAAS,GAAM,QAAS,GAAM,EAC7F,KAAK,kBAAoBmb,GAAY,UAAWnb,GAAM,KAAK,YAAYA,CAAC,CAAC,EACzE,KAAK,sBAAwB6b,GAAoB,IAAM,KAAK,kBAAkB,EAChF,CAEA,MAAa,CACN,KAAK,SACV,KAAK,OAAS,GACd,SAAS,oBAAoB,QAAS,KAAK,kBAAmB,EAAI,EAClE,SAAS,oBAAoB,SAAU,KAAK,mBAAoB,EAAI,EACpE,KAAK,oBAAA,EACL,KAAK,kBAAoB,KACzB,KAAK,wBAAA,EACL,KAAK,sBAAwB,KAC/B,CAEA,gBAA+B,CAC7B,MAAO,CAAC,GAAG,KAAK,WAAW,CAC7B,CAEQ,IAAIU,EAAyB,CACnC,KAAK,YAAY,KAAKA,CAAK,EACvB,KAAK,YAAY,OAASF,IAC5B,KAAK,YAAY,MAAA,CAErB,CAEQ,YAAYrc,EAAqB,CACvC,MAAMwc,EAASxc,EAAE,OACjB,GAAKwc,GACD,CAAAxY,EAAgBwY,CAAM,EAE1B,GAAI,CACF,KAAK,IAAI,CACP,KAAM,KACN,SAAU,WACV,UAAW,KAAK,IAAA,EAChB,QAAS/b,EAAe+b,CAAM,EAC9B,KAAM,CAAE,SAAUnb,GAAemb,CAAM,CAAA,CAAE,CAC1C,CACH,MAAQ,CAAuC,CACjD,CAEQ,aAAaxc,EAAgB,CACnC,MAAMwc,EAASxc,EAAE,OACjB,GAAKwc,GACD,CAAAxY,EAAgBwY,CAAM,EAE1B,GAAI,CACF,MAAMjR,EAAQiR,EACRC,EAAQlR,EAAM,MAAQA,EAAM,aAAeiR,EAAO,aAAa,YAAY,GAAKA,EAAO,QAC7F,KAAK,IAAI,CACP,KAAM,KACN,SAAU,WACV,UAAW,KAAK,IAAA,EAChB,QAASC,EACT,KAAM,CAAE,MAAAA,CAAA,CAAM,CACf,CACH,MAAQ,CAAuC,CACjD,CAEQ,YAAYzc,EAA2B,CAC7C,KAAK,IAAI,CACP,KAAM,UACN,SAAU,gBACV,UAAW,KAAK,IAAA,EAChB,QAASA,EAAE,QACX,KAAM,CAAE,QAASA,EAAE,OAAA,CAAQ,CAC5B,CACH,CAEQ,kBAAyB,CAC/B,GAAI,CAAC,KAAK,OAAQ,OAClB,MAAM0c,EAAO,KAAK,QACZC,EAAK,SAAS,KAChBD,IAASC,IACb,KAAK,QAAUA,EACf,KAAK,IAAI,CACP,KAAM,aACN,SAAU,aACV,UAAW,KAAK,IAAA,EAChB,QAAS,GAAGD,CAAI,MAAMC,CAAE,GACxB,KAAM,CAAE,KAAAD,EAAM,GAAAC,CAAA,CAAG,CAClB,EACH,CAEF,CCnGA,MAAMC,GAAc,wBAWpB,IAAIC,EAAuC,KAKpC,SAASC,GAAyC,CACvD,GAAI,CACF,MAAM3T,EAAM,OAAO,eAAe,QAAQyT,EAAW,EACrD,OACOG,EADF5T,EACY,KAAK,MAAMA,CAAG,EADJ0T,CACK,CAClC,MAAQ,CACN,OAAOE,EAAUF,CAAW,CAC9B,CACF,CAEO,SAASG,GAAqBC,EAA+B,CAClE,MAAMC,EAAaH,EAAUE,CAAK,EAClCJ,EAAcK,EACd,GAAI,CACF,OAAO,eAAe,QAAQN,GAAa,KAAK,UAAUM,CAAU,CAAC,CACvE,MAAQ,CAER,CACF,CAEO,SAASC,IAAkC,CAChD,OAAOL,IAAuB,eAChC,CAKO,SAASM,IAAiC,CAC/CJ,GAAqB,CAAE,GAAGF,EAAA,EAAwB,gBAAiB,GAAM,CAC3E,CAWA,SAASC,EAAUtT,EAAkC,CACnD,MAAMN,EAAOM,GAAS,CAAA,EACtB,MAAO,CACL,cAAe,MAAM,QAAQN,EAAI,aAAa,EAC1CA,EAAI,cAAc,OAAQkU,GAAmB,OAAOA,GAAM,QAAQ,EAClE,CAAA,EACJ,cAAe,OAAOlU,EAAI,eAAkB,SAAWA,EAAI,cAAgB,EAC3E,cAAe,MAAM,QAAQA,EAAI,aAAa,EAC1CA,EAAI,cAAc,OAAQmU,GAAmB,OAAOA,GAAM,QAAQ,EAAE,MAAM,GAAoB,EAC9F,CAAA,EACJ,gBAAiBnU,EAAI,kBAAoB,EAAA,CAE7C,CCzDA,MAAMoU,GAAuB,EACvBC,GAAuB,IACvBC,GAAsB,EACtBC,GAAsB,IACtBC,GAAsB,IACtBC,GAA0B,IAC1BC,GAA4B,IAE5BC,OAAuB,IAAI,CAC/B,IAAK,SAAU,QAAS,SAAU,WAAY,QAAS,UAAW,SACpE,CAAC,EAEKC,OAAwB,IAAI,CAChC,SAAU,OAAQ,WAAY,QAAS,MAAO,WAAY,SAC1D,SAAU,UAAW,WAAY,UAAW,SAAU,YACxD,CAAC,EAEKC,GAAsB,CAC1B,MAAO,MAAO,YAAa,iBAC3B,eAAgB,uBAClB,EAEaC,EAAN,MAAMA,CAAoB,CAuB/B,YAAYC,EAAkD,CAtB9D,KAAQ,aAA8B,CAAA,EAGtC,KAAQ,kBAAyC,KACjD,KAAQ,OAAS,GACjB,KAAQ,WAAa,EACrB,KAAQ,eAAiB,EACzB,KAAQ,cAAgB,EAGxB,KAAQ,cAA0B,CAAA,EAClC,KAAQ,sBAA6C,KACrD,KAAQ,sBAA6C,KACrD,KAAQ,iBAAmB,GAC3B,KAAQ,mBAAkD,KAC1D,KAAQ,oBAAmD,KAC3D,KAAQ,sBAAwB,QAChC,KAAQ,kBAAoB,IAC5B,KAAQ,YAAuC,KAC/C,KAAQ,iBAAmB,EAC3B,KAAQ,eAAiB,GAGvB,KAAK,cAAgBA,EACrB,KAAK,kBAAqB,GAAkB,KAAK,YAAY,CAAC,CAChE,CAEA,OAAc,CACR,KAAK,SACT,KAAK,OAAS,GACd,KAAK,aAAA,EACL,SAAS,iBAAiB,QAAS,KAAK,kBAAmB,EAAI,EAC/D,KAAK,kBAAoB/C,GAAY,UAAWgD,GAAO,CACrD,KAAK,YACP,CAAC,EAED,KAAK,wBAAA,EACL,KAAK,kBAAA,EACL,KAAK,eAAA,EACP,CAEA,MAAa,CACN,KAAK,SACV,KAAK,OAAS,GACd,SAAS,oBAAoB,QAAS,KAAK,kBAAmB,EAAI,EAClE,KAAK,oBAAA,EACL,KAAK,kBAAoB,KACzB,KAAK,aAAe,CAAA,EAEpB,KAAK,uBAAA,EACL,KAAK,iBAAA,EACL,KAAK,cAAc,MAAA,EAEnB,KAAK,sBAAA,EACP,CAEQ,yBAAgC,CACtC,KAAK,sBAAwBtC,GAAoB,IAAM,KAAK,kBAAkB,EAS9E,KAAK,sBAAwB,IAAM,KAAK,sBAAA,EACxC,OAAO,iBAAiB,eAAgB,KAAK,qBAAqB,EAClE,OAAO,iBAAiB,WAAY,KAAK,qBAAqB,CAChE,CAEQ,wBAA+B,CACrC,KAAK,wBAAA,EACL,KAAK,sBAAwB,KAC7B,KAAK,cAAgB,CAAA,EAEjB,KAAK,wBACP,OAAO,oBAAoB,eAAgB,KAAK,qBAAqB,EACrE,OAAO,oBAAoB,WAAY,KAAK,qBAAqB,EACjE,KAAK,sBAAwB,MAE/B,KAAK,iBAAmB,EAC1B,CAEQ,uBAA8B,CACpC,KAAK,iBAAmB,KAAK,IAAA,CAC/B,CAMQ,cAAqB,CAC3B,MAAMuC,EAAStB,EAAA,EACf,KAAK,cAAgBsB,EAAO,cAC5B,KAAK,cAAgBA,EAAO,cAC5B,KAAK,cAAgB,IAAI,IAAIA,EAAO,aAAa,CACnD,CAEQ,cAAqB,CAC3B,MAAMA,EAAStB,EAAA,EACfE,GAAqB,CACnB,GAAGoB,EACH,cAAe,KAAK,cACpB,cAAe,KAAK,cACpB,cAAe,CAAC,GAAG,KAAK,aAAa,CAAA,CACtC,CACH,CAEQ,mBAA0B,CAChC,KAAK,mBAAsBpe,GAAa,KAAK,iBAAiBA,CAAC,EAC/D,KAAK,oBAAuBA,GAAa,KAAK,kBAAkBA,CAAC,EACjE,SAAS,iBAAiB,SAAU,KAAK,mBAAoB,EAAI,EACjE,SAAS,iBAAiB,UAAW,KAAK,oBAAqB,EAAI,CACrE,CAEQ,kBAAyB,CAC3B,KAAK,qBACP,SAAS,oBAAoB,SAAU,KAAK,mBAAoB,EAAI,EACpE,KAAK,mBAAqB,MAExB,KAAK,sBACP,SAAS,oBAAoB,UAAW,KAAK,oBAAqB,EAAI,EACtE,KAAK,oBAAsB,KAE/B,CAEQ,YAAYA,EAAqB,CACvC,MAAMwc,EAASxc,EAAE,OAGjB,GAFI,CAACwc,GAEDxY,EAAgBwY,CAAM,EAAG,OAC7B,KAAK,sBAAsBA,CAAM,EAEjC,MAAM6B,EAAM,KAAK,IAAA,EACjB,KAAK,aAAa,KAAK,CAAE,OAAA7B,EAAQ,KAAM6B,EAAK,EAE5C,MAAMC,EAASD,EAAMb,GAIrB,GAHA,KAAK,aAAe,KAAK,aAAa,OAAOjF,GAAKA,EAAE,KAAO+F,CAAM,EAExC,KAAK,aAAa,OAAO/F,GAAKA,EAAE,SAAWiE,CAAM,EACrD,QAAUe,GAAsB,CACnD,KAAK,aAAe,CAAA,EACpB,KAAK,iBAAiB,CACpB,OAAQ,aACR,OAAQgB,EAAgB/B,CAAM,EAC9B,UAAW6B,CAAA,CACZ,EACD,MACF,CAEK,KAAK,cAAc7B,CAAM,IAC5B,KAAK,iBACD,KAAK,gBAAkB,GAAK,KAAK,WAAa,IAChD,KAAK,eAAiB,EACtB,KAAK,WAAa,EAClB,KAAK,YAAY,CACf,OAAQ,aACR,OAAQ+B,EAAgB/B,CAAM,EAC9B,UAAW6B,CAAA,CACZ,IAIL,KAAK,kBAAkB7B,EAAQ6B,CAAG,CACpC,CAEQ,kBAAyB,CAC/B,MAAMA,EAAM,KAAK,IAAA,EACjB,KAAK,sBAAA,EACL,KAAK,cAAc,KAAKA,CAAG,EAC3B,MAAMC,EAASD,EAAMX,GACrB,KAAK,cAAgB,KAAK,cAAc,OAAOL,GAAKA,EAAIiB,CAAM,EAC1D,KAAK,cAAc,QAAUb,KAC/B,KAAK,cAAgB,CAAA,EACrB,KAAK,YAAY,CACf,OAAQ,mBACR,UAAWY,CAAA,CACZ,GAEH,KAAK,aAAA,EACL,WAAW,IAAM,CACX,KAAK,QAAQ,KAAK,eAAA,CACxB,EAAGR,EAAyB,CAC9B,CAEQ,iBAAiB7d,EAAgB,CACvC,MAAMwH,EAAOxH,EAAE,OACTwH,aAAgB,kBAClBxD,EAAgBwD,CAAI,IAExB,KAAK,sBAAsBA,CAAI,EAE/B,WAAW,IAAM,CACV,KAAK,QACNA,EAAK,cAAc,oCAAoC,GACzD,KAAK,YAAY,CACf,OAAQ,eACR,OAAQ+W,EAAgB/W,CAAI,EAC5B,UAAW,KAAK,IAAA,CAAI,CACrB,CAEL,EAAGmW,EAAmB,GACxB,CAEQ,sBAAsBnB,EAAuB,CACnD,MAAMgC,EAAUhC,EAAO,QAAQ,eAAe,GACxCgC,aAAmB,mBAAqBA,aAAmB,oBAC7DA,EAAQ,OAAS,UAAYA,EAAQ,OAAS,SAC9C,CAACA,EAAQ,MAAQxa,EAAgBwa,EAAQ,IAAI,GAEjD,KAAK,sBAAsBA,EAAQ,IAAI,EACzC,CAEQ,sBAAsBhX,EAA6B,CACzD,KAAK,kBAAkB,IAAIA,CAAI,EAC/B,WAAW,IAAM,CACf,KAAK,kBAAkB,OAAOA,CAAI,CACpC,EAAGmW,EAAmB,CACxB,CAEQ,kBAAkB3d,EAAgB,CACxC,MAAMnB,EAAKmB,EAAE,OAEb,GADI,CAACnB,GACDmF,EAAgBnF,CAAE,EAAG,OACzB,MAAM2I,EAAO3I,EAAG,QAAQ,MAAM,EAC1B,CAAC2I,GAAQ,CAAC,KAAK,kBAAkB,IAAIA,CAAI,GAC7C,KAAK,YAAY,CACf,OAAQ,eACR,OAAQ+W,EAAgB/W,CAAI,EAC5B,UAAW,KAAK,IAAA,CAAI,CACrB,CACH,CAEQ,gBAAuB,CAC7B,MAAMe,EAAM,SAAS,KACrB,GAAI,KAAK,cAAc,IAAIA,CAAG,EAAG,OAEjC,MAAMvH,EAAQ,SAAS,MAAM,YAAA,EAC7B,GAAIgd,GAAoB,KAAKza,GAAKvC,EAAM,SAASuC,CAAC,CAAC,EAAG,CACpD,KAAK,cAAc,IAAIgF,CAAG,EAC1B,KAAK,iBAAiB,CACpB,OAAQ,aACR,OAAQ,SAAS,MACjB,UAAW,KAAK,IAAA,CAAI,CACrB,EACD,MACF,CAEA,MAAMkW,EAAa,SAAS,iBAC1B,kFAAA,EAEF,UAAW5f,KAAM4f,EAAY,CAC3B,MAAMxd,EAAOpC,EAAG,aAAe,GAC/B,GAAIoC,EAAK,OAAS,KAAO+c,GAAoB,KAAKza,GAAKtC,EAAK,YAAA,EAAc,SAASsC,CAAC,CAAC,EAAG,CACtF,KAAK,cAAc,IAAIgF,CAAG,EAC1B,KAAK,iBAAiB,CACpB,OAAQ,aACR,OAAQtH,EAAK,KAAA,EAAO,MAAM,EAAG,EAAE,EAC/B,UAAW,KAAK,IAAA,CAAI,CACrB,EACD,MACF,CACF,CACF,CAKQ,kBAAkBub,EAAiBkC,EAAyB,CAC7D,KAAK,iBAAiBlC,CAAM,IAEjC,KAAK,mBACL,KAAK,kBAAA,EAEL,WAAW,IAAM,CACf,KAAK,mBACL,MAAMmC,EAAU,KAAK,gBAAkBD,EAGjCE,EAAY,KAAK,kBAAoBF,EACvC,KAAK,mBAAqB,GAAG,KAAK,sBAAA,EAElC,CAACC,GAAW,CAACC,GAAa,KAAK,QACjC,KAAK,YAAY,CACf,OAAQ,iBACR,OAAQL,EAAgB/B,CAAM,EAC9B,UAAWkC,CAAA,CACZ,CAEL,EAAGd,EAAuB,EAC5B,CAEQ,mBAA0B,CAC5B,KAAK,cACT,KAAK,YAAc,IAAI,iBAAiB,IAAM,CAC5C,KAAK,eAAiB,KAAK,IAAA,CAC7B,CAAC,EACD,KAAK,YAAY,QAAQ,SAAS,KAAM,CACtC,UAAW,GACX,QAAS,GACT,WAAY,GACZ,cAAe,EAAA,CAChB,EACH,CAEQ,uBAA8B,CACpC,KAAK,aAAa,WAAA,EAClB,KAAK,YAAc,IACrB,CAEQ,iBAAiB/e,EAAsB,CAE7C,GADc,OAAO,iBAAiBA,CAAE,EAC9B,SAAW,UAAW,MAAO,GAEvC,GAAIA,EAAG,UACL,UAAWggB,KAAOhgB,EAAG,UAAW,CAC9B,MAAMigB,EAAQD,EAAI,YAAA,EAClB,GAAIC,EAAM,SAAS,KAAK,GAAKA,EAAM,SAAS,QAAQ,EAAG,MAAO,EAChE,CAGF,MAAO,EACT,CAEQ,cAAcjgB,EAAsB,CAC1C,GAAIif,GAAiB,IAAIjf,EAAG,OAAO,EAAG,MAAO,GAE7C,MAAMkgB,EAAOlgB,EAAG,aAAa,MAAM,EAUnC,MATI,GAAAkgB,GAAQhB,GAAkB,IAAIgB,CAAI,GAElClgB,EAAG,aAAa,SAAS,GAAKA,EAAG,aAAa,UAAU,GACvDA,EAAmB,kBAAoB,QAE9B,OAAO,iBAAiBA,CAAE,EAC9B,SAAW,WAENA,EAAG,QAAQ,kDAAkD,EAI9E,CAGQ,YAAY0K,EAA+B,CACjD,MAAM8U,EAAM,KAAK,IAAA,EACbA,EAAM,KAAK,gBACf,KAAK,cAAgBA,EAAMJ,EAAoB,YAC/C,KAAK,aAAA,EACL,KAAK,cAAc1U,CAAK,EAC1B,CAEQ,iBAAiBA,EAA+B,CACtD,KAAK,cAAgB,KAAK,IAAA,EAAQ0U,EAAoB,YACtD,KAAK,aAAA,EACL,KAAK,cAAc1U,CAAK,CAC1B,CACF,EA7VE0U,EAAwB,YAAc,IATjC,IAAMe,EAANf,EAwWP,SAASM,EAAgB1f,EAAqB,CAC5C,MAAMF,EAAME,EAAG,QAAQ,YAAA,EACjBuT,EAAKvT,EAAG,GAAK,IAAIA,EAAG,EAAE,GAAK,GAC3BggB,EAAMhgB,EAAG,WAAa,OAAOA,EAAG,WAAc,SAChD,IAAMA,EAAG,UAAU,OAAO,MAAM,KAAK,EAAE,MAAM,EAAG,CAAC,EAAE,KAAK,GAAG,EAC3D,GACEoC,EAAOpC,EAAG,aAAa,KAAA,EAAO,MAAM,EAAG,EAAE,GAAK,GACpD,MAAO,IAAIF,CAAG,GAAGyT,CAAE,GAAGyM,CAAG,IAAI5d,EAAO,KAAKA,CAAI,IAAM,EAAE,EACvD,CCtZO,SAASge,IAAkC,CAChD,MAAO,CACL,SAAU,OAAO,SAAS,KAC1B,WAAY,UAAU,UACtB,QAASC,GAAA,EACT,GAAIC,GAAA,EACJ,aAAc,OAAO,OAAO,MAC5B,cAAe,OAAO,OAAO,MAAA,CAEjC,CAEA,SAASD,IAAwB,CAC/B,MAAME,EAAK,UAAU,UACrB,MAAI,QAAQ,KAAKA,CAAE,EAAU,QAAQA,EAAG,MAAM,YAAY,IAAI,CAAC,GAAK,EAAE,GAClE,QAAQ,KAAKA,CAAE,EAAU,SAASA,EAAG,MAAM,YAAY,IAAI,CAAC,GAAK,EAAE,GACnE,WAAW,KAAKA,CAAE,EAAU,UAAUA,EAAG,MAAM,eAAe,IAAI,CAAC,GAAK,EAAE,GAC1E,WAAW,KAAKA,CAAE,GAAK,YAAY,KAAKA,CAAE,EAAU,UAAUA,EAAG,MAAM,gBAAgB,IAAI,CAAC,GAAK,EAAE,GACnG,YAAY,KAAKA,CAAE,EAAU,WAAWA,EAAG,MAAM,gBAAgB,IAAI,CAAC,GAAK,EAAE,GAC1E,SACT,CAEA,SAASD,IAAmB,CAC1B,MAAMC,EAAK,UAAU,UACrB,MAAI,gBAAgB,KAAKA,CAAE,EAAU,gBACjC,aAAa,KAAKA,CAAE,EAAU,UAC9B,gCAAgC,KAAKA,CAAE,GACvC,WAAW,KAAKA,CAAE,EAAU,QAC5B,UAAU,KAAKA,CAAE,EAAU,WAAWA,EAAG,MAAM,eAAe,IAAI,CAAC,GAAK,EAAE,GAC1E,mBAAmB,KAAKA,CAAE,EAAU,MACpC,QAAQ,KAAKA,CAAE,EAAU,QACtB,SACT,CCpCO,SAASC,GACdhZ,EACAiZ,EACAC,EACAzb,EACA0b,EACAC,EACAC,EACAC,EACAC,EACiB,CACjB,MAAO,CACL,YAAAvZ,EACA,GAAGiZ,EACH,eAAgBC,EAChB,YAAazb,EAAa,CAACA,CAAU,EAAI,CAAA,EACzC,eAAgBA,GAAY,eACxB,CACE,SAAUA,EAAW,eACrB,KAAMA,EAAW,YAAc,GAC/B,KAAMA,EAAW,YAAc,EAAA,EAEjC,OACJ,QAAS0b,GAAM,GACf,WAAYA,GAAM,MAClB,UAAWA,GAAM,KACjB,qBAAsBA,EAAO,OAAYE,EACzC,eAAgBF,EAAO,OAAYG,EACnC,iBAAkBF,GAAW,OAC7B,mBAAoBA,GAAW,SAC/B,YAAAG,CAAA,CAEJ,CCpCA,MAAMhD,GAAc,cACdiD,GAAY,qBACZC,GAAgB,gBAEtB,IAAIC,GAA0B,KAC1BC,GAA6B,KAC7BC,GAAgC,KAE7B,SAASC,IAAoB,CAClC,GAAI,CACF,MAAM9B,EAAS,OAAO,aAAa,QAAQxB,EAAW,EACtD,GAAIwB,GAAQ,WAAW,OAAO,EAAG,OAAOA,EACxC,MAAMhM,EAAK+N,GAAA,EACX,cAAO,aAAa,QAAQvD,GAAaxK,CAAE,EACpCA,CACT,MAAQ,CACN,OAAA2N,QAAaI,GAAA,GACNJ,EACT,CACF,CAEO,SAASK,IAA6C,CAC3D,GAAI,CACF,OAAO,OAAO,aAAa,QAAQP,EAAS,GAAK,MACnD,MAAQ,CACN,OAAOG,IAAe,MACxB,CACF,CAEO,SAASK,GAAsBtY,EAAqB,CACzDiY,GAAcjY,EACd,GAAI,CACF,OAAO,aAAa,QAAQ8X,GAAW9X,CAAK,CAC9C,MAAQ,CAER,CACF,CAEO,SAASuY,IAAwC,CACtD,GAAI,CACF,OAAO,OAAO,aAAa,QAAQR,EAAa,GAAK,MACvD,MAAQ,CACN,OAAOG,IAAkB,MAC3B,CACF,CAEO,SAASM,GAAchY,EAAmB,CAC/C0X,GAAiB1X,EACjB,GAAI,CACF,OAAO,aAAa,QAAQuX,GAAevX,CAAG,CAChD,MAAQ,CAER,CACF,CAEA,SAAS4X,IAAyB,CAChC,OAAI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WACzD,QAAQ,OAAO,WAAA,CAAY,GAG7B,QADQ,GAAG,KAAK,MAAM,SAAS,EAAE,CAAC,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,CAAC,EAC/D,EACvB,CC7DA,MAAAK,GAAe,CACb,IAAK,WACL,QAAS,CACP,OAAQ,UACR,OAAQ,SACR,KAAM,iCACN,WAAY,wBACZ,KAAM,MAAA,EAER,MAAO,CACL,MAAO,QACP,YAAa,sCACb,OAAQ,SACR,OAAQ,SACR,YAAa,cACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,oBAAA,EACtB,CAAE,MAAO,KAAM,MAAO,qBAAA,EACtB,CAAE,MAAO,KAAM,MAAO,cAAA,CAAe,CACvC,EAEF,QAAS,CACP,MAAO,iBACP,QAAS,8GACT,YAAa,wCACb,cAAe,wEACf,cAAe,mBACf,MAAO,QACP,aAAc,4EACd,kBAAmB,kBACnB,aAAc,YACd,YAAa,0CACb,YAAa,6CAAA,EAEf,MAAO,CACL,OAAQ,qCAAA,EAEV,IAAK,CACH,OAAQ,YAAA,EAEV,YAAa,CACX,OAAQ,kCACR,OAAQ,WACR,QAAS,SAAA,EAEX,WAAY,CACV,QAAS,UACT,QAAS,SAAA,EAEX,KAAM,CACJ,iBAAkB,6BAClB,KAAM,OACN,KAAM,OACN,OAAQ,SACR,OAAQ,QAAA,EAEV,OAAQ,CACN,KAAM,OACN,YAAa,YACb,YAAa,iCACb,aAAc,wBACd,KAAM,iBACN,MAAO,QACP,oBAAqB,qBAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,2BACV,SAAU,cACV,YAAa,0CACb,KAAM,OACN,cAAe,gBACf,KAAM,cACN,MAAO,QACP,MAAO,6CACP,QAAS,kGAAA,CAEb,EC7EAC,GAAe,CACb,IAAK,KACL,QAAS,CACP,OAAQ,KACR,OAAQ,KACR,KAAM,YACN,WAAY,SACZ,KAAM,IAAA,EAER,MAAO,CACL,MAAO,KACP,YAAa,aACb,OAAQ,KACR,OAAQ,KACR,YAAa,OACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,MAAA,EACtB,CAAE,MAAO,KAAM,MAAO,QAAA,EACtB,CAAE,MAAO,KAAM,MAAO,OAAA,CAAQ,CAChC,EAEF,QAAS,CACP,MAAO,UACP,QAAS,sCACT,YAAa,gBACb,cAAe,yBACf,cAAe,SACf,MAAO,KACP,aAAc,0BACd,kBAAmB,kBACnB,aAAc,MACd,YAAa,iBACb,YAAa,aAAA,EAEf,MAAO,CACL,OAAQ,WAAA,EAEV,IAAK,CACH,OAAQ,QAAA,EAEV,YAAa,CACX,OAAQ,cACR,OAAQ,KACR,QAAS,IAAA,EAEX,WAAY,CACV,QAAS,KACT,QAAS,IAAA,EAEX,KAAM,CACJ,iBAAkB,YAClB,KAAM,KACN,KAAM,KACN,OAAQ,KACR,OAAQ,IAAA,EAEV,OAAQ,CACN,KAAM,KACN,YAAa,MACb,YAAa,YACb,aAAc,wBACd,KAAM,OACN,MAAO,KACP,oBAAqB,OAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,WACV,SAAU,SACV,YAAa,aACb,KAAM,KACN,cAAe,OACf,KAAM,QACN,MAAO,KACP,MAAO,eACP,QAAS,yBAAA,CAEb,EC7EAC,GAAe,CACb,IAAK,UACL,QAAS,CACP,OAAQ,SACR,OAAQ,KACR,KAAM,oBACN,WAAY,SACZ,KAAM,IAAA,EAER,MAAO,CACL,MAAO,KACP,YAAa,oBACb,OAAQ,KACR,OAAQ,QACR,YAAa,aACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,UAAA,EACtB,CAAE,MAAO,KAAM,MAAO,SAAA,EACtB,CAAE,MAAO,KAAM,MAAO,UAAA,CAAW,CACnC,EAEF,QAAS,CACP,MAAO,qBACP,QAAS,uCACT,YAAa,8BACb,cAAe,yBACf,cAAe,aACf,MAAO,MACP,aAAc,0CACd,kBAAmB,kBACnB,aAAc,UACd,YAAa,mBACb,YAAa,iCAAA,EAEf,MAAO,CACL,OAAQ,wBAAA,EAEV,IAAK,CACH,OAAQ,SAAA,EAEV,YAAa,CACX,OAAQ,4BACR,OAAQ,KACR,QAAS,KAAA,EAEX,WAAY,CACV,QAAS,KACT,QAAS,IAAA,EAEX,KAAM,CACJ,iBAAkB,WAClB,KAAM,OACN,KAAM,OACN,OAAQ,QACR,OAAQ,IAAA,EAEV,OAAQ,CACN,KAAM,KACN,YAAa,MACb,YAAa,eACb,aAAc,wBACd,KAAM,QACN,MAAO,MACP,oBAAqB,eAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,iBACV,SAAU,SACV,YAAa,mBACb,KAAM,KACN,cAAe,aACf,KAAM,WACN,MAAO,MACP,MAAO,8BACP,QAAS,sDAAA,CAEb,EC7EAC,GAAe,CACb,IAAK,MACL,QAAS,CACP,OAAQ,MACR,OAAQ,KACR,KAAM,qBACN,WAAY,UACZ,KAAM,KAAA,EAER,MAAO,CACL,MAAO,KACP,YAAa,0BACb,OAAQ,KACR,OAAQ,KACR,YAAa,QACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,SAAA,EACtB,CAAE,MAAO,KAAM,MAAO,SAAA,EACtB,CAAE,MAAO,KAAM,MAAO,MAAA,CAAO,CAC/B,EAEF,QAAS,CACP,MAAO,kBACP,QAAS,6CACT,YAAa,sBACb,cAAe,4BACf,cAAe,WACf,MAAO,KACP,aAAc,yCACd,kBAAmB,kBACnB,aAAc,QACd,YAAa,oBACb,YAAa,8BAAA,EAEf,MAAO,CACL,OAAQ,yBAAA,EAEV,IAAK,CACH,OAAQ,aAAA,EAEV,YAAa,CACX,OAAQ,qBACR,OAAQ,KACR,QAAS,IAAA,EAEX,WAAY,CACV,QAAS,MACT,QAAS,IAAA,EAEX,KAAM,CACJ,iBAAkB,YAClB,KAAM,QACN,KAAM,QACN,OAAQ,KACR,OAAQ,KAAA,EAEV,OAAQ,CACN,KAAM,KACN,YAAa,OACb,YAAa,mBACb,aAAc,wBACd,KAAM,QACN,MAAO,KACP,oBAAqB,kBAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,aACV,SAAU,UACV,YAAa,sBACb,KAAM,MACN,cAAe,UACf,KAAM,WACN,MAAO,MACP,MAAO,6BACP,QAAS,8CAAA,CAEb,EC7EAC,GAAe,CACb,IAAK,cACL,QAAS,CACP,OAAQ,SACR,OAAQ,SACR,KAAM,6CACN,WAAY,oBACZ,KAAM,OAAA,EAER,MAAO,CACL,MAAO,YACP,YAAa,uCACb,OAAQ,SACR,OAAQ,WACR,YAAa,kBACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,kBAAA,EACtB,CAAE,MAAO,KAAM,MAAO,sBAAA,EACtB,CAAE,MAAO,KAAM,MAAO,kBAAA,CAAmB,CAC3C,EAEF,QAAS,CACP,MAAO,qBACP,QAAS,sGACT,YAAa,0CACb,cAAe,6EACf,cAAe,sBACf,MAAO,SACP,aAAc,yEACd,kBAAmB,iBACnB,aAAc,WACd,YAAa,0CACb,YAAa,mDAAA,EAEf,MAAO,CACL,OAAQ,iDAAA,EAEV,IAAK,CACH,OAAQ,mBAAA,EAEV,YAAa,CACX,OAAQ,gCACR,OAAQ,SACR,QAAS,QAAA,EAEX,WAAY,CACV,QAAS,SACT,QAAS,UAAA,EAEX,KAAM,CACJ,iBAAkB,6BAClB,KAAM,WACN,KAAM,UACN,OAAQ,WACR,OAAQ,QAAA,EAEV,OAAQ,CACN,KAAM,UACN,YAAa,WACb,YAAa,uCACb,aAAc,wBACd,KAAM,uBACN,MAAO,SACP,oBAAqB,4BAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,2BACV,SAAU,cACV,YAAa,6CACb,KAAM,SACN,cAAe,oBACf,KAAM,kBACN,MAAO,aACP,MAAO,iEACP,QAAS,iGAAA,CAEb,EC7EAC,GAAe,CACb,IAAK,OACL,QAAS,CACP,OAAQ,UACR,OAAQ,cACR,KAAM,gDACN,WAAY,4BACZ,KAAM,SAAA,EAER,MAAO,CACL,MAAO,WACP,YAAa,8CACb,OAAQ,UACR,OAAQ,UACR,YAAa,WACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,iCAAA,EACtB,CAAE,MAAO,KAAM,MAAO,qBAAA,EACtB,CAAE,MAAO,KAAM,MAAO,kBAAA,CAAmB,CAC3C,EAEF,QAAS,CACP,MAAO,kBACP,QAAS,6HACT,YAAa,2CACb,cAAe,0EACf,cAAe,gBACf,MAAO,SACP,aAAc,iGACd,kBAAmB,mBACnB,aAAc,cACd,YAAa,2CACb,YAAa,4DAAA,EAEf,MAAO,CACL,OAAQ,uCAAA,EAEV,IAAK,CACH,OAAQ,iBAAA,EAEV,YAAa,CACX,OAAQ,+BACR,OAAQ,UACR,QAAS,QAAA,EAEX,WAAY,CACV,QAAS,SACT,QAAS,SAAA,EAEX,KAAM,CACJ,iBAAkB,kCAClB,KAAM,UACN,KAAM,WACN,OAAQ,UACR,OAAQ,SAAA,EAEV,OAAQ,CACN,KAAM,UACN,YAAa,iBACb,YAAa,2CACb,aAAc,wBACd,KAAM,wBACN,MAAO,SACP,oBAAqB,qBAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,6BACV,SAAU,eACV,YAAa,mDACb,KAAM,UACN,cAAe,oBACf,KAAM,qBACN,MAAO,YACP,MAAO,+CACP,QAAS,kGAAA,CAEb,EC7EAC,GAAe,CACb,IAAK,WACL,QAAS,CACP,OAAQ,YACR,OAAQ,YACR,KAAM,gDACN,WAAY,8BACZ,KAAM,SAAA,EAER,MAAO,CACL,MAAO,OACP,YAAa,sDACb,OAAQ,WACR,OAAQ,YACR,YAAa,gBACb,aAAc,CACZ,CAAE,MAAO,KAAM,MAAO,0BAAA,EACtB,CAAE,MAAO,KAAM,MAAO,0BAAA,EACtB,CAAE,MAAO,KAAM,MAAO,kBAAA,CAAmB,CAC3C,EAEF,QAAS,CACP,MAAO,yBACP,QAAS,4IACT,YAAa,gDACb,cAAe,wFACf,cAAe,wBACf,MAAO,YACP,aAAc,4FACd,kBAAmB,kBACnB,aAAc,kBACd,YAAa,kDACb,YAAa,wEAAA,EAEf,MAAO,CACL,OAAQ,uDAAA,EAEV,IAAK,CACH,OAAQ,qBAAA,EAEV,YAAa,CACX,OAAQ,8CACR,OAAQ,eACR,QAAS,WAAA,EAEX,WAAY,CACV,QAAS,YACT,QAAS,SAAA,EAEX,KAAM,CACJ,iBAAkB,6CAClB,KAAM,aACN,KAAM,cACN,OAAQ,YACR,OAAQ,UAAA,EAEV,OAAQ,CACN,KAAM,QACN,YAAa,WACb,YAAa,kCACb,aAAc,wBACd,KAAM,qBACN,MAAO,YACP,oBAAqB,0BAAA,EAEvB,QAAS,CACP,MAAO,sBACP,SAAU,6BACV,SAAU,kBACV,YAAa,6CACb,KAAM,SACN,cAAe,kBACf,KAAM,wBACN,MAAO,mBACP,MAAO,6DACP,QAAS,sHAAA,CAEb,ECnEMC,EAAwC,CAC5C,GAAAP,GACA,QAASC,GACT,GAAAC,GACA,GAAAC,GACA,GAAAC,GACA,GAAAC,GACA,GAAAC,EACF,EAEO,SAASE,GAAYC,EAA8B,CACxD,GAAIF,EAAQE,CAAM,EAAG,OAAOF,EAAQE,CAAM,EAC1C,MAAMC,EAAOD,EAAO,MAAM,GAAG,EAAE,CAAC,EAChC,OAAIF,EAAQG,CAAI,EAAUH,EAAQG,CAAI,EAC/BH,EAAQ,EACjB,CCFA,MAAMI,GAAiB,GAGVC,GAAc,WACdC,GAAkB,UASzBC,GAAY,qEACZC,GAAY,0EAElB,IAAIC,EAA6C,KAEjD,SAASC,IAAoC,CAC3C,OAAID,IACJA,EAAcE,GAAA,EAAgB,MAAM,IAAMC,IAAY,EAC/CH,EACT,CAEA,eAAeE,IAAwC,CAErD,OADY,KAAM,QAAO,eAAe,GAC7B,MACb,CAOA,SAASE,IAA8C,CACrD,MAAMC,EAAM,WACZ,OAAOA,EAAI,aAAa,QAAUA,EAAI,OAAO,MAC/C,CAEA,SAASF,IAAqC,CAC5C,OAAO,IAAI,QAAQ,CAAC9Y,EAAS6E,IAAW,CACtC,MAAMoU,EAAWF,GAAA,EACjB,GAAIE,EAAU,CAAEjZ,EAAQiZ,CAAQ,EAAG,MAAO,CAC1C,MAAMC,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,IAAMT,GACbS,EAAO,UAAYR,GACnBQ,EAAO,YAAc,YACrBA,EAAO,OAAS,IAAM,CACpB,MAAMpY,EAASiY,GAAA,EACXjY,IAAgBA,CAAM,EACrB+D,EAAO,IAAI,MAAM,iDAAiD,CAAC,CAC1E,EACAqU,EAAO,QAAU,IAAMrU,EAAO,IAAI,MAAM,+BAA+B,CAAC,EACxE,SAAS,KAAK,YAAYqU,CAAM,CAClC,CAAC,CACH,CAEO,MAAMC,EAAc,CAYzB,YAAY/iB,EAAyBgjB,EAA2B9W,EAA4B,CAAA,EAAI,CAXhG,KAAQ,OAAuB,CAAA,EAC/B,KAAQ,OAAwB,KAChC,KAAQ,UAAY,EACpB,KAAQ,MAA8C,KACtD,KAAQ,aAAiD,KAIzD,KAAQ,QAAU,GAClB,KAAQ,UAAY,GAGlB,KAAK,OAASlM,EACd,KAAK,aAAegjB,EACpB,KAAK,QAAU9W,CACjB,CAEA,MAAM,OAAuB,CAC3B,MAAMxB,EAAS,MAAM8X,GAAA,EAOjB,KAAK,YAET,KAAK,UAAY,KAAK,IAAA,EACtB,KAAK,QAAU,GAEf,KAAK,OAAS9X,EAAO,CACnB,KAAOJ,GAAsB,CACtB,KAAK,SAAS,KAAK,OAAO,KAAKA,CAAK,CAC3C,EAKA,cAAe,KAAK,QAAQ,eAAiB,GAC7C,WAAY6X,GACZ,cAAeC,EAAA,CAChB,EAED,KAAK,aAAgB,GAAkB,CACrC,KAAK,gBAAgB,EAAE,QAAS,EAAE,OAAO,EACzC1X,EAAO,iBAAiB,YAAa,CACnC,EAAG,EAAE,QACL,EAAG,EAAE,QACL,OAAQ,EAAE,kBAAkB,YAAc,EAAE,OAAO,QAAU,EAAA,CAC9D,CACH,EACA,SAAS,iBAAiB,QAAS,KAAK,aAAc,EAAI,EAE1D,KAAK,MAAQ,WAAW,IAAM,CAC5B,KAAK,eAAA,CACP,EAAGwX,GAAiB,GAAI,EAC1B,CAEA,MAAwB,CACtB,YAAK,QAAU,GACf,KAAK,SAAA,EACL,KAAK,OAAS,KACd,KAAK,aAAA,EACL,KAAK,oBAAA,EAEE,CACL,OAAQ,KAAK,OACb,SAAU,KAAK,YAAA,CAAY,CAE/B,CAEA,aAAsB,CACpB,OAAI,KAAK,YAAc,EAAU,EAC1B,KAAK,IAAI,EAAG,KAAK,OAAO,KAAK,IAAA,EAAQ,KAAK,WAAa,GAAI,CAAC,CACrE,CAEA,SAAgB,CACd,KAAK,UAAY,GACjB,KAAK,QAAU,GACf,KAAK,SAAA,EACL,KAAK,OAAS,KACd,KAAK,aAAA,EACL,KAAK,oBAAA,EACL,KAAK,OAAS,CAAA,EACd,KAAK,UAAY,CACnB,CAEQ,cAAqB,CACvB,KAAK,QACP,aAAa,KAAK,KAAK,EACvB,KAAK,MAAQ,KAEjB,CAEQ,qBAA4B,CAC9B,KAAK,eACP,SAAS,oBAAoB,QAAS,KAAK,aAAc,EAAI,EAC7D,KAAK,aAAe,KAExB,CAEQ,gBAAgBpf,EAAWC,EAAiB,CAClD,MAAMkgB,EAAS,KAAK,OAAO,GAAmB,MAAO,kBAAkB,EACvEA,EAAO,MAAM,KAAO,GAAGngB,CAAC,KACxBmgB,EAAO,MAAM,IAAM,GAAGlgB,CAAC,KACvB,KAAK,OAAO,OAAOkgB,CAAM,EACzBA,EAAO,iBAAiB,eAAgB,IAAMA,EAAO,QAAQ,CAC/D,CACF,CC1LO,MAAMC,EAAiB,CAM5B,YACEljB,EACAC,EACAkjB,EACAC,EACA,CARF,KAAQ,WAAoD,KAS1D,KAAK,YAAcD,EAEnB,KAAK,GAAKnjB,EAAO,GAAmB,MAAO,gBAAgB,EAC3D,KAAK,GAAG,UAAY;AAAA;AAAA;AAAA,sDAG8BC,EAAS,OAAO,IAAI;AAAA,MAEtED,EAAO,OAAO,KAAK,EAAE,EAErB,KAAK,QAAU,KAAK,GAAG,cAAc,mBAAmB,EACxD,KAAK,GAAG,cAAc,kBAAkB,EAAG,iBAAiB,QAASojB,CAAM,EAE3E,KAAK,WAAa,YAAY,IAAM,KAAK,YAAA,EAAe,GAAI,CAC9D,CAEQ,aAAoB,CAC1B,MAAMC,EAAO,KAAK,YAAA,EACZC,EAAK,OAAO,KAAK,MAAMD,EAAO,EAAE,CAAC,EAAE,SAAS,EAAG,GAAG,EAClDE,EAAK,OAAOF,EAAO,EAAE,EAAE,SAAS,EAAG,GAAG,EAC5C,KAAK,QAAQ,YAAc,GAAGC,CAAE,IAAIC,CAAE,EACxC,CAEA,SAAgB,CACV,KAAK,aACP,cAAc,KAAK,UAAU,EAC7B,KAAK,WAAa,MAEpB,KAAK,GAAG,OAAA,CACV,CACF,CCpCO,MAAMC,EAAiB,CAAvB,aAAA,CACL,KAAQ,QAAgC,KACxC,KAAQ,IAA+B,KACvC,KAAQ,OAAiC,IAAA,CAEzC,MAAM,MACJxjB,EACAC,EACAmjB,EACAlX,EAA4B,CAAA,EACb,CACf,KAAK,QAAU,IAAI6W,GAAc/iB,EAAQojB,EAAQlX,CAAO,EACxD,KAAK,IAAM,IAAIgX,GACbljB,EACAC,EACA,IAAM,KAAK,SAAS,YAAA,GAAiB,EACrCmjB,CAAA,EAEF,MAAM,KAAK,QAAQ,MAAA,CACrB,CAEA,MAA+B,CAC7B,OAAK,KAAK,SACV,KAAK,OAAS,KAAK,QAAQ,KAAA,EAC3B,KAAK,WAAA,EACE,KAAK,QAHc,IAI5B,CAEA,cAAuC,CACrC,OAAO,KAAK,MACd,CAEA,SAAgB,CACd,KAAK,WAAA,EACL,KAAK,OAAS,IAChB,CAEQ,YAAmB,CACzB,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,KAAK,QAAA,EACV,KAAK,IAAM,IACb,CACF,CCxBA,MAAMK,GAAiC,IAGjCC,GAA6B,KAanC,SAASC,IAAuB,CAC9B,KAAM,CAAE,SAAAC,GAAa,OAAO,SAC5B,OACEA,IAAa,aACbA,IAAa,aACbA,IAAa,SACbA,EAAS,SAAS,YAAY,GAC9BA,EAAS,SAAS,QAAQ,GAC1BA,EAAS,SAAS,OAAO,CAE7B,CAEO,MAAMC,CAAiB,CA4B5B,YAAYC,EAA8B,CAzB1C,KAAQ,IAA0B,KAClC,KAAQ,QAAoC,KAC5C,KAAQ,QAAoC,KAC5C,KAAQ,WAAa,IAAInjB,GACzB,KAAQ,QAA8B,KACtC,KAAQ,IAAyB,KACjC,KAAQ,MAA6B,KACrC,KAAQ,QAA8B,KACtC,KAAQ,QAA8B,KACtC,KAAQ,kBAAkD,KAI1D,KAAQ,oBAAkD,KAE1D,KAAQ,KAAa,OACrB,KAAQ,IAAW,MACnB,KAAQ,kBAAuC,KAC/C,KAAQ,aAAoC,KAC5C,KAAQ,aAAgD,KACxD,KAAQ,iBAA4C,KACpD,KAAQ,iBAAqD,KAC7D,KAAQ,kBAAoB,EAC5B,KAAQ,YAAkF,CAAA,EAsB1F,KAAQ,cAAiB2J,GAA+B,CACtD,GAAIA,EAAM,MAAQ,SAElB,OAAQ,KAAK,KAAA,CACX,IAAK,aACL,IAAK,QACHA,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,KAAK,QAAA,EACL,MACF,IAAK,UACHA,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,KAAK,WAAA,EACL,MACF,IAAK,YACHA,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,KAAK,iBAAA,EACL,KAEA,CAEN,EAkKA,KAAQ,iBAAmB,IAAY,CAChC,KAAK,mBACV,KAAK,iBAAiB,KAAA,EACtB,KAAK,IAAM,SACX,KAAK,UAAU,OAAO,WAAa,EAAG,OAAO,YAAc,EAAG,KAAK,SAAS,OAAO,WAAW,EAChG,EAjNE,KAAK,OAASwZ,EACd,KAAK,SAAW/B,GAAY+B,EAAO,QAAU,SAAS,gBAAgB,MAAQ,IAAI,EAClF,KAAK,UAAY,IAAIpc,GAAUoc,EAAO,WAAYA,EAAO,OAAQ,OAAWA,EAAO,UAAWA,EAAO,WAAW,EAChH,KAAK,iBAAmB,IAAI1H,GAC5B,KAAK,iBAAiB,MAAA,EACtB,KAAK,oBAAsB,IAAIiB,GAC/B,KAAK,oBAAoB,MAAA,EACzB,KAAK,QAAA,EAEDyG,EAAO,uBAAyB,KAClC,KAAK,oBAAsB,IAAI/D,EAAoB,IAAM,KAAK,mBAAmB,EACjF,KAAK,oBAAoB,MAAA,GAG3B,SAAS,iBAAiB,UAAW,KAAK,cAAe,EAAI,CAC/D,CA6BQ,SAAgB,CAGtB,GAFA,KAAK,OAAS,IAAIzgB,GAAgB,KAAK,OAAO,OAAS,MAAM,EAEzD,KAAK,OAAO,YAAc,MAAO,CAM/BqkB,MACF,QAAQ,KACN,4HAAA,EAIJ,MACF,CAEA,KAAK,SAAA,CACP,CAEQ,UAAiB,CACnB,KAAK,MACT,KAAK,IAAM,IAAI5jB,GACb,KAAK,OACL,KAAK,SACL,KAAK,OAAO,UAAY,QACxB,IAAM,KAAK,eAAA,EACX,KAAK,OAAO,OAAA,EAEhB,CAGA,MAAa,CACP,KAAK,OAAS,SAClB,KAAK,yBAAA,EACL,KAAK,oBAAA,EACP,CAEA,OAAc,CACR,KAAK,OAAS,QAClB,KAAK,QAAA,CACP,CAEA,cAAqB,CACnB,KAAK,SAAA,EACL,KAAK,KAAK,UAAU,KAAK,OAAS,MAAM,CAC1C,CAEA,cAAqB,CACnB,KAAK,KAAK,QAAA,EACV,KAAK,IAAM,IACb,CAKA,UAAUiiB,EAAsB,CAC9B,KAAK,OAAO,OAASA,EACrB,KAAK,SAAWD,GAAYC,CAAM,EAClC,KAAK,KAAK,YAAY,KAAK,QAAQ,CACrC,CAEQ,gBAAuB,CACzB,KAAK,OAAS,QAChB,KAAK,yBAAA,EACL,KAAK,oBAAA,GAEL,KAAK,QAAA,CAET,CAEQ,mBAA0B,CAC5B,KAAK,OAAS,QAAU,KAAK,mBAAqB9D,OAEtD,KAAK,kBAAoB,IAAI1d,GAAsB,KAAK,OAAQ,KAAK,SAAU,CAC7E,OAAQ,IAAM,CACZ,KAAK,yBAAA,EACL,KAAK,oBAAA,CACP,EACA,UAAW,IAAM,CACf2d,GAAA,EACA,KAAK,yBAAA,CACP,EAGA,WAAY,IAAM,KAAK,yBAAA,CAAyB,CACjD,EACH,CAEQ,0BAAiC,CACvC,KAAK,mBAAmB,QAAA,EACxB,KAAK,kBAAoB,IAC3B,CAEQ,qBAA4B,CAClC,KAAK,KAAO,aACZ,KAAK,KAAK,UAAU,EAAI,EACxB,KAAK,WAAW,KAAA,EAEhB,KAAK,QAAU,IAAIvd,GACjB,KAAK,OACL,KAAK,SACL,IAAM,KAAK,QAAA,EACVO,GAAsB,KAAK,wBAAwBA,CAAI,CAAA,EAE1D,KAAK,QAAU,KAAK,cAAA,CACtB,CAEQ,eAAmC,CACzC,OAAO,IAAIsD,GAAkB,KAAK,OAAQ,KAAK,SAAU,CACvD,MAAO,CAACI,EAAYD,IAAe,CACjC,KAAK,kBAAoBC,EACzB,KAAK,IAAM,MACX,KAAK,UAAUA,EAAW,EAAGA,EAAW,EAAGD,EAAYC,EAAW,UAAU,CAC9E,EACA,aAAc,IAAM,KAAK,iBAAA,CAAiB,CAC3C,CACH,CAEQ,wBAAwB1D,EAAyB,CACvD,GAAI,KAAK,OAAS,aAAc,CAC9B,KAAK,SAAS,QAAQ,KAAK,MAAQ,SAAW,SAAW,QAAQ,EACjE,MACF,CAEA,GAAIA,IAAS,SAAU,CACrB,GAAI,KAAK,OAAS,YAAa,OAE/B,KAAK,KAAO,YACZ,KAAK,kBAAoB,KACzB,KAAK,aAAA,EACL,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KAGf,KAAK,WAAW,OAAA,EAChB,KAAK,iBAAmB,IAAIqiB,GAC5B,KAAK,iBAAiB,MACpB,KAAK,OACL,KAAK,SACL,KAAK,iBACL,KAAK,OAAO,WAAa,CAAA,CAAC,EAC1B,MAAOhc,GAAU,CAEjB,QAAQ,KAAK,2EAA4EA,CAAK,EAC1F,KAAK,OAAS,cAClB,KAAK,SAAS,QAAQ,QAAQ,EAC9B,KAAK,wBAAwB,QAAQ,EACvC,CAAC,CACH,MACE,KAAK,kBAAkB,QAAA,EACvB,KAAK,iBAAmB,KACxB,KAAK,aAAA,EACA,KAAK,UAAS,KAAK,QAAU,KAAK,cAAA,GACvC,KAAK,WAAW,KAAA,EAChB,KAAK,KAAO,YAEhB,CASQ,kBAAyB,CAC3B,KAAK,OAAS,YAChB,KAAK,KAAO,UACZ,KAAK,QAAU,IAAI9B,GAAY,KAAK,OAAQ,CAC1C,SAAU,KAAK,SACf,OAAQ,IAAM,KAAK,mBAAmB,MAAM,EAC5C,OAAQ,IAAM,KAAK,mBAAmB,MAAM,EAC5C,SAAU,IAAM,KAAK,WAAA,EACrB,SAAWqe,GAAS,KAAK,iBAAiBA,CAAI,CAAA,CAC/C,GAEH,KAAK,eAAA,CACP,CAEQ,mBAAmBC,EAA+B,CACpDA,IAAW,OAAQ,KAAK,SAAS,SAAA,EAChC,KAAK,SAAS,SAAA,EACnB,KAAK,eAAA,CACP,CAEQ,gBAAuB,CACxB,KAAK,SACV,KAAK,SAAS,YAAY,KAAK,QAAQ,cAAe,KAAK,QAAQ,aAAa,CAClF,CAEQ,YAAmB,CACzB,KAAK,SAAS,UAAA,EACd,KAAK,aAAA,EACL,KAAK,KAAO,YACd,CAEQ,cAAqB,CAC3B,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,IACjB,CAEQ,iBAAiBD,EAAoB,CAC3C,MAAMlf,EAAa,KAAK,SAAS,kBAAA,EACjC,GAAI,CAACA,EAAY,CACf,KAAK,WAAA,EACL,MACF,CACA,KAAK,kBAAoBA,EACzB,KAAK,IAAM,OACX,KAAK,SAAS,mBAAA,EACd,KAAK,aAAe,KAAK,QACpB,KAAK,aAAakf,GAAQ,KAAK,SAAS,WAAW,OAAO,CACjE,CAEQ,UAAUjhB,EAAWC,EAAW6B,EAAoBuB,EAA+B,CACzF,KAAK,KAAO,QACZ,KAAK,aAAe,CAAE,EAAArD,EAAG,EAAAC,CAAA,EACzB,KAAK,aAAA,EACL,KAAK,SAAS,mBAAA,EACd,KAAK,OAAO,QAAA,EACZ,KAAK,MAAQ,KACb,KAAK,KAAK,QAAA,EACV,KAAK,IAAM,KACX,KAAK,IAAM,IAAIrC,GAAW,KAAK,OAAQ,IAAM,KAAK,SAAS,EAE3D,KAAK,MAAQ,IAAIsF,GAAa,KAAK,OAAQ,CACzC,WAAApB,EACA,EAAA9B,EACA,EAAAC,EACA,WAAAoD,EACA,SAAU,KAAK,SACf,SAAWiB,GAAgB,KAAK,aAAaA,CAAW,EACxD,QAAS,IAAM,KAAK,QAAA,EACpB,aAAc,KAAK,uBAAA,EACnB,SAAU,KAAK,OAAO,UAAY,OAAA,CACnC,EACD,KAAK,aAAe,KAAK,KAC3B,CAEQ,wBAAmD,CACzD,GAAI,MAAK,OAAO,MACXia,GAAA,EAEL,MAAO,UAAY,CACjB,MAAM4C,EAAW,MAAM,KAAK,UAAU,oBAAoBhD,IAAW,EACjE,CAACgD,GAAU,gBAAkB,CAACA,EAAS,YAC3C3C,GAAc2C,EAAS,SAAS,EAChC,OAAO,KAAK,GAAGA,EAAS,SAAS,aAAa,mBAAmBA,EAAS,cAAc,CAAC,GAAI,QAAQ,EACvG,CACF,CAEA,MAAc,aAAa7c,EAAoC,CAC7D,MAAM8c,EAAK,KAAK,aAChB,GAAI,CAACA,EAAI,OACT,MAAMC,EAAoB,EAAE,KAAK,kBACjCD,EAAG,WAAW,EAAI,EAClB,MAAME,GAAA,EACN,MAAMvf,EAAa,KAAK,kBAClB2b,EAAY,KAAK,kBAAkB,aAAA,GAAkB,OAErD,CAACpY,EAAYiY,CAAW,EAAI,MAAM,QAAQ,IAAI,CAClDlG,GAAkBtV,EAAa,CAACA,CAAU,EAAI,CAAA,CAAE,EAChD,QAAQ,QAAQmb,GAAA,CAAoB,CAAA,CACrC,EAEK7X,EAAUiY,GACdhZ,EACAiZ,EACA,KAAK,iBAAiB,UAAA,EACtBxb,EACA,KAAK,OAAO,KACZ2b,EACA,KAAK,OAAO,KAAO,OAAYS,GAAA,EAC/B,KAAK,OAAO,KAAO,OAAYE,GAAA,EAC/B,KAAK,oBAAoB,eAAA,CAAe,EAG1C,GAAI,CACF,MAAMkD,EAAa,MAAM,KAAK,UAAU,wBAAwBlc,EAASC,CAAU,EACnF,GAAI+b,IAAsB,KAAK,kBAAmB,CAChD,MAAM,KAAK,UAAU,yBAAyBE,EAAW,GAAIA,EAAW,KAAK,EAAE,MAAM,IAAM,CAAC,CAAC,EAC7F,MACF,CACA,KAAK,iBAAmBA,EACxB,MAAM,KAAK,mBAAmBA,EAAY,KAAK,aAAcF,CAAiB,CAChF,MAAQ,CACN,GAAIA,IAAsB,KAAK,kBAAmB,OAClDD,EAAG,WAAW,EAAK,EACnBA,EAAG,SAAS,KAAK,SAAS,MAAM,MAAM,CACxC,CACF,CAEA,MAAc,mBACZG,EACAC,EACAH,EACe,CACf,GAAI,CAACE,EAAW,qBAAsB,CACpC,MAAME,EAAU,KAAK,qBAAqB,EAAI,EAC9C,KAAK,YAAYF,EAAYC,EAAK,CAChC,QAAAC,EACA,gBAAiB,CAAE,SAAU,CAAA,EAAI,KAAM,EAAA,CAAK,CAC7C,EACD,MACF,CAMA,MAAMC,EAAa,IAAI,gBACvB,IAAIC,EAAe,WAAW,IAAMD,EAAW,MAAA,EAASd,EAA0B,EAClF,MAAMgB,EAAoB,IAAM,CAC9B,aAAaD,CAAY,EACzBA,EAAe,WAAW,IAAMD,EAAW,MAAA,EAASd,EAA0B,CAChF,EACMiB,EAAiB,KAAK,UAAU,oBACpCN,EAAW,GACXA,EAAW,MACXK,EACAF,EAAW,MAAA,EACX,MAAM,IAAM,IAAI,EAAE,QAAQ,IAAM,aAAaC,CAAY,CAAC,EAEtDG,EAAiB,IAAI,WACzB,WAAW,IAAMhb,EAAQ,IAAI,EAAG6Z,EAA8B,CAAA,EAG1DzZ,EAAS,MAAM,QAAQ,KAAK,CAAC2a,EAAgBC,CAAc,CAAC,EAElE,GAAIT,IAAsB,KAAK,kBAAmB,OAElD,MAAMI,EAAU,KAAK,qBAAqB,EAAI,EAE1Cva,EACF,KAAK,YAAYqa,EAAYC,EAAK,CAAE,QAAAC,EAAS,gBAAiBva,EAAQ,EAEtE,KAAK,YAAYqa,EAAYC,EAAK,CAAE,QAAAC,EAAS,qBAAsBI,EAAgB,CAEvF,CAEQ,qBAAqBE,EAAgB,GAAmC,CAC9E,MAAMC,EAAeD,EAAgB,KAAK,OAAO,iBAAmB,OAMpE,YAAK,WAAW,OAAA,EAChB,KAAK,aAAA,EACAC,GAAc,KAAK,OAAO,QAAA,EAC/B,KAAK,MAAQ,KACb,KAAK,KAAK,QAAA,EACV,KAAK,IAAM,KACX,KAAK,SAAS,cAAA,EACd,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,kBAAkB,QAAA,EACvB,KAAK,iBAAmB,KACxB,KAAK,aAAe,KACbA,CACT,CAEQ,YACNT,EACAC,EACAS,EAKM,CACN,KAAK,KAAO,aACZ,KAAK,KAAK,UAAU,EAAI,EACxB,KAAK,QAAU,IAAI9Z,GAAY,KAAK,OAAQ,CAC1C,oBAAqBoZ,EAAW,GAChC,gBAAiBA,EAAW,MAC5B,UAAW,KAAK,UAChB,SAAU,KAAK,SACf,QAASU,GAAa,QACtB,SAAU,KAAK,OAAO,UAAY,QAClC,EAAGT,GAAK,EACR,EAAGA,GAAK,EACR,WAAY,IAAM,KAAK,mBAAA,EACvB,gBAAiBS,GAAa,gBAC9B,qBAAsBA,GAAa,oBAAA,CACpC,CACH,CAEA,MAAc,oBAAoC,CAChD,MAAMV,EAAa,KAAK,iBACxB,GAAI,CAACA,EAAY,MAAM,IAAI,MAAM,8BAA8B,EAC/D,MAAMF,EAAoB,KAAK,kBAEzBa,EAAW,MAAM,KAAK,UAAU,0BAA0BX,EAAW,GAAIA,EAAW,KAAK,EAC3FF,IAAsB,KAAK,mBAAqB,KAAK,mBAAqBE,IAE9E,KAAK,iBAAmB,KACxB,KAAK,YAAc,CACjB,WAAYW,EAAS,GACrB,SAAUA,EAAS,UACnB,cAAeA,EAAS,cAAA,EAEtBA,EAAS,WAAW1D,GAAc0D,EAAS,SAAS,EACxD,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,YAAY,CAAE,aAAcX,EAAW,uBAAyB,GAAO,EAC9E,CAEQ,YAAYnY,EAAoC,CACtD,KAAK,KAAO,OACZ,KAAK,KAAK,UAAU,EAAK,EACzB,KAAK,QAAU,IAAIH,GAAY,KAAK,OAAQ,KAAK,SAAU,IAAM,CAC/D,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,IACjB,EAAG,KAAK,yBAAA,EAA4B,CAAE,GAAGG,EAAS,aAAc,KAAK,kBAAA,EAAqB,CAC5F,CAEQ,mBAAmF,CACzF,GAAI,KAAK,OAAO,KAAM,OACtB,KAAM,CAAE,WAAArD,EAAY,cAAAE,CAAA,EAAkB,KAAK,YAC3C,GAAI,GAACF,GAAc,CAACE,IAChB,CAAAoY,GAAA,EAEJ,MAAO,CACL,SAAU,MAAOrY,GAAkB,CACjC,MAAMmc,EAAQ,MAAM,KAAK,UAAU,eAAepc,EAAYC,EAAOC,CAAa,EAClF,OAAIkc,MAA6Bnc,CAAK,EAC/Bmc,CACT,CAAA,CAEJ,CAEQ,0BAAqD,CAC3D,KAAM,CAAE,SAAAC,EAAU,cAAAnc,CAAA,EAAkB,KAAK,YACzC,GAAKmc,EAEL,IAAInc,EACF,MAAO,IAAM,CACX,OAAO,KAAK,GAAGmc,CAAQ,aAAa,mBAAmBnc,CAAa,CAAC,GAAI,QAAQ,CACnF,EAGF,GAAI,KAAK,OAAO,WAAa,KAAK,OAAO,YACvC,MAAO,UAAY,CACjB,MAAMb,EAAQ,MAAM,KAAK,UAAU,iBAAA,EAC/BA,GAAO,OAAO,KAAK,GAAGgd,CAAQ,aAAa,mBAAmBhd,CAAK,CAAC,GAAI,QAAQ,CACtF,EAIJ,CAEQ,SAAgB,CACtB,KAAK,mBAAqB,EAC1B,MAAMmc,EAAa,KAAK,iBACxB,KAAK,iBAAmB,KACpBA,GACG,KAAK,UAAU,yBAAyBA,EAAW,GAAIA,EAAW,KAAK,EAAE,MAAM,IAAM,CAAC,CAAC,EAE9F,KAAK,KAAO,OACZ,KAAK,IAAM,MACX,KAAK,KAAK,UAAU,EAAK,EAGzB,KAAK,WAAW,OAAA,EAChB,KAAK,aAAA,EACL,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,SAAS,cAAA,EACd,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,KAAK,QAAA,EACV,KAAK,IAAM,KACX,KAAK,OAAO,QAAA,EACZ,KAAK,MAAQ,KACb,KAAK,SAAS,QAAA,EACd,KAAK,QAAU,KACf,KAAK,kBAAoB,KACzB,KAAK,aAAe,KACpB,KAAK,kBAAkB,QAAA,EACvB,KAAK,iBAAmB,IAC1B,CAEA,SAAgB,CACd,SAAS,oBAAoB,UAAW,KAAK,cAAe,EAAI,EAChE,KAAK,QAAA,EACL,KAAK,iBAAiB,KAAA,EACtB,KAAK,oBAAoB,KAAA,EACzB,KAAK,qBAAqB,KAAA,EAC1B,KAAK,yBAAA,EACL,KAAK,SAAS,QAAA,EACd,KAAK,SAAS,QAAA,EACd,KAAK,KAAK,QAAA,EACV,KAAK,kBAAkB,QAAA,EACvB,KAAK,OAAO,QAAA,CACd,CACF,CAEA,SAASD,IAA8B,CACrC,OAAO,IAAI,QAAe9K,GAAM,sBAAsB,IAAM,WAAWA,EAAG,CAAC,CAAC,CAAC,CAC/E,CCtnBA,IAAIpK,EAAoC,KACpCiW,EAA0C,KAE9C,MAAMC,GAAiB,CACrB,KAAKtB,EAAoC,CACnC5U,IACFA,EAAS,QAAA,EACTA,EAAW,MAEbiW,EAAarB,EACT,SAAS,aAAe,UAC1B,SAAS,iBAAiB,mBAAoB,IAAM,CAClD5U,EAAW,IAAI2U,EAAiBC,CAAM,CACxC,CAAC,EAED5U,EAAW,IAAI2U,EAAiBC,CAAM,CAE1C,EAEA,SAAgB,CACd5U,GAAU,QAAA,EACVA,EAAW,KACXiW,EAAa,IACf,EAEA,UAAUnD,EAAsB,CAC1BmD,MAAuB,OAASnD,GACpC9S,GAAU,UAAU8S,CAAM,CAC5B,EAOA,MAAa,CACX9S,GAAU,KAAA,CACZ,EAEA,OAAc,CACZA,GAAU,MAAA,CACZ,EAEA,cAAqB,CACnBA,GAAU,aAAA,CACZ,EAEA,cAAqB,CACnBA,GAAU,aAAA,CACZ,CACF,EAKI,OAAO,OAAW,MACnB,OAA+D,eAAiBkW,GAEjF,SAAS,iBAAiB,aAAc,IAAM,CAC5C,MAAMpgB,EAAO,SAAS,eAAe,iBAAiB,EAClDmgB,IAAe,CAACngB,GAAQ,CAACA,EAAK,cAChCkK,GAAU,QAAA,EACVlK,GAAM,OAAA,EACNkK,EAAW,IAAI2U,EAAiBsB,CAAU,EAE9C,CAAC","x_google_ignoreList":[20,21,22,23,24,25,26,27,28,29]}
1
+ {"version":3,"file":"makethisbetter.cjs","sources":["../src/widget/shadow.ts","../src/widget/tab.ts","../src/widget/frustration-prompt.ts","../src/widget/dim-overlay.ts","../src/widget/scroll-lock.ts","../src/annotate/toolbar.ts","../src/annotate/overlay.ts","../src/annotate/highlighter.ts","../src/annotate/pin.ts","../src/styles.ts","../src/annotate/draw.ts","../src/annotate/session.ts","../src/context/dom-utils.ts","../src/popup/keyboard-inset.ts","../src/popup/sheet.ts","../src/annotate/draw-note-bar.ts","../src/popup/comment.ts","../src/api/client.ts","../src/popup/clarify.ts","../src/popup/success.ts","../node_modules/html-to-image/es/util.js","../node_modules/html-to-image/es/clone-pseudos.js","../node_modules/html-to-image/es/mimes.js","../node_modules/html-to-image/es/dataurl.js","../node_modules/html-to-image/es/clone-node.js","../node_modules/html-to-image/es/embed-resources.js","../node_modules/html-to-image/es/embed-images.js","../node_modules/html-to-image/es/apply-style.js","../node_modules/html-to-image/es/embed-webfonts.js","../node_modules/html-to-image/es/index.js","../src/screenshot/crop.ts","../src/screenshot/capture.ts","../src/context/error-source.ts","../src/context/console.ts","../src/context/history-patch.ts","../src/context/breadcrumbs.ts","../src/context/frustration-state.ts","../src/context/frustration.ts","../src/context/collector.ts","../src/widget/payload.ts","../src/widget/anon-id.ts","../src/i18n/en.ts","../src/i18n/zh-CN.ts","../src/i18n/ja.ts","../src/i18n/ko.ts","../src/i18n/es.ts","../src/i18n/fr.ts","../src/i18n/de.ts","../src/i18n/index.ts","../src/record/session.ts","../src/record/control-bar.ts","../src/widget/recording-manager.ts","../src/widget/controller.ts","../src/index.ts"],"sourcesContent":["import cssText from '../styles/widget.css?inline'\nimport type { MakeThisBetterConfig } from '../types'\n\nexport class ShadowContainer {\n // Readable so a component can mark the host with its own presence and have\n // :host(...) rules react — the only way CSS inside the shadow tree can be\n // told which components are currently mounted.\n readonly host: HTMLElement\n readonly root: ShadowRoot\n\n constructor(theme: MakeThisBetterConfig['theme'] = 'auto') {\n this.host = document.createElement('div')\n this.host.id = 'mtb-widget-host'\n this.host.style.cssText = 'position:fixed;top:0;left:0;width:0;height:0;overflow:visible;z-index:2147483646;'\n this.host.setAttribute('data-mtb-theme', theme)\n document.body.appendChild(this.host)\n\n this.root = this.host.attachShadow({ mode: 'open' })\n\n const style = document.createElement('style')\n style.textContent = cssText\n this.root.appendChild(style)\n }\n\n el<T extends HTMLElement = HTMLElement>(tag: string, className?: string): T {\n const el = document.createElement(tag) as T\n if (className) el.className = className\n return el\n }\n\n append(...nodes: Node[]): void {\n for (const n of nodes) this.root.appendChild(n)\n }\n\n remove(...nodes: Node[]): void {\n for (const n of nodes) {\n if (n.parentNode === this.root) this.root.removeChild(n)\n }\n }\n\n destroy(): void {\n // host.remove() is a safe no-op if the host is already detached — e.g.\n // when Turbo swapped document.body on navigation. removeChild(host) would\n // throw NotFoundError there, aborting re-init and dropping the widget.\n this.host.remove()\n }\n}\n","import type { ShadowContainer } from './shadow'\nimport type { I18nMessages } from '../i18n'\n\nexport class FeedbackTab {\n private el: HTMLButtonElement\n private onClick: () => void\n private idleLabel: string\n private activeLabel: string\n private customText?: string\n private active = false\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n position: 'left' | 'right',\n onClick: () => void,\n customText?: string,\n ) {\n this.onClick = onClick\n this.customText = customText\n this.el = shadow.el<HTMLButtonElement>('button', 'mtb-tab')\n if (position === 'left') this.el.classList.add('left')\n this.idleLabel = customText ?? messages.tab\n this.activeLabel = messages.toolbar.exit\n this.setLabel(this.idleLabel)\n this.el.addEventListener('click', onClick)\n shadow.append(this.el)\n }\n\n private setLabel(label: string): void {\n this.el.textContent = label\n this.el.setAttribute('aria-label', label)\n }\n\n setMessages(messages: I18nMessages): void {\n this.idleLabel = this.customText ?? messages.tab\n this.activeLabel = messages.toolbar.exit\n this.setLabel(this.active ? this.activeLabel : this.idleLabel)\n }\n\n setActive(active: boolean): void {\n this.active = active\n this.el.classList.toggle('active', active)\n this.setLabel(active ? this.activeLabel : this.idleLabel)\n }\n\n destroy(): void {\n this.el.removeEventListener('click', this.onClick)\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from './shadow'\nimport type { I18nMessages } from '../i18n'\n\nconst FRUSTRATION_DISMISS_MS = 8000\n\nexport interface FrustrationPromptHandlers {\n onTell: () => void\n // The reporter clicked Dismiss — a deliberate refusal.\n onDismiss: () => void\n // Nobody touched the card and it faded out on its own. Kept separate from\n // onDismiss because \"did not notice\" is not \"said no\": treating the two the\n // same suppressed every later prompt for the session.\n onAutoHide: () => void\n}\n\nexport class FrustrationPromptCard {\n private el: HTMLDivElement\n private autoHideTimer: ReturnType<typeof setTimeout> | null = null\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n handlers: FrustrationPromptHandlers,\n ) {\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-frustration-prompt')\n this.el.innerHTML = `\n <div class=\"mtb-frustration-icon\">&#9888;&#65039;</div>\n <span class=\"mtb-frustration-text\">${messages.frustration.prompt}</span>\n <div class=\"mtb-frustration-actions\">\n <button class=\"mtb-frustration-tell\">${messages.frustration.action}</button>\n <button class=\"mtb-frustration-dismiss\">${messages.frustration.dismiss}</button>\n </div>\n `\n\n this.el.querySelector('.mtb-frustration-tell')!.addEventListener('click', handlers.onTell)\n this.el.querySelector('.mtb-frustration-dismiss')!.addEventListener('click', handlers.onDismiss)\n\n shadow.append(this.el)\n this.autoHideTimer = setTimeout(handlers.onAutoHide, FRUSTRATION_DISMISS_MS)\n }\n\n destroy(): void {\n // Clearing matters on the engagement path too: without it, a card destroyed\n // by \"Tell us\" still fired its auto-hide 8s later.\n if (this.autoHideTimer) {\n clearTimeout(this.autoHideTimer)\n this.autoHideTimer = null\n }\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from './shadow'\n\n// Full-screen scrim shown behind the comment popup. Clicking it resets the\n// widget, mirroring the design's dim-to-dismiss behaviour.\nexport class DimOverlay {\n private el: HTMLDivElement\n private onClick: () => void\n\n constructor(shadow: ShadowContainer, onClick: () => void) {\n this.onClick = onClick\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-dim mtb-dim-clickable')\n this.el.addEventListener('click', this.onClick)\n shadow.append(this.el)\n }\n\n destroy(): void {\n this.el.removeEventListener('click', this.onClick)\n this.el.remove()\n }\n}\n","/**\n * Freezes the host page while a finger is annotating.\n *\n * Two reasons this exists, both of them touch problems. `touch-action: none`\n * is what makes freehand drawing possible at all on a touch screen —\n * otherwise the browser claims the gesture as a pan and never delivers the\n * pointermove stream. `overflow: hidden` then stops the page sliding under a\n * half-drawn stroke, which would leave the annotation pointing at whatever\n * scrolled into its place.\n *\n * A mouse has neither problem, so the desktop keeps scrolling as it always\n * has. Taking that away would be an unasked-for change to the one path that\n * already worked.\n *\n * The host page is not ours, so its own inline values are saved and put back\n * verbatim. Writing '' on unlock would silently delete a style the page set.\n */\nexport class ScrollLock {\n private locked = false\n private prevOverflow = ''\n private prevTouchAction = ''\n\n // No matchMedia means no evidence of a touch device — assume a mouse and\n // leave the host page alone.\n private isTouchPointer(): boolean {\n return window.matchMedia?.('(pointer: coarse)').matches ?? false\n }\n\n lock(): void {\n if (this.locked || !this.isTouchPointer()) return\n this.locked = true\n this.prevOverflow = document.body.style.overflow\n this.prevTouchAction = document.body.style.touchAction\n document.body.style.overflow = 'hidden'\n document.body.style.touchAction = 'none'\n }\n\n unlock(): void {\n if (!this.locked) return\n this.locked = false\n document.body.style.overflow = this.prevOverflow\n document.body.style.touchAction = this.prevTouchAction\n }\n\n isLocked(): boolean {\n return this.locked\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\n\nexport type ToolbarMode = 'markup' | 'record'\n\nexport class AnnotationToolbar {\n private el: HTMLDivElement\n // The capsule, which is what gets measured and dimmed. hintTextEl is only the\n // words inside it — dimming that instead would leave the capsule around them\n // at full strength, and shrink the region counted as \"under the pointer\".\n private hintBarEl: HTMLDivElement\n private hintTextEl!: HTMLSpanElement\n private host: HTMLElement\n private markupBtn!: HTMLButtonElement\n private recordBtn!: HTMLButtonElement\n private messages: I18nMessages\n private currentMode: ToolbarMode = 'markup'\n\n // The hint sits over the page and carries nothing to click, so it steps back\n // while the pointer is on top of it and comes forward again the moment the\n // pointer leaves. Nothing else about the page's movement affects it.\n //\n // This is a hover affordance, and touch has no hover — but a tap still emits\n // a compatibility move wherever the finger landed, which would dim the hint\n // for no reason. Restricting to a real mouse makes it a no-op on a phone.\n private handlePointerMove = (e: PointerEvent): void => {\n if (e.pointerType !== 'mouse') return\n\n const rect = this.hintBarEl.getBoundingClientRect()\n const inside =\n e.clientX >= rect.left && e.clientX <= rect.right && e.clientY >= rect.top && e.clientY <= rect.bottom\n\n this.hintBarEl.classList.toggle('mtb-hint-bar--under-pointer', inside)\n }\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n onExit: () => void,\n onModeChange?: (mode: ToolbarMode) => void,\n position: 'left' | 'right' = 'right',\n ) {\n this.messages = messages\n\n // Two siblings, not one element. A fixed-position child is laid out against\n // its nearest transformed ancestor rather than the viewport, and the bar is\n // transformed both at rest and by its entry animation — so a hint nested\n // inside it could never be centred on the page.\n this.hintBarEl = shadow.el<HTMLDivElement>('div', 'mtb-hint-bar')\n this.hintBarEl.innerHTML = `<span class=\"mtb-toolbar-hint\">${messages.toolbar.hint}</span>`\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-toolbar')\n if (position === 'left') this.el.classList.add('left')\n this.el.innerHTML = this.buildHTML(messages)\n shadow.append(this.hintBarEl, this.el)\n\n // Lets the CSS retire the tab for exactly as long as this bar is up. Keyed\n // to the bar's own lifetime rather than to the tab's active state: the tab\n // is still active while a clarification card is open, and by then the bar\n // is gone — hiding it there would leave no way out at all.\n this.host = shadow.host\n this.host.setAttribute('data-mtb-toolbar', '')\n\n this.hintTextEl = this.hintBarEl.querySelector('.mtb-toolbar-hint')!\n this.markupBtn = this.el.querySelector('.mtb-toolbar-mode-markup')!\n this.recordBtn = this.el.querySelector('.mtb-toolbar-mode-record')!\n\n this.markupBtn.addEventListener('click', () => {\n this.setMode('markup')\n onModeChange?.('markup')\n })\n this.recordBtn.addEventListener('click', () => {\n this.setMode('record')\n onModeChange?.('record')\n })\n this.el.querySelector('.mtb-exit-btn')!.addEventListener('click', onExit)\n\n document.addEventListener('pointermove', this.handlePointerMove as EventListener)\n }\n\n private buildHTML(m: I18nMessages): string {\n return `\n <div class=\"mtb-toolbar-modes\">\n <button class=\"mtb-toolbar-mode-btn mtb-toolbar-mode-markup active\" aria-label=\"${m.toolbar.markup}\" title=\"${m.toolbar.markup}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><circle cx=\"12\" cy=\"12\" r=\"9\"/><line x1=\"12\" y1=\"3\" x2=\"12\" y2=\"7\"/><line x1=\"12\" y1=\"17\" x2=\"12\" y2=\"21\"/><line x1=\"3\" y1=\"12\" x2=\"7\" y2=\"12\"/><line x1=\"17\" y1=\"12\" x2=\"21\" y2=\"12\"/></svg><span class=\"mtb-toolbar-label\">${m.toolbar.markup}</span>\n </button>\n <button class=\"mtb-toolbar-mode-btn mtb-toolbar-mode-record\" aria-label=\"${m.toolbar.record}\" title=\"${m.toolbar.record}\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"2\" y=\"6\" width=\"13\" height=\"12\" rx=\"2.5\"/><path d=\"M15 10.5 21.2 7.4a.6.6 0 0 1 .8.5v8.2a.6.6 0 0 1-.8.5L15 13.5z\"/></svg><span class=\"mtb-toolbar-label\">${m.toolbar.record}</span>\n </button>\n </div>\n <span class=\"mtb-toolbar-sep\"></span>\n <button class=\"mtb-exit-btn\" aria-label=\"${m.toolbar.exit}\" title=\"${m.toolbar.exit}\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg><span class=\"mtb-toolbar-label\">${m.toolbar.exit}</span>\n </button>\n `\n }\n\n setMode(mode: ToolbarMode): void {\n this.currentMode = mode\n if (mode === 'markup') {\n this.markupBtn.classList.add('active')\n this.recordBtn.classList.remove('active')\n this.hintTextEl.textContent = this.messages.toolbar.hint\n } else {\n this.markupBtn.classList.remove('active')\n this.recordBtn.classList.add('active')\n this.hintTextEl.textContent = this.messages.toolbar.hintRecord\n }\n }\n\n getMode(): ToolbarMode {\n return this.currentMode\n }\n\n destroy(): void {\n document.removeEventListener('pointermove', this.handlePointerMove as EventListener)\n this.host.removeAttribute('data-mtb-toolbar')\n this.hintBarEl.remove()\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\n\nexport interface OverlayHandlers {\n onPointerDown: (e: PointerEvent) => void\n onPointerMove: (e: PointerEvent) => void\n onPointerUp: (e: PointerEvent) => void\n onPointerCancel: (e: PointerEvent) => void\n}\n\n/**\n * The annotation surface. Runs on pointer events only — never mouse events.\n *\n * Mouse listeners are deliberately absent. Touch browsers replay a tap as\n * pointerdown/up followed by compatibility mousedown/up/click, so listening to\n * both would run the annotation logic twice for one tap and drop two pins.\n * Pointer events already cover mouse and stylus, so the desktop loses nothing.\n */\nexport class AnnotationOverlay {\n private overlayEl: HTMLDivElement\n private dimEl: HTMLDivElement\n private handlers: OverlayHandlers\n private onPointerDown: (e: Event) => void\n private onPointerMove: (e: Event) => void\n private onPointerUp: (e: Event) => void\n private onPointerCancel: (e: Event) => void\n\n constructor(shadow: ShadowContainer, handlers: OverlayHandlers) {\n this.handlers = handlers\n\n this.overlayEl = shadow.el<HTMLDivElement>('div', 'mtb-overlay')\n\n this.onPointerDown = (e) => {\n const pe = e as PointerEvent\n if (!pe.isPrimary) return\n // Capture keeps a stroke alive when the finger crosses the overlay edge.\n // Without it, a drag that leaves the surface silently stops mid-line.\n try {\n this.overlayEl.setPointerCapture(pe.pointerId)\n } catch {\n // Thrown when the pointer is already gone. The stroke can still run\n // uncaptured, so this is not worth aborting the gesture over.\n }\n this.handlers.onPointerDown(pe)\n }\n\n this.onPointerMove = (e) => {\n const pe = e as PointerEvent\n if (!pe.isPrimary) return\n this.handlers.onPointerMove(pe)\n }\n\n this.onPointerUp = (e) => {\n const pe = e as PointerEvent\n if (!pe.isPrimary) return\n this.releaseCapture(pe.pointerId)\n this.handlers.onPointerUp(pe)\n }\n\n // Replaces the old mouseleave path. The browser fires this when it takes\n // the gesture away from us — a system gesture, or the page going\n // background — which is exactly when a half-drawn stroke should end.\n this.onPointerCancel = (e) => {\n const pe = e as PointerEvent\n // A palm or second finger can be cancelled on its own. That pointer never\n // reached the handlers, so acting on its cancel would cut short a stroke\n // the primary finger is still drawing.\n if (!pe.isPrimary) return\n this.releaseCapture(pe.pointerId)\n this.handlers.onPointerCancel(pe)\n }\n\n this.overlayEl.addEventListener('pointerdown', this.onPointerDown)\n this.overlayEl.addEventListener('pointermove', this.onPointerMove)\n this.overlayEl.addEventListener('pointerup', this.onPointerUp)\n this.overlayEl.addEventListener('pointercancel', this.onPointerCancel)\n shadow.append(this.overlayEl)\n\n this.dimEl = shadow.el<HTMLDivElement>('div', 'mtb-dim')\n shadow.append(this.dimEl)\n }\n\n private releaseCapture(pointerId: number): void {\n try {\n this.overlayEl.releasePointerCapture(pointerId)\n } catch {\n // Already released, or the pointer is gone. Nothing to undo.\n }\n }\n\n destroy(): void {\n this.overlayEl.removeEventListener('pointerdown', this.onPointerDown)\n this.overlayEl.removeEventListener('pointermove', this.onPointerMove)\n this.overlayEl.removeEventListener('pointerup', this.onPointerUp)\n this.overlayEl.removeEventListener('pointercancel', this.onPointerCancel)\n this.overlayEl.remove()\n this.dimEl.remove()\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\n\nexport class ElementHighlighter {\n private highlightEl: HTMLDivElement\n private tooltipEl: HTMLDivElement\n\n constructor(shadow: ShadowContainer) {\n this.highlightEl = shadow.el<HTMLDivElement>('div', 'mtb-highlight')\n this.tooltipEl = shadow.el<HTMLDivElement>('div', 'mtb-highlight-tooltip')\n this.hide()\n shadow.append(this.highlightEl, this.tooltipEl)\n }\n\n highlight(el: Element): void {\n const rect = el.getBoundingClientRect()\n this.highlightEl.style.top = `${rect.top - 2}px`\n this.highlightEl.style.left = `${rect.left - 2}px`\n this.highlightEl.style.width = `${rect.width + 4}px`\n this.highlightEl.style.height = `${rect.height + 4}px`\n this.highlightEl.style.display = 'block'\n this.showTooltip(el, rect)\n }\n\n private showTooltip(el: Element, rect: DOMRect): void {\n this.tooltipEl.textContent = getElementName(el)\n const below = rect.top < 30\n this.tooltipEl.classList.toggle('below', below)\n this.tooltipEl.style.left = `${rect.left + rect.width / 2}px`\n this.tooltipEl.style.top = below ? `${rect.bottom + 8}px` : `${rect.top - 8}px`\n this.tooltipEl.style.display = 'block'\n }\n\n select(): void {\n this.highlightEl.classList.add('selected')\n this.tooltipEl.style.display = 'none'\n }\n\n hide(): void {\n this.highlightEl.style.display = 'none'\n this.highlightEl.classList.remove('selected')\n this.tooltipEl.style.display = 'none'\n }\n\n destroy(): void {\n this.highlightEl.remove()\n this.tooltipEl.remove()\n }\n}\n\n// textContent counts the source of <style> and <script> children as text. A\n// page with an inline stylesheet in its header therefore names that header\n// after its own CSS, and that name travels into the pin, the report, and the\n// triage prompt. Only what a reader would see counts.\nconst UNRENDERED = /^(script|style|noscript|template)$/i\n\nfunction renderedText(el: Element, limit = 80): string {\n let out = ''\n for (const node of Array.from(el.childNodes)) {\n if (out.length >= limit) break\n\n if (node.nodeType === 3) {\n out += node.nodeValue ?? ''\n } else if (node instanceof Element && !UNRENDERED.test(node.tagName)) {\n out += renderedText(node, limit - out.length)\n }\n }\n return out\n}\n\nexport function getElementName(el: Element): string {\n if (el instanceof HTMLElement) {\n const label = el.getAttribute('aria-label')\n if (label) return label\n\n const title = el.getAttribute('title')\n if (title) return title\n\n const text = renderedText(el).trim().slice(0, 40)\n if (text) return text\n\n const placeholder = (el as HTMLInputElement).placeholder\n if (placeholder) return placeholder\n\n const alt = (el as HTMLImageElement).alt\n if (alt) return alt\n\n const dataMark = el.getAttribute('data-mark')\n if (dataMark) return dataMark\n }\n return el.tagName.toLowerCase()\n}\n\nexport function getCssSelector(el: Element): string {\n const parts: string[] = []\n let current: Element | null = el\n while (current && current !== document.body && parts.length < 5) {\n let selector = current.tagName.toLowerCase()\n if (current.id) {\n selector = `#${current.id}`\n parts.unshift(selector)\n break\n }\n const classNames = Array.from(current.classList)\n .filter(c => !c.startsWith('mtb-'))\n .slice(0, 2)\n .join('.')\n if (classNames) selector += `.${classNames}`\n\n const parent = current.parentElement\n if (parent) {\n const siblings = Array.from(parent.children).filter(\n c => c.tagName === current!.tagName,\n )\n if (siblings.length > 1) {\n const idx = siblings.indexOf(current) + 1\n selector += `:nth-of-type(${idx})`\n }\n }\n\n parts.unshift(selector)\n current = current.parentElement\n }\n return parts.join(' > ')\n}\n","import type { ShadowContainer } from '../widget/shadow'\n\nexport class PinMarker {\n private pins: HTMLDivElement[] = []\n private shadow: ShadowContainer\n\n constructor(shadow: ShadowContainer) {\n this.shadow = shadow\n }\n\n addPin(x: number, y: number): void {\n const pin = this.shadow.el<HTMLDivElement>('div', 'mtb-pin')\n pin.style.top = `${y}px`\n pin.style.left = `${x}px`\n this.shadow.append(pin)\n this.pins.push(pin)\n }\n\n clearAll(): void {\n for (const pin of this.pins) pin.remove()\n this.pins = []\n }\n\n destroy(): void {\n this.clearAll()\n }\n}\n","export const BRAND_COLOR = '#059669'\n// Same green as BRAND_COLOR, in the form shadows need. Derived once so a brand\n// change cannot leave the shadows on the old colour.\nconst BRAND_RGB = '5,150,105'\n\nexport function brandAlpha(alpha: number): string {\n return `rgba(${BRAND_RGB},${alpha})`\n}\n\nexport const FONT_STACK = '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif'\n\nexport const DRAW_STROKE = {\n color: BRAND_COLOR,\n width: '3.5',\n linecap: 'round',\n linejoin: 'round',\n filter: `drop-shadow(0 1px 2px ${brandAlpha(0.35)})`,\n} as const\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { Annotation } from '../types'\nimport { DRAW_STROKE } from '../styles'\n\ntype Point = [number, number]\n\ninterface Stroke {\n path: SVGPathElement\n d: string\n points: Point[]\n}\n\nexport class DrawLayer {\n private svg: SVGSVGElement\n private currentPath: SVGPathElement | null = null\n private currentPoints: Point[] = []\n private isDrawing = false\n private committed: Stroke[] = []\n private redoStack: { d: string; points: Point[] }[] = []\n\n constructor(shadow: ShadowContainer) {\n this.svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n this.svg.setAttribute('class', 'mtb-draw-svg')\n shadow.append(this.svg)\n }\n\n startDraw(x: number, y: number): void {\n this.isDrawing = true\n this.currentPoints = [[x, y]]\n this.currentPath = this.createPath()\n this.svg.appendChild(this.currentPath)\n }\n\n continueDraw(x: number, y: number): void {\n if (!this.isDrawing || !this.currentPath) return\n this.currentPoints.push([x, y])\n this.currentPath.setAttribute('d', buildPathD(this.currentPoints))\n }\n\n // Commits the in-progress stroke to the undo stack and clears the redo stack.\n // Callers decide whether the stroke has enough points before committing.\n commitStroke(): boolean {\n if (!this.isDrawing || !this.currentPath) return false\n this.isDrawing = false\n this.committed.push({ path: this.currentPath, d: buildPathD(this.currentPoints), points: this.currentPoints })\n this.redoStack = []\n this.currentPath = null\n this.currentPoints = []\n return true\n }\n\n cancelCurrentDraw(): void {\n this.currentPath?.remove()\n this.currentPath = null\n this.isDrawing = false\n this.currentPoints = []\n }\n\n undo(): boolean {\n const stroke = this.committed.pop()\n if (!stroke) return false\n stroke.path.remove()\n this.redoStack.push({ d: stroke.d, points: stroke.points })\n return true\n }\n\n redo(): boolean {\n const entry = this.redoStack.pop()\n if (!entry) return false\n const path = this.createPath()\n path.setAttribute('d', entry.d)\n this.svg.appendChild(path)\n this.committed.push({ path, d: entry.d, points: entry.points })\n return true\n }\n\n canUndo(): boolean {\n return this.committed.length > 0\n }\n\n canRedo(): boolean {\n return this.redoStack.length > 0\n }\n\n hasStrokes(): boolean {\n return this.committed.length > 0\n }\n\n getAnnotation(): Annotation | null {\n if (this.committed.length === 0) return null\n const points = this.committed.flatMap(s => s.points)\n const [cx, cy] = center(points)\n return {\n type: 'draw',\n x: cx,\n y: cy,\n drawPath: this.committed.map(s => s.d).join(' '),\n }\n }\n\n clearAll(): void {\n while (this.svg.firstChild) this.svg.removeChild(this.svg.firstChild)\n this.currentPath = null\n this.isDrawing = false\n this.currentPoints = []\n this.committed = []\n this.redoStack = []\n }\n\n isCurrentlyDrawing(): boolean {\n return this.isDrawing\n }\n\n getCurrentPointCount(): number {\n return this.currentPoints.length\n }\n\n destroy(): void {\n this.svg.remove()\n }\n\n private createPath(): SVGPathElement {\n const path = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n path.setAttribute('fill', 'none')\n path.setAttribute('stroke', DRAW_STROKE.color)\n path.setAttribute('stroke-width', DRAW_STROKE.width)\n path.setAttribute('stroke-linecap', DRAW_STROKE.linecap)\n path.setAttribute('stroke-linejoin', DRAW_STROKE.linejoin)\n path.setAttribute('style', `filter:${DRAW_STROKE.filter}`)\n return path\n }\n}\n\nfunction buildPathD(points: Point[]): string {\n if (points.length === 0) return ''\n const [fx, fy] = points[0]\n let d = `M ${fx} ${fy}`\n for (let i = 1; i < points.length; i++) {\n const [x, y] = points[i]\n d += ` L ${x} ${y}`\n }\n return d\n}\n\nfunction center(points: Point[]): Point {\n const xs = points.map(p => p[0])\n const ys = points.map(p => p[1])\n const cx = (Math.min(...xs) + Math.max(...xs)) / 2\n const cy = (Math.min(...ys) + Math.max(...ys)) / 2\n return [cx, cy]\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { Annotation } from '../types'\nimport { AnnotationOverlay } from './overlay'\nimport { ElementHighlighter, getElementName, getCssSelector } from './highlighter'\nimport { PinMarker } from './pin'\nimport { DrawLayer } from './draw'\n\nconst DRAW_MIN_POINTS = 5\n\ninterface SessionHandlers {\n onPin: (annotation: Annotation, targetName: string) => void\n onDrawStroke: () => void\n}\n\nexport class AnnotationSession {\n private overlay: AnnotationOverlay\n private highlighter: ElementHighlighter\n private pinMarker: PinMarker\n private drawLayer: DrawLayer\n private interactionActive = true\n private pendingHighlightFrame: number | null = null\n private lastMoveX = 0\n private lastMoveY = 0\n\n constructor(\n shadow: ShadowContainer,\n private messages: I18nMessages,\n private handlers: SessionHandlers,\n ) {\n this.highlighter = new ElementHighlighter(shadow)\n this.pinMarker = new PinMarker(shadow)\n this.drawLayer = new DrawLayer(shadow)\n this.overlay = new AnnotationOverlay(shadow, {\n onPointerDown: (e) => this.handlePointerDown(e),\n onPointerMove: (e) => this.handlePointerMove(e),\n onPointerUp: (e) => this.handlePointerUp(e),\n // Previously mouseleave. The overlay now captures the pointer, so a\n // stroke no longer ends by wandering off the surface — only by the\n // browser taking the gesture away, which is what pointercancel means.\n onPointerCancel: () => {\n if (this.drawLayer.isCurrentlyDrawing()) this.finishStroke()\n this.cancelPendingHighlight()\n this.highlighter.hide()\n },\n })\n }\n\n private handlePointerDown(e: PointerEvent): void {\n e.preventDefault()\n this.drawLayer.startDraw(e.clientX, e.clientY)\n }\n\n private handlePointerMove(e: PointerEvent): void {\n if (this.drawLayer.isCurrentlyDrawing()) {\n this.cancelPendingHighlight()\n this.drawLayer.continueDraw(e.clientX, e.clientY)\n this.highlighter.hide()\n return\n }\n\n this.lastMoveX = e.clientX\n this.lastMoveY = e.clientY\n if (this.pendingHighlightFrame !== null) return\n this.pendingHighlightFrame = requestAnimationFrame(() => {\n this.pendingHighlightFrame = null\n this.updateHighlight()\n })\n }\n\n private updateHighlight(): void {\n if (!this.interactionActive || this.drawLayer.isCurrentlyDrawing() || this.drawSessionActive()) return\n const underEl = getElementUnder(this.lastMoveX, this.lastMoveY)\n if (underEl) this.highlighter.highlight(underEl)\n else this.highlighter.hide()\n }\n\n private cancelPendingHighlight(): void {\n if (this.pendingHighlightFrame === null) return\n cancelAnimationFrame(this.pendingHighlightFrame)\n this.pendingHighlightFrame = null\n }\n\n private handlePointerUp(e: PointerEvent): void {\n if (!this.drawLayer.isCurrentlyDrawing()) return\n this.finishStroke(e)\n }\n\n // A drag past the point threshold becomes a freehand stroke and opens the\n // draw note bar; a tap on an element becomes a pin. Stray taps while a\n // drawing already exists are ignored so they don't hijack the draw flow.\n private finishStroke(e?: PointerEvent): void {\n if (this.drawLayer.getCurrentPointCount() >= DRAW_MIN_POINTS) {\n this.drawLayer.commitStroke()\n this.highlighter.hide()\n this.handlers.onDrawStroke()\n return\n }\n\n this.drawLayer.cancelCurrentDraw()\n if (this.drawLayer.hasStrokes() || !e) return\n\n const underEl = getElementUnder(e.clientX, e.clientY)\n const targetName = underEl ? getElementName(underEl) : this.messages.annotation.element\n const rect = underEl?.getBoundingClientRect()\n const annotation: Annotation = {\n type: 'pin',\n x: e.clientX,\n y: e.clientY,\n targetSelector: underEl ? getCssSelector(underEl) : undefined,\n targetText: underEl?.textContent?.trim().slice(0, 200) ?? '',\n targetName,\n targetRect: rect ? { top: rect.top, left: rect.left, width: rect.width, height: rect.height, bottom: rect.bottom } : undefined,\n }\n this.pinMarker.addPin(e.clientX, e.clientY)\n this.highlighter.select()\n this.handlers.onPin(annotation, targetName)\n }\n\n undoDraw(): void {\n this.drawLayer.undo()\n }\n\n redoDraw(): void {\n this.drawLayer.redo()\n }\n\n canUndoDraw(): boolean {\n return this.drawLayer.canUndo()\n }\n\n canRedoDraw(): boolean {\n return this.drawLayer.canRedo()\n }\n\n hasDrawStrokes(): boolean {\n return this.drawLayer.hasStrokes()\n }\n\n private drawSessionActive(): boolean {\n return this.drawLayer.hasStrokes() || this.drawLayer.canRedo()\n }\n\n getDrawAnnotation(): Annotation | null {\n return this.drawLayer.getAnnotation()\n }\n\n clearDraw(): void {\n this.drawLayer.clearAll()\n }\n\n dismissInteraction(): void {\n if (!this.interactionActive) return\n this.interactionActive = false\n this.cancelPendingHighlight()\n this.overlay.destroy()\n }\n\n hideHighlight(): void {\n this.highlighter.hide()\n }\n\n destroy(): void {\n this.dismissInteraction()\n this.highlighter.destroy()\n this.pinMarker.destroy()\n this.drawLayer.destroy()\n }\n}\n\n// Skips the widget host via elementsFromPoint instead of toggling its\n// display — hiding the host on every mousemove flickered the toolbar.\nfunction getElementUnder(x: number, y: number): Element | null {\n return document.elementsFromPoint(x, y).find(el => el.id !== 'mtb-widget-host') ?? null\n}\n","const WIDGET_HOST_ID = 'mtb-widget-host'\n\nexport function isWidgetElement(el: Element): boolean {\n const host = document.getElementById(WIDGET_HOST_ID)\n if (!host) return false\n return host === el || host.contains(el)\n}\n\nexport function escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;')\n}\n","/**\n * How much of the window the software keyboard is covering.\n *\n * A `position: fixed` sheet gets no help from the browser here — the built-in\n * \"scroll the focused field into view\" only moves elements that are in the\n * document flow, so on iOS the keyboard simply covers the sheet.\n *\n * The two platforms hide the keyboard in different places, and this one\n * formula covers both. iOS keeps the layout viewport at full height and\n * shrinks (and shifts) the visual viewport, so the difference is the keyboard.\n * Android resizes the layout viewport itself, so `innerHeight` shrinks too and\n * the difference falls out to zero — which is the right answer there, because\n * the bottom of the window is already above the keyboard.\n *\n * `offsetTop` matters as much as `height`: iOS shifts the visual viewport up\n * as well as shrinking it, and ignoring the shift leaves the sheet floating\n * exactly that far off, with a strip of page showing beneath it.\n */\nexport class KeyboardInset {\n private onChange: ((inset: number) => void) | null = null\n private handler = (): void => {\n this.onChange?.(this.current())\n }\n\n current(): number {\n const vp = window.visualViewport\n if (!vp) return 0\n return Math.max(0, Math.round(window.innerHeight - (vp.height + vp.offsetTop)))\n }\n\n observe(onChange: (inset: number) => void): void {\n const vp = window.visualViewport\n if (!vp) return\n this.onChange = onChange\n vp.addEventListener('resize', this.handler)\n // Scroll fires for the shift-up on iOS, which resize alone does not report.\n vp.addEventListener('scroll', this.handler)\n }\n\n stop(): void {\n const vp = window.visualViewport\n this.onChange = null\n if (!vp) return\n vp.removeEventListener('resize', this.handler)\n vp.removeEventListener('scroll', this.handler)\n }\n}\n","import { KeyboardInset } from './keyboard-inset'\n\n/**\n * Matches the `max-width: 480px` block in widget.css, where every panel that\n * holds a text field stops being a card anchored near the annotation and\n * becomes a bottom sheet.\n */\nexport const SHEET_MAX_WIDTH = 480\n\nexport function isSheetViewport(): boolean {\n return window.innerWidth <= SHEET_MAX_WIDTH\n}\n\n/**\n * Hands a panel's geometry to the stylesheet on narrow screens, and keeps it\n * clear of the software keyboard.\n *\n * Two jobs that have to live together. The panels each position themselves\n * with inline `left`/`top`, which would beat the media query and drag the sheet\n * back into a floating card — so the inline values have to be cleared, not just\n * overridden. And a `position: fixed` sheet gets no help from the browser's\n * scroll-into-view, which only moves elements in the document flow, so the\n * keyboard simply covers it unless something lifts it.\n *\n * Shared by the comment popup, the clarify card, and the draw note bar: all\n * three carry a text field, and all three are the last thing between a reporter\n * and a submitted report.\n */\nexport class SheetLayout {\n private inset = new KeyboardInset()\n\n constructor(private el: HTMLElement) {}\n\n /** Returns true when this took over layout, i.e. the caller should not position. */\n apply(): boolean {\n if (!isSheetViewport()) return false\n\n this.el.style.left = ''\n this.el.style.top = ''\n this.el.style.maxHeight = ''\n this.lift(this.inset.current())\n this.inset.observe((px) => this.lift(px))\n return true\n }\n\n release(): void {\n this.inset.stop()\n }\n\n private lift(inset: number): void {\n this.el.style.bottom = inset > 0 ? `${inset}px` : ''\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport { escapeHtml } from '../context/dom-utils'\nimport { SheetLayout } from '../popup/sheet'\n\ninterface DrawNoteBarOptions {\n messages: I18nMessages\n onUndo: () => void\n onRedo: () => void\n onCancel: () => void\n onSubmit: (note: string) => void\n}\n\nexport class DrawNoteBar {\n private el: HTMLDivElement\n private sheet: SheetLayout\n private input!: HTMLInputElement\n private undoBtn!: HTMLButtonElement\n private redoBtn!: HTMLButtonElement\n private submitBtn!: HTMLButtonElement\n private errorEl!: HTMLDivElement\n private onSubmit: (note: string) => void\n private submitLabel: string\n private loading = false\n\n constructor(shadow: ShadowContainer, opts: DrawNoteBarOptions) {\n this.onSubmit = opts.onSubmit\n this.submitLabel = opts.messages.draw.submit\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-draw-bar')\n this.el.innerHTML = this.buildHTML(opts.messages)\n shadow.append(this.el)\n // The bar carries a text field and sits flush to the bottom on a phone,\n // which is exactly where the keyboard lands.\n this.sheet = new SheetLayout(this.el)\n this.sheet.apply()\n\n this.input = this.el.querySelector('.mtb-draw-input')!\n this.undoBtn = this.el.querySelector('.mtb-draw-undo')!\n this.redoBtn = this.el.querySelector('.mtb-draw-redo')!\n this.submitBtn = this.el.querySelector('.mtb-draw-submit')!\n this.errorEl = this.el.querySelector('.mtb-draw-error')!\n\n this.undoBtn.addEventListener('click', opts.onUndo)\n this.redoBtn.addEventListener('click', opts.onRedo)\n this.el.querySelector('.mtb-draw-cancel')!.addEventListener('click', opts.onCancel)\n this.submitBtn.addEventListener('click', () => this.submit())\n this.input.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n this.submit()\n }\n })\n\n this.input.focus()\n }\n\n private buildHTML(m: I18nMessages): string {\n return `\n <input class=\"mtb-draw-input\" type=\"text\" placeholder=\"${escapeHtml(m.draw.note_placeholder)}\" />\n <button class=\"mtb-draw-icon-btn mtb-draw-undo\" type=\"button\" title=\"${escapeHtml(m.draw.undo)}\" aria-label=\"${escapeHtml(m.draw.undo)}\" disabled>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M9 14L4 9l5-5\"/><path d=\"M4 9h11a5 5 0 0 1 0 10h-1\"/></svg>\n </button>\n <button class=\"mtb-draw-icon-btn mtb-draw-redo\" type=\"button\" title=\"${escapeHtml(m.draw.redo)}\" aria-label=\"${escapeHtml(m.draw.redo)}\" disabled>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M15 14l5-5-5-5\"/><path d=\"M20 9H9a5 5 0 0 0 0 10h1\"/></svg>\n </button>\n <span class=\"mtb-draw-sep\"></span>\n <button class=\"mtb-draw-cancel\" type=\"button\">${escapeHtml(m.draw.cancel)}</button>\n <button class=\"mtb-draw-submit\" type=\"button\">${escapeHtml(m.draw.submit)}</button>\n <div class=\"mtb-draw-error\" role=\"alert\" hidden></div>\n `\n }\n\n setUndoRedo(canUndo: boolean, canRedo: boolean): void {\n this.undoBtn.disabled = !canUndo || this.loading\n this.redoBtn.disabled = !canRedo || this.loading\n }\n\n setLoading(loading: boolean): void {\n this.loading = loading\n this.input.disabled = loading\n this.submitBtn.disabled = loading\n this.undoBtn.disabled = loading || this.undoBtn.disabled\n this.redoBtn.disabled = loading || this.redoBtn.disabled\n if (loading) {\n this.submitBtn.classList.add('loading')\n this.submitBtn.innerHTML = `<span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span>`\n this.errorEl.hidden = true\n this.errorEl.textContent = ''\n } else {\n this.submitBtn.classList.remove('loading')\n this.submitBtn.textContent = this.submitLabel\n }\n }\n\n setError(message: string): void {\n this.errorEl.textContent = message\n this.errorEl.hidden = false\n }\n\n private submit(): void {\n if (this.loading) return\n this.onSubmit(this.input.value.trim())\n }\n\n destroy(): void {\n this.sheet.release()\n this.el.remove()\n }\n}\n\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { TargetRect } from '../types'\nimport { escapeHtml } from '../context/dom-utils'\nimport { SheetLayout } from './sheet'\n\ninterface PopupOptions {\n targetName: string\n x: number\n y: number\n targetRect?: TargetRect\n onSubmit: (description: string) => void\n onClose: () => void\n onMyFeedback?: () => void\n messages: I18nMessages\n position?: 'left' | 'right'\n}\n\nexport class CommentPopup {\n private el: HTMLDivElement\n private sheet: SheetLayout\n private textarea!: HTMLTextAreaElement\n private submitBtn!: HTMLButtonElement\n private errorEl!: HTMLDivElement\n private onSubmit: (description: string) => void\n private onClose: () => void\n private submitLabel: string\n private loading = false\n private messages: I18nMessages\n private selectedQuickOption: string | null = null\n\n constructor(shadow: ShadowContainer, opts: PopupOptions) {\n this.onSubmit = opts.onSubmit\n this.onClose = opts.onClose\n this.submitLabel = opts.messages.popup.submit\n this.messages = opts.messages\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-popup')\n this.el.innerHTML = this.buildHTML(opts)\n shadow.append(this.el)\n this.sheet = new SheetLayout(this.el)\n\n this.textarea = this.el.querySelector('.mtb-textarea')!\n this.submitBtn = this.el.querySelector('.mtb-submit-btn')!\n\n this.positionPopup(opts.x, opts.y, opts.targetRect, opts.position ?? 'right')\n this.bindEvents(opts.messages)\n if (opts.onMyFeedback) {\n this.el.querySelector('.mtb-my-feedback')!.addEventListener('click', opts.onMyFeedback)\n }\n this.textarea.focus()\n }\n\n private buildHTML(opts: PopupOptions): string {\n const m = opts.messages\n const quickOpts = m.popup.quickOptions\n .map(\n o => `\n <button class=\"mtb-quick-option\" data-quick=\"${escapeHtml(o.label)}\">\n <span class=\"mtb-quick-option-emoji\">${o.emoji}</span>\n <span>${escapeHtml(o.label)}</span>\n </button>`,\n )\n .join('')\n\n return `\n <div class=\"mtb-popup-header\">\n <div class=\"mtb-popup-icon\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#059669\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z\"/><circle cx=\"12\" cy=\"10\" r=\"3\"/>\n </svg>\n </div>\n <span class=\"mtb-popup-title\">${m.popup.about} \"${escapeHtml(opts.targetName)}\"</span>\n <button class=\"mtb-popup-close\" aria-label=\"Close\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n <div class=\"mtb-popup-body\">\n <div class=\"mtb-quick-options\">\n ${quickOpts}\n </div>\n <div class=\"mtb-textarea-wrap\">\n <textarea class=\"mtb-textarea\" placeholder=\"${escapeHtml(m.popup.placeholder)}\"></textarea>\n </div>\n <div class=\"mtb-popup-error\" role=\"alert\"></div>\n <div class=\"mtb-popup-actions\">\n <button class=\"mtb-cancel-btn\" type=\"button\">${escapeHtml(m.popup.cancel)}</button>\n <button class=\"mtb-submit-btn\" type=\"button\" disabled>${escapeHtml(m.popup.submit)}</button>\n </div>\n ${opts.onMyFeedback ? `<button class=\"mtb-my-feedback\" type=\"button\">${escapeHtml(m.popup.my_feedback)}</button>` : ''}\n </div>\n `\n }\n\n\n\n private positionPopup(x: number, y: number, targetRect: TargetRect | undefined, tabPosition: 'left' | 'right'): void {\n if (this.sheet.apply()) return\n\n const vw = window.innerWidth\n const vh = window.innerHeight\n const margin = 12\n const gap = 8\n const tabWidth = 32\n const popupW = Math.min(320, vw - 2 * margin - tabWidth)\n const popupH = this.el.offsetHeight || 260\n const minLeft = margin + (tabPosition === 'left' ? tabWidth : 0)\n const maxRight = vw - margin - (tabPosition === 'right' ? tabWidth : 0)\n\n let left: number\n let top: number\n\n // Anchoring to the element only helps while the element is small enough to\n // point at. A click on empty space lands on whatever section or body spans\n // the page, and its rect says nothing about where the user clicked: the top\n // edge is off-screen, so the popup flips, and the left edge is 0, so it\n // lands in the bottom-left corner however far right the click was.\n const anchorIsInformative =\n targetRect && targetRect.width < vw * 0.6 && targetRect.height < vh * 0.6\n\n if (targetRect && anchorIsInformative) {\n left = targetRect.left\n top = targetRect.bottom + gap\n\n if (top + popupH > vh - margin) {\n top = targetRect.top - popupH - gap\n }\n if (top < margin) {\n top = Math.min(targetRect.bottom + gap, vh - popupH - margin)\n }\n } else {\n left = x + 12\n top = y + 12\n }\n\n if (left + popupW > maxRight) {\n left = maxRight - popupW\n }\n if (left < minLeft) left = minLeft\n if (top < margin) top = margin\n\n this.el.style.left = `${left}px`\n this.el.style.top = `${top}px`\n this.el.style.maxHeight = `${vh - top - margin}px`\n }\n\n private bindEvents(messages: I18nMessages): void {\n this.el.querySelector('.mtb-popup-close')!.addEventListener('click', () => this.onClose())\n this.el.querySelector('.mtb-cancel-btn')!.addEventListener('click', () => this.onClose())\n this.errorEl = this.el.querySelector('.mtb-popup-error')!\n\n this.el.querySelectorAll('.mtb-quick-option').forEach(btn => {\n btn.addEventListener('click', () => {\n const label = (btn as HTMLElement).dataset['quick'] ?? ''\n\n if (this.textarea.value.trim().length === 0) {\n this.textarea.value = label\n this.updateSubmitState()\n this.submit()\n return\n }\n\n this.selectedQuickOption = label\n this.el.querySelectorAll('.mtb-quick-option').forEach(option => {\n option.classList.toggle('selected', option === btn)\n })\n })\n })\n\n this.textarea.addEventListener('input', () => this.updateSubmitState())\n\n this.textarea.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n this.submit()\n }\n })\n\n this.submitBtn.addEventListener('click', () => this.submit())\n }\n\n private updateSubmitState(): void {\n const hasText = this.textarea.value.trim().length > 0\n this.submitBtn.classList.toggle('ready', hasText && !this.loading)\n this.submitBtn.disabled = !hasText || this.loading\n this.errorEl.hidden = true\n this.errorEl.textContent = ''\n }\n\n private submit(): void {\n const text = this.textarea.value.trim()\n if (!text || this.loading) return\n const description = this.selectedQuickOption ? `[${this.selectedQuickOption}] ${text}` : text\n this.onSubmit(description)\n }\n\n setLoading(loading: boolean): void {\n this.loading = loading\n if (loading) {\n this.submitBtn.classList.add('loading')\n this.submitBtn.innerHTML = `<span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span>`\n this.textarea.disabled = true\n } else {\n this.submitBtn.classList.remove('loading')\n this.submitBtn.textContent = this.submitLabel\n this.textarea.disabled = false\n }\n this.updateSubmitState()\n }\n\n setError(message: string): void {\n this.errorEl.textContent = message\n this.errorEl.hidden = false\n }\n\n releaseElement(): HTMLDivElement {\n // Ownership of the element passes to the caller, which means destroy() will\n // never run for this instance. Stop observing here or the listener outlives\n // the popup and keeps writing `bottom` on an element it no longer manages.\n this.sheet.release()\n return this.el\n }\n\n destroy(): void {\n this.sheet.release()\n this.el.remove()\n }\n}\n","import type {\n FeedbackPayload,\n FeedbackResponse,\n SubmissionSessionResponse,\n ClarifyResponse,\n ClarifyMessage,\n} from '../types'\n\nexport interface ClarifyStreamResult {\n messages: ClarifyMessage[]\n done: boolean\n failed?: boolean\n}\n\n// Carries the HTTP status so callers can tell a retryable failure from a terminal\n// one (e.g. 409 = the submission session is no longer accepting a finalize, which\n// retrying can never fix). The message stays `HTTP <status>` for compatibility.\nexport class ApiError extends Error {\n readonly status: number\n\n constructor(status: number) {\n super(`HTTP ${status}`)\n this.name = 'ApiError'\n this.status = status\n }\n}\n\nexport function isTerminalConflict(error: unknown): boolean {\n return error instanceof ApiError && error.status === 409\n}\n\nconst DEFAULT_API_URL = 'https://makethisbetter.dev/api/v1'\n\nexport class ApiClient {\n private apiUrl: string\n private projectKey: string\n private retryDelayMs: number\n private userToken?: string\n private userTokenFn?: () => Promise<string>\n\n constructor(projectKey: string, apiUrl?: string, retryDelayMs = 1000, userToken?: string, userTokenFn?: () => Promise<string>) {\n this.projectKey = projectKey\n this.apiUrl = (apiUrl ?? DEFAULT_API_URL).replace(/\\/$/, '')\n this.retryDelayMs = retryDelayMs\n this.userToken = userToken\n this.userTokenFn = userTokenFn\n }\n\n async resolveUserToken(): Promise<string | undefined> {\n if (this.userTokenFn) return this.userTokenFn()\n return this.userToken\n }\n\n private async authHeaders(contentType?: string): Promise<Record<string, string>> {\n const headers: Record<string, string> = { 'X-Project-Key': this.projectKey }\n const token = await this.resolveUserToken()\n if (token) headers['X-User-Token'] = token\n if (contentType) headers['Content-Type'] = contentType\n return headers\n }\n\n private async submissionHeaders(token: string, contentType?: string): Promise<Record<string, string>> {\n const headers = await this.authHeaders(contentType)\n headers['X-Submission-Token'] = token\n return headers\n }\n\n async createSubmissionSession(payload: FeedbackPayload, screenshot: Blob | null): Promise<SubmissionSessionResponse> {\n const submissionToken = generateSubmissionToken()\n const form = new FormData()\n form.append('feedback[description]', payload.description)\n form.append('feedback[page_url]', payload.page_url)\n form.append('feedback[user_agent]', payload.user_agent)\n form.append('feedback[browser]', payload.browser)\n form.append('feedback[os]', payload.os)\n form.append('feedback[screen_width]', String(payload.screen_width))\n form.append('feedback[screen_height]', String(payload.screen_height))\n form.append('feedback[console_errors]', JSON.stringify(payload.console_errors))\n form.append('feedback[annotations]', JSON.stringify(payload.annotations))\n\n if (payload.target_element) {\n form.append('feedback[target_element]', JSON.stringify(payload.target_element))\n }\n if (payload.user_id) form.append('feedback[user_id]', payload.user_id)\n if (payload.reporter_external_id) form.append('feedback[reporter_external_id]', payload.reporter_external_id)\n if (payload.reporter_email) form.append('feedback[reporter_email]', payload.reporter_email)\n if (payload.user_email) form.append('feedback[user_email]', payload.user_email)\n if (payload.user_name) form.append('feedback[user_name]', payload.user_name)\n\n if (payload.breadcrumbs && payload.breadcrumbs.length > 0) {\n form.append('feedback[breadcrumbs]', JSON.stringify(payload.breadcrumbs))\n }\n\n if (payload.recording_events && payload.recording_events.length > 0) {\n const json = JSON.stringify(payload.recording_events)\n const blob = new Blob([json], { type: 'application/json' })\n form.append('feedback[recording]', blob, 'interaction-replay.json')\n form.append('feedback[recording_duration]', String(payload.recording_duration ?? 0))\n }\n\n if (screenshot) {\n const ext = screenshot.type === 'image/jpeg' ? 'jpg' : 'png'\n form.append('feedback[screenshot]', screenshot, `screenshot.${ext}`)\n }\n\n const headers = await this.authHeaders()\n headers['X-Submission-Token'] = submissionToken\n // One key per submission, reused across retries: if the first POST\n // reached the server but the response was lost, the retry must not\n // create a second feedback.\n headers['X-Idempotency-Key'] = generateIdempotencyKey()\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions`, {\n method: 'POST',\n headers,\n body: form,\n })\n const body = await res.json() as {\n submission_session: Omit<SubmissionSessionResponse, 'token'> & { token?: string }\n }\n return { ...body.submission_session, token: submissionToken }\n }\n\n async createIdentityToken(reporterExternalId: string): Promise<{ identity_token: string; board_url: string } | null> {\n const headers = await this.authHeaders('application/json')\n try {\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/identity_tokens`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ reporter_external_id: reporterExternalId }),\n })\n return await res.json()\n } catch {\n return null\n }\n }\n\n async updateReporter(feedbackId: string, email: string, identityToken: string): Promise<boolean> {\n const headers = await this.authHeaders('application/json')\n headers['X-Identity-Token'] = identityToken\n try {\n await this.fetchWithRetry(`${this.apiUrl}/widget/feedbacks/${feedbackId}/reporter`, {\n method: 'PATCH',\n headers,\n body: JSON.stringify({ reporter: { email } }),\n })\n return true\n } catch {\n return false\n }\n }\n\n async startClarification(submissionSessionId: string, token: string, message?: string): Promise<ClarifyResponse> {\n const body: Record<string, string | boolean> = {}\n if (message) body.message = message\n return this.requestClarification(submissionSessionId, token, body)\n }\n\n async retryClarification(submissionSessionId: string, token: string): Promise<ClarifyResponse> {\n return this.requestClarification(submissionSessionId, token, { retry: true })\n }\n\n private async requestClarification(\n submissionSessionId: string,\n token: string,\n body: Record<string, string | boolean>,\n ): Promise<ClarifyResponse> {\n const headers = await this.submissionHeaders(token, 'application/json')\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/clarification`, {\n method: 'POST',\n headers,\n body: JSON.stringify(body),\n })\n const response = await res.json() as { clarification: ClarifyResponse }\n return response.clarification\n }\n\n async getClarification(submissionSessionId: string, token: string): Promise<ClarifyResponse> {\n const headers = await this.submissionHeaders(token)\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/clarification`, {\n method: 'GET',\n headers,\n })\n const response = await res.json() as { clarification: ClarifyResponse }\n return response.clarification\n }\n\n // Streams a clarification turn over SSE. Calls onDelta for each token and\n // resolves with the committed result. Throws if the server doesn't stream\n // (e.g. old backend returns JSON) so the caller can fall back to polling.\n async streamClarification(\n submissionSessionId: string,\n token: string,\n onDelta: (text: string) => void,\n signal?: AbortSignal,\n ): Promise<ClarifyStreamResult> {\n const headers = await this.submissionHeaders(token, 'application/json')\n headers['Accept'] = 'text/event-stream'\n\n const res = await fetch(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/clarification`, {\n method: 'POST',\n headers,\n body: JSON.stringify({}),\n signal,\n })\n\n const contentType = res.headers.get('Content-Type') ?? ''\n if (!res.ok || !res.body || !contentType.includes('text/event-stream')) {\n throw new Error('clarify stream unavailable')\n }\n\n return consumeSse(res.body, onDelta)\n }\n\n async finalizeSubmissionSession(submissionSessionId: string, token: string): Promise<FeedbackResponse> {\n const headers = await this.submissionHeaders(token)\n const res = await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}/feedback`, {\n method: 'POST',\n headers,\n })\n const response = await res.json() as { feedback: FeedbackResponse }\n return response.feedback\n }\n\n async abandonSubmissionSession(submissionSessionId: string, token: string): Promise<void> {\n const headers = await this.submissionHeaders(token)\n await this.fetchWithRetry(`${this.apiUrl}/widget/feedback_submission_sessions/${submissionSessionId}`, {\n method: 'DELETE',\n headers,\n })\n }\n\n private async fetchWithRetry(url: string, init: RequestInit, retries = 1): Promise<Response> {\n let res: Response\n try {\n res = await fetch(url, init)\n } catch (err) {\n if (retries > 0) {\n await delay(this.retryDelayMs)\n return this.fetchWithRetry(url, init, retries - 1)\n }\n throw err\n }\n\n if (res.ok) return res\n if (res.status >= 500 && retries > 0) {\n await delay(this.retryDelayMs)\n return this.fetchWithRetry(url, init, retries - 1)\n }\n throw new ApiError(res.status)\n }\n}\n\nfunction delay(ms: number): Promise<void> {\n if (ms <= 0) return Promise.resolve()\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\nasync function consumeSse(\n body: ReadableStream<Uint8Array>,\n onDelta: (text: string) => void,\n): Promise<ClarifyStreamResult> {\n const reader = body.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let result: ClarifyStreamResult | null = null\n\n const flush = (raw: string): void => {\n // Each SSE record is \"event: <name>\\n data: <json>\". Parse event + data.\n const eventLine = raw.split('\\n').find(l => l.startsWith('event:'))\n const dataLine = raw.split('\\n').find(l => l.startsWith('data:'))\n if (!dataLine) return\n const event = eventLine?.slice(6).trim()\n const payload = JSON.parse(dataLine.slice(5).trim())\n if (event === 'delta' && typeof payload.text === 'string') {\n onDelta(payload.text)\n } else if (event === 'done') {\n result = {\n messages: Array.isArray(payload.messages) ? payload.messages : [],\n done: payload.done !== false,\n failed: payload.error === true,\n }\n }\n }\n\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n let sep: number\n while ((sep = buffer.indexOf('\\n\\n')) !== -1) {\n const record = buffer.slice(0, sep)\n buffer = buffer.slice(sep + 2)\n try { flush(record) } catch { /* skip malformed record */ }\n }\n }\n\n buffer += decoder.decode()\n if (buffer.trim()) {\n try { flush(buffer) } catch { /* handled by the missing done check below */ }\n }\n if (!result) throw new Error('clarify stream ended before done')\n\n return result\n}\n\nfunction generateIdempotencyKey(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 12)}`\n}\n\nfunction generateSubmissionToken(): string {\n if (typeof crypto === 'undefined' || typeof crypto.getRandomValues !== 'function') {\n throw new Error('Secure random generation is unavailable')\n }\n\n const bytes = crypto.getRandomValues(new Uint8Array(32))\n return Array.from(bytes, byte => byte.toString(16).padStart(2, '0')).join('')\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { ApiClient, ClarifyStreamResult } from '../api/client'\nimport { isTerminalConflict } from '../api/client'\nimport type { ClarifyMessage, ClarifyResponse } from '../types'\nimport { escapeHtml } from '../context/dom-utils'\nimport { SheetLayout } from './sheet'\n\nconst POLL_INTERVAL_MS = 2000\n// Give up polling after this long with no assistant reply so the card never spins\n// forever (e.g. a backend job that silently died). This is the queued path — the\n// answer is being generated by a job, not streamed — so it needs room for queue wait\n// plus generation. The 12s deadline on the streaming request is a different budget:\n// there, silence means the stream itself is stuck.\nconst POLL_TIMEOUT_MS = 45000\n\ninterface ClarifyCardOptions {\n submissionSessionId: string\n submissionToken: string\n apiClient: ApiClient\n messages: I18nMessages\n onFinalize: () => Promise<void> | void\n element?: HTMLDivElement\n position?: 'left' | 'right'\n x?: number\n y?: number\n preloadedResult?: ClarifyStreamResult\n pendingClarification?: Promise<ClarifyStreamResult | null>\n}\n\nconst CARD_WIDTH = 346\nconst CARD_HEIGHT = 270\n\nexport class ClarifyCard {\n private el: HTMLDivElement\n private sheet: SheetLayout\n private messagesEl!: HTMLDivElement\n private inputEl!: HTMLTextAreaElement\n private sendBtn!: HTMLButtonElement\n private pollTimer: ReturnType<typeof setInterval> | null = null\n private pollDeadline = 0\n private streamingBubble: HTMLDivElement | null = null\n private submissionSessionId: string\n private submissionToken: string\n private apiClient: ApiClient\n private onFinalize: () => Promise<void> | void\n private i18n: I18nMessages\n private lastMessages: ClarifyMessage[] = []\n private done = false\n private sending = false\n private finalizing = false\n private destroyed = false\n private unrecoverable = false\n\n private preloadedResult?: ClarifyStreamResult\n private pendingClarification?: Promise<ClarifyStreamResult | null>\n\n constructor(shadow: ShadowContainer, opts: ClarifyCardOptions) {\n this.submissionSessionId = opts.submissionSessionId\n this.submissionToken = opts.submissionToken\n this.apiClient = opts.apiClient\n this.onFinalize = opts.onFinalize\n this.i18n = opts.messages\n this.preloadedResult = opts.preloadedResult\n this.pendingClarification = opts.pendingClarification\n\n const existingElement = opts.element\n this.el = existingElement ?? shadow.el<HTMLDivElement>('div', 'mtb-clarify')\n this.el.className = existingElement ? 'mtb-clarify mtb-clarify-continuation' : 'mtb-clarify'\n this.el.innerHTML = this.buildHTML(opts.messages)\n this.sheet = new SheetLayout(this.el)\n if (!existingElement) {\n shadow.append(this.el)\n this.positionCard(opts.x, opts.y, opts.position ?? 'right')\n } else {\n // A continuation inherits the comment popup's element, and with it the\n // sheet layout that popup was using — but the class just changed from\n // .mtb-popup to .mtb-clarify, so the sheet rules stop matching and the\n // cleared inline offsets leave a fixed element with nowhere to sit.\n // Re-applying binds the new class to the same geometry and re-attaches\n // the keyboard tracking the released popup gave up.\n this.sheet.apply()\n }\n\n this.messagesEl = this.el.querySelector('.mtb-clarify-messages')!\n this.bindEvents()\n this.startConversation()\n }\n\n // Anchors the card near the annotation point, clamped to the viewport so it\n // never overflows a screen edge (mirrors CommentPopup.positionPopup).\n private positionCard(x: number | undefined, y: number | undefined, tabPosition: 'left' | 'right'): void {\n if (this.sheet.apply()) return\n\n const vw = window.innerWidth\n const vh = window.innerHeight\n const margin = 12\n const tabWidth = 32\n const cardW = Math.min(CARD_WIDTH, vw - 2 * margin - tabWidth)\n const cardH = this.el.offsetHeight || CARD_HEIGHT\n const minLeft = margin + (tabPosition === 'left' ? tabWidth : 0)\n const maxRight = vw - margin - (tabPosition === 'right' ? tabWidth : 0)\n\n if (x === undefined || y === undefined) {\n const centeredLeft = Math.max(minLeft, (vw - cardW) / 2)\n this.el.style.left = `${Math.min(centeredLeft, maxRight - cardW)}px`\n this.el.style.top = `${Math.max(margin, (vh - cardH) / 2)}px`\n this.el.style.maxHeight = `${vh - 2 * margin}px`\n return\n }\n\n let left = x + 12\n let top = y + 12\n if (left + cardW > maxRight) left = x - cardW - 12\n if (left + cardW > maxRight) left = maxRight - cardW\n if (left < minLeft) left = minLeft\n if (top + cardH > vh - margin) top = vh - cardH - margin\n if (top < margin) top = margin\n\n this.el.style.left = `${left}px`\n this.el.style.top = `${top}px`\n this.el.style.maxHeight = `${vh - top - margin}px`\n }\n\n private buildHTML(m: I18nMessages): string {\n return `\n <div class=\"mtb-clarify-header\">\n <span class=\"mtb-clarify-icon\">\n <svg width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"1.9\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M12 3l1.6 5.4L19 10l-5.4 1.6L12 17l-1.6-5.4L5 10l5.4-1.6L12 3z\"/>\n </svg>\n </span>\n <div class=\"mtb-clarify-titles\">\n <div class=\"mtb-clarify-title\">${escapeHtml(m.clarify.title)}</div>\n <div class=\"mtb-clarify-subtitle\">${escapeHtml(m.clarify.subtitle)}</div>\n </div>\n <button class=\"mtb-clarify-close\" type=\"button\" title=\"${escapeHtml(m.clarify.skip)}\" aria-label=\"${escapeHtml(m.clarify.skip)}\">\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n <div class=\"mtb-clarify-messages\"></div>\n <div class=\"mtb-clarify-footer\">${this.buildConversationControls(m)}</div>\n `\n }\n\n private buildConversationControls(m: I18nMessages): string {\n return `\n <textarea class=\"mtb-clarify-input\" rows=\"1\" placeholder=\"${escapeHtml(m.clarify.placeholder)}\"></textarea>\n <div class=\"mtb-clarify-actions\">\n <button class=\"mtb-clarify-skip\" type=\"button\">${escapeHtml(m.clarify.skip)}</button>\n <button class=\"mtb-clarify-send\" type=\"button\" disabled>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n <span>${escapeHtml(m.clarify.send)}</span>\n </button>\n </div>\n `\n }\n\n private bindEvents(): void {\n this.el.querySelector('.mtb-clarify-close')!.addEventListener('click', () => this.skipAndFinalize())\n this.bindConversationControls()\n }\n\n private bindConversationControls(): void {\n this.inputEl = this.el.querySelector('.mtb-clarify-input')!\n this.sendBtn = this.el.querySelector('.mtb-clarify-send')!\n this.el.querySelector('.mtb-clarify-skip')!.addEventListener('click', () => this.skipAndFinalize())\n\n this.inputEl.addEventListener('input', () => {\n this.sendBtn.disabled = !this.inputEl.value.trim()\n })\n\n this.inputEl.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.isComposing || e.keyCode === 229) return\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault()\n this.sendMessage()\n }\n })\n\n this.sendBtn.addEventListener('click', () => this.sendMessage())\n }\n\n private skipAndFinalize(): void {\n this.stopPolling()\n void this.finalize()\n }\n\n private async startConversation(): Promise<void> {\n if (this.preloadedResult) {\n this.applyResult(this.preloadedResult)\n return\n }\n\n if (this.pendingClarification) {\n this.showThinking()\n try {\n const result = await this.pendingClarification\n if (this.destroyed) return\n if (result) {\n if (!this.applyResult(result)) this.startPolling()\n } else {\n await this.runInitialTurnViaPolling()\n }\n } catch {\n if (this.destroyed) return\n await this.runInitialTurnViaPolling()\n }\n return\n }\n\n this.showThinking()\n await this.runInitialTurn()\n }\n\n private async sendMessage(): Promise<void> {\n const text = this.inputEl.value.trim()\n if (!text || this.sending) return\n\n this.sending = true\n this.inputEl.disabled = true\n this.sendBtn.disabled = true\n this.stopPolling()\n\n this.appendMessage({ role: 'user', content: text })\n this.inputEl.value = ''\n this.showThinking()\n this.clearError()\n\n try {\n await this.runAnswerTurn(text)\n } catch {\n if (this.destroyed) return\n this.renderConversation(this.lastMessages, false)\n this.inputEl.value = text\n this.showError()\n } finally {\n this.sending = false\n this.inputEl.disabled = false\n this.sendBtn.disabled = !this.inputEl.value.trim()\n this.inputEl.focus()\n }\n }\n\n // Streams the assistant reply; falls back to POST + polling if the backend\n // doesn't support SSE (older server) or the stream errors mid-flight.\n private async runInitialTurn(): Promise<void> {\n try {\n const result = await this.apiClient.streamClarification(\n this.submissionSessionId,\n this.submissionToken,\n (text) => this.appendStreamDelta(text),\n )\n if (this.destroyed) return\n this.endStreamingBubble()\n if (!this.applyResult(result)) this.startPolling()\n } catch {\n if (this.destroyed) return\n this.endStreamingBubble()\n await this.runInitialTurnViaPolling()\n }\n }\n\n private async runInitialTurnViaPolling(): Promise<void> {\n try {\n const res = await this.apiClient.startClarification(\n this.submissionSessionId,\n this.submissionToken,\n )\n if (this.destroyed) return\n if (!this.applyResult(res)) this.startPolling()\n } catch {\n if (this.destroyed) return\n this.handleFailure()\n }\n }\n\n private async runAnswerTurn(message: string): Promise<void> {\n const res = await this.apiClient.startClarification(\n this.submissionSessionId,\n this.submissionToken,\n message,\n )\n if (this.destroyed) return\n if (!this.applyResult(res)) this.startPolling()\n }\n\n private showError(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n const error = document.createElement('div')\n error.className = 'mtb-clarify-error'\n error.textContent = this.i18n.error.submit\n footer.prepend(error)\n }\n\n private clearError(): void {\n this.el.querySelector('.mtb-clarify-error')?.remove()\n }\n\n private appendStreamDelta(text: string): void {\n if (!this.streamingBubble) {\n this.removeThinking()\n this.streamingBubble = document.createElement('div')\n this.streamingBubble.className = 'mtb-clarify-bubble mtb-clarify-ai'\n this.messagesEl.appendChild(this.streamingBubble)\n }\n this.streamingBubble.textContent = (this.streamingBubble.textContent ?? '') + text\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private endStreamingBubble(): void {\n this.streamingBubble = null\n }\n\n private startPolling(): void {\n this.stopPolling()\n this.pollDeadline = Date.now() + POLL_TIMEOUT_MS\n this.pollTimer = setInterval(() => this.poll(), POLL_INTERVAL_MS)\n }\n\n private stopPolling(): void {\n if (this.pollTimer !== null) {\n clearInterval(this.pollTimer)\n this.pollTimer = null\n }\n }\n\n private async poll(): Promise<void> {\n if (Date.now() > this.pollDeadline) {\n this.stopPolling()\n this.handleFailure()\n return\n }\n try {\n const res = await this.apiClient.getClarification(\n this.submissionSessionId,\n this.submissionToken,\n )\n if (this.destroyed) return\n if (this.applyResult(res)) this.stopPolling()\n } catch {\n if (this.destroyed) return\n this.stopPolling()\n this.handleFailure()\n }\n }\n\n private handleDone(): void {\n if (this.done) return\n this.done = true\n this.stopPolling()\n this.removeThinking()\n this.showFinalizeButton()\n }\n\n private handleFailure(): void {\n if (this.done) return\n this.done = true\n this.stopPolling()\n this.removeThinking()\n this.showClarificationFailureActions()\n }\n\n private showClarificationFailureActions(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `\n <div class=\"mtb-clarify-error\">${escapeHtml(this.i18n.clarify.error)}</div>\n <div class=\"mtb-clarify-actions\">\n <button class=\"mtb-clarify-fallback\" type=\"button\">${escapeHtml(this.i18n.clarify.send_feedback)}</button>\n <button class=\"mtb-clarify-retry\" type=\"button\">${escapeHtml(this.i18n.clarify.retry)}</button>\n </div>\n `\n footer.querySelector('.mtb-clarify-fallback')!.addEventListener('click', () => this.skipAndFinalize())\n footer.querySelector('.mtb-clarify-retry')!.addEventListener('click', () => {\n if (!this.destroyed) void this.retryClarification()\n })\n }\n\n private async retryClarification(): Promise<void> {\n if (this.sending || this.destroyed) return\n\n this.sending = true\n this.done = false\n this.showConversationControls()\n this.inputEl.disabled = true\n this.sendBtn.disabled = true\n this.renderConversation(this.lastMessages, false)\n\n try {\n const snapshot = await this.apiClient.getClarification(this.submissionSessionId, this.submissionToken)\n if (this.destroyed) return\n let result = snapshot\n // Each server status needs a different move. `processing` means a job is\n // already running for this session, so kicking off another turn would\n // duplicate it — fall through to polling instead. `awaiting_response` means\n // the assistant already asked its question and the server is waiting on the\n // reporter; applyResult hands the card back to them rather than polling for\n // a state only a human reply can change.\n if (snapshot.status === 'failed') {\n result = await this.apiClient.retryClarification(this.submissionSessionId, this.submissionToken)\n } else if (snapshot.status === 'idle') {\n result = await this.apiClient.startClarification(this.submissionSessionId, this.submissionToken)\n }\n if (this.destroyed) return\n if (!this.applyResult(result)) {\n this.showConversationControls()\n this.startPolling()\n }\n } catch {\n if (this.destroyed) return\n this.handleFailure()\n } finally {\n this.sending = false\n }\n }\n\n private showConversationControls(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = this.buildConversationControls(this.i18n)\n this.bindConversationControls()\n }\n\n // Returns true when the exchange has settled — the caller uses that to decide\n // whether it still needs to poll.\n private applyResult(result: ClarifyStreamResult | ClarifyResponse): boolean {\n this.renderConversation(result.messages, result.done)\n const status = 'status' in result ? result.status : undefined\n const failed = 'status' in result ? result.status === 'failed' : result.failed === true\n if (failed) {\n this.handleFailure()\n return true\n }\n if (result.done) {\n this.handleDone()\n return true\n }\n if (status === 'awaiting_response') {\n // The ball is in the reporter's court: polling here would spin until the\n // deadline and then show a failure card for a perfectly healthy session.\n this.stopPolling()\n this.removeThinking()\n this.enableInput()\n return true\n }\n return false\n }\n\n private enableInput(): void {\n if (!this.el.contains(this.inputEl)) this.showConversationControls()\n this.inputEl.disabled = false\n this.sendBtn.disabled = !this.inputEl.value.trim()\n }\n\n private showFinalizeButton(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `\n <button class=\"mtb-clarify-send-feedback\" type=\"button\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n <span>${escapeHtml(this.i18n.clarify.send_feedback)}</span>\n </button>\n `\n footer.querySelector('.mtb-clarify-send-feedback')!.addEventListener('click', () => {\n if (!this.destroyed) void this.finalize()\n })\n }\n\n private async finalize(): Promise<void> {\n if (this.finalizing || this.destroyed || this.unrecoverable) return\n\n this.finalizing = true\n this.el.querySelectorAll<HTMLButtonElement>('button').forEach(button => { button.disabled = true })\n try {\n await this.onFinalize()\n } catch (error) {\n if (this.destroyed) return\n this.finalizing = false\n this.clearError()\n // A 409 means the server will never accept this session again (it expired\n // past its retention window, or was already finalized/abandoned). Offering\n // Retry there just loops the reporter through the same generic error, so say\n // what happened and what to do instead.\n if (isTerminalConflict(error)) {\n this.showUnrecoverable()\n return\n }\n this.showFinalizeRetry()\n }\n }\n\n private showUnrecoverable(): void {\n this.unrecoverable = true\n this.stopPolling()\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `<div class=\"mtb-clarify-error\">${escapeHtml(this.i18n.clarify.expired)}</div>`\n }\n\n // Renders the reason and the retry together: replacing the footer wholesale is\n // what used to discard the error message showError() had just prepended, so the\n // reporter saw a bare Retry button with no explanation.\n private showFinalizeRetry(): void {\n const footer = this.el.querySelector('.mtb-clarify-footer')!\n footer.innerHTML = `\n <div class=\"mtb-clarify-error\">${escapeHtml(this.i18n.error.submit)}</div>\n <button class=\"mtb-clarify-send-feedback mtb-clarify-retry\" type=\"button\">${escapeHtml(this.i18n.clarify.retry)}</button>\n `\n footer.querySelector('.mtb-clarify-retry')!.addEventListener('click', () => {\n if (!this.destroyed) void this.finalize()\n })\n }\n\n private renderConversation(messages: ClarifyMessage[], done: boolean): void {\n this.lastMessages = messages\n this.renderMessages(messages)\n const last = messages[messages.length - 1]\n if (!done && (!last || last.role === 'user')) this.showThinking()\n }\n\n private renderMessages(messages: ClarifyMessage[]): void {\n this.messagesEl.innerHTML = ''\n for (const msg of messages) {\n this.appendMessage(msg)\n }\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private appendMessage(msg: ClarifyMessage): void {\n const bubble = document.createElement('div')\n bubble.className = msg.role === 'user' ? 'mtb-clarify-bubble mtb-clarify-user' : 'mtb-clarify-bubble mtb-clarify-ai'\n bubble.textContent = msg.content\n this.messagesEl.appendChild(bubble)\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private showThinking(): void {\n if (this.messagesEl.querySelector('.mtb-clarify-thinking')) return\n const dots = document.createElement('div')\n dots.className = 'mtb-clarify-bubble mtb-clarify-ai mtb-clarify-thinking'\n dots.innerHTML = '<span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span><span class=\"mtb-dot\"></span>'\n this.messagesEl.appendChild(dots)\n this.messagesEl.scrollTop = this.messagesEl.scrollHeight\n }\n\n private removeThinking(): void {\n this.messagesEl.querySelector('.mtb-clarify-thinking')?.remove()\n }\n\n destroy(): void {\n this.destroyed = true\n this.stopPolling()\n this.sheet.release()\n this.el.remove()\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\nimport { BRAND_COLOR } from '../styles'\n\nconst SUCCESS_AUTO_CLOSE_MS = 5000\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n\nexport interface SuccessCardOptions {\n skipFollowup?: boolean\n emailCapture?: {\n onSubmit: (email: string) => Promise<boolean>\n }\n}\n\nexport class SuccessCard {\n private el: HTMLDivElement\n private messages: I18nMessages\n\n constructor(shadow: ShadowContainer, messages: I18nMessages, onClose: () => void, onViewFeedback?: () => void, options?: SuccessCardOptions) {\n this.messages = messages\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-success')\n this.el.style.right = '20px'\n this.el.style.bottom = '20px'\n\n const title = options?.skipFollowup ? messages.success.title_no_ai : messages.success.title\n const msg = options?.skipFollowup ? messages.success.message_no_ai : messages.success.message\n\n const viewLink = onViewFeedback\n ? `<button class=\"mtb-view-feedback-link\">${messages.success.view_feedback} <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M5 12h14M12 5l7 7-7 7\"/></svg></button>`\n : ''\n\n const emailCapture = options?.emailCapture\n ? `\n <div class=\"mtb-email-capture\">\n <div class=\"mtb-email-prompt\">${messages.success.email_prompt}</div>\n <div class=\"mtb-email-row\">\n <input class=\"mtb-email-input\" type=\"email\" placeholder=\"${messages.success.email_placeholder}\">\n <button class=\"mtb-email-submit\">${messages.success.email_submit}</button>\n </div>\n <div class=\"mtb-email-error\" hidden>${messages.success.email_error}</div>\n </div>`\n : ''\n\n this.el.innerHTML = `\n <div class=\"mtb-success-icon\">\n <svg width=\"23\" height=\"23\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${BRAND_COLOR}\" stroke-width=\"2.4\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n </div>\n <div class=\"mtb-success-title\">${title}</div>\n <div class=\"mtb-success-msg\">${msg}</div>\n ${emailCapture}\n ${viewLink}\n <button class=\"mtb-close-link\">${messages.success.close}</button>\n `\n shadow.append(this.el)\n this.el.querySelector('.mtb-close-link')!.addEventListener('click', onClose)\n\n if (onViewFeedback) {\n this.el.querySelector('.mtb-view-feedback-link')!.addEventListener('click', onViewFeedback)\n }\n\n if (options?.emailCapture) {\n this.bindEmailCapture(options.emailCapture.onSubmit)\n } else {\n setTimeout(() => onClose(), SUCCESS_AUTO_CLOSE_MS)\n }\n }\n\n private bindEmailCapture(onSubmit: (email: string) => Promise<boolean>): void {\n const input = this.el.querySelector<HTMLInputElement>('.mtb-email-input')!\n const submit = this.el.querySelector<HTMLButtonElement>('.mtb-email-submit')!\n const error = this.el.querySelector<HTMLDivElement>('.mtb-email-error')!\n\n const handle = async () => {\n const email = input.value.trim()\n if (!EMAIL_PATTERN.test(email)) {\n input.classList.add('mtb-email-invalid')\n return\n }\n input.classList.remove('mtb-email-invalid')\n error.hidden = true\n submit.disabled = true\n\n const saved = await onSubmit(email)\n if (saved) {\n this.el.querySelector('.mtb-email-capture')!.innerHTML =\n `<div class=\"mtb-email-saved\">${this.messages.success.email_saved}</div>`\n } else {\n error.hidden = false\n submit.disabled = false\n }\n }\n\n submit.addEventListener('click', handle)\n input.addEventListener('keydown', (event) => {\n if (event.key === 'Enter') handle()\n })\n }\n\n destroy(): void {\n this.el.remove()\n }\n}\n","export function resolveUrl(url, baseUrl) {\n // url is absolute already\n if (url.match(/^[a-z]+:\\/\\//i)) {\n return url;\n }\n // url is absolute already, without protocol\n if (url.match(/^\\/\\//)) {\n return window.location.protocol + url;\n }\n // dataURI, mailto:, tel:, etc.\n if (url.match(/^[a-z]+:/i)) {\n return url;\n }\n const doc = document.implementation.createHTMLDocument();\n const base = doc.createElement('base');\n const a = doc.createElement('a');\n doc.head.appendChild(base);\n doc.body.appendChild(a);\n if (baseUrl) {\n base.href = baseUrl;\n }\n a.href = url;\n return a.href;\n}\nexport const uuid = (() => {\n // generate uuid for className of pseudo elements.\n // We should not use GUIDs, otherwise pseudo elements sometimes cannot be captured.\n let counter = 0;\n // ref: http://stackoverflow.com/a/6248722/2519373\n const random = () => \n // eslint-disable-next-line no-bitwise\n `0000${((Math.random() * 36 ** 4) << 0).toString(36)}`.slice(-4);\n return () => {\n counter += 1;\n return `u${random()}${counter}`;\n };\n})();\nexport function delay(ms) {\n return (args) => new Promise((resolve) => {\n setTimeout(() => resolve(args), ms);\n });\n}\nexport function toArray(arrayLike) {\n const arr = [];\n for (let i = 0, l = arrayLike.length; i < l; i++) {\n arr.push(arrayLike[i]);\n }\n return arr;\n}\nlet styleProps = null;\nexport function getStyleProperties(options = {}) {\n if (styleProps) {\n return styleProps;\n }\n if (options.includeStyleProperties) {\n styleProps = options.includeStyleProperties;\n return styleProps;\n }\n styleProps = toArray(window.getComputedStyle(document.documentElement));\n return styleProps;\n}\nfunction px(node, styleProperty) {\n const win = node.ownerDocument.defaultView || window;\n const val = win.getComputedStyle(node).getPropertyValue(styleProperty);\n return val ? parseFloat(val.replace('px', '')) : 0;\n}\nfunction getNodeWidth(node) {\n const leftBorder = px(node, 'border-left-width');\n const rightBorder = px(node, 'border-right-width');\n return node.clientWidth + leftBorder + rightBorder;\n}\nfunction getNodeHeight(node) {\n const topBorder = px(node, 'border-top-width');\n const bottomBorder = px(node, 'border-bottom-width');\n return node.clientHeight + topBorder + bottomBorder;\n}\nexport function getImageSize(targetNode, options = {}) {\n const width = options.width || getNodeWidth(targetNode);\n const height = options.height || getNodeHeight(targetNode);\n return { width, height };\n}\nexport function getPixelRatio() {\n let ratio;\n let FINAL_PROCESS;\n try {\n FINAL_PROCESS = process;\n }\n catch (e) {\n // pass\n }\n const val = FINAL_PROCESS && FINAL_PROCESS.env\n ? FINAL_PROCESS.env.devicePixelRatio\n : null;\n if (val) {\n ratio = parseInt(val, 10);\n if (Number.isNaN(ratio)) {\n ratio = 1;\n }\n }\n return ratio || window.devicePixelRatio || 1;\n}\n// @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas#maximum_canvas_size\nconst canvasDimensionLimit = 16384;\nexport function checkCanvasDimensions(canvas) {\n if (canvas.width > canvasDimensionLimit ||\n canvas.height > canvasDimensionLimit) {\n if (canvas.width > canvasDimensionLimit &&\n canvas.height > canvasDimensionLimit) {\n if (canvas.width > canvas.height) {\n canvas.height *= canvasDimensionLimit / canvas.width;\n canvas.width = canvasDimensionLimit;\n }\n else {\n canvas.width *= canvasDimensionLimit / canvas.height;\n canvas.height = canvasDimensionLimit;\n }\n }\n else if (canvas.width > canvasDimensionLimit) {\n canvas.height *= canvasDimensionLimit / canvas.width;\n canvas.width = canvasDimensionLimit;\n }\n else {\n canvas.width *= canvasDimensionLimit / canvas.height;\n canvas.height = canvasDimensionLimit;\n }\n }\n}\nexport function canvasToBlob(canvas, options = {}) {\n if (canvas.toBlob) {\n return new Promise((resolve) => {\n canvas.toBlob(resolve, options.type ? options.type : 'image/png', options.quality ? options.quality : 1);\n });\n }\n return new Promise((resolve) => {\n const binaryString = window.atob(canvas\n .toDataURL(options.type ? options.type : undefined, options.quality ? options.quality : undefined)\n .split(',')[1]);\n const len = binaryString.length;\n const binaryArray = new Uint8Array(len);\n for (let i = 0; i < len; i += 1) {\n binaryArray[i] = binaryString.charCodeAt(i);\n }\n resolve(new Blob([binaryArray], {\n type: options.type ? options.type : 'image/png',\n }));\n });\n}\nexport function createImage(url) {\n return new Promise((resolve, reject) => {\n const img = new Image();\n img.onload = () => {\n img.decode().then(() => {\n requestAnimationFrame(() => resolve(img));\n });\n };\n img.onerror = reject;\n img.crossOrigin = 'anonymous';\n img.decoding = 'async';\n img.src = url;\n });\n}\nexport async function svgToDataURL(svg) {\n return Promise.resolve()\n .then(() => new XMLSerializer().serializeToString(svg))\n .then(encodeURIComponent)\n .then((html) => `data:image/svg+xml;charset=utf-8,${html}`);\n}\nexport async function nodeToDataURL(node, width, height) {\n const xmlns = 'http://www.w3.org/2000/svg';\n const svg = document.createElementNS(xmlns, 'svg');\n const foreignObject = document.createElementNS(xmlns, 'foreignObject');\n svg.setAttribute('width', `${width}`);\n svg.setAttribute('height', `${height}`);\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n foreignObject.setAttribute('width', '100%');\n foreignObject.setAttribute('height', '100%');\n foreignObject.setAttribute('x', '0');\n foreignObject.setAttribute('y', '0');\n foreignObject.setAttribute('externalResourcesRequired', 'true');\n svg.appendChild(foreignObject);\n foreignObject.appendChild(node);\n return svgToDataURL(svg);\n}\nexport const isInstanceOfElement = (node, instance) => {\n if (node instanceof instance)\n return true;\n const nodePrototype = Object.getPrototypeOf(node);\n if (nodePrototype === null)\n return false;\n return (nodePrototype.constructor.name === instance.name ||\n isInstanceOfElement(nodePrototype, instance));\n};\n//# sourceMappingURL=util.js.map","import { uuid, getStyleProperties } from './util';\nfunction formatCSSText(style) {\n const content = style.getPropertyValue('content');\n return `${style.cssText} content: '${content.replace(/'|\"/g, '')}';`;\n}\nfunction formatCSSProperties(style, options) {\n return getStyleProperties(options)\n .map((name) => {\n const value = style.getPropertyValue(name);\n const priority = style.getPropertyPriority(name);\n return `${name}: ${value}${priority ? ' !important' : ''};`;\n })\n .join(' ');\n}\nfunction getPseudoElementStyle(className, pseudo, style, options) {\n const selector = `.${className}:${pseudo}`;\n const cssText = style.cssText\n ? formatCSSText(style)\n : formatCSSProperties(style, options);\n return document.createTextNode(`${selector}{${cssText}}`);\n}\nfunction clonePseudoElement(nativeNode, clonedNode, pseudo, options) {\n const style = window.getComputedStyle(nativeNode, pseudo);\n const content = style.getPropertyValue('content');\n if (content === '' || content === 'none') {\n return;\n }\n const className = uuid();\n try {\n clonedNode.className = `${clonedNode.className} ${className}`;\n }\n catch (err) {\n return;\n }\n const styleElement = document.createElement('style');\n styleElement.appendChild(getPseudoElementStyle(className, pseudo, style, options));\n clonedNode.appendChild(styleElement);\n}\nexport function clonePseudoElements(nativeNode, clonedNode, options) {\n clonePseudoElement(nativeNode, clonedNode, ':before', options);\n clonePseudoElement(nativeNode, clonedNode, ':after', options);\n}\n//# sourceMappingURL=clone-pseudos.js.map","const WOFF = 'application/font-woff';\nconst JPEG = 'image/jpeg';\nconst mimes = {\n woff: WOFF,\n woff2: WOFF,\n ttf: 'application/font-truetype',\n eot: 'application/vnd.ms-fontobject',\n png: 'image/png',\n jpg: JPEG,\n jpeg: JPEG,\n gif: 'image/gif',\n tiff: 'image/tiff',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n};\nfunction getExtension(url) {\n const match = /\\.([^./]*?)$/g.exec(url);\n return match ? match[1] : '';\n}\nexport function getMimeType(url) {\n const extension = getExtension(url).toLowerCase();\n return mimes[extension] || '';\n}\n//# sourceMappingURL=mimes.js.map","function getContentFromDataUrl(dataURL) {\n return dataURL.split(/,/)[1];\n}\nexport function isDataUrl(url) {\n return url.search(/^(data:)/) !== -1;\n}\nexport function makeDataUrl(content, mimeType) {\n return `data:${mimeType};base64,${content}`;\n}\nexport async function fetchAsDataURL(url, init, process) {\n const res = await fetch(url, init);\n if (res.status === 404) {\n throw new Error(`Resource \"${res.url}\" not found`);\n }\n const blob = await res.blob();\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onerror = reject;\n reader.onloadend = () => {\n try {\n resolve(process({ res, result: reader.result }));\n }\n catch (error) {\n reject(error);\n }\n };\n reader.readAsDataURL(blob);\n });\n}\nconst cache = {};\nfunction getCacheKey(url, contentType, includeQueryParams) {\n let key = url.replace(/\\?.*/, '');\n if (includeQueryParams) {\n key = url;\n }\n // font resource\n if (/ttf|otf|eot|woff2?/i.test(key)) {\n key = key.replace(/.*\\//, '');\n }\n return contentType ? `[${contentType}]${key}` : key;\n}\nexport async function resourceToDataURL(resourceUrl, contentType, options) {\n const cacheKey = getCacheKey(resourceUrl, contentType, options.includeQueryParams);\n if (cache[cacheKey] != null) {\n return cache[cacheKey];\n }\n // ref: https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest#Bypassing_the_cache\n if (options.cacheBust) {\n // eslint-disable-next-line no-param-reassign\n resourceUrl += (/\\?/.test(resourceUrl) ? '&' : '?') + new Date().getTime();\n }\n let dataURL;\n try {\n const content = await fetchAsDataURL(resourceUrl, options.fetchRequestInit, ({ res, result }) => {\n if (!contentType) {\n // eslint-disable-next-line no-param-reassign\n contentType = res.headers.get('Content-Type') || '';\n }\n return getContentFromDataUrl(result);\n });\n dataURL = makeDataUrl(content, contentType);\n }\n catch (error) {\n dataURL = options.imagePlaceholder || '';\n let msg = `Failed to fetch resource: ${resourceUrl}`;\n if (error) {\n msg = typeof error === 'string' ? error : error.message;\n }\n if (msg) {\n console.warn(msg);\n }\n }\n cache[cacheKey] = dataURL;\n return dataURL;\n}\n//# sourceMappingURL=dataurl.js.map","import { clonePseudoElements } from './clone-pseudos';\nimport { createImage, toArray, isInstanceOfElement, getStyleProperties, } from './util';\nimport { getMimeType } from './mimes';\nimport { resourceToDataURL } from './dataurl';\nasync function cloneCanvasElement(canvas) {\n const dataURL = canvas.toDataURL();\n if (dataURL === 'data:,') {\n return canvas.cloneNode(false);\n }\n return createImage(dataURL);\n}\nasync function cloneVideoElement(video, options) {\n if (video.currentSrc) {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n canvas.width = video.clientWidth;\n canvas.height = video.clientHeight;\n ctx === null || ctx === void 0 ? void 0 : ctx.drawImage(video, 0, 0, canvas.width, canvas.height);\n const dataURL = canvas.toDataURL();\n return createImage(dataURL);\n }\n const poster = video.poster;\n const contentType = getMimeType(poster);\n const dataURL = await resourceToDataURL(poster, contentType, options);\n return createImage(dataURL);\n}\nasync function cloneIFrameElement(iframe, options) {\n var _a;\n try {\n if ((_a = iframe === null || iframe === void 0 ? void 0 : iframe.contentDocument) === null || _a === void 0 ? void 0 : _a.body) {\n return (await cloneNode(iframe.contentDocument.body, options, true));\n }\n }\n catch (_b) {\n // Failed to clone iframe\n }\n return iframe.cloneNode(false);\n}\nasync function cloneSingleNode(node, options) {\n if (isInstanceOfElement(node, HTMLCanvasElement)) {\n return cloneCanvasElement(node);\n }\n if (isInstanceOfElement(node, HTMLVideoElement)) {\n return cloneVideoElement(node, options);\n }\n if (isInstanceOfElement(node, HTMLIFrameElement)) {\n return cloneIFrameElement(node, options);\n }\n return node.cloneNode(isSVGElement(node));\n}\nconst isSlotElement = (node) => node.tagName != null && node.tagName.toUpperCase() === 'SLOT';\nconst isSVGElement = (node) => node.tagName != null && node.tagName.toUpperCase() === 'SVG';\nasync function cloneChildren(nativeNode, clonedNode, options) {\n var _a, _b;\n if (isSVGElement(clonedNode)) {\n return clonedNode;\n }\n let children = [];\n if (isSlotElement(nativeNode) && nativeNode.assignedNodes) {\n children = toArray(nativeNode.assignedNodes());\n }\n else if (isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n ((_a = nativeNode.contentDocument) === null || _a === void 0 ? void 0 : _a.body)) {\n children = toArray(nativeNode.contentDocument.body.childNodes);\n }\n else {\n children = toArray(((_b = nativeNode.shadowRoot) !== null && _b !== void 0 ? _b : nativeNode).childNodes);\n }\n if (children.length === 0 ||\n isInstanceOfElement(nativeNode, HTMLVideoElement)) {\n return clonedNode;\n }\n await children.reduce((deferred, child) => deferred\n .then(() => cloneNode(child, options))\n .then((clonedChild) => {\n if (clonedChild) {\n clonedNode.appendChild(clonedChild);\n }\n }), Promise.resolve());\n return clonedNode;\n}\nfunction cloneCSSStyle(nativeNode, clonedNode, options) {\n const targetStyle = clonedNode.style;\n if (!targetStyle) {\n return;\n }\n const sourceStyle = window.getComputedStyle(nativeNode);\n if (sourceStyle.cssText) {\n targetStyle.cssText = sourceStyle.cssText;\n targetStyle.transformOrigin = sourceStyle.transformOrigin;\n }\n else {\n getStyleProperties(options).forEach((name) => {\n let value = sourceStyle.getPropertyValue(name);\n if (name === 'font-size' && value.endsWith('px')) {\n const reducedFont = Math.floor(parseFloat(value.substring(0, value.length - 2))) - 0.1;\n value = `${reducedFont}px`;\n }\n if (isInstanceOfElement(nativeNode, HTMLIFrameElement) &&\n name === 'display' &&\n value === 'inline') {\n value = 'block';\n }\n if (name === 'd' && clonedNode.getAttribute('d')) {\n value = `path(${clonedNode.getAttribute('d')})`;\n }\n targetStyle.setProperty(name, value, sourceStyle.getPropertyPriority(name));\n });\n }\n}\nfunction cloneInputValue(nativeNode, clonedNode) {\n if (isInstanceOfElement(nativeNode, HTMLTextAreaElement)) {\n clonedNode.innerHTML = nativeNode.value;\n }\n if (isInstanceOfElement(nativeNode, HTMLInputElement)) {\n clonedNode.setAttribute('value', nativeNode.value);\n }\n}\nfunction cloneSelectValue(nativeNode, clonedNode) {\n if (isInstanceOfElement(nativeNode, HTMLSelectElement)) {\n const clonedSelect = clonedNode;\n const selectedOption = Array.from(clonedSelect.children).find((child) => nativeNode.value === child.getAttribute('value'));\n if (selectedOption) {\n selectedOption.setAttribute('selected', '');\n }\n }\n}\nfunction decorate(nativeNode, clonedNode, options) {\n if (isInstanceOfElement(clonedNode, Element)) {\n cloneCSSStyle(nativeNode, clonedNode, options);\n clonePseudoElements(nativeNode, clonedNode, options);\n cloneInputValue(nativeNode, clonedNode);\n cloneSelectValue(nativeNode, clonedNode);\n }\n return clonedNode;\n}\nasync function ensureSVGSymbols(clone, options) {\n const uses = clone.querySelectorAll ? clone.querySelectorAll('use') : [];\n if (uses.length === 0) {\n return clone;\n }\n const processedDefs = {};\n for (let i = 0; i < uses.length; i++) {\n const use = uses[i];\n const id = use.getAttribute('xlink:href');\n if (id) {\n const exist = clone.querySelector(id);\n const definition = document.querySelector(id);\n if (!exist && definition && !processedDefs[id]) {\n // eslint-disable-next-line no-await-in-loop\n processedDefs[id] = (await cloneNode(definition, options, true));\n }\n }\n }\n const nodes = Object.values(processedDefs);\n if (nodes.length) {\n const ns = 'http://www.w3.org/1999/xhtml';\n const svg = document.createElementNS(ns, 'svg');\n svg.setAttribute('xmlns', ns);\n svg.style.position = 'absolute';\n svg.style.width = '0';\n svg.style.height = '0';\n svg.style.overflow = 'hidden';\n svg.style.display = 'none';\n const defs = document.createElementNS(ns, 'defs');\n svg.appendChild(defs);\n for (let i = 0; i < nodes.length; i++) {\n defs.appendChild(nodes[i]);\n }\n clone.appendChild(svg);\n }\n return clone;\n}\nexport async function cloneNode(node, options, isRoot) {\n if (!isRoot && options.filter && !options.filter(node)) {\n return null;\n }\n return Promise.resolve(node)\n .then((clonedNode) => cloneSingleNode(clonedNode, options))\n .then((clonedNode) => cloneChildren(node, clonedNode, options))\n .then((clonedNode) => decorate(node, clonedNode, options))\n .then((clonedNode) => ensureSVGSymbols(clonedNode, options));\n}\n//# sourceMappingURL=clone-node.js.map","import { resolveUrl } from './util';\nimport { getMimeType } from './mimes';\nimport { isDataUrl, makeDataUrl, resourceToDataURL } from './dataurl';\nconst URL_REGEX = /url\\((['\"]?)([^'\"]+?)\\1\\)/g;\nconst URL_WITH_FORMAT_REGEX = /url\\([^)]+\\)\\s*format\\(([\"']?)([^\"']+)\\1\\)/g;\nconst FONT_SRC_REGEX = /src:\\s*(?:url\\([^)]+\\)\\s*format\\([^)]+\\)[,;]\\s*)+/g;\nfunction toRegex(url) {\n // eslint-disable-next-line no-useless-escape\n const escaped = url.replace(/([.*+?^${}()|\\[\\]\\/\\\\])/g, '\\\\$1');\n return new RegExp(`(url\\\\(['\"]?)(${escaped})(['\"]?\\\\))`, 'g');\n}\nexport function parseURLs(cssText) {\n const urls = [];\n cssText.replace(URL_REGEX, (raw, quotation, url) => {\n urls.push(url);\n return raw;\n });\n return urls.filter((url) => !isDataUrl(url));\n}\nexport async function embed(cssText, resourceURL, baseURL, options, getContentFromUrl) {\n try {\n const resolvedURL = baseURL ? resolveUrl(resourceURL, baseURL) : resourceURL;\n const contentType = getMimeType(resourceURL);\n let dataURL;\n if (getContentFromUrl) {\n const content = await getContentFromUrl(resolvedURL);\n dataURL = makeDataUrl(content, contentType);\n }\n else {\n dataURL = await resourceToDataURL(resolvedURL, contentType, options);\n }\n return cssText.replace(toRegex(resourceURL), `$1${dataURL}$3`);\n }\n catch (error) {\n // pass\n }\n return cssText;\n}\nfunction filterPreferredFontFormat(str, { preferredFontFormat }) {\n return !preferredFontFormat\n ? str\n : str.replace(FONT_SRC_REGEX, (match) => {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const [src, , format] = URL_WITH_FORMAT_REGEX.exec(match) || [];\n if (!format) {\n return '';\n }\n if (format === preferredFontFormat) {\n return `src: ${src};`;\n }\n }\n });\n}\nexport function shouldEmbed(url) {\n return url.search(URL_REGEX) !== -1;\n}\nexport async function embedResources(cssText, baseUrl, options) {\n if (!shouldEmbed(cssText)) {\n return cssText;\n }\n const filteredCSSText = filterPreferredFontFormat(cssText, options);\n const urls = parseURLs(filteredCSSText);\n return urls.reduce((deferred, url) => deferred.then((css) => embed(css, url, baseUrl, options)), Promise.resolve(filteredCSSText));\n}\n//# sourceMappingURL=embed-resources.js.map","import { embedResources } from './embed-resources';\nimport { toArray, isInstanceOfElement } from './util';\nimport { isDataUrl, resourceToDataURL } from './dataurl';\nimport { getMimeType } from './mimes';\nasync function embedProp(propName, node, options) {\n var _a;\n const propValue = (_a = node.style) === null || _a === void 0 ? void 0 : _a.getPropertyValue(propName);\n if (propValue) {\n const cssString = await embedResources(propValue, null, options);\n node.style.setProperty(propName, cssString, node.style.getPropertyPriority(propName));\n return true;\n }\n return false;\n}\nasync function embedBackground(clonedNode, options) {\n ;\n (await embedProp('background', clonedNode, options)) ||\n (await embedProp('background-image', clonedNode, options));\n (await embedProp('mask', clonedNode, options)) ||\n (await embedProp('-webkit-mask', clonedNode, options)) ||\n (await embedProp('mask-image', clonedNode, options)) ||\n (await embedProp('-webkit-mask-image', clonedNode, options));\n}\nasync function embedImageNode(clonedNode, options) {\n const isImageElement = isInstanceOfElement(clonedNode, HTMLImageElement);\n if (!(isImageElement && !isDataUrl(clonedNode.src)) &&\n !(isInstanceOfElement(clonedNode, SVGImageElement) &&\n !isDataUrl(clonedNode.href.baseVal))) {\n return;\n }\n const url = isImageElement ? clonedNode.src : clonedNode.href.baseVal;\n const dataURL = await resourceToDataURL(url, getMimeType(url), options);\n await new Promise((resolve, reject) => {\n clonedNode.onload = resolve;\n clonedNode.onerror = options.onImageErrorHandler\n ? (...attributes) => {\n try {\n resolve(options.onImageErrorHandler(...attributes));\n }\n catch (error) {\n reject(error);\n }\n }\n : reject;\n const image = clonedNode;\n if (image.decode) {\n image.decode = resolve;\n }\n if (image.loading === 'lazy') {\n image.loading = 'eager';\n }\n if (isImageElement) {\n clonedNode.srcset = '';\n clonedNode.src = dataURL;\n }\n else {\n clonedNode.href.baseVal = dataURL;\n }\n });\n}\nasync function embedChildren(clonedNode, options) {\n const children = toArray(clonedNode.childNodes);\n const deferreds = children.map((child) => embedImages(child, options));\n await Promise.all(deferreds).then(() => clonedNode);\n}\nexport async function embedImages(clonedNode, options) {\n if (isInstanceOfElement(clonedNode, Element)) {\n await embedBackground(clonedNode, options);\n await embedImageNode(clonedNode, options);\n await embedChildren(clonedNode, options);\n }\n}\n//# sourceMappingURL=embed-images.js.map","export function applyStyle(node, options) {\n const { style } = node;\n if (options.backgroundColor) {\n style.backgroundColor = options.backgroundColor;\n }\n if (options.width) {\n style.width = `${options.width}px`;\n }\n if (options.height) {\n style.height = `${options.height}px`;\n }\n const manual = options.style;\n if (manual != null) {\n Object.keys(manual).forEach((key) => {\n style[key] = manual[key];\n });\n }\n return node;\n}\n//# sourceMappingURL=apply-style.js.map","import { toArray } from './util';\nimport { fetchAsDataURL } from './dataurl';\nimport { shouldEmbed, embedResources } from './embed-resources';\nconst cssFetchCache = {};\nasync function fetchCSS(url) {\n let cache = cssFetchCache[url];\n if (cache != null) {\n return cache;\n }\n const res = await fetch(url);\n const cssText = await res.text();\n cache = { url, cssText };\n cssFetchCache[url] = cache;\n return cache;\n}\nasync function embedFonts(data, options) {\n let cssText = data.cssText;\n const regexUrl = /url\\([\"']?([^\"')]+)[\"']?\\)/g;\n const fontLocs = cssText.match(/url\\([^)]+\\)/g) || [];\n const loadFonts = fontLocs.map(async (loc) => {\n let url = loc.replace(regexUrl, '$1');\n if (!url.startsWith('https://')) {\n url = new URL(url, data.url).href;\n }\n return fetchAsDataURL(url, options.fetchRequestInit, ({ result }) => {\n cssText = cssText.replace(loc, `url(${result})`);\n return [loc, result];\n });\n });\n return Promise.all(loadFonts).then(() => cssText);\n}\nfunction parseCSS(source) {\n if (source == null) {\n return [];\n }\n const result = [];\n const commentsRegex = /(\\/\\*[\\s\\S]*?\\*\\/)/gi;\n // strip out comments\n let cssText = source.replace(commentsRegex, '');\n // eslint-disable-next-line prefer-regex-literals\n const keyframesRegex = new RegExp('((@.*?keyframes [\\\\s\\\\S]*?){([\\\\s\\\\S]*?}\\\\s*?)})', 'gi');\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const matches = keyframesRegex.exec(cssText);\n if (matches === null) {\n break;\n }\n result.push(matches[0]);\n }\n cssText = cssText.replace(keyframesRegex, '');\n const importRegex = /@import[\\s\\S]*?url\\([^)]*\\)[\\s\\S]*?;/gi;\n // to match css & media queries together\n const combinedCSSRegex = '((\\\\s*?(?:\\\\/\\\\*[\\\\s\\\\S]*?\\\\*\\\\/)?\\\\s*?@media[\\\\s\\\\S]' +\n '*?){([\\\\s\\\\S]*?)}\\\\s*?})|(([\\\\s\\\\S]*?){([\\\\s\\\\S]*?)})';\n // unified regex\n const unifiedRegex = new RegExp(combinedCSSRegex, 'gi');\n // eslint-disable-next-line no-constant-condition\n while (true) {\n let matches = importRegex.exec(cssText);\n if (matches === null) {\n matches = unifiedRegex.exec(cssText);\n if (matches === null) {\n break;\n }\n else {\n importRegex.lastIndex = unifiedRegex.lastIndex;\n }\n }\n else {\n unifiedRegex.lastIndex = importRegex.lastIndex;\n }\n result.push(matches[0]);\n }\n return result;\n}\nasync function getCSSRules(styleSheets, options) {\n const ret = [];\n const deferreds = [];\n // First loop inlines imports\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray(sheet.cssRules || []).forEach((item, index) => {\n if (item.type === CSSRule.IMPORT_RULE) {\n let importIndex = index + 1;\n const url = item.href;\n const deferred = fetchCSS(url)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) => parseCSS(cssText).forEach((rule) => {\n try {\n sheet.insertRule(rule, rule.startsWith('@import')\n ? (importIndex += 1)\n : sheet.cssRules.length);\n }\n catch (error) {\n console.error('Error inserting rule from remote css', {\n rule,\n error,\n });\n }\n }))\n .catch((e) => {\n console.error('Error loading remote css', e.toString());\n });\n deferreds.push(deferred);\n }\n });\n }\n catch (e) {\n const inline = styleSheets.find((a) => a.href == null) || document.styleSheets[0];\n if (sheet.href != null) {\n deferreds.push(fetchCSS(sheet.href)\n .then((metadata) => embedFonts(metadata, options))\n .then((cssText) => parseCSS(cssText).forEach((rule) => {\n inline.insertRule(rule, inline.cssRules.length);\n }))\n .catch((err) => {\n console.error('Error loading remote stylesheet', err);\n }));\n }\n console.error('Error inlining remote css file', e);\n }\n }\n });\n return Promise.all(deferreds).then(() => {\n // Second loop parses rules\n styleSheets.forEach((sheet) => {\n if ('cssRules' in sheet) {\n try {\n toArray(sheet.cssRules || []).forEach((item) => {\n ret.push(item);\n });\n }\n catch (e) {\n console.error(`Error while reading CSS rules from ${sheet.href}`, e);\n }\n }\n });\n return ret;\n });\n}\nfunction getWebFontRules(cssRules) {\n return cssRules\n .filter((rule) => rule.type === CSSRule.FONT_FACE_RULE)\n .filter((rule) => shouldEmbed(rule.style.getPropertyValue('src')));\n}\nasync function parseWebFontRules(node, options) {\n if (node.ownerDocument == null) {\n throw new Error('Provided element is not within a Document');\n }\n const styleSheets = toArray(node.ownerDocument.styleSheets);\n const cssRules = await getCSSRules(styleSheets, options);\n return getWebFontRules(cssRules);\n}\nfunction normalizeFontFamily(font) {\n return font.trim().replace(/[\"']/g, '');\n}\nfunction getUsedFonts(node) {\n const fonts = new Set();\n function traverse(node) {\n const fontFamily = node.style.fontFamily || getComputedStyle(node).fontFamily;\n fontFamily.split(',').forEach((font) => {\n fonts.add(normalizeFontFamily(font));\n });\n Array.from(node.children).forEach((child) => {\n if (child instanceof HTMLElement) {\n traverse(child);\n }\n });\n }\n traverse(node);\n return fonts;\n}\nexport async function getWebFontCSS(node, options) {\n const rules = await parseWebFontRules(node, options);\n const usedFonts = getUsedFonts(node);\n const cssTexts = await Promise.all(rules\n .filter((rule) => usedFonts.has(normalizeFontFamily(rule.style.fontFamily)))\n .map((rule) => {\n const baseUrl = rule.parentStyleSheet\n ? rule.parentStyleSheet.href\n : null;\n return embedResources(rule.cssText, baseUrl, options);\n }));\n return cssTexts.join('\\n');\n}\nexport async function embedWebFonts(clonedNode, options) {\n const cssText = options.fontEmbedCSS != null\n ? options.fontEmbedCSS\n : options.skipFonts\n ? null\n : await getWebFontCSS(clonedNode, options);\n if (cssText) {\n const styleNode = document.createElement('style');\n const sytleContent = document.createTextNode(cssText);\n styleNode.appendChild(sytleContent);\n if (clonedNode.firstChild) {\n clonedNode.insertBefore(styleNode, clonedNode.firstChild);\n }\n else {\n clonedNode.appendChild(styleNode);\n }\n }\n}\n//# sourceMappingURL=embed-webfonts.js.map","import { cloneNode } from './clone-node';\nimport { embedImages } from './embed-images';\nimport { applyStyle } from './apply-style';\nimport { embedWebFonts, getWebFontCSS } from './embed-webfonts';\nimport { getImageSize, getPixelRatio, createImage, canvasToBlob, nodeToDataURL, checkCanvasDimensions, } from './util';\nexport async function toSvg(node, options = {}) {\n const { width, height } = getImageSize(node, options);\n const clonedNode = (await cloneNode(node, options, true));\n await embedWebFonts(clonedNode, options);\n await embedImages(clonedNode, options);\n applyStyle(clonedNode, options);\n const datauri = await nodeToDataURL(clonedNode, width, height);\n return datauri;\n}\nexport async function toCanvas(node, options = {}) {\n const { width, height } = getImageSize(node, options);\n const svg = await toSvg(node, options);\n const img = await createImage(svg);\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('2d');\n const ratio = options.pixelRatio || getPixelRatio();\n const canvasWidth = options.canvasWidth || width;\n const canvasHeight = options.canvasHeight || height;\n canvas.width = canvasWidth * ratio;\n canvas.height = canvasHeight * ratio;\n if (!options.skipAutoScale) {\n checkCanvasDimensions(canvas);\n }\n canvas.style.width = `${canvasWidth}`;\n canvas.style.height = `${canvasHeight}`;\n if (options.backgroundColor) {\n context.fillStyle = options.backgroundColor;\n context.fillRect(0, 0, canvas.width, canvas.height);\n }\n context.drawImage(img, 0, 0, canvas.width, canvas.height);\n return canvas;\n}\nexport async function toPixelData(node, options = {}) {\n const { width, height } = getImageSize(node, options);\n const canvas = await toCanvas(node, options);\n const ctx = canvas.getContext('2d');\n return ctx.getImageData(0, 0, width, height).data;\n}\nexport async function toPng(node, options = {}) {\n const canvas = await toCanvas(node, options);\n return canvas.toDataURL();\n}\nexport async function toJpeg(node, options = {}) {\n const canvas = await toCanvas(node, options);\n return canvas.toDataURL('image/jpeg', options.quality || 1);\n}\nexport async function toBlob(node, options = {}) {\n const canvas = await toCanvas(node, options);\n const blob = await canvasToBlob(canvas);\n return blob;\n}\nexport async function getFontEmbedCSS(node, options = {}) {\n return getWebFontCSS(node, options);\n}\n//# sourceMappingURL=index.js.map","import type { Annotation } from '../types'\nimport { parsePathPolylines } from './capture'\n\nexport interface CropRect {\n x: number\n y: number\n width: number\n height: number\n}\n\ninterface Bounds {\n minX: number\n minY: number\n maxX: number\n maxY: number\n}\n\nconst MIN_CROP_WIDTH = 400\nconst MIN_CROP_HEIGHT = 300\nconst PADDING_PX = 150\nconst PADDING_RATIO = 0.3\nconst SKIP_CROP_RATIO = 0.85\n\nexport function getAnnotationBounds(annotations: Annotation[]): Bounds | null {\n let minX = Infinity\n let minY = Infinity\n let maxX = -Infinity\n let maxY = -Infinity\n\n for (const ann of annotations) {\n if (ann.type === 'pin') {\n minX = Math.min(minX, ann.x)\n minY = Math.min(minY, ann.y)\n maxX = Math.max(maxX, ann.x)\n maxY = Math.max(maxY, ann.y)\n if (ann.targetRect) {\n const r = ann.targetRect\n minX = Math.min(minX, r.left)\n minY = Math.min(minY, r.top)\n maxX = Math.max(maxX, r.left + r.width)\n maxY = Math.max(maxY, r.bottom)\n }\n } else if (ann.type === 'draw' && ann.drawPath) {\n for (const polyline of parsePathPolylines(ann.drawPath)) {\n for (const [x, y] of polyline) {\n minX = Math.min(minX, x)\n minY = Math.min(minY, y)\n maxX = Math.max(maxX, x)\n maxY = Math.max(maxY, y)\n }\n }\n }\n }\n\n if (!isFinite(minX) || !isFinite(minY)) return null\n return { minX, minY, maxX, maxY }\n}\n\nexport function computeCropRegion(\n annotations: Annotation[],\n viewportWidth: number,\n viewportHeight: number,\n): CropRect | null {\n const bounds = getAnnotationBounds(annotations)\n if (!bounds) return null\n\n const padX = Math.max(PADDING_PX, viewportWidth * PADDING_RATIO)\n const padY = Math.max(PADDING_PX, viewportHeight * PADDING_RATIO)\n\n let x = bounds.minX - padX\n let y = bounds.minY - padY\n let w = (bounds.maxX - bounds.minX) + padX * 2\n let h = (bounds.maxY - bounds.minY) + padY * 2\n\n if (w < MIN_CROP_WIDTH) {\n x -= (MIN_CROP_WIDTH - w) / 2\n w = MIN_CROP_WIDTH\n }\n if (h < MIN_CROP_HEIGHT) {\n y -= (MIN_CROP_HEIGHT - h) / 2\n h = MIN_CROP_HEIGHT\n }\n\n x = Math.max(0, x)\n y = Math.max(0, y)\n w = Math.min(w, viewportWidth - x)\n h = Math.min(h, viewportHeight - y)\n\n if (w >= viewportWidth * SKIP_CROP_RATIO && h >= viewportHeight * SKIP_CROP_RATIO) {\n return null\n }\n\n return {\n x: Math.round(x),\n y: Math.round(y),\n width: Math.round(w),\n height: Math.round(h),\n }\n}\n\nexport function cropCanvas(source: HTMLCanvasElement, rect: CropRect): HTMLCanvasElement {\n const cropped = document.createElement('canvas')\n cropped.width = rect.width\n cropped.height = rect.height\n const ctx = cropped.getContext('2d')\n if (ctx) {\n ctx.drawImage(source, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height)\n }\n return cropped\n}\n\nexport async function cropDataUrl(dataUrl: string, rect: CropRect): Promise<string> {\n const image = await loadImageForCrop(dataUrl)\n if (!image) return dataUrl\n const canvas = document.createElement('canvas')\n canvas.width = rect.width\n canvas.height = rect.height\n const ctx = canvas.getContext('2d')\n if (!ctx) return dataUrl\n ctx.drawImage(image, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height)\n return canvas.toDataURL('image/jpeg', 0.85)\n}\n\nfunction loadImageForCrop(dataUrl: string): Promise<HTMLImageElement | null> {\n return new Promise(resolve => {\n const img = new Image()\n img.onload = () => resolve(img)\n img.onerror = () => resolve(null)\n img.src = dataUrl\n })\n}\n","import { toJpeg } from 'html-to-image'\nimport type { Annotation } from '../types'\nimport { BRAND_COLOR, FONT_STACK, brandAlpha } from '../styles'\nimport { computeCropRegion, cropCanvas } from './crop'\n\ninterface CaptureMetrics {\n left: number\n top: number\n width: number\n height: number\n}\n\n// Capture at CSS pixels (pixelRatio 1) as JPEG to keep the upload small: on\n// retina screens the default devicePixelRatio would quadruple the pixel count,\n// and the model downscales past ~1568px anyway.\n//\n// Annotations are baked onto the captured bitmap with canvas 2D afterwards —\n// never mounted into the live page — so the capture leaves the page visually\n// untouched no matter how long the DOM snapshot takes.\nexport async function captureScreenshot(annotations: Annotation[] = []): Promise<Blob | null> {\n try {\n const captureMetrics = getCaptureMetrics(document.body)\n const dataUrl = await toJpeg(document.body, {\n quality: 0.85,\n pixelRatio: 1,\n backgroundColor: '#ffffff',\n skipFonts: true,\n skipAutoScale: false,\n filter: (node) => {\n if (node instanceof HTMLElement && node.id === 'mtb-widget-host') return false\n return true\n },\n })\n if (annotations.length > 0) {\n const annotated = await bakeAnnotations(dataUrl, annotations, captureMetrics)\n if (annotated) return annotated\n }\n return dataUrlToBlob(dataUrl)\n } catch {\n return null\n }\n}\n\nasync function bakeAnnotations(\n dataUrl: string,\n annotations: Annotation[],\n captureMetrics: CaptureMetrics,\n): Promise<Blob | null> {\n const canvas = document.createElement('canvas')\n const ctx = canvas.getContext('2d')\n if (!ctx) return null\n\n const image = await loadImage(dataUrl)\n if (!image) return null\n\n canvas.width = image.naturalWidth || window.innerWidth\n canvas.height = image.naturalHeight || window.innerHeight\n ctx.drawImage(image, 0, 0)\n const scaleX = canvas.width / captureMetrics.width\n const scaleY = canvas.height / captureMetrics.height\n\n let pinIndex = 0\n for (const annotation of annotations) {\n if (annotation.type === 'draw' && annotation.drawPath) {\n drawStroke(ctx, annotation.drawPath, captureMetrics, scaleX, scaleY)\n } else if (annotation.type === 'pin') {\n drawPin(\n ctx,\n (annotation.x - captureMetrics.left) * scaleX,\n (annotation.y - captureMetrics.top) * scaleY,\n ++pinIndex,\n )\n }\n }\n\n const cropRect = computeCropRegion(annotations, window.innerWidth, window.innerHeight)\n if (cropRect) {\n const left = Math.max(0, Math.round((cropRect.x - captureMetrics.left) * scaleX))\n const top = Math.max(0, Math.round((cropRect.y - captureMetrics.top) * scaleY))\n const right = Math.min(canvas.width, Math.round((cropRect.x + cropRect.width - captureMetrics.left) * scaleX))\n const bottom = Math.min(canvas.height, Math.round((cropRect.y + cropRect.height - captureMetrics.top) * scaleY))\n const scaled = {\n x: left,\n y: top,\n width: right - left,\n height: bottom - top,\n }\n return canvasToJpegBlob(cropCanvas(canvas, scaled))\n }\n\n return canvasToJpegBlob(canvas)\n}\n\nfunction drawStroke(\n ctx: CanvasRenderingContext2D,\n drawPath: string,\n captureMetrics: CaptureMetrics,\n scaleX: number,\n scaleY: number,\n): void {\n ctx.save()\n ctx.strokeStyle = BRAND_COLOR\n ctx.lineWidth = 3.5\n ctx.lineCap = 'round'\n ctx.lineJoin = 'round'\n ctx.shadowColor = brandAlpha(0.35)\n ctx.shadowOffsetY = 1\n ctx.shadowBlur = 2\n for (const points of parsePathPolylines(drawPath)) {\n if (points.length === 0) continue\n ctx.beginPath()\n ctx.moveTo(\n (points[0][0] - captureMetrics.left) * scaleX,\n (points[0][1] - captureMetrics.top) * scaleY,\n )\n for (let i = 1; i < points.length; i++) {\n ctx.lineTo(\n (points[i][0] - captureMetrics.left) * scaleX,\n (points[i][1] - captureMetrics.top) * scaleY,\n )\n }\n ctx.stroke()\n }\n ctx.restore()\n}\n\nfunction getCaptureMetrics(node: HTMLElement): CaptureMetrics {\n const rect = node.getBoundingClientRect()\n const style = window.getComputedStyle(node)\n const borderWidth = parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth)\n const borderHeight = parseFloat(style.borderTopWidth) + parseFloat(style.borderBottomWidth)\n\n return {\n left: rect.left,\n top: rect.top,\n width: node.clientWidth + (Number.isFinite(borderWidth) ? borderWidth : 0) || window.innerWidth,\n height: node.clientHeight + (Number.isFinite(borderHeight) ? borderHeight : 0) || window.innerHeight,\n }\n}\n\nfunction drawPin(ctx: CanvasRenderingContext2D, x: number, y: number, index: number): void {\n ctx.save()\n ctx.shadowColor = brandAlpha(0.45)\n ctx.shadowOffsetY = 2\n ctx.shadowBlur = 8\n ctx.fillStyle = BRAND_COLOR\n ctx.beginPath()\n ctx.arc(x, y, 11, 0, Math.PI * 2)\n ctx.fill()\n ctx.shadowColor = 'transparent'\n ctx.lineWidth = 2\n ctx.strokeStyle = '#ffffff'\n ctx.stroke()\n ctx.fillStyle = '#ffffff'\n ctx.font = `700 10px ${FONT_STACK}`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(String(index), x, y)\n ctx.restore()\n}\n\n// The draw layer only ever emits M/L polyline commands (see buildPathD in\n// annotate/draw.ts); anything else in the string is ignored.\nexport function parsePathPolylines(drawPath: string): Array<Array<[number, number]>> {\n const polylines: Array<Array<[number, number]>> = []\n let current: Array<[number, number]> | null = null\n const tokens = drawPath.match(/[ML]\\s*[-\\d.]+\\s+[-\\d.]+/g) ?? []\n for (const token of tokens) {\n const [x, y] = token.slice(1).trim().split(/\\s+/).map(Number)\n if (Number.isNaN(x) || Number.isNaN(y)) continue\n if (token[0] === 'M') {\n current = [[x, y]]\n polylines.push(current)\n } else if (current) {\n current.push([x, y])\n }\n }\n return polylines\n}\n\nfunction loadImage(dataUrl: string): Promise<HTMLImageElement | null> {\n return new Promise(resolve => {\n const image = new Image()\n image.onload = () => resolve(image)\n image.onerror = () => resolve(null)\n image.src = dataUrl\n })\n}\n\nfunction canvasToJpegBlob(canvas: HTMLCanvasElement): Promise<Blob | null> {\n return new Promise(resolve => {\n try {\n canvas.toBlob(blob => resolve(blob), 'image/jpeg', 0.85)\n } catch {\n resolve(null)\n }\n })\n}\n\nfunction dataUrlToBlob(dataUrl: string): Blob {\n const [header, data] = dataUrl.split(',')\n const mime = header.match(/:(.*?);/)?.[1] ?? 'image/png'\n const binary = atob(data)\n const bytes = new Uint8Array(binary.length)\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i)\n }\n return new Blob([bytes], { type: mime })\n}\n","export interface ErrorSourceEvent {\n message: string\n source?: string\n line?: number\n col?: number\n error?: unknown\n}\n\ntype ErrorListener = (event: ErrorSourceEvent) => void\n\nclass ErrorSource {\n private listeners = new Set<ErrorListener>()\n private originalOnError: OnErrorEventHandler | null = null\n private installedOnError: OnErrorEventHandler | null = null\n private rejectionHandler: ((e: PromiseRejectionEvent) => void) | null = null\n private hooked = false\n\n subscribe(listener: ErrorListener): () => void {\n this.listeners.add(listener)\n this.hook()\n return () => {\n this.listeners.delete(listener)\n if (this.listeners.size === 0) this.unhook()\n }\n }\n\n private hook(): void {\n if (this.hooked) return\n this.hooked = true\n\n this.originalOnError = window.onerror\n this.installedOnError = (msg, source, line, col, error) => {\n this.emit({ message: String(msg), source, line, col, error })\n if (this.originalOnError) {\n return this.originalOnError.call(window, msg, source, line, col, error)\n }\n return false\n }\n window.onerror = this.installedOnError\n\n this.rejectionHandler = (e: PromiseRejectionEvent) => {\n const reason = e.reason instanceof Error ? e.reason.message : String(e.reason)\n this.emit({ message: `Unhandled rejection: ${reason}` })\n }\n window.addEventListener('unhandledrejection', this.rejectionHandler)\n }\n\n private unhook(): void {\n if (!this.hooked) return\n this.hooked = false\n // Only restore if nothing replaced our handler meanwhile — restoring\n // the stale snapshot would clobber a handler the page installed later.\n if (window.onerror === this.installedOnError) {\n window.onerror = this.originalOnError\n }\n this.installedOnError = null\n this.originalOnError = null\n if (this.rejectionHandler) {\n window.removeEventListener('unhandledrejection', this.rejectionHandler)\n this.rejectionHandler = null\n }\n }\n\n private emit(event: ErrorSourceEvent): void {\n for (const listener of this.listeners) listener(event)\n }\n}\n\nexport const errorSource = new ErrorSource()\n","import { errorSource, type ErrorSourceEvent } from './error-source'\n\nconst MAX_CONSOLE_ERRORS = 20\n\nexport class ConsoleErrorCollector {\n private errors: string[] = []\n private unsubscribe: (() => void) | null = null\n\n start(): void {\n if (this.unsubscribe) return\n this.unsubscribe = errorSource.subscribe((e) => this.record(e))\n }\n\n private record(e: ErrorSourceEvent): void {\n const location = e.line != null ? ` (${e.line}:${e.col ?? 0})` : ''\n this.addError(`${e.message}${location}`)\n }\n\n private addError(msg: string): void {\n if (this.errors.length >= MAX_CONSOLE_ERRORS) return\n if (!this.errors.includes(msg)) {\n this.errors.push(msg)\n }\n }\n\n getErrors(): string[] {\n return [...this.errors]\n }\n\n stop(): void {\n this.unsubscribe?.()\n this.unsubscribe = null\n }\n}\n","// Single owner of the history.pushState / replaceState patch.\n//\n// Two collectors (breadcrumbs and frustration) both need to know when an SPA\n// navigates. When each wrapped history itself, teardown could only restore the\n// native function if it happened to be the outermost wrapper — so tearing them\n// down in install order (FIFO teardown of a LIFO stack) left one dead wrapper\n// behind per cycle, and Turbo Drive reinstalls on every visit. Refcounting one\n// wrapper here makes the install order irrelevant: the patch goes on when the\n// first listener subscribes and comes off when the last one unsubscribes.\n\ntype NavListener = () => void\n\nconst listeners = new Set<NavListener>()\n\nlet nativePushState: History['pushState'] | null = null\nlet nativeReplaceState: History['replaceState'] | null = null\nlet installedPushState: History['pushState'] | null = null\nlet installedReplaceState: History['replaceState'] | null = null\nlet popstateHandler: (() => void) | null = null\n\n// Subscribes to pushState, replaceState and popstate. Returns an unsubscribe\n// function; calling it twice is harmless.\nexport function onHistoryNavigation(listener: NavListener): () => void {\n listeners.add(listener)\n install()\n\n let released = false\n return () => {\n if (released) return\n released = true\n listeners.delete(listener)\n if (listeners.size === 0) uninstall()\n }\n}\n\nfunction notify(): void {\n // Copy first: a listener may unsubscribe (or subscribe) while being notified.\n for (const listener of [...listeners]) {\n try { listener() } catch { /* never propagate into the host page */ }\n }\n}\n\nfunction install(): void {\n if (installedPushState) return\n\n popstateHandler = () => notify()\n window.addEventListener('popstate', popstateHandler)\n\n // Snapshot the raw functions and invoke them with .call — binding would hand\n // back a different function object on uninstall, so the host page would never\n // get its own pushState identity back and each cycle would add a bind layer.\n nativePushState = history.pushState\n nativeReplaceState = history.replaceState\n const pushOrig = nativePushState\n const replaceOrig = nativeReplaceState\n\n installedPushState = function (data: unknown, unused: string, url?: string | URL | null) {\n pushOrig.call(history, data, unused, url)\n notify()\n }\n installedReplaceState = function (data: unknown, unused: string, url?: string | URL | null) {\n replaceOrig.call(history, data, unused, url)\n notify()\n }\n history.pushState = installedPushState\n history.replaceState = installedReplaceState\n}\n\nfunction uninstall(): void {\n if (popstateHandler) {\n window.removeEventListener('popstate', popstateHandler)\n popstateHandler = null\n }\n // Only restore if nothing (e.g. an SPA router) re-wrapped the functions\n // after us — restoring the stale snapshot would discard their wrapper.\n if (nativePushState && history.pushState === installedPushState) {\n history.pushState = nativePushState\n }\n if (nativeReplaceState && history.replaceState === installedReplaceState) {\n history.replaceState = nativeReplaceState\n }\n nativePushState = null\n nativeReplaceState = null\n installedPushState = null\n installedReplaceState = null\n}\n","import { errorSource, type ErrorSourceEvent } from './error-source'\nimport { getCssSelector, getElementName } from '../annotate/highlighter'\nimport { isWidgetElement } from './dom-utils'\nimport { onHistoryNavigation } from './history-patch'\nimport type { Breadcrumb } from '../types'\n\nconst MAX_BREADCRUMBS = 20\n\nexport class BreadcrumbCollector {\n private breadcrumbs: Breadcrumb[] = []\n private active = false\n private unsubscribeErrors: (() => void) | null = null\n private boundClickHandler: (e: MouseEvent) => void\n private boundChangeHandler: (e: Event) => void\n private unsubscribeNavigation: (() => void) | null = null\n private lastUrl = ''\n\n constructor() {\n this.boundClickHandler = (e: MouseEvent) => this.handleClick(e)\n this.boundChangeHandler = (e: Event) => this.handleChange(e)\n }\n\n start(): void {\n if (this.active) return\n this.active = true\n this.lastUrl = location.href\n document.addEventListener('click', this.boundClickHandler, { capture: true, passive: true })\n document.addEventListener('change', this.boundChangeHandler, { capture: true, passive: true })\n this.unsubscribeErrors = errorSource.subscribe((e) => this.recordError(e))\n this.unsubscribeNavigation = onHistoryNavigation(() => this.handleNavigation())\n }\n\n stop(): void {\n if (!this.active) return\n this.active = false\n document.removeEventListener('click', this.boundClickHandler, true)\n document.removeEventListener('change', this.boundChangeHandler, true)\n this.unsubscribeErrors?.()\n this.unsubscribeErrors = null\n this.unsubscribeNavigation?.()\n this.unsubscribeNavigation = null\n }\n\n getBreadcrumbs(): Breadcrumb[] {\n return [...this.breadcrumbs]\n }\n\n private add(crumb: Breadcrumb): void {\n this.breadcrumbs.push(crumb)\n if (this.breadcrumbs.length > MAX_BREADCRUMBS) {\n this.breadcrumbs.shift()\n }\n }\n\n private handleClick(e: MouseEvent): void {\n const target = e.target as Element | null\n if (!target) return\n if (isWidgetElement(target)) return\n\n try {\n this.add({\n type: 'ui',\n category: 'ui.click',\n timestamp: Date.now(),\n message: getElementName(target),\n data: { selector: getCssSelector(target) },\n })\n } catch { /* never propagate into host page */ }\n }\n\n private handleChange(e: Event): void {\n const target = e.target as Element | null\n if (!target) return\n if (isWidgetElement(target)) return\n\n try {\n const input = target as HTMLInputElement\n const field = input.name || input.placeholder || target.getAttribute('aria-label') || target.tagName\n this.add({\n type: 'ui',\n category: 'ui.input',\n timestamp: Date.now(),\n message: field,\n data: { field },\n })\n } catch { /* never propagate into host page */ }\n }\n\n private recordError(e: ErrorSourceEvent): void {\n this.add({\n type: 'console',\n category: 'console.error',\n timestamp: Date.now(),\n message: e.message,\n data: { message: e.message },\n })\n }\n\n private handleNavigation(): void {\n if (!this.active) return\n const from = this.lastUrl\n const to = location.href\n if (from === to) return\n this.lastUrl = to\n this.add({\n type: 'navigation',\n category: 'navigation',\n timestamp: Date.now(),\n message: `${from} → ${to}`,\n data: { from, to },\n })\n }\n\n}\n","// Frustration state that must outlive a single page visit.\n//\n// The detector and the widget controller are both rebuilt from scratch on every\n// Turbo Drive navigation (see src/index.ts), which used to reset all of this.\n// The consequences were: `rapid_navigation` could never fire (it needs 3\n// timestamps within 5s but each visit contributed at most one), the 60s cooldown\n// was bypassed by navigating, an already-reported error page re-prompted on\n// revisit, and a reporter's explicit \"Dismiss\" did not survive one visit.\n//\n// sessionStorage is the right scope — this is per-tab, per-visit-series state,\n// not a long-lived identity like mtb_anon_id. Writes are best-effort: Safari\n// private mode and storage-partitioned iframes throw, so an in-memory copy backs\n// every read (it covers the current page at least).\n\nconst STORAGE_KEY = 'mtb_frustration_state'\n// Keeps a long browsing session from growing the stored payload without bound.\nconst MAX_ERROR_PAGE_URLS = 20\n\nexport interface FrustrationState {\n navTimestamps: number[]\n cooldownUntil: number\n errorPageUrls: string[]\n dismissedByUser: boolean\n}\n\nlet memoryState: FrustrationState | null = null\n\n// Every return path goes through normalize(), which rebuilds the arrays. Callers\n// own their copy and mutate it in place (the detector pushes onto navTimestamps),\n// so handing out a shared array would let one caller corrupt the stored state.\nexport function loadFrustrationState(): FrustrationState {\n try {\n const raw = window.sessionStorage.getItem(STORAGE_KEY)\n if (!raw) return normalize(memoryState)\n return normalize(JSON.parse(raw))\n } catch {\n return normalize(memoryState)\n }\n}\n\nexport function saveFrustrationState(state: FrustrationState): void {\n const normalized = normalize(state)\n memoryState = normalized\n try {\n window.sessionStorage.setItem(STORAGE_KEY, JSON.stringify(normalized))\n } catch {\n // sessionStorage unavailable — the in-memory copy covers this page\n }\n}\n\nexport function isFrustrationDismissed(): boolean {\n return loadFrustrationState().dismissedByUser\n}\n\n// Records a real refusal (the reporter clicked Dismiss), which suppresses\n// proactive prompts for the rest of the tab session. An auto-hide must never\n// call this — the 60s cooldown is what rate-limits an ignored prompt.\nexport function markFrustrationDismissed(): void {\n saveFrustrationState({ ...loadFrustrationState(), dismissedByUser: true })\n}\n\nexport function clearFrustrationState(): void {\n memoryState = null\n try {\n window.sessionStorage.removeItem(STORAGE_KEY)\n } catch {\n // nothing to clear\n }\n}\n\nfunction normalize(value: unknown): FrustrationState {\n const raw = (value ?? {}) as Partial<Record<keyof FrustrationState, unknown>>\n return {\n navTimestamps: Array.isArray(raw.navTimestamps)\n ? raw.navTimestamps.filter((t): t is number => typeof t === 'number')\n : [],\n cooldownUntil: typeof raw.cooldownUntil === 'number' ? raw.cooldownUntil : 0,\n errorPageUrls: Array.isArray(raw.errorPageUrls)\n ? raw.errorPageUrls.filter((u): u is string => typeof u === 'string').slice(-MAX_ERROR_PAGE_URLS)\n : [],\n dismissedByUser: raw.dismissedByUser === true,\n }\n}\n","import { errorSource } from './error-source'\nimport { isWidgetElement } from './dom-utils'\nimport { onHistoryNavigation } from './history-patch'\nimport { loadFrustrationState, saveFrustrationState } from './frustration-state'\n\nexport type FrustrationSignal =\n | 'rage_click'\n | 'dead_click'\n | 'rapid_navigation'\n | 'form_failure'\n | 'error_page'\n | 'dead_click_dom'\n\nexport interface FrustrationEvent {\n signal: FrustrationSignal\n target?: string\n detail?: string\n timestamp: number\n}\n\ninterface ClickRecord {\n target: EventTarget | null\n time: number\n}\n\nconst RAGE_CLICK_THRESHOLD = 3\nconst RAGE_CLICK_WINDOW_MS = 1000\nconst RAPID_NAV_THRESHOLD = 3\nconst RAPID_NAV_WINDOW_MS = 5000\nconst FORM_CHECK_DELAY_MS = 500\nconst DEAD_CLICK_DOM_DELAY_MS = 500\nconst ERROR_PAGE_CHECK_DELAY_MS = 300\n\nconst INTERACTIVE_TAGS = new Set([\n 'A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA', 'LABEL', 'SUMMARY', 'DETAILS',\n])\n\nconst INTERACTIVE_ROLES = new Set([\n 'button', 'link', 'checkbox', 'radio', 'tab', 'menuitem', 'option',\n 'switch', 'textbox', 'combobox', 'listbox', 'slider', 'spinbutton',\n])\n\nconst ERROR_PAGE_PATTERNS = [\n '404', '500', 'not found', 'page not found',\n 'server error', 'internal server error',\n]\n\nexport class FrustrationDetector {\n private clickHistory: ClickRecord[] = []\n private onFrustration: (event: FrustrationEvent) => void\n private boundClickHandler: (e: MouseEvent) => void\n private unsubscribeErrors: (() => void) | null = null\n private active = false\n private errorCount = 0\n private deadClickCount = 0\n private cooldownUntil = 0\n private static readonly COOLDOWN_MS = 60_000\n\n private navTimestamps: number[] = []\n private unsubscribeNavigation: (() => void) | null = null\n private boundPageLeaveHandler: (() => void) | null = null\n private lastNavigationAt = -1\n private boundSubmitHandler: ((e: Event) => void) | null = null\n private boundInvalidHandler: ((e: Event) => void) | null = null\n private recentSubmitForms = new WeakSet<HTMLFormElement>()\n private errorPageUrls = new Set<string>()\n private domObserver: MutationObserver | null = null\n private pendingDomChecks = 0\n private lastMutationAt = -1\n\n constructor(onFrustration: (event: FrustrationEvent) => void) {\n this.onFrustration = onFrustration\n this.boundClickHandler = (e: MouseEvent) => this.handleClick(e)\n }\n\n start(): void {\n if (this.active) return\n this.active = true\n this.restoreState()\n document.addEventListener('click', this.boundClickHandler, true)\n this.unsubscribeErrors = errorSource.subscribe((_e) => {\n this.errorCount++\n })\n\n this.startNavigationTracking()\n this.startFormTracking()\n this.checkErrorPage()\n }\n\n stop(): void {\n if (!this.active) return\n this.active = false\n document.removeEventListener('click', this.boundClickHandler, true)\n this.unsubscribeErrors?.()\n this.unsubscribeErrors = null\n this.clickHistory = []\n\n this.stopNavigationTracking()\n this.stopFormTracking()\n this.errorPageUrls.clear()\n\n this.disconnectDomObserver()\n }\n\n private startNavigationTracking(): void {\n this.unsubscribeNavigation = onHistoryNavigation(() => this.handleNavigation())\n\n // A click that starts a full-page navigation (checkout, OAuth, external\n // link, download, window.location assignment) leaves the DOM untouched\n // while the browser tears the page down, which is indistinguishable from a\n // dead click by mutation alone. Recording when the page starts leaving lets\n // checkDeadClickDom acquit those clicks. Both events are needed: browsers\n // skip beforeunload when nothing registered an unload prompt, and Safari\n // reaches bfcache via pagehide only.\n this.boundPageLeaveHandler = () => this.noteNavigationStarted()\n window.addEventListener('beforeunload', this.boundPageLeaveHandler)\n window.addEventListener('pagehide', this.boundPageLeaveHandler)\n }\n\n private stopNavigationTracking(): void {\n this.unsubscribeNavigation?.()\n this.unsubscribeNavigation = null\n this.navTimestamps = []\n\n if (this.boundPageLeaveHandler) {\n window.removeEventListener('beforeunload', this.boundPageLeaveHandler)\n window.removeEventListener('pagehide', this.boundPageLeaveHandler)\n this.boundPageLeaveHandler = null\n }\n this.lastNavigationAt = -1\n }\n\n private noteNavigationStarted(): void {\n this.lastNavigationAt = Date.now()\n }\n\n // Rehydrates the state a Turbo Drive visit would otherwise reset. Without this,\n // a fresh detector on every page starts with an empty nav history (so\n // `rapid_navigation` can never reach its 3-in-5s threshold), no cooldown, and no\n // memory of which error pages it already reported.\n private restoreState(): void {\n const stored = loadFrustrationState()\n this.navTimestamps = stored.navTimestamps\n this.cooldownUntil = stored.cooldownUntil\n this.errorPageUrls = new Set(stored.errorPageUrls)\n }\n\n private persistState(): void {\n const stored = loadFrustrationState()\n saveFrustrationState({\n ...stored,\n navTimestamps: this.navTimestamps,\n cooldownUntil: this.cooldownUntil,\n errorPageUrls: [...this.errorPageUrls],\n })\n }\n\n private startFormTracking(): void {\n this.boundSubmitHandler = (e: Event) => this.handleFormSubmit(e)\n this.boundInvalidHandler = (e: Event) => this.handleFormInvalid(e)\n document.addEventListener('submit', this.boundSubmitHandler, true)\n document.addEventListener('invalid', this.boundInvalidHandler, true)\n }\n\n private stopFormTracking(): void {\n if (this.boundSubmitHandler) {\n document.removeEventListener('submit', this.boundSubmitHandler, true)\n this.boundSubmitHandler = null\n }\n if (this.boundInvalidHandler) {\n document.removeEventListener('invalid', this.boundInvalidHandler, true)\n this.boundInvalidHandler = null\n }\n }\n\n private handleClick(e: MouseEvent): void {\n const target = e.target as Element | null\n if (!target) return\n\n if (isWidgetElement(target)) return\n this.trackFormSubmitIntent(target)\n\n const now = Date.now()\n this.clickHistory.push({ target, time: now })\n\n const cutoff = now - RAGE_CLICK_WINDOW_MS\n this.clickHistory = this.clickHistory.filter(r => r.time > cutoff)\n\n const sameTargetClicks = this.clickHistory.filter(r => r.target === target)\n if (sameTargetClicks.length >= RAGE_CLICK_THRESHOLD) {\n this.clickHistory = []\n this.emitHighPriority({\n signal: 'rage_click',\n target: describeElement(target),\n timestamp: now,\n })\n return\n }\n\n if (!this.isInteractive(target)) {\n this.deadClickCount++\n if (this.deadClickCount >= 3 && this.errorCount > 0) {\n this.deadClickCount = 0\n this.errorCount = 0\n this.emitIfReady({\n signal: 'dead_click',\n target: describeElement(target),\n timestamp: now,\n })\n }\n }\n\n this.checkDeadClickDom(target, now)\n }\n\n private handleNavigation(): void {\n const now = Date.now()\n this.noteNavigationStarted()\n this.navTimestamps.push(now)\n const cutoff = now - RAPID_NAV_WINDOW_MS\n this.navTimestamps = this.navTimestamps.filter(t => t > cutoff)\n if (this.navTimestamps.length >= RAPID_NAV_THRESHOLD) {\n this.navTimestamps = []\n this.emitIfReady({\n signal: 'rapid_navigation',\n timestamp: now,\n })\n }\n this.persistState()\n setTimeout(() => {\n if (this.active) this.checkErrorPage()\n }, ERROR_PAGE_CHECK_DELAY_MS)\n }\n\n private handleFormSubmit(e: Event): void {\n const form = e.target\n if (!(form instanceof HTMLFormElement)) return\n if (isWidgetElement(form)) return\n\n this.rememberSubmitAttempt(form)\n\n setTimeout(() => {\n if (!this.active) return\n if (form.querySelector('[aria-invalid=\"true\"], .is-invalid')) {\n this.emitIfReady({\n signal: 'form_failure',\n target: describeElement(form),\n timestamp: Date.now(),\n })\n }\n }, FORM_CHECK_DELAY_MS)\n }\n\n private trackFormSubmitIntent(target: Element): void {\n const control = target.closest('button, input')\n if (!(control instanceof HTMLButtonElement || control instanceof HTMLInputElement)) return\n if (control.type !== 'submit' && control.type !== 'image') return\n if (!control.form || isWidgetElement(control.form)) return\n\n this.rememberSubmitAttempt(control.form)\n }\n\n private rememberSubmitAttempt(form: HTMLFormElement): void {\n this.recentSubmitForms.add(form)\n setTimeout(() => {\n this.recentSubmitForms.delete(form)\n }, FORM_CHECK_DELAY_MS)\n }\n\n private handleFormInvalid(e: Event): void {\n const el = e.target as Element | null\n if (!el) return\n if (isWidgetElement(el)) return\n const form = el.closest('form')\n if (!form || !this.recentSubmitForms.has(form)) return\n this.emitIfReady({\n signal: 'form_failure',\n target: describeElement(form),\n timestamp: Date.now(),\n })\n }\n\n private checkErrorPage(): void {\n const url = location.href\n if (this.errorPageUrls.has(url)) return\n\n const title = document.title.toLowerCase()\n if (ERROR_PAGE_PATTERNS.some(p => title.includes(p))) {\n this.errorPageUrls.add(url)\n this.emitHighPriority({\n signal: 'error_page',\n detail: document.title,\n timestamp: Date.now(),\n })\n return\n }\n\n const candidates = document.querySelectorAll(\n 'h1, h2, [class*=\"error\"], [class*=\"not-found\"], [id*=\"error\"], [id*=\"not-found\"]'\n )\n for (const el of candidates) {\n const text = el.textContent ?? ''\n if (text.length < 200 && ERROR_PAGE_PATTERNS.some(p => text.toLowerCase().includes(p))) {\n this.errorPageUrls.add(url)\n this.emitHighPriority({\n signal: 'error_page',\n detail: text.trim().slice(0, 60),\n timestamp: Date.now(),\n })\n return\n }\n }\n }\n\n // One shared observer for all in-flight dead-click checks, connected only\n // while at least one check is pending — a full-page observer per click was\n // too heavy on mutation-busy pages.\n private checkDeadClickDom(target: Element, clickTime: number): void {\n if (!this.looksInteractive(target)) return\n\n this.pendingDomChecks++\n this.ensureDomObserver()\n\n setTimeout(() => {\n this.pendingDomChecks--\n const mutated = this.lastMutationAt >= clickTime\n // A navigation that began at or after the click means the click worked;\n // the page just left before it could mutate anything.\n const navigated = this.lastNavigationAt >= clickTime\n if (this.pendingDomChecks === 0) this.disconnectDomObserver()\n\n if (!mutated && !navigated && this.active) {\n this.emitIfReady({\n signal: 'dead_click_dom',\n target: describeElement(target),\n timestamp: clickTime,\n })\n }\n }, DEAD_CLICK_DOM_DELAY_MS)\n }\n\n private ensureDomObserver(): void {\n if (this.domObserver) return\n this.domObserver = new MutationObserver(() => {\n this.lastMutationAt = Date.now()\n })\n this.domObserver.observe(document.body, {\n childList: true,\n subtree: true,\n attributes: true,\n characterData: true,\n })\n }\n\n private disconnectDomObserver(): void {\n this.domObserver?.disconnect()\n this.domObserver = null\n }\n\n private looksInteractive(el: Element): boolean {\n const style = window.getComputedStyle(el)\n if (style.cursor === 'pointer') return true\n\n if (el.classList) {\n for (const cls of el.classList) {\n const lower = cls.toLowerCase()\n if (lower.includes('btn') || lower.includes('button')) return true\n }\n }\n\n return false\n }\n\n private isInteractive(el: Element): boolean {\n if (INTERACTIVE_TAGS.has(el.tagName)) return true\n\n const role = el.getAttribute('role')\n if (role && INTERACTIVE_ROLES.has(role)) return true\n\n if (el.hasAttribute('onclick') || el.hasAttribute('tabindex')) return true\n if ((el as HTMLElement).contentEditable === 'true') return true\n\n const style = window.getComputedStyle(el)\n if (style.cursor === 'pointer') return true\n\n const parent = el.closest('a, button, [role=\"button\"], [role=\"link\"], label')\n if (parent) return true\n\n return false\n }\n\n\n private emitIfReady(event: FrustrationEvent): void {\n const now = Date.now()\n if (now < this.cooldownUntil) return\n this.cooldownUntil = now + FrustrationDetector.COOLDOWN_MS\n this.persistState()\n this.onFrustration(event)\n }\n\n private emitHighPriority(event: FrustrationEvent): void {\n this.cooldownUntil = Date.now() + FrustrationDetector.COOLDOWN_MS\n this.persistState()\n this.onFrustration(event)\n }\n}\n\nfunction describeElement(el: Element): string {\n const tag = el.tagName.toLowerCase()\n const id = el.id ? `#${el.id}` : ''\n const cls = el.className && typeof el.className === 'string'\n ? '.' + el.className.trim().split(/\\s+/).slice(0, 2).join('.')\n : ''\n const text = el.textContent?.trim().slice(0, 30) ?? ''\n return `<${tag}${id}${cls}>${text ? ` \"${text}\"` : ''}`\n}\n","export interface PageContext {\n page_url: string\n user_agent: string\n browser: string\n os: string\n screen_width: number\n screen_height: number\n}\n\nexport function collectPageContext(): PageContext {\n return {\n page_url: window.location.href,\n user_agent: navigator.userAgent,\n browser: detectBrowser(),\n os: detectOS(),\n screen_width: window.screen.width,\n screen_height: window.screen.height,\n }\n}\n\nfunction detectBrowser(): string {\n const ua = navigator.userAgent\n if (/Edg\\//.test(ua)) return `Edge ${ua.match(/Edg\\/(\\S+)/)?.[1] ?? ''}`\n if (/OPR\\//.test(ua)) return `Opera ${ua.match(/OPR\\/(\\S+)/)?.[1] ?? ''}`\n if (/Chrome\\//.test(ua)) return `Chrome ${ua.match(/Chrome\\/(\\S+)/)?.[1] ?? ''}`\n if (/Safari\\//.test(ua) && /Version\\//.test(ua)) return `Safari ${ua.match(/Version\\/(\\S+)/)?.[1] ?? ''}`\n if (/Firefox\\//.test(ua)) return `Firefox ${ua.match(/Firefox\\/(\\S+)/)?.[1] ?? ''}`\n return 'Unknown'\n}\n\nfunction detectOS(): string {\n const ua = navigator.userAgent\n if (/Windows NT 10/.test(ua)) return 'Windows 10/11'\n if (/Windows NT/.test(ua)) return 'Windows'\n if (/Mac OS X 10_15|macOS 1[56789]/.test(ua)) return 'macOS'\n if (/Mac OS X/.test(ua)) return 'macOS'\n if (/Android/.test(ua)) return `Android ${ua.match(/Android (\\d+)/)?.[1] ?? ''}`\n if (/iPhone|iPad|iPod/.test(ua)) return 'iOS'\n if (/Linux/.test(ua)) return 'Linux'\n return 'Unknown'\n}\n","import type { PageContext } from '../context/collector'\nimport type { Annotation, Breadcrumb, FeedbackPayload, MakeThisBetterConfig } from '../types'\nimport type { RecordingResult } from '../record/session'\n\nexport function buildPayload(\n description: string,\n pageContext: PageContext,\n consoleErrors: string[],\n annotation: Annotation | null,\n user: MakeThisBetterConfig['user'],\n recording?: RecordingResult,\n anonId?: string,\n anonEmail?: string,\n breadcrumbs?: Breadcrumb[],\n): FeedbackPayload {\n return {\n description,\n ...pageContext,\n console_errors: consoleErrors,\n annotations: annotation ? [annotation] : [],\n target_element: annotation?.targetSelector\n ? {\n selector: annotation.targetSelector,\n text: annotation.targetText ?? '',\n name: annotation.targetName ?? '',\n }\n : undefined,\n user_id: user?.id,\n user_email: user?.email,\n user_name: user?.name,\n reporter_external_id: user ? undefined : anonId,\n reporter_email: user ? undefined : anonEmail,\n recording_events: recording?.events,\n recording_duration: recording?.duration,\n breadcrumbs,\n }\n}\n","const STORAGE_KEY = 'mtb_anon_id'\nconst EMAIL_KEY = 'mtb_reporter_email'\nconst BOARD_URL_KEY = 'mtb_board_url'\n\nlet memoryId: string | null = null\nlet memoryEmail: string | null = null\nlet memoryBoardUrl: string | null = null\n\nexport function getAnonId(): string {\n try {\n const stored = window.localStorage.getItem(STORAGE_KEY)\n if (stored?.startsWith('anon_')) return stored\n const id = generateAnonId()\n window.localStorage.setItem(STORAGE_KEY, id)\n return id\n } catch {\n memoryId ??= generateAnonId()\n return memoryId\n }\n}\n\nexport function getStoredReporterEmail(): string | undefined {\n try {\n return window.localStorage.getItem(EMAIL_KEY) ?? undefined\n } catch {\n return memoryEmail ?? undefined\n }\n}\n\nexport function rememberReporterEmail(email: string): void {\n memoryEmail = email\n try {\n window.localStorage.setItem(EMAIL_KEY, email)\n } catch {\n // localStorage unavailable — the in-memory copy covers this session\n }\n}\n\nexport function getCachedBoardUrl(): string | undefined {\n try {\n return window.localStorage.getItem(BOARD_URL_KEY) ?? undefined\n } catch {\n return memoryBoardUrl ?? undefined\n }\n}\n\nexport function cacheBoardUrl(url: string): void {\n memoryBoardUrl = url\n try {\n window.localStorage.setItem(BOARD_URL_KEY, url)\n } catch {\n // localStorage unavailable — the in-memory copy covers this session\n }\n}\n\nfunction generateAnonId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return `anon_${crypto.randomUUID()}`\n }\n const random = `${Date.now().toString(16)}-${Math.random().toString(16).slice(2, 10)}`\n return `anon_${random}`\n}\n","export default {\n tab: 'Feedback',\n toolbar: {\n markup: 'Mark up',\n record: 'Record',\n hint: 'Click to comment, drag to draw',\n hintRecord: 'Recording your screen',\n exit: 'Exit',\n },\n popup: {\n about: 'About',\n placeholder: 'Describe the issue or suggestion...',\n submit: 'Submit',\n cancel: 'Cancel',\n my_feedback: 'My feedback',\n quickOptions: [\n { emoji: '🐛', label: \"Something's broken\" },\n { emoji: '💡', label: 'I have a suggestion' },\n { emoji: '🤔', label: \"I'm confused\" },\n ],\n },\n success: {\n title: 'Sent — thanks!',\n message: 'Your note and captured technical context are on their way to the team. You’ll hear back when it’s resolved.',\n title_no_ai: \"Thanks! We've received your feedback.\",\n message_no_ai: \"The team will take it from here. You'll hear back when it's resolved.\",\n view_feedback: 'View my feedback',\n close: 'Close',\n email_prompt: \"Want updates? Leave your email and we'll let you know when it's resolved.\",\n email_placeholder: 'you@example.com',\n email_submit: 'Notify me',\n email_saved: \"You'll get an email when it's resolved.\",\n email_error: \"Couldn't save your email. Please try again.\",\n },\n error: {\n submit: 'Failed to submit. Please try again.',\n },\n pet: {\n bubble: 'Need help?',\n },\n frustration: {\n prompt: 'Something not working? Tell us.',\n action: 'Annotate',\n dismiss: 'Dismiss',\n },\n annotation: {\n drawing: 'Drawing',\n element: 'element',\n },\n draw: {\n note_placeholder: 'Add a note to your drawing',\n undo: 'Undo',\n redo: 'Redo',\n cancel: 'Cancel',\n submit: 'Submit',\n },\n record: {\n stop: 'Stop',\n timer_label: 'Recording',\n max_reached: 'Maximum recording time reached',\n replay_label: 'screen-recording.json',\n play: 'Play recording',\n close: 'Close',\n preview_unavailable: 'Preview unavailable',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Sharpening your feedback',\n thinking: 'Thinking...',\n placeholder: 'Type your answer — or skip the question',\n send: 'Send',\n send_feedback: 'Send feedback',\n skip: 'Skip & send',\n retry: 'Retry',\n error: 'AI clarification failed. Please try again.',\n expired: 'This feedback session expired before it could be sent. Please close the widget and submit again.',\n },\n}\n","export default {\n tab: '反馈',\n toolbar: {\n markup: '标注',\n record: '录屏',\n hint: '点击评论,拖动绘制',\n hintRecord: '正在录制屏幕',\n exit: '退出',\n },\n popup: {\n about: '关于',\n placeholder: '描述问题或建议...',\n submit: '提交',\n cancel: '取消',\n my_feedback: '我的反馈',\n quickOptions: [\n { emoji: '🐛', label: '出问题了' },\n { emoji: '💡', label: '我有一个建议' },\n { emoji: '🤔', label: '我有点困惑' },\n ],\n },\n success: {\n title: '已发送,感谢!',\n message: '您的反馈和采集到的技术上下文正在发送给团队。问题解决后,您会收到通知。',\n title_no_ai: '感谢!我们已收到您的反馈。',\n message_no_ai: '接下来由团队处理。问题解决后,您会收到通知。',\n view_feedback: '查看我的反馈',\n close: '关闭',\n email_prompt: '想了解进展?留下邮箱,问题解决后我们会通知您。',\n email_placeholder: 'you@example.com',\n email_submit: '通知我',\n email_saved: '问题解决后您会收到邮件通知。',\n email_error: '邮箱保存失败,请重试。',\n },\n error: {\n submit: '提交失败,请重试。',\n },\n pet: {\n bubble: '需要帮助吗?',\n },\n frustration: {\n prompt: '遇到问题了?告诉我们。',\n action: '标注',\n dismiss: '关闭',\n },\n annotation: {\n drawing: '绘制',\n element: '元素',\n },\n draw: {\n note_placeholder: '给你的绘制添加说明',\n undo: '撤销',\n redo: '重做',\n cancel: '取消',\n submit: '提交',\n },\n record: {\n stop: '停止',\n timer_label: '录制中',\n max_reached: '已达到最长录制时间',\n replay_label: 'screen-recording.json',\n play: '播放录屏',\n close: '关闭',\n preview_unavailable: '暂无法预览',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: '正在完善你的反馈',\n thinking: '思考中...',\n placeholder: '输入回答,或跳过问题',\n send: '发送',\n send_feedback: '发送反馈',\n skip: '跳过并发送',\n retry: '重试',\n error: 'AI 澄清失败,请重试。',\n expired: '这条反馈在发送前已过期。请关闭组件后重新提交。',\n },\n}\n","export default {\n tab: 'フィードバック',\n toolbar: {\n markup: 'マークアップ',\n record: '録画',\n hint: 'クリックでコメント、ドラッグで描画',\n hintRecord: '画面を録画中',\n exit: '終了',\n },\n popup: {\n about: '概要',\n placeholder: '問題や提案を入力してください...',\n submit: '送信',\n cancel: 'キャンセル',\n my_feedback: '自分のフィードバック',\n quickOptions: [\n { emoji: '🐛', label: '不具合があります' },\n { emoji: '💡', label: '提案があります' },\n { emoji: '🤔', label: 'わかりにくいです' },\n ],\n },\n success: {\n title: '送信しました。ありがとうございます!',\n message: 'ご意見と取得した技術情報をチームに送信しました。解決次第お知らせします。',\n title_no_ai: 'ありがとうございます!フィードバックを受け付けました。',\n message_no_ai: 'チームが対応します。解決次第お知らせします。',\n view_feedback: 'フィードバックを確認',\n close: '閉じる',\n email_prompt: '進捗を知りたい場合は、メールアドレスをご記入ください。解決次第お知らせします。',\n email_placeholder: 'you@example.com',\n email_submit: '通知を受け取る',\n email_saved: '解決次第メールでお知らせします。',\n email_error: 'メールアドレスを保存できませんでした。もう一度お試しください。',\n },\n error: {\n submit: '送信に失敗しました。もう一度お試しください。',\n },\n pet: {\n bubble: 'お困りですか?',\n },\n frustration: {\n prompt: 'うまくいかないことがありますか?お知らせください。',\n action: '注釈',\n dismiss: '閉じる',\n },\n annotation: {\n drawing: '描画',\n element: '要素',\n },\n draw: {\n note_placeholder: '描画にメモを追加',\n undo: '元に戻す',\n redo: 'やり直す',\n cancel: 'キャンセル',\n submit: '送信',\n },\n record: {\n stop: '停止',\n timer_label: '録画中',\n max_reached: '最大記録時間に達しました',\n replay_label: 'screen-recording.json',\n play: '録画を再生',\n close: '閉じる',\n preview_unavailable: 'プレビューは利用できません',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'フィードバックを整えています',\n thinking: '考え中...',\n placeholder: '回答を入力、または質問をスキップ',\n send: '送信',\n send_feedback: 'フィードバックを送信',\n skip: 'スキップして送信',\n retry: '再試行',\n error: 'AIによる確認に失敗しました。もう一度お試しください。',\n expired: 'このフィードバックは送信される前に有効期限が切れました。ウィジェットを閉じて、もう一度送信してください。',\n },\n}\n","export default {\n tab: '피드백',\n toolbar: {\n markup: '마크업',\n record: '녹화',\n hint: '클릭하여 댓글, 드래그하여 그리기',\n hintRecord: '화면 녹화 중',\n exit: '나가기',\n },\n popup: {\n about: '정보',\n placeholder: '문제 또는 제안 사항을 설명해 주세요...',\n submit: '제출',\n cancel: '취소',\n my_feedback: '내 피드백',\n quickOptions: [\n { emoji: '🐛', label: '문제가 있어요' },\n { emoji: '💡', label: '제안이 있어요' },\n { emoji: '🤔', label: '헷갈려요' },\n ],\n },\n success: {\n title: '전송되었습니다. 감사합니다!',\n message: '피드백과 수집된 기술 정보가 팀에 전달되었습니다. 해결되면 알려드리겠습니다.',\n title_no_ai: '감사합니다! 피드백을 접수했습니다.',\n message_no_ai: '팀에서 처리합니다. 해결되면 알려드리겠습니다.',\n view_feedback: '내 피드백 보기',\n close: '닫기',\n email_prompt: '진행 상황이 궁금하신가요? 이메일을 남겨주시면 해결 시 알려드립니다.',\n email_placeholder: 'you@example.com',\n email_submit: '알림 받기',\n email_saved: '해결되면 이메일로 알려드립니다.',\n email_error: '이메일을 저장하지 못했습니다. 다시 시도해 주세요.',\n },\n error: {\n submit: '제출에 실패했습니다. 다시 시도해 주세요.',\n },\n pet: {\n bubble: '도움이 필요하신가요?',\n },\n frustration: {\n prompt: '문제가 있으신가요? 알려 주세요.',\n action: '주석',\n dismiss: '닫기',\n },\n annotation: {\n drawing: '그리기',\n element: '요소',\n },\n draw: {\n note_placeholder: '그림에 메모 추가',\n undo: '실행 취소',\n redo: '다시 실행',\n cancel: '취소',\n submit: '보내기',\n },\n record: {\n stop: '중지',\n timer_label: '녹화 중',\n max_reached: '최대 녹화 시간에 도달했습니다',\n replay_label: 'screen-recording.json',\n play: '녹화 재생',\n close: '닫기',\n preview_unavailable: '미리보기를 사용할 수 없습니다',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: '피드백을 다듬는 중',\n thinking: '생각 중...',\n placeholder: '답변을 입력하거나 질문을 건너뛰세요',\n send: '보내기',\n send_feedback: '피드백 보내기',\n skip: '건너뛰고 보내기',\n retry: '재시도',\n error: 'AI 확인에 실패했습니다. 다시 시도해 주세요.',\n expired: '이 피드백 세션은 전송되기 전에 만료되었습니다. 위젯을 닫고 다시 보내 주세요.',\n },\n}\n","export default {\n tab: 'Comentarios',\n toolbar: {\n markup: 'Anotar',\n record: 'Grabar',\n hint: 'Clic para comentar, arrastrar para dibujar',\n hintRecord: 'Grabando pantalla',\n exit: 'Salir',\n },\n popup: {\n about: 'Acerca de',\n placeholder: 'Describe el problema o sugerencia...',\n submit: 'Enviar',\n cancel: 'Cancelar',\n my_feedback: 'Mis comentarios',\n quickOptions: [\n { emoji: '🐛', label: 'Algo no funciona' },\n { emoji: '💡', label: 'Tengo una sugerencia' },\n { emoji: '🤔', label: 'Estoy confundido' },\n ],\n },\n success: {\n title: 'Enviado, ¡gracias!',\n message: 'Tu nota y el contexto técnico capturado se han enviado al equipo. Te avisaremos cuando se resuelva.',\n title_no_ai: '¡Gracias! Hemos recibido tu comentario.',\n message_no_ai: 'El equipo se encargará a partir de aquí. Te avisaremos cuando se resuelva.',\n view_feedback: 'Ver mis comentarios',\n close: 'Cerrar',\n email_prompt: '¿Quieres novedades? Deja tu correo y te avisaremos cuando se resuelva.',\n email_placeholder: 'tu@ejemplo.com',\n email_submit: 'Avisarme',\n email_saved: 'Recibirás un correo cuando se resuelva.',\n email_error: 'No se pudo guardar tu correo. Inténtalo de nuevo.',\n },\n error: {\n submit: 'Error al enviar. Por favor, inténtalo de nuevo.',\n },\n pet: {\n bubble: '¿Necesitas ayuda?',\n },\n frustration: {\n prompt: '¿Algo no funciona? Cuéntanos.',\n action: 'Anotar',\n dismiss: 'Cerrar',\n },\n annotation: {\n drawing: 'Dibujo',\n element: 'elemento',\n },\n draw: {\n note_placeholder: 'Añade una nota a tu dibujo',\n undo: 'Deshacer',\n redo: 'Rehacer',\n cancel: 'Cancelar',\n submit: 'Enviar',\n },\n record: {\n stop: 'Detener',\n timer_label: 'Grabando',\n max_reached: 'Tiempo máximo de grabación alcanzado',\n replay_label: 'screen-recording.json',\n play: 'Reproducir grabación',\n close: 'Cerrar',\n preview_unavailable: 'Vista previa no disponible',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Afinando tus comentarios',\n thinking: 'Pensando...',\n placeholder: 'Escribe tu respuesta — u omite la pregunta',\n send: 'Enviar',\n send_feedback: 'Enviar comentario',\n skip: 'Omitir y enviar',\n retry: 'Reintentar',\n error: 'No se pudo completar la aclaración con IA. Inténtalo de nuevo.',\n expired: 'Esta sesión de comentarios caducó antes de poder enviarse. Cierra el widget y envíalo de nuevo.',\n },\n}\n","export default {\n tab: 'Avis',\n toolbar: {\n markup: 'Annoter',\n record: 'Enregistrer',\n hint: 'Cliquer pour commenter, glisser pour dessiner',\n hintRecord: \"Enregistrement de l'écran\",\n exit: 'Quitter',\n },\n popup: {\n about: 'À propos',\n placeholder: 'Décrivez le problème ou votre suggestion...',\n submit: 'Envoyer',\n cancel: 'Annuler',\n my_feedback: 'Mes avis',\n quickOptions: [\n { emoji: '🐛', label: 'Quelque chose ne fonctionne pas' },\n { emoji: '💡', label: \"J'ai une suggestion\" },\n { emoji: '🤔', label: 'Je suis perplexe' },\n ],\n },\n success: {\n title: 'Envoyé, merci !',\n message: 'Votre message et le contexte technique collecté ont été transmis à l’équipe. Vous serez informé(e) dès que ce sera résolu.',\n title_no_ai: 'Merci ! Nous avons bien reçu votre avis.',\n message_no_ai: \"L’équipe prend le relais. Vous serez informé(e) dès que ce sera résolu.\",\n view_feedback: 'Voir mes avis',\n close: 'Fermer',\n email_prompt: \"Envie de suivre l'avancement ? Laissez votre e-mail et nous vous préviendrons une fois résolu.\",\n email_placeholder: 'vous@exemple.com',\n email_submit: 'Me prévenir',\n email_saved: 'Vous recevrez un e-mail une fois résolu.',\n email_error: \"Impossible d'enregistrer votre e-mail. Veuillez réessayer.\",\n },\n error: {\n submit: \"Échec de l'envoi. Veuillez réessayer.\",\n },\n pet: {\n bubble: \"Besoin d'aide ?\",\n },\n frustration: {\n prompt: 'Un problème ? Dites-le-nous.',\n action: 'Annoter',\n dismiss: 'Fermer',\n },\n annotation: {\n drawing: 'Dessin',\n element: 'élément',\n },\n draw: {\n note_placeholder: 'Ajoutez une note à votre dessin',\n undo: 'Annuler',\n redo: 'Rétablir',\n cancel: 'Annuler',\n submit: 'Envoyer',\n },\n record: {\n stop: 'Arrêter',\n timer_label: 'Enregistrement',\n max_reached: \"Durée maximale d'enregistrement atteinte\",\n replay_label: 'screen-recording.json',\n play: \"Lire l'enregistrement\",\n close: 'Fermer',\n preview_unavailable: 'Aperçu indisponible',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Affinement de votre retour',\n thinking: 'Réflexion...',\n placeholder: 'Saisissez votre réponse — ou ignorez la question',\n send: 'Envoyer',\n send_feedback: 'Envoyer le retour',\n skip: 'Ignorer et envoyer',\n retry: 'Réessayer',\n error: 'La clarification par IA a échoué. Réessayez.',\n expired: 'Cette session de retour a expiré avant d\\'avoir pu être envoyée. Fermez le widget et renvoyez-la.',\n },\n}\n","export default {\n tab: 'Feedback',\n toolbar: {\n markup: 'Markieren',\n record: 'Aufnehmen',\n hint: 'Klicken zum Kommentieren, ziehen zum Zeichnen',\n hintRecord: 'Bildschirm wird aufgenommen',\n exit: 'Beenden',\n },\n popup: {\n about: 'Info',\n placeholder: 'Beschreiben Sie das Problem oder Ihren Vorschlag...',\n submit: 'Absenden',\n cancel: 'Abbrechen',\n my_feedback: 'Mein Feedback',\n quickOptions: [\n { emoji: '🐛', label: 'Etwas funktioniert nicht' },\n { emoji: '💡', label: 'Ich habe einen Vorschlag' },\n { emoji: '🤔', label: 'Ich bin verwirrt' },\n ],\n },\n success: {\n title: 'Gesendet, vielen Dank!',\n message: 'Ihre Nachricht und der erfasste technische Kontext wurden an das Team gesendet. Sie werden benachrichtigt, sobald das Problem gelöst ist.',\n title_no_ai: 'Vielen Dank! Wir haben Ihr Feedback erhalten.',\n message_no_ai: 'Das Team übernimmt ab hier. Sie werden benachrichtigt, sobald das Problem gelöst ist.',\n view_feedback: 'Mein Feedback ansehen',\n close: 'Schließen',\n email_prompt: 'Updates gewünscht? Hinterlassen Sie Ihre E-Mail und wir melden uns, sobald es gelöst ist.',\n email_placeholder: 'sie@beispiel.de',\n email_submit: 'Benachrichtigen',\n email_saved: 'Sie erhalten eine E-Mail, sobald es gelöst ist.',\n email_error: 'E-Mail konnte nicht gespeichert werden. Bitte versuchen Sie es erneut.',\n },\n error: {\n submit: 'Senden fehlgeschlagen. Bitte versuchen Sie es erneut.',\n },\n pet: {\n bubble: 'Brauchen Sie Hilfe?',\n },\n frustration: {\n prompt: 'Etwas funktioniert nicht? Sagen Sie es uns.',\n action: 'Kommentieren',\n dismiss: 'Schließen',\n },\n annotation: {\n drawing: 'Zeichnung',\n element: 'Element',\n },\n draw: {\n note_placeholder: 'Fügen Sie Ihrer Zeichnung eine Notiz hinzu',\n undo: 'Rückgängig',\n redo: 'Wiederholen',\n cancel: 'Abbrechen',\n submit: 'Absenden',\n },\n record: {\n stop: 'Stopp',\n timer_label: 'Aufnahme',\n max_reached: 'Maximale Aufnahmedauer erreicht',\n replay_label: 'screen-recording.json',\n play: 'Aufnahme abspielen',\n close: 'Schließen',\n preview_unavailable: 'Vorschau nicht verfügbar',\n },\n clarify: {\n title: 'Make This Better AI',\n subtitle: 'Wir schärfen dein Feedback',\n thinking: 'Einen Moment...',\n placeholder: 'Antwort eingeben — oder Frage überspringen',\n send: 'Senden',\n send_feedback: 'Feedback senden',\n skip: 'Überspringen & senden',\n retry: 'Erneut versuchen',\n error: 'Die KI-Klärung ist fehlgeschlagen. Bitte erneut versuchen.',\n expired: 'Diese Feedback-Sitzung ist abgelaufen, bevor sie gesendet werden konnte. Bitte schließe das Widget und sende erneut.',\n },\n}\n","import en from './en'\nimport zhCN from './zh-CN'\nimport ja from './ja'\nimport ko from './ko'\nimport es from './es'\nimport fr from './fr'\nimport de from './de'\n\nexport type I18nMessages = typeof en\n\nconst locales: Record<string, I18nMessages> = {\n en,\n 'zh-CN': zhCN,\n ja,\n ko,\n es,\n fr,\n de,\n}\n\nexport function getMessages(locale: string): I18nMessages {\n if (locales[locale]) return locales[locale]\n const lang = locale.split('-')[0]\n if (locales[lang]) return locales[lang]\n return locales['en']\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { RecordingOptions } from '../types'\n\ntype RRWebEvent = Record<string, unknown>\ntype StopFn = () => void\n\ninterface RRWebRecordOptions {\n emit: (event: RRWebEvent) => void\n maskAllInputs: boolean\n blockClass: string\n maskTextClass: string\n}\n\ninterface RRWebRecordFn {\n (options: RRWebRecordOptions): StopFn\n addCustomEvent: (tag: string, payload: Record<string, unknown>) => void\n}\n\nexport interface RecordingResult {\n events: RRWebEvent[]\n duration: number\n}\n\nconst MAX_DURATION_S = 60\n// rrweb's own defaults for opting an element out of a replay. Named here so the\n// README can document them and so the values stay in one place.\nexport const BLOCK_CLASS = 'rr-block'\nexport const MASK_TEXT_CLASS = 'rr-mask'\n// Pinned version + SRI: this script executes on customers' pages, so a\n// floating tag or unverified content would be a supply-chain hole. Bumping\n// the version requires recomputing the hash from the exact CDN file:\n// curl -sL <url> | openssl dgst -sha384 -binary | openssl base64 -A\n// Must stay on @rrweb/record's static /umd/ build: the `rrweb` package ships\n// no UMD in 2.x (its dist files are ESM and throw \"Unexpected token 'export'\"\n// in a classic script tag), and jsDelivr's auto-minified files are unsafe for\n// SRI because their hash changes when jsDelivr upgrades its minifier.\nconst RRWEB_CDN = 'https://cdn.jsdelivr.net/npm/@rrweb/record@2.1.0/umd/record.min.js'\nconst RRWEB_SRI = 'sha384-MrD66HBNSykaP2N95+6hQCFlF5oH2tvL3TD/zyvHNkP/sAFWZx98DX9MEDy8MdVT'\n\nlet rrwebLoaded: Promise<RRWebRecordFn> | null = null\n\nfunction loadRrweb(): Promise<RRWebRecordFn> {\n if (rrwebLoaded) return rrwebLoaded\n rrwebLoaded = loadViaImport().catch(() => loadViaCdn())\n return rrwebLoaded\n}\n\nasync function loadViaImport(): Promise<RRWebRecordFn> {\n const mod = await import('@rrweb/record')\n return mod.record as unknown as RRWebRecordFn\n}\n\ninterface RRWebGlobals {\n rrwebRecord?: { record: RRWebRecordFn }\n rrweb?: { record: RRWebRecordFn }\n}\n\nfunction findGlobalRecord(): RRWebRecordFn | undefined {\n const win = globalThis as unknown as Window & RRWebGlobals\n return win.rrwebRecord?.record ?? win.rrweb?.record\n}\n\nfunction loadViaCdn(): Promise<RRWebRecordFn> {\n return new Promise((resolve, reject) => {\n const existing = findGlobalRecord()\n if (existing) { resolve(existing); return }\n const script = document.createElement('script')\n script.src = RRWEB_CDN\n script.integrity = RRWEB_SRI\n script.crossOrigin = 'anonymous'\n script.onload = () => {\n const record = findGlobalRecord()\n if (record) resolve(record)\n else reject(new Error('rrweb record global not found after script load'))\n }\n script.onerror = () => reject(new Error('Failed to load rrweb from CDN'))\n document.head.appendChild(script)\n })\n}\n\nexport class RecordSession {\n private events: RRWebEvent[] = []\n private stopFn: StopFn | null = null\n private startedAt = 0\n private timer: ReturnType<typeof setTimeout> | null = null\n private clickHandler: ((e: MouseEvent) => void) | null = null\n private shadow: ShadowContainer\n private onMaxReached?: () => void\n private options: RecordingOptions\n private stopped = false\n private destroyed = false\n\n constructor(shadow: ShadowContainer, onMaxReached?: () => void, options: RecordingOptions = {}) {\n this.shadow = shadow\n this.onMaxReached = onMaxReached\n this.options = options\n }\n\n async start(): Promise<void> {\n const record = await loadRrweb()\n\n // A cold dynamic import takes hundreds of milliseconds, and the reporter can\n // cancel the replay inside that window. Without this guard the resumed start()\n // would attach a recorder, a document click listener and a 60s timer that no\n // live object holds a handle to — rrweb would then serialize every mutation of\n // the host page for the rest of the session, after an explicit cancel.\n if (this.destroyed) return\n\n this.startedAt = Date.now()\n this.stopped = false\n\n this.stopFn = record({\n emit: (event: RRWebEvent) => {\n if (!this.stopped) this.events.push(event)\n },\n // Default to masking every input value, not just password fields (rrweb's\n // own default). A replay is captured from whatever page the reporter happens\n // to be on, which may be a checkout or a 2FA prompt, and nothing downstream\n // scrubs it. Customers who need real values in replays must opt in.\n maskAllInputs: this.options.maskAllInputs ?? true,\n blockClass: BLOCK_CLASS,\n maskTextClass: MASK_TEXT_CLASS,\n })\n\n this.clickHandler = (e: MouseEvent) => {\n this.showClickRipple(e.clientX, e.clientY)\n record.addCustomEvent?.('mtb-click', {\n x: e.clientX,\n y: e.clientY,\n target: e.target instanceof HTMLElement ? e.target.tagName : '',\n })\n }\n document.addEventListener('click', this.clickHandler, true)\n\n this.timer = setTimeout(() => {\n this.onMaxReached?.()\n }, MAX_DURATION_S * 1000)\n }\n\n stop(): RecordingResult {\n this.stopped = true\n this.stopFn?.()\n this.stopFn = null\n this.cleanupTimer()\n this.cleanupClickHandler()\n\n return {\n events: this.events,\n duration: this.getDuration(),\n }\n }\n\n getDuration(): number {\n if (this.startedAt === 0) return 0\n return Math.max(1, Math.round((Date.now() - this.startedAt) / 1000))\n }\n\n destroy(): void {\n this.destroyed = true\n this.stopped = true\n this.stopFn?.()\n this.stopFn = null\n this.cleanupTimer()\n this.cleanupClickHandler()\n this.events = []\n this.startedAt = 0\n }\n\n private cleanupTimer(): void {\n if (this.timer) {\n clearTimeout(this.timer)\n this.timer = null\n }\n }\n\n private cleanupClickHandler(): void {\n if (this.clickHandler) {\n document.removeEventListener('click', this.clickHandler, true)\n this.clickHandler = null\n }\n }\n\n private showClickRipple(x: number, y: number): void {\n const ripple = this.shadow.el<HTMLDivElement>('div', 'mtb-click-ripple')\n ripple.style.left = `${x}px`\n ripple.style.top = `${y}px`\n this.shadow.append(ripple)\n ripple.addEventListener('animationend', () => ripple.remove())\n }\n}\n","import type { ShadowContainer } from '../widget/shadow'\nimport type { I18nMessages } from '../i18n'\n\nexport class RecordControlBar {\n private el: HTMLDivElement\n private timerEl!: HTMLSpanElement\n private intervalId: ReturnType<typeof setInterval> | null = null\n private getDuration: () => number\n\n constructor(\n shadow: ShadowContainer,\n messages: I18nMessages,\n getDuration: () => number,\n onStop: () => void,\n ) {\n this.getDuration = getDuration\n\n this.el = shadow.el<HTMLDivElement>('div', 'mtb-record-bar')\n this.el.innerHTML = `\n <span class=\"mtb-record-dot\"></span>\n <span class=\"mtb-record-timer\">00:00</span>\n <button class=\"mtb-record-stop\" type=\"button\">${messages.record.stop}</button>\n `\n shadow.append(this.el)\n\n this.timerEl = this.el.querySelector('.mtb-record-timer')!\n this.el.querySelector('.mtb-record-stop')!.addEventListener('click', onStop)\n\n this.intervalId = setInterval(() => this.updateTimer(), 1000)\n }\n\n private updateTimer(): void {\n const secs = this.getDuration()\n const mm = String(Math.floor(secs / 60)).padStart(2, '0')\n const ss = String(secs % 60).padStart(2, '0')\n this.timerEl.textContent = `${mm}:${ss}`\n }\n\n destroy(): void {\n if (this.intervalId) {\n clearInterval(this.intervalId)\n this.intervalId = null\n }\n this.el.remove()\n }\n}\n","import { RecordSession } from '../record/session'\nimport type { RecordingResult } from '../record/session'\nimport { RecordControlBar } from '../record/control-bar'\nimport type { ShadowContainer } from './shadow'\nimport type { I18nMessages } from '../i18n'\nimport type { RecordingOptions } from '../types'\n\nexport type { RecordingResult }\n\nexport class RecordingManager {\n private session: RecordSession | null = null\n private bar: RecordControlBar | null = null\n private result: RecordingResult | null = null\n\n async start(\n shadow: ShadowContainer,\n messages: I18nMessages,\n onStop: () => void,\n options: RecordingOptions = {},\n ): Promise<void> {\n this.session = new RecordSession(shadow, onStop, options)\n this.bar = new RecordControlBar(\n shadow,\n messages,\n () => this.session?.getDuration() ?? 0,\n onStop,\n )\n await this.session.start()\n }\n\n stop(): RecordingResult | null {\n if (!this.session) return null\n this.result = this.session.stop()\n this.teardownUI()\n return this.result\n }\n\n getRecording(): RecordingResult | null {\n return this.result\n }\n\n destroy(): void {\n this.teardownUI()\n this.result = null\n }\n\n private teardownUI(): void {\n this.session?.destroy()\n this.session = null\n this.bar?.destroy()\n this.bar = null\n }\n}\n","import { ShadowContainer } from './shadow'\nimport { FeedbackTab } from './tab'\nimport { FrustrationPromptCard } from './frustration-prompt'\nimport { DimOverlay } from './dim-overlay'\nimport { ScrollLock } from './scroll-lock'\nimport { AnnotationToolbar } from '../annotate/toolbar'\nimport type { ToolbarMode } from '../annotate/toolbar'\nimport { AnnotationSession } from '../annotate/session'\nimport { DrawNoteBar } from '../annotate/draw-note-bar'\nimport { CommentPopup } from '../popup/comment'\nimport { ClarifyCard } from '../popup/clarify'\nimport { SuccessCard } from '../popup/success'\nimport type { SuccessCardOptions } from '../popup/success'\nimport { captureScreenshot } from '../screenshot/capture'\nimport { ConsoleErrorCollector } from '../context/console'\nimport { BreadcrumbCollector } from '../context/breadcrumbs'\nimport { FrustrationDetector } from '../context/frustration'\nimport { isFrustrationDismissed, markFrustrationDismissed } from '../context/frustration-state'\nimport { collectPageContext } from '../context/collector'\nimport type { PageContext } from '../context/collector'\nimport { ApiClient } from '../api/client'\nimport type { ClarifyStreamResult } from '../api/client'\nimport { buildPayload } from './payload'\nimport { cacheBoardUrl, getAnonId, getCachedBoardUrl, getStoredReporterEmail, rememberReporterEmail } from './anon-id'\nimport { getMessages } from '../i18n'\nimport { RecordingManager } from './recording-manager'\nimport type { MakeThisBetterConfig, Annotation, SubmissionSessionResponse, TargetRect } from '../types'\n\nconst SPECULATIVE_CLARIFY_TIMEOUT_MS = 3000\n// How long a clarification stream may stay silent before it becomes retryable.\n// Measured between tokens, not from the start, so a long answer is not cut off.\nconst CLARIFY_SILENCE_TIMEOUT_MS = 12000\n\ntype Mode = 'idle' | 'annotating' | 'recording' | 'drawing' | 'popup' | 'clarifying'\ntype Via = 'pin' | 'draw' | 'record'\n\ninterface SubmittingUi {\n setLoading: (loading: boolean) => void\n setError: (message: string) => void\n}\n\n// A browser SDK has no build-time environment, so \"is a developer watching?\"\n// has to be inferred. Loopback and the .local/.test dev TLDs are where an\n// integrator runs; anything else is somebody's live site.\nfunction isLocalHost(): boolean {\n const { hostname } = window.location\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '[::1]' ||\n hostname.endsWith('.localhost') ||\n hostname.endsWith('.local') ||\n hostname.endsWith('.test')\n )\n}\n\nexport class WidgetController {\n private config: MakeThisBetterConfig\n private shadow!: ShadowContainer\n private tab: FeedbackTab | null = null\n private toolbar: AnnotationToolbar | null = null\n private session: AnnotationSession | null = null\n private scrollLock = new ScrollLock()\n private drawBar: DrawNoteBar | null = null\n private dim: DimOverlay | null = null\n private popup: CommentPopup | null = null\n private clarify: ClarifyCard | null = null\n private success: SuccessCard | null = null\n private frustrationPrompt: FrustrationPromptCard | null = null\n private apiClient: ApiClient\n private consoleCollector: ConsoleErrorCollector\n private breadcrumbCollector: BreadcrumbCollector\n private frustrationDetector: FrustrationDetector | null = null\n private messages: ReturnType<typeof getMessages>\n private mode: Mode = 'idle'\n private via: Via = 'pin'\n private currentAnnotation: Annotation | null = null\n private submittingUi: SubmittingUi | null = null\n private lastPopupPos: { x: number; y: number } | null = null\n private recordingManager: RecordingManager | null = null\n private activeSubmission: SubmissionSessionResponse | null = null\n private submissionAttempt = 0\n private lastHandoff: { feedbackId?: string; boardUrl?: string; identityToken?: string } = {}\n\n constructor(config: MakeThisBetterConfig) {\n this.config = config\n this.messages = getMessages(config.locale ?? document.documentElement.lang ?? 'en')\n this.apiClient = new ApiClient(config.projectKey, config.apiUrl, undefined, config.userToken, config.userTokenFn)\n this.consoleCollector = new ConsoleErrorCollector()\n this.consoleCollector.start()\n this.breadcrumbCollector = new BreadcrumbCollector()\n this.breadcrumbCollector.start()\n this.buildUI()\n\n if (config.frustrationDetection !== false) {\n this.frustrationDetector = new FrustrationDetector(() => this.handleFrustration())\n this.frustrationDetector.start()\n }\n\n document.addEventListener('keydown', this.handleKeydown, true)\n }\n\n // Escape only acts while the widget is in an active state; idle/clarifying\n // fall through untouched so the host page's own Escape handling still works.\n private handleKeydown = (event: KeyboardEvent): void => {\n if (event.key !== 'Escape') return\n\n switch (this.mode) {\n case 'annotating':\n case 'popup':\n event.preventDefault()\n event.stopPropagation()\n this.exitAll()\n break\n case 'drawing':\n event.preventDefault()\n event.stopPropagation()\n this.cancelDraw()\n break\n case 'recording':\n event.preventDefault()\n event.stopPropagation()\n this.handleRecordStop()\n break\n default:\n break\n }\n }\n\n private buildUI(): void {\n this.shadow = new ShadowContainer(this.config.theme ?? 'auto')\n\n if (this.config.entryMode === 'api') {\n // Nothing is reachable until the host wires up open(), and silence would\n // look identical to a broken install. But 'api' is a supported setting,\n // so a warning on every production page load would be a third-party SDK\n // shouting at customers who did nothing wrong — say it only where an\n // integrator is watching.\n if (isLocalHost()) {\n console.warn(\n '[MakeThisBetter] entryMode: \"api\" renders no launcher. ' +\n 'Call MakeThisBetter.open() from your own UI, or use showLauncher().',\n )\n }\n return\n }\n\n this.mountTab()\n }\n\n private mountTab(): void {\n if (this.tab) return\n this.tab = new FeedbackTab(\n this.shadow,\n this.messages,\n this.config.position ?? 'right',\n () => this.handleTabClick(),\n this.config.tabText,\n )\n }\n\n /** Opens annotation mode. Idempotent: a second call while open does nothing. */\n open(): void {\n if (this.mode !== 'idle') return\n this.dismissFrustrationPrompt()\n this.enterAnnotationMode()\n }\n\n close(): void {\n if (this.mode === 'idle') return\n this.exitAll()\n }\n\n showLauncher(): void {\n this.mountTab()\n this.tab?.setActive(this.mode !== 'idle')\n }\n\n hideLauncher(): void {\n this.tab?.destroy()\n this.tab = null\n }\n\n // Takes effect for anything opened afterwards. Components already on screen keep\n // the language they were opened in rather than being re-rendered underneath a\n // reporter who may be mid-sentence.\n setLocale(locale: string): void {\n this.config.locale = locale\n this.messages = getMessages(locale)\n this.tab?.setMessages(this.messages)\n }\n\n private handleTabClick(): void {\n if (this.mode === 'idle') {\n this.dismissFrustrationPrompt()\n this.enterAnnotationMode()\n } else {\n this.exitAll()\n }\n }\n\n private handleFrustration(): void {\n if (this.mode !== 'idle' || this.frustrationPrompt || isFrustrationDismissed()) return\n\n this.frustrationPrompt = new FrustrationPromptCard(this.shadow, this.messages, {\n onTell: () => {\n this.dismissFrustrationPrompt()\n this.enterAnnotationMode()\n },\n onDismiss: () => {\n markFrustrationDismissed()\n this.dismissFrustrationPrompt()\n },\n // An unnoticed card is not a refusal, so it must not suppress later\n // prompts. The detector's own 60s cooldown does the rate limiting.\n onAutoHide: () => this.dismissFrustrationPrompt(),\n })\n }\n\n private dismissFrustrationPrompt(): void {\n this.frustrationPrompt?.destroy()\n this.frustrationPrompt = null\n }\n\n private enterAnnotationMode(): void {\n this.mode = 'annotating'\n this.tab?.setActive(true)\n this.scrollLock.lock()\n\n this.toolbar = new AnnotationToolbar(\n this.shadow,\n this.messages,\n () => this.exitAll(),\n (mode: ToolbarMode) => this.handleToolbarModeChange(mode),\n // The bar stands at whichever edge the tab does. Leaving it pinned right\n // while a left-configured tab sat opposite would split the widget across\n // both sides of the page.\n this.config.position ?? 'right',\n )\n this.session = this.createSession()\n }\n\n private createSession(): AnnotationSession {\n return new AnnotationSession(this.shadow, this.messages, {\n onPin: (annotation, targetName) => {\n this.currentAnnotation = annotation\n this.via = 'pin'\n this.showPopup(annotation.x, annotation.y, targetName, annotation.targetRect)\n },\n onDrawStroke: () => this.handleDrawStroke(),\n })\n }\n\n private handleToolbarModeChange(mode: ToolbarMode): void {\n if (this.mode === 'clarifying') {\n this.toolbar?.setMode(this.via === 'record' ? 'record' : 'markup')\n return\n }\n\n if (mode === 'record') {\n if (this.mode === 'recording') return\n\n this.mode = 'recording'\n this.currentAnnotation = null\n this.teardownDraw()\n this.session?.destroy()\n this.session = null\n // Recording exists to capture the user reproducing something, which\n // usually means scrolling. The annotation freeze must not carry over.\n this.scrollLock.unlock()\n this.recordingManager = new RecordingManager()\n this.recordingManager.start(\n this.shadow,\n this.messages,\n this.handleRecordStop,\n this.config.recording ?? {},\n ).catch((error) => {\n // rrweb failed to load (network / SRI mismatch) — fall back to markup\n console.warn('[MakeThisBetter] Interaction replay unavailable, falling back to markup:', error)\n if (this.mode !== 'recording') return\n this.toolbar?.setMode('markup')\n this.handleToolbarModeChange('markup')\n })\n } else {\n this.recordingManager?.destroy()\n this.recordingManager = null\n this.teardownDraw()\n if (!this.session) this.session = this.createSession()\n this.scrollLock.lock()\n this.mode = 'annotating'\n }\n }\n\n private handleRecordStop = (): void => {\n if (!this.recordingManager) return\n this.recordingManager.stop()\n this.via = 'record'\n this.showPopup(window.innerWidth / 2, window.innerHeight / 2, this.messages.record.timer_label)\n }\n\n private handleDrawStroke(): void {\n if (this.mode !== 'drawing') {\n this.mode = 'drawing'\n this.drawBar = new DrawNoteBar(this.shadow, {\n messages: this.messages,\n onUndo: () => this.handleDrawUndoRedo('undo'),\n onRedo: () => this.handleDrawUndoRedo('redo'),\n onCancel: () => this.cancelDraw(),\n onSubmit: (note) => this.handleDrawSubmit(note),\n })\n }\n this.refreshDrawBar()\n }\n\n private handleDrawUndoRedo(action: 'undo' | 'redo'): void {\n if (action === 'undo') this.session?.undoDraw()\n else this.session?.redoDraw()\n this.refreshDrawBar()\n }\n\n private refreshDrawBar(): void {\n if (!this.session) return\n this.drawBar?.setUndoRedo(this.session.canUndoDraw(), this.session.canRedoDraw())\n }\n\n private cancelDraw(): void {\n this.session?.clearDraw()\n this.teardownDraw()\n this.mode = 'annotating'\n }\n\n private teardownDraw(): void {\n this.drawBar?.destroy()\n this.drawBar = null\n }\n\n private handleDrawSubmit(note: string): void {\n const annotation = this.session?.getDrawAnnotation()\n if (!annotation) {\n this.cancelDraw()\n return\n }\n this.currentAnnotation = annotation\n this.via = 'draw'\n this.session?.dismissInteraction()\n this.submittingUi = this.drawBar\n void this.handleSubmit(note || this.messages.annotation.drawing)\n }\n\n private showPopup(x: number, y: number, targetName: string, targetRect?: TargetRect): void {\n this.mode = 'popup'\n this.lastPopupPos = { x, y }\n this.teardownDraw()\n this.session?.dismissInteraction()\n this.popup?.destroy()\n this.popup = null\n this.dim?.destroy()\n this.dim = null\n this.dim = new DimOverlay(this.shadow, () => this.exitAll())\n\n this.popup = new CommentPopup(this.shadow, {\n targetName,\n x,\n y,\n targetRect,\n messages: this.messages,\n onSubmit: (description) => this.handleSubmit(description),\n onClose: () => this.exitAll(),\n onMyFeedback: this.buildMyFeedbackHandler(),\n position: this.config.position ?? 'right',\n })\n this.submittingUi = this.popup\n }\n\n private buildMyFeedbackHandler(): (() => void) | undefined {\n if (this.config.user) return undefined\n if (!getCachedBoardUrl()) return undefined\n\n return async () => {\n const exchange = await this.apiClient.createIdentityToken(getAnonId())\n if (!exchange?.identity_token || !exchange.board_url) return\n cacheBoardUrl(exchange.board_url)\n window.open(`${exchange.board_url}?identity=${encodeURIComponent(exchange.identity_token)}`, '_blank')\n }\n }\n\n private async handleSubmit(description: string): Promise<void> {\n const ui = this.submittingUi\n if (!ui) return\n const submissionAttempt = ++this.submissionAttempt\n ui.setLoading(true)\n await waitForPaint()\n const annotation = this.currentAnnotation\n const recording = this.recordingManager?.getRecording() ?? undefined\n\n const [screenshot, pageContext] = await Promise.all([\n captureScreenshot(annotation ? [annotation] : []),\n Promise.resolve(collectPageContext()),\n ])\n\n const payload = buildPayload(\n description,\n pageContext,\n this.consoleCollector.getErrors(),\n annotation,\n this.config.user,\n recording,\n this.config.user ? undefined : getAnonId(),\n this.config.user ? undefined : getStoredReporterEmail(),\n this.breadcrumbCollector.getBreadcrumbs(),\n )\n\n try {\n const submission = await this.apiClient.createSubmissionSession(payload, screenshot)\n if (submissionAttempt !== this.submissionAttempt) {\n await this.apiClient.abandonSubmissionSession(submission.id, submission.token).catch(() => {})\n return\n }\n this.activeSubmission = submission\n await this.speculativeClarify(submission, this.lastPopupPos, submissionAttempt)\n } catch {\n if (submissionAttempt !== this.submissionAttempt) return\n ui.setLoading(false)\n ui.setError(this.messages.error.submit)\n }\n }\n\n private async speculativeClarify(\n submission: SubmissionSessionResponse,\n pos: { x: number; y: number } | null,\n submissionAttempt: number,\n ): Promise<void> {\n if (!submission.ai_clarify_available) {\n const element = this.teardownSubmittingUi(true)\n this.showClarify(submission, pos, {\n element,\n preloadedResult: { messages: [], done: true },\n })\n return\n }\n\n // A stream the server accepts but never terminates would leave the card showing\n // its thinking state forever, with no retry and no way to skip. The deadline\n // measures silence rather than total time: a stream still delivering tokens is\n // making progress and is left alone, however long the answer turns out to be.\n const controller = new AbortController()\n let silenceTimer = setTimeout(() => controller.abort(), CLARIFY_SILENCE_TIMEOUT_MS)\n const resetSilenceTimer = () => {\n clearTimeout(silenceTimer)\n silenceTimer = setTimeout(() => controller.abort(), CLARIFY_SILENCE_TIMEOUT_MS)\n }\n const clarifyPromise = this.apiClient.streamClarification(\n submission.id,\n submission.token,\n resetSilenceTimer,\n controller.signal,\n ).catch(() => null).finally(() => clearTimeout(silenceTimer))\n\n const timeoutPromise = new Promise<null>(resolve =>\n setTimeout(() => resolve(null), SPECULATIVE_CLARIFY_TIMEOUT_MS),\n )\n\n const result = await Promise.race([clarifyPromise, timeoutPromise])\n\n if (submissionAttempt !== this.submissionAttempt) return\n\n const element = this.teardownSubmittingUi(true)\n\n if (result) {\n this.showClarify(submission, pos, { element, preloadedResult: result })\n } else {\n this.showClarify(submission, pos, { element, pendingClarification: clarifyPromise })\n }\n }\n\n private teardownSubmittingUi(preservePopup = false): HTMLDivElement | undefined {\n const popupElement = preservePopup ? this.popup?.releaseElement() : undefined\n // The freeze exists to hold the target still under a pin. This is where the\n // session — and with it the pin — goes away, so it is also where the host\n // page gets its scrolling back. Submitting never reaches exitAll, so\n // relying on that alone would strand every reporter who actually sends\n // something on an unscrollable page.\n this.scrollLock.unlock()\n this.teardownDraw()\n if (!popupElement) this.popup?.destroy()\n this.popup = null\n this.dim?.destroy()\n this.dim = null\n this.session?.hideHighlight()\n this.session?.destroy()\n this.session = null\n this.recordingManager?.destroy()\n this.recordingManager = null\n this.submittingUi = null\n return popupElement\n }\n\n private showClarify(\n submission: SubmissionSessionResponse,\n pos: { x: number; y: number } | null,\n speculative?: {\n element?: HTMLDivElement\n preloadedResult?: ClarifyStreamResult\n pendingClarification?: Promise<ClarifyStreamResult | null>\n },\n ): void {\n this.mode = 'clarifying'\n this.tab?.setActive(true)\n this.clarify = new ClarifyCard(this.shadow, {\n submissionSessionId: submission.id,\n submissionToken: submission.token,\n apiClient: this.apiClient,\n messages: this.messages,\n element: speculative?.element,\n position: this.config.position ?? 'right',\n x: pos?.x,\n y: pos?.y,\n onFinalize: () => this.finalizeSubmission(),\n preloadedResult: speculative?.preloadedResult,\n pendingClarification: speculative?.pendingClarification,\n })\n }\n\n private async finalizeSubmission(): Promise<void> {\n const submission = this.activeSubmission\n if (!submission) throw new Error('No active submission session')\n const submissionAttempt = this.submissionAttempt\n\n const feedback = await this.apiClient.finalizeSubmissionSession(submission.id, submission.token)\n if (submissionAttempt !== this.submissionAttempt || this.activeSubmission !== submission) return\n\n this.activeSubmission = null\n this.lastHandoff = {\n feedbackId: feedback.id,\n boardUrl: feedback.board_url,\n identityToken: feedback.identity_token,\n }\n if (feedback.board_url) cacheBoardUrl(feedback.board_url)\n this.clarify?.destroy()\n this.clarify = null\n this.toolbar?.destroy()\n this.toolbar = null\n this.showSuccess({ skipFollowup: submission.ai_clarify_available === false })\n }\n\n private showSuccess(options?: SuccessCardOptions): void {\n this.mode = 'idle'\n this.tab?.setActive(false)\n this.success = new SuccessCard(this.shadow, this.messages, () => {\n this.success?.destroy()\n this.success = null\n }, this.buildViewFeedbackHandler(), { ...options, emailCapture: this.buildEmailCapture() })\n }\n\n private buildEmailCapture(): { onSubmit: (email: string) => Promise<boolean> } | undefined {\n if (this.config.user) return undefined\n const { feedbackId, identityToken } = this.lastHandoff\n if (!feedbackId || !identityToken) return undefined\n if (getStoredReporterEmail()) return undefined\n\n return {\n onSubmit: async (email: string) => {\n const saved = await this.apiClient.updateReporter(feedbackId, email, identityToken)\n if (saved) rememberReporterEmail(email)\n return saved\n },\n }\n }\n\n private buildViewFeedbackHandler(): (() => void) | undefined {\n const { boardUrl, identityToken } = this.lastHandoff\n if (!boardUrl) return undefined\n\n if (identityToken) {\n return () => {\n window.open(`${boardUrl}?identity=${encodeURIComponent(identityToken)}`, '_blank')\n }\n }\n\n if (this.config.userToken || this.config.userTokenFn) {\n return async () => {\n const token = await this.apiClient.resolveUserToken()\n if (token) window.open(`${boardUrl}?identity=${encodeURIComponent(token)}`, '_blank')\n }\n }\n\n return undefined\n }\n\n private exitAll(): void {\n this.submissionAttempt += 1\n const submission = this.activeSubmission\n this.activeSubmission = null\n if (submission) {\n void this.apiClient.abandonSubmissionSession(submission.id, submission.token).catch(() => {})\n }\n this.mode = 'idle'\n this.via = 'pin'\n this.tab?.setActive(false)\n // Before anything else that can throw: leaving the host page unscrollable\n // is the one failure here the user cannot recover from without a reload.\n this.scrollLock.unlock()\n this.teardownDraw()\n this.toolbar?.destroy()\n this.toolbar = null\n this.session?.hideHighlight()\n this.session?.destroy()\n this.session = null\n this.dim?.destroy()\n this.dim = null\n this.popup?.destroy()\n this.popup = null\n this.clarify?.destroy()\n this.clarify = null\n this.currentAnnotation = null\n this.submittingUi = null\n this.recordingManager?.destroy()\n this.recordingManager = null\n }\n\n destroy(): void {\n document.removeEventListener('keydown', this.handleKeydown, true)\n this.exitAll()\n this.consoleCollector.stop()\n this.breadcrumbCollector.stop()\n this.frustrationDetector?.stop()\n this.dismissFrustrationPrompt()\n this.clarify?.destroy()\n this.success?.destroy()\n this.tab?.destroy()\n this.recordingManager?.destroy()\n this.shadow.destroy()\n }\n}\n\nfunction waitForPaint(): Promise<void> {\n return new Promise<void>((r) => requestAnimationFrame(() => setTimeout(r, 0)))\n}\n","import { WidgetController } from './widget/controller'\nimport type { MakeThisBetterConfig } from './types'\n\nlet instance: WidgetController | null = null\nlet lastConfig: MakeThisBetterConfig | null = null\n\nconst MakeThisBetter = {\n init(config: MakeThisBetterConfig): void {\n if (instance) {\n instance.destroy()\n instance = null\n }\n lastConfig = config\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => {\n instance = new WidgetController(config)\n })\n } else {\n instance = new WidgetController(config)\n }\n },\n\n destroy(): void {\n instance?.destroy()\n instance = null\n lastConfig = null\n },\n\n setLocale(locale: string): void {\n if (lastConfig) lastConfig.locale = locale\n instance?.setLocale(locale)\n },\n\n /**\n * Opens annotation mode from the host's own UI. Pair with\n * `entryMode: 'api'` to replace the docked tab entirely, which is the only\n * good answer on a phone where a permanent floating control is in the way.\n */\n open(): void {\n instance?.open()\n },\n\n close(): void {\n instance?.close()\n },\n\n showLauncher(): void {\n instance?.showLauncher()\n },\n\n hideLauncher(): void {\n instance?.hideLauncher()\n },\n}\n\nexport { MakeThisBetter }\nexport type { MakeThisBetterConfig }\n\nif (typeof window !== 'undefined') {\n (window as Window & { MakeThisBetter?: typeof MakeThisBetter }).MakeThisBetter = MakeThisBetter\n\n document.addEventListener('turbo:load', () => {\n const host = document.getElementById('mtb-widget-host')\n if (lastConfig && (!host || !host.shadowRoot)) {\n instance?.destroy()\n host?.remove()\n instance = new WidgetController(lastConfig)\n }\n })\n}\n"],"names":["ShadowContainer","theme","style","cssText","tag","className","el","nodes","n","FeedbackTab","shadow","messages","position","onClick","customText","label","active","FRUSTRATION_DISMISS_MS","FrustrationPromptCard","handlers","DimOverlay","ScrollLock","AnnotationToolbar","onExit","onModeChange","e","rect","inside","m","mode","AnnotationOverlay","pe","pointerId","ElementHighlighter","getElementName","below","UNRENDERED","renderedText","limit","out","node","title","text","placeholder","alt","dataMark","getCssSelector","parts","current","selector","classNames","c","parent","siblings","idx","PinMarker","x","y","pin","BRAND_COLOR","BRAND_RGB","brandAlpha","alpha","FONT_STACK","DRAW_STROKE","DrawLayer","buildPathD","stroke","entry","path","points","s","cx","cy","center","fx","fy","d","i","xs","p","ys","DRAW_MIN_POINTS","AnnotationSession","underEl","getElementUnder","targetName","annotation","WIDGET_HOST_ID","isWidgetElement","host","escapeHtml","KeyboardInset","vp","onChange","SHEET_MAX_WIDTH","isSheetViewport","SheetLayout","px","inset","DrawNoteBar","opts","canUndo","canRedo","loading","message","CommentPopup","quickOpts","o","targetRect","tabPosition","vw","vh","margin","gap","tabWidth","popupW","popupH","minLeft","maxRight","left","top","anchorIsInformative","btn","option","hasText","description","ApiError","status","isTerminalConflict","error","DEFAULT_API_URL","ApiClient","projectKey","apiUrl","retryDelayMs","userToken","userTokenFn","contentType","headers","token","payload","screenshot","submissionToken","generateSubmissionToken","form","json","blob","ext","generateIdempotencyKey","reporterExternalId","feedbackId","email","identityToken","submissionSessionId","body","onDelta","signal","res","consumeSse","url","init","retries","err","delay","ms","resolve","reader","decoder","buffer","result","flush","raw","eventLine","l","dataLine","event","done","value","sep","record","bytes","byte","POLL_INTERVAL_MS","POLL_TIMEOUT_MS","CARD_WIDTH","CARD_HEIGHT","ClarifyCard","existingElement","cardW","cardH","centeredLeft","footer","snapshot","button","last","msg","bubble","dots","SUCCESS_AUTO_CLOSE_MS","EMAIL_PATTERN","SuccessCard","onClose","onViewFeedback","options","viewLink","emailCapture","onSubmit","input","submit","handle","resolveUrl","baseUrl","doc","base","a","uuid","counter","random","toArray","arrayLike","arr","styleProps","getStyleProperties","styleProperty","val","getNodeWidth","leftBorder","rightBorder","getNodeHeight","topBorder","bottomBorder","getImageSize","targetNode","width","height","getPixelRatio","ratio","FINAL_PROCESS","canvasDimensionLimit","checkCanvasDimensions","canvas","createImage","reject","img","svgToDataURL","svg","html","nodeToDataURL","xmlns","foreignObject","isInstanceOfElement","instance","nodePrototype","formatCSSText","content","formatCSSProperties","name","priority","getPseudoElementStyle","pseudo","clonePseudoElement","nativeNode","clonedNode","styleElement","clonePseudoElements","WOFF","JPEG","mimes","getExtension","match","getMimeType","extension","getContentFromDataUrl","dataURL","isDataUrl","makeDataUrl","mimeType","fetchAsDataURL","process","cache","getCacheKey","includeQueryParams","key","resourceToDataURL","resourceUrl","cacheKey","cloneCanvasElement","cloneVideoElement","video","ctx","poster","cloneIFrameElement","iframe","_a","cloneNode","cloneSingleNode","isSVGElement","isSlotElement","cloneChildren","_b","children","deferred","child","clonedChild","cloneCSSStyle","targetStyle","sourceStyle","cloneInputValue","cloneSelectValue","clonedSelect","selectedOption","decorate","ensureSVGSymbols","clone","uses","processedDefs","id","exist","definition","ns","defs","isRoot","URL_REGEX","URL_WITH_FORMAT_REGEX","FONT_SRC_REGEX","toRegex","escaped","parseURLs","urls","quotation","embed","resourceURL","baseURL","getContentFromUrl","resolvedURL","filterPreferredFontFormat","str","preferredFontFormat","src","format","shouldEmbed","embedResources","filteredCSSText","css","embedProp","propName","propValue","cssString","embedBackground","embedImageNode","isImageElement","attributes","image","embedChildren","deferreds","embedImages","applyStyle","manual","cssFetchCache","fetchCSS","embedFonts","data","regexUrl","loadFonts","loc","parseCSS","source","commentsRegex","keyframesRegex","matches","importRegex","combinedCSSRegex","unifiedRegex","getCSSRules","styleSheets","ret","sheet","item","index","importIndex","metadata","rule","inline","getWebFontRules","cssRules","parseWebFontRules","normalizeFontFamily","font","getUsedFonts","fonts","traverse","getWebFontCSS","rules","usedFonts","embedWebFonts","styleNode","sytleContent","toSvg","toCanvas","context","canvasWidth","canvasHeight","toJpeg","MIN_CROP_WIDTH","MIN_CROP_HEIGHT","PADDING_PX","PADDING_RATIO","SKIP_CROP_RATIO","getAnnotationBounds","annotations","minX","minY","maxX","maxY","ann","r","polyline","parsePathPolylines","computeCropRegion","viewportWidth","viewportHeight","bounds","padX","padY","w","h","cropCanvas","cropped","captureScreenshot","captureMetrics","getCaptureMetrics","dataUrl","annotated","bakeAnnotations","dataUrlToBlob","loadImage","scaleX","scaleY","pinIndex","drawStroke","drawPin","cropRect","right","bottom","scaled","canvasToJpegBlob","drawPath","borderWidth","borderHeight","polylines","tokens","header","mime","binary","ErrorSource","listener","line","col","reason","errorSource","MAX_CONSOLE_ERRORS","ConsoleErrorCollector","location","listeners","nativePushState","nativeReplaceState","installedPushState","installedReplaceState","popstateHandler","onHistoryNavigation","install","released","uninstall","notify","pushOrig","replaceOrig","unused","MAX_BREADCRUMBS","BreadcrumbCollector","crumb","target","field","from","to","STORAGE_KEY","memoryState","loadFrustrationState","normalize","saveFrustrationState","state","normalized","isFrustrationDismissed","markFrustrationDismissed","t","u","RAGE_CLICK_THRESHOLD","RAGE_CLICK_WINDOW_MS","RAPID_NAV_THRESHOLD","RAPID_NAV_WINDOW_MS","FORM_CHECK_DELAY_MS","DEAD_CLICK_DOM_DELAY_MS","ERROR_PAGE_CHECK_DELAY_MS","INTERACTIVE_TAGS","INTERACTIVE_ROLES","ERROR_PAGE_PATTERNS","_FrustrationDetector","onFrustration","_e","stored","now","cutoff","describeElement","control","candidates","clickTime","mutated","navigated","cls","lower","role","FrustrationDetector","collectPageContext","detectBrowser","detectOS","ua","buildPayload","pageContext","consoleErrors","user","recording","anonId","anonEmail","breadcrumbs","EMAIL_KEY","BOARD_URL_KEY","memoryId","memoryEmail","memoryBoardUrl","getAnonId","generateAnonId","getStoredReporterEmail","rememberReporterEmail","getCachedBoardUrl","cacheBoardUrl","en","zhCN","ja","ko","es","fr","de","locales","getMessages","locale","lang","MAX_DURATION_S","BLOCK_CLASS","MASK_TEXT_CLASS","RRWEB_CDN","RRWEB_SRI","rrwebLoaded","loadRrweb","loadViaImport","loadViaCdn","findGlobalRecord","win","existing","script","RecordSession","onMaxReached","ripple","RecordControlBar","getDuration","onStop","secs","mm","ss","RecordingManager","SPECULATIVE_CLARIFY_TIMEOUT_MS","CLARIFY_SILENCE_TIMEOUT_MS","isLocalHost","hostname","WidgetController","config","note","action","exchange","ui","submissionAttempt","waitForPaint","submission","pos","element","controller","silenceTimer","resetSilenceTimer","clarifyPromise","timeoutPromise","preservePopup","popupElement","speculative","feedback","saved","boardUrl","lastConfig","MakeThisBetter"],"mappings":"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","x_google_ignoreList":[20,21,22,23,24,25,26,27,28,29]}