lib-e2e-cypress-for-dummys-ts 1.0.0 → 1.0.1
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.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/code-format.utils.ts","../src/utils/selector-quality.utils.ts","../src/components/selector-picker/selector-picker.styles.ts","../src/utils/html.utils.ts","../src/components/selector-picker/selector-picker.template.ts","../src/components/selector-picker/selector-picker.ts","../src/index.ts","../src/models/lang.model.ts","../src/models/input-types.model.ts","../src/models/db-schema.model.ts","../src/utils/subject.ts","../src/i18n/es.ts","../src/i18n/en.ts","../src/i18n/fr.ts","../src/i18n/it.ts","../src/i18n/de.ts","../src/services/translation.service.ts","../src/services/transformation.service.ts","../src/services/advanced-test.transformation.service.ts","../src/services/recording.service.ts","../src/utils/assertion.utils.ts","../src/services/persistence.service.ts","../src/models/issue-tracker.model.ts","../src/utils/ticket.utils.ts","../src/services/http-monitor.ts","../src/utils/redact.utils.ts","../src/utils/styles.utils.ts","../src/utils/modal.utils.ts","../src/utils/toast.utils.ts","../src/utils/export-selection.utils.ts","../src/utils/host.utils.ts","../src/components/test-previsualizer/test-previsualizer.styles.ts","../src/components/test-previsualizer/test-previsualizer.template.ts","../src/components/test-previsualizer/test-previsualizer.ts","../src/components/save-test/save-test.styles.ts","../src/components/save-test/save-test.template.ts","../src/components/save-test/save-test.ts","../src/components/test-editor/test-editor.ts","../src/components/test-editor/test-editor.styles.ts","../src/components/test-editor/test-editor.template.ts","../src/utils/syntax-highlight.utils.ts","../src/models/active-session.model.ts","../src/utils/login-setup.utils.ts","../src/components/configuration/configuration.styles.ts","../src/components/configuration/configuration.template.ts","../src/components/configuration/configuration.ts","../src/components/advanced-test-editor/advanced-test-editor.ts","../src/components/advanced-test-editor/advanced-test-editor.styles.ts","../src/components/advanced-test-editor/advanced-test-editor.template.ts","../src/components/file-preview/file-preview.styles.ts","../src/components/file-preview/file-preview.template.ts","../src/components/file-preview/file-preview.ts","../src/components/help-panel/help-panel.styles.ts","../src/components/help-panel/help-panel.template.ts","../src/components/help-panel/help-panel.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.styles.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.template.ts","../src/components/lib-e2e-recorder/assertion-builder.ts","../src/components/lib-e2e-recorder/filesystem-setup.ts","../src/utils/swal-mount.utils.ts","../src/utils/widget-position.utils.ts","../src/utils/fixture-convert.utils.ts"],"sourcesContent":["function gcd(a: number, b: number): number {\n while (b) { const t = b; b = a % b; a = t; }\n return a;\n}\n\n/**\n * Escapes backslashes and single quotes so a value can be safely embedded inside\n * a single-quoted JavaScript string literal — e.g. an `it('…')` / `describe('…')`\n * name. Without this, a test named `User's login` produces broken generated JS.\n */\nexport function escapeSingleQuotes(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Escapes double quotes so a value can be safely embedded inside a CSS\n * double-quoted attribute selector, e.g. [data-cy=\"VALUE\"].\n * The result must subsequently pass through escapeSingleQuotes when it is\n * placed inside a single-quoted JS string literal (the JS layer doubles the\n * backslash introduced here).\n */\nexport function escapeCssAttrValue(value: string): string {\n return value.replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Normalizes indentation in a code block and prefixes every line with baseIndent.\n *\n * Algorithm:\n * 1. Strip trailing whitespace from each line.\n * 2. Find the minimum leading-whitespace count of non-empty lines (dedent).\n * 3. Compute the indent step as the GCD of all non-zero relative indent values,\n * so the original indent unit (4-space, 8-space, etc.) maps to 2-space levels.\n * 4. Re-emit each line as: baseIndent + ' '.repeat(level) + trimmedContent.\n *\n * This handles multi-line interceptor/command blocks that were stored with\n * inconsistent or file-origin indentation.\n */\nexport function normalizeBlock(code: string, baseIndent: string): string {\n const lines = code.split('\\n').map(l => l.trimEnd());\n const nonEmpty = lines.filter(l => l.trim().length > 0);\n if (!nonEmpty.length) return '';\n\n const indents = nonEmpty.map(l => l.length - l.trimStart().length);\n const minIndent = Math.min(...indents);\n const relIndents = [...new Set(indents.map(n => n - minIndent).filter(n => n > 0))];\n const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;\n\n return lines\n .map(l => {\n if (!l.trim()) return '';\n const level = Math.round((l.length - l.trimStart().length - minIndent) / step);\n return baseIndent + ' '.repeat(level) + l.trimStart();\n })\n .join('\\n');\n}\n","import { escapeCssAttrValue } from './code-format.utils';\n\nexport type SelectorQuality = 'excellent' | 'good' | 'acceptable' | 'poor';\n\nexport const FORBIDDEN_ID_PREFIXES = [\n 'cdk-', 'mat-', 'p-', 'ng-', 'mdc-',\n 'primeng-', 'auto-', 'field-', 'input-', 'select-',\n];\n\nexport function getSelectorQuality(el: HTMLElement): SelectorQuality {\n if (\n el.hasAttribute('data-cy') ||\n el.hasAttribute('data-testid') ||\n el.hasAttribute('aria-label')\n ) {\n return 'excellent';\n }\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return 'good';\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n return 'acceptable';\n }\n\n return 'poor';\n}\n\n/** Returns the best cy.get() selector string for a given element. */\nexport function buildPickerSelector(el: HTMLElement): string {\n const dataCy = el.getAttribute('data-cy');\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n\n const dataTestid = el.getAttribute('data-testid');\n if (dataTestid) return `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]`;\n\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return `[aria-label=\"${escapeCssAttrValue(ariaLabel)}\"]`;\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return `#${rawId}`;\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n const classes = el.className.trim().split(/\\s+/);\n return classes.map((c) => `.${c}`).join('');\n }\n\n return el.tagName.toLowerCase();\n}\n\n/** Human-readable key attribute/selector preview for a picker row (raw, unescaped). */\nexport function keyAttrDisplay(el: HTMLElement): string {\n for (const attr of ['data-cy', 'data-testid', 'aria-label']) {\n const v = el.getAttribute(attr);\n if (v) return `${attr}=\"${v}\"`;\n }\n if (el.id) return `id=\"${el.id}\"`;\n if (el.className && el.className.trim()) {\n return el.className.trim().split(/\\s+/).map((c) => `.${c}`).join('');\n }\n return '';\n}\n\n/** Plain, serializable view-model for one picker row — no DOM held. */\nexport interface PickerRow {\n quality: SelectorQuality;\n selector: string;\n tag: string;\n attr: string;\n}\n\n/** Reads an element once and returns the plain data a picker row needs to render. */\nexport function describePickerRow(el: HTMLElement): PickerRow {\n return {\n quality: getSelectorQuality(el),\n selector: buildPickerSelector(el),\n tag: el.tagName.toLowerCase(),\n attr: keyAttrDisplay(el),\n };\n}\n","export const SELECTOR_PICKER_STYLES = `\n :host {\n position: fixed;\n z-index: 2147483647;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n }\n\n .overlay {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: all;\n background: #161b22;\n border: 1px solid #30363d;\n border-radius: 10px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n min-width: 420px;\n max-width: 600px;\n font-family: 'Segoe UI', system-ui, sans-serif;\n color: #e6edf3;\n font-size: 13px;\n }\n\n .header {\n padding: 12px 16px 8px;\n border-bottom: 1px solid #21262d;\n font-weight: 600;\n font-size: 13px;\n color: #8b949e;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n }\n\n .list {\n max-height: 320px;\n overflow-y: auto;\n padding: 6px 0;\n }\n\n .row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 14px;\n cursor: pointer;\n border-radius: 6px;\n margin: 1px 6px;\n transition: background 0.1s;\n }\n\n .row:hover,\n .row.selected {\n background: #21262d;\n }\n\n .row.selected {\n outline: 2px solid #388bfd;\n outline-offset: -2px;\n }\n\n .quality-badge {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n }\n\n .badge-excellent { background: #238636; }\n .badge-good { background: #1f6feb; }\n .badge-acceptable{ background: #9e6a03; }\n .badge-poor { background: #da3633; }\n\n .tag-name {\n font-family: monospace;\n font-size: 12px;\n color: #8b949e;\n flex-shrink: 0;\n }\n\n .attr-value {\n font-family: monospace;\n font-size: 12px;\n color: #c9d1d9;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .selector-preview {\n font-family: monospace;\n font-size: 11px;\n color: #58a6ff;\n flex-shrink: 0;\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .poor-warning {\n font-size: 10px;\n color: #f85149;\n margin-left: auto;\n }\n\n .footer {\n padding: 8px 14px 10px;\n border-top: 1px solid #21262d;\n display: flex;\n gap: 16px;\n font-size: 11px;\n color: #484f58;\n }\n\n .hint kbd {\n background: #21262d;\n border: 1px solid #30363d;\n border-radius: 3px;\n padding: 1px 5px;\n font-size: 10px;\n color: #8b949e;\n }\n`;\n","export function escHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nexport function escAttr(s: string): string {\n return s.replace(/\"/g, '"').replace(/</g, '<');\n}\n","import type { PickerRow, SelectorQuality } from '../../utils/selector-quality.utils';\nimport { escHtml } from '../../utils/html.utils';\n\nconst QUALITY_EMOJI: Record<SelectorQuality, string> = {\n excellent: '🟢',\n good: '🔵',\n acceptable: '🟡',\n poor: '🔴',\n};\n\nconst QUALITY_CLASS: Record<SelectorQuality, string> = {\n excellent: 'badge-excellent',\n good: 'badge-good',\n acceptable: 'badge-acceptable',\n poor: 'badge-poor',\n};\n\nexport function renderPickerRows(\n rows: PickerRow[],\n selectedIndex: number,\n t: (key: string) => string,\n): string {\n return rows.map((row, i) => {\n const isSelected = i === selectedIndex;\n const isPoor = row.quality === 'poor';\n\n return `\n <div class=\"row${isSelected ? ' selected' : ''}\" data-idx=\"${i}\" role=\"option\" aria-selected=\"${isSelected}\">\n <span class=\"quality-badge ${QUALITY_CLASS[row.quality]}\" title=\"${escHtml(t(`SELECTOR_PICKER.QUALITY_${row.quality.toUpperCase()}`))}\">\n ${QUALITY_EMOJI[row.quality]}\n </span>\n <span class=\"tag-name\"><${escHtml(row.tag)}></span>\n ${row.attr ? `<span class=\"attr-value\">${escHtml(row.attr)}</span>` : '<span class=\"attr-value\"></span>'}\n <span class=\"selector-preview\">${escHtml(row.selector)}</span>\n ${isPoor ? `<span class=\"poor-warning\" title=\"${escHtml(t('SELECTOR_PICKER.QUALITY_POOR'))}\">⚠</span>` : ''}\n </div>`;\n }).join('');\n}\n\nexport function renderPicker(\n rows: PickerRow[],\n selectedIndex: number,\n t: (key: string) => string,\n): string {\n return `\n <div class=\"overlay\" role=\"listbox\">\n <div class=\"header\">${escHtml(t('SELECTOR_PICKER.TITLE'))}</div>\n <div class=\"list\">\n ${renderPickerRows(rows, selectedIndex, t)}\n </div>\n <div class=\"footer\">\n <span class=\"hint\"><kbd>↑↓</kbd> ${escHtml(t('SELECTOR_PICKER.PREVIEW_LABEL'))}</span>\n <span class=\"hint\"><kbd>Enter</kbd> ${escHtml(t('SELECTOR_PICKER.CONFIRM_HINT'))}</span>\n <span class=\"hint\"><kbd>Esc</kbd> ${escHtml(t('SELECTOR_PICKER.CANCEL_HINT'))}</span>\n </div>\n </div>`;\n}\n","import type { RecordingService } from '../../services/recording.service';\nimport type { TranslationService } from '../../services/translation.service';\nimport { describePickerRow, type PickerRow } from '../../utils/selector-quality.utils';\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { SELECTOR_PICKER_STYLES } from './selector-picker.styles';\nimport { renderPicker } from './selector-picker.template';\n\nconst OWN_DATA_CY = 'lib-e2e-cypress-for-dummys';\nconst MAX_ANCESTORS = 10;\n\nexport class SelectorPickerElement extends HTMLElement {\n targetElement: HTMLElement | null = null;\n recording!: RecordingService;\n translation!: TranslationService;\n\n private shadow: ShadowRoot;\n private ancestors: HTMLElement[] = [];\n private rows: PickerRow[] = [];\n private selectedIndex = 0;\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\n private unsubRecording: (() => void) | null = null;\n private unsubPause: (() => void) | null = null;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\n this.ancestors = this.buildAncestors();\n this.rows = this.ancestors.map(describePickerRow);\n this.selectedIndex = this.findBestIndex();\n this.render();\n this.attachKeyListener();\n this.attachRowClickListeners();\n this.subscribeToRecordingChanges();\n }\n\n disconnectedCallback(): void {\n this.detachKeyListener();\n this.unsubRecording?.();\n this.unsubPause?.();\n }\n\n private t(key: string): string {\n return this.translation?.translate(key) ?? key;\n }\n\n // ── Ancestor chain ──────────────────────────────────────────────────────────\n\n private buildAncestors(): HTMLElement[] {\n const chain: HTMLElement[] = [];\n let current: HTMLElement | null = this.targetElement;\n\n while (current && current.tagName.toLowerCase() !== 'html' && chain.length < MAX_ANCESTORS) {\n if (current.getAttribute('data-cy') === OWN_DATA_CY) {\n current = current.parentElement;\n continue;\n }\n chain.push(current);\n current = current.parentElement;\n }\n\n return chain;\n }\n\n private findBestIndex(): number {\n for (let i = 0; i < this.rows.length; i++) {\n const q = this.rows[i].quality;\n if (q === 'excellent' || q === 'good' || q === 'acceptable') return i;\n }\n return 0;\n }\n\n // ── Rendering ───────────────────────────────────────────────────────────────\n\n private render(): void {\n this.shadow.innerHTML = `<style>${SELECTOR_PICKER_STYLES}</style>${renderPicker(\n this.rows,\n this.selectedIndex,\n this.t.bind(this),\n )}`;\n }\n\n // ── Keyboard ────────────────────────────────────────────────────────────────\n\n private attachKeyListener(): void {\n this.keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.stopPropagation();\n e.preventDefault();\n this.selectedIndex = (this.selectedIndex + 1) % this.ancestors.length;\n this.render();\n this.attachRowClickListeners();\n } else if (e.key === 'ArrowUp') {\n e.stopPropagation();\n e.preventDefault();\n this.selectedIndex = (this.selectedIndex - 1 + this.ancestors.length) % this.ancestors.length;\n this.render();\n this.attachRowClickListeners();\n } else if (e.key === 'Enter') {\n e.stopPropagation();\n this.confirm(this.selectedIndex);\n } else if (e.key === 'Escape') {\n e.stopPropagation();\n this.cancel();\n }\n };\n window.addEventListener('keydown', this.keyHandler, { capture: true });\n }\n\n private detachKeyListener(): void {\n if (this.keyHandler) {\n window.removeEventListener('keydown', this.keyHandler, { capture: true });\n this.keyHandler = null;\n }\n }\n\n // ── Row click listeners ─────────────────────────────────────────────────────\n\n private attachRowClickListeners(): void {\n this.shadow.querySelectorAll('[data-idx]').forEach((row) => {\n (row as HTMLElement).addEventListener('click', () => {\n const idx = parseInt((row as HTMLElement).dataset['idx'] ?? '0', 10);\n this.confirm(idx);\n });\n });\n }\n\n // ── Recording auto-close ────────────────────────────────────────────────────\n\n private subscribeToRecordingChanges(): void {\n this.unsubRecording = this.recording.onRecordingChange((isRecording) => {\n if (!isRecording) this.closeSilently();\n });\n this.unsubPause = this.recording.onPauseChange((isPaused) => {\n if (isPaused) this.closeSilently();\n });\n }\n\n // ── Actions ─────────────────────────────────────────────────────────────────\n\n private confirm(index: number): void {\n const row = this.rows[index];\n if (!row) return;\n const command = `cy.get('${escapeSingleQuotes(row.selector)}').click()`;\n this.recording.appendCommand(command);\n this.dispatchEvent(new CustomEvent('selectorchosen', { detail: command, bubbles: true, composed: true }));\n this.closeSilently();\n }\n\n private cancel(): void {\n this.dispatchEvent(new CustomEvent('pickercancelled', { bubbles: true, composed: true }));\n this.closeSilently();\n }\n\n private closeSilently(): void {\n this.detachKeyListener();\n this.unsubRecording?.();\n this.unsubPause?.();\n this.unsubRecording = null;\n this.unsubPause = null;\n this.remove();\n }\n}\n\nif (!customElements.get('lib-e2e-selector-picker')) {\n customElements.define('lib-e2e-selector-picker', SelectorPickerElement);\n}\n","// Public API for lib-e2e-cypress-for-dummys-ts.\n//\n// This is an EXPLICIT allowlist — everything exported here is part of the\n// semver-stable public contract. Internal singletons, magic-key constants,\n// low-level drag/geometry helpers and test-only utilities are intentionally\n// NOT re-exported (import them from their module path for internal use).\n//\n// Keep VERSION in sync with package.json \"version\" (asserted in\n// specs/public-api.spec.ts).\nexport const VERSION = '1.0.0';\n\n// ── Models (public types & stable constants) ────────────────────────────────\nexport { SUPPORTED_LANGS, isLang, LOCALE_BY_LANG, localeForLang } from './models/lang.model';\nexport type { Lang } from './models/lang.model';\nexport { INPUT_TYPES } from './models/input-types.model';\nexport type { InputType } from './models/input-types.model';\nexport { DB_SCHEMA, DB_STORE_NAMES } from './models/db-schema.model';\nexport type { DBSchema, DBStore, DBStoreIndex } from './models/db-schema.model';\nexport type { ActiveSessionState } from './models/active-session.model';\n// Internal (not exported): ACTIVE_SESSION_BREADCRUMB_KEY, RESUME_TTL_CONFIG_KEY,\n// DEFAULT_RESUME_TTL_MINUTES.\n\n// ── Services ────────────────────────────────────────────────────────────────\nexport { TranslationService } from './services/translation.service';\nexport { TransformationService } from './services/transformation.service';\nexport { AdvancedTestTransformationService } from './services/advanced-test.transformation.service';\nexport type { DirectoryNode, FileNode } from './services/advanced-test.transformation.service';\nexport { RecordingService } from './services/recording.service';\nexport type { SelectorStrategy } from './services/recording.service';\nexport { PersistenceService } from './services/persistence.service';\nexport type { TestWithDetails, TestDetail } from './services/persistence.service';\nexport { HttpMonitor, generateAlias } from './services/http-monitor';\n// Internal (not exported): translationService / transformationService /\n// advancedTestTransformationService singletons, _resetHttpMonitorState.\n\n// ── UI utilities (public) ────────────────────────────────────────────────────\nexport { SCROLLBAR_STYLES, LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, injectStyles } from './utils/styles.utils';\nexport { makeModalResizable, makeSwalDraggable } from './utils/modal.utils';\nexport { showToast } from './utils/toast.utils';\nexport { selectTestsForExport } from './utils/export-selection.utils';\nexport type { ExportMode, ExportSelectionOptions } from './utils/export-selection.utils';\nexport { isLocalHost } from './utils/host.utils';\nexport { inferAssertionCommand } from './utils/assertion.utils';\n// Internal (not exported): makeSwalDraggableByContentId, setSwal2DataCyAttribute,\n// ensurePopupDimensions, and the widget-position geometry helpers.\n\n// ── Web Components (registers the custom elements as an import side effect) ──\nexport { SelectorPickerElement } from './components/selector-picker/selector-picker';\nexport { TestPrevisualizerElement } from './components/test-previsualizer/test-previsualizer';\nexport { SaveTestElement } from './components/save-test/save-test';\nexport { TestEditorElement } from './components/test-editor/test-editor';\nexport { ConfigurationElement } from './components/configuration/configuration';\nexport { AdvancedTestEditorElement } from './components/advanced-test-editor/advanced-test-editor';\nexport { FilePreviewElement } from './components/file-preview/file-preview';\nexport { HelpPanelElement } from './components/help-panel/help-panel';\nexport { LibE2eRecorderElement } from './components/lib-e2e-recorder/lib-e2e-recorder';\n","export type Lang = 'es' | 'en' | 'fr' | 'it' | 'de';\n\nexport const SUPPORTED_LANGS: Lang[] = ['es', 'en', 'fr', 'it', 'de'];\n\nexport function isLang(value: string): value is Lang {\n return SUPPORTED_LANGS.includes(value as Lang);\n}\n\n/** BCP-47 locale used for date/number formatting per UI language. */\nexport const LOCALE_BY_LANG: Record<Lang, string> = {\n es: 'es-ES',\n en: 'en-GB',\n fr: 'fr-FR',\n it: 'it-IT',\n de: 'de-DE',\n};\n\n/** Returns the formatting locale for a UI language (falls back to es-ES). */\nexport function localeForLang(lang: string): string {\n return isLang(lang) ? LOCALE_BY_LANG[lang] : 'es-ES';\n}\n","export const INPUT_TYPES = [\n 'text',\n 'password',\n 'email',\n 'search',\n 'tel',\n 'url',\n 'number',\n 'textarea',\n] as const;\n\nexport type InputType = (typeof INPUT_TYPES)[number];\n","export interface DBStoreIndex {\n name: string;\n keyPath: string;\n unique: boolean;\n}\n\nexport interface DBStore {\n name: string;\n keyPath: string;\n autoIncrement: boolean;\n indexes: DBStoreIndex[];\n}\n\nexport interface DBSchema {\n name: string;\n version: number;\n stores: DBStore[];\n}\n\nexport const DB_SCHEMA: DBSchema = {\n name: 'E2ECypressDB',\n version: 11,\n stores: [\n {\n name: 'tests',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'name', keyPath: 'name', unique: false },\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\n ],\n },\n {\n name: 'commands',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'command', keyPath: 'command', unique: false },\n { name: 'testId', keyPath: 'testId', unique: false },\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\n ],\n },\n {\n name: 'interceptors',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'interceptor', keyPath: 'interceptor', unique: false },\n { name: 'testId', keyPath: 'testId', unique: false },\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\n ],\n },\n {\n name: 'configuration',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'language', keyPath: 'language', unique: false },\n { name: 'extendedHttpCommands', keyPath: 'extendedHttpCommands', unique: false },\n { name: 'allowReadWriteFiles', keyPath: 'allowReadWriteFiles', unique: false },\n ],\n },\n {\n // Single-record store (fixed key id=1) holding the live, in-progress\n // recording session so it survives a micro-frontend crossing or reload.\n // See docs/specs/006-cross-app-recording-continuity.md.\n name: 'activeSession',\n keyPath: 'id',\n autoIncrement: false,\n indexes: [],\n },\n ],\n};\n\nexport const DB_STORE_NAMES = DB_SCHEMA.stores.map(s => s.name) as [\n 'tests',\n 'commands',\n 'interceptors',\n 'configuration',\n 'activeSession',\n];\n","export class Subject<T> {\n private _value: T;\n private listeners = new Set<(v: T) => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n }\n\n next(value: T): void {\n this._value = value;\n this.listeners.forEach((l) => l(value));\n }\n\n getValue(): T {\n return this._value;\n }\n\n subscribe(fn: (v: T) => void): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n}\n","export const I18N_ES = {\n MAIN_FRAME: {\n SETTINGS: 'Configuración',\n SHOW_ADVANCED_EDITOR: 'Editor avanzado',\n DIALOG_SAVED_TESTS: 'Pruebas guardadas',\n DIALOG_COMMANDS: 'Previsualizador de comandos Cypress',\n DIALOG_SAVE: '¿Guardar la grabación?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Descripción de la prueba',\n CANCEL: 'Cancelar',\n ASK: '¿Guardar el test grabado?',\n YES_CONTINUE: 'Sí, continuar',\n NO_DISCARD: 'No, descartar',\n DESC_PLACEHOLDER: 'Ej: Login correcto con credenciales válidas',\n TAGS_LABEL: 'Etiquetas (opcional, para filtrar después):',\n TAGS_PLACEHOLDER: 'smoke, login, regresión…',\n ADD_TAG: '+ Añadir',\n NO_TAGS: 'Sin etiquetas',\n SAVE_BTN: '💾 Guardar',\n SAVE_AND_EDIT: '📝 Guardar y editar',\n REMOVE_TAG_TITLE: 'Quitar',\n NOTES_LABEL: 'Descripción / Notas (opcional):',\n NOTES_PLACEHOLDER: 'Qué valida este test, condiciones previas, etc.',\n TICKET_LABEL: 'Ticket / Issue (opcional):',\n TICKET_PLACEHOLDER: 'Ej: PROJ-123, #42',\n TICKET_WARN: 'ID no válido para el proveedor configurado (se guardará igualmente)',\n CONFIRM_DISCARD: '¿Seguro que quieres descartar el test grabado? Se perderán todos los pasos registrados.',\n CONFIRM_DISCARD_BTN: 'Sí, descartar',\n BACK_BTN: 'Volver',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Sin etiquetas',\n SELECTED_SINGULAR: 'seleccionado',\n SELECTED_PLURAL: 'seleccionados',\n DESCRIBE_PLACEHOLDER: 'Nombre del describe (opcional)',\n COPY_DESCRIBE: '🗂 Copiar describe()',\n MULTI_SELECT: '🗂 Multi-select',\n CANCEL_SELECT: '✕ Cancelar',\n COPY_CMDS_BTN: '📋 Copiar comandos',\n COPY_ICPS_BTN: '📋 Copiar interceptores',\n DEFAULT_DESCRIBE: 'Suite de tests',\n NO_TESTS: 'No hay tests guardados',\n DELETE_TITLE: 'Eliminar',\n GROUP_BY_TICKET: '🎫 Agrupar por ticket',\n UNGROUP_TICKET: '🎫 Desagrupar',\n NO_TICKET: 'Sin ticket',\n TICKET_LINK_TITLE: 'Abrir ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Idioma',\n LANG_FIELD: 'Interfaz',\n HTTP_SECTION: '⚡ HTTP Avanzado',\n HTTP_TITLE: 'Validaciones de body',\n HTTP_SUB: 'GET → response · POST/PUT → request',\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\n FIXTURE_TITLE: 'Grabar respuestas como fixtures',\n FIXTURE_SUB: 'Las GET se guardan en cypress/fixtures y se stubean con cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Estrategia de selector',\n SELECTOR_LABEL: 'Atributo preferido para cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (por defecto)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#elemento)',\n SELECTOR_HINT: 'El grabador buscará este atributo primero. Si no existe, intentará los demás.',\n FOLDER_SECTION: '📁 Carpeta Cypress',\n FOLDER_CONNECTED: 'conectado —',\n FOLDER_NOT_SET: 'sin configurar',\n FOLDER_CHANGE_BTN: '📁 Cambiar carpeta',\n FOLDER_SELECT_BTN: '📁 Seleccionar carpeta',\n FOLDER_REVOKE_BTN: '✕ Quitar acceso',\n DATA_SECTION: '💾 Datos',\n DATA_DESC: 'Exporta todos tus tests a JSON o importa una copia de seguridad.',\n EXPORT_BTN: '⬆️ Exportar tests',\n EXPORT_DIALOG_TITLE: '⬆️ Exportar tests',\n EXPORT_MODE_ALL: 'Todo',\n EXPORT_MODE_MANUAL: 'Selección manual',\n EXPORT_MODE_TAGS: 'Por tags',\n EXPORT_ALL_DESC: 'Se exportarán todos los tests guardados.',\n EXPORT_COUNT: 'A exportar:',\n EXPORT_CONFIRM: '⬆️ Exportar',\n EXPORT_CANCEL: 'Cancelar',\n EXPORT_EMPTY: 'No hay tests para exportar.',\n EXPORT_NO_TAGS: 'No hay tags disponibles.',\n EXPORT_TAGS_HINT: 'Selecciona uno o más tags para ver qué pruebas se exportarán.',\n EXPORT_RESULT_LABEL: 'Pruebas que se exportarán:',\n IMPORT_BTN: '⬇️ Importar tests',\n FOLDER_UPDATED_TOAST: '✓ Carpeta de Cypress actualizada',\n FOLDER_ERROR_TOAST: 'Error al acceder a la carpeta',\n IMPORT_SUCCESS: 'Datos importados correctamente.',\n IMPORT_ERROR: 'Error al importar.',\n JSON_INVALID: 'El archivo no es un JSON válido.',\n JSON_BAD_FORMAT: 'El archivo no tiene el formato esperado.',\n SMART_SELECTOR_SECTION: '🔍 Selector inteligente',\n SMART_SELECTOR_TITLE: 'Selector inteligente',\n SMART_SELECTOR_SUB: 'Muestra un picker al hacer click en elementos sin selector válido.',\n START_HIDDEN_SECTION: '👁 Visibilidad del widget',\n START_HIDDEN_TITLE: 'Iniciar oculto',\n START_HIDDEN_SUB: 'El widget arranca invisible. Usa Ctrl+Shift+E para mostrarlo u ocultarlo.',\n RESUME_TTL_SECTION: '⏱ Continuidad de grabación',\n RESUME_TTL_LABEL: 'Reanudar sin preguntar (minutos)',\n RESUME_TTL_HINT: 'Si recargas o cambias de proyecto, una grabación activa se reanuda sin preguntar dentro de este margen. Pasado ese tiempo, te preguntará si continuar o descartar.',\n WIDGET_POSITION_SECTION: '🧲 Posición del widget',\n WIDGET_POSITION_HINT: 'Arrastra el botón de grabar para moverlo donde no estorbe. Se recuerda su posición.',\n WIDGET_POSITION_RESET_BTN: '↺ Restablecer posición',\n WIDGET_POSITION_RESET_DONE: '✓ Posición restablecida',\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\n ISSUE_TRACKER_TITLE: 'Vincular tests a tickets',\n ISSUE_TRACKER_SUB: 'Añade un ID de ticket al guardar y genera un enlace clickable en el listado.',\n ISSUE_TRACKER_PROVIDER: 'Proveedor',\n ISSUE_TRACKER_BASE_URL: 'URL base',\n ISSUE_TRACKER_BASE_URL_PH: 'Ej: https://miproyecto.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'No configurado',\n LOGIN_SETUP_SET_UP_BTN: 'Configurar',\n LOGIN_SETUP_TITLE: 'Configuración de login',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Crear scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Seleccionar fichero existente',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nombre del fichero',\n LOGIN_SETUP_FILE_NAME_PH: 'Ej: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-escanear',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Funciones detectadas',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Asignación de bloques',\n LOGIN_SETUP_NO_FUNCTIONS: 'No se encontraron funciones exportadas. Rellena el scaffold y re-escanea.',\n LOGIN_SETUP_BEFORE_LABEL: 'Función before() (una vez por suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Función beforeEach() (antes de cada test)',\n LOGIN_SETUP_NONE_OPTION: '— Ninguna —',\n LOGIN_SETUP_SUMMARY: 'Fichero: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Guardar',\n LOGIN_SETUP_CLEAR_BTN: 'Eliminar configuración',\n LOGIN_SETUP_CANCEL_BTN: 'Cancelar',\n LOGIN_SETUP_SOURCE_LABEL: 'Origen del fichero de login',\n LOGIN_SETUP_CREATE_SUB: 'Genera un scaffold con funciones de ejemplo',\n LOGIN_SETUP_SELECT_SUB: 'Apunta a un servicio de login existente',\n LOGIN_SETUP_INJECT_TITLE: '¿Añadir bloques de login?',\n LOGIN_SETUP_INJECT_TEXT: 'Este fichero no tiene los bloques de login configurados. ¿Quieres añadir el import y los bloques before/beforeEach ahora?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Sí, añadir',\n },\n SELECTOR_PICKER: {\n TITLE: 'Selecciona un elemento del DOM',\n PREVIEW_LABEL: 'navegar',\n CONFIRM_HINT: 'confirmar',\n CANCEL_HINT: 'cancelar',\n QUALITY_EXCELLENT: 'Excelente — tiene atributo de prueba (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Bueno — tiene un id válido',\n QUALITY_ACCEPTABLE: 'Aceptable — solo tiene clases CSS',\n QUALITY_POOR: 'No recomendado — solo tag o estilo inline',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptores',\n COPY_CMDS_BTN: '📋 Copiar comandos',\n SHOW_INTERCEPTORS: '▼ Ver interceptores',\n HIDE_INTERCEPTORS: '▲ Ocultar interceptores',\n SECTION_COMMANDS: 'Comandos',\n NO_CMDS_YET: 'Sin comandos aún',\n NO_ICP_SHORT: 'Sin interceptores',\n COPY_ICP_BTN: '📋 Copiar interceptores',\n UP_TITLE: 'Subir',\n DOWN_TITLE: 'Bajar',\n DEL_TITLE: 'Eliminar',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Reactivar acceso',\n PERMISSION_EXPIRED: '🔑 El permiso ha caducado',\n PERMISSION_EXPIRED_HINT: 'Haz clic para reactivar el acceso a tu carpeta de Cypress.',\n NO_ACCESS: '🔒 Sin acceso a archivos locales',\n NO_ACCESS_HINT: 'Configura el acceso en ⚙️ Config.',\n NO_FILES: 'Sin archivos',\n SELECT_FILE: '← Selecciona un archivo del árbol',\n IT_LABEL: '🧪 it() a insertar:',\n COPY_IT_BTN: '📋 Copiar it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptores:',\n COPY_ICP_BTN: '📋 Copiar interceptores',\n INSERT_BTN: '💾 Insertar en archivo',\n EDIT_MANUAL_BTN: '✏️ Editar manualmente',\n CLOSE_BTN: '✕ Cerrar',\n NEW_FILE_BTN: '+ Nuevo archivo',\n NEW_FOLDER_BTN: '+ Nueva carpeta',\n REFRESH_BTN: '↻ Actualizar',\n NEW_FILE_PLACEHOLDER: 'nombre-del-test',\n NEW_FOLDER_PLACEHOLDER: 'nombre-de-carpeta',\n NEW_FILE_CONFIRM: 'Crear',\n NEW_FILE_CANCEL: 'Cancelar',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Sin archivo',\n COPY_TITLE: 'Copiar contenido del editor',\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copiar',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: 'Sin cambios respecto al original',\n NO_CHANGES_SHORT: 'Sin cambios',\n LAUNCH_BTN: '▶ Lanzar test',\n LAUNCH_LOCAL_ONLY: 'Muévelo a local para poder probar',\n LAUNCH_RUNNING: '⏳ Ejecutando…',\n LAUNCH_PASSED: '✓ Prueba superada',\n LAUNCH_FAILED: '✗ Prueba fallida',\n LAUNCH_NO_RUNNER: 'No se detectó el runner local (¿lo has arrancado?)',\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Guardar',\n CLOSE_BTN: '✕ Cerrar',\n BACK_TO_EDITOR: '← Volver al editor',\n INSERT_BTN: '🪄 Insertar bloques',\n INSERT_TITLE: 'Insertar it() y beforeEach() en el contenido del editor',\n INSERT_DONE: 'Bloques insertados en el editor',\n INSERT_ERROR: 'No se encontró un bloque describe() válido en el archivo',\n },\n RECORDER: {\n FS_TITLE: '📁 Acceso a ficheros',\n FS_LATER_BTN: 'Ahora no',\n FS_SELECT_BTN: '📁 Seleccionar carpeta',\n FS_SUCCESS_TOAST: '✓ Carpeta de Cypress configurada',\n FS_ERROR_TOAST: 'Error al acceder a la carpeta',\n FS_INTRO_HTML: 'El <strong style=\"color:#e6edf3\">editor avanzado</strong> puede insertar tus tests directamente en los archivos <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\n FS_STRUCTURE_HINT_HTML: 'Selecciona la carpeta que contiene la subcarpeta <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. La extensión espera esta estructura:',\n FS_TREE_PICK_HINT: '← selecciona esta carpeta',\n FS_TREE_READ_HINT: '← la extensión leerá aquí',\n FS_PERMISSION_NOTE: 'El permiso se guarda en el navegador y no se vuelve a solicitar.',\n ASSERTION_SECTION: '➕ Añadir aserción',\n ASSERT_SELECTOR_PH: 'selector, ej: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'valor esperado',\n ASSERT_ADD_BTN: '➕ Añadir',\n FILE_EDITOR_TITLE: '✏️ Editor de archivo',\n FILE_SAVED_TOAST: '✓ Archivo guardado',\n FILE_SAVE_ERROR_TOAST: 'Error al guardar el archivo',\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures escritos en cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'No se pudieron escribir los fixtures (configura la carpeta Cypress)',\n FILE_UPLOAD_MANUAL_TOAST: 'Añade {files} a cypress/fixtures/ antes de ejecutar el test.',\n FILE_UPLOAD_COPIED_TOAST: '{files} copiado/s a cypress/fixtures/.',\n FILE_UPLOAD_COPY_ERROR_TOAST: 'No se pudo copiar {files} a cypress/fixtures/. Añádelo manualmente.',\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Ficheros',\n BTN_COMMANDS: 'Comandos',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pausar (Ctrl+P)',\n RESUME_TITLE: 'Reanudar (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSA',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Detener (Ctrl+R)',\n START_TITLE: 'Grabar (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Grabación en curso',\n SESSION_RESUME_TEXT: 'Hay una grabación activa sin terminar.',\n SESSION_RESUME_COUNT: 'comandos capturados',\n SESSION_CONTINUE_BTN: 'Continuar grabando',\n SESSION_DISCARD_BTN: 'Descartar',\n BTN_HELP: 'Ayuda',\n },\n HELP: {\n TITLE: '❓ Ayuda — Guía rápida',\n INTRO: 'Todo lo que puede hacer el grabador.',\n SEC_RECORDING: '⏺ Grabar',\n RECORDING_1: 'Pulsa ⏺ (o Ctrl+R) para empezar; ⏹ para parar y guardar.',\n RECORDING_2: 'Pausa / reanuda con ⏸ (o Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Atajos de teclado',\n SC_RECORD: 'Ctrl+R — Grabar / detener',\n SC_PAUSE: 'Ctrl+P — Pausar / reanudar',\n SC_TESTS: 'Ctrl+1 — Panel de tests guardados',\n SC_COMMANDS: 'Ctrl+2 — Panel de comandos',\n SC_CONFIG: 'Ctrl+3 — Configuración',\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostrar / ocultar el widget',\n SC_HELP: 'Ctrl+Shift+H — Esta ayuda',\n SEC_CAPTURED: '🎯 Qué se graba',\n CAP_CLICK: 'Click → .click()',\n CAP_DBLCLICK: 'Doble-click → .dblclick()',\n CAP_RIGHTCLICK: 'Click derecho → .rightclick()',\n CAP_TYPE: 'Escribir en un campo → .clear().type(...)',\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Cambio de ruta (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Aserciones',\n ASSERT_1: 'Alt+click sobre un elemento para verificarlo sin ejecutar su acción (texto, valor, checked o visible).',\n ASSERT_2: 'O usa el constructor de aserciones en el panel de Comandos.',\n SEC_PANELS: '🗂 Paneles',\n PANEL_TESTS: '📋 Tests — guardados: filtrar por tag, copiar, combinar, exportar.',\n PANEL_COMMANDS: '⌨️ Comandos — de la grabación actual: reordenar, borrar, añadir aserciones.',\n PANEL_CONFIG: '⚙️ Config — idioma, selector, HTTP, carpeta Cypress, login setup, datos, visibilidad, posición.',\n PANEL_FILES: '📁 Ficheros — inserta tests en tus .cy.ts y lanza el runner.',\n SEC_SELECTOR: '🔎 Selectores',\n SELECTOR_1: 'Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.',\n SELECTOR_2: 'Si un click no tiene selector fiable, aparece un picker para elegir el mejor ancestro.',\n SEC_DATA: '💾 Datos',\n DATA_1: 'Exporta tests a JSON (todo / selección / por tags).',\n DATA_2: 'Importa un JSON: se fusiona con lo existente (no se borra nada).',\n SEC_ADVANCED: '🚀 Avanzado',\n ADV_INVISIBLE: 'Modo invisible: start-hidden + Ctrl+Shift+E para grabar en producción sin molestar.',\n ADV_RUNNER: 'Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.',\n ADV_CROSSAPP: 'Cross-app: la grabación sobrevive al cambiar de micro-frontend (mismo origen).',\n ADV_DRAG: 'Arrastra el botón ⏺ para mover el widget; recuerda su posición.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.',\n CLOSE: 'Cerrar',\n TAB_REFERENCE: 'Referencia rápida',\n TAB_GUIDE: 'Guía de uso',\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.',\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","export const I18N_EN = {\n MAIN_FRAME: {\n SETTINGS: 'Settings',\n SHOW_ADVANCED_EDITOR: 'Advanced editor',\n DIALOG_SAVED_TESTS: 'Saved tests',\n DIALOG_COMMANDS: 'Cypress commands previewer',\n DIALOG_SAVE: 'Save recording?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Test description',\n CANCEL: 'Cancel',\n ASK: 'Save the recorded test?',\n YES_CONTINUE: 'Yes, continue',\n NO_DISCARD: 'No, discard',\n DESC_PLACEHOLDER: 'E.g.: Successful login with valid credentials',\n TAGS_LABEL: 'Tags (optional, for later filtering):',\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\n ADD_TAG: '+ Add',\n NO_TAGS: 'No tags',\n SAVE_BTN: '💾 Save',\n SAVE_AND_EDIT: '📝 Save and edit',\n REMOVE_TAG_TITLE: 'Remove',\n NOTES_LABEL: 'Description / Notes (optional):',\n NOTES_PLACEHOLDER: 'What this test validates, preconditions, etc.',\n TICKET_LABEL: 'Ticket / Issue (optional):',\n TICKET_PLACEHOLDER: 'E.g.: PROJ-123, #42',\n TICKET_WARN: 'Invalid ID for the configured provider (will be saved anyway)',\n CONFIRM_DISCARD: 'Are you sure you want to discard this recording? All recorded steps will be lost.',\n CONFIRM_DISCARD_BTN: 'Yes, discard',\n BACK_BTN: 'Go back',\n },\n TEST_EDITOR: {\n NO_TAGS: 'No tags',\n SELECTED_SINGULAR: 'selected',\n SELECTED_PLURAL: 'selected',\n DESCRIBE_PLACEHOLDER: 'describe name (optional)',\n COPY_DESCRIBE: '🗂 Copy describe()',\n MULTI_SELECT: '🗂 Multi-select',\n CANCEL_SELECT: '✕ Cancel',\n COPY_CMDS_BTN: '📋 Copy commands',\n COPY_ICPS_BTN: '📋 Copy interceptors',\n DEFAULT_DESCRIBE: 'Test suite',\n NO_TESTS: 'No saved tests',\n DELETE_TITLE: 'Delete',\n GROUP_BY_TICKET: '🎫 Group by ticket',\n UNGROUP_TICKET: '🎫 Ungroup',\n NO_TICKET: 'No ticket',\n TICKET_LINK_TITLE: 'Open ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Language',\n LANG_FIELD: 'Interface',\n HTTP_SECTION: '⚡ Advanced HTTP',\n HTTP_TITLE: 'Body validations',\n HTTP_SUB: 'GET → response · POST/PUT → request',\n FIXTURE_SECTION: '🧪 HTTP Fixtures',\n FIXTURE_TITLE: 'Record responses as fixtures',\n FIXTURE_SUB: 'GET responses are saved to cypress/fixtures and stubbed via cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Selector strategy',\n SELECTOR_LABEL: 'Preferred attribute for cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (default)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#element)',\n SELECTOR_HINT: 'The recorder will look for this attribute first. If not found, it will try the others.',\n FOLDER_SECTION: '📁 Cypress Folder',\n FOLDER_CONNECTED: 'connected —',\n FOLDER_NOT_SET: 'not configured',\n FOLDER_CHANGE_BTN: '📁 Change folder',\n FOLDER_SELECT_BTN: '📁 Select folder',\n FOLDER_REVOKE_BTN: '✕ Revoke access',\n DATA_SECTION: '💾 Data',\n DATA_DESC: 'Export all your tests to JSON or import a backup.',\n EXPORT_BTN: '⬆️ Export tests',\n EXPORT_DIALOG_TITLE: '⬆️ Export tests',\n EXPORT_MODE_ALL: 'All',\n EXPORT_MODE_MANUAL: 'Manual selection',\n EXPORT_MODE_TAGS: 'By tags',\n EXPORT_ALL_DESC: 'All saved tests will be exported.',\n EXPORT_COUNT: 'To export:',\n EXPORT_CONFIRM: '⬆️ Export',\n EXPORT_CANCEL: 'Cancel',\n EXPORT_EMPTY: 'No tests to export.',\n EXPORT_NO_TAGS: 'No tags available.',\n EXPORT_TAGS_HINT: 'Select one or more tags to preview which tests will be exported.',\n EXPORT_RESULT_LABEL: 'Tests that will be exported:',\n IMPORT_BTN: '⬇️ Import tests',\n FOLDER_UPDATED_TOAST: '✓ Cypress folder updated',\n FOLDER_ERROR_TOAST: 'Error accessing the folder',\n IMPORT_SUCCESS: 'Data imported successfully.',\n IMPORT_ERROR: 'Error importing.',\n JSON_INVALID: 'The file is not valid JSON.',\n JSON_BAD_FORMAT: 'The file does not have the expected format.',\n SMART_SELECTOR_SECTION: '🔍 Smart selector',\n SMART_SELECTOR_TITLE: 'Smart selector',\n SMART_SELECTOR_SUB: 'Shows a picker when clicking elements with no valid selector.',\n START_HIDDEN_SECTION: '👁 Widget visibility',\n START_HIDDEN_TITLE: 'Start hidden',\n START_HIDDEN_SUB: 'The widget starts invisible. Use Ctrl+Shift+E to show or hide it.',\n RESUME_TTL_SECTION: '⏱ Recording continuity',\n RESUME_TTL_LABEL: 'Resume without asking (minutes)',\n RESUME_TTL_HINT: 'If you reload or switch projects, an active recording resumes without asking within this window. After that, you will be asked to continue or discard.',\n WIDGET_POSITION_SECTION: '🧲 Widget position',\n WIDGET_POSITION_HINT: 'Drag the record button to move it out of the way. Its position is remembered.',\n WIDGET_POSITION_RESET_BTN: '↺ Reset position',\n WIDGET_POSITION_RESET_DONE: '✓ Position reset',\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\n ISSUE_TRACKER_TITLE: 'Link tests to tickets',\n ISSUE_TRACKER_SUB: 'Add a ticket ID when saving and generate a clickable link in the test list.',\n ISSUE_TRACKER_PROVIDER: 'Provider',\n ISSUE_TRACKER_BASE_URL: 'Base URL',\n ISSUE_TRACKER_BASE_URL_PH: 'E.g.: https://myproject.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Not configured',\n LOGIN_SETUP_SET_UP_BTN: 'Set up',\n LOGIN_SETUP_TITLE: 'Login setup',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Create scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Select existing file',\n LOGIN_SETUP_FILE_NAME_LABEL: 'File name',\n LOGIN_SETUP_FILE_NAME_PH: 'E.g.: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-scan',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Detected functions',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Block assignment',\n LOGIN_SETUP_NO_FUNCTIONS: 'No exported functions found. Fill in the scaffold and re-scan.',\n LOGIN_SETUP_BEFORE_LABEL: 'before() function (once per suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'beforeEach() function (before every test)',\n LOGIN_SETUP_NONE_OPTION: '— None —',\n LOGIN_SETUP_SUMMARY: 'File: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Save',\n LOGIN_SETUP_CLEAR_BTN: 'Remove configuration',\n LOGIN_SETUP_CANCEL_BTN: 'Cancel',\n LOGIN_SETUP_SOURCE_LABEL: 'Login file source',\n LOGIN_SETUP_CREATE_SUB: 'Generate a scaffold with sample functions',\n LOGIN_SETUP_SELECT_SUB: 'Point to an existing login service file',\n LOGIN_SETUP_INJECT_TITLE: 'Add login blocks?',\n LOGIN_SETUP_INJECT_TEXT: 'This file does not have the configured login blocks. Do you want to add the import and before/beforeEach blocks now?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Yes, add them',\n },\n SELECTOR_PICKER: {\n TITLE: 'Select a DOM element',\n PREVIEW_LABEL: 'navigate',\n CONFIRM_HINT: 'confirm',\n CANCEL_HINT: 'cancel',\n QUALITY_EXCELLENT: 'Excellent — has a testing attribute (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Good — has a valid id',\n QUALITY_ACCEPTABLE: 'Acceptable — CSS classes only',\n QUALITY_POOR: 'Not recommended — tag name or inline style only',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptors',\n COPY_CMDS_BTN: '📋 Copy commands',\n SHOW_INTERCEPTORS: '▼ Show interceptors',\n HIDE_INTERCEPTORS: '▲ Hide interceptors',\n SECTION_COMMANDS: 'Commands',\n NO_CMDS_YET: 'No commands yet',\n NO_ICP_SHORT: 'No interceptors',\n COPY_ICP_BTN: '📋 Copy interceptors',\n UP_TITLE: 'Move up',\n DOWN_TITLE: 'Move down',\n DEL_TITLE: 'Delete',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Reactivate access',\n PERMISSION_EXPIRED: '🔑 Permission expired',\n PERMISSION_EXPIRED_HINT: 'Click to reactivate access to your Cypress folder.',\n NO_ACCESS: '🔒 No access to local files',\n NO_ACCESS_HINT: 'Configure access in ⚙️ Config.',\n NO_FILES: 'No files',\n SELECT_FILE: '← Select a file from the tree',\n IT_LABEL: '🧪 it() to insert:',\n COPY_IT_BTN: '📋 Copy it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptors:',\n COPY_ICP_BTN: '📋 Copy interceptors',\n INSERT_BTN: '💾 Insert into file',\n EDIT_MANUAL_BTN: '✏️ Edit manually',\n CLOSE_BTN: '✕ Close',\n NEW_FILE_BTN: '+ New file',\n NEW_FOLDER_BTN: '+ New folder',\n REFRESH_BTN: '↻ Refresh',\n NEW_FILE_PLACEHOLDER: 'test-name',\n NEW_FOLDER_PLACEHOLDER: 'folder-name',\n NEW_FILE_CONFIRM: 'Create',\n NEW_FILE_CANCEL: 'Cancel',\n },\n FILE_PREVIEW: {\n NO_FILE: 'No file',\n COPY_TITLE: 'Copy editor content',\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copy',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: 'No changes from original',\n NO_CHANGES_SHORT: 'No changes',\n LAUNCH_BTN: '▶ Run test',\n LAUNCH_LOCAL_ONLY: 'Move it to localhost to run tests',\n LAUNCH_RUNNING: '⏳ Running…',\n LAUNCH_PASSED: '✓ Test passed',\n LAUNCH_FAILED: '✗ Test failed',\n LAUNCH_NO_RUNNER: 'No local runner detected (did you start it?)',\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Save',\n CLOSE_BTN: '✕ Close',\n BACK_TO_EDITOR: '← Back to editor',\n INSERT_BTN: '🪄 Insert blocks',\n INSERT_TITLE: 'Insert it() and beforeEach() into the editor content',\n INSERT_DONE: 'Blocks inserted into the editor',\n INSERT_ERROR: 'No valid describe() block found in the file',\n },\n RECORDER: {\n FS_TITLE: '📁 File access',\n FS_LATER_BTN: 'Not now',\n FS_SELECT_BTN: '📁 Select folder',\n FS_SUCCESS_TOAST: '✓ Cypress folder configured',\n FS_ERROR_TOAST: 'Error accessing the folder',\n FS_INTRO_HTML: 'The <strong style=\"color:#e6edf3\">advanced editor</strong> can insert your tests directly into the Cypress <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> files.',\n FS_STRUCTURE_HINT_HTML: 'Select the folder that contains the <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> subfolder. The extension expects this structure:',\n FS_TREE_PICK_HINT: '← select this folder',\n FS_TREE_READ_HINT: '← the extension will read here',\n FS_PERMISSION_NOTE: 'The permission is stored in the browser and will not be requested again.',\n ASSERTION_SECTION: '➕ Add assertion',\n ASSERT_SELECTOR_PH: 'selector, e.g.: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'expected value',\n ASSERT_ADD_BTN: '➕ Add',\n FILE_EDITOR_TITLE: '✏️ File editor',\n FILE_SAVED_TOAST: '✓ File saved',\n FILE_SAVE_ERROR_TOAST: 'Error saving the file',\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures written to cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'Could not write fixtures (configure the Cypress folder)',\n FILE_UPLOAD_MANUAL_TOAST: 'Add {files} to cypress/fixtures/ before running the test.',\n FILE_UPLOAD_COPIED_TOAST: '{files} copied to cypress/fixtures/.',\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Could not copy {files} to cypress/fixtures/. Add it manually.',\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Files',\n BTN_COMMANDS: 'Commands',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pause (Ctrl+P)',\n RESUME_TITLE: 'Resume (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSED',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Stop (Ctrl+R)',\n START_TITLE: 'Record (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Recording in progress',\n SESSION_RESUME_TEXT: 'There is an unfinished active recording.',\n SESSION_RESUME_COUNT: 'commands captured',\n SESSION_CONTINUE_BTN: 'Keep recording',\n SESSION_DISCARD_BTN: 'Discard',\n BTN_HELP: 'Help',\n },\n HELP: {\n TITLE: '❓ Help — Quick guide',\n INTRO: 'Everything the recorder can do.',\n SEC_RECORDING: '⏺ Recording',\n RECORDING_1: 'Press ⏺ (or Ctrl+R) to start; ⏹ to stop and save.',\n RECORDING_2: 'Pause / resume with ⏸ (or Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Keyboard shortcuts',\n SC_RECORD: 'Ctrl+R — Record / stop',\n SC_PAUSE: 'Ctrl+P — Pause / resume',\n SC_TESTS: 'Ctrl+1 — Saved tests panel',\n SC_COMMANDS: 'Ctrl+2 — Commands panel',\n SC_CONFIG: 'Ctrl+3 — Settings',\n SC_VISIBILITY: 'Ctrl+Shift+E — Show / hide the widget',\n SC_HELP: 'Ctrl+Shift+H — This help',\n SEC_CAPTURED: '🎯 What gets recorded',\n CAP_CLICK: 'Click → .click()',\n CAP_DBLCLICK: 'Double-click → .dblclick()',\n CAP_RIGHTCLICK: 'Right-click → .rightclick()',\n CAP_TYPE: 'Type into a field → .clear().type(...)',\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Route change (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Assertions',\n ASSERT_1: 'Alt+click an element to verify it without running its action (text, value, checked or visible).',\n ASSERT_2: 'Or use the assertion builder in the Commands panel.',\n SEC_PANELS: '🗂 Panels',\n PANEL_TESTS: '📋 Tests — saved tests: filter by tag, copy, combine, export.',\n PANEL_COMMANDS: '⌨️ Commands — current recording: reorder, delete, add assertions.',\n PANEL_CONFIG: '⚙️ Config — language, selector, HTTP, Cypress folder, login setup, data, visibility, position.',\n PANEL_FILES: '📁 Files — insert tests into your .cy.ts and launch the runner.',\n SEC_SELECTOR: '🔎 Selectors',\n SELECTOR_1: 'Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.',\n SELECTOR_2: 'If a click has no reliable selector, a picker appears to choose the best ancestor.',\n SEC_DATA: '💾 Data',\n DATA_1: 'Export tests to JSON (all / selection / by tags).',\n DATA_2: 'Import a JSON: it merges into your data (nothing is wiped).',\n SEC_ADVANCED: '🚀 Advanced',\n ADV_INVISIBLE: 'Invisible mode: start-hidden + Ctrl+Shift+E to record in production unobtrusively.',\n ADV_RUNNER: 'Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.',\n ADV_CROSSAPP: 'Cross-app: the recording survives switching micro-frontend (same origin).',\n ADV_DRAG: 'Drag the ⏺ button to move the widget; its position is remembered.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): point to your login service; the recorder automatically injects before()/beforeEach() blocks into each new test.',\n CLOSE: 'Close',\n TAB_REFERENCE: 'Quick reference',\n TAB_GUIDE: 'Usage guide',\n GUIDE_INTRO: 'How to get the most out of the recorder, and what it does / doesn\\'t cover.',\n G_SEC_WORKFLOW: '🧭 Workflow',\n G_WF_1: '1. Press ⏺ (or Ctrl+R) to start recording.',\n G_WF_2: '2. Use your app like a user: clicks, forms, navigation. Each action becomes a Cypress command.',\n G_WF_3: '3. Add checks with Alt+click on whatever you want to verify.',\n G_WF_4: '4. Press ⏹ to stop; give it a name and tags, and save it.',\n G_WF_5: '5. In 📁 Files, insert the test into a .cy.ts or run it with the local runner.',\n G_SEC_COVERED: '✅ What it covers',\n G_COV_1: 'Clicks, double-click, right-click, text inputs, checkbox/radio, select and Enter/Escape keys.',\n G_COV_2: 'SPA navigation (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'fetch/XHR calls (GET/POST/PUT) → cy.intercept + cy.wait, with optional body validation.',\n G_COV_4: 'Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.',\n G_COV_5: 'Automatic assertions (Alt+click) and the manual builder.',\n G_COV_6: 'Continuity when switching micro-frontend (same origin), invisible mode and i18n.',\n G_COV_7: 'Login Setup: configure your login function under Ctrl+3 → Login Setup; the recorder adds before()/beforeEach() blocks to every new test.',\n G_SEC_NOTCOVERED: '🚫 What it does NOT cover (yet)',\n G_NC_1: 'Different origins / subdomains (same origin only).',\n G_NC_2: 'File upload (selectFile), drag & drop, and hover.',\n G_NC_3: 'The Tab key (Cypress can\\'t .type() it).',\n G_NC_4: 'DELETE requests (intentionally ignored).',\n G_NC_5: 'Third-party iframes and Shadow DOM may not be captured.',\n },\n};\n","export const I18N_FR = {\n MAIN_FRAME: {\n SETTINGS: 'Paramètres',\n SHOW_ADVANCED_EDITOR: 'Éditeur avancé',\n DIALOG_SAVED_TESTS: 'Tests enregistrés',\n DIALOG_COMMANDS: 'Aperçu des commandes Cypress',\n DIALOG_SAVE: \"Enregistrer l'enregistrement ?\",\n },\n SAVE_TEST: {\n DESC_LABEL: 'Description du test',\n CANCEL: 'Annuler',\n ASK: 'Enregistrer le test ?',\n YES_CONTINUE: 'Oui, continuer',\n NO_DISCARD: 'Non, ignorer',\n DESC_PLACEHOLDER: 'Ex : Connexion réussie avec identifiants valides',\n TAGS_LABEL: 'Étiquettes (optionnel, pour filtrer ensuite) :',\n TAGS_PLACEHOLDER: 'smoke, login, régression…',\n ADD_TAG: '+ Ajouter',\n NO_TAGS: 'Sans étiquettes',\n SAVE_BTN: '💾 Enregistrer',\n SAVE_AND_EDIT: '📝 Enregistrer et éditer',\n REMOVE_TAG_TITLE: 'Retirer',\n NOTES_LABEL: 'Description / Notes (optionnel) :',\n NOTES_PLACEHOLDER: 'Ce que ce test valide, conditions préalables, etc.',\n TICKET_LABEL: 'Ticket / Issue (optionnel) :',\n TICKET_PLACEHOLDER: 'Ex : PROJ-123, #42',\n TICKET_WARN: 'ID non valide pour le fournisseur configuré (sera enregistré quand même)', // TODO: translate\n CONFIRM_DISCARD: 'Êtes-vous sûr de vouloir abandonner cet enregistrement ? Toutes les étapes enregistrées seront perdues.',\n CONFIRM_DISCARD_BTN: 'Oui, abandonner',\n BACK_BTN: 'Retour',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Sans étiquettes',\n SELECTED_SINGULAR: 'sélectionné',\n SELECTED_PLURAL: 'sélectionnés',\n DESCRIBE_PLACEHOLDER: 'Nom du describe (optionnel)',\n COPY_DESCRIBE: '🗂 Copier describe()',\n MULTI_SELECT: '🗂 Multi-sélection',\n CANCEL_SELECT: '✕ Annuler',\n COPY_CMDS_BTN: '📋 Copier les commandes',\n COPY_ICPS_BTN: '📋 Copier les intercepteurs',\n DEFAULT_DESCRIBE: 'Suite de tests',\n NO_TESTS: 'Aucun test enregistré',\n DELETE_TITLE: 'Supprimer',\n GROUP_BY_TICKET: '🎫 Grouper par ticket',\n UNGROUP_TICKET: '🎫 Dégrouper',\n NO_TICKET: 'Sans ticket',\n TICKET_LINK_TITLE: 'Ouvrir le ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Langue',\n LANG_FIELD: 'Interface',\n HTTP_SECTION: '⚡ HTTP Avancé',\n HTTP_TITLE: 'Validations du corps',\n HTTP_SUB: 'GET → réponse · POST/PUT → requête',\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\n FIXTURE_TITLE: 'Enregistrer les réponses comme fixtures',\n FIXTURE_SUB: 'Les GET sont enregistrées dans cypress/fixtures et stubées via cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Stratégie de sélecteur',\n SELECTOR_LABEL: 'Attribut préféré pour cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (par défaut)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#élément)',\n SELECTOR_HINT: \"L'enregistreur cherchera d'abord cet attribut. Si absent, il essaiera les autres.\",\n FOLDER_SECTION: '📁 Dossier Cypress',\n FOLDER_CONNECTED: 'connecté —',\n FOLDER_NOT_SET: 'non configuré',\n FOLDER_CHANGE_BTN: '📁 Changer de dossier',\n FOLDER_SELECT_BTN: '📁 Sélectionner un dossier',\n FOLDER_REVOKE_BTN: \"✕ Révoquer l'accès\",\n DATA_SECTION: '💾 Données',\n DATA_DESC: 'Exportez tous vos tests en JSON ou importez une sauvegarde.',\n EXPORT_BTN: '⬆️ Exporter les tests',\n EXPORT_DIALOG_TITLE: '⬆️ Exporter les tests',\n EXPORT_MODE_ALL: 'Tout',\n EXPORT_MODE_MANUAL: 'Sélection manuelle',\n EXPORT_MODE_TAGS: 'Par tags',\n EXPORT_ALL_DESC: 'Tous les tests enregistrés seront exportés.',\n EXPORT_COUNT: 'À exporter :',\n EXPORT_CONFIRM: '⬆️ Exporter',\n EXPORT_CANCEL: 'Annuler',\n EXPORT_EMPTY: 'Aucun test à exporter.',\n EXPORT_NO_TAGS: 'Aucun tag disponible.',\n EXPORT_TAGS_HINT: 'Sélectionnez un ou plusieurs tags pour voir les tests qui seront exportés.',\n EXPORT_RESULT_LABEL: 'Tests qui seront exportés :',\n IMPORT_BTN: '⬇️ Importer les tests',\n FOLDER_UPDATED_TOAST: '✓ Dossier Cypress mis à jour',\n FOLDER_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\n IMPORT_SUCCESS: 'Données importées avec succès.',\n IMPORT_ERROR: \"Erreur lors de l'importation.\",\n JSON_INVALID: \"Le fichier n'est pas un JSON valide.\",\n JSON_BAD_FORMAT: \"Le fichier n'a pas le format attendu.\",\n SMART_SELECTOR_SECTION: '🔍 Sélecteur intelligent',\n SMART_SELECTOR_TITLE: 'Sélecteur intelligent',\n SMART_SELECTOR_SUB: 'Affiche un sélecteur lors du clic sur des éléments sans sélecteur valide.',\n START_HIDDEN_SECTION: '👁 Visibilité du widget',\n START_HIDDEN_TITLE: 'Démarrer masqué',\n START_HIDDEN_SUB: 'Le widget démarre invisible. Utilisez Ctrl+Shift+E pour l\\'afficher ou le masquer.',\n RESUME_TTL_SECTION: '⏱ Continuité d\\'enregistrement',\n RESUME_TTL_LABEL: 'Reprendre sans demander (minutes)',\n RESUME_TTL_HINT: 'Si vous rechargez ou changez de projet, un enregistrement actif reprend sans demander dans ce délai. Au-delà, il vous demandera de continuer ou d\\'ignorer.',\n WIDGET_POSITION_SECTION: '🧲 Position du widget',\n WIDGET_POSITION_HINT: 'Fais glisser le bouton d\\'enregistrement pour le déplacer. Sa position est mémorisée.',\n WIDGET_POSITION_RESET_BTN: '↺ Réinitialiser la position',\n WIDGET_POSITION_RESET_DONE: '✓ Position réinitialisée',\n ISSUE_TRACKER_SECTION: '🎫 Gestionnaire de tickets',\n ISSUE_TRACKER_TITLE: 'Lier les tests aux tickets',\n ISSUE_TRACKER_SUB: \"Ajoutez un ID de ticket lors de l'enregistrement et générez un lien cliquable.\",\n ISSUE_TRACKER_PROVIDER: 'Fournisseur',\n ISSUE_TRACKER_BASE_URL: 'URL de base',\n ISSUE_TRACKER_BASE_URL_PH: 'Ex : https://monprojet.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Non configuré',\n LOGIN_SETUP_SET_UP_BTN: 'Configurer',\n LOGIN_SETUP_TITLE: 'Configuration du login',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Créer un scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Sélectionner un fichier existant',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nom du fichier',\n LOGIN_SETUP_FILE_NAME_PH: 'Ex : cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-scanner',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Fonctions détectées',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Affectation des blocs',\n LOGIN_SETUP_NO_FUNCTIONS: 'Aucune fonction exportée trouvée. Remplissez le scaffold et re-scannez.',\n LOGIN_SETUP_BEFORE_LABEL: 'Fonction before() (une fois par suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Fonction beforeEach() (avant chaque test)',\n LOGIN_SETUP_NONE_OPTION: '— Aucune —',\n LOGIN_SETUP_SUMMARY: 'Fichier : {file} · before : {before} · beforeEach : {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Enregistrer',\n LOGIN_SETUP_CLEAR_BTN: 'Supprimer la configuration',\n LOGIN_SETUP_CANCEL_BTN: 'Annuler',\n LOGIN_SETUP_SOURCE_LABEL: 'Source du fichier de login',\n LOGIN_SETUP_CREATE_SUB: 'Générer un scaffold avec des fonctions exemples',\n LOGIN_SETUP_SELECT_SUB: 'Pointer vers un fichier de service de login existant',\n LOGIN_SETUP_INJECT_TITLE: 'Ajouter les blocs de login ?',\n LOGIN_SETUP_INJECT_TEXT: 'Ce fichier ne contient pas les blocs de login configurés. Voulez-vous ajouter l\\'import et les blocs before/beforeEach maintenant ?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Oui, ajouter',\n },\n SELECTOR_PICKER: {\n TITLE: 'Sélectionnez un élément du DOM',\n PREVIEW_LABEL: 'naviguer',\n CONFIRM_HINT: 'confirmer',\n CANCEL_HINT: 'annuler',\n QUALITY_EXCELLENT: 'Excellent — attribut de test présent (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Bon — id valide',\n QUALITY_ACCEPTABLE: 'Acceptable — classes CSS uniquement',\n QUALITY_POOR: 'Déconseillé — seulement le nom de balise ou style inline',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Intercepteurs',\n COPY_CMDS_BTN: '📋 Copier les commandes',\n SHOW_INTERCEPTORS: '▼ Voir les intercepteurs',\n HIDE_INTERCEPTORS: '▲ Masquer les intercepteurs',\n SECTION_COMMANDS: 'Commandes',\n NO_CMDS_YET: 'Aucune commande encore',\n NO_ICP_SHORT: 'Aucun intercepteur',\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\n UP_TITLE: 'Monter',\n DOWN_TITLE: 'Descendre',\n DEL_TITLE: 'Supprimer',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: \"🔓 Réactiver l'accès\",\n PERMISSION_EXPIRED: '🔑 Autorisation expirée',\n PERMISSION_EXPIRED_HINT: \"Cliquez pour réactiver l'accès à votre dossier Cypress.\",\n NO_ACCESS: '🔒 Pas d\\'accès aux fichiers locaux',\n NO_ACCESS_HINT: \"Configurez l'accès dans ⚙️ Config.\",\n NO_FILES: 'Aucun fichier',\n SELECT_FILE: \"← Sélectionnez un fichier dans l'arborescence\",\n IT_LABEL: '🧪 it() à insérer :',\n COPY_IT_BTN: '📋 Copier it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() intercepteurs :',\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\n INSERT_BTN: '💾 Insérer dans le fichier',\n EDIT_MANUAL_BTN: '✏️ Éditer manuellement',\n CLOSE_BTN: '✕ Fermer',\n NEW_FILE_BTN: '+ Nouveau fichier',\n NEW_FOLDER_BTN: '+ Nouveau dossier',\n REFRESH_BTN: '↻ Actualiser',\n NEW_FILE_PLACEHOLDER: 'nom-du-test',\n NEW_FOLDER_PLACEHOLDER: 'nom-du-dossier',\n NEW_FILE_CONFIRM: 'Créer',\n NEW_FILE_CANCEL: 'Annuler',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Sans fichier',\n COPY_TITLE: \"Copier le contenu de l'éditeur\",\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copier',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: \"Aucun changement par rapport à l'original\",\n NO_CHANGES_SHORT: 'Aucun changement',\n LAUNCH_BTN: '▶ Lancer le test',\n LAUNCH_LOCAL_ONLY: 'Passe en local pour pouvoir tester',\n LAUNCH_RUNNING: '⏳ Exécution…',\n LAUNCH_PASSED: '✓ Test réussi',\n LAUNCH_FAILED: '✗ Test échoué',\n LAUNCH_NO_RUNNER: \"Aucun runner local détecté (l'avez-vous démarré ?)\",\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Enregistrer',\n CLOSE_BTN: '✕ Fermer',\n BACK_TO_EDITOR: \"← Retour à l'éditeur\",\n INSERT_BTN: '🪄 Insérer les blocs',\n INSERT_TITLE: \"Insérer it() et beforeEach() dans le contenu de l'éditeur\",\n INSERT_DONE: \"Blocs insérés dans l'éditeur\",\n INSERT_ERROR: 'Aucun bloc describe() valide trouvé dans le fichier',\n },\n RECORDER: {\n FS_TITLE: '📁 Accès aux fichiers',\n FS_LATER_BTN: 'Pas maintenant',\n FS_SELECT_BTN: '📁 Sélectionner un dossier',\n FS_SUCCESS_TOAST: '✓ Dossier Cypress configuré',\n FS_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">éditeur avancé</strong> peut insérer vos tests directement dans les fichiers <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\n FS_STRUCTURE_HINT_HTML: 'Sélectionnez le dossier qui contient le sous-dossier <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'extension attend cette structure :',\n FS_TREE_PICK_HINT: '← sélectionnez ce dossier',\n FS_TREE_READ_HINT: '← l\\'extension lira ici',\n FS_PERMISSION_NOTE: 'L\\'autorisation est enregistrée dans le navigateur et ne sera plus demandée.',\n ASSERTION_SECTION: '➕ Ajouter une assertion',\n ASSERT_SELECTOR_PH: 'sélecteur, ex : [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'valeur attendue',\n ASSERT_ADD_BTN: '➕ Ajouter',\n FILE_EDITOR_TITLE: '✏️ Éditeur de fichier',\n FILE_SAVED_TOAST: '✓ Fichier enregistré',\n FILE_SAVE_ERROR_TOAST: \"Erreur lors de l'enregistrement\",\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures écrites dans cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'Impossible d\\'écrire les fixtures (configure le dossier Cypress)',\n FILE_UPLOAD_MANUAL_TOAST: 'Ajoutez {files} à cypress/fixtures/ avant d\\'exécuter le test.', // TODO: translate\n FILE_UPLOAD_COPIED_TOAST: '{files} copié(s) dans cypress/fixtures/.', // TODO: translate\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Impossible de copier {files} vers cypress/fixtures/. Ajoutez-le manuellement.', // TODO: translate\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Fichiers',\n BTN_COMMANDS: 'Commandes',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pause (Ctrl+P)',\n RESUME_TITLE: 'Reprendre (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSE',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Arrêter (Ctrl+R)',\n START_TITLE: 'Enregistrer (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Enregistrement en cours',\n SESSION_RESUME_TEXT: 'Un enregistrement actif est inachevé.',\n SESSION_RESUME_COUNT: 'commandes capturées',\n SESSION_CONTINUE_BTN: 'Continuer l\\'enregistrement',\n SESSION_DISCARD_BTN: 'Ignorer',\n BTN_HELP: 'Aide',\n },\n HELP: {\n TITLE: '❓ Aide — Guide rapide',\n INTRO: 'Tout ce que l\\'enregistreur sait faire.',\n SEC_RECORDING: '⏺ Enregistrer',\n RECORDING_1: 'Appuie sur ⏺ (ou Ctrl+R) pour commencer ; ⏹ pour arrêter et enregistrer.',\n RECORDING_2: 'Pause / reprise avec ⏸ (ou Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Raccourcis clavier',\n SC_RECORD: 'Ctrl+R — Enregistrer / arrêter',\n SC_PAUSE: 'Ctrl+P — Pause / reprise',\n SC_TESTS: 'Ctrl+1 — Panneau des tests enregistrés',\n SC_COMMANDS: 'Ctrl+2 — Panneau des commandes',\n SC_CONFIG: 'Ctrl+3 — Paramètres',\n SC_VISIBILITY: 'Ctrl+Shift+E — Afficher / masquer le widget',\n SC_HELP: 'Ctrl+Shift+H — Cette aide',\n SEC_CAPTURED: '🎯 Ce qui est enregistré',\n CAP_CLICK: 'Clic → .click()',\n CAP_DBLCLICK: 'Double-clic → .dblclick()',\n CAP_RIGHTCLICK: 'Clic droit → .rightclick()',\n CAP_TYPE: 'Saisie dans un champ → .clear().type(...)',\n CAP_CHECK: 'Case à cocher / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Entrée / Échap → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Changement de route (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Assertions',\n ASSERT_1: 'Alt+clic sur un élément pour le vérifier sans exécuter son action (texte, valeur, coché ou visible).',\n ASSERT_2: 'Ou utilise le constructeur d\\'assertions dans le panneau Commandes.',\n SEC_PANELS: '🗂 Panneaux',\n PANEL_TESTS: '📋 Tests — enregistrés : filtrer par tag, copier, combiner, exporter.',\n PANEL_COMMANDS: '⌨️ Commandes — enregistrement en cours : réordonner, supprimer, ajouter des assertions.',\n PANEL_CONFIG: '⚙️ Config — langue, sélecteur, HTTP, dossier Cypress, login setup, données, visibilité, position.',\n PANEL_FILES: '📁 Fichiers — insère des tests dans tes .cy.ts et lance le runner.',\n SEC_SELECTOR: '🔎 Sélecteurs',\n SELECTOR_1: 'Choisis l\\'attribut préféré (data-cy, data-testid, aria-label, id) dans Config.',\n SELECTOR_2: 'Si un clic n\\'a pas de sélecteur fiable, un sélecteur apparaît pour choisir le meilleur ancêtre.',\n SEC_DATA: '💾 Données',\n DATA_1: 'Exporte les tests en JSON (tout / sélection / par tags).',\n DATA_2: 'Importe un JSON : il fusionne avec tes données (rien n\\'est effacé).',\n SEC_ADVANCED: '🚀 Avancé',\n ADV_INVISIBLE: 'Mode invisible : start-hidden + Ctrl+Shift+E pour enregistrer en production discrètement.',\n ADV_RUNNER: 'Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l\\'éditeur.',\n ADV_CROSSAPP: 'Cross-app : l\\'enregistrement survit au changement de micro-frontend (même origine).',\n ADV_DRAG: 'Fais glisser le bouton ⏺ pour déplacer le widget ; sa position est mémorisée.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (fr)\n CLOSE: 'Fermer',\n TAB_REFERENCE: 'Référence rapide',\n TAB_GUIDE: 'Guide d\\'utilisation',\n // TODO: translate (fr) — usage guide body kept in Spanish for now.\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (fr)\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","export const I18N_IT = {\n MAIN_FRAME: {\n SETTINGS: 'Impostazioni',\n SHOW_ADVANCED_EDITOR: 'Editor avanzato',\n DIALOG_SAVED_TESTS: 'Test salvati',\n DIALOG_COMMANDS: 'Anteprima comandi Cypress',\n DIALOG_SAVE: 'Salvare la registrazione?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Descrizione del test',\n CANCEL: 'Annulla',\n ASK: 'Salvare il test registrato?',\n YES_CONTINUE: 'Sì, continua',\n NO_DISCARD: 'No, annulla',\n DESC_PLACEHOLDER: 'Es: Login riuscito con credenziali valide',\n TAGS_LABEL: 'Etichette (opzionale, per filtrare dopo):',\n TAGS_PLACEHOLDER: 'smoke, login, regressione…',\n ADD_TAG: '+ Aggiungi',\n NO_TAGS: 'Nessuna etichetta',\n SAVE_BTN: '💾 Salva',\n SAVE_AND_EDIT: '📝 Salva e modifica',\n REMOVE_TAG_TITLE: 'Rimuovi',\n NOTES_LABEL: 'Descrizione / Note (opzionale):',\n NOTES_PLACEHOLDER: 'Cosa valida questo test, condizioni preliminari, ecc.',\n TICKET_LABEL: 'Ticket / Issue (opzionale):',\n TICKET_PLACEHOLDER: 'Es: PROJ-123, #42',\n TICKET_WARN: 'ID non valido per il provider configurato (verrà salvato comunque)', // TODO: translate\n CONFIRM_DISCARD: 'Sei sicuro di voler scartare questa registrazione? Tutti i passi registrati andranno persi.',\n CONFIRM_DISCARD_BTN: 'Sì, scarta',\n BACK_BTN: 'Indietro',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Nessuna etichetta',\n SELECTED_SINGULAR: 'selezionato',\n SELECTED_PLURAL: 'selezionati',\n DESCRIBE_PLACEHOLDER: 'Nome del describe (opzionale)',\n COPY_DESCRIBE: '🗂 Copia describe()',\n MULTI_SELECT: '🗂 Multi-selezione',\n CANCEL_SELECT: '✕ Annulla',\n COPY_CMDS_BTN: '📋 Copia comandi',\n COPY_ICPS_BTN: '📋 Copia interceptor',\n DEFAULT_DESCRIBE: 'Suite di test',\n NO_TESTS: 'Nessun test salvato',\n DELETE_TITLE: 'Elimina',\n GROUP_BY_TICKET: '🎫 Raggruppa per ticket',\n UNGROUP_TICKET: '🎫 Separa',\n NO_TICKET: 'Senza ticket',\n TICKET_LINK_TITLE: 'Apri ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Lingua',\n LANG_FIELD: 'Interfaccia',\n HTTP_SECTION: '⚡ HTTP Avanzato',\n HTTP_TITLE: 'Validazioni del body',\n HTTP_SUB: 'GET → risposta · POST/PUT → richiesta',\n FIXTURE_SECTION: '🧪 Fixture HTTP',\n FIXTURE_TITLE: 'Registra le risposte come fixture',\n FIXTURE_SUB: 'Le GET vengono salvate in cypress/fixtures e stubbate con cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Strategia selettore',\n SELECTOR_LABEL: 'Attributo preferito per cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (predefinito)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#elemento)',\n SELECTOR_HINT: 'Il registratore cercherà prima questo attributo. Se assente, proverà gli altri.',\n FOLDER_SECTION: '📁 Cartella Cypress',\n FOLDER_CONNECTED: 'connesso —',\n FOLDER_NOT_SET: 'non configurato',\n FOLDER_CHANGE_BTN: '📁 Cambia cartella',\n FOLDER_SELECT_BTN: '📁 Seleziona cartella',\n FOLDER_REVOKE_BTN: '✕ Revoca accesso',\n DATA_SECTION: '💾 Dati',\n DATA_DESC: 'Esporta tutti i tuoi test in JSON o importa un backup.',\n EXPORT_BTN: '⬆️ Esporta test',\n EXPORT_DIALOG_TITLE: '⬆️ Esporta test',\n EXPORT_MODE_ALL: 'Tutto',\n EXPORT_MODE_MANUAL: 'Selezione manuale',\n EXPORT_MODE_TAGS: 'Per tag',\n EXPORT_ALL_DESC: 'Verranno esportati tutti i test salvati.',\n EXPORT_COUNT: 'Da esportare:',\n EXPORT_CONFIRM: '⬆️ Esporta',\n EXPORT_CANCEL: 'Annulla',\n EXPORT_EMPTY: 'Nessun test da esportare.',\n EXPORT_NO_TAGS: 'Nessun tag disponibile.',\n EXPORT_TAGS_HINT: 'Seleziona uno o più tag per vedere quali test verranno esportati.',\n EXPORT_RESULT_LABEL: 'Test che verranno esportati:',\n IMPORT_BTN: '⬇️ Importa test',\n FOLDER_UPDATED_TOAST: '✓ Cartella Cypress aggiornata',\n FOLDER_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\n IMPORT_SUCCESS: 'Dati importati correttamente.',\n IMPORT_ERROR: \"Errore durante l'importazione.\",\n JSON_INVALID: 'Il file non è un JSON valido.',\n JSON_BAD_FORMAT: 'Il file non ha il formato previsto.',\n SMART_SELECTOR_SECTION: '🔍 Selettore intelligente',\n SMART_SELECTOR_TITLE: 'Selettore intelligente',\n SMART_SELECTOR_SUB: 'Mostra un selettore quando si fa clic su elementi senza selettore valido.',\n START_HIDDEN_SECTION: '👁 Visibilità del widget',\n START_HIDDEN_TITLE: 'Avvia nascosto',\n START_HIDDEN_SUB: 'Il widget si avvia invisibile. Usa Ctrl+Shift+E per mostrarlo o nasconderlo.',\n RESUME_TTL_SECTION: '⏱ Continuità di registrazione',\n RESUME_TTL_LABEL: 'Riprendi senza chiedere (minuti)',\n RESUME_TTL_HINT: 'Se ricarichi o cambi progetto, una registrazione attiva riprende senza chiedere entro questo intervallo. Trascorso, ti chiederà se continuare o annullare.',\n WIDGET_POSITION_SECTION: '🧲 Posizione del widget',\n WIDGET_POSITION_HINT: 'Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.',\n WIDGET_POSITION_RESET_BTN: '↺ Reimposta posizione',\n WIDGET_POSITION_RESET_DONE: '✓ Posizione reimpostata',\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\n ISSUE_TRACKER_TITLE: 'Collega i test ai ticket',\n ISSUE_TRACKER_SUB: \"Aggiungi un ID ticket al salvataggio e genera un link cliccabile nell'elenco.\",\n ISSUE_TRACKER_PROVIDER: 'Provider',\n ISSUE_TRACKER_BASE_URL: 'URL base',\n ISSUE_TRACKER_BASE_URL_PH: 'Es: https://mioprogetto.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Non configurato',\n LOGIN_SETUP_SET_UP_BTN: 'Configura',\n LOGIN_SETUP_TITLE: 'Configurazione del login',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Crea scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Seleziona file esistente',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nome del file',\n LOGIN_SETUP_FILE_NAME_PH: 'Es: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-scansiona',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Funzioni rilevate',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Assegnazione dei blocchi',\n LOGIN_SETUP_NO_FUNCTIONS: 'Nessuna funzione esportata trovata. Compila lo scaffold e ri-scansiona.',\n LOGIN_SETUP_BEFORE_LABEL: 'Funzione before() (una volta per suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Funzione beforeEach() (prima di ogni test)',\n LOGIN_SETUP_NONE_OPTION: '— Nessuna —',\n LOGIN_SETUP_SUMMARY: 'File: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Salva',\n LOGIN_SETUP_CLEAR_BTN: 'Rimuovi configurazione',\n LOGIN_SETUP_CANCEL_BTN: 'Annulla',\n LOGIN_SETUP_SOURCE_LABEL: 'Sorgente del file di login',\n LOGIN_SETUP_CREATE_SUB: 'Genera uno scaffold con funzioni di esempio',\n LOGIN_SETUP_SELECT_SUB: 'Punta a un file di servizio di login esistente',\n LOGIN_SETUP_INJECT_TITLE: 'Aggiungere i blocchi di login?',\n LOGIN_SETUP_INJECT_TEXT: 'Questo file non contiene i blocchi di login configurati. Vuoi aggiungere l\\'import e i blocchi before/beforeEach ora?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Sì, aggiungi',\n },\n SELECTOR_PICKER: {\n TITLE: 'Seleziona un elemento DOM',\n PREVIEW_LABEL: 'navigare',\n CONFIRM_HINT: 'confermare',\n CANCEL_HINT: 'annullare',\n QUALITY_EXCELLENT: 'Eccellente — attributo di test presente (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Buono — id valido',\n QUALITY_ACCEPTABLE: 'Accettabile — solo classi CSS',\n QUALITY_POOR: 'Sconsigliato — solo tag o stile inline',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptor',\n COPY_CMDS_BTN: '📋 Copia comandi',\n SHOW_INTERCEPTORS: '▼ Vedi interceptor',\n HIDE_INTERCEPTORS: '▲ Nascondi interceptor',\n SECTION_COMMANDS: 'Comandi',\n NO_CMDS_YET: 'Ancora nessun comando',\n NO_ICP_SHORT: 'Nessun interceptor',\n COPY_ICP_BTN: '📋 Copia interceptor',\n UP_TITLE: 'Su',\n DOWN_TITLE: 'Giù',\n DEL_TITLE: 'Elimina',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Riattiva accesso',\n PERMISSION_EXPIRED: '🔑 Autorizzazione scaduta',\n PERMISSION_EXPIRED_HINT: \"Clicca per riattivare l'accesso alla cartella Cypress.\",\n NO_ACCESS: '🔒 Nessun accesso ai file locali',\n NO_ACCESS_HINT: \"Configura l'accesso in ⚙️ Config.\",\n NO_FILES: 'Nessun file',\n SELECT_FILE: \"← Seleziona un file dall'albero\",\n IT_LABEL: '🧪 it() da inserire:',\n COPY_IT_BTN: '📋 Copia it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptor:',\n COPY_ICP_BTN: '📋 Copia interceptor',\n INSERT_BTN: '💾 Inserisci nel file',\n EDIT_MANUAL_BTN: '✏️ Modifica manualmente',\n CLOSE_BTN: '✕ Chiudi',\n NEW_FILE_BTN: '+ Nuovo file',\n NEW_FOLDER_BTN: '+ Nuova cartella',\n REFRESH_BTN: '↻ Aggiorna',\n NEW_FILE_PLACEHOLDER: 'nome-del-test',\n NEW_FOLDER_PLACEHOLDER: 'nome-cartella',\n NEW_FILE_CONFIRM: 'Crea',\n NEW_FILE_CANCEL: 'Annulla',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Nessun file',\n COPY_TITLE: \"Copia il contenuto dell'editor\",\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copia',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: \"Nessuna modifica rispetto all'originale\",\n NO_CHANGES_SHORT: 'Nessuna modifica',\n LAUNCH_BTN: '▶ Esegui test',\n LAUNCH_LOCAL_ONLY: 'Spostati in locale per poter testare',\n LAUNCH_RUNNING: '⏳ Esecuzione…',\n LAUNCH_PASSED: '✓ Test superato',\n LAUNCH_FAILED: '✗ Test fallito',\n LAUNCH_NO_RUNNER: \"Nessun runner locale rilevato (l'hai avviato?)\",\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Salva',\n CLOSE_BTN: '✕ Chiudi',\n BACK_TO_EDITOR: \"← Torna all'editor\",\n INSERT_BTN: '🪄 Inserisci blocchi',\n INSERT_TITLE: \"Inserisci it() e beforeEach() nel contenuto dell'editor\",\n INSERT_DONE: \"Blocchi inseriti nell'editor\",\n INSERT_ERROR: 'Nessun blocco describe() valido trovato nel file',\n },\n RECORDER: {\n FS_TITLE: '📁 Accesso ai file',\n FS_LATER_BTN: 'Non ora',\n FS_SELECT_BTN: '📁 Seleziona cartella',\n FS_SUCCESS_TOAST: '✓ Cartella Cypress configurata',\n FS_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">editor avanzato</strong> può inserire i tuoi test direttamente nei file <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> di Cypress.',\n FS_STRUCTURE_HINT_HTML: 'Seleziona la cartella che contiene la sottocartella <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'estensione si aspetta questa struttura:',\n FS_TREE_PICK_HINT: '← seleziona questa cartella',\n FS_TREE_READ_HINT: '← l\\'estensione leggerà qui',\n FS_PERMISSION_NOTE: 'Il permesso viene salvato nel browser e non sarà richiesto di nuovo.',\n ASSERTION_SECTION: '➕ Aggiungi asserzione',\n ASSERT_SELECTOR_PH: 'selettore, es: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'valore atteso',\n ASSERT_ADD_BTN: '➕ Aggiungi',\n FILE_EDITOR_TITLE: '✏️ Editor di file',\n FILE_SAVED_TOAST: '✓ File salvato',\n FILE_SAVE_ERROR_TOAST: 'Errore durante il salvataggio',\n FIXTURES_WRITTEN_TOAST: '✓ Fixture scritte in cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'Impossibile scrivere le fixture (configura la cartella Cypress)',\n FILE_UPLOAD_MANUAL_TOAST: 'Aggiungi {files} a cypress/fixtures/ prima di eseguire il test.', // TODO: translate\n FILE_UPLOAD_COPIED_TOAST: '{files} copiato/i in cypress/fixtures/.', // TODO: translate\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Impossibile copiare {files} in cypress/fixtures/. Aggiungilo manualmente.', // TODO: translate\n BTN_CONFIG: 'Config',\n BTN_FILES: 'File',\n BTN_COMMANDS: 'Comandi',\n BTN_TESTS: 'Test',\n PAUSE_TITLE: 'Pausa (Ctrl+P)',\n RESUME_TITLE: 'Riprendi (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSA',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Ferma (Ctrl+R)',\n START_TITLE: 'Registra (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Registrazione in corso',\n SESSION_RESUME_TEXT: 'C\\'è una registrazione attiva non terminata.',\n SESSION_RESUME_COUNT: 'comandi catturati',\n SESSION_CONTINUE_BTN: 'Continua a registrare',\n SESSION_DISCARD_BTN: 'Annulla',\n BTN_HELP: 'Aiuto',\n },\n HELP: {\n TITLE: '❓ Aiuto — Guida rapida',\n INTRO: 'Tutto ciò che il registratore sa fare.',\n SEC_RECORDING: '⏺ Registrare',\n RECORDING_1: 'Premi ⏺ (o Ctrl+R) per iniziare; ⏹ per fermare e salvare.',\n RECORDING_2: 'Pausa / ripresa con ⏸ (o Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Scorciatoie da tastiera',\n SC_RECORD: 'Ctrl+R — Registra / ferma',\n SC_PAUSE: 'Ctrl+P — Pausa / ripresa',\n SC_TESTS: 'Ctrl+1 — Pannello test salvati',\n SC_COMMANDS: 'Ctrl+2 — Pannello comandi',\n SC_CONFIG: 'Ctrl+3 — Impostazioni',\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostra / nascondi il widget',\n SC_HELP: 'Ctrl+Shift+H — Questo aiuto',\n SEC_CAPTURED: '🎯 Cosa viene registrato',\n CAP_CLICK: 'Click → .click()',\n CAP_DBLCLICK: 'Doppio click → .dblclick()',\n CAP_RIGHTCLICK: 'Click destro → .rightclick()',\n CAP_TYPE: 'Digitare in un campo → .clear().type(...)',\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Invio / Esc → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Cambio di rotta (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Asserzioni',\n ASSERT_1: 'Alt+click su un elemento per verificarlo senza eseguire la sua azione (testo, valore, checked o visibile).',\n ASSERT_2: 'Oppure usa il costruttore di asserzioni nel pannello Comandi.',\n SEC_PANELS: '🗂 Pannelli',\n PANEL_TESTS: '📋 Test — salvati: filtra per tag, copia, combina, esporta.',\n PANEL_COMMANDS: '⌨️ Comandi — registrazione corrente: riordina, elimina, aggiungi asserzioni.',\n PANEL_CONFIG: '⚙️ Config — lingua, selettore, HTTP, cartella Cypress, login setup, dati, visibilità, posizione.',\n PANEL_FILES: '📁 File — inserisci test nei tuoi .cy.ts e avvia il runner.',\n SEC_SELECTOR: '🔎 Selettori',\n SELECTOR_1: 'Scegli l\\'attributo preferito (data-cy, data-testid, aria-label, id) in Config.',\n SELECTOR_2: 'Se un click non ha un selettore affidabile, appare un picker per scegliere l\\'antenato migliore.',\n SEC_DATA: '💾 Dati',\n DATA_1: 'Esporta i test in JSON (tutto / selezione / per tag).',\n DATA_2: 'Importa un JSON: si fonde con i tuoi dati (non si cancella nulla).',\n SEC_ADVANCED: '🚀 Avanzato',\n ADV_INVISIBLE: 'Modalità invisibile: start-hidden + Ctrl+Shift+E per registrare in produzione senza disturbare.',\n ADV_RUNNER: 'Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall\\'editor.',\n ADV_CROSSAPP: 'Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).',\n ADV_DRAG: 'Trascina il pulsante ⏺ per spostare il widget; la posizione viene ricordata.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (it)\n CLOSE: 'Chiudi',\n TAB_REFERENCE: 'Riferimento rapido',\n TAB_GUIDE: 'Guida all\\'uso',\n // TODO: translate (it) — usage guide body kept in Spanish for now.\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (it)\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","export const I18N_DE = {\n MAIN_FRAME: {\n SETTINGS: 'Einstellungen',\n SHOW_ADVANCED_EDITOR: 'Erweiterter Editor',\n DIALOG_SAVED_TESTS: 'Gespeicherte Tests',\n DIALOG_COMMANDS: 'Cypress-Befehle Vorschau',\n DIALOG_SAVE: 'Aufzeichnung speichern?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Testbeschreibung',\n CANCEL: 'Abbrechen',\n ASK: 'Aufgezeichneten Test speichern?',\n YES_CONTINUE: 'Ja, weiter',\n NO_DISCARD: 'Nein, verwerfen',\n DESC_PLACEHOLDER: 'Z. B.: Erfolgreiche Anmeldung mit gültigen Zugangsdaten',\n TAGS_LABEL: 'Tags (optional, zum späteren Filtern):',\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\n ADD_TAG: '+ Hinzufügen',\n NO_TAGS: 'Keine Tags',\n SAVE_BTN: '💾 Speichern',\n SAVE_AND_EDIT: '📝 Speichern und bearbeiten',\n REMOVE_TAG_TITLE: 'Entfernen',\n NOTES_LABEL: 'Beschreibung / Notizen (optional):',\n NOTES_PLACEHOLDER: 'Was dieser Test validiert, Voraussetzungen usw.',\n TICKET_LABEL: 'Ticket / Issue (optional):',\n TICKET_PLACEHOLDER: 'Z. B.: PROJ-123, #42',\n TICKET_WARN: 'Ungültige ID für den konfigurierten Anbieter (wird trotzdem gespeichert)', // TODO: translate\n CONFIRM_DISCARD: 'Sind Sie sicher, dass Sie diese Aufzeichnung verwerfen möchten? Alle aufgezeichneten Schritte gehen verloren.',\n CONFIRM_DISCARD_BTN: 'Ja, verwerfen',\n BACK_BTN: 'Zurück',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Keine Tags',\n SELECTED_SINGULAR: 'ausgewählt',\n SELECTED_PLURAL: 'ausgewählt',\n DESCRIBE_PLACEHOLDER: 'describe-Name (optional)',\n COPY_DESCRIBE: '🗂 describe() kopieren',\n MULTI_SELECT: '🗂 Mehrfachauswahl',\n CANCEL_SELECT: '✕ Abbrechen',\n COPY_CMDS_BTN: '📋 Befehle kopieren',\n COPY_ICPS_BTN: '📋 Interceptors kopieren',\n DEFAULT_DESCRIBE: 'Test-Suite',\n NO_TESTS: 'Keine gespeicherten Tests',\n DELETE_TITLE: 'Löschen',\n GROUP_BY_TICKET: '🎫 Nach Ticket gruppieren',\n UNGROUP_TICKET: '🎫 Gruppierung aufheben',\n NO_TICKET: 'Kein Ticket',\n TICKET_LINK_TITLE: 'Ticket öffnen',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Sprache',\n LANG_FIELD: 'Oberfläche',\n HTTP_SECTION: '⚡ Erweitertes HTTP',\n HTTP_TITLE: 'Body-Validierungen',\n HTTP_SUB: 'GET → Antwort · POST/PUT → Anfrage',\n FIXTURE_SECTION: '🧪 HTTP-Fixtures',\n FIXTURE_TITLE: 'Antworten als Fixtures aufzeichnen',\n FIXTURE_SUB: 'GET-Antworten werden in cypress/fixtures gespeichert und mit cy.intercept({ fixture }) gestubbt.',\n SELECTOR_SECTION: '🎯 Selector-Strategie',\n SELECTOR_LABEL: 'Bevorzugtes Attribut für cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (Standard)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#element)',\n SELECTOR_HINT: 'Der Recorder sucht zuerst nach diesem Attribut. Falls nicht gefunden, versucht er die anderen.',\n FOLDER_SECTION: '📁 Cypress-Ordner',\n FOLDER_CONNECTED: 'verbunden —',\n FOLDER_NOT_SET: 'nicht konfiguriert',\n FOLDER_CHANGE_BTN: '📁 Ordner wechseln',\n FOLDER_SELECT_BTN: '📁 Ordner auswählen',\n FOLDER_REVOKE_BTN: '✕ Zugriff widerrufen',\n DATA_SECTION: '💾 Daten',\n DATA_DESC: 'Exportieren Sie alle Tests als JSON oder importieren Sie ein Backup.',\n EXPORT_BTN: '⬆️ Tests exportieren',\n EXPORT_DIALOG_TITLE: '⬆️ Tests exportieren',\n EXPORT_MODE_ALL: 'Alle',\n EXPORT_MODE_MANUAL: 'Manuelle Auswahl',\n EXPORT_MODE_TAGS: 'Nach Tags',\n EXPORT_ALL_DESC: 'Alle gespeicherten Tests werden exportiert.',\n EXPORT_COUNT: 'Zu exportieren:',\n EXPORT_CONFIRM: '⬆️ Exportieren',\n EXPORT_CANCEL: 'Abbrechen',\n EXPORT_EMPTY: 'Keine Tests zum Exportieren.',\n EXPORT_NO_TAGS: 'Keine Tags verfügbar.',\n EXPORT_TAGS_HINT: 'Wähle ein oder mehrere Tags, um zu sehen, welche Tests exportiert werden.',\n EXPORT_RESULT_LABEL: 'Diese Tests werden exportiert:',\n IMPORT_BTN: '⬇️ Tests importieren',\n FOLDER_UPDATED_TOAST: '✓ Cypress-Ordner aktualisiert',\n FOLDER_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\n IMPORT_SUCCESS: 'Daten erfolgreich importiert.',\n IMPORT_ERROR: 'Fehler beim Importieren.',\n JSON_INVALID: 'Die Datei ist kein gültiges JSON.',\n JSON_BAD_FORMAT: 'Die Datei hat nicht das erwartete Format.',\n SMART_SELECTOR_SECTION: '🔍 Intelligenter Selektor',\n SMART_SELECTOR_TITLE: 'Intelligenter Selektor',\n SMART_SELECTOR_SUB: 'Zeigt ein Auswahlfeld, wenn auf Elemente ohne gültigen Selektor geklickt wird.',\n START_HIDDEN_SECTION: '👁 Widget-Sichtbarkeit',\n START_HIDDEN_TITLE: 'Versteckt starten',\n START_HIDDEN_SUB: 'Das Widget startet unsichtbar. Verwenden Sie Ctrl+Shift+E zum Ein-/Ausblenden.',\n RESUME_TTL_SECTION: '⏱ Aufzeichnungskontinuität',\n RESUME_TTL_LABEL: 'Ohne Nachfrage fortsetzen (Minuten)',\n RESUME_TTL_HINT: 'Wenn Sie neu laden oder das Projekt wechseln, wird eine aktive Aufzeichnung innerhalb dieses Zeitfensters ohne Nachfrage fortgesetzt. Danach werden Sie gefragt, ob fortsetzen oder verwerfen.',\n WIDGET_POSITION_SECTION: '🧲 Widget-Position',\n WIDGET_POSITION_HINT: 'Ziehe den Aufnahme-Button, um ihn aus dem Weg zu schieben. Die Position wird gespeichert.',\n WIDGET_POSITION_RESET_BTN: '↺ Position zurücksetzen',\n WIDGET_POSITION_RESET_DONE: '✓ Position zurückgesetzt',\n ISSUE_TRACKER_SECTION: '🎫 Issue-Tracker',\n ISSUE_TRACKER_TITLE: 'Tests mit Tickets verknüpfen',\n ISSUE_TRACKER_SUB: 'Füge beim Speichern eine Ticket-ID hinzu und erstelle einen klickbaren Link.',\n ISSUE_TRACKER_PROVIDER: 'Anbieter',\n ISSUE_TRACKER_BASE_URL: 'Basis-URL',\n ISSUE_TRACKER_BASE_URL_PH: 'Z. B.: https://meinprojekt.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Nicht konfiguriert',\n LOGIN_SETUP_SET_UP_BTN: 'Einrichten',\n LOGIN_SETUP_TITLE: 'Login-Konfiguration',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Scaffold erstellen',\n LOGIN_SETUP_SELECT_EXISTING: 'Vorhandene Datei auswählen',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Dateiname',\n LOGIN_SETUP_FILE_NAME_PH: 'Z. B.: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Erneut scannen',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Erkannte Funktionen',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Blockzuweisung',\n LOGIN_SETUP_NO_FUNCTIONS: 'Keine exportierten Funktionen gefunden. Scaffold ausfüllen und erneut scannen.',\n LOGIN_SETUP_BEFORE_LABEL: 'before()-Funktion (einmal pro Suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'beforeEach()-Funktion (vor jedem Test)',\n LOGIN_SETUP_NONE_OPTION: '— Keine —',\n LOGIN_SETUP_SUMMARY: 'Datei: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Speichern',\n LOGIN_SETUP_CLEAR_BTN: 'Konfiguration entfernen',\n LOGIN_SETUP_CANCEL_BTN: 'Abbrechen',\n LOGIN_SETUP_SOURCE_LABEL: 'Quelle der Login-Datei',\n LOGIN_SETUP_CREATE_SUB: 'Scaffold mit Beispielfunktionen erstellen',\n LOGIN_SETUP_SELECT_SUB: 'Auf eine vorhandene Login-Service-Datei verweisen',\n LOGIN_SETUP_INJECT_TITLE: 'Login-Blöcke hinzufügen?',\n LOGIN_SETUP_INJECT_TEXT: 'Diese Datei enthält die konfigurierten Login-Blöcke nicht. Möchten Sie jetzt den Import und die before/beforeEach-Blöcke hinzufügen?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Ja, hinzufügen',\n },\n SELECTOR_PICKER: {\n TITLE: 'DOM-Element auswählen',\n PREVIEW_LABEL: 'navigieren',\n CONFIRM_HINT: 'bestätigen',\n CANCEL_HINT: 'abbrechen',\n QUALITY_EXCELLENT: 'Ausgezeichnet — Test-Attribut vorhanden (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Gut — gültige ID',\n QUALITY_ACCEPTABLE: 'Akzeptabel — nur CSS-Klassen',\n QUALITY_POOR: 'Nicht empfohlen — nur Tag oder Inline-Style',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptors',\n COPY_CMDS_BTN: '📋 Befehle kopieren',\n SHOW_INTERCEPTORS: '▼ Interceptors anzeigen',\n HIDE_INTERCEPTORS: '▲ Interceptors ausblenden',\n SECTION_COMMANDS: 'Befehle',\n NO_CMDS_YET: 'Noch keine Befehle',\n NO_ICP_SHORT: 'Keine Interceptors',\n COPY_ICP_BTN: '📋 Interceptors kopieren',\n UP_TITLE: 'Nach oben',\n DOWN_TITLE: 'Nach unten',\n DEL_TITLE: 'Löschen',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Zugriff reaktivieren',\n PERMISSION_EXPIRED: '🔑 Berechtigung abgelaufen',\n PERMISSION_EXPIRED_HINT: 'Klicken Sie, um den Zugriff auf Ihren Cypress-Ordner zu reaktivieren.',\n NO_ACCESS: '🔒 Kein Zugriff auf lokale Dateien',\n NO_ACCESS_HINT: 'Konfigurieren Sie den Zugriff unter ⚙️ Config.',\n NO_FILES: 'Keine Dateien',\n SELECT_FILE: '← Wählen Sie eine Datei aus dem Baum',\n IT_LABEL: '🧪 it() zum Einfügen:',\n COPY_IT_BTN: '📋 it() kopieren',\n BEFORE_EACH_LABEL: '🔀 beforeEach() Interceptors:',\n COPY_ICP_BTN: '📋 Interceptors kopieren',\n INSERT_BTN: '💾 In Datei einfügen',\n EDIT_MANUAL_BTN: '✏️ Manuell bearbeiten',\n CLOSE_BTN: '✕ Schließen',\n NEW_FILE_BTN: '+ Neue Datei',\n NEW_FOLDER_BTN: '+ Neuer Ordner',\n REFRESH_BTN: '↻ Aktualisieren',\n NEW_FILE_PLACEHOLDER: 'test-name',\n NEW_FOLDER_PLACEHOLDER: 'ordnername',\n NEW_FILE_CONFIRM: 'Erstellen',\n NEW_FILE_CANCEL: 'Abbrechen',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Keine Datei',\n COPY_TITLE: 'Editor-Inhalt kopieren',\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Kopieren',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: 'Keine Änderungen gegenüber dem Original',\n NO_CHANGES_SHORT: 'Keine Änderungen',\n LAUNCH_BTN: '▶ Test starten',\n LAUNCH_LOCAL_ONLY: 'Wechsle zu localhost, um Tests auszuführen',\n LAUNCH_RUNNING: '⏳ Läuft…',\n LAUNCH_PASSED: '✓ Test bestanden',\n LAUNCH_FAILED: '✗ Test fehlgeschlagen',\n LAUNCH_NO_RUNNER: 'Kein lokaler Runner erkannt (gestartet?)',\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Speichern',\n CLOSE_BTN: '✕ Schließen',\n BACK_TO_EDITOR: '← Zurück zum Editor',\n INSERT_BTN: '🪄 Blöcke einfügen',\n INSERT_TITLE: 'it() und beforeEach() in den Editor-Inhalt einfügen',\n INSERT_DONE: 'Blöcke in den Editor eingefügt',\n INSERT_ERROR: 'Kein gültiger describe()-Block in der Datei gefunden',\n },\n RECORDER: {\n FS_TITLE: '📁 Dateizugriff',\n FS_LATER_BTN: 'Nicht jetzt',\n FS_SELECT_BTN: '📁 Ordner auswählen',\n FS_SUCCESS_TOAST: '✓ Cypress-Ordner konfiguriert',\n FS_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\n FS_INTRO_HTML: 'Der <strong style=\"color:#e6edf3\">erweiterte Editor</strong> kann Ihre Tests direkt in die Cypress-Dateien <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> einfügen.',\n FS_STRUCTURE_HINT_HTML: 'Wählen Sie den Ordner, der den Unterordner <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> enthält. Die Erweiterung erwartet diese Struktur:',\n FS_TREE_PICK_HINT: '← diesen Ordner auswählen',\n FS_TREE_READ_HINT: '← die Erweiterung liest hier',\n FS_PERMISSION_NOTE: 'Die Berechtigung wird im Browser gespeichert und nicht erneut angefordert.',\n ASSERTION_SECTION: '➕ Assertion hinzufügen',\n ASSERT_SELECTOR_PH: 'Selektor, z. B.: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'erwarteter Wert',\n ASSERT_ADD_BTN: '➕ Hinzufügen',\n FILE_EDITOR_TITLE: '✏️ Datei-Editor',\n FILE_SAVED_TOAST: '✓ Datei gespeichert',\n FILE_SAVE_ERROR_TOAST: 'Fehler beim Speichern',\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures in cypress/fixtures geschrieben',\n FIXTURES_NO_FOLDER_TOAST: 'Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)',\n FILE_UPLOAD_MANUAL_TOAST: 'Füge {files} zu cypress/fixtures/ hinzu, bevor du den Test ausführst.', // TODO: translate\n FILE_UPLOAD_COPIED_TOAST: '{files} nach cypress/fixtures/ kopiert.', // TODO: translate\n FILE_UPLOAD_COPY_ERROR_TOAST: '{files} konnte nicht nach cypress/fixtures/ kopiert werden. Füge es manuell hinzu.', // TODO: translate\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Dateien',\n BTN_COMMANDS: 'Befehle',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pausieren (Ctrl+P)',\n RESUME_TITLE: 'Fortsetzen (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSE',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Stopp (Ctrl+R)',\n START_TITLE: 'Aufzeichnen (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Aufzeichnung läuft',\n SESSION_RESUME_TEXT: 'Es gibt eine nicht abgeschlossene aktive Aufzeichnung.',\n SESSION_RESUME_COUNT: 'erfasste Befehle',\n SESSION_CONTINUE_BTN: 'Weiter aufzeichnen',\n SESSION_DISCARD_BTN: 'Verwerfen',\n BTN_HELP: 'Hilfe',\n },\n HELP: {\n TITLE: '❓ Hilfe — Kurzanleitung',\n INTRO: 'Alles, was der Recorder kann.',\n SEC_RECORDING: '⏺ Aufzeichnen',\n RECORDING_1: 'Drücke ⏺ (oder Ctrl+R) zum Starten; ⏹ zum Stoppen und Speichern.',\n RECORDING_2: 'Pause / Fortsetzen mit ⏸ (oder Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Tastenkürzel',\n SC_RECORD: 'Ctrl+R — Aufzeichnen / stoppen',\n SC_PAUSE: 'Ctrl+P — Pausieren / fortsetzen',\n SC_TESTS: 'Ctrl+1 — Panel gespeicherte Tests',\n SC_COMMANDS: 'Ctrl+2 — Befehle-Panel',\n SC_CONFIG: 'Ctrl+3 — Einstellungen',\n SC_VISIBILITY: 'Ctrl+Shift+E — Widget ein-/ausblenden',\n SC_HELP: 'Ctrl+Shift+H — Diese Hilfe',\n SEC_CAPTURED: '🎯 Was aufgezeichnet wird',\n CAP_CLICK: 'Klick → .click()',\n CAP_DBLCLICK: 'Doppelklick → .dblclick()',\n CAP_RIGHTCLICK: 'Rechtsklick → .rightclick()',\n CAP_TYPE: 'In ein Feld tippen → .clear().type(...)',\n CAP_CHECK: 'Checkbox / Radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Routenwechsel (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Assertions',\n ASSERT_1: 'Alt+Klick auf ein Element, um es zu prüfen, ohne seine Aktion auszulösen (Text, Wert, checked oder sichtbar).',\n ASSERT_2: 'Oder nutze den Assertion-Builder im Befehle-Panel.',\n SEC_PANELS: '🗂 Panels',\n PANEL_TESTS: '📋 Tests — gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.',\n PANEL_COMMANDS: '⌨️ Befehle — aktuelle Aufzeichnung: umsortieren, löschen, Assertions hinzufügen.',\n PANEL_CONFIG: '⚙️ Config — Sprache, Selektor, HTTP, Cypress-Ordner, Login-Setup, Daten, Sichtbarkeit, Position.',\n PANEL_FILES: '📁 Dateien — Tests in deine .cy.ts einfügen und den Runner starten.',\n SEC_SELECTOR: '🔎 Selektoren',\n SELECTOR_1: 'Wähle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.',\n SELECTOR_2: 'Hat ein Klick keinen zuverlässigen Selektor, erscheint ein Picker zur Wahl des besten Vorfahren.',\n SEC_DATA: '💾 Daten',\n DATA_1: 'Tests als JSON exportieren (alle / Auswahl / nach Tags).',\n DATA_2: 'JSON importieren: wird zu deinen Daten hinzugefügt (nichts wird gelöscht).',\n SEC_ADVANCED: '🚀 Erweitert',\n ADV_INVISIBLE: 'Unsichtbarer Modus: start-hidden + Ctrl+Shift+E, um in Produktion unauffällig aufzuzeichnen.',\n ADV_RUNNER: 'Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.',\n ADV_CROSSAPP: 'Cross-App: die Aufzeichnung übersteht den Wechsel des Micro-Frontends (gleicher Origin).',\n ADV_DRAG: 'Ziehe den ⏺-Button, um das Widget zu verschieben; die Position wird gemerkt.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (de)\n CLOSE: 'Schließen',\n TAB_REFERENCE: 'Kurzreferenz',\n TAB_GUIDE: 'Nutzungsleitfaden',\n // TODO: translate (de) — usage guide body kept in Spanish for now.\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (de)\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","import { type Lang, isLang } from '../models/lang.model';\nimport { Subject } from '../utils/subject';\nimport { I18N_ES } from '../i18n/es';\nimport { I18N_EN } from '../i18n/en';\nimport { I18N_FR } from '../i18n/fr';\nimport { I18N_IT } from '../i18n/it';\nimport { I18N_DE } from '../i18n/de';\n\ntype Translations = typeof I18N_ES;\n\nexport class TranslationService {\n private readonly lang$: Subject<Lang>;\n\n private readonly translations: Record<Lang, Translations> = {\n es: I18N_ES,\n en: I18N_EN,\n fr: I18N_FR,\n it: I18N_IT,\n de: I18N_DE,\n };\n\n constructor() {\n this.lang$ = new Subject<Lang>(this.detectLang());\n }\n\n setLang(lang: Lang): void {\n this.lang$.next(lang);\n }\n\n getLang(): Lang {\n return this.lang$.getValue();\n }\n\n /** Subscribe to language changes; returns an unsubscribe function. */\n onLangChange(fn: (lang: Lang) => void): () => void {\n return this.lang$.subscribe(fn);\n }\n\n translate(key: string): string {\n const keys = key.split('.');\n let value: unknown = this.translations[this.lang$.getValue()];\n for (const k of keys) {\n value = (value as Record<string, unknown>)?.[k];\n if (value === undefined) return key;\n }\n return value as string;\n }\n\n detectLang(): Lang {\n const browserLang = navigator.language.split('-')[0];\n return isLang(browserLang) ? browserLang : 'es';\n }\n}\n\nexport const translationService = new TranslationService();\n","import { type Lang, isLang } from '../models/lang.model';\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\n\nexport class TransformationService {\n toLang(lang: string): Lang {\n return isLang(lang) ? lang : 'en';\n }\n\n generateItDescription(description: string, commands: string[]): string {\n const commandsBlock = commands.map((cmd) => normalizeBlock(cmd, ' ')).join('\\n');\n return `it('${escapeSingleQuotes(description)}', () => {\\n${commandsBlock}\\n});`;\n }\n}\n\nexport const transformationService = new TransformationService();\n","export interface DirectoryNode {\n name: string;\n kind: 'directory';\n children: (DirectoryNode | FileNode)[];\n}\n\nexport interface FileNode {\n name: string;\n kind: 'file';\n}\n\nexport class AdvancedTestTransformationService {\n insertBeforeEach(content: string, interceptors: string, alertFn?: (msg: string) => void): string {\n const match = content.match(/(describe\\s*\\(.*?{)/s);\n if (!match) {\n alertFn?.('ADVANCED_EDITOR.NO_DESCRIBE');\n return '';\n }\n const insertPos = (match.index ?? 0) + match[0].length;\n const beforeEachBlock = `\\n beforeEach(() => {\\n${interceptors} })\\n`;\n return content.slice(0, insertPos) + beforeEachBlock + content.slice(insertPos);\n }\n\n insertItBlock(content: string, itBlock: string, alertFn?: (msg: string) => void): string {\n const idx = content.lastIndexOf('})');\n if (idx === -1) {\n alertFn?.('ADVANCED_EDITOR.NO_END');\n return '';\n }\n return content.slice(0, idx) + '\\n' + itBlock + '\\n' + content.slice(idx);\n }\n\n buildBlockComment(notes: string): string {\n if (!notes.trim()) return '';\n const lines = notes.split('\\n').map(l => ` * ${l}`).join('\\n');\n return `/**\\n${lines}\\n */`;\n }\n\n isFile(file: unknown): boolean {\n return !!file && (file as FileNode).kind === 'file';\n }\n\n async scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode> {\n const result: DirectoryNode = { name: dirHandle.name, kind: 'directory', children: [] };\n for await (const entry of dirHandle.values()) {\n if (entry.kind === 'directory') {\n result.children.push(await this.scanDirectory(entry as FileSystemDirectoryHandle));\n } else {\n result.children.push({ name: entry.name, kind: 'file' });\n }\n }\n return result;\n }\n}\n\nexport const advancedTestTransformationService = new AdvancedTestTransformationService();\n","import { INPUT_TYPES } from '../models/input-types.model';\nimport type { ActiveSessionState } from '../models/active-session.model';\nimport { Subject } from '../utils/subject';\nimport { FORBIDDEN_ID_PREFIXES } from '../utils/selector-quality.utils';\nimport { inferAssertionCommand } from '../utils/assertion.utils';\nimport { escapeSingleQuotes, escapeCssAttrValue } from '../utils/code-format.utils';\n\nconst OWN_SELECTOR = '[data-cy=\"lib-e2e-cypress-for-dummys\"]';\n\nexport type SelectorStrategy = 'data-cy' | 'data-testid' | 'aria-label' | 'id';\n\n/** Generates a stable, collision-resistant session id (browser + jsdom safe). */\nfunction createSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `sess-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;\n}\n\nexport class RecordingService {\n private readonly commands$ = new Subject<string[]>([]);\n private readonly interceptors$ = new Subject<string[]>([]);\n private readonly isRecording$ = new Subject<boolean>(false);\n private readonly isPaused$ = new Subject<boolean>(false);\n private readonly selectorNotFound$ = new Subject<{ target: HTMLElement; action: 'click' } | null>(null);\n private readonly inputDebounceTimers = new Map<HTMLElement, ReturnType<typeof setTimeout>>();\n private readonly fixtures = new Map<string, string>();\n private readonly uploadedFiles = new Map<string, ArrayBuffer>();\n private readonly abort = new AbortController();\n\n selectorStrategy: SelectorStrategy = 'data-cy';\n\n /** Stable id of the current live session (null when none has started). */\n sessionId: string | null = null;\n private startedAt = 0;\n\n // Stored originals for history patching cleanup\n private readonly origPushState = history.pushState.bind(history);\n private readonly origReplaceState = history.replaceState.bind(history);\n\n constructor() {\n this.listenToAssertClicks();\n this.listenToClicks();\n this.listenToDoubleClicks();\n this.listenToContextMenu();\n this.listenToInput();\n this.listenToSelect();\n this.listenToKeys();\n this.listenToRouteChanges();\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n startRecording(): void {\n this.clearCommands();\n this.sessionId = createSessionId();\n this.startedAt = Date.now();\n this.isPaused$.next(false);\n this.isRecording$.next(true);\n this.addCommand(`cy.viewport(1900, 1200)`);\n this.addCommand(`cy.visit('${escapeSingleQuotes(window.location.pathname)}')`);\n this.addCommand(`cy.get('[data-cy=\"lib-e2e-cypress-for-dummys\"]').invoke('hide');`);\n }\n\n /**\n * Rehydrates a previously persisted session WITHOUT running the startRecording\n * bootstrap (no viewport/visit/hide). Used to continue a recording across a\n * micro-frontend crossing or a same-origin reload.\n * See docs/specs/006-cross-app-recording-continuity.md.\n */\n restoreSession(state: ActiveSessionState): void {\n this.sessionId = state.sessionId;\n this.startedAt = state.startedAt;\n this.selectorStrategy = state.selectorStrategy;\n this.commands$.next([...state.commands]);\n this.interceptors$.next([...state.interceptors]);\n this.isPaused$.next(state.isPaused);\n // isRecording last so subscribers observe a fully-populated buffer.\n this.isRecording$.next(state.isRecording);\n }\n\n /** Full snapshot of the live session for persistence. */\n getSessionSnapshot(): ActiveSessionState {\n return {\n sessionId: this.sessionId ?? createSessionId(),\n isRecording: this.isRecording$.getValue(),\n isPaused: this.isPaused$.getValue(),\n commands: this.commands$.getValue(),\n interceptors: this.interceptors$.getValue(),\n selectorStrategy: this.selectorStrategy,\n startedAt: this.startedAt,\n updatedAt: Date.now(),\n };\n }\n\n stopRecording(): void {\n this.isPaused$.next(false);\n this.isRecording$.next(false);\n }\n\n toggleRecording(): void {\n if (this.isRecording$.getValue()) {\n this.stopRecording();\n } else {\n this.startRecording();\n }\n }\n\n pauseRecording(): void {\n if (!this.isRecording$.getValue()) return;\n this.isPaused$.next(true);\n }\n\n resumeRecording(): void {\n this.isPaused$.next(false);\n }\n\n togglePause(): void {\n if (this.isPaused$.getValue()) {\n this.resumeRecording();\n } else {\n this.pauseRecording();\n }\n }\n\n addCommand(cmd: string): void {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n this.commands$.next([...this.commands$.getValue(), cmd]);\n }\n\n /** Appends a command regardless of recording/paused state (e.g. assertions added manually). */\n appendCommand(cmd: string): void {\n this.commands$.next([...this.commands$.getValue(), cmd]);\n }\n\n removeCommand(index: number): void {\n const cmds = this.commands$.getValue();\n if (index < 0 || index >= cmds.length) return;\n this.commands$.next([...cmds.slice(0, index), ...cmds.slice(index + 1)]);\n }\n\n moveCommand(from: number, to: number): void {\n const cmds = [...this.commands$.getValue()];\n if (from < 0 || to < 0 || from >= cmds.length || to >= cmds.length || from === to) return;\n const [item] = cmds.splice(from, 1);\n cmds.splice(to, 0, item);\n this.commands$.next(cmds);\n }\n\n removeInterceptor(index: number): void {\n const ints = this.interceptors$.getValue();\n if (index < 0 || index >= ints.length) return;\n this.interceptors$.next([...ints.slice(0, index), ...ints.slice(index + 1)]);\n }\n\n registerInterceptor(method: string, url: string, alias: string, fixtureFile?: string): void {\n // Only capture interceptors while actively recording — otherwise HTTP calls\n // the host app fires before recording starts (the monitor is installed on\n // mount) would leak orphan cy.intercept lines into the saved test.\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n const wildcard = escapeSingleQuotes(this.urlToWildcard(url, method));\n const command = fixtureFile\n ? `cy.intercept('${method}', '${wildcard}', { fixture: '${escapeSingleQuotes(fixtureFile)}' }).as('${alias}')`\n : `cy.intercept('${method}', '${wildcard}').as('${alias}')`;\n const current = this.interceptors$.getValue();\n if (!current.includes(command)) {\n this.interceptors$.next([...current, command]);\n }\n }\n\n /** Registers a captured response as a Cypress fixture (name → JSON content). */\n registerFixture(name: string, content: string): void {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n this.fixtures.set(name, content);\n }\n\n getFixturesSnapshot(): Array<{ name: string; content: string }> {\n return [...this.fixtures.entries()].map(([name, content]) => ({ name, content }));\n }\n\n addUploadedFile(filename: string, bytes: ArrayBuffer): void {\n this.uploadedFiles.set(filename, bytes);\n }\n\n getUploadedFilesSnapshot(): Array<{ filename: string; bytes: ArrayBuffer }> {\n return [...this.uploadedFiles.entries()].map(([filename, bytes]) => ({ filename, bytes }));\n }\n\n clearUploadedFiles(): void {\n this.uploadedFiles.clear();\n }\n\n clearCommands(): void {\n this.commands$.next([]);\n this.interceptors$.next([]);\n this.fixtures.clear();\n this.uploadedFiles.clear();\n }\n\n clearInterceptors(): void {\n this.interceptors$.next([]);\n }\n\n getCommandsSnapshot(): string[] { return this.commands$.getValue(); }\n getInterceptorsSnapshot(): string[] { return this.interceptors$.getValue(); }\n getPausedSnapshot(): boolean { return this.isPaused$.getValue(); }\n\n onCommandsChange(fn: (cmds: string[]) => void): () => void {\n return this.commands$.subscribe(fn);\n }\n\n onInterceptorsChange(fn: (ints: string[]) => void): () => void {\n return this.interceptors$.subscribe(fn);\n }\n\n onRecordingChange(fn: (isRecording: boolean) => void): () => void {\n return this.isRecording$.subscribe(fn);\n }\n\n onPauseChange(fn: (isPaused: boolean) => void): () => void {\n return this.isPaused$.subscribe(fn);\n }\n\n /**\n * Fires a full session snapshot whenever any persisted field changes\n * (commands, interceptors, recording or paused state). Drives the debounced\n * persistence of the live session. Returns a combined unsubscribe.\n */\n onSessionChange(fn: (state: ActiveSessionState) => void): () => void {\n const emit = (): void => fn(this.getSessionSnapshot());\n const unsubs = [\n this.commands$.subscribe(emit),\n this.interceptors$.subscribe(emit),\n this.isRecording$.subscribe(emit),\n this.isPaused$.subscribe(emit),\n ];\n return () => unsubs.forEach((u) => u());\n }\n\n onSelectorNotFound(fn: (target: HTMLElement, action: 'click') => void): () => void {\n return this.selectorNotFound$.subscribe((v) => {\n if (v) fn(v.target, v.action);\n });\n }\n\n destroy(): void {\n this.abort.abort();\n history.pushState = this.origPushState;\n history.replaceState = this.origReplaceState;\n this.inputDebounceTimers.forEach((t) => clearTimeout(t));\n this.inputDebounceTimers.clear();\n }\n\n // ── DOM listeners ─────────────────────────────────────────────────────────\n\n /**\n * Alt+click captures an ASSERTION for the element instead of a click, and\n * suppresses the element's real action. Runs in the capture phase so it fires\n * before the app's handlers and before the bubble-phase click listener below\n * (stopImmediatePropagation prevents a duplicate `.click()`). See spec 009.\n */\n private listenToAssertClicks(): void {\n document.addEventListener(\n 'click',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n if (!(e as MouseEvent).altKey) return;\n const target = e.target as HTMLElement;\n if (!target || this.isOwnElement(target)) return;\n const tag = target.tagName?.toLowerCase();\n if (tag === 'body' || tag === 'html') return;\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return; // no reliable selector → leave it as a normal Alt+click\n const selector = this.getReliableSelector(container);\n if (!selector || this.isOwnSelector(selector)) return;\n // Assert-only: don't let the click perform its action or record a click.\n e.preventDefault();\n e.stopImmediatePropagation();\n const emit = (): void => this.addCommand(inferAssertionCommand(container, selector));\n // A checkbox/radio toggles its `checked` during the click's activation;\n // since we cancelled the action it is restored afterwards, so read the true\n // state on the next microtask rather than the transient toggled value.\n const type = (container.getAttribute('type') ?? '').toLowerCase();\n if (container.tagName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio')) {\n queueMicrotask(emit);\n } else {\n emit();\n }\n },\n { capture: true, signal: this.abort.signal }\n );\n }\n\n private listenToClicks(): void {\n document.addEventListener(\n 'click',\n (e: Event) => {\n if (!this.isRecording$.getValue()) return;\n const target = e.target as HTMLElement;\n if (!target || this.isOwnElement(target)) return;\n const tag = target.tagName?.toLowerCase();\n if (tag === 'body' || tag === 'html') return;\n this.handleClickEvent(target);\n },\n { signal: this.abort.signal }\n );\n }\n\n /** Centralised selector resolution for the pointer/key listeners (spec 010). */\n private resolveSelectorFor(target: HTMLElement | null): string | null {\n if (!target || this.isOwnElement(target)) return null;\n const tag = target.tagName?.toLowerCase();\n if (tag === 'body' || tag === 'html') return null;\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return null;\n const selector = this.getReliableSelector(container);\n if (!selector || this.isOwnSelector(selector)) return null;\n return selector;\n }\n\n private listenToDoubleClicks(): void {\n document.addEventListener(\n 'dblclick',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n if ((e as MouseEvent).altKey) return;\n const selector = this.resolveSelectorFor(e.target as HTMLElement);\n if (!selector) return;\n // Collapse the up-to-2 single clicks the browser fired before the dblclick.\n const safeSelector = escapeSingleQuotes(selector);\n const clickCmd = `cy.get('${safeSelector}').click()`;\n let cmds = this.commands$.getValue();\n let removed = 0;\n while (removed < 2 && cmds.length > 0 && cmds[cmds.length - 1] === clickCmd) {\n cmds = cmds.slice(0, -1);\n removed++;\n }\n if (removed > 0) this.commands$.next(cmds);\n this.addCommand(`cy.get('${safeSelector}').dblclick()`);\n },\n { signal: this.abort.signal }\n );\n }\n\n private listenToContextMenu(): void {\n document.addEventListener(\n 'contextmenu',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n const selector = this.resolveSelectorFor(e.target as HTMLElement);\n if (!selector) return;\n this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').rightclick()`);\n },\n { signal: this.abort.signal }\n );\n }\n\n /** Enter → type('{enter}'), Escape → type('{esc}'), only inside a field. */\n private listenToKeys(): void {\n document.addEventListener(\n 'keydown',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n const key = (e as KeyboardEvent).key;\n if (key !== 'Enter' && key !== 'Escape') return;\n const target = e.target as HTMLElement;\n const tag = target?.tagName?.toLowerCase();\n if (tag !== 'input' && tag !== 'textarea' && tag !== 'select') return;\n const selector = this.resolveSelectorFor(target);\n if (!selector) return;\n // Record the field's pending value before the key press.\n this.flushInputDebounce(target);\n const token = key === 'Enter' ? '{enter}' : '{esc}';\n this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').type('${token}')`);\n },\n { signal: this.abort.signal }\n );\n }\n\n private listenToInput(): void {\n document.addEventListener(\n 'input',\n (e: Event) => {\n if (!this.isRecording$.getValue()) return;\n const target = e.target as HTMLInputElement | HTMLTextAreaElement;\n if (!target || this.isOwnElement(target)) return;\n this.handleInputEvent(target);\n },\n { signal: this.abort.signal }\n );\n }\n\n private listenToSelect(): void {\n document.addEventListener(\n 'change',\n (e: Event) => {\n if (!this.isRecording$.getValue()) return;\n const target = e.target as HTMLInputElement | HTMLSelectElement;\n if (!target || this.isOwnElement(target)) return;\n const tag = target.tagName.toLowerCase();\n if (tag === 'select') {\n this.handleSelectEvent(target as HTMLSelectElement);\n } else if (tag === 'input') {\n const type = (target.getAttribute('type') ?? '').toLowerCase();\n if (type === 'file') {\n void this.handleFileInputChange(target as HTMLInputElement);\n }\n }\n },\n { signal: this.abort.signal }\n );\n }\n\n private async handleFileInputChange(target: HTMLInputElement): Promise<void> {\n if (this.isPaused$.getValue()) return;\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n const selector = this.getReliableSelector(container);\n if (!selector || this.isOwnSelector(selector)) return;\n\n const files = Array.from(target.files ?? []);\n if (!files.length) return;\n\n const paths = files.map(f => `'cypress/fixtures/${escapeSingleQuotes(f.name)}'`);\n const pathArg = paths.length === 1 ? paths[0] : `[${paths.join(', ')}]`;\n this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').selectFile(${pathArg})`);\n\n for (const file of files) {\n const bytes = await this.readFileAsArrayBuffer(file);\n this.addUploadedFile(file.name, bytes);\n }\n }\n\n private readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {\n if (typeof file.arrayBuffer === 'function') {\n return file.arrayBuffer();\n }\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(file);\n });\n }\n\n private listenToRouteChanges(): void {\n let lastUrl = window.location.pathname + window.location.search + window.location.hash;\n\n const addUrlCommand = (newUrl: string): void => {\n if (!this.isRecording$.getValue()) return;\n if (newUrl === lastUrl) return;\n this.addCommand(`cy.url().should('include', '${escapeSingleQuotes(newUrl)}')`);\n lastUrl = newUrl;\n };\n\n const wrapMethod = (type: 'pushState' | 'replaceState'): void => {\n const orig = history[type].bind(history);\n history[type] = (data: unknown, unused: string, url?: string | URL | null) => {\n const result = orig(data, unused, url);\n let newUrl = window.location.pathname + window.location.search + window.location.hash;\n if (typeof url === 'string' && url.length > 0) {\n const a = document.createElement('a');\n a.href = url;\n newUrl = a.pathname + a.search + a.hash;\n } else if (url instanceof URL) {\n newUrl = url.pathname + url.search + url.hash;\n }\n addUrlCommand(newUrl);\n return result;\n };\n };\n\n wrapMethod('pushState');\n wrapMethod('replaceState');\n\n window.addEventListener(\n 'popstate',\n () => {\n const newUrl = window.location.pathname + window.location.search + window.location.hash;\n addUrlCommand(newUrl);\n },\n { signal: this.abort.signal }\n );\n }\n\n // ── Click helpers ─────────────────────────────────────────────────────────\n\n private handleClickEvent(target: HTMLElement): void {\n // Bubble up from non-interactive span/div inside button or mat-option\n if (!this.isInteractiveElement(target)) {\n const tag = target.tagName.toLowerCase();\n if (\n (tag === 'span' || tag === 'div') &&\n target.parentElement &&\n (target.parentElement.tagName.toLowerCase() === 'button' ||\n target.parentElement.tagName.toLowerCase() === 'mat-option') &&\n (target.parentElement.hasAttribute('data-cy') || target.parentElement.hasAttribute('id'))\n ) {\n target = target.parentElement;\n }\n const matSelect = target.closest('mat-select');\n if (matSelect) {\n const sel = this.getReliableSelector(matSelect as HTMLElement);\n if (sel) {\n this.addCommand(`cy.get('${sel}').click()`);\n } else {\n this.selectorNotFound$.next({ target: matSelect as HTMLElement, action: 'click' });\n }\n return;\n }\n\n // Ignore decorative/non-interactive elements (divs, paragraphs, headings…).\n // Re-target to the nearest interactive ancestor if one exists.\n if (!this.isInteractiveElement(target)) {\n const interactive = target.closest<HTMLElement>(\n 'button,a,input,select,textarea,label,summary,mat-option,' +\n '[role=\"button\"],[role=\"link\"],[role=\"menuitem\"],[role=\"option\"],[role=\"tab\"]'\n );\n if (!interactive) return;\n target = interactive;\n }\n }\n\n const tag = target.tagName.toLowerCase();\n if (tag === 'input' || tag === 'textarea' || tag === 'select') {\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) { this.selectorNotFound$.next({ target, action: 'click' }); return; }\n // Checkbox/radio → check()/uncheck(); other input clicks stay a no-op (the\n // value is captured via the `input` event). Runs in the bubble phase, so\n // `checked` already reflects the post-click state (spec 010).\n if (tag === 'input') {\n const input = target as HTMLInputElement;\n const type = (input.getAttribute('type') ?? '').toLowerCase();\n if (type === 'checkbox' || type === 'radio') {\n const selector = this.getReliableSelector(container);\n if (selector && !this.isOwnSelector(selector)) {\n const action = type === 'radio' || input.checked ? 'check' : 'uncheck';\n this.addCommand(`cy.get('${selector}').${action}()`);\n }\n }\n }\n return;\n }\n\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) {\n this.selectorNotFound$.next({ target, action: 'click' });\n return;\n }\n\n const selector = this.getReliableSelector(container);\n if (selector === OWN_SELECTOR) return;\n\n if (tag === 'mat-option') {\n this.handleMatOptionClick(target, selector);\n return;\n }\n\n if (!selector) {\n this.selectorNotFound$.next({ target, action: 'click' });\n return;\n }\n\n this.addGenericCommand({\n selector,\n action: (s) => `cy.get('${s}').click()`,\n });\n }\n\n private handleMatOptionClick(target: HTMLElement, selector: string | null): void {\n const matSelect = target.closest('mat-select');\n let dataCy: string | null = null;\n if (matSelect) dataCy = matSelect.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\n if (!dataCy) dataCy = target.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\n if (dataCy) {\n const safeSel = escapeSingleQuotes(`[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`);\n this.addCommand(`cy.get('${safeSel}').click()`);\n return;\n }\n if (selector) {\n this.addCommand(`cy.get('${selector}').eq(0).click()`);\n } else {\n this.selectorNotFound$.next({ target, action: 'click' });\n }\n }\n\n // ── Input helpers ─────────────────────────────────────────────────────────\n\n private handleInputEvent(target: HTMLInputElement | HTMLTextAreaElement): void {\n const tag = target.tagName.toLowerCase();\n const isText = tag === 'textarea' || (tag === 'input' && (INPUT_TYPES as readonly string[]).includes(target.type));\n if (!isText) return;\n\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n\n if (this.inputDebounceTimers.has(target)) {\n clearTimeout(this.inputDebounceTimers.get(target));\n }\n this.inputDebounceTimers.set(\n target,\n setTimeout(() => {\n this.inputDebounceTimers.delete(target);\n this.recordInputValue(target);\n }, 1000)\n );\n }\n\n /** Records a text field's current value as a `clear().type()` command. */\n private recordInputValue(target: HTMLInputElement | HTMLTextAreaElement): void {\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n const selector = this.getReliableSelector(container);\n const value = escapeSingleQuotes(target.value);\n this.addGenericCommand({\n selector,\n action: (s) => `cy.get('${s}').clear().type('${value}')`,\n });\n }\n\n /** Flushes any pending debounced value for an element, recording it now. */\n private flushInputDebounce(target: HTMLElement): void {\n const timer = this.inputDebounceTimers.get(target);\n if (timer === undefined) return;\n clearTimeout(timer);\n this.inputDebounceTimers.delete(target);\n this.recordInputValue(target as HTMLInputElement | HTMLTextAreaElement);\n }\n\n // ── Select helpers ────────────────────────────────────────────────────────\n\n private handleSelectEvent(target: HTMLSelectElement): void {\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n const selector = this.getReliableSelector(container);\n const value = escapeSingleQuotes(target.value);\n this.addGenericCommand({\n selector,\n action: (s) => `cy.get('${s}').select('${value}')`,\n });\n }\n\n // ── Shared helpers ────────────────────────────────────────────────────────\n\n private addGenericCommand(opts: {\n selector: string | null;\n action: (s: string) => string;\n }): void {\n if (!opts.selector || this.isOwnSelector(opts.selector)) return;\n this.addCommand(opts.action(escapeSingleQuotes(opts.selector)));\n }\n\n private getReliableSelector(el: HTMLElement): string | null {\n const strategy = this.selectorStrategy;\n const dataCy = el.getAttribute('data-cy');\n const dataTestid = el.getAttribute('data-testid');\n const ariaLabel = el.getAttribute('aria-label');\n const dataDotCy = el.getAttribute('data.cy');\n\n const rawId = el.id;\n const validId = rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId) ? rawId : null;\n\n switch (strategy) {\n case 'data-testid':\n if (dataTestid) return `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]`;\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n return validId ? `#${validId}` : null;\n case 'aria-label':\n if (ariaLabel) return `[aria-label=\"${escapeCssAttrValue(ariaLabel)}\"]`;\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n return validId ? `#${validId}` : null;\n case 'id':\n if (validId) return `#${validId}`;\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n return dataTestid ? `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]` : null;\n default: // 'data-cy'\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n if (dataDotCy) return `[data.cy=\"${escapeCssAttrValue(dataDotCy)}\"]`;\n return validId ? `#${validId}` : null;\n }\n }\n\n private isInteractiveElement(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName.toLowerCase();\n return ['select', 'option', 'input', 'textarea', 'button'].includes(tag);\n }\n\n private isOwnSelector(selector: string | null): boolean {\n return selector === OWN_SELECTOR;\n }\n\n private isOwnElement(target: HTMLElement): boolean {\n return !!target.closest('[data-cy=\"lib-e2e-cypress-for-dummys\"]');\n }\n\n private urlToWildcard(url: string, method: string): string {\n const u = new URL(url, 'http://localhost');\n if (method.toUpperCase() === 'GET' && u.search) {\n return `**${u.pathname}/**`;\n }\n return `**${u.pathname}`;\n }\n}\n","import { escapeSingleQuotes } from './code-format.utils';\n\n/** Longest visible-text snippet turned into a `contain.text` assertion. */\nconst MAX_TEXT_LENGTH = 60;\n\n/**\n * Infers a sensible Cypress assertion for an element, given the selector already\n * resolved for it (spec 009 — Alt+click assertion capture):\n *\n * - checkbox / radio → should('be.checked' | 'not.be.checked')\n * - input/textarea/select → should('have.value', '<value>') (or be.visible if empty)\n * - short visible text → should('contain.text', '<text>')\n * - otherwise → should('be.visible')\n *\n * All embedded values/text are single-quote escaped so the generated command is\n * always valid JS.\n */\nexport function inferAssertionCommand(el: HTMLElement, selector: string): string {\n const safeSelector = escapeSingleQuotes(selector);\n const should = (body: string): string => `cy.get('${safeSelector}').should(${body})`;\n const tag = el.tagName.toLowerCase();\n\n if (tag === 'input') {\n const input = el as HTMLInputElement;\n const type = (input.getAttribute('type') ?? 'text').toLowerCase();\n if (type === 'checkbox' || type === 'radio') {\n return should(`'${input.checked ? 'be.checked' : 'not.be.checked'}'`);\n }\n return input.value\n ? should(`'have.value', '${escapeSingleQuotes(input.value)}'`)\n : should(`'be.visible'`);\n }\n\n if (tag === 'textarea' || tag === 'select') {\n const value = (el as HTMLTextAreaElement | HTMLSelectElement).value;\n return value\n ? should(`'have.value', '${escapeSingleQuotes(value)}'`)\n : should(`'be.visible'`);\n }\n\n const text = (el.textContent ?? '').replace(/\\s+/g, ' ').trim();\n if (text && text.length <= MAX_TEXT_LENGTH) {\n return should(`'contain.text', '${escapeSingleQuotes(text)}'`);\n }\n return should(`'be.visible'`);\n}\n","import { openDB, type IDBPDatabase } from 'idb';\nimport { DB_SCHEMA } from '../models/db-schema.model';\nimport type { ActiveSessionState } from '../models/active-session.model';\nimport type { LoginSetupConfig } from '../models/login-setup.model';\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\nimport { buildTicketComment } from '../utils/ticket.utils';\n\n/** Fixed primary key for the single active-session record. */\nconst ACTIVE_SESSION_ID = 1;\n\ninterface TestRecord { id: number; name: string; createdAt: number; tags?: string[]; notes?: string; ticketId?: string; }\ninterface CommandRecord { id: number; command: string; testId: number; createdAt: number; }\ninterface InterceptorRecord { id: number; interceptor: string; testId: number; createdAt: number; }\ninterface ConfigRecord { id: number; [key: string]: unknown; }\n\nexport interface TestWithDetails extends TestRecord {\n commands: string[];\n interceptors: string[];\n}\n\nexport interface TestDetail extends TestWithDetails {\n cypressCommands: string[];\n itBlock: string;\n interceptorsBlock: string;\n}\n\nexport class PersistenceService {\n private _db: Promise<IDBPDatabase> | null = null;\n\n // dbName is overridable so tests can use unique names for isolation.\n constructor(private readonly dbName: string = DB_SCHEMA.name) {}\n\n private getDB(): Promise<IDBPDatabase> {\n if (!this._db) {\n this._db = openDB(this.dbName, DB_SCHEMA.version, {\n upgrade(database) {\n for (const store of DB_SCHEMA.stores) {\n if (!database.objectStoreNames.contains(store.name)) {\n const os = database.createObjectStore(store.name, {\n keyPath: store.keyPath,\n autoIncrement: store.autoIncrement,\n });\n for (const index of store.indexes) {\n os.createIndex(index.name, index.keyPath, { unique: index.unique });\n }\n }\n }\n },\n });\n }\n return this._db as Promise<IDBPDatabase>;\n }\n\n // ── Tests ─────────────────────────────────────────────────────────────────\n\n async insertTest(name: string, commands: string[] = [], interceptors: string[] = [], tags: string[] = [], notes?: string, ticketId?: string): Promise<number> {\n const db = await this.getDB();\n const record: Omit<TestRecord, 'id'> = { name, createdAt: Date.now(), ...(tags.length ? { tags } : {}), ...(notes ? { notes } : {}), ...(ticketId ? { ticketId } : {}) };\n const id = await db.add('tests', record) as number;\n if (commands.length) await this.insertCommands(commands, id);\n if (interceptors.length) await this.insertInterceptors(interceptors, id);\n return id;\n }\n\n async getAllTests(): Promise<TestWithDetails[]> {\n const db = await this.getDB();\n const tests = await db.getAll('tests') as TestRecord[];\n return Promise.all(\n tests.map(async (test) => ({\n ...test,\n commands: await this.getCommandStrings(test.id),\n interceptors: await this.getInterceptorStrings(test.id),\n }))\n );\n }\n\n async getTestById(testId: number): Promise<TestDetail | null> {\n const db = await this.getDB();\n const record = await db.get('tests', testId) as TestRecord | undefined;\n if (!record) return null;\n\n const commands = await this.getCommandStrings(testId);\n const interceptors = await this.getInterceptorStrings(testId);\n const ticketComment = record.ticketId ? buildTicketComment(record.ticketId) + '\\n' : '';\n const itBlock = `${ticketComment}it('${escapeSingleQuotes(record.name)}', () => {\\n${commands.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\n const interceptorsBlock = interceptors.length\n ? ' // Auto-generated Cypress interceptors\\n' +\n interceptors.map(i => normalizeBlock(i, ' ')).join('\\n') + '\\n'\n : '';\n\n return { ...record, commands, interceptors, cypressCommands: commands, itBlock, interceptorsBlock };\n }\n\n async deleteTest(id: number): Promise<void> {\n const db = await this.getDB();\n await db.delete('tests', id);\n await this.deleteCommandsByTestId(id);\n await this.deleteInterceptorsByTestId(id);\n }\n\n // ── Commands ──────────────────────────────────────────────────────────────\n\n async insertCommands(commands: string[], testId: number): Promise<void> {\n const db = await this.getDB();\n await Promise.all(\n commands.map((command) => db.add('commands', { command, testId, createdAt: Date.now() }))\n );\n }\n\n async getCommandsByTestId(testId: number): Promise<CommandRecord[]> {\n const db = await this.getDB();\n return db.getAllFromIndex('commands', 'testId', testId) as Promise<CommandRecord[]>;\n }\n\n private async getCommandStrings(testId: number): Promise<string[]> {\n return (await this.getCommandsByTestId(testId)).map((r) => r.command).filter(Boolean);\n }\n\n private async deleteCommandsByTestId(testId: number): Promise<void> {\n const db = await this.getDB();\n const rows = await this.getCommandsByTestId(testId);\n const tx = db.transaction('commands', 'readwrite');\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\n await tx.done;\n }\n\n // ── Interceptors ──────────────────────────────────────────────────────────\n\n async insertInterceptors(interceptors: string[], testId: number): Promise<void> {\n const db = await this.getDB();\n await Promise.all(\n interceptors.map((interceptor) => db.add('interceptors', { interceptor, testId, createdAt: Date.now() }))\n );\n }\n\n async getInterceptorsByTestId(testId: number): Promise<InterceptorRecord[]> {\n const db = await this.getDB();\n return db.getAllFromIndex('interceptors', 'testId', testId) as Promise<InterceptorRecord[]>;\n }\n\n private async getInterceptorStrings(testId: number): Promise<string[]> {\n return (await this.getInterceptorsByTestId(testId)).map((r) => r.interceptor).filter(Boolean);\n }\n\n async deleteInterceptorsByTestId(testId: number): Promise<void> {\n const db = await this.getDB();\n const rows = await this.getInterceptorsByTestId(testId);\n const tx = db.transaction('interceptors', 'readwrite');\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\n await tx.done;\n }\n\n // ── Configuration ─────────────────────────────────────────────────────────\n\n async setConfig(config: Record<string, unknown>): Promise<void> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n const current = records[0] ?? {};\n const merged = { ...current, ...config };\n if ((current as ConfigRecord).id) {\n await db.put('configuration', merged);\n } else {\n await db.add('configuration', merged);\n }\n }\n\n async setConfigKey(key: string, value: unknown): Promise<void> {\n return this.setConfig({ [key]: value });\n }\n\n async getConfig(key: string): Promise<Record<string, unknown> | null> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n if (!records.length) return null;\n const config = records[0];\n return Object.prototype.hasOwnProperty.call(config, key) ? { [key]: config[key] } : null;\n }\n\n async getGeneralConfig(): Promise<ConfigRecord | null> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n return records[0] ?? null;\n }\n\n // ── Login setup config ───────────────────────────────────────────────────\n\n private static readonly LOGIN_SETUP_KEY = 'loginSetupConfig';\n\n async saveLoginSetup(config: LoginSetupConfig): Promise<void> {\n await this.setConfigKey(PersistenceService.LOGIN_SETUP_KEY, JSON.stringify(config));\n }\n\n async getLoginSetup(): Promise<LoginSetupConfig | null> {\n const record = await this.getConfig(PersistenceService.LOGIN_SETUP_KEY);\n if (!record) return null;\n const raw = record[PersistenceService.LOGIN_SETUP_KEY];\n if (typeof raw !== 'string') return null;\n try { return JSON.parse(raw) as LoginSetupConfig; } catch { return null; }\n }\n\n async clearLoginSetup(): Promise<void> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n if (!records.length) return;\n const current = { ...records[0] };\n delete current[PersistenceService.LOGIN_SETUP_KEY];\n await db.put('configuration', current);\n }\n\n // ── Active recording session ──────────────────────────────────────────────\n\n /** Upserts the live recording session (single record, fixed key). */\n async saveActiveSession(state: ActiveSessionState): Promise<void> {\n const db = await this.getDB();\n await db.put('activeSession', { ...state, id: ACTIVE_SESSION_ID });\n }\n\n /** Returns the persisted live session, or null when none is stored. */\n async getActiveSession(): Promise<ActiveSessionState | null> {\n const db = await this.getDB();\n const record = await db.get('activeSession', ACTIVE_SESSION_ID) as (ActiveSessionState & { id: number }) | undefined;\n if (!record) return null;\n const { id: _id, ...state } = record;\n return state as ActiveSessionState;\n }\n\n /** Removes the live session record. Safe to call when none exists. */\n async clearActiveSession(): Promise<void> {\n const db = await this.getDB();\n await db.delete('activeSession', ACTIVE_SESSION_ID);\n }\n\n // ── Bulk operations ───────────────────────────────────────────────────────\n\n async clearAllData(): Promise<void> {\n const db = await this.getDB();\n await Promise.all([\n db.clear('tests'),\n db.clear('commands'),\n db.clear('interceptors'),\n ]);\n }\n\n async ingestFileData(tests: Record<string, unknown>[], interceptors: Record<string, unknown>[]): Promise<void> {\n if (Array.isArray(tests)) {\n const db = await this.getDB();\n for (const test of tests) {\n // Split the nested commands/interceptors back into their own stores,\n // keyed by the freshly-assigned testId — otherwise they would be stored\n // as stray fields and silently lost on read (getAllTests reads them by\n // testId from the commands/interceptors stores).\n const { id: _id, commands, interceptors: testInterceptors, ...record } = test;\n const newId = await db.add('tests', record) as number;\n const cmds = Array.isArray(commands) ? commands as string[] : [];\n const icps = Array.isArray(testInterceptors) ? testInterceptors as string[] : [];\n if (cmds.length) await this.insertCommands(cmds, newId);\n if (icps.length) await this.insertInterceptors(icps, newId);\n }\n }\n // Back-compat: legacy files may carry top-level interceptors with their own testId.\n await this.bulkInsertWithoutId('interceptors', interceptors);\n }\n\n async hasDirectoryAccess(): Promise<boolean> {\n const config = await this.getGeneralConfig();\n return !!config?.['cypressDirectoryHandle'];\n }\n\n async writeUploadedFile(filename: string, bytes: ArrayBuffer): Promise<void> {\n const config = await this.getGeneralConfig();\n const dirHandle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\n if (!dirHandle) throw new Error('No Cypress folder configured');\n\n const perm = dirHandle as unknown as FileSystemHandleWithPermission;\n let state = await perm.queryPermission({ mode: 'readwrite' });\n if (state !== 'granted') state = await perm.requestPermission({ mode: 'readwrite' });\n if (state !== 'granted') throw new Error('Write permission denied');\n\n const fixturesDir = await dirHandle.getDirectoryHandle('fixtures', { create: true });\n const fileHandle = await fixturesDir.getFileHandle(filename, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(bytes);\n await writable.close();\n }\n\n async requestDirectoryPermissions(): Promise<void> {\n if (!('showDirectoryPicker' in window)) {\n throw new Error('File System Access API not supported');\n }\n const dirHandle = await window.showDirectoryPicker();\n await this.setConfigKey('cypressDirectoryHandle', dirHandle);\n await this.setConfigKey('allowReadWriteFiles', 'true');\n }\n\n /**\n * Writes captured fixtures into `cypress/fixtures/` using the configured Cypress\n * folder handle (spec 012). Returns the number written. Throws if no folder is\n * configured or write permission is denied.\n */\n async writeFixtures(fixtures: Array<{ name: string; content: string }>): Promise<number> {\n if (!fixtures.length) return 0;\n const config = await this.getGeneralConfig();\n const dirHandle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\n if (!dirHandle) throw new Error('No Cypress folder configured');\n\n const perm = dirHandle as unknown as FileSystemHandleWithPermission;\n let state = await perm.queryPermission({ mode: 'readwrite' });\n if (state !== 'granted') state = await perm.requestPermission({ mode: 'readwrite' });\n if (state !== 'granted') throw new Error('Write permission denied');\n\n const fixturesDir = await dirHandle.getDirectoryHandle('fixtures', { create: true });\n let written = 0;\n for (const fx of fixtures) {\n const fileHandle = await fixturesDir.getFileHandle(fx.name, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(fx.content);\n await writable.close();\n written++;\n }\n return written;\n }\n\n private async bulkInsertWithoutId(store: string, items: Record<string, unknown>[]): Promise<void> {\n if (!Array.isArray(items)) return;\n const db = await this.getDB();\n for (const item of items) {\n const { id: _id, ...rest } = item;\n await db.add(store, rest);\n }\n }\n}\n","export type IssueTrackerProvider = 'jira' | 'github' | 'gitlab' | 'azure' | 'bitbucket' | 'custom';\n\nexport interface IssueTrackerPreset {\n id: IssueTrackerProvider;\n label: string;\n urlPattern: string;\n idPattern: RegExp;\n}\n\nexport const ISSUE_TRACKER_PRESETS: Record<IssueTrackerProvider, IssueTrackerPreset> = {\n jira: { id: 'jira', label: 'Jira', urlPattern: '{baseUrl}/browse/{id}', idPattern: /^[A-Z][A-Z0-9]+-\\d+$/ },\n github: { id: 'github', label: 'GitHub Issues', urlPattern: '{baseUrl}/issues/{id}', idPattern: /^\\d+$/ },\n gitlab: { id: 'gitlab', label: 'GitLab Issues', urlPattern: '{baseUrl}/-/issues/{id}', idPattern: /^\\d+$/ },\n azure: { id: 'azure', label: 'Azure DevOps', urlPattern: '{baseUrl}/_workitems/edit/{id}', idPattern: /^\\d+$/ },\n bitbucket: { id: 'bitbucket', label: 'Bitbucket Issues',urlPattern: '{baseUrl}/issues/{id}', idPattern: /^\\d+$/ },\n custom: { id: 'custom', label: 'Custom', urlPattern: '{baseUrl}/{id}', idPattern: /.+/ },\n};\n\nexport interface IssueTrackerConfig {\n enabled: boolean;\n provider: IssueTrackerProvider;\n baseUrl: string;\n}\n\nexport const DEFAULT_ISSUE_TRACKER_CONFIG: IssueTrackerConfig = {\n enabled: false,\n provider: 'jira',\n baseUrl: '',\n};\n","import { ISSUE_TRACKER_PRESETS, type IssueTrackerConfig, type IssueTrackerProvider } from '../models/issue-tracker.model';\n\nexport function buildTicketUrl(ticketId: string, config: IssueTrackerConfig): string | null {\n if (!config.enabled || !ticketId.trim() || !config.baseUrl.trim()) return null;\n const preset = ISSUE_TRACKER_PRESETS[config.provider];\n const base = config.baseUrl.replace(/\\/+$/, '');\n return preset.urlPattern.replace('{baseUrl}', base).replace('{id}', encodeURIComponent(ticketId.trim()));\n}\n\nexport function buildTicketComment(ticketId: string): string {\n return `// Ticket: ${ticketId.trim()}`;\n}\n\nexport function isValidTicketId(ticketId: string, provider: IssueTrackerProvider): boolean {\n if (!ticketId.trim()) return false;\n return ISSUE_TRACKER_PRESETS[provider].idPattern.test(ticketId.trim());\n}\n","import { type RecordingService } from './recording.service';\nimport { escapeSingleQuotes } from '../utils/code-format.utils';\nimport { redactSensitiveFields } from '../utils/redact.utils';\n\nconst INTERCEPTED_METHODS = ['GET', 'POST', 'PUT'] as const;\ntype InterceptedMethod = (typeof INTERCEPTED_METHODS)[number];\n\nexport function generateAlias(method: string, url: string): string {\n try {\n const u = new URL(url, 'http://localhost');\n const path = u.pathname\n .replace(/[^a-zA-Z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/(^-)|(-$)/g, '');\n return `${method.toLowerCase()}-${path}`;\n } catch {\n return `${method.toLowerCase()}-intercepted-request`;\n }\n}\n\nconst SAFE_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction buildValidations(base: string, obj: Record<string, unknown>): string {\n return Object.keys(obj)\n .filter((key) => key !== 'id' && key !== 'uid')\n .map((key) => {\n const accessor = SAFE_IDENTIFIER.test(key)\n ? `.${key}`\n : `['${escapeSingleQuotes(key)}']`;\n return `expect(${base}${accessor}).to.equal(${JSON.stringify(obj[key])});`;\n })\n .join('\\n');\n}\n\nfunction buildCyWaitCommand(\n method: string,\n alias: string,\n extendedHttp: boolean,\n requestBody: Record<string, unknown> | null,\n responseBody: Record<string, unknown> | null\n): string {\n if (extendedHttp && method === 'GET' && responseBody) {\n const validations = buildValidations('interception.response.body', responseBody);\n return `cy.wait('@${alias}').then((interception) => {\\n if (interception.response) {\\n${validations}\\n }\\n})`;\n }\n if (extendedHttp && (method === 'POST' || method === 'PUT') && requestBody) {\n const validations = buildValidations('interception.request.body', requestBody);\n return `cy.wait('@${alias}').then((interception) => {\\n${validations}\\n})`;\n }\n return `cy.wait('@${alias}').then((interception) => { })`;\n}\n\nfunction parseJsonObject(text: string): Record<string, unknown> | null {\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Non-JSON or array — fall through\n }\n return null;\n}\n\n/** Returns pretty-printed JSON (objects OR arrays) for a fixture, or null. */\nfunction prettyJsonOrNull(text: string): string | null {\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === 'object') return JSON.stringify(parsed, null, 2);\n } catch {\n // not JSON\n }\n return null;\n}\n\nfunction parseRequestBody(init?: RequestInit): Record<string, unknown> | null {\n const body = init?.body;\n if (typeof body === 'string') return parseJsonObject(body);\n return null;\n}\n\nfunction resolveUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n return input.url;\n}\n\nfunction resolveMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) return init.method.toUpperCase();\n if (input instanceof Request) return input.method.toUpperCase();\n return 'GET';\n}\n\n// ─── module-level interception handlers ──────────────────────────────────────\n\nasync function _handleFetchInterception(\n recording: RecordingService,\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n responseClone: Response\n): Promise<void> {\n const method = resolveMethod(input, init);\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method)) return;\n\n const url = resolveUrl(input);\n const alias = generateAlias(method, url);\n\n recording.registerInterceptor(method, url, alias);\n\n // Must be synchronous — we are inside an active fetch interception handler.\n // IndexedDB would require await and is not viable here; localStorage is the\n // sync cache kept fresh by initHttpConfig() on recorder mount.\n const extendedHttp = localStorage.getItem('extendedHttpCommands') === 'true';\n const fixtureMode = localStorage.getItem('fixtureMode') === 'true';\n const requestBody = extendedHttp ? parseRequestBody(init) : null;\n\n let responseText: string | null = null;\n let responseBody: Record<string, unknown> | null = null;\n\n if (extendedHttp || (fixtureMode && method === 'GET')) {\n try {\n responseText = await responseClone.text();\n if (extendedHttp) responseBody = parseJsonObject(responseText);\n } catch {\n // Unreadable body — continue without validations\n }\n }\n\n if (fixtureMode && method === 'GET' && responseText !== null) {\n const pretty = prettyJsonOrNull(responseText);\n if (pretty !== null) {\n const redacted = redactSensitiveFields(JSON.parse(pretty));\n recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));\n }\n }\n\n const cmd = buildCyWaitCommand(\n method, alias, extendedHttp,\n requestBody ? redactSensitiveFields(requestBody) as Record<string, unknown> : null,\n responseBody ? redactSensitiveFields(responseBody) as Record<string, unknown> : null,\n );\n recording.addCommand(cmd);\n}\n\nfunction _handleXhrInterception(\n recording: RecordingService,\n method: string,\n url: string,\n requestBody: Record<string, unknown> | null,\n responseText: string\n): void {\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method as InterceptedMethod)) return;\n\n const alias = generateAlias(method, url);\n\n recording.registerInterceptor(method, url, alias);\n\n // Same sync-cache rationale as in _handleFetchInterception above.\n if (localStorage.getItem('fixtureMode') === 'true' && method === 'GET') {\n const pretty = prettyJsonOrNull(responseText);\n if (pretty !== null) {\n const redacted = redactSensitiveFields(JSON.parse(pretty));\n recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));\n }\n }\n\n const extendedHttp = localStorage.getItem('extendedHttpCommands') === 'true';\n const responseBody = extendedHttp ? parseJsonObject(responseText) : null;\n\n const cmd = buildCyWaitCommand(\n method, alias, extendedHttp,\n requestBody ? redactSensitiveFields(requestBody) as Record<string, unknown> : null,\n responseBody ? redactSensitiveFields(responseBody) as Record<string, unknown> : null,\n );\n recording.addCommand(cmd);\n}\n\n// ─── module-level singleton state ────────────────────────────────────────────\n\nlet _refCount = 0;\nlet _originalFetch: typeof window.fetch | null = null;\nlet _originalXHR: typeof XMLHttpRequest | null = null;\nconst _recordings = new Set<RecordingService>();\n\nfunction _patchFetch(): void {\n const orig = window.fetch;\n _originalFetch = orig;\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const response = await orig(input, init);\n try {\n const active = [..._recordings];\n if (active.length > 0) {\n await Promise.all(\n active.map((rec) => _handleFetchInterception(rec, input, init, response.clone()).catch(() => {}))\n );\n }\n } catch {\n // Never let monitoring errors break the actual request\n }\n return response;\n };\n}\n\nfunction _restoreFetch(): void {\n if (!_originalFetch) return;\n window.fetch = _originalFetch;\n _originalFetch = null;\n}\n\nfunction _patchXhr(): void {\n const OrigXHR = window.XMLHttpRequest;\n _originalXHR = OrigXHR;\n\n window.XMLHttpRequest = class extends OrigXHR {\n private _xhrMethod = 'GET';\n private _xhrUrl = '';\n private _xhrRequestBody: Record<string, unknown> | null = null;\n\n override open(\n method: string,\n url: string | URL,\n async = true,\n user?: string | null,\n password?: string | null\n ): void {\n this._xhrMethod = method.toUpperCase();\n this._xhrUrl = url instanceof URL ? url.href : url;\n super.open(method, url as string, async, user, password);\n }\n\n override send(body?: Document | XMLHttpRequestBodyInit | null): void {\n if (typeof body === 'string') {\n this._xhrRequestBody = parseJsonObject(body);\n }\n this.addEventListener('load', () => {\n try {\n for (const rec of _recordings) {\n _handleXhrInterception(rec, this._xhrMethod, this._xhrUrl, this._xhrRequestBody, this.responseText);\n }\n } catch {\n // Never let monitoring errors surface\n }\n });\n super.send(body);\n }\n } as unknown as typeof XMLHttpRequest;\n}\n\nfunction _restoreXhr(): void {\n if (!_originalXHR) return;\n window.XMLHttpRequest = _originalXHR;\n _originalXHR = null;\n}\n\n/** @internal — resets singleton state between test suites; do not use in production code */\nexport function _resetHttpMonitorState(): void {\n _refCount = 0;\n _originalFetch = null;\n _originalXHR = null;\n _recordings.clear();\n}\n\n// ─── HttpMonitor — public API (thin wrapper over the module-level singleton) ─\n\nexport class HttpMonitor {\n constructor(private readonly recording: RecordingService) {}\n\n install(): void {\n _recordings.add(this.recording);\n _refCount++;\n if (_refCount === 1) {\n _patchFetch();\n _patchXhr();\n }\n }\n\n uninstall(): void {\n _recordings.delete(this.recording);\n if (_refCount <= 0) return;\n _refCount--;\n if (_refCount === 0) {\n _restoreFetch();\n _restoreXhr();\n }\n }\n\n isExtendedHttpEnabled(): boolean {\n return localStorage.getItem('extendedHttpCommands') === 'true';\n }\n\n isFixtureModeEnabled(): boolean {\n return localStorage.getItem('fixtureMode') === 'true';\n }\n}\n","// Substrings that unambiguously mark a key as sensitive. Matched against the\n// normalized key (lowercased, non-alphanumerics stripped), so `access_token`,\n// `X-Api-Key` and `refreshToken` all collapse to a form these can catch. These\n// are safe as substrings — none appears inside a common non-sensitive key.\nconst SENSITIVE_SUBSTRINGS = [\n 'password',\n 'passwd',\n 'passphrase',\n 'secret',\n 'token', // access_token, refresh_token, id_token, csrf_token…\n 'apikey', // api_key, x-api-key — NOT bare \"key\" (avoids \"normalKey\")\n 'authorization',\n 'cookie',\n 'credential',\n 'privatekey',\n 'sessionid',\n 'creditcard',\n 'cardnumber',\n 'cvv',\n];\n\n// Short / ambiguous names that would over-match as substrings (e.g. \"auth\" ⊂\n// \"author\", \"pin\" ⊂ \"shipping\"), so they are matched only as the WHOLE key.\nconst SENSITIVE_EXACT = new Set([\n 'auth',\n 'pwd',\n 'pin',\n 'otp',\n 'ssn',\n]);\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, '');\n}\n\nexport function isSensitiveKey(key: string): boolean {\n const normalized = normalizeKey(key);\n if (SENSITIVE_EXACT.has(normalized)) return true;\n return SENSITIVE_SUBSTRINGS.some((s) => normalized.includes(s));\n}\n\n/**\n * Recursively replaces values for sensitive keys with the literal string\n * \"[REDACTED]\". A key is sensitive if, once normalized (lowercased, separators\n * stripped), it contains a known credential substring (password, secret, token,\n * apikey, authorization, cookie, credential, privatekey, sessionid, card data)\n * or exactly equals a short marker (auth, pwd, pin, otp, ssn). Case-insensitive\n * and separator-insensitive so `access_token`, `X-Api-Key`, `clientSecret` and\n * `refreshToken` are all caught.\n *\n * Safe for use before writing fixtures or generating cy.wait validations —\n * credentials never reach generated test code. Returns a new object/array; the\n * original is never mutated.\n */\nexport function redactSensitiveFields(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map(redactSensitiveFields);\n }\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[key] = isSensitiveKey(key) ? '[REDACTED]' : redactSensitiveFields(value);\n }\n return result;\n }\n return obj;\n}\n","export const SCROLLBAR_STYLES = `\n.swal2-popup::-webkit-scrollbar,\n.swal2-html-container::-webkit-scrollbar,\n.swal2-content::-webkit-scrollbar,\n.swal2-container::-webkit-scrollbar {\n width: 5px;\n height: 5px;\n background: transparent;\n}\n.swal2-popup::-webkit-scrollbar-thumb,\n.swal2-html-container::-webkit-scrollbar-thumb,\n.swal2-content::-webkit-scrollbar-thumb,\n.swal2-container::-webkit-scrollbar-thumb {\n background: #30363d;\n border-radius: 3px;\n}\n.swal2-popup::-webkit-scrollbar-thumb:hover,\n.swal2-html-container::-webkit-scrollbar-thumb:hover,\n.swal2-content::-webkit-scrollbar-thumb:hover {\n background: #484f58;\n}\n.swal2-popup::-webkit-scrollbar-track,\n.swal2-html-container::-webkit-scrollbar-track,\n.swal2-content::-webkit-scrollbar-track,\n.swal2-container::-webkit-scrollbar-track {\n background: transparent;\n}\n.swal2-popup, .swal2-html-container, .swal2-content, .swal2-container {\n scrollbar-width: thin;\n scrollbar-color: #30363d transparent;\n}\n`;\n\nexport const LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES = `\n.swal2-container, .swal2-popup {\n z-index: 99999 !important;\n}\n.swal2-container {\n padding: 0 !important;\n align-items: center !important;\n justify-content: center !important;\n}\n.swal2-popup {\n background: #161b22 !important;\n color: #e6edf3 !important;\n border-radius: 12px !important;\n box-shadow: 0 24px 64px rgba(0,0,0,0.72), 0 0 0 1px #30363d !important;\n border: none !important;\n padding: 0 !important;\n min-width: 400px;\n max-width: 90vw;\n min-height: 200px;\n max-height: 90vh;\n}\n/* Override SweetAlert2 v11's display:grid on .swal2-popup.swal2-modal */\n.swal2-popup.swal2-modal {\n display: flex !important;\n flex-direction: column !important;\n align-items: stretch !important;\n overflow: hidden !important;\n}\n.swal2-header {\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n overflow: hidden !important;\n}\n.swal2-title {\n color: #e6edf3 !important;\n font-weight: 600 !important;\n font-size: 14px !important;\n background: #161b22;\n padding: 14px 48px 13px 18px !important;\n margin: 0 !important;\n border-bottom: 1px solid #21262d;\n text-align: left !important;\n letter-spacing: 0.1px;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n}\n.swal2-close {\n position: absolute !important;\n top: 10px !important;\n right: 12px !important;\n color: #8b949e !important;\n font-size: 1.1rem !important;\n z-index: 1 !important;\n border-radius: 6px !important;\n width: 28px !important;\n height: 28px !important;\n line-height: 28px !important;\n transition: background 0.15s, color 0.15s !important;\n}\n.swal2-close:hover {\n background: #21262d !important;\n color: #e6edf3 !important;\n}\n/* In SweetAlert2 v11, .swal2-html-container is a direct child of .swal2-popup */\n.swal2-html-container {\n flex: 1 !important;\n min-height: 0 !important;\n background: #161b22;\n padding: 0 !important;\n margin: 0 !important;\n width: 100%;\n display: flex !important;\n flex-direction: column !important;\n align-items: stretch;\n box-sizing: border-box;\n overflow: hidden !important;\n /* Left-align modal body text/code (SweetAlert defaults it to centre, which\n inherits into the panels — including their shadow DOM). Titles/buttons keep\n their own alignment. */\n text-align: left !important;\n}\n/* The single wrapper div we inject inside each modal fills the container */\n.swal2-html-container > div {\n flex: 1 !important;\n min-height: 0 !important;\n display: flex !important;\n flex-direction: column !important;\n overflow: hidden !important;\n}\n.swal2-actions, .swal2-footer {\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n}\n`;\n\nexport function injectStyles(css: string, id: string): void {\n if (document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n style.innerHTML = css;\n document.head.appendChild(style);\n}\n","export function makeModalResizable(\n modal: HTMLElement,\n options?: { minWidth?: number; minHeight?: number }\n): () => void {\n if (!modal || modal.querySelector('.modal-resizer')) return () => { /* no-op */ };\n\n const rect = modal.getBoundingClientRect();\n modal.style.position = 'fixed';\n modal.style.top = `${rect.top}px`;\n modal.style.left = `${rect.left}px`;\n modal.style.width = `${rect.width}px`;\n modal.style.margin = '0';\n modal.style.resize = 'both';\n modal.style.overflow = 'hidden';\n modal.style.minWidth = (options?.minWidth ?? 320) + 'px';\n modal.style.minHeight = (options?.minHeight ?? 180) + 'px';\n\n const resizer = document.createElement('div');\n resizer.className = 'modal-resizer';\n resizer.style.position = 'absolute';\n resizer.style.width = '16px';\n resizer.style.height = '16px';\n resizer.style.right = '2px';\n resizer.style.bottom = '2px';\n resizer.style.cursor = 'nwse-resize';\n resizer.style.background = 'rgba(0,0,0,0.1)';\n resizer.style.zIndex = '10';\n modal.appendChild(resizer);\n\n let isResizing = false;\n let lastX = 0;\n let lastY = 0;\n\n const mouseMove = (e: MouseEvent): void => {\n if (!isResizing) return;\n const dx = e.clientX - lastX;\n const dy = e.clientY - lastY;\n lastX = e.clientX;\n lastY = e.clientY;\n const rect = modal.getBoundingClientRect();\n modal.style.width = rect.width + dx + 'px';\n modal.style.height = rect.height + dy + 'px';\n };\n\n const mouseUp = (): void => {\n isResizing = false;\n document.body.style.userSelect = '';\n };\n\n resizer.addEventListener('mousedown', (e) => {\n e.preventDefault();\n isResizing = true;\n lastX = e.clientX;\n lastY = e.clientY;\n document.body.style.userSelect = 'none';\n });\n\n window.addEventListener('mousemove', mouseMove);\n window.addEventListener('mouseup', mouseUp);\n\n return () => {\n window.removeEventListener('mousemove', mouseMove);\n window.removeEventListener('mouseup', mouseUp);\n if (resizer.parentNode) resizer.parentNode.removeChild(resizer);\n };\n}\n\nfunction applyDraggable(swal: HTMLElement, dragArea: HTMLElement): void {\n let isDragging = false;\n let offsetX = 0;\n let offsetY = 0;\n\n dragArea.style.cursor = 'move';\n dragArea.onmousedown = (e: MouseEvent) => {\n isDragging = true;\n const rect = swal.getBoundingClientRect();\n offsetX = e.clientX - rect.left;\n offsetY = e.clientY - rect.top;\n document.onmousemove = (ev: MouseEvent) => {\n if (isDragging) {\n swal.style.position = 'fixed';\n swal.style.margin = '0';\n swal.style.left = `${ev.clientX - offsetX}px`;\n swal.style.top = `${ev.clientY - offsetY}px`;\n }\n };\n document.onmouseup = () => {\n isDragging = false;\n document.onmousemove = null;\n document.onmouseup = null;\n };\n };\n}\n\nfunction resolveDragArea(swal: HTMLElement): HTMLElement | null {\n return (swal.querySelector('.swal2-header') as HTMLElement | null)\n ?? (swal.querySelector('.swal2-title') as HTMLElement | null);\n}\n\nexport function makeSwalDraggable(): void {\n const popups = document.querySelectorAll('.swal2-popup');\n if (!popups.length) return;\n const swal = popups[popups.length - 1] as HTMLElement;\n const dragArea = resolveDragArea(swal);\n if (!dragArea) return;\n applyDraggable(swal, dragArea);\n}\n\nexport function makeSwalDraggableByContentId(contentId: string): void {\n const content = document.getElementById(contentId);\n if (!content) {\n makeSwalDraggable();\n return;\n }\n const swal = (content.closest('.swal2-popup') as HTMLElement | null)\n ?? (document.querySelector('.swal2-popup') as HTMLElement | null);\n if (!swal) return;\n const dragArea = resolveDragArea(swal);\n if (!dragArea) return;\n applyDraggable(swal, dragArea);\n}\n\nexport function setSwal2DataCyAttribute(dataCy = 'lib-e2e-cypress-for-dummys'): void {\n document.querySelector('.swal2-container')?.setAttribute('data-cy', dataCy);\n document.querySelector('.swal2-html-container')?.setAttribute('data-cy', dataCy);\n document.querySelector('.swal2-title')?.setAttribute('data-cy', dataCy);\n}\n\nexport function ensurePopupDimensions(popup: HTMLElement | null, heightPx: number): void {\n if (!popup) return;\n popup.style.height = `${heightPx}px`;\n const htmlContainer = popup.querySelector('.swal2-html-container') as HTMLElement | null;\n if (!htmlContainer) return;\n htmlContainer.style.flex = '1';\n htmlContainer.style.minHeight = '0';\n htmlContainer.style.overflow = 'hidden';\n htmlContainer.style.padding = '0';\n htmlContainer.style.margin = '0';\n htmlContainer.style.display = 'flex';\n htmlContainer.style.flexDirection = 'column';\n}\n","export function showToast(message: string, isSuccess = true): void {\n const toast = document.createElement('div');\n toast.textContent = message;\n toast.style.position = 'fixed';\n toast.style.top = '30px';\n toast.style.right = '30px';\n toast.style.padding = '16px 24px';\n toast.style.background = isSuccess ? '#4caf50' : '#f44336';\n toast.style.color = '#fff';\n toast.style.borderRadius = '8px';\n toast.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';\n toast.style.zIndex = '9999';\n toast.style.fontSize = '1rem';\n toast.style.fontWeight = 'bold';\n toast.style.pointerEvents = 'none';\n document.body.appendChild(toast);\n setTimeout(() => toast.remove(), 3000);\n}\n","import type { TestWithDetails } from '../services/persistence.service';\n\n/** How the user chose which tests to export. */\nexport type ExportMode = 'all' | 'manual' | 'tags';\n\nexport interface ExportSelectionOptions {\n /** Test ids to include in `manual` mode. */\n ids?: Iterable<number>;\n /** Tags to match in `tags` mode. */\n tags?: Iterable<string>;\n}\n\n/**\n * Returns the subset of tests to export for a given selection mode.\n *\n * - `all` → every test (a shallow copy).\n * - `manual` → tests whose id is in `opts.ids`. Empty/absent ids → none.\n * - `tags` → tests carrying at least one of `opts.tags` (OR semantics).\n * Empty/absent tags → none.\n *\n * Pure: never mutates its inputs.\n */\nexport function selectTestsForExport(\n tests: TestWithDetails[],\n mode: ExportMode,\n opts: ExportSelectionOptions = {},\n): TestWithDetails[] {\n if (mode === 'all') return [...tests];\n\n if (mode === 'manual') {\n const ids = new Set(opts.ids ?? []);\n return tests.filter((t) => ids.has(t.id));\n }\n\n // 'tags' — include a test if it carries ANY of the selected tags (OR).\n const tags = new Set(opts.tags ?? []);\n if (tags.size === 0) return [];\n return tests.filter((t) => (t.tags ?? []).some((tag) => tags.has(tag)));\n}\n","/**\n * True when a hostname refers to the local machine — used to gate dev-only\n * features (e.g. launching a Cypress run via the local runner) so they are\n * offered only when the app is served locally, not from a deployed environment.\n *\n * Treats as local: localhost, *.localhost, 127.0.0.1, ::1, 0.0.0.0, and the\n * empty hostname (e.g. file:// URLs). Case-insensitive.\n */\nexport function isLocalHost(hostname: string): boolean {\n if (!hostname) return true;\n const h = hostname.toLowerCase();\n return (\n h === 'localhost' ||\n h.endsWith('.localhost') ||\n h === '127.0.0.1' ||\n h === '::1' ||\n h === '0.0.0.0'\n );\n}\n","export const TEST_PREVISUALIZER_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; gap: 6px; padding: 10px 12px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d;\n }\n button {\n padding: 5px 12px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s; letter-spacing: 0.1px;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button.active { background: #2f81f7; color: #fff; }\n .section { padding: 10px 12px; flex-shrink: 0; }\n .section.section-cmds { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .section-title {\n font-size: 10px; font-weight: 600; color: #484f58; text-transform: uppercase;\n letter-spacing: 0.8px; margin-bottom: 7px; flex-shrink: 0;\n }\n .list {\n overflow-y: auto; background: #0d1117;\n border-radius: 8px; padding: 6px 8px;\n border: 1px solid #21262d;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .section-cmds .list { flex: 1; min-height: 0; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .item {\n display: flex; align-items: flex-start; gap: 6px;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n color: #c9d1d9; padding: 4px 8px; border-radius: 4px;\n word-break: break-all; line-height: 1.65;\n border-left: 2px solid transparent;\n transition: background 0.1s, border-color 0.1s;\n }\n .item:hover { background: #161b22; border-left-color: #2f81f7; }\n .cmd-text { flex: 1; }\n .item-actions {\n display: flex; gap: 3px; flex-shrink: 0;\n opacity: 0; transition: opacity 0.15s;\n }\n .item:hover .item-actions { opacity: 1; }\n .btn-step {\n width: 20px; height: 20px; border: none; border-radius: 3px; cursor: pointer;\n font-size: 12px; background: transparent; color: #484f58;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; justify-content: center;\n padding: 0; line-height: 1;\n }\n .btn-step:hover { background: #30363d; color: #e6edf3; }\n .btn-step-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n .empty { color: #484f58; font-size: 12px; padding: 20px 8px; text-align: center; }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport function renderTestPrevisualizer(\n commands: string[],\n interceptors: string[],\n showInterceptors: boolean,\n editable: boolean,\n t: (key: string) => string,\n): string {\n const editControls = (idx: number, total: number) => editable ? `\n <span class=\"item-actions\">\n <button class=\"btn-step\" data-move-up=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.UP_TITLE')}\" ${idx === 0 ? 'disabled style=\"opacity:.3\"' : ''}>↑</button>\n <button class=\"btn-step\" data-move-dn=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DOWN_TITLE')}\" ${idx === total - 1 ? 'disabled style=\"opacity:.3\"' : ''}>↓</button>\n <button class=\"btn-step btn-step-del\" data-del=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button>\n </span>` : '';\n\n const cmdItems = commands.length\n ? commands.map((c, i) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(c)}</span>\n ${editControls(i, commands.length)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_CMDS_YET')}</div>`;\n\n const icpEditControls = (idx: number) => editable\n ? `<span class=\"item-actions\"><button class=\"btn-step btn-step-del\" data-del-icp=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button></span>`\n : '';\n\n const icpSection = showInterceptors\n ? `<div class=\"section\" data-section=\"interceptors\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.INTERCEPTORS')}</div>\n <div class=\"list\">\n ${\n interceptors.length\n ? interceptors.map((ic, idx) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(ic)}</span>\n ${icpEditControls(idx)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_ICP_SHORT')}</div>`\n }\n </div>\n <button style=\"margin-top:6px\" data-action=\"copy-icp\">${t('TEST_PREVISUALIZER.COPY_ICP_BTN')}</button>\n </div>`\n : '';\n\n return `\n <div class=\"toolbar\">\n <button data-action=\"copy\">${t('TEST_PREVISUALIZER.COPY_CMDS_BTN')}</button>\n <button data-action=\"toggle-icp\" class=\"${showInterceptors ? 'active' : ''}\">\n ${showInterceptors ? t('TEST_PREVISUALIZER.HIDE_INTERCEPTORS') : t('TEST_PREVISUALIZER.SHOW_INTERCEPTORS')} (${interceptors.length})\n </button>\n </div>\n <div class=\"section section-cmds\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.SECTION_COMMANDS')} (${commands.length})</div>\n <div class=\"list\" data-ref=\"cmds\">${cmdItems}</div>\n </div>\n ${icpSection}`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { TEST_PREVISUALIZER_STYLES } from './test-previsualizer.styles';\nimport { renderTestPrevisualizer } from './test-previsualizer.template';\n\nexport class TestPrevisualizerElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _commands: string[] = [];\n private _interceptors: string[] = [];\n private _showInterceptors = false;\n editable = false;\n translation: TranslationService = translationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.render();\n }\n\n get commands(): string[] {\n return this._commands;\n }\n set commands(v: string[]) {\n this._commands = v;\n this.render();\n }\n\n get interceptors(): string[] {\n return this._interceptors;\n }\n set interceptors(v: string[]) {\n this._interceptors = v;\n this.render();\n }\n\n get showInterceptors(): boolean {\n return this._showInterceptors;\n }\n\n toggleInterceptors(): void {\n this._showInterceptors = !this._showInterceptors;\n this.render();\n }\n\n copyToClipboard(): void {\n const text = this._commands.join('\\n');\n if (!text) return;\n navigator.clipboard?.writeText(text);\n }\n\n copyInterceptorsToClipboard(): void {\n const text = this._interceptors.join('\\n');\n if (!text) return;\n navigator.clipboard?.writeText(text);\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private dispatchDelete(index: number): void {\n this.dispatchEvent(new CustomEvent('deletecommand', { detail: index, bubbles: true, composed: true }));\n }\n\n private dispatchMove(from: number, to: number): void {\n this.dispatchEvent(new CustomEvent('movecommand', { detail: { from, to }, bubbles: true, composed: true }));\n }\n\n private dispatchDeleteInterceptor(index: number): void {\n this.dispatchEvent(new CustomEvent('deleteinterceptor', { detail: index, bubbles: true, composed: true }));\n }\n\n private render(): void {\n this.shadow.innerHTML = `<style>${TEST_PREVISUALIZER_STYLES}</style>${renderTestPrevisualizer(\n this._commands,\n this._interceptors,\n this._showInterceptors,\n this.editable,\n this.t.bind(this),\n )}`;\n\n const cmdsEl = this.shadow.querySelector<HTMLElement>('[data-ref=\"cmds\"]');\n if (cmdsEl) cmdsEl.scrollTop = cmdsEl.scrollHeight;\n\n this.shadow.querySelector('[data-action=\"copy\"]')?.addEventListener('click', () => this.copyToClipboard());\n this.shadow.querySelector('[data-action=\"toggle-icp\"]')?.addEventListener('click', () => this.toggleInterceptors());\n this.shadow.querySelector('[data-action=\"copy-icp\"]')?.addEventListener('click', () => this.copyInterceptorsToClipboard());\n\n if (this.editable) {\n this.shadow.querySelectorAll('[data-del]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.dispatchDelete(Number((btn as HTMLElement).dataset['del']));\n });\n });\n this.shadow.querySelectorAll('[data-move-up]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const idx = Number((btn as HTMLElement).dataset['moveUp']);\n this.dispatchMove(idx, idx - 1);\n });\n });\n this.shadow.querySelectorAll('[data-move-dn]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const idx = Number((btn as HTMLElement).dataset['moveDn']);\n this.dispatchMove(idx, idx + 1);\n });\n });\n this.shadow.querySelectorAll('[data-del-icp]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.dispatchDeleteInterceptor(Number((btn as HTMLElement).dataset['delIcp']));\n });\n });\n }\n }\n}\n\nif (!customElements.get('lib-e2e-test-previsualizer')) {\n customElements.define('lib-e2e-test-previsualizer', TestPrevisualizerElement);\n}\n","export const SAVE_TEST_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { padding: 24px 28px; text-align: left; }\n .btn-row { text-align: center; }\n p { margin: 0 0 20px; font-size: 14px; color: #8b949e; line-height: 1.5; }\n .btn-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }\n button {\n padding: 7px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; transition: filter 0.15s, transform 0.1s;\n letter-spacing: 0.1px;\n }\n button:hover { filter: brightness(1.1); }\n button:active { transform: scale(0.97); }\n .btn-primary { background: #2f81f7; color: #fff; }\n .btn-success { background: #3fb950; color: #fff; }\n .btn-danger { background: transparent; color: #f85149; border: 1px solid rgba(248,81,73,0.5); }\n .btn-danger:hover { background: rgba(248,81,73,0.08); filter: none; }\n input[type=\"text\"] {\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\n border-radius: 8px; background: #0d1117; color: #e6edf3;\n font-size: 14px; outline: none; margin-bottom: 4px;\n transition: border-color 0.15s, box-shadow 0.15s;\n }\n input[type=\"text\"]:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\n input[type=\"text\"]::placeholder { color: #484f58; }\n textarea {\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\n border-radius: 8px; background: #0d1117; color: #e6edf3;\n font-size: 14px; outline: none; margin-bottom: 4px;\n font-family: inherit; resize: vertical; line-height: 1.5;\n transition: border-color 0.15s, box-shadow 0.15s;\n }\n textarea:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\n textarea::placeholder { color: #484f58; }\n .tag-label {\n font-size: 11px; color: #484f58; text-align: left; margin-bottom: 5px; display: block;\n }\n .tag-input-row { display: flex; gap: 6px; margin-bottom: 8px; }\n .tag-input-row input[type=\"text\"] {\n font-size: 12px; padding: 6px 10px; margin: 0;\n }\n .btn-tag-add {\n padding: 6px 12px; font-size: 12px; background: #21262d; color: #8b949e;\n border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n transition: background 0.15s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-tag-add:hover { background: #30363d; color: #e6edf3; filter: none; }\n .chips { display: flex; flex-wrap: wrap; gap: 5px; min-height: 24px; text-align: left; }\n .chip {\n display: inline-flex; align-items: center; gap: 5px;\n background: rgba(47,129,247,0.15); color: #2f81f7;\n border: 1px solid rgba(47,129,247,0.3); border-radius: 20px;\n padding: 2px 10px 2px 10px; font-size: 11px; font-weight: 500;\n }\n .chip-del {\n cursor: pointer; color: #8b949e; font-size: 12px; line-height: 1;\n transition: color 0.12s; padding: 0; background: none; border: none;\n }\n .chip-del:hover { color: #f85149; filter: none; }\n .discard-warn { color: #e6edf3; font-size: 13px; margin-bottom: 20px; line-height: 1.5; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\n\nexport function renderSaveTestConfirmDiscard(t: (key: string) => string): string {\n return `\n <div class=\"container\">\n <p class=\"discard-warn\">⚠ ${t('SAVE_TEST.CONFIRM_DISCARD')}</p>\n <div class=\"btn-row\">\n <button class=\"btn-danger\" id=\"btn-confirm-discard\">${t('SAVE_TEST.CONFIRM_DISCARD_BTN')}</button>\n <button id=\"btn-back-discard\">${t('SAVE_TEST.BACK_BTN')}</button>\n </div>\n </div>`;\n}\n\nexport function renderSaveTestAsk(t: (key: string) => string): string {\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.ASK')}</p>\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-yes\">${t('SAVE_TEST.YES_CONTINUE')}</button>\n <button class=\"btn-danger\" id=\"btn-no\">${t('SAVE_TEST.NO_DISCARD')}</button>\n </div>\n </div>`;\n}\n\nexport function renderSaveTestDesc(description: string, notes: string, tags: string[], ticketId: string, issueTrackerEnabled: boolean, ticketWarn: boolean, t: (key: string) => string): string {\n const chipsHtml = tags.map((tag) =>\n `<span class=\"chip\">${escHtml(tag)}<button class=\"chip-del\" data-tag=\"${escAttr(tag)}\" title=\"${t('SAVE_TEST.REMOVE_TAG_TITLE')}\">✕</button></span>`\n ).join('');\n\n const ticketHtml = issueTrackerEnabled ? `\n <span class=\"tag-label\">${t('SAVE_TEST.TICKET_LABEL')}</span>\n <input id=\"ticket-input\" type=\"text\" placeholder=\"${escAttr(t('SAVE_TEST.TICKET_PLACEHOLDER'))}\"\n value=\"${escAttr(ticketId)}\" autocomplete=\"off\" />\n ${ticketWarn ? `<span class=\"ticket-warn\">⚠ ${t('SAVE_TEST.TICKET_WARN')}</span>` : ''}` : '';\n\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.DESC_LABEL')} (<code>it()</code>):</p>\n <input id=\"desc-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.DESC_PLACEHOLDER')}\"\n value=\"${escAttr(description)}\" autocomplete=\"off\" />\n <span class=\"tag-label\">${t('SAVE_TEST.NOTES_LABEL')}</span>\n <textarea id=\"notes-input\" rows=\"3\" placeholder=\"${escAttr(t('SAVE_TEST.NOTES_PLACEHOLDER'))}\">${escHtml(notes)}</textarea>\n <span class=\"tag-label\">${t('SAVE_TEST.TAGS_LABEL')}</span>\n <div class=\"tag-input-row\">\n <input id=\"tag-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.TAGS_PLACEHOLDER')}\" autocomplete=\"off\" />\n <button class=\"btn-tag-add\" id=\"btn-add-tag\">${t('SAVE_TEST.ADD_TAG')}</button>\n </div>\n <div class=\"chips\" id=\"chips-container\">${chipsHtml || `<span style=\"color:#484f58;font-size:11px\">${t('SAVE_TEST.NO_TAGS')}</span>`}</div>\n ${ticketHtml}\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-confirm\">${t('SAVE_TEST.SAVE_BTN')}</button>\n <button class=\"btn-success\" id=\"btn-export\">${t('SAVE_TEST.SAVE_AND_EDIT')}</button>\n <button class=\"btn-danger\" id=\"btn-cancel\">${t('SAVE_TEST.CANCEL')}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { isValidTicketId } from '../../utils/ticket.utils';\nimport type { IssueTrackerConfig } from '../../models/issue-tracker.model';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG } from '../../models/issue-tracker.model';\nimport { SAVE_TEST_STYLES } from './save-test.styles';\nimport { renderSaveTestAsk, renderSaveTestDesc, renderSaveTestConfirmDiscard } from './save-test.template';\n\nexport class SaveTestElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _step: 'ask' | 'desc' | 'confirm-discard' = 'ask';\n private _stepBeforeDiscard: 'ask' | 'desc' = 'ask';\n description = '';\n notes = '';\n tags: string[] = [];\n ticketId = '';\n issueTrackerConfig: IssueTrackerConfig = DEFAULT_ISSUE_TRACKER_CONFIG;\n translation: TranslationService = translationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void { this.render(); }\n\n get step(): 'ask' | 'desc' | 'confirm-discard' { return this._step; }\n\n askSave(): void { this._step = 'desc'; this.render(); }\n\n confirmSave(): void { this.dispatch('savetest', { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() }); }\n\n confirmSaveAndExport(): void { this.dispatch('saveandexport', { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() }); }\n\n cancel(): void {\n this._stepBeforeDiscard = this._step === 'confirm-discard' ? 'ask' : (this._step as 'ask' | 'desc');\n this._step = 'confirm-discard';\n this.render();\n }\n\n confirmDiscard(): void { this.dispatch('savetest', { description: null, notes: '', tags: [], ticketId: '' }); }\n\n backFromDiscard(): void { this._step = this._stepBeforeDiscard; this.render(); }\n\n restartComponent(): void { this._step = 'ask'; this.description = ''; this.notes = ''; this.tags = []; this.ticketId = ''; this.render(); }\n\n addTag(tag: string): void {\n const t = tag.trim().replace(/[,;]/g, '');\n if (t && !this.tags.includes(t)) {\n this.tags = [...this.tags, t];\n this.render();\n }\n }\n\n removeTag(tag: string): void {\n this.tags = this.tags.filter((t) => t !== tag);\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n get ticketIdWarning(): boolean {\n if (!this.ticketId.trim() || !this.issueTrackerConfig.enabled) return false;\n return !isValidTicketId(this.ticketId, this.issueTrackerConfig.provider);\n }\n\n private dispatch(type: string, detail: { description: string | null; notes: string; tags: string[]; ticketId: string }): void {\n this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));\n }\n\n private render(): void {\n if (this._step === 'confirm-discard') {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestConfirmDiscard(this.t.bind(this))}`;\n this.shadow.getElementById('btn-confirm-discard')?.addEventListener('click', () => this.confirmDiscard());\n this.shadow.getElementById('btn-back-discard')?.addEventListener('click', () => this.backFromDiscard());\n return;\n }\n if (this._step === 'ask') {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestAsk(this.t.bind(this))}`;\n this.shadow.getElementById('btn-yes')?.addEventListener('click', () => this.askSave());\n this.shadow.getElementById('btn-no')?.addEventListener('click', () => this.cancel());\n } else {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.ticketId, this.issueTrackerConfig.enabled, this.ticketIdWarning, this.t.bind(this))}`;\n\n const descInput = this.shadow.getElementById('desc-input') as HTMLInputElement;\n const notesInput = this.shadow.getElementById('notes-input') as HTMLTextAreaElement;\n const tagInput = this.shadow.getElementById('tag-input') as HTMLInputElement;\n const ticketInput = this.shadow.getElementById('ticket-input') as HTMLInputElement | null;\n\n descInput.addEventListener('input', () => { this.description = descInput.value; });\n notesInput.addEventListener('input', () => { this.notes = notesInput.value; });\n ticketInput?.addEventListener('input', () => { this.ticketId = ticketInput.value; this.render(); });\n\n const tryAddTag = () => {\n this.addTag(tagInput.value);\n tagInput.value = '';\n };\n this.shadow.getElementById('btn-add-tag')?.addEventListener('click', tryAddTag);\n tagInput.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); tryAddTag(); }\n });\n\n this.shadow.querySelectorAll<HTMLButtonElement>('.chip-del').forEach((btn) => {\n btn.addEventListener('click', () => this.removeTag(btn.dataset['tag'] ?? ''));\n });\n\n this.shadow.getElementById('btn-confirm')?.addEventListener('click', () => this.confirmSave());\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.confirmSaveAndExport());\n this.shadow.getElementById('btn-cancel')?.addEventListener('click', () => this.cancel());\n setTimeout(() => descInput.focus(), 60);\n }\n }\n}\n\nif (!customElements.get('lib-e2e-save-test')) {\n customElements.define('lib-e2e-save-test', SaveTestElement);\n}\n","import { PersistenceService } from '../../services/persistence.service';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport { translationService, type TranslationService } from '../../services/translation.service';\nimport { localeForLang } from '../../models/lang.model';\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG, type IssueTrackerConfig } from '../../models/issue-tracker.model';\nimport { TEST_EDITOR_STYLES } from './test-editor.styles';\nimport { renderTestEditor } from './test-editor.template';\n\nexport class TestEditorElement extends HTMLElement {\n private shadow: ShadowRoot;\n persistence!: PersistenceService;\n translation: TranslationService = translationService;\n tests: TestWithDetails[] = [];\n expandedIndex: number | null = null;\n interceptorsByTest: Record<number, string[]> = {};\n activeTag: string | null = null;\n selectMode = false;\n selectedIds: Set<number> = new Set();\n describeName = '';\n groupByTicket = false;\n issueTrackerConfig: IssueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.persistence) this.persistence = new PersistenceService();\n this.loadTests();\n }\n\n async loadTests(): Promise<void> {\n this.tests = await this.persistence.getAllTests();\n this.render();\n }\n\n async deleteTest(id: number): Promise<void> {\n await this.persistence.deleteTest(id);\n this.selectedIds.delete(id);\n await this.loadTests();\n }\n\n toggleExpand(index: number): void {\n this.expandedIndex = this.expandedIndex === index ? null : index;\n if (this.expandedIndex !== null) {\n const test = this.tests[this.expandedIndex];\n if (test?.id && !this.interceptorsByTest[test.id]) {\n this.interceptorsByTest[test.id] = Array.isArray(test.interceptors) ? test.interceptors : [];\n }\n }\n this.render();\n }\n\n hasInterceptors(testId: number): boolean {\n return Array.isArray(this.interceptorsByTest[testId]) && this.interceptorsByTest[testId].length > 0;\n }\n\n toggleGroupByTicket(): void {\n this.groupByTicket = !this.groupByTicket;\n this.render();\n }\n\n toggleSelectMode(): void {\n this.selectMode = !this.selectMode;\n if (!this.selectMode) this.selectedIds.clear();\n this.render();\n }\n\n toggleSelectTest(id: number): void {\n if (this.selectedIds.has(id)) this.selectedIds.delete(id);\n else this.selectedIds.add(id);\n this.render();\n }\n\n generateDescribe(): void {\n const selected = this.tests.filter((t) => this.selectedIds.has(t.id));\n if (!selected.length) return;\n\n const name = this.describeName.trim() || this.t('TEST_EDITOR.DEFAULT_DESCRIBE');\n\n const allInterceptors = [...new Set(\n selected.flatMap((t) => this.interceptorsByTest[t.id] ?? t.interceptors ?? [])\n )];\n\n const beforeEach = allInterceptors.length\n ? ` beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n ${allInterceptors.join('\\n ')}\\n });\\n\\n`\n : '';\n\n const itBlocks = selected\n .map((t) => {\n const cmds = (t.commands ?? []).map((c) => ` ${c}`).join('\\n');\n return ` it('${escapeSingleQuotes(t.name ?? '')}', () => {\\n${cmds}\\n });`;\n })\n .join('\\n\\n');\n\n const block = `describe('${escapeSingleQuotes(name)}', () => {\\n${beforeEach}${itBlocks}\\n});`;\n navigator.clipboard?.writeText(block);\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard?.writeText(text);\n }\n\n get allTags(): string[] {\n const tagSet = new Set<string>();\n this.tests.forEach((t) => (t.tags ?? []).forEach((tag) => tagSet.add(tag)));\n return [...tagSet].sort();\n }\n\n get visibleTests(): TestWithDetails[] {\n const tag = this.activeTag;\n if (!tag) return this.tests;\n return this.tests.filter((t) => (t.tags ?? []).includes(tag));\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private render(): void {\n const tags = this.allTags;\n const visible = this.visibleTests;\n const selectedVisible = visible.filter((t) => this.selectedIds.has(t.id));\n\n this.shadow.innerHTML = `<style>${TEST_EDITOR_STYLES}</style>${renderTestEditor({\n tags,\n visible,\n selectedVisible,\n activeTag: this.activeTag,\n selectMode: this.selectMode,\n selectedIds: this.selectedIds,\n describeName: this.describeName,\n expandedIndex: this.expandedIndex,\n interceptorsByTest: this.interceptorsByTest,\n locale: localeForLang(this.translation.getLang()),\n groupByTicket: this.groupByTicket,\n issueTrackerConfig: this.issueTrackerConfig,\n }, this.t.bind(this))}`;\n\n this.shadow.getElementById('btn-group-ticket')?.addEventListener('click', () => this.toggleGroupByTicket());\n this.shadow.getElementById('btn-select-mode')?.addEventListener('click', () => this.toggleSelectMode());\n\n this.shadow.querySelectorAll('[data-filter-tag]').forEach((el) => {\n el.addEventListener('click', () => {\n const tag = (el as HTMLElement).dataset['filterTag'] ?? '';\n if (!tag) return;\n this.activeTag = this.activeTag === tag ? null : tag;\n this.render();\n });\n });\n\n const descInput = this.shadow.getElementById('describe-name') as HTMLInputElement | null;\n if (descInput) {\n descInput.addEventListener('input', () => { this.describeName = descInput.value; });\n }\n this.shadow.getElementById('btn-gen-describe')?.addEventListener('click', () => {\n this.describeName = descInput?.value ?? this.describeName;\n this.generateDescribe();\n });\n\n this.shadow.querySelectorAll('[data-select]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n this.toggleSelectTest(Number((el as HTMLElement).dataset['select']));\n });\n });\n\n this.shadow.querySelectorAll('[data-action=\"expand\"]').forEach((el) => {\n el.addEventListener('click', () => {\n if (this.selectMode) {\n const row = visible[Number((el as HTMLElement).dataset['idx'])];\n if (row) this.toggleSelectTest(row.id);\n } else {\n this.toggleExpand(Number((el as HTMLElement).dataset['idx']));\n }\n });\n });\n this.shadow.querySelectorAll('[data-action=\"delete\"]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n this.deleteTest(Number((el as HTMLElement).dataset['id']));\n });\n });\n this.shadow.querySelectorAll('[data-action=\"copy-cmds\"]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n const idx = Number((el as HTMLElement).dataset['idx']);\n this.copyToClipboard((visible[idx]?.commands ?? []).join('\\n'));\n });\n });\n this.shadow.querySelectorAll('[data-action=\"copy-icps\"]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n const idx = Number((el as HTMLElement).dataset['idx']);\n const t = visible[idx];\n this.copyToClipboard((this.interceptorsByTest[t?.id] ?? t?.interceptors ?? []).join('\\n'));\n });\n });\n }\n}\n\nif (!customElements.get('lib-e2e-test-editor')) {\n customElements.define('lib-e2e-test-editor', TestEditorElement);\n}\n","export const TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; align-items: center; gap: 6px; padding: 8px 10px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d; flex-wrap: wrap;\n }\n .tag-filter { display: flex; gap: 5px; flex-wrap: wrap; flex: 1; }\n .tag-chip {\n padding: 2px 10px; border-radius: 20px; cursor: pointer; font-size: 11px; font-weight: 500;\n border: 1px solid #30363d; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s, border-color 0.12s;\n }\n .tag-chip:hover { background: #30363d; color: #e6edf3; }\n .tag-chip.active { background: rgba(47,129,247,0.2); color: #2f81f7; border-color: rgba(47,129,247,0.4); }\n .btn-select {\n padding: 4px 12px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-select:hover { background: #30363d; color: #e6edf3; }\n .btn-select.active { background: rgba(47,129,247,0.15); color: #2f81f7; border-color: rgba(47,129,247,0.3); }\n .describe-bar {\n display: flex; align-items: center; gap: 8px; padding: 8px 10px;\n background: rgba(47,129,247,0.06); border-bottom: 1px solid rgba(47,129,247,0.2);\n flex-wrap: wrap;\n }\n .describe-bar input {\n flex: 1; min-width: 150px; padding: 5px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px; color: #e6edf3;\n font-size: 12px; outline: none;\n }\n .describe-bar input:focus { border-color: #2f81f7; }\n .btn-gen-describe {\n padding: 5px 14px; border: 1px solid #2f81f7; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: rgba(47,129,247,0.15); color: #2f81f7;\n transition: background 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-gen-describe:hover { background: rgba(47,129,247,0.25); }\n .selected-count { font-size: 11px; color: #8b949e; }\n .describe-bar { flex-shrink: 0; }\n .list { padding: 8px; flex: 1; min-height: 0; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .empty { color: #484f58; text-align: center; padding: 32px; font-size: 13px; }\n .row {\n background: #0d1117; border-radius: 8px; margin-bottom: 6px;\n overflow: hidden; border: 1px solid #21262d;\n transition: border-color 0.15s;\n }\n .row:hover { border-color: #30363d; }\n .row.selected-row { border-color: rgba(47,129,247,0.5); }\n .row-header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px; cursor: pointer; user-select: none;\n }\n .row-header:hover { background: rgba(48,54,61,0.3); }\n .test-name { flex: 1; font-size: 13px; font-weight: 500; color: #e6edf3; }\n .test-date { font-size: 10.5px; color: #484f58; margin-right: 4px; }\n .test-tags { display: flex; gap: 4px; margin-right: 4px; }\n .test-tag {\n padding: 1px 7px; border-radius: 20px; font-size: 10px;\n background: rgba(47,129,247,0.1); color: #8b949e; border: 1px solid rgba(47,129,247,0.2);\n }\n .ticket-badge, .ticket-link {\n padding: 1px 7px; border-radius: 20px; font-size: 10px; font-weight: 500;\n background: rgba(210,153,34,0.12); color: #d29922; border: 1px solid rgba(210,153,34,0.3);\n white-space: nowrap; flex-shrink: 0;\n }\n .ticket-link {\n text-decoration: none; cursor: pointer;\n transition: background 0.12s, border-color 0.12s;\n }\n .ticket-link::before { content: '🎫 '; font-size: 9px; }\n .ticket-link:hover { background: rgba(210,153,34,0.22); border-color: rgba(210,153,34,0.55); color: #e3b341; }\n .ticket-badge::before { content: '🎫 '; font-size: 9px; }\n .btn-icon {\n padding: 3px 8px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n .btn-icon:hover { background: #30363d; color: #e6edf3; }\n .btn-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n input[type=\"checkbox\"] {\n width: 14px; height: 14px; accent-color: #2f81f7; cursor: pointer; flex-shrink: 0;\n }\n .row-body {\n background: #0d1117; padding: 10px 14px;\n border-top: 1px solid #21262d;\n }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .code-preview {\n margin: 0; padding: 10px 12px; background: #161b22;\n border-radius: 6px; border: 1px solid #21262d;\n font-size: 11px; color: #c9d1d9; line-height: 1.7;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n overflow-x: auto; white-space: pre;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .code-preview::-webkit-scrollbar { height: 4px; }\n .code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .code-preview-icp { margin-top: 8px; }\n .ticket-group { margin-bottom: 8px; }\n .ticket-group-header {\n padding: 4px 10px; margin-bottom: 4px;\n font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.7px;\n color: #d29922; border-left: 3px solid rgba(210,153,34,0.5);\n background: rgba(210,153,34,0.06); border-radius: 0 4px 4px 0;\n }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport { normalizeBlock, escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { buildTicketUrl, buildTicketComment } from '../../utils/ticket.utils';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport type { IssueTrackerConfig } from '../../models/issue-tracker.model';\n\nexport interface TestEditorState {\n tags: string[];\n visible: TestWithDetails[];\n selectedVisible: TestWithDetails[];\n activeTag: string | null;\n selectMode: boolean;\n selectedIds: Set<number>;\n describeName: string;\n expandedIndex: number | null;\n interceptorsByTest: Record<number, string[]>;\n locale: string;\n groupByTicket: boolean;\n issueTrackerConfig: IssueTrackerConfig;\n}\n\nfunction renderTestRow(test: TestWithDetails, i: number, state: TestEditorState, t: (key: string) => string): string {\n const { selectMode, selectedIds, expandedIndex, interceptorsByTest, locale, issueTrackerConfig } = state;\n const expanded = expandedIndex === i;\n const date = new Date(test.createdAt).toLocaleString(locale, { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });\n const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];\n const tagsHtml = (test.tags ?? []).length\n ? `<span class=\"test-tags\">${(test.tags ?? []).map((tag) => `<span class=\"test-tag\">${escHtml(tag)}</span>`).join('')}</span>`\n : '';\n const checkbox = selectMode\n ? `<input type=\"checkbox\" ${selectedIds.has(test.id) ? 'checked' : ''} data-select=\"${test.id}\" />`\n : '';\n const hasIcps = (test.interceptors ?? []).length > 0;\n const ticketId = (test as TestWithDetails & { ticketId?: string }).ticketId;\n const ticketComment = ticketId ? buildTicketComment(ticketId) + '\\n' : '';\n const itBlockCode = `${ticketComment}it('${escapeSingleQuotes(test.name)}', () => {\\n${(test.commands ?? []).map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\n const icpBlockCode = icps.length ? `beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n${icps.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});` : '';\n const notesHtml = (expanded && test.notes)\n ? `<p class=\"test-notes\">${escHtml(test.notes)}</p>`\n : '';\n const ticketUrl = ticketId ? buildTicketUrl(ticketId, issueTrackerConfig) : null;\n const ticketHtml = ticketId\n ? ticketUrl\n ? `<a class=\"ticket-link\" href=\"${escAttr(ticketUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\" title=\"${t('TEST_EDITOR.TICKET_LINK_TITLE')}\">${escHtml(ticketId)}</a>`\n : `<span class=\"ticket-badge\">${escHtml(ticketId)}</span>`\n : '';\n\n const body = expanded ? `\n <div class=\"row-body\">\n ${notesHtml}\n <pre class=\"code-preview\">${syntaxHighlight(itBlockCode)}</pre>\n ${icpBlockCode ? `<pre class=\"code-preview code-preview-icp\">${syntaxHighlight(icpBlockCode)}</pre>` : ''}\n </div>` : '';\n\n return `\n <div class=\"row${selectedIds.has(test.id) ? ' selected-row' : ''}\">\n <div class=\"row-header\" data-action=\"expand\" data-idx=\"${i}\">\n ${checkbox}\n <span class=\"test-name\">${escHtml(test.name)}</span>\n ${tagsHtml}\n ${ticketHtml}\n <span class=\"test-date\">${date}</span>\n <button class=\"btn-icon\" data-action=\"copy-cmds\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_CMDS_BTN')}\">${t('TEST_EDITOR.COPY_CMDS_BTN')}</button>\n ${hasIcps ? `<button class=\"btn-icon\" data-action=\"copy-icps\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_ICPS_BTN')}\">${t('TEST_EDITOR.COPY_ICPS_BTN')}</button>` : ''}\n <button class=\"btn-icon btn-del\" data-action=\"delete\" data-id=\"${test.id}\" title=\"${t('TEST_EDITOR.DELETE_TITLE')}\">🗑</button>\n </div>\n ${body}\n </div>`;\n}\n\nexport function renderTestEditor(state: TestEditorState, t: (key: string) => string): string {\n const { tags, visible, selectedVisible, activeTag, selectMode, describeName, groupByTicket } = state;\n\n const tagFilterHtml = tags.length\n ? `<div class=\"tag-filter\">\n ${tags.map((tag) => `<button class=\"tag-chip${activeTag === tag ? ' active' : ''}\" data-filter-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}\n </div>`\n : `<div class=\"tag-filter\" style=\"color:#484f58;font-size:11px\">${t('TEST_EDITOR.NO_TAGS')}</div>`;\n\n const describeBarHtml = selectMode && selectedVisible.length > 0\n ? `<div class=\"describe-bar\">\n <span class=\"selected-count\">${selectedVisible.length} ${selectedVisible.length !== 1 ? t('TEST_EDITOR.SELECTED_PLURAL') : t('TEST_EDITOR.SELECTED_SINGULAR')}</span>\n <input id=\"describe-name\" type=\"text\" placeholder=\"${t('TEST_EDITOR.DESCRIBE_PLACEHOLDER')}\" value=\"${escAttr(describeName)}\" />\n <button class=\"btn-gen-describe\" id=\"btn-gen-describe\">${t('TEST_EDITOR.COPY_DESCRIBE')}</button>\n </div>`\n : '';\n\n let rows: string;\n if (groupByTicket) {\n const groups = new Map<string, TestWithDetails[]>();\n for (const test of visible) {\n const key = (test as TestWithDetails & { ticketId?: string }).ticketId?.trim() || '';\n const group = groups.get(key) ?? [];\n group.push(test);\n groups.set(key, group);\n }\n const sortedKeys = [...groups.keys()].sort((a, b) =>\n a === '' ? 1 : b === '' ? -1 : a.localeCompare(b)\n );\n rows = sortedKeys.map((key) => {\n const group = groups.get(key) as TestWithDetails[];\n const header = `<div class=\"ticket-group-header\">${key ? escHtml(key) : t('TEST_EDITOR.NO_TICKET')}</div>`;\n const groupRows = group.map((test) => {\n const i = visible.indexOf(test);\n return renderTestRow(test, i, state, t);\n }).join('');\n return `<div class=\"ticket-group\">${header}${groupRows}</div>`;\n }).join('');\n } else {\n rows = visible.map((test, i) => renderTestRow(test, i, state, t)).join('');\n }\n\n return `\n <div class=\"toolbar\">\n ${tagFilterHtml}\n <button class=\"btn-select${groupByTicket ? ' active' : ''}\" id=\"btn-group-ticket\">\n ${groupByTicket ? t('TEST_EDITOR.UNGROUP_TICKET') : t('TEST_EDITOR.GROUP_BY_TICKET')}\n </button>\n <button class=\"btn-select${selectMode ? ' active' : ''}\" id=\"btn-select-mode\">\n ${selectMode ? t('TEST_EDITOR.CANCEL_SELECT') : t('TEST_EDITOR.MULTI_SELECT')}\n </button>\n </div>\n ${describeBarHtml}\n <div class=\"list\">\n ${visible.length ? rows : `<div class=\"empty\">${t('TEST_EDITOR.NO_TESTS')}</div>`}\n </div>`;\n}\n","import { escHtml } from './html.utils';\n\nconst KEYWORDS = new Set([\n 'describe', 'it', 'xit', 'fit', 'xdescribe', 'fdescribe',\n 'beforeEach', 'afterEach', 'before', 'after', 'context',\n 'const', 'let', 'var', 'function', 'return', 'if', 'else',\n 'import', 'export', 'from', 'new', 'this', 'null', 'undefined',\n 'true', 'false', 'async', 'await', 'of', 'in', 'typeof', 'void',\n]);\n\nconst BUILTINS = new Set(['cy', 'expect', 'assert', 'Cypress', 'chai']);\n\nexport function syntaxHighlight(code: string): string {\n return code.split('\\n').map(highlightLine).join('\\n');\n}\n\nfunction highlightLine(line: string): string {\n let result = '';\n let i = 0;\n const len = line.length;\n\n while (i < len) {\n // Single-line comment\n if (line[i] === '/' && i + 1 < len && line[i + 1] === '/') {\n result += `<span class=\"sh-cmt\">${escHtml(line.slice(i))}</span>`;\n return result;\n }\n // String literal (single, double, or template)\n const q = line[i];\n if (q === \"'\" || q === '\"' || q === '`') {\n let j = i + 1;\n while (j < len) {\n if (line[j] === '\\\\') { j += 2; continue; }\n if (line[j] === q) { j++; break; }\n j++;\n }\n result += `<span class=\"sh-str\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Number (not preceded by identifier character)\n if (/[0-9]/.test(line[i]) && (i === 0 || !/[a-zA-Z_$]/.test(line[i - 1]))) {\n let j = i;\n while (j < len && /[0-9.]/.test(line[j])) j++;\n result += `<span class=\"sh-num\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Identifier, keyword, or builtin\n if (/[a-zA-Z_$]/.test(line[i])) {\n let j = i;\n while (j < len && /[a-zA-Z0-9_$]/.test(line[j])) j++;\n const word = line.slice(i, j);\n if (KEYWORDS.has(word)) {\n result += `<span class=\"sh-kw\">${escHtml(word)}</span>`;\n } else if (BUILTINS.has(word)) {\n result += `<span class=\"sh-bi\">${escHtml(word)}</span>`;\n } else {\n result += escHtml(word);\n }\n i = j;\n continue;\n }\n result += escHtml(line[i]);\n i++;\n }\n return result;\n}\n","import type { SelectorStrategy } from '../services/recording.service';\n\n/**\n * A live, in-progress recording session, persisted so it can survive a\n * micro-frontend crossing (single-spa app swap) or an accidental same-origin\n * reload. Only an actively-recording session is ever stored/resumed.\n *\n * The full payload lives in IndexedDB; a lightweight breadcrumb (sessionId +\n * isRecording + updatedAt) is mirrored to localStorage for synchronous detection.\n *\n * See docs/specs/006-cross-app-recording-continuity.md.\n */\nexport interface ActiveSessionState {\n /** Stable id for the session, generated when recording starts. */\n sessionId: string;\n isRecording: boolean;\n isPaused: boolean;\n commands: string[];\n interceptors: string[];\n selectorStrategy: SelectorStrategy;\n /** Epoch ms when the session started recording. */\n startedAt: number;\n /** Epoch ms of the last mutation — acts as the recency heartbeat. */\n updatedAt: number;\n}\n\n/** localStorage key for the synchronous \"is a session active?\" breadcrumb. */\nexport const ACTIVE_SESSION_BREADCRUMB_KEY = 'e2e-active-session';\n\n/** Configuration key (in the `configuration` store) for the resume recency TTL. */\nexport const RESUME_TTL_CONFIG_KEY = 'resumeRecencyTtlMinutes';\n\n/** Default minutes within which an active session resumes silently. */\nexport const DEFAULT_RESUME_TTL_MINUTES = 30;\n","const EXPORT_FN_RE =\n /^(?!\\/\\/).*\\bexport\\s+(?:async\\s+)?function\\s+(\\w+)|^(?!\\/\\/).*\\bexport\\s+const\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/gm;\n\nexport function extractExportedFunctions(fileContent: string): string[] {\n const names: string[] = [];\n let match: RegExpExecArray | null;\n const re = new RegExp(EXPORT_FN_RE.source, EXPORT_FN_RE.flags);\n while ((match = re.exec(fileContent)) !== null) {\n const name = match[1] ?? match[2];\n if (name) names.push(name);\n }\n return names;\n}\n\nexport function buildLoginScaffold(): string {\n return [\n '/**',\n ' * Login service scaffold — fill in your own auth logic.',\n ' * This file is not committed to source control.',\n ' */',\n '',\n 'export function fetchAuthToken() {',\n ' // TODO: implement — retrieve and return your auth token',\n '}',\n '',\n 'export function setupRequestInterceptors() {',\n ' // TODO: implement — configure cy.intercept() or set localStorage/cookies',\n '}',\n '',\n ].join('\\n');\n}\n\nexport function buildLoginImportPath(fromFilePath: string, toServiceFilePath: string): string {\n const fromParts = fromFilePath.replace(/\\\\/g, '/').split('/');\n const toParts = toServiceFilePath.replace(/\\\\/g, '/').split('/');\n\n fromParts.pop(); // remove filename, keep directory segments\n\n // find common prefix length\n let common = 0;\n while (common < fromParts.length && common < toParts.length - 1 && fromParts[common] === toParts[common]) {\n common++;\n }\n\n const ups = fromParts.length - common;\n const downs = toParts.slice(common);\n\n const serviceFile = downs[downs.length - 1].replace(/\\.ts$/, '');\n const prefix = ups === 0 ? '.' : Array(ups).fill('..').join('/');\n const middle = downs.slice(0, -1);\n\n return [prefix, ...middle, serviceFile].join('/');\n}\n\nexport function hasLoginBlocks(content: string, fnNames: string[]): boolean {\n return fnNames.some(fn => new RegExp(`\\\\b${fn}\\\\s*\\\\(`).test(content));\n}\n\nexport function injectLoginBlocksIntoExisting(\n content: string,\n importLine: string,\n beforeBlock: string,\n beforeEachBlock: string,\n): string {\n let result = content;\n\n if (importLine && !content.includes(importLine)) {\n result = `${importLine}\\n\\n${result}`;\n }\n\n const blocks = [beforeBlock, beforeEachBlock].filter(Boolean).join('');\n if (blocks) {\n const describeMatch = result.match(/(describe\\s*\\(.*?{)/s);\n if (describeMatch) {\n const insertPos = (describeMatch.index ?? 0) + describeMatch[0].length;\n result = result.slice(0, insertPos) + '\\n' + blocks + result.slice(insertPos);\n }\n }\n\n return result;\n}\n\nexport function buildLoginBlocks(\n importPath: string,\n beforeFn: string | null,\n beforeEachFn: string | null,\n): { importLine: string; beforeBlock: string; beforeEachBlock: string } {\n if (!beforeFn && !beforeEachFn) {\n return { importLine: '', beforeBlock: '', beforeEachBlock: '' };\n }\n\n const fns = [...new Set([beforeFn, beforeEachFn].filter(Boolean))] as string[];\n const importLine = `import { ${fns.join(', ')} } from '${importPath}';`;\n\n const beforeBlock = beforeFn ? ` before(() => { ${beforeFn}(); });\\n` : '';\n const beforeEachBlock = beforeEachFn ? ` beforeEach(() => { ${beforeEachFn}(); });\\n` : '';\n\n return { importLine, beforeBlock, beforeEachBlock };\n}\n","export const CONFIGURATION_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; max-height: 70vh; overflow-y: auto; scrollbar-width: thin; scrollbar-color: #30363d transparent; }\n * { box-sizing: border-box; }\n\n /* ── Grid container ───────────────────────────────────── */\n .cfg-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n padding: 14px;\n }\n\n /* ── Cards ────────────────────────────────────────────── */\n .card {\n background: #161b22;\n border: 1px solid #21262d;\n border-radius: 10px;\n padding: 14px 16px;\n transition: border-color 0.15s;\n }\n .card:hover { border-color: #30363d; }\n .card-wide { grid-column: 1 / -1; }\n\n /* ── Card header ──────────────────────────────────────── */\n .card-hd {\n display: flex; align-items: center; gap: 7px;\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.8px; color: #484f58; margin-bottom: 12px;\n }\n .card-hd-icon { font-size: 13px; }\n\n /* ── Language ─────────────────────────────────────────── */\n .field-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\n .field-label { font-size: 12px; color: #8b949e; }\n select {\n background: #0d1117; color: #e6edf3; border: 1px solid #30363d;\n border-radius: 6px; padding: 6px 10px; font-size: 12px; outline: none;\n cursor: pointer; transition: border-color 0.15s; flex-shrink: 0;\n }\n select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n /* ── HTTP toggle ──────────────────────────────────────── */\n .check-row {\n display: flex; align-items: flex-start; gap: 10px;\n cursor: pointer; user-select: none;\n }\n input[type=\"checkbox\"] { width: 15px; height: 15px; margin-top: 2px; cursor: pointer; accent-color: #2f81f7; flex-shrink: 0; }\n .check-title { font-size: 12px; color: #c9d1d9; margin-bottom: 3px; }\n .check-sub { font-size: 10px; color: #484f58; line-height: 1.5; }\n\n /* ── Cypress folder ───────────────────────────────────── */\n .fs-layout { display: flex; gap: 12px; align-items: flex-start; }\n .fs-tree {\n flex-shrink: 0;\n margin: 0; padding: 8px 10px;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n font-size: 10px; color: #c9d1d9; line-height: 1.8;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n }\n .fs-right { display: flex; flex-direction: column; gap: 10px; flex: 1; }\n .fs-status {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: #8b949e;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n padding: 8px 10px;\n }\n .fs-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }\n .fs-dot.on { background: #3fb950; box-shadow: 0 0 6px rgba(63,185,80,.5); }\n .fs-dot.off { background: #484f58; }\n .fs-folder { color: #e6edf3; font-family: 'Cascadia Code','Fira Code','Consolas',monospace; font-size: 11px; }\n\n /* ── Buttons ──────────────────────────────────────────── */\n .btn-row { display: flex; gap: 8px; flex-wrap: wrap; }\n button {\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n button:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-import {\n display: inline-block;\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n .btn-import:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-danger { border-color: rgba(248,81,73,.4); color: #f85149; background: transparent; }\n .btn-danger:hover { background: rgba(248,81,73,.08); border-color: #f85149; color: #f85149; }\n .file-input { display: none; }\n\n /* ── Data section desc ────────────────────────────────── */\n .data-desc { font-size: 11px; color: #484f58; margin-bottom: 10px; line-height: 1.5; }\n\n /* ── Export overlay (modal) ───────────────────────────── */\n .export-overlay {\n position: fixed; inset: 0; z-index: 100000;\n background: rgba(1,4,9,0.7);\n display: flex; align-items: center; justify-content: center; padding: 20px;\n }\n .export-modal {\n width: 640px; max-width: 100%; max-height: 86vh;\n display: flex; flex-direction: column;\n background: #161b22; border: 1px solid #30363d; border-radius: 12px;\n box-shadow: 0 12px 40px rgba(0,0,0,0.5); overflow: hidden;\n }\n .export-hd {\n padding: 14px 18px; font-size: 13px; font-weight: 700;\n border-bottom: 1px solid #21262d; color: #e6edf3;\n }\n .export-modes { display: flex; gap: 6px; padding: 12px 18px 0; }\n .export-mode {\n flex: 1; padding: 7px 10px; font-size: 11px; border-radius: 6px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-mode:hover { background: #21262d; color: #e6edf3; }\n .export-mode.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-body {\n padding: 14px 18px; overflow-y: auto; flex: 1; min-height: 160px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .export-tag-hint { font-size: 12px; color: #484f58; margin-top: 12px; }\n .export-result-label {\n font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px;\n font-weight: 600; margin: 14px 0 6px;\n }\n .export-row-static { cursor: default; }\n .export-row-static:hover { background: transparent; }\n .export-all-desc { font-size: 12px; color: #8b949e; }\n .export-empty { font-size: 12px; color: #484f58; text-align: center; padding: 20px; }\n .export-list { display: flex; flex-direction: column; gap: 4px; }\n .export-row {\n display: flex; align-items: center; gap: 8px;\n padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12px; color: #c9d1d9;\n }\n .export-row:hover { background: #0d1117; }\n .export-row-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .export-row-tag {\n font-size: 9px; color: #8b949e; background: #0d1117;\n border: 1px solid #30363d; border-radius: 10px; padding: 1px 7px; flex-shrink: 0;\n }\n .export-tags { display: flex; flex-wrap: wrap; gap: 6px; }\n .export-tag {\n padding: 4px 10px; font-size: 11px; border-radius: 12px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-tag:hover { background: #21262d; color: #e6edf3; }\n .export-tag.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-ft {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n padding: 12px 18px; border-top: 1px solid #21262d;\n }\n .export-count { font-size: 11px; color: #8b949e; }\n .export-count b { color: #e6edf3; }\n .export-ft-actions { display: flex; gap: 8px; }\n .btn-export-confirm { background: #238636; border-color: #238636; color: #fff; }\n .btn-export-confirm:hover:not(:disabled) { background: #2ea043; border-color: #2ea043; }\n .btn-export-confirm:disabled { opacity: 0.45; cursor: not-allowed; }\n\n /* ── Form-element font reset ──────────────────────────────── */\n input, select, button, textarea { font-family: inherit; }\n\n /* ── Primary action button ────────────────────────────────── */\n .btn-primary { background: #1f6feb; border-color: #1f6feb; color: #fff; }\n .btn-primary:hover { background: #388bfd; border-color: #388bfd; color: #fff; }\n .btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }\n\n /* ── Login Setup overlay ──────────────────────────────────── */\n .ls-modal { max-width: 500px; }\n .ls-hd { display: flex; align-items: center; gap: 8px; }\n .ls-hd-icon { font-size: 15px; }\n\n .ls-body {\n padding: 20px; overflow-y: auto; flex: 1;\n display: flex; flex-direction: column; gap: 20px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n\n .ls-section { display: flex; flex-direction: column; gap: 8px; }\n .ls-section-label {\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.8px; color: #484f58;\n }\n\n .ls-actions { display: flex; gap: 10px; }\n .ls-action-btn {\n flex: 1; padding: 14px 12px; border-radius: 8px;\n background: #0d1117; border: 1px solid #21262d; color: #8b949e;\n display: flex; flex-direction: column; align-items: center; gap: 6px;\n transition: background 0.15s, border-color 0.15s, color 0.15s;\n }\n .ls-action-btn:hover { background: #161b22; color: #e6edf3; border-color: #388bfd; }\n .ls-action-icon { font-size: 22px; line-height: 1; }\n .ls-action-label { font-size: 12px; font-weight: 600; color: #c9d1d9; }\n .ls-action-btn:hover .ls-action-label { color: #e6edf3; }\n .ls-action-sub { font-size: 10px; color: #484f58; line-height: 1.4; text-align: center; }\n\n .ls-file-row {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 12px; background: #0d1117;\n border: 1px solid #21262d; border-radius: 8px;\n }\n .ls-file-icon { font-size: 14px; flex-shrink: 0; }\n .ls-file-name {\n flex: 1; font-size: 11px; color: #c9d1d9;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n min-width: 0;\n }\n .ls-btn-rescan {\n flex-shrink: 0; padding: 4px 10px; font-size: 11px;\n background: #161b22; border-color: #30363d; color: #8b949e;\n }\n .ls-btn-rescan:hover { background: #21262d; color: #e6edf3; }\n\n .ls-input {\n width: 100%; padding: 8px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px;\n color: #c9d1d9; font-size: 12px; outline: none; font-family: inherit;\n }\n .ls-input:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n .ls-fns {\n display: flex; flex-wrap: wrap; gap: 6px;\n padding: 10px; background: #0d1117;\n border: 1px solid #21262d; border-radius: 6px; min-height: 38px;\n }\n .ls-fn-chip {\n padding: 3px 10px; font-size: 11px; color: #79c0ff;\n background: rgba(47,129,247,0.1); border: 1px solid rgba(47,129,247,0.2);\n border-radius: 12px; font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n }\n\n .ls-field-block { display: flex; flex-direction: column; gap: 6px; }\n .ls-field-block + .ls-field-block { margin-top: 12px; }\n .ls-label { font-size: 11px; color: #8b949e; }\n .ls-select {\n width: 100%; padding: 8px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px;\n color: #c9d1d9; font-size: 12px; outline: none; cursor: pointer;\n }\n .ls-select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n .ls-empty-state {\n display: flex; align-items: center; gap: 10px;\n padding: 14px; background: #0d1117; border: 1px solid #21262d;\n border-radius: 8px; font-size: 12px; color: #484f58;\n }\n .ls-empty-icon { font-size: 16px; }\n\n .ls-ft { padding: 14px 20px; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport { ISSUE_TRACKER_PRESETS, type IssueTrackerConfig } from '../../models/issue-tracker.model';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\n\nexport const LANGS = [\n { value: 'es', label: 'Español' },\n { value: 'en', label: 'English' },\n { value: 'fr', label: 'Français' },\n { value: 'it', label: 'Italiano' },\n { value: 'de', label: 'Deutsch' },\n];\n\nexport interface ConfigurationState {\n selectedLanguage: string;\n advancedHttpConfig: boolean;\n fixtureMode: boolean;\n selectorStrategy: string;\n filesystemGranted: boolean;\n cypressFolderName: string | null;\n smartSelectorEnabled: boolean;\n startHidden: boolean;\n resumeTtlMinutes: number;\n isExporting: boolean;\n exportMode: ExportMode;\n exportTests: TestWithDetails[];\n exportSelectedIds: Set<number>;\n exportSelectedTags: Set<string>;\n issueTrackerConfig: IssueTrackerConfig;\n isLoginSetupOpen: boolean;\n loginSetupConfig: LoginSetupConfig | null;\n // draft state — only populated while the overlay is open\n loginSetupDraftPath?: string;\n loginSetupDraftFunctions?: string[];\n loginSetupDraftBeforeFn?: string | null;\n loginSetupDraftBeforeEachFn?: string | null;\n loginSetupDraftHasContent?: boolean;\n}\n\nexport function renderExportOverlay(state: ConfigurationState, t: (key: string) => string): string {\n const { isExporting, exportMode, exportTests, exportSelectedIds, exportSelectedTags } = state;\n if (!isExporting) return '';\n\n const count = selectTestsForExport(exportTests, exportMode, {\n ids: exportSelectedIds,\n tags: exportSelectedTags,\n }).length;\n\n const modeBtn = (mode: ExportMode, key: string) =>\n `<button class=\"export-mode ${exportMode === mode ? 'active' : ''}\" data-export-mode=\"${mode}\">${t(key)}</button>`;\n\n let body: string;\n if (exportTests.length === 0) {\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_EMPTY')}</div>`;\n } else if (exportMode === 'all') {\n body = `<div class=\"export-all-desc\">${t('CONFIG.EXPORT_ALL_DESC')}</div>`;\n } else if (exportMode === 'manual') {\n body = `<div class=\"export-list\">${exportTests.map((test) => `\n <label class=\"export-row\">\n <input type=\"checkbox\" data-export-test=\"${test.id}\" ${exportSelectedIds.has(test.id) ? 'checked' : ''} />\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\n </label>`).join('')}</div>`;\n } else {\n const allTags = [...new Set(exportTests.flatMap((test) => test.tags ?? []))].sort();\n if (!allTags.length) {\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_NO_TAGS')}</div>`;\n } else {\n const chips = `<div class=\"export-tags\">${allTags.map((tag) =>\n `<button class=\"export-tag ${exportSelectedTags.has(tag) ? 'active' : ''}\" data-export-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}</div>`;\n // Preview the tests that the selected tags resolve to, so QA sees exactly\n // what will be exported.\n const matched = selectTestsForExport(exportTests, 'tags', { tags: exportSelectedTags });\n const preview = exportSelectedTags.size === 0\n ? `<div class=\"export-tag-hint\">${t('CONFIG.EXPORT_TAGS_HINT')}</div>`\n : `<div class=\"export-result-label\">${t('CONFIG.EXPORT_RESULT_LABEL')}</div>\n <div class=\"export-list\">${matched.map((test) => `\n <div class=\"export-row export-row-static\">\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\n </div>`).join('')}</div>`;\n body = chips + preview;\n }\n }\n\n return `\n <div class=\"export-overlay\" id=\"export-overlay\">\n <div class=\"export-modal\">\n <div class=\"export-hd\">${t('CONFIG.EXPORT_DIALOG_TITLE')}</div>\n ${exportTests.length ? `<div class=\"export-modes\">\n ${modeBtn('all', 'CONFIG.EXPORT_MODE_ALL')}\n ${modeBtn('manual', 'CONFIG.EXPORT_MODE_MANUAL')}\n ${modeBtn('tags', 'CONFIG.EXPORT_MODE_TAGS')}\n </div>` : ''}\n <div class=\"export-body\">${body}</div>\n <div class=\"export-ft\">\n <span class=\"export-count\">${t('CONFIG.EXPORT_COUNT')} <b>${count}</b></span>\n <span class=\"export-ft-actions\">\n <button id=\"btn-export-confirm\" class=\"btn-export-confirm\" ${count === 0 ? 'disabled' : ''}>${t('CONFIG.EXPORT_CONFIRM')}</button>\n <button id=\"btn-export-cancel\">${t('CONFIG.EXPORT_CANCEL')}</button>\n </span>\n </div>\n </div>\n </div>`;\n}\n\nexport function renderConfiguration(state: ConfigurationState, t: (key: string) => string): string {\n const { selectedLanguage, advancedHttpConfig, fixtureMode, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes, issueTrackerConfig } = state;\n\n const langOptions = LANGS.map(\n (l) => `<option value=\"${l.value}\" ${selectedLanguage === l.value ? 'selected' : ''}>${l.label}</option>`,\n ).join('');\n\n return `\n <div class=\"cfg-grid\">\n\n <!-- Language -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.LANG_SECTION')}</div>\n <div class=\"field-row\">\n <span class=\"field-label\">${t('CONFIG.LANG_FIELD')}</span>\n <select id=\"lang-select\">${langOptions}</select>\n </div>\n </div>\n\n <!-- HTTP Advanced -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.HTTP_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"http-toggle\" ${advancedHttpConfig ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.HTTP_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.HTTP_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- HTTP Fixtures -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.FIXTURE_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"fixture-toggle\" ${fixtureMode ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.FIXTURE_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.FIXTURE_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- Smart Selector -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.SMART_SELECTOR_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"smart-selector-toggle\" ${smartSelectorEnabled ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.SMART_SELECTOR_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.SMART_SELECTOR_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- Start Hidden -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.START_HIDDEN_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"start-hidden-toggle\" ${startHidden ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.START_HIDDEN_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.START_HIDDEN_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- Widget position (draggable widget) -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.WIDGET_POSITION_SECTION')}</div>\n <div class=\"check-sub\" style=\"margin-bottom:10px\">${t('CONFIG.WIDGET_POSITION_HINT')}</div>\n <div class=\"btn-row\">\n <button id=\"btn-reset-position\">${t('CONFIG.WIDGET_POSITION_RESET_BTN')}</button>\n </div>\n </div>\n\n <!-- Recording continuity (cross-app resume TTL) -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.RESUME_TTL_SECTION')}</div>\n <div class=\"field-row\">\n <span class=\"field-label\">${t('CONFIG.RESUME_TTL_LABEL')}</span>\n <input type=\"number\" id=\"resume-ttl-input\" min=\"1\" step=\"1\" value=\"${resumeTtlMinutes}\"\n style=\"width:80px;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none\" />\n </div>\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.RESUME_TTL_HINT')}</div>\n </div>\n\n <!-- Selector Strategy -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.SELECTOR_SECTION')}</div>\n <div class=\"field-row\">\n <span class=\"field-label\">${t('CONFIG.SELECTOR_LABEL')}</span>\n <select id=\"selector-strategy\">\n <option value=\"data-cy\" ${selectorStrategy === 'data-cy' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_DATACY')}</option>\n <option value=\"data-testid\" ${selectorStrategy === 'data-testid' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_TESTID')}</option>\n <option value=\"aria-label\" ${selectorStrategy === 'aria-label' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ARIA')}</option>\n <option value=\"id\" ${selectorStrategy === 'id' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ID')}</option>\n </select>\n </div>\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.SELECTOR_HINT')}</div>\n </div>\n\n <!-- Cypress Folder -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.FOLDER_SECTION')}</div>\n <div class=\"fs-layout\">\n <pre class=\"fs-tree\">cypress/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_PICK_HINT')}</span>\n└── e2e/\n └── *.cy.ts</pre>\n <div class=\"fs-right\">\n <div class=\"fs-status\">\n <span class=\"fs-dot ${filesystemGranted ? 'on' : 'off'}\"></span>\n ${filesystemGranted && cypressFolderName\n ? `<span>${t('CONFIG.FOLDER_CONNECTED')}</span> <span class=\"fs-folder\">📁 ${escHtml(cypressFolderName)}</span>`\n : `<span>${t('CONFIG.FOLDER_NOT_SET')}</span>`}\n </div>\n <div class=\"btn-row\">\n <button id=\"btn-change-folder\">\n ${filesystemGranted ? t('CONFIG.FOLDER_CHANGE_BTN') : t('CONFIG.FOLDER_SELECT_BTN')}\n </button>\n ${filesystemGranted\n ? `<button id=\"btn-revoke\" class=\"btn-danger\">${t('CONFIG.FOLDER_REVOKE_BTN')}</button>`\n : ''}\n </div>\n </div>\n </div>\n </div>\n\n <!-- Issue Tracker -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.ISSUE_TRACKER_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"issue-tracker-toggle\" ${issueTrackerConfig.enabled ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.ISSUE_TRACKER_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.ISSUE_TRACKER_SUB')}</div>\n </div>\n </label>\n ${issueTrackerConfig.enabled ? `\n <div class=\"field-row\" style=\"margin-top:10px\">\n <span class=\"field-label\">${t('CONFIG.ISSUE_TRACKER_PROVIDER')}</span>\n <select id=\"issue-tracker-provider\">\n ${Object.values(ISSUE_TRACKER_PRESETS).map((p) =>\n `<option value=\"${p.id}\" ${issueTrackerConfig.provider === p.id ? 'selected' : ''}>${escHtml(p.label)}</option>`\n ).join('')}\n </select>\n </div>\n <div class=\"field-row\" style=\"margin-top:8px\">\n <span class=\"field-label\">${t('CONFIG.ISSUE_TRACKER_BASE_URL')}</span>\n <input id=\"issue-tracker-base-url\" type=\"text\"\n placeholder=\"${escAttr(t('CONFIG.ISSUE_TRACKER_BASE_URL_PH'))}\"\n value=\"${escAttr(issueTrackerConfig.baseUrl)}\"\n style=\"flex:1;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none\" />\n </div>` : ''}\n </div>\n\n <!-- Login Setup -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.LOGIN_SETUP_SECTION')}</div>\n ${state.loginSetupConfig\n ? `<p style=\"font-size:12px;color:#8b949e;margin:0 0 8px\">${escHtml(state.loginSetupConfig.filePath)}</p>`\n : `<p style=\"font-size:12px;color:#8b949e;margin:0 0 8px\">${t('CONFIG.LOGIN_SETUP_NOT_CONFIGURED')}</p>`}\n <button id=\"btn-open-login-setup\" class=\"btn-sm\">${t('CONFIG.LOGIN_SETUP_SET_UP_BTN')}</button>\n </div>\n\n <!-- Data -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.DATA_SECTION')}</div>\n <p class=\"data-desc\">${t('CONFIG.DATA_DESC')}</p>\n <div class=\"btn-row\">\n <button id=\"btn-export\">${t('CONFIG.EXPORT_BTN')}</button>\n <label style=\"cursor:pointer;margin:0\">\n <span class=\"btn-import\">${t('CONFIG.IMPORT_BTN')}</span>\n <input type=\"file\" class=\"file-input\" id=\"file-input\" accept=\".json\" />\n </label>\n </div>\n </div>\n\n </div>${renderExportOverlay(state, t)}${renderLoginSetupOverlay(state, t)}`;\n}\n\nfunction renderLoginSetupOverlay(state: ConfigurationState, t: (key: string) => string): string {\n if (!state.isLoginSetupOpen) return '';\n\n const cfg = state.loginSetupConfig;\n const path = state.loginSetupDraftPath ?? cfg?.filePath ?? '';\n const fns = state.loginSetupDraftFunctions ?? cfg?.detectedFunctions ?? [];\n const beforeFn = state.loginSetupDraftBeforeFn !== undefined\n ? state.loginSetupDraftBeforeFn : (cfg?.beforeFn ?? null);\n const beforeEachFn = state.loginSetupDraftBeforeEachFn !== undefined\n ? state.loginSetupDraftBeforeEachFn : (cfg?.beforeEachFn ?? null);\n const hasContent = state.loginSetupDraftHasContent ?? !!(cfg?.fileContent);\n\n const fnOption = (name: string | null, selected: string | null) =>\n `<option value=\"${escAttr(name ?? '')}\" ${selected === name ? 'selected' : ''}>${name ? escHtml(name) : t('CONFIG.LOGIN_SETUP_NONE_OPTION')}</option>`;\n\n const fnDropdown = (id: string, label: string, selected: string | null) => `\n <div class=\"ls-field-block\">\n <label class=\"ls-label\" for=\"${id}\">${escHtml(label)}</label>\n <select id=\"${id}\" class=\"ls-select\">\n ${fnOption(null, selected)}\n ${fns.map((fn) => fnOption(fn, selected)).join('')}\n </select>\n </div>`;\n\n const functionsSection = hasContent\n ? (fns.length > 0\n ? `<div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_FUNCTIONS_DETECTED')}</span>\n <div class=\"ls-fns\">${fns.map((fn) => `<span class=\"ls-fn-chip\">${escHtml(fn)}</span>`).join('')}</div>\n </div>\n <div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_BLOCK_ASSIGN')}</span>\n ${fnDropdown('login-setup-before-fn', t('CONFIG.LOGIN_SETUP_BEFORE_LABEL'), beforeFn)}\n ${fnDropdown('login-setup-before-each-fn', t('CONFIG.LOGIN_SETUP_BEFORE_EACH_LABEL'), beforeEachFn)}\n </div>`\n : `<div class=\"ls-empty-state\">\n <span class=\"ls-empty-icon\">🔍</span>\n <span>${t('CONFIG.LOGIN_SETUP_NO_FUNCTIONS')}</span>\n </div>`)\n : '';\n\n const fileSection = hasContent\n ? `<div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_FILE_NAME_LABEL')}</span>\n <div class=\"ls-file-row\">\n <span class=\"ls-file-icon\">📄</span>\n <span class=\"ls-file-name\">${escHtml(path)}</span>\n <button id=\"btn-login-setup-rescan\" class=\"ls-btn-rescan\">${t('CONFIG.LOGIN_SETUP_RESCAN')}</button>\n </div>\n </div>`\n : `<div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_FILE_NAME_LABEL')}</span>\n <input id=\"login-setup-filepath\" type=\"text\" class=\"ls-input\"\n placeholder=\"${escAttr(t('CONFIG.LOGIN_SETUP_FILE_NAME_PH'))}\"\n value=\"${escAttr(path)}\" />\n </div>`;\n\n return `\n <div class=\"export-overlay\" id=\"login-setup-overlay\">\n <div class=\"export-modal ls-modal\">\n\n <div class=\"export-hd ls-hd\">\n <span class=\"ls-hd-icon\">🔐</span>\n ${t('CONFIG.LOGIN_SETUP_TITLE')}\n </div>\n\n <div class=\"ls-body\">\n\n <div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_SOURCE_LABEL')}</span>\n <div class=\"ls-actions\">\n <button id=\"btn-login-setup-create-scaffold\" class=\"ls-action-btn\">\n <span class=\"ls-action-icon\">✨</span>\n <span class=\"ls-action-label\">${t('CONFIG.LOGIN_SETUP_CREATE_SCAFFOLD')}</span>\n <span class=\"ls-action-sub\">${t('CONFIG.LOGIN_SETUP_CREATE_SUB')}</span>\n </button>\n <button id=\"btn-login-setup-pick-file\" class=\"ls-action-btn\">\n <span class=\"ls-action-icon\">📂</span>\n <span class=\"ls-action-label\">${t('CONFIG.LOGIN_SETUP_SELECT_EXISTING')}</span>\n <span class=\"ls-action-sub\">${t('CONFIG.LOGIN_SETUP_SELECT_SUB')}</span>\n </button>\n </div>\n </div>\n\n ${fileSection}\n\n ${functionsSection}\n\n </div>\n\n <div class=\"export-ft ls-ft\">\n <button id=\"btn-login-setup-clear\" class=\"btn-danger\">${t('CONFIG.LOGIN_SETUP_CLEAR_BTN')}</button>\n <span class=\"export-ft-actions\">\n <button id=\"btn-login-setup-cancel\">${t('CONFIG.LOGIN_SETUP_CANCEL_BTN')}</button>\n <button id=\"btn-login-setup-save\" class=\"btn-primary\">${t('CONFIG.LOGIN_SETUP_SAVE_BTN')}</button>\n </span>\n </div>\n\n </div>\n </div>`;\n}\n","import { PersistenceService } from '../../services/persistence.service';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport { TranslationService } from '../../services/translation.service';\nimport type { Lang } from '../../models/lang.model';\nimport type { SelectorStrategy } from '../../services/recording.service';\nimport { RESUME_TTL_CONFIG_KEY, DEFAULT_RESUME_TTL_MINUTES } from '../../models/active-session.model';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG, type IssueTrackerConfig, type IssueTrackerProvider } from '../../models/issue-tracker.model';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\nimport { extractExportedFunctions, buildLoginScaffold } from '../../utils/login-setup.utils';\nimport { showToast } from '../../utils/toast.utils';\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\nimport { CONFIGURATION_STYLES } from './configuration.styles';\nimport { renderConfiguration } from './configuration.template';\n\nexport class ConfigurationElement extends HTMLElement {\n private shadow: ShadowRoot;\n persistence!: PersistenceService;\n translation!: TranslationService;\n selectedLanguage = 'es';\n advancedHttpConfig = false;\n fixtureMode = false;\n selectorStrategy: SelectorStrategy = 'data-cy';\n smartSelectorEnabled = true;\n startHidden = false;\n resumeTtlMinutes = DEFAULT_RESUME_TTL_MINUTES;\n isExporting = false;\n exportMode: ExportMode = 'all';\n exportTests: TestWithDetails[] = [];\n exportSelectedIds: Set<number> = new Set();\n exportSelectedTags: Set<string> = new Set();\n issueTrackerConfig: IssueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };\n isLoginSetupOpen = false;\n loginSetupConfig: LoginSetupConfig | null = null;\n loginSetupDraftPath = '';\n loginSetupDraftFunctions: string[] = [];\n loginSetupDraftBeforeFn: string | null = null;\n loginSetupDraftBeforeEachFn: string | null = null;\n loginSetupDraftHasContent = false;\n private loginSetupDraftHandle: FileSystemFileHandle | null = null;\n private loginSetupDraftContent = '';\n private filesystemGranted = false;\n private cypressFolderName: string | null = null;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n // Read from localStorage (sync cache) — see initHttpConfig() in the recorder.\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\n this.fixtureMode = localStorage.getItem('fixtureMode') === 'true';\n }\n\n connectedCallback(): void {\n if (!this.persistence) this.persistence = new PersistenceService();\n if (!this.translation) this.translation = new TranslationService();\n this.loadConfig();\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private async loadConfig(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n if (config?.['language']) {\n this.selectedLanguage = config['language'] as string;\n this.translation.setLang(this.selectedLanguage as Lang);\n }\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\n this.fixtureMode = localStorage.getItem('fixtureMode') === 'true';\n this.selectorStrategy = (config?.['selectorStrategy'] as SelectorStrategy) ?? 'data-cy';\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\n this.startHidden = config?.['startHidden'] === 'true';\n // Only override when the key exists — otherwise an async load could clobber a\n // value just set via onResumeTtlChange (same pattern as `language`).\n const ttlRaw = config?.[RESUME_TTL_CONFIG_KEY];\n if (ttlRaw !== undefined && ttlRaw !== null) {\n const ttl = Number(ttlRaw);\n this.resumeTtlMinutes = Number.isFinite(ttl) && ttl > 0 ? ttl : DEFAULT_RESUME_TTL_MINUTES;\n }\n this.filesystemGranted = config?.['allowReadWriteFiles'] === 'true';\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\n this.cypressFolderName = handle?.name ?? null;\n this.issueTrackerConfig = {\n enabled: config?.['issueTrackerEnabled'] === 'true',\n provider: (config?.['issueTrackerProvider'] as IssueTrackerProvider) ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,\n baseUrl: (config?.['issueTrackerBaseUrl'] as string) ?? '',\n };\n this.loginSetupConfig = await this.persistence.getLoginSetup();\n this.render();\n }\n\n async onLanguageChange(lang: string): Promise<void> {\n this.selectedLanguage = lang;\n this.translation.setLang(lang as Lang);\n await this.persistence.setConfig({ language: lang });\n this.render();\n }\n\n onAdvancedHttpConfigChange(checked: boolean): void {\n this.advancedHttpConfig = checked;\n // Write to both: localStorage for immediate sync access by HttpMonitor,\n // IndexedDB as persistent source of truth mirrored on recorder mount.\n localStorage.setItem('extendedHttpCommands', checked ? 'true' : 'false');\n this.persistence.setConfig({ extendedHttpCommands: checked ? 'true' : 'false' });\n this.render();\n }\n\n onFixtureModeChange(checked: boolean): void {\n this.fixtureMode = checked;\n // Same dual-write pattern as extendedHttpCommands — see above.\n localStorage.setItem('fixtureMode', checked ? 'true' : 'false');\n this.persistence.setConfig({ fixtureMode: checked ? 'true' : 'false' });\n this.render();\n }\n\n async onStartHiddenChange(checked: boolean): Promise<void> {\n this.startHidden = checked;\n await this.persistence.setConfig({ startHidden: checked ? 'true' : 'false' });\n this.dispatchEvent(new CustomEvent('starthiddenchange', { detail: checked, bubbles: true, composed: true }));\n this.render();\n }\n\n async onResumeTtlChange(minutes: number): Promise<void> {\n const safe = Number.isFinite(minutes) && minutes > 0 ? Math.round(minutes) : DEFAULT_RESUME_TTL_MINUTES;\n this.resumeTtlMinutes = safe;\n await this.persistence.setConfig({ [RESUME_TTL_CONFIG_KEY]: safe });\n this.render();\n }\n\n onResetWidgetPosition(): void {\n this.dispatchEvent(new CustomEvent('resetwidgetposition', { bubbles: true, composed: true }));\n showToast(this.t('CONFIG.WIDGET_POSITION_RESET_DONE'));\n }\n\n async onSmartSelectorChange(enabled: boolean): Promise<void> {\n this.smartSelectorEnabled = enabled;\n await this.persistence.setConfig({ smartSelectorEnabled: enabled ? 'true' : 'false' });\n this.dispatchEvent(new CustomEvent('smartselectorchange', { detail: enabled, bubbles: true, composed: true }));\n this.render();\n }\n\n async onSelectorStrategyChange(strategy: SelectorStrategy): Promise<void> {\n this.selectorStrategy = strategy;\n await this.persistence.setConfig({ selectorStrategy: strategy });\n this.dispatchEvent(new CustomEvent('selectorstrategychange', { detail: strategy, bubbles: true, composed: true }));\n this.render();\n }\n\n async onIssueTrackerEnabledChange(enabled: boolean): Promise<void> {\n this.issueTrackerConfig = { ...this.issueTrackerConfig, enabled };\n await this.persistence.setConfig({ issueTrackerEnabled: enabled ? 'true' : 'false' });\n this.dispatchEvent(new CustomEvent('issuetrackerchange', { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));\n this.render();\n }\n\n async onIssueTrackerProviderChange(provider: IssueTrackerProvider): Promise<void> {\n this.issueTrackerConfig = { ...this.issueTrackerConfig, provider };\n await this.persistence.setConfig({ issueTrackerProvider: provider });\n this.dispatchEvent(new CustomEvent('issuetrackerchange', { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));\n this.render();\n }\n\n async onIssueTrackerBaseUrlChange(baseUrl: string): Promise<void> {\n this.issueTrackerConfig = { ...this.issueTrackerConfig, baseUrl };\n await this.persistence.setConfig({ issueTrackerBaseUrl: baseUrl });\n this.dispatchEvent(new CustomEvent('issuetrackerchange', { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));\n }\n\n openLoginSetupPanel(): void {\n this.isLoginSetupOpen = true;\n const cfg = this.loginSetupConfig;\n this.loginSetupDraftHandle = null;\n this.loginSetupDraftContent = cfg?.fileContent ?? '';\n this.loginSetupDraftPath = cfg?.filePath ?? '';\n this.loginSetupDraftFunctions = cfg?.detectedFunctions ?? [];\n this.loginSetupDraftBeforeFn = cfg?.beforeFn ?? null;\n this.loginSetupDraftBeforeEachFn = cfg?.beforeEachFn ?? null;\n this.loginSetupDraftHasContent = !!(cfg?.fileContent);\n this.render();\n }\n\n closeLoginSetupPanel(): void {\n this.isLoginSetupOpen = false;\n this.render();\n }\n\n async saveLoginSetupConfig(config: LoginSetupConfig): Promise<void> {\n await this.persistence.saveLoginSetup(config);\n this.loginSetupConfig = config;\n this.isLoginSetupOpen = false;\n this.render();\n }\n\n async clearLoginSetupConfig(): Promise<void> {\n await this.persistence.clearLoginSetup();\n this.loginSetupConfig = null;\n this.render();\n }\n\n async loginSetupPickFile(): Promise<void> {\n type OpenPicker = (opts: object) => Promise<FileSystemFileHandle[]>;\n const currentPath = (this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null)?.value.trim() ?? '';\n try {\n const [handle] = await (window as unknown as { showOpenFilePicker: OpenPicker }).showOpenFilePicker({\n types: [{ description: 'TypeScript files', accept: { 'text/plain': ['.ts'] } }],\n multiple: false,\n });\n this.loginSetupDraftHandle = handle;\n const file = await handle.getFile();\n this.loginSetupDraftContent = await file.text();\n this.loginSetupDraftHasContent = true;\n this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;\n this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);\n this.render();\n } catch (e) {\n if ((e as DOMException)?.name !== 'AbortError') showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\n }\n }\n\n async loginSetupCreateScaffold(): Promise<void> {\n type SavePicker = (opts: object) => Promise<FileSystemFileHandle>;\n const currentPath = (this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null)?.value.trim() ?? '';\n try {\n const handle = await (window as unknown as { showSaveFilePicker: SavePicker }).showSaveFilePicker({\n suggestedName: 'login.service.ts',\n types: [{ description: 'TypeScript files', accept: { 'text/plain': ['.ts'] } }],\n });\n const content = buildLoginScaffold();\n const writable = await handle.createWritable();\n await writable.write(content);\n await writable.close();\n this.loginSetupDraftHandle = handle;\n this.loginSetupDraftContent = content;\n this.loginSetupDraftHasContent = true;\n this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;\n this.loginSetupDraftFunctions = extractExportedFunctions(content);\n this.render();\n } catch (e) {\n if ((e as DOMException)?.name !== 'AbortError') showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\n }\n }\n\n async loginSetupRescan(): Promise<void> {\n const currentPath = (this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null)?.value.trim();\n if (currentPath !== undefined) this.loginSetupDraftPath = currentPath;\n try {\n if (this.loginSetupDraftHandle) {\n const file = await this.loginSetupDraftHandle.getFile();\n this.loginSetupDraftContent = await file.text();\n }\n this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);\n this.render();\n } catch { /* silently ignore */ }\n }\n\n async changeFolder(): Promise<void> {\n try {\n await this.persistence.requestDirectoryPermissions();\n await this.loadConfig();\n showToast(this.t('CONFIG.FOLDER_UPDATED_TOAST'));\n } catch (e: unknown) {\n if ((e as DOMException)?.name !== 'AbortError') {\n showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\n }\n }\n }\n\n async revokeAccess(): Promise<void> {\n await this.persistence.setConfig({ allowReadWriteFiles: 'false', cypressDirectoryHandle: null });\n this.filesystemGranted = false;\n this.cypressFolderName = null;\n this.render();\n }\n\n private downloadTests(tests: TestWithDetails[]): void {\n const blob = new Blob([JSON.stringify({ tests, interceptors: [] }, null, 2)], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'e2e-cypress-export.json';\n a.click();\n URL.revokeObjectURL(url);\n }\n\n /** Downloads every saved test (used by the \"Todo\" mode and as a direct API). */\n async exportAllData(): Promise<void> {\n const tests = await this.persistence.getAllTests();\n this.downloadTests(tests);\n }\n\n /** Opens the export selection dialog, loading the current tests. */\n async openExportDialog(): Promise<void> {\n this.exportTests = await this.persistence.getAllTests();\n this.exportMode = 'all';\n this.exportSelectedIds = new Set();\n this.exportSelectedTags = new Set();\n this.isExporting = true;\n this.render();\n }\n\n cancelExport(): void {\n this.isExporting = false;\n this.exportSelectedIds.clear();\n this.exportSelectedTags.clear();\n this.render();\n }\n\n setExportMode(mode: ExportMode): void {\n this.exportMode = mode;\n this.render();\n }\n\n toggleExportTest(id: number): void {\n if (this.exportSelectedIds.has(id)) this.exportSelectedIds.delete(id);\n else this.exportSelectedIds.add(id);\n this.render();\n }\n\n toggleExportTag(tag: string): void {\n if (this.exportSelectedTags.has(tag)) this.exportSelectedTags.delete(tag);\n else this.exportSelectedTags.add(tag);\n this.render();\n }\n\n /** Downloads the tests resolved by the current mode + selection. No-op if empty. */\n confirmExport(): void {\n const subset = selectTestsForExport(this.exportTests, this.exportMode, {\n ids: this.exportSelectedIds,\n tags: this.exportSelectedTags,\n });\n if (!subset.length) return;\n this.downloadTests(subset);\n this.isExporting = false;\n this.exportSelectedIds.clear();\n this.exportSelectedTags.clear();\n this.render();\n }\n\n async importAllData(file: File): Promise<void> {\n const text = await file.text();\n let data: { tests: Record<string, unknown>[]; interceptors: Record<string, unknown>[] };\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(this.t('CONFIG.JSON_INVALID'));\n }\n if (!data || !Array.isArray(data.tests) || !Array.isArray(data.interceptors)) {\n throw new Error(this.t('CONFIG.JSON_BAD_FORMAT'));\n }\n // Merge: append the imported tests to whatever is already stored — never wipe\n // existing data (see docs/specs/004-merge-on-import.md).\n await this.persistence.ingestFileData(data.tests, data.interceptors);\n }\n\n private render(): void {\n this.shadow.innerHTML = `<style>${CONFIGURATION_STYLES}</style>${renderConfiguration({\n selectedLanguage: this.selectedLanguage,\n advancedHttpConfig: this.advancedHttpConfig,\n fixtureMode: this.fixtureMode,\n selectorStrategy: this.selectorStrategy,\n filesystemGranted: this.filesystemGranted,\n cypressFolderName: this.cypressFolderName,\n smartSelectorEnabled: this.smartSelectorEnabled,\n startHidden: this.startHidden,\n resumeTtlMinutes: this.resumeTtlMinutes,\n isExporting: this.isExporting,\n exportMode: this.exportMode,\n exportTests: this.exportTests,\n exportSelectedIds: this.exportSelectedIds,\n exportSelectedTags: this.exportSelectedTags,\n issueTrackerConfig: this.issueTrackerConfig,\n isLoginSetupOpen: this.isLoginSetupOpen,\n loginSetupConfig: this.loginSetupConfig,\n loginSetupDraftPath: this.loginSetupDraftPath,\n loginSetupDraftFunctions: this.loginSetupDraftFunctions,\n loginSetupDraftBeforeFn: this.loginSetupDraftBeforeFn,\n loginSetupDraftBeforeEachFn: this.loginSetupDraftBeforeEachFn,\n loginSetupDraftHasContent: this.loginSetupDraftHasContent,\n }, this.t.bind(this))}`;\n ;(this.shadow.getElementById('lang-select') as HTMLSelectElement).addEventListener('change', (e) =>\n this.onLanguageChange((e.target as HTMLSelectElement).value),\n )\n ;(this.shadow.getElementById('http-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onAdvancedHttpConfigChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('fixture-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onFixtureModeChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('smart-selector-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onSmartSelectorChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('start-hidden-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onStartHiddenChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('resume-ttl-input') as HTMLInputElement).addEventListener('change', (e) =>\n this.onResumeTtlChange(Number((e.target as HTMLInputElement).value)),\n )\n ;this.shadow.getElementById('btn-reset-position')?.addEventListener('click', () => this.onResetWidgetPosition())\n ;(this.shadow.getElementById('selector-strategy') as HTMLSelectElement).addEventListener('change', (e) =>\n this.onSelectorStrategyChange((e.target as HTMLSelectElement).value as SelectorStrategy),\n );\n\n ;(this.shadow.getElementById('issue-tracker-toggle') as HTMLInputElement)?.addEventListener('change', (e) =>\n this.onIssueTrackerEnabledChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('issue-tracker-provider') as HTMLSelectElement)?.addEventListener('change', (e) =>\n this.onIssueTrackerProviderChange((e.target as HTMLSelectElement).value as IssueTrackerProvider),\n )\n ;(this.shadow.getElementById('issue-tracker-base-url') as HTMLInputElement)?.addEventListener('change', (e) =>\n this.onIssueTrackerBaseUrlChange((e.target as HTMLInputElement).value),\n )\n ;this.shadow.getElementById('btn-change-folder')?.addEventListener('click', () => this.changeFolder());\n this.shadow.getElementById('btn-revoke')?.addEventListener('click', () => this.revokeAccess());\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.openExportDialog());\n\n this.shadow.getElementById('btn-export-confirm')?.addEventListener('click', () => this.confirmExport());\n this.shadow.getElementById('btn-export-cancel')?.addEventListener('click', () => this.cancelExport());\n this.shadow.querySelectorAll('[data-export-mode]').forEach((el) =>\n el.addEventListener('click', () => this.setExportMode((el as HTMLElement).dataset['exportMode'] as ExportMode)),\n );\n this.shadow.querySelectorAll('[data-export-test]').forEach((el) =>\n el.addEventListener('change', () => this.toggleExportTest(Number((el as HTMLElement).dataset['exportTest']))),\n );\n this.shadow.querySelectorAll('[data-export-tag]').forEach((el) =>\n el.addEventListener('click', () => this.toggleExportTag((el as HTMLElement).dataset['exportTag'] ?? '')),\n );\n this.shadow.getElementById('btn-open-login-setup')?.addEventListener('click', () => this.openLoginSetupPanel());\n this.shadow.getElementById('btn-login-setup-cancel')?.addEventListener('click', () => this.closeLoginSetupPanel());\n this.shadow.getElementById('btn-login-setup-pick-file')?.addEventListener('click', () => this.loginSetupPickFile());\n this.shadow.getElementById('btn-login-setup-create-scaffold')?.addEventListener('click', () => this.loginSetupCreateScaffold());\n this.shadow.getElementById('btn-login-setup-rescan')?.addEventListener('click', () => this.loginSetupRescan());\n this.shadow.getElementById('btn-login-setup-clear')?.addEventListener('click', () => this.clearLoginSetupConfig());\n this.shadow.getElementById('btn-login-setup-save')?.addEventListener('click', async () => {\n const pathEl = this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null;\n const beforeEl = this.shadow.getElementById('login-setup-before-fn') as HTMLSelectElement | null;\n const beforeEachEl = this.shadow.getElementById('login-setup-before-each-fn') as HTMLSelectElement | null;\n await this.saveLoginSetupConfig({\n enabled: true,\n filePath: pathEl?.value.trim() ?? this.loginSetupDraftPath,\n fileContent: this.loginSetupDraftContent,\n detectedFunctions: this.loginSetupDraftFunctions,\n beforeFn: beforeEl?.value || null,\n beforeEachFn: beforeEachEl?.value || null,\n });\n });\n\n ;(this.shadow.getElementById('file-input') as HTMLInputElement).addEventListener('change', async (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (!file) return;\n try {\n await this.importAllData(file);\n showToast(this.t('CONFIG.IMPORT_SUCCESS'));\n } catch (err: unknown) {\n showToast((err as Error).message ?? this.t('CONFIG.IMPORT_ERROR'), false);\n }\n const target = e.target as HTMLInputElement | null;\n if (target) target.value = '';\n });\n }\n}\n\nif (!customElements.get('lib-e2e-configuration')) {\n customElements.define('lib-e2e-configuration', ConfigurationElement);\n}\n","import Swal from 'sweetalert2';\nimport { PersistenceService } from '../../services/persistence.service';\nimport { TranslationService } from '../../services/translation.service';\nimport { AdvancedTestTransformationService } from '../../services/advanced-test.transformation.service';\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { buildLoginBlocks, buildLoginImportPath, hasLoginBlocks, injectLoginBlocksIntoExisting } from '../../utils/login-setup.utils';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\nimport { ADVANCED_TEST_EDITOR_STYLES } from './advanced-test-editor.styles';\nimport { renderNoPermission, renderAdvancedEditor, findFileHandleRecursive } from './advanced-test-editor.template';\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\n\nexport class AdvancedTestEditorElement extends HTMLElement {\n private shadow: ShadowRoot;\n private readonly transformationService = new AdvancedTestTransformationService();\n\n persistence!: PersistenceService;\n translation!: TranslationService;\n testId?: number;\n\n e2eTree: Array<DirectoryNode | FileNode> = [];\n selectedFile: unknown = null;\n saveButtonEnabled = false;\n selectedFileHandle: FileSystemFileHandle | null = null;\n selectedFileContent: string | null = null;\n testItBlock = '';\n interceptorsBlock = '';\n testNotes = '';\n isPreviewMode = false;\n previewFileName: string | null = null;\n previewFileContent: string | null = null;\n isCreatingFile = false;\n isCreatingFolder = false;\n collapsedDirs: Set<string> = new Set();\n sidebarWidth = 220;\n loginSetupConfig: LoginSetupConfig | null = null;\n private hasPermission = false;\n private needsReauth = false;\n private _dirHandle: FileSystemDirectoryHandle | null = null;\n private _e2eHandle: FileSystemDirectoryHandle | null = null;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.persistence) this.persistence = new PersistenceService();\n if (!this.translation) this.translation = new TranslationService();\n this.init();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private async init(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n const allowed = config?.['allowReadWriteFiles'] === 'true';\n\n if (!allowed) {\n this.hasPermission = false;\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\n this.render();\n return;\n }\n\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | null;\n if (!handle) {\n this.hasPermission = false;\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\n this.render();\n return;\n }\n\n // queryPermission does NOT require a user gesture\n const perm = await (handle as unknown as FileSystemHandleWithPermission).queryPermission({ mode: 'readwrite' });\n this._dirHandle = handle;\n this.hasPermission = perm === 'granted';\n this.needsReauth = perm === 'prompt';\n\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\n if (this.hasPermission) await this.getFoldersData();\n this.render();\n }\n\n async getFoldersData(): Promise<void> {\n if (!this.hasPermission || !this._dirHandle) return;\n try {\n for await (const entry of this._dirHandle.values()) {\n if (entry.kind === 'directory' && entry.name === 'e2e') {\n this._e2eHandle = entry as FileSystemDirectoryHandle;\n const tree = await this.transformationService.scanDirectory(this._e2eHandle);\n this.e2eTree = tree.children ?? [];\n this.render();\n return;\n }\n }\n } catch { /* silently skip permission errors */ }\n }\n\n async createNewFile(rawName: string): Promise<void> {\n if (!this._e2eHandle) return;\n const name = rawName.trim().replace(/\\.cy\\.ts$/, '');\n if (!name) return;\n const fileName = `${name}.cy.ts`;\n\n const cfg = this.loginSetupConfig;\n if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {\n const e2eName = this._e2eHandle.name ?? 'e2e';\n const fromPath = `cypress/${e2eName}/${fileName}`;\n const importPath = buildLoginImportPath(fromPath, cfg.filePath);\n const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(\n importPath, cfg.beforeFn, cfg.beforeEachFn,\n );\n const header = importLine ? `${importLine}\\n\\n` : '';\n const inner = [beforeBlock, beforeEachBlock].filter(Boolean).join('');\n const template = `${header}describe('${escapeSingleQuotes(name)}', () => {\\n${inner}\\n it('should ', () => {\\n\\n });\\n\\n});\\n`;\n try {\n const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(template);\n await writable.close();\n } catch { /* silently ignore */ }\n } else {\n const template = `describe('${escapeSingleQuotes(name)}', () => {\\n\\n it('should ', () => {\\n\\n });\\n\\n});\\n`;\n try {\n const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(template);\n await writable.close();\n } catch { /* silently ignore */ }\n }\n this.isCreatingFile = false;\n await this.getFoldersData();\n }\n\n async createNewFolder(rawName: string): Promise<void> {\n if (!this._e2eHandle) return;\n const name = rawName.trim().replace(/[/\\\\]/g, '');\n if (!name) return;\n try {\n await this._e2eHandle.getDirectoryHandle(name, { create: true });\n } catch { /* silently ignore if folder already exists or permission denied */ }\n this.isCreatingFolder = false;\n await this.getFoldersData();\n }\n\n async refreshTree(): Promise<void> {\n await this.getFoldersData();\n }\n\n async saveCommandsToFile(): Promise<void> {\n if (!this.selectedFileHandle || !this.selectedFileContent || !this.testItBlock) return;\n let content = this.selectedFileContent;\n if (this.interceptorsBlock) {\n content = this.transformationService.insertBeforeEach(content, this.interceptorsBlock);\n }\n const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + '\\n' : '';\n content = this.transformationService.insertItBlock(content, comment + this.testItBlock);\n if (!content) return;\n\n const cfg = this.loginSetupConfig;\n if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {\n const fns = [cfg.beforeFn, cfg.beforeEachFn].filter(Boolean) as string[];\n if (!hasLoginBlocks(content, fns)) {\n const e2eName = this._e2eHandle?.name ?? 'e2e';\n const fileName = (this.selectedFile as { name: string } | null)?.name ?? '';\n const fromPath = `cypress/${e2eName}/${fileName}`;\n const importPath = buildLoginImportPath(fromPath, cfg.filePath);\n const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(importPath, cfg.beforeFn, cfg.beforeEachFn);\n const result = await Swal.fire({\n title: this.t('CONFIG.LOGIN_SETUP_INJECT_TITLE'),\n html: `<div style=\"padding:10px 18px 14px;color:#8b949e;font-size:13px;line-height:1.6;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif\">${this.t('CONFIG.LOGIN_SETUP_INJECT_TEXT')}</div>`,\n icon: 'question',\n showCancelButton: true,\n confirmButtonText: this.t('CONFIG.LOGIN_SETUP_INJECT_CONFIRM'),\n cancelButtonText: this.t('CONFIG.LOGIN_SETUP_CANCEL_BTN'),\n confirmButtonColor: '#1f6feb',\n width: 460,\n });\n if (result.isConfirmed) {\n content = injectLoginBlocksIntoExisting(content, importLine, beforeBlock, beforeEachBlock);\n }\n }\n }\n\n const writable = await this.selectedFileHandle.createWritable();\n await writable.write(content);\n await writable.close();\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\n }\n\n async onFileClick(file: unknown): Promise<void> {\n if (!this.transformationService.isFile(file)) return;\n this.selectedFile = file;\n this.saveButtonEnabled = true;\n\n if (!this._dirHandle) return;\n const handle = await findFileHandleRecursive(this._dirHandle, (file as { name: string }).name);\n if (!handle) return;\n this.selectedFileHandle = handle;\n const fileObj = await handle.getFile();\n this.selectedFileContent = await fileObj.text();\n this.render();\n }\n\n markFileAsSelected(file: unknown): void {\n this.selectedFile = file;\n }\n\n async loadCypressCommandsForTest(testId: number): Promise<void> {\n const test = await this.persistence.getTestById(testId);\n if (test) {\n this.testItBlock = test.itBlock ?? '';\n this.interceptorsBlock = test.interceptorsBlock ?? '';\n this.testNotes = test.notes ?? '';\n } else {\n this.testItBlock = '';\n this.interceptorsBlock = '';\n this.testNotes = '';\n }\n this.render();\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard?.writeText(text);\n }\n\n openEditManually(): void {\n if (!this.selectedFileHandle || !this.selectedFileContent) return;\n this.dispatchEvent(new CustomEvent('openfileeditor', {\n detail: {\n handle: this.selectedFileHandle,\n content: this.selectedFileContent,\n fileName: (this.selectedFile as { name?: string } | null)?.name ?? '',\n testId: this.testId,\n itBlock: this.testItBlock,\n interceptorsBlock: this.interceptorsBlock,\n notes: this.testNotes,\n },\n bubbles: true,\n composed: true,\n }));\n }\n\n toggleDir(path: string): void {\n if (this.collapsedDirs.has(path)) {\n this.collapsedDirs.delete(path);\n } else {\n this.collapsedDirs.add(path);\n }\n this.render();\n }\n\n private setupResizeHandle(): void {\n const handle = this.shadow.getElementById('resize-handle');\n const sidebar = this.shadow.querySelector('.sidebar') as HTMLElement | null;\n if (!handle || !sidebar) return;\n\n let startX = 0;\n let startWidth = 0;\n\n const onMouseMove = (e: MouseEvent) => {\n const delta = e.clientX - startX;\n const newWidth = Math.max(140, Math.min(500, startWidth + delta));\n this.sidebarWidth = newWidth;\n sidebar.style.width = `${newWidth}px`;\n };\n\n const onMouseUp = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n handle.classList.remove('dragging');\n };\n\n handle.addEventListener('mousedown', (e: MouseEvent) => {\n startX = e.clientX;\n startWidth = sidebar.offsetWidth;\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n handle.classList.add('dragging');\n e.preventDefault();\n });\n }\n\n closePreview(): void {\n this.isPreviewMode = false;\n this.previewFileName = null;\n this.previewFileContent = null;\n if (this.testId !== undefined) {\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\n }\n this.render();\n }\n\n private render(): void {\n if (!this.hasPermission) {\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderNoPermission(this.needsReauth, this.t.bind(this))}`;\n\n this.shadow.getElementById('btn-reauth')?.addEventListener('click', async () => {\n if (!this._dirHandle) return;\n const perm = await (this._dirHandle as unknown as FileSystemHandleWithPermission).requestPermission({ mode: 'readwrite' });\n if (perm === 'granted') {\n this.hasPermission = true;\n this.needsReauth = false;\n await this.getFoldersData();\n this.render();\n }\n });\n return;\n }\n\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderAdvancedEditor({\n e2eTree: this.e2eTree,\n selectedFile: this.selectedFile,\n selectedFileContent: this.selectedFileContent,\n testItBlock: this.testItBlock,\n interceptorsBlock: this.interceptorsBlock,\n testNotes: this.testNotes,\n saveButtonEnabled: this.saveButtonEnabled,\n isCreatingFile: this.isCreatingFile,\n isCreatingFolder: this.isCreatingFolder,\n collapsedDirs: this.collapsedDirs,\n sidebarWidth: this.sidebarWidth,\n }, this.t.bind(this))}`;\n\n this.shadow.querySelectorAll('[data-file]').forEach((el) => {\n el.addEventListener('click', () => {\n const data = (el as HTMLElement).dataset['file'];\n if (data) this.onFileClick(JSON.parse(data));\n });\n });\n this.shadow.querySelectorAll('[data-dir-path]').forEach((el) => {\n el.addEventListener('click', () => {\n const path = (el as HTMLElement).dataset['dirPath'];\n if (path) this.toggleDir(path);\n });\n });\n this.setupResizeHandle();\n this.shadow.getElementById('btn-save')\n ?.addEventListener('click', () => this.saveCommandsToFile());\n this.shadow.getElementById('btn-edit')\n ?.addEventListener('click', () => this.openEditManually());\n this.shadow.getElementById('btn-copy-it')\n ?.addEventListener('click', () => this.copyToClipboard(this.testItBlock));\n this.shadow.getElementById('btn-copy-interceptors')\n ?.addEventListener('click', () => this.copyToClipboard(this.interceptorsBlock));\n this.shadow.getElementById('btn-close')\n ?.addEventListener('click', () => this.closePreview());\n this.shadow.getElementById('btn-new-file')\n ?.addEventListener('click', () => {\n this.isCreatingFile = !this.isCreatingFile;\n this.isCreatingFolder = false;\n this.render();\n if (this.isCreatingFile) this.shadow.getElementById('input-new-file')?.focus();\n });\n this.shadow.getElementById('btn-new-folder')\n ?.addEventListener('click', () => {\n this.isCreatingFolder = !this.isCreatingFolder;\n this.isCreatingFile = false;\n this.render();\n if (this.isCreatingFolder) this.shadow.getElementById('input-new-folder')?.focus();\n });\n this.shadow.getElementById('btn-refresh')\n ?.addEventListener('click', () => this.refreshTree());\n this.shadow.getElementById('btn-new-file-confirm')\n ?.addEventListener('click', () => {\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\n this.createNewFile(input?.value ?? '');\n });\n this.shadow.getElementById('btn-new-file-cancel')\n ?.addEventListener('click', () => {\n this.isCreatingFile = false;\n this.render();\n });\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\n input?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n this.createNewFile(input.value);\n } else if (e.key === 'Escape') {\n this.isCreatingFile = false;\n this.render();\n }\n });\n this.shadow.getElementById('btn-new-folder-confirm')\n ?.addEventListener('click', () => {\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\n this.createNewFolder(folderInput?.value ?? '');\n });\n this.shadow.getElementById('btn-new-folder-cancel')\n ?.addEventListener('click', () => {\n this.isCreatingFolder = false;\n this.render();\n });\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\n folderInput?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n this.createNewFolder(folderInput.value);\n } else if (e.key === 'Escape') {\n this.isCreatingFolder = false;\n this.render();\n }\n });\n }\n}\n\nif (!customElements.get('lib-e2e-advanced-test-editor')) {\n customElements.define('lib-e2e-advanced-test-editor', AdvancedTestEditorElement);\n}\n","export const ADVANCED_TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .layout { display: flex; flex: 1; min-height: 0; }\n .sidebar {\n border-right: none; display: flex; flex-direction: column;\n background: #0d1117; flex-shrink: 0; min-width: 140px; max-width: 500px;\n }\n .tree-scroll {\n flex: 1; overflow-y: auto; padding: 6px 4px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .tree-scroll::-webkit-scrollbar { width: 4px; }\n .tree-scroll::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .resize-handle {\n width: 4px; background: #21262d; cursor: col-resize; flex-shrink: 0;\n transition: background 0.15s;\n }\n .resize-handle:hover, .resize-handle.dragging { background: #2f81f7; }\n .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #161b22; min-width: 0; }\n .no-perm {\n padding: 28px; color: #484f58; font-size: 13px; text-align: center;\n display: flex; flex-direction: column; align-items: center; gap: 12px; line-height: 1.6;\n }\n .tree-item {\n padding: 4px 6px; border-radius: 4px; cursor: pointer;\n font-size: 12px; color: #8b949e; white-space: nowrap;\n overflow: hidden; text-overflow: ellipsis;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; gap: 4px; user-select: none;\n }\n .tree-item:hover { background: #161b22; color: #c9d1d9; }\n .tree-item.selected { background: rgba(47,129,247,0.12); color: #2f81f7; }\n .tree-item.dir { color: #e3b341; font-weight: 600; }\n .tree-item.dir:hover { background: rgba(227,179,65,0.08); color: #f0c040; }\n .dir-arrow { font-size: 8px; color: #484f58; width: 10px; flex-shrink: 0; line-height: 1; }\n .tree-connector { display: block; width: 1px; background: #21262d; margin-left: 13px; height: 100%; }\n .content-area {\n flex: 1; padding: 12px 14px; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .content-area::-webkit-scrollbar { width: 4px; }\n .content-area::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .file-name { font-size: 11px; color: #484f58; margin-bottom: 8px; font-family: monospace; }\n pre {\n background: #0d1117; padding: 12px; border-radius: 8px;\n font-size: 11px; color: #c9d1d9; margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n line-height: 1.7; border: 1px solid #21262d;\n white-space: pre; overflow-x: auto; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n pre::-webkit-scrollbar { width: 4px; height: 4px; }\n pre::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .pre-block { font-size: 10.5px; }\n .pre-icp .sh-str { color: #85e89d; }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n .footer {\n padding: 10px 14px; border-top: 1px solid #21262d;\n display: flex; gap: 8px; justify-content: flex-end; background: #161b22;\n }\n button {\n padding: 6px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button:disabled { opacity: 0.35; cursor: default; }\n .btn-save { background: #2f81f7; border-color: #2f81f7; color: #fff; }\n .btn-save:hover { background: #1f6feb; border-color: #1f6feb; color: #fff; }\n .btn-save:disabled { background: #21262d; border-color: #30363d; color: #8b949e; }\n .placeholder { color: #484f58; font-size: 13px; padding: 28px; text-align: center; }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .block-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }\n .btn-copy {\n padding: 3px 10px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-copy:hover { background: #30363d; color: #e6edf3; }\n .sidebar-toolbar {\n display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 6px 4px;\n border-bottom: 1px solid #21262d; flex-shrink: 0; background: #0d1117;\n }\n .btn-toolbar {\n flex: 1 1 calc(50% - 2px); padding: 4px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #161b22; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; overflow: hidden;\n text-overflow: ellipsis;\n }\n .btn-toolbar.btn-full { flex: 1 1 100%; }\n .btn-toolbar:hover { background: #30363d; color: #e6edf3; }\n .btn-toolbar.btn-new { color: #3fb950; border-color: #238636; }\n .btn-toolbar.btn-new:hover { background: #238636; color: #fff; }\n .btn-toolbar.btn-new-folder { color: #d29922; border-color: #9e6a03; }\n .btn-toolbar.btn-new-folder:hover { background: #9e6a03; color: #fff; }\n .new-file-form {\n padding: 6px; border-bottom: 1px solid #21262d; display: flex; flex-direction: column; gap: 4px;\n }\n .new-file-form input {\n width: 100%; padding: 4px 7px; background: #0d1117; border: 1px solid #30363d;\n border-radius: 5px; color: #e6edf3; font-size: 11px; font-family: monospace;\n outline: none;\n }\n .new-file-form input:focus { border-color: #2f81f7; }\n .new-file-form .ext { font-size: 9px; color: #484f58; padding: 0 2px; }\n .new-file-actions { display: flex; gap: 4px; }\n .btn-confirm { flex: 1; padding: 3px 6px; border: 1px solid #238636; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #238636; color: #fff; transition: background 0.12s; }\n .btn-confirm:hover { background: #2ea043; }\n .btn-cancel-form { flex: 1; padding: 3px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e; transition: background 0.12s; }\n .btn-cancel-form:hover { background: #30363d; color: #e6edf3; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\n\nexport interface AdvancedEditorState {\n e2eTree: Array<DirectoryNode | FileNode>;\n selectedFile: unknown;\n selectedFileContent: string | null;\n testItBlock: string;\n interceptorsBlock: string;\n testNotes: string;\n saveButtonEnabled: boolean;\n isCreatingFile: boolean;\n isCreatingFolder: boolean;\n collapsedDirs: Set<string>;\n sidebarWidth: number;\n}\n\nexport function renderNoPermission(needsReauth: boolean, t: (key: string) => string): string {\n const reauthBtn = needsReauth\n ? `<button id=\"btn-reauth\"\n style=\"margin-top:14px;padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\n ${t('ADVANCED_EDITOR.REAUTH_BTN')}\n </button>`\n : '';\n\n return `\n <div class=\"no-perm\">\n <div>${needsReauth ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED') : t('ADVANCED_EDITOR.NO_ACCESS')}</div>\n <div style=\"font-size:11px\">${needsReauth\n ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED_HINT')\n : t('ADVANCED_EDITOR.NO_ACCESS_HINT')}</div>\n ${reauthBtn}\n </div>`;\n}\n\nexport function renderAdvancedEditor(state: AdvancedEditorState, t: (key: string) => string): string {\n const { e2eTree, selectedFile, selectedFileContent, testItBlock, interceptorsBlock, testNotes, saveButtonEnabled, isCreatingFile, isCreatingFolder, collapsedDirs, sidebarWidth } = state;\n\n const treeHtml = e2eTree.length\n ? renderTree(e2eTree, selectedFile, collapsedDirs)\n : `<div class=\"tree-item\" style=\"color:#6c7a99\">${t('ADVANCED_EDITOR.NO_FILES')}</div>`;\n\n const contentHtml = selectedFileContent\n ? `<div class=\"file-name\">📄 ${escHtml((selectedFile as { name?: string } | null)?.name ?? '')}</div>\n <pre class=\"pre-file\">${syntaxHighlight(selectedFileContent.slice(0, 6000))}${selectedFileContent.length > 6000 ? '\\n...' : ''}</pre>`\n : `<div class=\"placeholder\">${t('ADVANCED_EDITOR.SELECT_FILE')}</div>`;\n\n const notesHtml = (testItBlock && testNotes)\n ? `<p class=\"test-notes\">${escHtml(testNotes)}</p>`\n : '';\n\n const itHtml = testItBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.IT_LABEL')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_IT_BTN')}</button>\n </div>\n <pre class=\"pre-block\">${syntaxHighlight(testItBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const interceptorsHtml = interceptorsBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.BEFORE_EACH_LABEL')}</span>\n <button id=\"btn-copy-interceptors\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_ICP_BTN')}</button>\n </div>\n <pre class=\"pre-block pre-icp\">${syntaxHighlight(interceptorsBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const newFileForm = isCreatingFile\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-file\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FILE_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <span class=\"ext\">.cy.ts</span>\n <div class=\"new-file-actions\">\n <button id=\"btn-new-file-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-file-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const newFolderForm = isCreatingFolder\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-folder\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FOLDER_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <div class=\"new-file-actions\">\n <button id=\"btn-new-folder-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-folder-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const toolbar = `\n <div class=\"sidebar-toolbar\">\n <button id=\"btn-new-file\" class=\"btn-toolbar btn-new\">${t('ADVANCED_EDITOR.NEW_FILE_BTN')}</button>\n <button id=\"btn-new-folder\" class=\"btn-toolbar btn-new-folder\">${t('ADVANCED_EDITOR.NEW_FOLDER_BTN')}</button>\n <button id=\"btn-refresh\" class=\"btn-toolbar btn-full\">${t('ADVANCED_EDITOR.REFRESH_BTN')}</button>\n </div>`;\n\n return `\n <div class=\"layout\">\n <div class=\"sidebar\" style=\"width:${sidebarWidth}px\">\n ${toolbar}\n ${newFileForm}\n ${newFolderForm}\n <div class=\"tree-scroll\">${treeHtml}</div>\n </div>\n <div id=\"resize-handle\" class=\"resize-handle\"></div>\n <div class=\"main\">\n <div class=\"content-area\">${contentHtml}${notesHtml}${itHtml}${interceptorsHtml}</div>\n <div class=\"footer\">\n <button id=\"btn-save\" class=\"btn-save\"\n ${!saveButtonEnabled || !testItBlock ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.INSERT_BTN')}\n </button>\n <button id=\"btn-edit\" ${!saveButtonEnabled ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.EDIT_MANUAL_BTN')}\n </button>\n <button id=\"btn-close\">${t('ADVANCED_EDITOR.CLOSE_BTN')}</button>\n </div>\n </div>\n </div>`;\n}\n\nexport function renderTree(\n nodes: Array<DirectoryNode | FileNode>,\n selected: unknown,\n collapsedDirs: Set<string>,\n indent = 0,\n parentPath = '',\n): string {\n return nodes.map((n) => {\n const currentPath = parentPath ? `${parentPath}/${n.name}` : n.name;\n const isFile = n.kind === 'file';\n const pad = `padding-left:${6 + indent * 14}px`;\n\n if (!isFile) {\n const dir = n as DirectoryNode;\n const hasChildren = (dir.children?.length ?? 0) > 0;\n const isCollapsed = collapsedDirs.has(currentPath);\n const arrow = hasChildren ? (isCollapsed ? '▶' : '▼') : '·';\n const dirHtml = `<div class=\"tree-item dir\" style=\"${pad}\" data-dir-path=\"${escAttr(currentPath)}\">\n <span class=\"dir-arrow\">${arrow}</span>📁 ${escHtml(n.name)}\n </div>`;\n if (!hasChildren || isCollapsed) return dirHtml;\n return dirHtml + renderTree(dir.children, selected, collapsedDirs, indent + 1, currentPath);\n }\n\n const isSel = (selected as { name?: string } | null)?.name === n.name;\n const cls = `tree-item${isSel ? ' selected' : ''}`;\n const data = JSON.stringify({ kind: n.kind, name: n.name }).replace(/\"/g, '"');\n return `<div class=\"${cls}\" style=\"${pad}\" data-file=\"${data}\">📄 ${escHtml(n.name)}</div>`;\n }).join('');\n}\n\nexport async function findFileHandleRecursive(\n dir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemFileHandle | null> {\n for await (const entry of dir.values()) {\n if (entry.kind === 'file' && entry.name === name) return entry as FileSystemFileHandle;\n if (entry.kind === 'directory') {\n const found = await findFileHandleRecursive(entry as FileSystemDirectoryHandle, name);\n if (found) return found;\n }\n }\n return null;\n}\n","export const FILE_PREVIEW_STYLES = `\n :host { display: block; height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { display: flex; flex-direction: column; height: 100%; }\n .header {\n display: flex; align-items: center; gap: 8px;\n padding: 8px 12px; border-bottom: 1px solid #21262d;\n background: #161b22;\n }\n .file-name { flex: 1; font-size: 12px; color: #8b949e;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; }\n .body { display: flex; flex: 1; overflow: hidden; min-height: 0; }\n .editor {\n flex: 1; min-width: 0; padding: 14px;\n background: #0d1117; color: #c9d1d9; border: none; outline: none;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 12px;\n line-height: 1.7; resize: none;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .editor::-webkit-scrollbar { width: 5px; }\n .editor::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .blocks-panel {\n width: 260px; flex-shrink: 0; border-left: 1px solid #21262d;\n background: #0d1117; padding: 10px 12px; overflow-y: auto;\n display: flex; flex-direction: column; gap: 10px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .blocks-panel::-webkit-scrollbar { width: 4px; }\n .blocks-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .block-section { display: flex; flex-direction: column; gap: 4px; }\n .block-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }\n .block-label { font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; }\n .btn-copy-sm {\n padding: 2px 8px; border: 1px solid #30363d; border-radius: 4px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap;\n }\n .btn-copy-sm:hover { background: #30363d; color: #e6edf3; }\n .block-pre {\n margin: 0; padding: 6px 8px; background: #161b22;\n border-radius: 5px; border: 1px solid #21262d;\n font-size: 10px; color: #c9d1d9; line-height: 1.6;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n max-height: 280px; overflow-y: auto; white-space: pre-wrap; word-break: break-all;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel {\n flex: 1; overflow-y: auto; background: #0d1117; border-left: 1px solid #21262d;\n padding: 8px 0; min-width: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n line-height: 1.6;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel::-webkit-scrollbar { width: 5px; }\n .diff-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .diff-line {\n display: flex; gap: 0; white-space: pre; padding: 0 12px;\n }\n .diff-line.added { background: rgba(63,185,80,0.12); color: #3fb950; }\n .diff-line.removed { background: rgba(248,81,73,0.1); color: #f85149; }\n .diff-line.same { color: #484f58; }\n .diff-sign { width: 14px; flex-shrink: 0; user-select: none; }\n .diff-empty { color: #484f58; font-size: 12px; padding: 20px; text-align: center; }\n .footer {\n display: flex; gap: 8px; padding: 8px 12px;\n border-top: 1px solid #21262d; justify-content: flex-end;\n background: #161b22;\n }\n button {\n padding: 6px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n .btn-save { background: #3fb950; border-color: #3fb950; color: #fff; }\n .btn-save:hover { background: #2ea043; border-color: #2ea043; }\n .btn-launch { background: transparent; border-color: #e3b341; color: #e3b341; }\n .btn-launch:hover { background: rgba(227,179,65,0.1); }\n .btn-launch:disabled { opacity: 0.45; cursor: not-allowed; }\n .btn-launch:disabled:hover { background: transparent; }\n .launch-hint { font-size: 10px; color: #8b6d3b; align-self: center; }\n .btn-insert { background: transparent; border-color: #a371f7; color: #a371f7; }\n .btn-insert:hover { background: rgba(163,113,247,0.12); color: #c8a8ff; }\n .btn-diff-active { background: rgba(47,129,247,0.15); border-color: rgba(47,129,247,0.4); color: #2f81f7; }\n\n /* ── Run result panel ─────────────────────────────────── */\n .run-result {\n border-top: 1px solid #21262d; padding: 8px 12px; background: #0d1117;\n max-height: 220px; overflow-y: auto; flex-shrink: 0;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .run-status { font-size: 12px; font-weight: 600; }\n .run-passed .run-status { color: #3fb950; }\n .run-failed .run-status { color: #f85149; }\n .run-running .run-status { color: #e3b341; }\n .run-error .run-status { color: #f85149; }\n .run-output {\n margin: 6px 0 0; padding: 8px 10px; background: #161b22; border: 1px solid #21262d;\n border-radius: 5px; font-size: 10px; color: #c9d1d9; line-height: 1.5;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto;\n }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport type DiffEntry = { type: 'same' | 'added' | 'removed'; line: string };\n\nexport function computeDiff(original: string, modified: string): DiffEntry[] {\n const MAX_LINES = 600;\n const a = original.split('\\n').slice(0, MAX_LINES);\n const b = modified.split('\\n').slice(0, MAX_LINES);\n const m = a.length, n = b.length;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]);\n }\n }\n\n const result: DiffEntry[] = [];\n let i = m, j = n;\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {\n result.unshift({ type: 'same', line: a[i - 1] });\n i--; j--;\n } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {\n result.unshift({ type: 'added', line: b[j - 1] });\n j--;\n } else {\n result.unshift({ type: 'removed', line: a[i - 1] });\n i--;\n }\n }\n return result;\n}\n\nexport function buildDiffHtml(original: string, current: string, t: (key: string) => string): string {\n if (original === current) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES')}</div>`;\n\n const diff = computeDiff(original, current);\n if (!diff.length) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES_SHORT')}</div>`;\n\n const CONTEXT = 2;\n const compressed: DiffEntry[] = [];\n let sameRun = 0;\n for (let idx = 0; idx < diff.length; idx++) {\n if (diff[idx].type === 'same') {\n sameRun++;\n if (sameRun <= CONTEXT) compressed.push(diff[idx]);\n else if (idx + 1 < diff.length && diff[idx + 1].type !== 'same') {\n if (sameRun > CONTEXT * 2) compressed.push({ type: 'same', line: '…' });\n compressed.push(diff[idx]);\n }\n } else {\n sameRun = 0;\n compressed.push(diff[idx]);\n }\n }\n\n return compressed.map(({ type, line }) => {\n const sign = type === 'added' ? '+' : type === 'removed' ? '−' : ' ';\n return `<div class=\"diff-line ${type}\"><span class=\"diff-sign\">${sign}</span><span>${escHtml(line)}</span></div>`;\n }).join('');\n}\n\nexport type RunState = 'idle' | 'running' | 'passed' | 'failed' | 'error';\n\nexport interface FilePreviewState {\n fileName: string | null;\n showDiff: boolean;\n fileContent: string | null;\n originalContent: string | null;\n currentContent: string;\n itBlock: string;\n interceptorsBlock: string;\n closeLabel: string;\n isLocal: boolean;\n runState: RunState;\n runOutput: string;\n}\n\nconst RUN_STATUS_KEY: Record<Exclude<RunState, 'idle'>, string> = {\n running: 'FILE_PREVIEW.LAUNCH_RUNNING',\n passed: 'FILE_PREVIEW.LAUNCH_PASSED',\n failed: 'FILE_PREVIEW.LAUNCH_FAILED',\n error: 'FILE_PREVIEW.LAUNCH_NO_RUNNER',\n};\n\nexport function renderFilePreview(state: FilePreviewState, t: (key: string) => string): string {\n const { fileName, showDiff, fileContent, originalContent, currentContent, itBlock, interceptorsBlock, closeLabel, isLocal, runState, runOutput } = state;\n\n const blocksPanelHtml = (itBlock || interceptorsBlock) ? `\n <div class=\"blocks-panel\">\n ${itBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_IT')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\">${escHtml(itBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n ${interceptorsBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_BEFORE_EACH')}</span>\n <button id=\"btn-copy-icp\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\" style=\"color:#3fb950\">${escHtml(interceptorsBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n </div>` : '';\n\n const hasChanges = originalContent !== null && originalContent !== (fileContent ?? '');\n const hasBlocks = !!(itBlock || interceptorsBlock);\n\n const launchBtnHtml = isLocal\n ? `<button id=\"btn-launch\" class=\"btn-launch\" ${runState === 'running' ? 'disabled' : ''}>${runState === 'running' ? t('FILE_PREVIEW.LAUNCH_RUNNING') : t('FILE_PREVIEW.LAUNCH_BTN')}</button>`\n : `<button class=\"btn-launch\" disabled title=\"${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}\">${t('FILE_PREVIEW.LAUNCH_BTN')}</button>\n <span class=\"launch-hint\">${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}</span>`;\n\n const runResultHtml = runState !== 'idle'\n ? `<div class=\"run-result run-${runState}\">\n <span class=\"run-status\">${t(RUN_STATUS_KEY[runState])}</span>\n ${runOutput ? `<pre class=\"run-output\">${escHtml(runOutput.slice(0, 8000))}</pre>` : ''}\n </div>`\n : '';\n\n return `\n <div class=\"container\">\n <div class=\"header\">\n <span class=\"file-name\">📄 ${fileName ? escHtml(fileName) : t('FILE_PREVIEW.NO_FILE')}</span>\n <button id=\"btn-copy\" title=\"${t('FILE_PREVIEW.COPY_TITLE')}\">📋</button>\n </div>\n <div class=\"body\">\n ${showDiff\n ? `<div class=\"diff-panel\" id=\"diff-panel\">${buildDiffHtml(originalContent ?? '', currentContent, t)}</div>`\n : `<textarea class=\"editor\" id=\"editor\" spellcheck=\"false\">${escHtml(fileContent ?? '')}</textarea>`}\n ${blocksPanelHtml}\n </div>\n ${runResultHtml}\n <div class=\"footer\">\n ${launchBtnHtml}\n ${hasChanges ? `<button id=\"btn-diff\" class=\"${showDiff ? 'btn-diff-active' : ''}\">${t('FILE_PREVIEW.DIFF_BTN')}</button>` : ''}\n ${hasBlocks && !showDiff ? `<button id=\"btn-insert\" class=\"btn-insert\" title=\"${t('FILE_PREVIEW.INSERT_TITLE')}\">${t('FILE_PREVIEW.INSERT_BTN')}</button>` : ''}\n <button id=\"btn-save\" class=\"btn-save\">${t('FILE_PREVIEW.SAVE_BTN')}</button>\n <button id=\"btn-close\">${escHtml(closeLabel || t('FILE_PREVIEW.CLOSE_BTN'))}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { advancedTestTransformationService } from '../../services/advanced-test.transformation.service';\nimport { showToast } from '../../utils/toast.utils';\nimport { isLocalHost } from '../../utils/host.utils';\nimport { FILE_PREVIEW_STYLES } from './file-preview.styles';\nimport { renderFilePreview, type RunState } from './file-preview.template';\n\nexport class FilePreviewElement extends HTMLElement {\n private shadow: ShadowRoot;\n private textarea: HTMLTextAreaElement | null = null;\n\n fileName: string | null = null;\n closeLabel = '';\n translation: TranslationService = translationService;\n itBlock = '';\n interceptorsBlock = '';\n notes = '';\n commands: string[] = [];\n interceptors: string[] = [];\n /** Endpoint of the local Cypress runner. Configurable; defaults to the bundled runner's port. */\n runnerUrl = 'http://localhost:8123/run-test';\n /** Whether the app is served locally — gates the launch button. Overridable for tests. */\n isLocal = isLocalHost(window.location.hostname);\n private _fileContent: string | null = null;\n private _originalContent: string | null = null;\n private _showDiff = false;\n private _runState: RunState = 'idle';\n private _runOutput = '';\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.closeLabel) this.closeLabel = this.translation.translate('FILE_PREVIEW.CLOSE_BTN');\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n get fileContent(): string | null { return this._fileContent; }\n set fileContent(v: string | null) {\n if (this._originalContent === null) this._originalContent = v;\n this._fileContent = v;\n if (this.textarea) this.textarea.value = v ?? '';\n else this.render();\n }\n\n saveFile(): void {\n const content = this.textarea?.value ?? this._fileContent ?? '';\n this.dispatchEvent(new CustomEvent('save', { detail: content, bubbles: true, composed: true }));\n }\n\n onClose(): void {\n this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\n }\n\n /**\n * Runs the current spec headless via the local runner and shows the result.\n * No-op off localhost. Never throws — connection failures surface as an\n * \"error\" state + toast instead of an unhandled rejection.\n */\n async launchTest(specPath?: string): Promise<void> {\n if (!this.isLocal) return;\n const path = specPath ?? this.fileName ?? '';\n if (!path) return;\n\n this._runState = 'running';\n this._runOutput = '';\n this.render();\n\n try {\n const response = await fetch(this.runnerUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ specPath: path }),\n });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n const result = await response.json() as { success?: boolean; output?: string };\n this._runOutput = result.output ?? '';\n this._runState = result.success ? 'passed' : 'failed';\n } catch {\n this._runState = 'error';\n this._runOutput = '';\n showToast(this.t('FILE_PREVIEW.LAUNCH_NO_RUNNER'), false);\n }\n this.render();\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard?.writeText(text);\n }\n\n toggleDiff(): void {\n this._showDiff = !this._showDiff;\n this.render();\n }\n\n /**\n * Merges the it() and beforeEach() blocks into the current editor content\n * using the same logic as the automatic \"Insert into file\" action, so the\n * user does not have to copy/paste manually. Leaves the content untouched\n * (and warns) when the file has no valid describe() block to insert into.\n */\n insertBlocks(): void {\n const base = this.textarea?.value ?? this._fileContent ?? '';\n let content = base;\n if (this.interceptorsBlock) {\n const merged = advancedTestTransformationService.insertBeforeEach(content, this.interceptorsBlock);\n if (merged) content = merged;\n }\n if (this.itBlock) {\n const comment = this.notes ? advancedTestTransformationService.buildBlockComment(this.notes) + '\\n' : '';\n const merged = advancedTestTransformationService.insertItBlock(content, comment + this.itBlock);\n if (merged) content = merged;\n }\n if (content === base) {\n showToast(this.t('FILE_PREVIEW.INSERT_ERROR'), false);\n return;\n }\n this._fileContent = content;\n this.render();\n showToast(this.t('FILE_PREVIEW.INSERT_DONE'));\n }\n\n private render(): void {\n this.shadow.innerHTML = `<style>${FILE_PREVIEW_STYLES}</style>${renderFilePreview({\n fileName: this.fileName,\n showDiff: this._showDiff,\n fileContent: this._fileContent,\n originalContent: this._originalContent,\n currentContent: this.textarea?.value ?? this._fileContent ?? '',\n itBlock: this.itBlock,\n interceptorsBlock: this.interceptorsBlock,\n closeLabel: this.closeLabel,\n isLocal: this.isLocal,\n runState: this._runState,\n runOutput: this._runOutput,\n }, this.t.bind(this))}`;\n\n this.textarea = this.shadow.getElementById('editor') as HTMLTextAreaElement | null;\n if (this.textarea) {\n const ta = this.textarea;\n this.textarea.addEventListener('input', () => {\n this._fileContent = ta.value;\n });\n }\n this.shadow.getElementById('btn-save')?.addEventListener('click', () => this.saveFile());\n this.shadow.getElementById('btn-close')?.addEventListener('click', () => this.onClose());\n this.shadow.getElementById('btn-launch')?.addEventListener('click', () => this.launchTest());\n this.shadow.getElementById('btn-copy')?.addEventListener('click', () => {\n this.copyToClipboard(this.textarea?.value ?? this._fileContent ?? '');\n });\n this.shadow.getElementById('btn-diff')?.addEventListener('click', () => this.toggleDiff());\n this.shadow.getElementById('btn-insert')?.addEventListener('click', () => this.insertBlocks());\n this.shadow.getElementById('btn-copy-it')?.addEventListener('click', () => {\n this.copyToClipboard(this.itBlock);\n });\n this.shadow.getElementById('btn-copy-icp')?.addEventListener('click', () => {\n this.copyToClipboard(this.interceptorsBlock);\n });\n }\n}\n\nif (!customElements.get('lib-e2e-file-preview')) {\n customElements.define('lib-e2e-file-preview', FilePreviewElement);\n}\n","export const HELP_PANEL_STYLES = `\n :host { display: block; }\n *, *::before, *::after { box-sizing: border-box; }\n\n .help-tabs {\n display: flex;\n gap: 4px;\n border-bottom: 1px solid #21262d;\n margin-bottom: 8px;\n }\n .help-tab {\n appearance: none;\n border: none;\n background: transparent;\n color: #8b949e;\n font-size: 12px;\n font-weight: 600;\n padding: 8px 12px;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n margin-bottom: -1px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n transition: color .12s, border-color .12s;\n }\n .help-tab:hover { color: #c9d1d9; }\n .help-tab.active { color: #e6edf3; border-bottom-color: #2f81f7; }\n\n .help-panel {\n max-height: 60vh;\n overflow-y: auto;\n padding: 4px 6px 8px;\n color: #c9d1d9;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 13px;\n line-height: 1.55;\n }\n\n .help-intro {\n margin: 0 0 12px;\n color: #8b949e;\n font-size: 12px;\n }\n\n .help-sec { margin: 0 0 14px; }\n\n .help-sec-hd {\n margin: 0 0 6px;\n font-size: 12px;\n font-weight: 700;\n color: #e6edf3;\n letter-spacing: .3px;\n border-bottom: 1px solid #21262d;\n padding-bottom: 4px;\n }\n\n .help-list {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .help-list li {\n padding: 3px 0 3px 14px;\n position: relative;\n color: #c9d1d9;\n }\n\n .help-list li::before {\n content: '·';\n position: absolute;\n left: 3px;\n color: #2f81f7;\n font-weight: 700;\n }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\n/**\n * Pure render function for the in-app Help panel (spec 011). Two tabs — a quick\n * reference (cheat-sheet) and a verbose usage guide (workflow + coverage). All\n * text comes from the HELP.* i18n section and is escaped (values contain literal\n * `<select>` etc. that would otherwise be parsed as HTML).\n */\n\nexport type HelpTab = 'reference' | 'guide';\n\ninterface Section { title: string; items: string[] }\n\nconst REFERENCE_SECTIONS: Section[] = [\n { title: 'HELP.SEC_RECORDING', items: ['HELP.RECORDING_1', 'HELP.RECORDING_2'] },\n {\n title: 'HELP.SEC_SHORTCUTS',\n items: ['HELP.SC_RECORD', 'HELP.SC_PAUSE', 'HELP.SC_TESTS', 'HELP.SC_COMMANDS', 'HELP.SC_CONFIG', 'HELP.SC_VISIBILITY', 'HELP.SC_HELP'],\n },\n {\n title: 'HELP.SEC_CAPTURED',\n items: ['HELP.CAP_CLICK', 'HELP.CAP_DBLCLICK', 'HELP.CAP_RIGHTCLICK', 'HELP.CAP_TYPE', 'HELP.CAP_CHECK', 'HELP.CAP_SELECT', 'HELP.CAP_KEYS', 'HELP.CAP_ROUTE', 'HELP.CAP_HTTP'],\n },\n { title: 'HELP.SEC_ASSERT', items: ['HELP.ASSERT_1', 'HELP.ASSERT_2'] },\n { title: 'HELP.SEC_PANELS', items: ['HELP.PANEL_TESTS', 'HELP.PANEL_COMMANDS', 'HELP.PANEL_CONFIG', 'HELP.PANEL_FILES'] },\n { title: 'HELP.SEC_SELECTOR', items: ['HELP.SELECTOR_1', 'HELP.SELECTOR_2'] },\n { title: 'HELP.SEC_DATA', items: ['HELP.DATA_1', 'HELP.DATA_2'] },\n { title: 'HELP.SEC_ADVANCED', items: ['HELP.ADV_INVISIBLE', 'HELP.ADV_RUNNER', 'HELP.ADV_CROSSAPP', 'HELP.ADV_DRAG', 'HELP.ADV_LOGIN'] },\n];\n\nconst GUIDE_SECTIONS: Section[] = [\n { title: 'HELP.G_SEC_WORKFLOW', items: ['HELP.G_WF_1', 'HELP.G_WF_2', 'HELP.G_WF_3', 'HELP.G_WF_4', 'HELP.G_WF_5'] },\n { title: 'HELP.G_SEC_COVERED', items: ['HELP.G_COV_1', 'HELP.G_COV_2', 'HELP.G_COV_3', 'HELP.G_COV_4', 'HELP.G_COV_5', 'HELP.G_COV_6', 'HELP.G_COV_7'] },\n { title: 'HELP.G_SEC_NOTCOVERED', items: ['HELP.G_NC_1', 'HELP.G_NC_2', 'HELP.G_NC_3', 'HELP.G_NC_4', 'HELP.G_NC_5'] },\n];\n\nfunction sectionsHtml(sections: Section[], t: (key: string) => string): string {\n return sections\n .map(\n (s) => `\n <section class=\"help-sec\">\n <h3 class=\"help-sec-hd\">${escHtml(t(s.title))}</h3>\n <ul class=\"help-list\">${s.items.map((k) => `<li>${escHtml(t(k))}</li>`).join('')}</ul>\n </section>`,\n )\n .join('');\n}\n\nexport function renderHelpPanel(t: (key: string) => string, activeTab: HelpTab = 'reference'): string {\n const tab = (id: HelpTab, key: string): string =>\n `<button class=\"help-tab ${activeTab === id ? 'active' : ''}\" data-tab=\"${id}\">${escHtml(t(key))}</button>`;\n\n const body =\n activeTab === 'guide'\n ? `<p class=\"help-intro\">${escHtml(t('HELP.GUIDE_INTRO'))}</p>${sectionsHtml(GUIDE_SECTIONS, t)}`\n : `<p class=\"help-intro\">${escHtml(t('HELP.INTRO'))}</p>${sectionsHtml(REFERENCE_SECTIONS, t)}`;\n\n return `\n <div class=\"help-root\">\n <div class=\"help-tabs\" role=\"tablist\">\n ${tab('reference', 'HELP.TAB_REFERENCE')}\n ${tab('guide', 'HELP.TAB_GUIDE')}\n </div>\n <div class=\"help-panel\" data-tab-panel=\"${activeTab}\">${body}</div>\n </div>`;\n}\n","import { TranslationService } from '../../services/translation.service';\nimport { HELP_PANEL_STYLES } from './help-panel.styles';\nimport { renderHelpPanel, type HelpTab } from './help-panel.template';\n\n/**\n * `<help-panel>` — an in-app guide (spec 011). Two tabs: a quick reference\n * cheat-sheet and a verbose usage guide (workflow + coverage). Content is driven\n * by the HELP.* i18n keys.\n */\nexport class HelpPanelElement extends HTMLElement {\n private shadow: ShadowRoot;\n private activeTab: HelpTab = 'reference';\n translation!: TranslationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.translation) this.translation = new TranslationService();\n this.render();\n }\n\n private render(): void {\n this.shadow.innerHTML =\n `<style>${HELP_PANEL_STYLES}</style>${renderHelpPanel(this.translation.translate.bind(this.translation), this.activeTab)}`;\n this.shadow.querySelectorAll<HTMLElement>('[data-tab]').forEach((btn) => {\n btn.addEventListener('click', () => {\n this.activeTab = (btn.dataset['tab'] as HelpTab) ?? 'reference';\n this.render();\n });\n });\n }\n}\n\nif (!customElements.get('lib-e2e-help-panel')) {\n customElements.define('lib-e2e-help-panel', HelpPanelElement);\n}\n","import Swal, { type SweetAlertOptions } from 'sweetalert2';\nimport { getRecorderStyles } from './lib-e2e-recorder.styles';\nimport { renderRecorderWidget } from './lib-e2e-recorder.template';\nimport { injectAssertionBuilder } from './assertion-builder';\nimport { mountFilesystemSetupContent } from './filesystem-setup';\nimport { mountComponentInSwal } from '../../utils/swal-mount.utils';\nimport { RecordingService, type SelectorStrategy } from '../../services/recording.service';\nimport { PersistenceService } from '../../services/persistence.service';\nimport { TranslationService } from '../../services/translation.service';\nimport { HttpMonitor } from '../../services/http-monitor';\nimport {\n injectStyles,\n LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,\n SCROLLBAR_STYLES,\n} from '../../utils/styles.utils';\nimport {\n makeModalResizable,\n makeSwalDraggable,\n setSwal2DataCyAttribute,\n ensurePopupDimensions,\n} from '../../utils/modal.utils';\nimport type { Lang } from '../../models/lang.model';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\nimport {\n type ActiveSessionState,\n ACTIVE_SESSION_BREADCRUMB_KEY,\n RESUME_TTL_CONFIG_KEY,\n DEFAULT_RESUME_TTL_MINUTES,\n} from '../../models/active-session.model';\nimport {\n type ExpandDirection,\n type Point,\n DRAG_THRESHOLD,\n clampTogglePosition,\n resolveExpandDirection,\n defaultTogglePosition,\n boxTopLeftFor,\n} from '../../utils/widget-position.utils';\nimport { showToast } from '../../utils/toast.utils';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG, type IssueTrackerConfig, type IssueTrackerProvider } from '../../models/issue-tracker.model';\nimport { toFixtureInterceptors, simplifyFixtureWaits } from '../../utils/fixture-convert.utils';\n\n/**\n * Minimal property/event shapes for dynamically-created child custom elements.\n * Not extending HTMLElement avoids conflicts with the strict EventListener signature;\n * cast to Node/HTMLElement only for actual DOM insertion.\n */\ninterface PrevisualizerEl {\n translation: TranslationService; commands: string[]; interceptors: string[]; editable: boolean;\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\n}\ninterface TestEditorEl { persistence: PersistenceService; translation: TranslationService; issueTrackerConfig: IssueTrackerConfig; groupByTicket: boolean; }\ninterface SaveTestEl {\n translation: TranslationService;\n issueTrackerConfig: IssueTrackerConfig;\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\n}\ninterface ConfigEl {\n persistence: PersistenceService; translation: TranslationService;\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\n}\ninterface AdvancedEditorEl {\n persistence: PersistenceService; translation: TranslationService; testId?: number;\n loginSetupConfig: LoginSetupConfig | null;\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\n}\ninterface FilePreviewEl {\n translation: TranslationService; fileContent: string | null; fileName: string | null;\n closeLabel: string; itBlock: string; interceptorsBlock: string; notes: string;\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\n}\ninterface SelectorPickerEl {\n targetElement: HTMLElement; recording: RecordingService; translation: TranslationService;\n}\ninterface HelpPanelEl { translation: TranslationService }\n\nexport class LibE2eRecorderElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _isDisabled = false;\n private keydownHandler!: (e: KeyboardEvent) => void;\n private recordingUnsub?: () => void;\n private commandsUnsub?: () => void;\n private interceptorsUnsub?: () => void;\n private pauseUnsub?: () => void;\n private selectorNotFoundUnsub?: () => void;\n private langUnsub?: () => void;\n private sessionUnsub?: () => void;\n private sessionSaveTimer?: ReturnType<typeof setTimeout>;\n private controlFirstTimeData = true;\n\n // ── draggable widget (spec 007) ──\n private togglePos: Point | null = null;\n private expandDir: ExpandDirection = 'up-left';\n private dragState?: { startX: number; startY: number; origX: number; origY: number; moved: boolean };\n private suppressNextToggleClick = false;\n private widgetPointerMove?: (e: MouseEvent) => void;\n private widgetPointerUp?: () => void;\n private widgetResize?: () => void;\n private _previsualizerRef: { commands: string[]; interceptors: string[] } | null = null;\n private httpMonitor?: HttpMonitor;\n private smartSelectorEnabled = true;\n private _needsRecordingRebuild = false;\n private issueTrackerConfig: IssueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };\n\n recording!: RecordingService;\n persistence!: PersistenceService;\n translation!: TranslationService;\n\n isVisible = false;\n isRecording = false;\n isPaused = false;\n cypressCommands: string[] = [];\n interceptors: string[] = [];\n\n isCommandsDialogOpen = false;\n isSavedTestsDialogOpen = false;\n isSaveTestDialogOpen = false;\n isSettingsDialogOpen = false;\n isAdvancedEditorDialogOpen = false;\n isHelpDialogOpen = false;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if ('Cypress' in window) {\n this._isDisabled = true;\n return;\n }\n if (!this.getAttribute('data-cy')) {\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\n }\n // Build a fresh recording service on first connect, or rebuild after a\n // disconnect destroyed the previous one (its listeners are dead). spec 008.\n if (!this.recording || this._needsRecordingRebuild) {\n this.recording = new RecordingService();\n this._needsRecordingRebuild = false;\n }\n if (!this.persistence) this.persistence = new PersistenceService();\n if (!this.translation) this.translation = new TranslationService();\n\n this.httpMonitor = new HttpMonitor(this.recording);\n this.httpMonitor.install();\n\n injectStyles(LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, 'lib-e2e-swal2-styles');\n injectStyles(SCROLLBAR_STYLES, 'lib-e2e-scrollbar-styles');\n\n this.initHttpConfig();\n this.initLanguage();\n this.initFilesystemAccess();\n this.initSelectorStrategy();\n this.initSubscriptions();\n this.render();\n this.initVisibility();\n this.initSessionContinuity();\n this.initWidgetPosition();\n\n this.keydownHandler = (e: KeyboardEvent) => this.handleKeyboardEvent(e);\n window.addEventListener('keydown', this.keydownHandler);\n\n // Draggable widget (spec 007): pointer move/up tracked at window level so the\n // drag keeps working even if the cursor leaves the toggle button.\n this.widgetPointerMove = (e: MouseEvent) => this.onWidgetPointerMove(e);\n this.widgetPointerUp = () => this.onWidgetPointerUp();\n this.widgetResize = () => this.applyWidgetPosition();\n window.addEventListener('pointermove', this.widgetPointerMove as EventListener);\n window.addEventListener('pointerup', this.widgetPointerUp);\n window.addEventListener('resize', this.widgetResize);\n }\n\n disconnectedCallback(): void {\n if (this._isDisabled) return;\n window.removeEventListener('keydown', this.keydownHandler);\n // Final flush: if a recording is in progress, persist it synchronously-ish\n // before tearing the service down, so an unmount (single-spa per-sub-project\n // placement) does not lose the last commands. The realm survives client-side\n // navigation, so this async write completes even after the element is gone.\n this.flushActiveSessionOnDisconnect();\n this.recordingUnsub?.();\n this.commandsUnsub?.();\n this.interceptorsUnsub?.();\n this.pauseUnsub?.();\n this.selectorNotFoundUnsub?.();\n this.langUnsub?.();\n this.sessionUnsub?.();\n if (this.widgetPointerMove) window.removeEventListener('pointermove', this.widgetPointerMove as EventListener);\n if (this.widgetPointerUp) window.removeEventListener('pointerup', this.widgetPointerUp);\n if (this.widgetResize) window.removeEventListener('resize', this.widgetResize);\n this.httpMonitor?.uninstall();\n this.recording.destroy();\n // The service's AbortController is now spent (DOM listeners are dead) and the\n // patched history methods are restored. Flag a rebuild so a reconnect of the\n // SAME element gets a FRESH service + monitor (the buffer is recovered from\n // IndexedDB by initSessionContinuity, spec 006). We do NOT null the reference\n // here — the Subjects stay functional, so any in-flight async (e.g. a deferred\n // save calling clearCommands) won't hit `undefined`.\n this._needsRecordingRebuild = true;\n }\n\n // HttpMonitor reads extendedHttpCommands and fixtureMode synchronously inside\n // fetch/XHR interception handlers, so they must live in localStorage (sync).\n // IndexedDB is the persistent source of truth; this method mirrors it into\n // localStorage on every mount so the sync cache is always fresh.\n private async initHttpConfig(): Promise<void> {\n const config = await this.persistence.getConfig('extendedHttpCommands');\n if (config === null) {\n await this.persistence.setConfig({ extendedHttpCommands: 'true' });\n localStorage.setItem('extendedHttpCommands', 'true');\n } else {\n localStorage.setItem('extendedHttpCommands', (config['extendedHttpCommands'] as string) ?? 'true');\n }\n const fx = await this.persistence.getConfig('fixtureMode');\n localStorage.setItem('fixtureMode', (fx?.['fixtureMode'] as string) ?? 'false');\n }\n\n private async initLanguage(): Promise<void> {\n const config = await this.persistence.getConfig('language');\n const lang = config?.['language'] as Lang | undefined;\n this.translation.setLang(lang ?? this.translation.detectLang());\n }\n\n private initSubscriptions(): void {\n this.recordingUnsub = this.recording.onRecordingChange((val) => {\n this.isRecording = val;\n if (!val && !this.controlFirstTimeData) {\n this.saveRecordingHistory();\n // Stopping the recording ends the cross-app session: only an actively\n // recording session is ever persisted/resumed (spec 006, Q2).\n this.clearSessionPersistence();\n this.showSaveTestDialog();\n }\n this.controlFirstTimeData = false;\n this.render();\n });\n // Persist the live session incrementally so it survives a micro-frontend\n // crossing or a same-origin reload (spec 006).\n this.sessionUnsub = this.recording.onSessionChange((state) => this.persistActiveSession(state));\n this.commandsUnsub = this.recording.onCommandsChange((cmds) => {\n this.cypressCommands = cmds;\n if (this._previsualizerRef) this._previsualizerRef.commands = cmds;\n });\n this.interceptorsUnsub = this.recording.onInterceptorsChange((icps) => {\n this.interceptors = icps;\n if (this._previsualizerRef) this._previsualizerRef.interceptors = icps;\n });\n this.pauseUnsub = this.recording.onPauseChange((paused) => {\n this.isPaused = paused;\n this.render();\n });\n this.selectorNotFoundUnsub = this.recording.onSelectorNotFound((target) => {\n if (this.smartSelectorEnabled) this.showSelectorPicker(target);\n });\n // Re-render the widget chrome when the UI language changes so labels update live.\n this.langUnsub = this.translation.onLangChange(() => this.render());\n }\n\n private showSelectorPicker(target: HTMLElement): void {\n import('../../components/selector-picker/selector-picker').then(() => {\n const existing = document.querySelector('lib-e2e-selector-picker');\n if (existing) existing.remove();\n\n const picker = document.createElement('lib-e2e-selector-picker') as unknown as SelectorPickerEl;\n picker.targetElement = target;\n picker.recording = this.recording;\n picker.translation = this.translation;\n document.body.appendChild(picker as unknown as Node);\n });\n }\n\n private async initVisibility(): Promise<void> {\n if (this.hasAttribute('start-hidden')) {\n // Attribute overrides DB: presence → hidden, explicit \"false\" → visible\n this.isVisible = this.getAttribute('start-hidden') === 'false';\n this.style.display = this.isVisible ? '' : 'none';\n return;\n }\n const config = await this.persistence.getGeneralConfig();\n this.isVisible = config?.['startHidden'] !== 'true';\n this.style.display = this.isVisible ? '' : 'none';\n }\n\n private async initSelectorStrategy(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n const strategy = config?.['selectorStrategy'] as string | undefined;\n if (strategy) this.recording.selectorStrategy = strategy as SelectorStrategy;\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\n this.issueTrackerConfig = {\n enabled: config?.['issueTrackerEnabled'] === 'true',\n provider: (config?.['issueTrackerProvider'] as IssueTrackerProvider) ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,\n baseUrl: (config?.['issueTrackerBaseUrl'] as string) ?? '',\n };\n }\n\n // ── cross-app session continuity (spec 006) ───────────────────────────────\n\n /**\n * On mount, detect a persisted live recording session and either resume it\n * silently (recent) or prompt continue/discard (stale). No-op when there is\n * no actively-recording session.\n */\n private async initSessionContinuity(): Promise<void> {\n if (this._isDisabled) return;\n const session = await this.persistence.getActiveSession();\n if (!session || !session.isRecording) return;\n const ttlMin = await this.getResumeTtlMinutes();\n const ageMs = Date.now() - session.updatedAt;\n if (ageMs <= ttlMin * 60_000) {\n this.resumeSessionState(session);\n } else {\n this.promptResumeOrDiscard(session);\n }\n }\n\n private async getResumeTtlMinutes(): Promise<number> {\n const config = await this.persistence.getConfig(RESUME_TTL_CONFIG_KEY);\n const raw = config?.[RESUME_TTL_CONFIG_KEY];\n const n = typeof raw === 'number' ? raw : Number(raw);\n return Number.isFinite(n) && n > 0 ? n : DEFAULT_RESUME_TTL_MINUTES;\n }\n\n /** Rehydrates the recorder from a persisted session (no bootstrap re-emitted). */\n private resumeSessionState(session: ActiveSessionState): void {\n this.recording.restoreSession(session);\n this.cypressCommands = session.commands;\n this.interceptors = session.interceptors;\n this.controlFirstTimeData = false;\n this.render();\n }\n\n private async promptResumeOrDiscard(session: ActiveSessionState): Promise<void> {\n const t = this.translation.translate.bind(this.translation);\n const result = await Swal.fire({\n title: t('RECORDER.SESSION_RESUME_TITLE'),\n html:\n `<div style=\"padding:8px 4px;color:#8b949e;font-size:13px;line-height:1.6\">` +\n `<p>${t('RECORDER.SESSION_RESUME_TEXT')}</p>` +\n `<p style=\"margin-top:6px;color:#c9d1d9\"><b>${session.commands.length}</b> ${t('RECORDER.SESSION_RESUME_COUNT')}</p>` +\n `</div>`,\n showCancelButton: true,\n confirmButtonText: t('RECORDER.SESSION_CONTINUE_BTN'),\n cancelButtonText: t('RECORDER.SESSION_DISCARD_BTN'),\n color: '#e6edf3',\n });\n if (result && (result as { isConfirmed?: boolean }).isConfirmed) {\n this.resumeSessionState(session);\n } else {\n this.discardSession();\n }\n }\n\n /** Debounced persistence of the live session; clears it the moment recording stops. */\n private persistActiveSession(state: ActiveSessionState): void {\n if (this._isDisabled) return;\n if (!state.isRecording) {\n this.clearSessionPersistence();\n return;\n }\n this.writeSessionBreadcrumb(state);\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\n this.sessionSaveTimer = setTimeout(() => {\n const snap = this.recording.getSessionSnapshot();\n if (snap.isRecording) this.persistence.saveActiveSession(snap).catch(() => { /* storage errors are non-fatal */ });\n }, 300);\n }\n\n private writeSessionBreadcrumb(state: ActiveSessionState): void {\n try {\n localStorage.setItem(ACTIVE_SESSION_BREADCRUMB_KEY, JSON.stringify({\n sessionId: state.sessionId,\n isRecording: state.isRecording,\n updatedAt: state.updatedAt,\n }));\n } catch { /* ignore storage errors */ }\n }\n\n private flushActiveSessionOnDisconnect(): void {\n const snap = this.recording.getSessionSnapshot();\n if (!snap.isRecording) return;\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\n this.writeSessionBreadcrumb(snap);\n this.persistence.saveActiveSession(snap).catch(() => { /* non-fatal */ });\n }\n\n private clearSessionPersistence(): void {\n if (this.sessionSaveTimer) { clearTimeout(this.sessionSaveTimer); this.sessionSaveTimer = undefined; }\n try { localStorage.removeItem(ACTIVE_SESSION_BREADCRUMB_KEY); } catch { /* ignore */ }\n this.persistence.clearActiveSession().catch(() => { /* non-fatal */ });\n }\n\n /** True when a synchronous breadcrumb marks an active recording session. */\n hasActiveSession(): boolean {\n try {\n const raw = localStorage.getItem(ACTIVE_SESSION_BREADCRUMB_KEY);\n if (!raw) return false;\n return !!(JSON.parse(raw) as { isRecording?: boolean }).isRecording;\n } catch { return false; }\n }\n\n /** Programmatically resume the persisted session, if any. */\n resumeSession(): void {\n this.persistence.getActiveSession().then((s) => { if (s) this.resumeSessionState(s); });\n }\n\n /** Discard the persisted live session (breadcrumb + DB record). */\n discardSession(): void {\n this.clearSessionPersistence();\n }\n\n // ── draggable widget (spec 007) ────────────────────────────────────────────\n\n /** Loads a previously saved widget position and applies it. */\n private async initWidgetPosition(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n const pos = config?.['widgetPosition'] as Partial<Point> | null | undefined;\n if (pos && typeof pos.x === 'number' && typeof pos.y === 'number') {\n this.togglePos = { x: pos.x, y: pos.y };\n }\n this.applyWidgetPosition();\n }\n\n /** Positions the `.widget` box from the (clamped) toggle centre and orients the arc. */\n private applyWidgetPosition(): void {\n const widget = this.shadow.querySelector('.widget') as HTMLElement | null;\n if (!widget) return;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const centre = this.togglePos ?? defaultTogglePosition(vw, vh);\n const clamped = clampTogglePosition(centre.x, centre.y, vw, vh);\n this.expandDir = resolveExpandDirection(clamped.x, clamped.y, vw, vh);\n const topLeft = boxTopLeftFor(clamped, this.expandDir);\n widget.style.left = `${topLeft.x}px`;\n widget.style.top = `${topLeft.y}px`;\n widget.style.right = 'auto';\n widget.style.bottom = 'auto';\n widget.setAttribute('data-expand', this.expandDir);\n }\n\n private beginWidgetDrag(e: MouseEvent): void {\n // Clear any stale suppression from a previous drag that ended off the toggle\n // (no click fired there), so this fresh press can't swallow a genuine click.\n this.suppressNextToggleClick = false;\n const origin = this.togglePos ?? defaultTogglePosition(window.innerWidth, window.innerHeight);\n this.dragState = { startX: e.clientX, startY: e.clientY, origX: origin.x, origY: origin.y, moved: false };\n }\n\n private onWidgetPointerMove(e: MouseEvent): void {\n if (!this.dragState) return;\n const dx = e.clientX - this.dragState.startX;\n const dy = e.clientY - this.dragState.startY;\n if (!this.dragState.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n this.dragState.moved = true;\n this.togglePos = { x: this.dragState.origX + dx, y: this.dragState.origY + dy };\n this.applyWidgetPosition();\n }\n\n private onWidgetPointerUp(): void {\n if (!this.dragState) return;\n const moved = this.dragState.moved;\n this.dragState = undefined;\n if (!moved || !this.togglePos) return;\n // It was a drag, not a click: suppress the click that fires next and persist.\n this.suppressNextToggleClick = true;\n const clamped = clampTogglePosition(this.togglePos.x, this.togglePos.y, window.innerWidth, window.innerHeight);\n this.togglePos = clamped;\n this.persistence.setConfig({ widgetPosition: clamped }).catch(() => { /* non-fatal */ });\n }\n\n /** Resets the widget to its default corner and clears the saved position. */\n resetWidgetPosition(): void {\n this.togglePos = null;\n this.persistence.setConfig({ widgetPosition: null }).catch(() => { /* non-fatal */ });\n this.applyWidgetPosition();\n }\n\n toggle(): void {\n this.recording.toggleRecording();\n }\n\n togglePause(): void {\n this.recording.togglePause();\n }\n\n setLanguage(lang?: string): void {\n const resolved = lang ? (lang as Lang) : this.translation.detectLang();\n this.translation.setLang(resolved);\n }\n\n handleKeyboardEvent(event: KeyboardEvent): void {\n if (!event.ctrlKey) return;\n const key = event.key.toLowerCase();\n if (key === 'e' && event.shiftKey) { event.preventDefault(); this.toggleVisibility(); return; }\n if (!this.isVisible) return;\n if (key === 'r') { event.preventDefault(); this.toggle(); }\n else if (key === 'p') { event.preventDefault(); this.togglePause(); }\n else if (key === '1') { event.preventDefault(); this.showSavedTestsDialog(); }\n else if (key === '2') { event.preventDefault(); this.showCommandsDialog(); }\n else if (key === '3') { event.preventDefault(); this.showSettingsDialog(); }\n else if (key === 'h' && event.shiftKey) { event.preventDefault(); this.showHelpDialog(); }\n }\n\n toggleVisibility(): void {\n this.isVisible = !this.isVisible;\n this.style.display = this.isVisible ? '' : 'none';\n }\n\n // ── recording history (task 5) ────────────────────────────────────────────\n\n private saveRecordingHistory(): void {\n if (!this.cypressCommands.length) return;\n try {\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\n existing.unshift({ commands: this.cypressCommands, interceptors: this.interceptors, savedAt: Date.now() });\n if (existing.length > 5) existing.splice(5);\n localStorage.setItem('e2e-recording-history', JSON.stringify(existing));\n } catch { /* ignore storage errors */ }\n }\n\n recoverLastRecording(): void {\n try {\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\n if (!existing.length) return;\n const { commands, interceptors } = existing[0];\n commands.forEach((cmd: string) => this.recording.appendCommand(cmd));\n (interceptors as string[]).forEach((_icp: string) => { /* interceptors are not appendable the same way */ });\n } catch { /* ignore */ }\n }\n\n clearRecordingHistory(): void {\n localStorage.removeItem('e2e-recording-history');\n }\n\n getRecordingHistory(): Array<{ commands: string[]; interceptors: string[]; savedAt: number }> {\n try {\n return JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\n } catch { return []; }\n }\n\n // ── filesystem setup ─────────────────────────────────────────────────────\n\n private async initFilesystemAccess(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n // Only show if the user has never made a choice (key doesn't exist yet)\n if (config && 'allowReadWriteFiles' in config) return;\n this.showFilesystemSetupDialog();\n }\n\n private showFilesystemSetupDialog(): void {\n const t = this.translation.translate.bind(this.translation);\n Swal.fire({\n title: t('RECORDER.FS_TITLE'),\n html: '<div id=\"fs-setup-content\"></div>',\n showCloseButton: true,\n showConfirmButton: false,\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n const container = document.getElementById('fs-setup-content');\n if (!container) return;\n mountFilesystemSetupContent(\n container,\n t,\n async () => {\n await this.persistence.setConfigKey('allowReadWriteFiles', 'false');\n Swal.close();\n },\n async () => {\n try {\n await this.persistence.requestDirectoryPermissions();\n Swal.close();\n showToast(t('RECORDER.FS_SUCCESS_TOAST'));\n } catch (e: unknown) {\n if ((e as DOMException)?.name !== 'AbortError') {\n showToast(t('RECORDER.FS_ERROR_TOAST'), false);\n }\n // AbortError = user cancelled the picker, leave dialog open\n }\n },\n );\n },\n });\n }\n\n // ── dialogs ──────────────────────────────────────────────────────────────\n\n showCommandsDialog(): void {\n this.openSwalDialog(\n 'isCommandsDialogOpen',\n 'commands-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.DIALOG_COMMANDS'),\n html: '<div id=\"commands-modal-content\" style=\"min-height:250px;padding:0\"></div>',\n showCloseButton: true, allowOutsideClick: false, backdrop: false, width: 640,\n },\n (container) => {\n const child = mountComponentInSwal<PrevisualizerEl>('lib-e2e-test-previsualizer', container, {\n translation: this.translation,\n commands: this.cypressCommands,\n interceptors: this.interceptors,\n editable: true,\n }, [\n { name: 'deletecommand', handler: (e) => this.recording.removeCommand(e.detail) },\n { name: 'movecommand', handler: (e) => this.recording.moveCommand(e.detail.from, e.detail.to) },\n { name: 'deleteinterceptor', handler: (e) => this.recording.removeInterceptor(e.detail) },\n ]);\n this._previsualizerRef = child;\n injectAssertionBuilder(container, this.translation.translate.bind(this.translation), (cmd) => this.recording.appendCommand(cmd));\n },\n {\n // Make the container click-through so the page underneath remains interactive\n onDidOpenPreamble: () => {\n const swalContainer = document.querySelector('.swal2-container') as HTMLElement | null;\n if (swalContainer) {\n swalContainer.style.pointerEvents = 'none';\n const popup = swalContainer.querySelector('.swal2-popup') as HTMLElement | null;\n if (popup) popup.style.pointerEvents = 'all';\n }\n },\n onWillClose: () => { this._previsualizerRef = null; },\n },\n );\n }\n\n showSavedTestsDialog(): void {\n this.openSwalDialog(\n 'isSavedTestsDialogOpen',\n 'saved-tests-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVED_TESTS'),\n html: '<div id=\"saved-tests-modal-content\" style=\"min-height:250px;padding:0\"></div>',\n showCloseButton: true, width: 680,\n },\n (container) => {\n mountComponentInSwal<TestEditorEl>('lib-e2e-test-editor', container, {\n persistence: this.persistence,\n translation: this.translation,\n issueTrackerConfig: this.issueTrackerConfig,\n });\n },\n );\n }\n\n showSaveTestDialog(): void {\n this.openSwalDialog(\n 'isSaveTestDialogOpen',\n 'save-test-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVE'),\n html: '<div id=\"save-test-modal-content\" style=\"padding:0\"></div>',\n showCloseButton: false, allowOutsideClick: false, allowEscapeKey: false,\n },\n (container) => {\n mountComponentInSwal<SaveTestEl>('lib-e2e-save-test', container, {\n translation: this.translation,\n issueTrackerConfig: this.issueTrackerConfig,\n }, [\n { name: 'savetest', handler: (e) => {\n const { description, notes, tags, ticketId } = e.detail ?? {};\n this.onSaveTest(description ?? null, tags ?? [], notes ?? '', ticketId ?? '');\n Swal.close();\n }},\n { name: 'saveandexport', handler: (e) => {\n const { description, notes, tags, ticketId } = e.detail ?? {};\n this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? '', ticketId ?? '');\n Swal.close();\n }},\n ]);\n },\n { skipResize: true },\n );\n }\n\n showSettingsDialog(): void {\n this.openSwalDialog(\n 'isSettingsDialogOpen',\n 'settings-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.SETTINGS'),\n html: '<div id=\"settings-modal-content\" style=\"padding:0\"></div>',\n showCloseButton: true, width: 520,\n },\n (container) => {\n mountComponentInSwal<ConfigEl>('lib-e2e-configuration', container, {\n persistence: this.persistence,\n translation: this.translation,\n }, [\n { name: 'smartselectorchange', handler: (e) => { this.smartSelectorEnabled = e.detail; } },\n { name: 'starthiddenchange', handler: (e) => {\n this.isVisible = !e.detail;\n this.style.display = this.isVisible ? '' : 'none';\n }},\n { name: 'resetwidgetposition', handler: () => this.resetWidgetPosition() },\n { name: 'issuetrackerchange', handler: (e) => { this.issueTrackerConfig = e.detail as IssueTrackerConfig; } },\n ]);\n },\n );\n }\n\n showHelpDialog(): void {\n this.openSwalDialog(\n 'isHelpDialogOpen',\n 'help-modal-content',\n {\n title: this.translation.translate('HELP.TITLE'),\n html: '<div id=\"help-modal-content\" style=\"padding:0\"></div>',\n showCloseButton: true, width: 560,\n },\n (container) => {\n mountComponentInSwal<HelpPanelEl>('lib-e2e-help-panel', container, {\n translation: this.translation,\n });\n },\n );\n }\n\n showAdvancedEditorDialog(testId?: number): void {\n this.toggleModal('isAdvancedEditorDialogOpen', () => {\n Swal.fire({\n title: this.translation.translate('MAIN_FRAME.SHOW_ADVANCED_EDITOR'),\n html: '<div id=\"advanced-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\n showCloseButton: true,\n showConfirmButton: false,\n allowOutsideClick: false,\n width: 780,\n color: '#e6edf3',\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n ensurePopupDimensions(Swal.getPopup(), 600);\n const container = document.getElementById('advanced-editor-modal-content');\n if (!container) return;\n const child = mountComponentInSwal<AdvancedEditorEl>('lib-e2e-advanced-test-editor', container, {\n persistence: this.persistence,\n translation: this.translation,\n ...(testId !== undefined ? { testId } : {}),\n }, [\n { name: 'selectorstrategychange', handler: (e) => { this.recording.selectorStrategy = e.detail; } },\n { name: 'closemodal', handler: () => Swal.close() },\n { name: 'openfileeditor', handler: (e) => {\n Swal.close();\n setTimeout(() => this.showFileEditorDialog(\n e.detail.handle, e.detail.content, e.detail.fileName, e.detail.testId,\n e.detail.itBlock, e.detail.interceptorsBlock, e.detail.notes,\n ), 150);\n }},\n ]);\n void this.persistence.getLoginSetup().then(cfg => { child.loginSetupConfig = cfg; });\n },\n willClose: () => { this.isAdvancedEditorDialogOpen = false; },\n });\n setTimeout(() => {\n const popup = Swal.getPopup();\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });\n }, 0);\n });\n }\n\n private showFileEditorDialog(\n handle: FileSystemFileHandle,\n content: string,\n fileName: string,\n testId?: number,\n itBlock = '',\n interceptorsBlock = '',\n notes = '',\n ): void {\n Swal.fire({\n title: this.translation.translate('RECORDER.FILE_EDITOR_TITLE'),\n html: '<div id=\"file-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\n showCloseButton: false,\n showConfirmButton: false,\n allowOutsideClick: false,\n width: 1100,\n color: '#e6edf3',\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n // Give the code editor a tall default height (otherwise the popup collapses\n // to its ~210px min-height and the user has to resize it every time).\n ensurePopupDimensions(Swal.getPopup(), 640);\n const container = document.getElementById('file-editor-modal-content');\n if (!container) return;\n mountComponentInSwal<FilePreviewEl>('lib-e2e-file-preview', container, {\n translation: this.translation,\n fileContent: content,\n fileName,\n closeLabel: this.translation.translate('FILE_PREVIEW.BACK_TO_EDITOR'),\n itBlock,\n interceptorsBlock,\n notes,\n }, [\n { name: 'close', handler: () => {\n Swal.close();\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\n }},\n { name: 'save', handler: async (e) => {\n try {\n const writable = await handle.createWritable();\n await writable.write(e.detail);\n await writable.close();\n showToast(this.translation.translate('RECORDER.FILE_SAVED_TOAST'));\n } catch {\n showToast(this.translation.translate('RECORDER.FILE_SAVE_ERROR_TOAST'), false);\n }\n Swal.close();\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\n }},\n ]);\n },\n });\n this.resizePopup();\n }\n\n // ── save handlers ─────────────────────────────────────────────────────────\n\n private async onSaveTest(description: string | null, tags: string[] = [], notes = '', ticketId = ''): Promise<void> {\n if (!description) return;\n // Plain save → IndexedDB only, spy interceptors with inline validations.\n // No fixture files written regardless of fixture mode (spec 012).\n await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId || undefined);\n\n const uploadedFiles = this.recording.getUploadedFilesSnapshot();\n if (uploadedFiles.length > 0) {\n const filenames = uploadedFiles.map(f => f.filename).join(', ');\n showToast(\n this.translation.translate('RECORDER.FILE_UPLOAD_MANUAL_TOAST').replace('{files}', filenames),\n false,\n );\n }\n\n this.recording.clearCommands();\n this.clearRecordingHistory();\n this.cypressCommands = [];\n this.interceptors = [];\n }\n\n private async onSaveAndExportTest(description: string | null, tags: string[] = [], notes = '', ticketId = ''): Promise<void> {\n if (!description) return;\n\n const fixtures = this.recording.getFixturesSnapshot();\n const isFixtureMode = this.httpMonitor?.isFixtureModeEnabled() ?? false;\n let finalInterceptors = this.interceptors;\n let finalCommands = this.cypressCommands;\n\n // Fixture mode + Save-and-Edit: attempt to write fixture files and convert\n // spy interceptors to fixture stubs. Falls back to spy on no folder/permission.\n if (isFixtureMode && fixtures.length > 0) {\n try {\n const n = await this.persistence.writeFixtures(fixtures);\n finalInterceptors = toFixtureInterceptors(this.interceptors, fixtures);\n finalCommands = simplifyFixtureWaits(this.cypressCommands, fixtures);\n showToast(`${this.translation.translate('RECORDER.FIXTURES_WRITTEN_TOAST')} (${n})`);\n } catch {\n showToast(this.translation.translate('RECORDER.FIXTURES_NO_FOLDER_TOAST'), false);\n }\n }\n\n const uploadedFiles = this.recording.getUploadedFilesSnapshot();\n if (uploadedFiles.length > 0) {\n const filenames = uploadedFiles.map(f => f.filename).join(', ');\n const hasAccess = await this.persistence.hasDirectoryAccess();\n if (hasAccess) {\n try {\n for (const uf of uploadedFiles) {\n await this.persistence.writeUploadedFile(uf.filename, uf.bytes);\n }\n showToast(this.translation.translate('RECORDER.FILE_UPLOAD_COPIED_TOAST').replace('{files}', filenames));\n } catch {\n showToast(\n this.translation.translate('RECORDER.FILE_UPLOAD_COPY_ERROR_TOAST').replace('{files}', filenames),\n false,\n );\n }\n } else {\n showToast(\n this.translation.translate('RECORDER.FILE_UPLOAD_MANUAL_TOAST').replace('{files}', filenames),\n false,\n );\n }\n }\n\n const id = await this.persistence.insertTest(description, finalCommands, finalInterceptors, tags, notes, ticketId || undefined);\n this.recording.clearCommands();\n this.clearRecordingHistory();\n this.cypressCommands = [];\n this.interceptors = [];\n setTimeout(() => this.showAdvancedEditorDialog(id), 300);\n }\n\n // ── helpers ───────────────────────────────────────────────────────────────\n\n private toggleModal(flag: keyof this, openFn: () => void): void {\n if (this[flag]) {\n Swal.close();\n (this as Record<string, unknown>)[flag as string] = false;\n return;\n }\n (this as Record<string, unknown>)[flag as string] = true;\n openFn();\n }\n\n private resizePopup(): void {\n setTimeout(() => {\n const popup = Swal.getPopup();\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 200 });\n }, 0);\n }\n\n private openSwalDialog(\n flag: keyof this,\n contentId: string,\n swalOptions: SweetAlertOptions,\n onMount: (container: HTMLElement) => void,\n extra?: { onDidOpenPreamble?: () => void; onWillClose?: () => void; skipResize?: boolean },\n ): void {\n this.toggleModal(flag, () => {\n Swal.fire({\n showConfirmButton: false,\n color: '#e6edf3',\n ...swalOptions,\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n extra?.onDidOpenPreamble?.();\n const container = document.getElementById(contentId);\n if (!container) return;\n onMount(container);\n },\n willClose: () => {\n (this as Record<string, unknown>)[flag as string] = false;\n extra?.onWillClose?.();\n },\n });\n if (!extra?.skipResize) this.resizePopup();\n });\n }\n\n private render(): void {\n const rec = this.isRecording;\n const paused = this.isPaused;\n this.style.display = this.isVisible ? '' : 'none';\n this.shadow.innerHTML = `<style>${getRecorderStyles(rec, paused)}</style>${renderRecorderWidget(rec, paused, this.translation.translate.bind(this.translation))}`;\n const toggleBtn = this.shadow.querySelector('[data-action=\"toggle\"]');\n toggleBtn?.addEventListener('click', () => {\n // A drag ends with a click event we must swallow so it doesn't toggle recording.\n if (this.suppressNextToggleClick) { this.suppressNextToggleClick = false; return; }\n this.toggle();\n });\n toggleBtn?.addEventListener('pointerdown', (e) => this.beginWidgetDrag(e as MouseEvent));\n this.shadow.querySelector('[data-action=\"pause\"]')\n ?.addEventListener('click', () => this.togglePause());\n this.shadow.querySelector('[data-action=\"tests\"]')\n ?.addEventListener('click', () => this.showSavedTestsDialog());\n this.shadow.querySelector('[data-action=\"commands\"]')\n ?.addEventListener('click', () => this.showCommandsDialog());\n this.shadow.querySelector('[data-action=\"config\"]')\n ?.addEventListener('click', () => this.showSettingsDialog());\n this.shadow.querySelector('[data-action=\"browse\"]')\n ?.addEventListener('click', () => this.showAdvancedEditorDialog());\n this.shadow.querySelector('[data-action=\"help\"]')\n ?.addEventListener('click', () => this.showHelpDialog());\n // Re-apply the dragged position/orientation after every re-render.\n this.applyWidgetPosition();\n }\n}\n\nif (!customElements.get('lib-e2e-recorder')) {\n customElements.define('lib-e2e-recorder', LibE2eRecorderElement);\n}\n","import type { ExpandDirection } from '../../utils/widget-position.utils';\n\nconst DIRECTIONS: ExpandDirection[] = ['up-left', 'up-right', 'down-left', 'down-right'];\n\n/**\n * Per-direction anchors for the toggle/pause buttons and the action-menu popover.\n * The menu opens on the side of the FAB that faces the viewport interior, so it\n * stays on-screen wherever the (draggable) widget is dropped (spec 007 + 012).\n */\nfunction directionBlocks(): string {\n return DIRECTIONS.map((dir) => {\n const tv = dir.startsWith('up') ? 'bottom' : 'top'; // FAB vertical side\n const th = dir.endsWith('left') ? 'right' : 'left'; // FAB horizontal side\n const ov = tv === 'bottom' ? 'top' : 'bottom';\n const oh = th === 'right' ? 'left' : 'right';\n const sel = `.widget[data-expand=\"${dir}\"]`;\n return `\n ${sel} .btn-toggle { ${tv}: 24px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\n ${sel} .btn-pause { ${tv}: 78px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\n ${sel} .action-menu { ${tv}: 118px; ${th}: 8px; ${ov}: auto; ${oh}: auto; transform-origin: ${tv} ${th}; }\n `;\n }).join('\\n');\n}\n\nexport function getRecorderStyles(rec: boolean, paused: boolean): string {\n return `\n :host { all: initial; }\n *, *::before, *::after { box-sizing: border-box; }\n\n /*\n * Hit area. Position (left/top) is set from JS so the widget can be dragged;\n * data-expand orients the action-menu popover toward the viewport interior.\n * The menu is a DOM child, so hovering it keeps :host(.widget):hover alive even\n * though it visually overflows this box. Defaults to bottom-right.\n */\n .widget {\n position: fixed;\n bottom: 0;\n right: 0;\n width: 190px;\n height: 190px;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n }\n\n /* ── Toggle (FAB) ─────────────────────────────────── */\n .btn-toggle {\n position: absolute;\n bottom: 24px;\n right: 24px;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n border: none;\n cursor: grab;\n touch-action: none;\n font-size: 19px;\n background: ${rec\n ? 'linear-gradient(135deg,#f85149 0%,#da3633 100%)'\n : 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'};\n color: #fff;\n box-shadow: ${rec\n ? '0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13)'\n : '0 4px 20px rgba(47,129,247,.45),0 0 0 4px rgba(47,129,247,.11)'};\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform .18s, box-shadow .2s;\n z-index: 2;\n ${rec ? 'animation: toggle-pulse 2s ease-in-out infinite;' : ''}\n }\n .btn-toggle:hover { transform: scale(1.1); }\n .btn-toggle:active { transform: scale(0.93); cursor: grabbing; }\n\n @keyframes toggle-pulse {\n 0%,100% { box-shadow: 0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13); }\n 50% { box-shadow: 0 6px 28px rgba(248,81,73,.75),0 0 0 8px rgba(248,81,73,.06); }\n }\n\n /* ── Pause button ────────────────────────────────── */\n .btn-pause {\n position: absolute;\n bottom: 78px;\n right: 24px;\n width: 34px;\n height: 34px;\n border-radius: 50%;\n border: none;\n cursor: pointer;\n font-size: 15px;\n display: ${rec ? 'flex' : 'none'};\n align-items: center;\n justify-content: center;\n background: ${paused\n ? 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'\n : 'rgba(13,17,23,0.85)'};\n color: ${paused ? '#fff' : '#e3b341'};\n box-shadow: 0 2px 12px rgba(0,0,0,.4), 0 0 0 1px rgba(48,54,61,.8);\n transition: transform .15s, background .2s, color .2s;\n z-index: 2;\n }\n .btn-pause:hover { transform: scale(1.12); }\n .btn-pause:active { transform: scale(0.93); }\n\n /* ── Action menu (labelled grid popover) ─────────── */\n .action-menu {\n position: absolute;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 4px;\n padding: 8px;\n width: 174px;\n background: rgba(13,17,23,.97);\n border: 1px solid rgba(48,54,61,.9);\n border-radius: 12px;\n box-shadow: 0 8px 28px rgba(0,0,0,.5);\n backdrop-filter: blur(14px);\n -webkit-backdrop-filter: blur(14px);\n opacity: 0;\n transform: scale(0.9);\n pointer-events: none;\n transition: opacity .16s, transform .2s cubic-bezier(.34,1.56,.64,1);\n z-index: 3;\n }\n .widget:hover .action-menu {\n opacity: 1;\n transform: scale(1);\n pointer-events: all;\n }\n\n .action-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n gap: 3px;\n padding: 8px 4px;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n background: transparent;\n color: #c9d1d9;\n font-size: 18px;\n line-height: 1;\n transition: background .12s;\n }\n .action-item:hover { background: #21262d; }\n .action-item .label {\n font-size: 9px;\n font-weight: 500;\n color: #8b949e;\n white-space: nowrap;\n }\n .action-item:hover .label { color: #e6edf3; }\n\n /* Per-direction anchors */\n ${directionBlocks()}\n\n /* ── REC / PAUSED badge ──────────────────────────── */\n .rec-badge {\n position: fixed;\n top: 14px;\n left: 50%;\n transform: translateX(-50%);\n background: ${paused\n ? 'linear-gradient(90deg,#e3b341,#d29922)'\n : 'linear-gradient(90deg,#f85149,#da3633)'};\n color: #fff;\n padding: 3px 16px;\n border-radius: 20px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 2px;\n text-transform: uppercase;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n box-shadow: ${paused\n ? '0 4px 16px rgba(227,179,65,.4)'\n : '0 4px 16px rgba(248,81,73,.4)'};\n display: ${rec ? 'block' : 'none'};\n ${!paused ? 'animation: rec-pulse 1.8s ease-in-out infinite;' : ''}\n }\n @keyframes rec-pulse {\n 0%,100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n `;\n}\n","export function renderRecorderWidget(rec: boolean, paused: boolean, t: (key: string) => string): string {\n return `\n <div class=\"widget\">\n <div class=\"action-menu\">\n <button class=\"action-item\" data-action=\"config\">\n <span class=\"ico\">⚙️</span><span class=\"label\">${t('RECORDER.BTN_CONFIG')}</span></button>\n <button class=\"action-item\" data-action=\"browse\">\n <span class=\"ico\">📁</span><span class=\"label\">${t('RECORDER.BTN_FILES')}</span></button>\n <button class=\"action-item\" data-action=\"commands\">\n <span class=\"ico\">⌨️</span><span class=\"label\">${t('RECORDER.BTN_COMMANDS')}</span></button>\n <button class=\"action-item\" data-action=\"tests\">\n <span class=\"ico\">📋</span><span class=\"label\">${t('RECORDER.BTN_TESTS')}</span></button>\n <button class=\"action-item\" data-action=\"help\">\n <span class=\"ico\">❓</span><span class=\"label\">${t('RECORDER.BTN_HELP')}</span></button>\n </div>\n <button class=\"btn-pause\" data-action=\"pause\"\n title=\"${paused ? t('RECORDER.RESUME_TITLE') : t('RECORDER.PAUSE_TITLE')}\">\n ${paused ? '▶' : '⏸'}\n </button>\n <button class=\"btn-toggle\" data-action=\"toggle\"\n title=\"${rec ? t('RECORDER.STOP_TITLE') : t('RECORDER.START_TITLE')}\">\n ${rec ? '⏹' : '⏺'}\n </button>\n </div>\n <div class=\"rec-badge\">${paused ? t('RECORDER.BADGE_PAUSED') : t('RECORDER.BADGE_REC')}</div>`;\n}\n","import { escapeSingleQuotes } from '../../utils/code-format.utils';\n\nconst NO_VALUE_ASSERTIONS = new Set(['be.visible', 'not.exist', 'be.disabled', 'be.checked']);\n\nexport function injectAssertionBuilder(\n container: HTMLElement,\n t: (key: string) => string,\n onAddCommand: (cmd: string) => void,\n): void {\n container.insertAdjacentHTML('beforeend', `\n <div id=\"assertion-builder\"\n style=\"padding:10px 12px;border-top:1px solid #21262d;background:#0d1117\">\n <div style=\"font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px\">\n ${t('RECORDER.ASSERTION_SECTION')}\n </div>\n <div style=\"display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end\">\n <input id=\"assert-selector\" type=\"text\"\n placeholder=\"${t('RECORDER.ASSERT_SELECTOR_PH').replace(/\"/g, '"')}\"\n style=\"flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;\n font-family:'Cascadia Code','Fira Code',monospace\"/>\n <select id=\"assert-type\"\n style=\"padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;\n color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0\">\n <option value=\"be.visible\">be.visible</option>\n <option value=\"not.exist\">not.exist</option>\n <option value=\"be.disabled\">be.disabled</option>\n <option value=\"be.checked\">be.checked</option>\n <option value=\"contain.text\">contain.text</option>\n <option value=\"have.value\">have.value</option>\n <option value=\"have.length\">have.length</option>\n <option value=\"have.class\">have.class</option>\n <option value=\"have.attr\">have.attr</option>\n </select>\n <input id=\"assert-value\" type=\"text\" placeholder=\"${t('RECORDER.ASSERT_VALUE_PH')}\"\n style=\"flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none\"/>\n <button id=\"btn-add-assertion\"\n style=\"padding:5px 12px;border:none;border-radius:5px;cursor:pointer;\n font-size:11px;font-weight:500;background:#2f81f7;color:#fff;\n white-space:nowrap;flex-shrink:0\">\n ${t('RECORDER.ASSERT_ADD_BTN')}\n </button>\n </div>\n </div>`);\n\n document.getElementById('btn-add-assertion')?.addEventListener('click', () => {\n const sel = (document.getElementById('assert-selector') as HTMLInputElement).value.trim();\n const type = (document.getElementById('assert-type') as HTMLSelectElement).value;\n const val = (document.getElementById('assert-value') as HTMLInputElement).value.trim();\n if (!sel) return;\n const s = escapeSingleQuotes(sel);\n const v = escapeSingleQuotes(val);\n const cmd = NO_VALUE_ASSERTIONS.has(type) || !val\n ? `cy.get('${s}').should('${type}')`\n : `cy.get('${s}').should('${type}', '${v}')`;\n onAddCommand(cmd);\n (document.getElementById('assert-selector') as HTMLInputElement).value = '';\n (document.getElementById('assert-value') as HTMLInputElement).value = '';\n });\n}\n","export function mountFilesystemSetupContent(\n container: HTMLElement,\n t: (key: string) => string,\n onSkip: () => Promise<void>,\n onSelect: () => Promise<void>,\n): void {\n container.innerHTML = `\n <div style=\"padding:16px 20px 20px;color:#8b949e;font-size:13px;line-height:1.7\">\n <p>${t('RECORDER.FS_INTRO_HTML')}</p>\n <p style=\"margin-top:10px;margin-bottom:6px;font-size:11px;color:#8b949e\">\n ${t('RECORDER.FS_STRUCTURE_HINT_HTML')}\n </p>\n <pre style=\"margin:0;padding:10px 14px;background:#0d1117;border:1px solid #21262d;\n border-radius:8px;font-size:11px;color:#c9d1d9;line-height:1.8;\n font-family:'Cascadia Code','Fira Code','Consolas',monospace\">\ncypress/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_PICK_HINT')}</span>\n└── e2e/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_READ_HINT')}</span>\n └── *.cy.ts</pre>\n <p style=\"margin-top:8px;font-size:11px;color:#484f58\">\n ${t('RECORDER.FS_PERMISSION_NOTE')}\n </p>\n <div style=\"display:flex;gap:8px;justify-content:flex-end;margin-top:20px\">\n <button id=\"fs-skip\"\n style=\"padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:transparent;color:#8b949e\">\n ${t('RECORDER.FS_LATER_BTN')}\n </button>\n <button id=\"fs-select\"\n style=\"padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\n ${t('RECORDER.FS_SELECT_BTN')}\n </button>\n </div>\n </div>`;\n\n document.getElementById('fs-skip')?.addEventListener('click', () => { void onSkip(); });\n document.getElementById('fs-select')?.addEventListener('click', () => { void onSelect(); });\n}\n","export function mountComponentInSwal<T extends object>(\n tagName: string,\n container: HTMLElement,\n props: Partial<T>,\n events?: Array<{ name: string; handler: (e: CustomEvent) => void }>,\n): T {\n const el = document.createElement(tagName) as unknown as T;\n Object.assign(el, props);\n container.appendChild(el as unknown as Node);\n for (const { name, handler } of events ?? []) {\n (el as unknown as EventTarget).addEventListener(name, handler as EventListener);\n }\n return el;\n}\n","/**\n * Geometry helpers for the draggable recording widget (spec 007).\n * Pure functions — no DOM — so the drag/clamp/expansion logic is unit-testable\n * without real layout (jsdom returns 0-sized rects).\n */\n\nexport type ExpandDirection = 'up-left' | 'up-right' | 'down-left' | 'down-right';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Toggle radius (44/2) + small gap, so the toggle never touches the edge. */\nexport const TOGGLE_MARGIN = 30;\n\n/** Pixels the pointer must travel before a press becomes a drag (vs a click). */\nexport const DRAG_THRESHOLD = 5;\n\n/** Distance, in px, from the bottom-right edges of the original (default) anchor. */\nconst DEFAULT_EDGE_OFFSET = 46;\n\n/**\n * Toggle-centre offset inside the 190×190 widget box, per expansion direction.\n * The toggle sits at the box corner nearest the screen edge so the arc always\n * expands toward the viewport interior (and stays inside the box / on screen).\n */\nexport function boxOffsetForDirection(dir: ExpandDirection): Point {\n return {\n x: dir.endsWith('left') ? 144 : 46,\n y: dir.startsWith('up') ? 144 : 46,\n };\n}\n\n/** Clamps the toggle-centre so the toggle button stays fully on screen. */\nexport function clampTogglePosition(\n x: number,\n y: number,\n vw: number,\n vh: number,\n margin: number = TOGGLE_MARGIN,\n): Point {\n const maxX = Math.max(margin, vw - margin);\n const maxY = Math.max(margin, vh - margin);\n return {\n x: Math.min(Math.max(x, margin), maxX),\n y: Math.min(Math.max(y, margin), maxY),\n };\n}\n\n/**\n * Chooses the radial expansion direction so the menu opens toward the centre of\n * the viewport (top half → expand down; left half → expand right).\n */\nexport function resolveExpandDirection(x: number, y: number, vw: number, vh: number): ExpandDirection {\n const vertical = y < vh / 2 ? 'down' : 'up';\n const horizontal = x < vw / 2 ? 'right' : 'left';\n return `${vertical}-${horizontal}` as ExpandDirection;\n}\n\n/** Default toggle-centre (bottom-right corner), matching the original CSS anchor. */\nexport function defaultTogglePosition(vw: number, vh: number): Point {\n return { x: vw - DEFAULT_EDGE_OFFSET, y: vh - DEFAULT_EDGE_OFFSET };\n}\n\n/** Box top-left for a given (clamped) toggle-centre and direction. */\nexport function boxTopLeftFor(toggleCentre: Point, dir: ExpandDirection): Point {\n const off = boxOffsetForDirection(dir);\n return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };\n}\n","/**\n * Converts spy-style `cy.intercept(...)` strings to fixture-stub form when a\n * matching fixture exists, and simplifies the corresponding `cy.wait(...)` commands\n * by stripping inline body-validation callbacks (the data is now stubbed).\n *\n * These conversions are applied at save-and-export time (spec 012) so that:\n * - recording always uses spy interceptors (no decision about save mode needed);\n * - fixture stubs are only emitted when the user clicks \"Save and Edit\" AND the\n * Cypress folder has write permission.\n */\n\n/**\n * For each spy interceptor whose alias has a matching fixture, inserts the\n * `{ fixture: '<alias>.json' }` response body.\n *\n * Input: `cy.intercept('GET', '**\\/api').as('get-api')`\n * Output: `cy.intercept('GET', '**\\/api', { fixture: 'get-api.json' }).as('get-api')`\n */\nexport function toFixtureInterceptors(\n interceptors: string[],\n fixtures: Array<{ name: string }>,\n): string[] {\n const fixtureNames = new Set(fixtures.map((f) => f.name));\n return interceptors.map((icp) => {\n const match = icp.match(/\\.as\\('([^']+)'\\)$/);\n if (!match) return icp;\n const fixtureFile = `${match[1]}.json`;\n if (!fixtureNames.has(fixtureFile)) return icp;\n return icp.replace(/\\)\\.as\\(/, `, { fixture: '${fixtureFile}' }).as(`);\n });\n}\n\n/**\n * For each `cy.wait('@alias')` command whose alias maps to a captured fixture,\n * replaces any inline body-validation callback with the no-op form.\n *\n * Input: `cy.wait('@get-api').then((interception) => { expect(...) ... })`\n * Output: `cy.wait('@get-api').then((interception) => { })`\n */\nexport function simplifyFixtureWaits(\n commands: string[],\n fixtures: Array<{ name: string }>,\n): string[] {\n const fixtureAliases = new Set(fixtures.map((f) => f.name.replace(/\\.json$/, '')));\n return commands.map((cmd) => {\n const match = cmd.match(/^cy\\.wait\\('@([^']+)'\\)/);\n if (!match || !fixtureAliases.has(match[1])) return cmd;\n return `cy.wait('@${match[1]}').then((interception) => { })`;\n });\n}\n"],"mappings":"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","names":["tag","container","selector","rect","Swal","input","folderInput","i","j","import_sweetalert2","Swal"]}
|
|
1
|
+
{"version":3,"sources":["../src/utils/code-format.utils.ts","../src/utils/selector-quality.utils.ts","../src/components/selector-picker/selector-picker.styles.ts","../src/utils/html.utils.ts","../src/components/selector-picker/selector-picker.template.ts","../src/components/selector-picker/selector-picker.ts","../src/index.ts","../src/models/lang.model.ts","../src/models/input-types.model.ts","../src/models/db-schema.model.ts","../src/utils/subject.ts","../src/i18n/es.ts","../src/i18n/en.ts","../src/i18n/fr.ts","../src/i18n/it.ts","../src/i18n/de.ts","../src/services/translation.service.ts","../src/services/transformation.service.ts","../src/services/advanced-test.transformation.service.ts","../src/services/recording.service.ts","../src/utils/assertion.utils.ts","../src/services/persistence.service.ts","../src/models/issue-tracker.model.ts","../src/utils/ticket.utils.ts","../src/services/http-monitor.ts","../src/utils/redact.utils.ts","../src/utils/styles.utils.ts","../src/utils/modal.utils.ts","../src/utils/toast.utils.ts","../src/utils/export-selection.utils.ts","../src/utils/host.utils.ts","../src/components/test-previsualizer/test-previsualizer.styles.ts","../src/components/test-previsualizer/test-previsualizer.template.ts","../src/components/test-previsualizer/test-previsualizer.ts","../src/components/save-test/save-test.styles.ts","../src/components/save-test/save-test.template.ts","../src/components/save-test/save-test.ts","../src/components/test-editor/test-editor.ts","../src/components/test-editor/test-editor.styles.ts","../src/components/test-editor/test-editor.template.ts","../src/utils/syntax-highlight.utils.ts","../src/models/active-session.model.ts","../src/utils/login-setup.utils.ts","../src/components/configuration/configuration.styles.ts","../src/components/configuration/configuration.template.ts","../src/components/configuration/configuration.ts","../src/components/advanced-test-editor/advanced-test-editor.ts","../src/components/advanced-test-editor/advanced-test-editor.styles.ts","../src/components/advanced-test-editor/advanced-test-editor.template.ts","../src/components/file-preview/file-preview.styles.ts","../src/components/file-preview/file-preview.template.ts","../src/components/file-preview/file-preview.ts","../src/components/help-panel/help-panel.styles.ts","../src/components/help-panel/help-panel.template.ts","../src/components/help-panel/help-panel.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.styles.ts","../src/components/lib-e2e-recorder/lib-e2e-recorder.template.ts","../src/components/lib-e2e-recorder/assertion-builder.ts","../src/components/lib-e2e-recorder/filesystem-setup.ts","../src/utils/swal-mount.utils.ts","../src/utils/widget-position.utils.ts","../src/utils/fixture-convert.utils.ts"],"sourcesContent":["function gcd(a: number, b: number): number {\n while (b) { const t = b; b = a % b; a = t; }\n return a;\n}\n\n/**\n * Escapes backslashes and single quotes so a value can be safely embedded inside\n * a single-quoted JavaScript string literal — e.g. an `it('…')` / `describe('…')`\n * name. Without this, a test named `User's login` produces broken generated JS.\n */\nexport function escapeSingleQuotes(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\");\n}\n\n/**\n * Escapes double quotes so a value can be safely embedded inside a CSS\n * double-quoted attribute selector, e.g. [data-cy=\"VALUE\"].\n * The result must subsequently pass through escapeSingleQuotes when it is\n * placed inside a single-quoted JS string literal (the JS layer doubles the\n * backslash introduced here).\n */\nexport function escapeCssAttrValue(value: string): string {\n return value.replace(/\"/g, '\\\\\"');\n}\n\n/**\n * Normalizes indentation in a code block and prefixes every line with baseIndent.\n *\n * Algorithm:\n * 1. Strip trailing whitespace from each line.\n * 2. Find the minimum leading-whitespace count of non-empty lines (dedent).\n * 3. Compute the indent step as the GCD of all non-zero relative indent values,\n * so the original indent unit (4-space, 8-space, etc.) maps to 2-space levels.\n * 4. Re-emit each line as: baseIndent + ' '.repeat(level) + trimmedContent.\n *\n * This handles multi-line interceptor/command blocks that were stored with\n * inconsistent or file-origin indentation.\n */\nexport function normalizeBlock(code: string, baseIndent: string): string {\n const lines = code.split('\\n').map(l => l.trimEnd());\n const nonEmpty = lines.filter(l => l.trim().length > 0);\n if (!nonEmpty.length) return '';\n\n const indents = nonEmpty.map(l => l.length - l.trimStart().length);\n const minIndent = Math.min(...indents);\n const relIndents = [...new Set(indents.map(n => n - minIndent).filter(n => n > 0))];\n const step = relIndents.length > 0 ? relIndents.reduce(gcd) : 2;\n\n return lines\n .map(l => {\n if (!l.trim()) return '';\n const level = Math.round((l.length - l.trimStart().length - minIndent) / step);\n return baseIndent + ' '.repeat(level) + l.trimStart();\n })\n .join('\\n');\n}\n","import { escapeCssAttrValue } from './code-format.utils';\n\nexport type SelectorQuality = 'excellent' | 'good' | 'acceptable' | 'poor';\n\nexport const FORBIDDEN_ID_PREFIXES = [\n 'cdk-', 'mat-', 'p-', 'ng-', 'mdc-',\n 'primeng-', 'auto-', 'field-', 'input-', 'select-',\n];\n\nexport function getSelectorQuality(el: HTMLElement): SelectorQuality {\n if (\n el.hasAttribute('data-cy') ||\n el.hasAttribute('data-testid') ||\n el.hasAttribute('aria-label')\n ) {\n return 'excellent';\n }\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return 'good';\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n return 'acceptable';\n }\n\n return 'poor';\n}\n\n/** Returns the best cy.get() selector string for a given element. */\nexport function buildPickerSelector(el: HTMLElement): string {\n const dataCy = el.getAttribute('data-cy');\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n\n const dataTestid = el.getAttribute('data-testid');\n if (dataTestid) return `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]`;\n\n const ariaLabel = el.getAttribute('aria-label');\n if (ariaLabel) return `[aria-label=\"${escapeCssAttrValue(ariaLabel)}\"]`;\n\n const rawId = el.id;\n if (\n rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId)\n ) {\n return `#${rawId}`;\n }\n\n if (typeof el.className === 'string' && el.className.trim().length > 0) {\n const classes = el.className.trim().split(/\\s+/);\n return classes.map((c) => `.${c}`).join('');\n }\n\n return el.tagName.toLowerCase();\n}\n\n/** Human-readable key attribute/selector preview for a picker row (raw, unescaped). */\nexport function keyAttrDisplay(el: HTMLElement): string {\n for (const attr of ['data-cy', 'data-testid', 'aria-label']) {\n const v = el.getAttribute(attr);\n if (v) return `${attr}=\"${v}\"`;\n }\n if (el.id) return `id=\"${el.id}\"`;\n if (el.className && el.className.trim()) {\n return el.className.trim().split(/\\s+/).map((c) => `.${c}`).join('');\n }\n return '';\n}\n\n/** Plain, serializable view-model for one picker row — no DOM held. */\nexport interface PickerRow {\n quality: SelectorQuality;\n selector: string;\n tag: string;\n attr: string;\n}\n\n/** Reads an element once and returns the plain data a picker row needs to render. */\nexport function describePickerRow(el: HTMLElement): PickerRow {\n return {\n quality: getSelectorQuality(el),\n selector: buildPickerSelector(el),\n tag: el.tagName.toLowerCase(),\n attr: keyAttrDisplay(el),\n };\n}\n","export const SELECTOR_PICKER_STYLES = `\n :host {\n position: fixed;\n z-index: 2147483647;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n }\n\n .overlay {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n pointer-events: all;\n background: #161b22;\n border: 1px solid #30363d;\n border-radius: 10px;\n box-shadow: 0 8px 32px rgba(0,0,0,0.6);\n min-width: 420px;\n max-width: 600px;\n font-family: 'Segoe UI', system-ui, sans-serif;\n color: #e6edf3;\n font-size: 13px;\n }\n\n .header {\n padding: 12px 16px 8px;\n border-bottom: 1px solid #21262d;\n font-weight: 600;\n font-size: 13px;\n color: #8b949e;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n }\n\n .list {\n max-height: 320px;\n overflow-y: auto;\n padding: 6px 0;\n }\n\n .row {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 7px 14px;\n cursor: pointer;\n border-radius: 6px;\n margin: 1px 6px;\n transition: background 0.1s;\n }\n\n .row:hover,\n .row.selected {\n background: #21262d;\n }\n\n .row.selected {\n outline: 2px solid #388bfd;\n outline-offset: -2px;\n }\n\n .quality-badge {\n width: 18px;\n height: 18px;\n border-radius: 50%;\n flex-shrink: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 10px;\n }\n\n .badge-excellent { background: #238636; }\n .badge-good { background: #1f6feb; }\n .badge-acceptable{ background: #9e6a03; }\n .badge-poor { background: #da3633; }\n\n .tag-name {\n font-family: monospace;\n font-size: 12px;\n color: #8b949e;\n flex-shrink: 0;\n }\n\n .attr-value {\n font-family: monospace;\n font-size: 12px;\n color: #c9d1d9;\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .selector-preview {\n font-family: monospace;\n font-size: 11px;\n color: #58a6ff;\n flex-shrink: 0;\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n .poor-warning {\n font-size: 10px;\n color: #f85149;\n margin-left: auto;\n }\n\n .footer {\n padding: 8px 14px 10px;\n border-top: 1px solid #21262d;\n display: flex;\n gap: 16px;\n font-size: 11px;\n color: #484f58;\n }\n\n .hint kbd {\n background: #21262d;\n border: 1px solid #30363d;\n border-radius: 3px;\n padding: 1px 5px;\n font-size: 10px;\n color: #8b949e;\n }\n`;\n","export function escHtml(s: string): string {\n return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\nexport function escAttr(s: string): string {\n return s.replace(/\"/g, '"').replace(/</g, '<');\n}\n","import type { PickerRow, SelectorQuality } from '../../utils/selector-quality.utils';\nimport { escHtml } from '../../utils/html.utils';\n\nconst QUALITY_EMOJI: Record<SelectorQuality, string> = {\n excellent: '🟢',\n good: '🔵',\n acceptable: '🟡',\n poor: '🔴',\n};\n\nconst QUALITY_CLASS: Record<SelectorQuality, string> = {\n excellent: 'badge-excellent',\n good: 'badge-good',\n acceptable: 'badge-acceptable',\n poor: 'badge-poor',\n};\n\nexport function renderPickerRows(\n rows: PickerRow[],\n selectedIndex: number,\n t: (key: string) => string,\n): string {\n return rows.map((row, i) => {\n const isSelected = i === selectedIndex;\n const isPoor = row.quality === 'poor';\n\n return `\n <div class=\"row${isSelected ? ' selected' : ''}\" data-idx=\"${i}\" role=\"option\" aria-selected=\"${isSelected}\">\n <span class=\"quality-badge ${QUALITY_CLASS[row.quality]}\" title=\"${escHtml(t(`SELECTOR_PICKER.QUALITY_${row.quality.toUpperCase()}`))}\">\n ${QUALITY_EMOJI[row.quality]}\n </span>\n <span class=\"tag-name\"><${escHtml(row.tag)}></span>\n ${row.attr ? `<span class=\"attr-value\">${escHtml(row.attr)}</span>` : '<span class=\"attr-value\"></span>'}\n <span class=\"selector-preview\">${escHtml(row.selector)}</span>\n ${isPoor ? `<span class=\"poor-warning\" title=\"${escHtml(t('SELECTOR_PICKER.QUALITY_POOR'))}\">⚠</span>` : ''}\n </div>`;\n }).join('');\n}\n\nexport function renderPicker(\n rows: PickerRow[],\n selectedIndex: number,\n t: (key: string) => string,\n): string {\n return `\n <div class=\"overlay\" role=\"listbox\">\n <div class=\"header\">${escHtml(t('SELECTOR_PICKER.TITLE'))}</div>\n <div class=\"list\">\n ${renderPickerRows(rows, selectedIndex, t)}\n </div>\n <div class=\"footer\">\n <span class=\"hint\"><kbd>↑↓</kbd> ${escHtml(t('SELECTOR_PICKER.PREVIEW_LABEL'))}</span>\n <span class=\"hint\"><kbd>Enter</kbd> ${escHtml(t('SELECTOR_PICKER.CONFIRM_HINT'))}</span>\n <span class=\"hint\"><kbd>Esc</kbd> ${escHtml(t('SELECTOR_PICKER.CANCEL_HINT'))}</span>\n </div>\n </div>`;\n}\n","import type { RecordingService } from '../../services/recording.service';\nimport type { TranslationService } from '../../services/translation.service';\nimport { describePickerRow, type PickerRow } from '../../utils/selector-quality.utils';\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { SELECTOR_PICKER_STYLES } from './selector-picker.styles';\nimport { renderPicker } from './selector-picker.template';\n\nconst OWN_DATA_CY = 'lib-e2e-cypress-for-dummys';\nconst MAX_ANCESTORS = 10;\n\nexport class SelectorPickerElement extends HTMLElement {\n targetElement: HTMLElement | null = null;\n recording!: RecordingService;\n translation!: TranslationService;\n\n private shadow: ShadowRoot;\n private ancestors: HTMLElement[] = [];\n private rows: PickerRow[] = [];\n private selectedIndex = 0;\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\n private unsubRecording: (() => void) | null = null;\n private unsubPause: (() => void) | null = null;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\n this.ancestors = this.buildAncestors();\n this.rows = this.ancestors.map(describePickerRow);\n this.selectedIndex = this.findBestIndex();\n this.render();\n this.attachKeyListener();\n this.attachRowClickListeners();\n this.subscribeToRecordingChanges();\n }\n\n disconnectedCallback(): void {\n this.detachKeyListener();\n this.unsubRecording?.();\n this.unsubPause?.();\n }\n\n private t(key: string): string {\n return this.translation?.translate(key) ?? key;\n }\n\n // ── Ancestor chain ──────────────────────────────────────────────────────────\n\n private buildAncestors(): HTMLElement[] {\n const chain: HTMLElement[] = [];\n let current: HTMLElement | null = this.targetElement;\n\n while (current && current.tagName.toLowerCase() !== 'html' && chain.length < MAX_ANCESTORS) {\n if (current.getAttribute('data-cy') === OWN_DATA_CY) {\n current = current.parentElement;\n continue;\n }\n chain.push(current);\n current = current.parentElement;\n }\n\n return chain;\n }\n\n private findBestIndex(): number {\n for (let i = 0; i < this.rows.length; i++) {\n const q = this.rows[i].quality;\n if (q === 'excellent' || q === 'good' || q === 'acceptable') return i;\n }\n return 0;\n }\n\n // ── Rendering ───────────────────────────────────────────────────────────────\n\n private render(): void {\n this.shadow.innerHTML = `<style>${SELECTOR_PICKER_STYLES}</style>${renderPicker(\n this.rows,\n this.selectedIndex,\n this.t.bind(this),\n )}`;\n }\n\n // ── Keyboard ────────────────────────────────────────────────────────────────\n\n private attachKeyListener(): void {\n this.keyHandler = (e: KeyboardEvent) => {\n if (e.key === 'ArrowDown') {\n e.stopPropagation();\n e.preventDefault();\n this.selectedIndex = (this.selectedIndex + 1) % this.ancestors.length;\n this.render();\n this.attachRowClickListeners();\n } else if (e.key === 'ArrowUp') {\n e.stopPropagation();\n e.preventDefault();\n this.selectedIndex = (this.selectedIndex - 1 + this.ancestors.length) % this.ancestors.length;\n this.render();\n this.attachRowClickListeners();\n } else if (e.key === 'Enter') {\n e.stopPropagation();\n this.confirm(this.selectedIndex);\n } else if (e.key === 'Escape') {\n e.stopPropagation();\n this.cancel();\n }\n };\n window.addEventListener('keydown', this.keyHandler, { capture: true });\n }\n\n private detachKeyListener(): void {\n if (this.keyHandler) {\n window.removeEventListener('keydown', this.keyHandler, { capture: true });\n this.keyHandler = null;\n }\n }\n\n // ── Row click listeners ─────────────────────────────────────────────────────\n\n private attachRowClickListeners(): void {\n this.shadow.querySelectorAll('[data-idx]').forEach((row) => {\n (row as HTMLElement).addEventListener('click', () => {\n const idx = parseInt((row as HTMLElement).dataset['idx'] ?? '0', 10);\n this.confirm(idx);\n });\n });\n }\n\n // ── Recording auto-close ────────────────────────────────────────────────────\n\n private subscribeToRecordingChanges(): void {\n this.unsubRecording = this.recording.onRecordingChange((isRecording) => {\n if (!isRecording) this.closeSilently();\n });\n this.unsubPause = this.recording.onPauseChange((isPaused) => {\n if (isPaused) this.closeSilently();\n });\n }\n\n // ── Actions ─────────────────────────────────────────────────────────────────\n\n private confirm(index: number): void {\n const row = this.rows[index];\n if (!row) return;\n const command = `cy.get('${escapeSingleQuotes(row.selector)}').click()`;\n this.recording.appendCommand(command);\n this.dispatchEvent(new CustomEvent('selectorchosen', { detail: command, bubbles: true, composed: true }));\n this.closeSilently();\n }\n\n private cancel(): void {\n this.dispatchEvent(new CustomEvent('pickercancelled', { bubbles: true, composed: true }));\n this.closeSilently();\n }\n\n private closeSilently(): void {\n this.detachKeyListener();\n this.unsubRecording?.();\n this.unsubPause?.();\n this.unsubRecording = null;\n this.unsubPause = null;\n this.remove();\n }\n}\n\nif (!customElements.get('lib-e2e-selector-picker')) {\n customElements.define('lib-e2e-selector-picker', SelectorPickerElement);\n}\n","// Public API for lib-e2e-cypress-for-dummys-ts.\n//\n// This is an EXPLICIT allowlist — everything exported here is part of the\n// semver-stable public contract. Internal singletons, magic-key constants,\n// low-level drag/geometry helpers and test-only utilities are intentionally\n// NOT re-exported (import them from their module path for internal use).\n//\n// Keep VERSION in sync with package.json \"version\" (asserted in\n// specs/public-api.spec.ts).\nexport const VERSION = '1.0.1';\n\n// ── Models (public types & stable constants) ────────────────────────────────\nexport { SUPPORTED_LANGS, isLang, LOCALE_BY_LANG, localeForLang } from './models/lang.model';\nexport type { Lang } from './models/lang.model';\nexport { INPUT_TYPES } from './models/input-types.model';\nexport type { InputType } from './models/input-types.model';\nexport { DB_SCHEMA, DB_STORE_NAMES } from './models/db-schema.model';\nexport type { DBSchema, DBStore, DBStoreIndex } from './models/db-schema.model';\nexport type { ActiveSessionState } from './models/active-session.model';\n// Internal (not exported): ACTIVE_SESSION_BREADCRUMB_KEY, RESUME_TTL_CONFIG_KEY,\n// DEFAULT_RESUME_TTL_MINUTES.\n\n// ── Services ────────────────────────────────────────────────────────────────\nexport { TranslationService } from './services/translation.service';\nexport { TransformationService } from './services/transformation.service';\nexport { AdvancedTestTransformationService } from './services/advanced-test.transformation.service';\nexport type { DirectoryNode, FileNode } from './services/advanced-test.transformation.service';\nexport { RecordingService } from './services/recording.service';\nexport type { SelectorStrategy } from './services/recording.service';\nexport { PersistenceService } from './services/persistence.service';\nexport type { TestWithDetails, TestDetail } from './services/persistence.service';\nexport { HttpMonitor, generateAlias } from './services/http-monitor';\n// Internal (not exported): translationService / transformationService /\n// advancedTestTransformationService singletons, _resetHttpMonitorState.\n\n// ── UI utilities (public) ────────────────────────────────────────────────────\nexport { SCROLLBAR_STYLES, LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, injectStyles } from './utils/styles.utils';\nexport { makeModalResizable, makeSwalDraggable } from './utils/modal.utils';\nexport { showToast } from './utils/toast.utils';\nexport { selectTestsForExport } from './utils/export-selection.utils';\nexport type { ExportMode, ExportSelectionOptions } from './utils/export-selection.utils';\nexport { isLocalHost } from './utils/host.utils';\nexport { inferAssertionCommand } from './utils/assertion.utils';\n// Internal (not exported): makeSwalDraggableByContentId, setSwal2DataCyAttribute,\n// ensurePopupDimensions, and the widget-position geometry helpers.\n\n// ── Web Components (registers the custom elements as an import side effect) ──\nexport { SelectorPickerElement } from './components/selector-picker/selector-picker';\nexport { TestPrevisualizerElement } from './components/test-previsualizer/test-previsualizer';\nexport { SaveTestElement } from './components/save-test/save-test';\nexport { TestEditorElement } from './components/test-editor/test-editor';\nexport { ConfigurationElement } from './components/configuration/configuration';\nexport { AdvancedTestEditorElement } from './components/advanced-test-editor/advanced-test-editor';\nexport { FilePreviewElement } from './components/file-preview/file-preview';\nexport { HelpPanelElement } from './components/help-panel/help-panel';\nexport { LibE2eRecorderElement } from './components/lib-e2e-recorder/lib-e2e-recorder';\n","export type Lang = 'es' | 'en' | 'fr' | 'it' | 'de';\n\nexport const SUPPORTED_LANGS: Lang[] = ['es', 'en', 'fr', 'it', 'de'];\n\nexport function isLang(value: string): value is Lang {\n return SUPPORTED_LANGS.includes(value as Lang);\n}\n\n/** BCP-47 locale used for date/number formatting per UI language. */\nexport const LOCALE_BY_LANG: Record<Lang, string> = {\n es: 'es-ES',\n en: 'en-GB',\n fr: 'fr-FR',\n it: 'it-IT',\n de: 'de-DE',\n};\n\n/** Returns the formatting locale for a UI language (falls back to es-ES). */\nexport function localeForLang(lang: string): string {\n return isLang(lang) ? LOCALE_BY_LANG[lang] : 'es-ES';\n}\n","export const INPUT_TYPES = [\n 'text',\n 'password',\n 'email',\n 'search',\n 'tel',\n 'url',\n 'number',\n 'textarea',\n] as const;\n\nexport type InputType = (typeof INPUT_TYPES)[number];\n","export interface DBStoreIndex {\n name: string;\n keyPath: string;\n unique: boolean;\n}\n\nexport interface DBStore {\n name: string;\n keyPath: string;\n autoIncrement: boolean;\n indexes: DBStoreIndex[];\n}\n\nexport interface DBSchema {\n name: string;\n version: number;\n stores: DBStore[];\n}\n\nexport const DB_SCHEMA: DBSchema = {\n name: 'E2ECypressDB',\n version: 11,\n stores: [\n {\n name: 'tests',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'name', keyPath: 'name', unique: false },\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\n ],\n },\n {\n name: 'commands',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'command', keyPath: 'command', unique: false },\n { name: 'testId', keyPath: 'testId', unique: false },\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\n ],\n },\n {\n name: 'interceptors',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'interceptor', keyPath: 'interceptor', unique: false },\n { name: 'testId', keyPath: 'testId', unique: false },\n { name: 'createdAt', keyPath: 'createdAt', unique: false },\n ],\n },\n {\n name: 'configuration',\n keyPath: 'id',\n autoIncrement: true,\n indexes: [\n { name: 'language', keyPath: 'language', unique: false },\n { name: 'extendedHttpCommands', keyPath: 'extendedHttpCommands', unique: false },\n { name: 'allowReadWriteFiles', keyPath: 'allowReadWriteFiles', unique: false },\n ],\n },\n {\n // Single-record store (fixed key id=1) holding the live, in-progress\n // recording session so it survives a micro-frontend crossing or reload.\n // See docs/specs/006-cross-app-recording-continuity.md.\n name: 'activeSession',\n keyPath: 'id',\n autoIncrement: false,\n indexes: [],\n },\n ],\n};\n\nexport const DB_STORE_NAMES = DB_SCHEMA.stores.map(s => s.name) as [\n 'tests',\n 'commands',\n 'interceptors',\n 'configuration',\n 'activeSession',\n];\n","export class Subject<T> {\n private _value: T;\n private listeners = new Set<(v: T) => void>();\n\n constructor(initialValue: T) {\n this._value = initialValue;\n }\n\n next(value: T): void {\n this._value = value;\n this.listeners.forEach((l) => l(value));\n }\n\n getValue(): T {\n return this._value;\n }\n\n subscribe(fn: (v: T) => void): () => void {\n this.listeners.add(fn);\n return () => this.listeners.delete(fn);\n }\n}\n","export const I18N_ES = {\n MAIN_FRAME: {\n SETTINGS: 'Configuración',\n SHOW_ADVANCED_EDITOR: 'Editor avanzado',\n DIALOG_SAVED_TESTS: 'Pruebas guardadas',\n DIALOG_COMMANDS: 'Previsualizador de comandos Cypress',\n DIALOG_SAVE: '¿Guardar la grabación?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Descripción de la prueba',\n CANCEL: 'Cancelar',\n ASK: '¿Guardar el test grabado?',\n YES_CONTINUE: 'Sí, continuar',\n NO_DISCARD: 'No, descartar',\n DESC_PLACEHOLDER: 'Ej: Login correcto con credenciales válidas',\n TAGS_LABEL: 'Etiquetas (opcional, para filtrar después):',\n TAGS_PLACEHOLDER: 'smoke, login, regresión…',\n ADD_TAG: '+ Añadir',\n NO_TAGS: 'Sin etiquetas',\n SAVE_BTN: '💾 Guardar',\n SAVE_AND_EDIT: '📝 Guardar y editar',\n REMOVE_TAG_TITLE: 'Quitar',\n NOTES_LABEL: 'Descripción / Notas (opcional):',\n NOTES_PLACEHOLDER: 'Qué valida este test, condiciones previas, etc.',\n TICKET_LABEL: 'Ticket / Issue (opcional):',\n TICKET_PLACEHOLDER: 'Ej: PROJ-123, #42',\n TICKET_WARN: 'ID no válido para el proveedor configurado (se guardará igualmente)',\n CONFIRM_DISCARD: '¿Seguro que quieres descartar el test grabado? Se perderán todos los pasos registrados.',\n CONFIRM_DISCARD_BTN: 'Sí, descartar',\n BACK_BTN: 'Volver',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Sin etiquetas',\n SELECTED_SINGULAR: 'seleccionado',\n SELECTED_PLURAL: 'seleccionados',\n DESCRIBE_PLACEHOLDER: 'Nombre del describe (opcional)',\n COPY_DESCRIBE: '🗂 Copiar describe()',\n MULTI_SELECT: '🗂 Multi-select',\n CANCEL_SELECT: '✕ Cancelar',\n COPY_CMDS_BTN: '📋 Copiar comandos',\n COPY_ICPS_BTN: '📋 Copiar interceptores',\n DEFAULT_DESCRIBE: 'Suite de tests',\n NO_TESTS: 'No hay tests guardados',\n DELETE_TITLE: 'Eliminar',\n GROUP_BY_TICKET: '🎫 Agrupar por ticket',\n UNGROUP_TICKET: '🎫 Desagrupar',\n NO_TICKET: 'Sin ticket',\n TICKET_LINK_TITLE: 'Abrir ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Idioma',\n LANG_FIELD: 'Interfaz',\n HTTP_SECTION: '⚡ HTTP Avanzado',\n HTTP_TITLE: 'Validaciones de body',\n HTTP_SUB: 'GET → response · POST/PUT → request',\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\n FIXTURE_TITLE: 'Grabar respuestas como fixtures',\n FIXTURE_SUB: 'Las GET se guardan en cypress/fixtures y se stubean con cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Estrategia de selector',\n SELECTOR_LABEL: 'Atributo preferido para cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (por defecto)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#elemento)',\n SELECTOR_HINT: 'El grabador buscará este atributo primero. Si no existe, intentará los demás.',\n FOLDER_SECTION: '📁 Carpeta Cypress',\n FOLDER_CONNECTED: 'conectado —',\n FOLDER_NOT_SET: 'sin configurar',\n FOLDER_CHANGE_BTN: '📁 Cambiar carpeta',\n FOLDER_SELECT_BTN: '📁 Seleccionar carpeta',\n FOLDER_REVOKE_BTN: '✕ Quitar acceso',\n DATA_SECTION: '💾 Datos',\n DATA_DESC: 'Exporta todos tus tests a JSON o importa una copia de seguridad.',\n EXPORT_BTN: '⬆️ Exportar tests',\n EXPORT_DIALOG_TITLE: '⬆️ Exportar tests',\n EXPORT_MODE_ALL: 'Todo',\n EXPORT_MODE_MANUAL: 'Selección manual',\n EXPORT_MODE_TAGS: 'Por tags',\n EXPORT_ALL_DESC: 'Se exportarán todos los tests guardados.',\n EXPORT_COUNT: 'A exportar:',\n EXPORT_CONFIRM: '⬆️ Exportar',\n EXPORT_CANCEL: 'Cancelar',\n EXPORT_EMPTY: 'No hay tests para exportar.',\n EXPORT_NO_TAGS: 'No hay tags disponibles.',\n EXPORT_TAGS_HINT: 'Selecciona uno o más tags para ver qué pruebas se exportarán.',\n EXPORT_RESULT_LABEL: 'Pruebas que se exportarán:',\n IMPORT_BTN: '⬇️ Importar tests',\n FOLDER_UPDATED_TOAST: '✓ Carpeta de Cypress actualizada',\n FOLDER_ERROR_TOAST: 'Error al acceder a la carpeta',\n IMPORT_SUCCESS: 'Datos importados correctamente.',\n IMPORT_ERROR: 'Error al importar.',\n JSON_INVALID: 'El archivo no es un JSON válido.',\n JSON_BAD_FORMAT: 'El archivo no tiene el formato esperado.',\n SMART_SELECTOR_SECTION: '🔍 Selector inteligente',\n SMART_SELECTOR_TITLE: 'Selector inteligente',\n SMART_SELECTOR_SUB: 'Muestra un picker al hacer click en elementos sin selector válido.',\n START_HIDDEN_SECTION: '👁 Visibilidad del widget',\n START_HIDDEN_TITLE: 'Iniciar oculto',\n START_HIDDEN_SUB: 'El widget arranca invisible. Usa Ctrl+Shift+E para mostrarlo u ocultarlo.',\n RESUME_TTL_SECTION: '⏱ Continuidad de grabación',\n RESUME_TTL_LABEL: 'Reanudar sin preguntar (minutos)',\n RESUME_TTL_HINT: 'Si recargas o cambias de proyecto, una grabación activa se reanuda sin preguntar dentro de este margen. Pasado ese tiempo, te preguntará si continuar o descartar.',\n WIDGET_POSITION_SECTION: '🧲 Posición del widget',\n WIDGET_POSITION_HINT: 'Arrastra el botón de grabar para moverlo donde no estorbe. Se recuerda su posición.',\n WIDGET_POSITION_RESET_BTN: '↺ Restablecer posición',\n WIDGET_POSITION_RESET_DONE: '✓ Posición restablecida',\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\n ISSUE_TRACKER_TITLE: 'Vincular tests a tickets',\n ISSUE_TRACKER_SUB: 'Añade un ID de ticket al guardar y genera un enlace clickable en el listado.',\n ISSUE_TRACKER_PROVIDER: 'Proveedor',\n ISSUE_TRACKER_BASE_URL: 'URL base',\n ISSUE_TRACKER_BASE_URL_PH: 'Ej: https://miproyecto.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'No configurado',\n LOGIN_SETUP_SET_UP_BTN: 'Configurar',\n LOGIN_SETUP_TITLE: 'Configuración de login',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Crear scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Seleccionar fichero existente',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nombre del fichero',\n LOGIN_SETUP_FILE_NAME_PH: 'Ej: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-escanear',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Funciones detectadas',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Asignación de bloques',\n LOGIN_SETUP_NO_FUNCTIONS: 'No se encontraron funciones exportadas. Rellena el scaffold y re-escanea.',\n LOGIN_SETUP_BEFORE_LABEL: 'Función before() (una vez por suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Función beforeEach() (antes de cada test)',\n LOGIN_SETUP_NONE_OPTION: '— Ninguna —',\n LOGIN_SETUP_SUMMARY: 'Fichero: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Guardar',\n LOGIN_SETUP_CLEAR_BTN: 'Eliminar configuración',\n LOGIN_SETUP_CANCEL_BTN: 'Cancelar',\n LOGIN_SETUP_SOURCE_LABEL: 'Origen del fichero de login',\n LOGIN_SETUP_CREATE_SUB: 'Genera un scaffold con funciones de ejemplo',\n LOGIN_SETUP_SELECT_SUB: 'Apunta a un servicio de login existente',\n LOGIN_SETUP_INJECT_TITLE: '¿Añadir bloques de login?',\n LOGIN_SETUP_INJECT_TEXT: 'Este fichero no tiene los bloques de login configurados. ¿Quieres añadir el import y los bloques before/beforeEach ahora?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Sí, añadir',\n },\n SELECTOR_PICKER: {\n TITLE: 'Selecciona un elemento del DOM',\n PREVIEW_LABEL: 'navegar',\n CONFIRM_HINT: 'confirmar',\n CANCEL_HINT: 'cancelar',\n QUALITY_EXCELLENT: 'Excelente — tiene atributo de prueba (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Bueno — tiene un id válido',\n QUALITY_ACCEPTABLE: 'Aceptable — solo tiene clases CSS',\n QUALITY_POOR: 'No recomendado — solo tag o estilo inline',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptores',\n COPY_CMDS_BTN: '📋 Copiar comandos',\n SHOW_INTERCEPTORS: '▼ Ver interceptores',\n HIDE_INTERCEPTORS: '▲ Ocultar interceptores',\n SECTION_COMMANDS: 'Comandos',\n NO_CMDS_YET: 'Sin comandos aún',\n NO_ICP_SHORT: 'Sin interceptores',\n COPY_ICP_BTN: '📋 Copiar interceptores',\n UP_TITLE: 'Subir',\n DOWN_TITLE: 'Bajar',\n DEL_TITLE: 'Eliminar',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Reactivar acceso',\n PERMISSION_EXPIRED: '🔑 El permiso ha caducado',\n PERMISSION_EXPIRED_HINT: 'Haz clic para reactivar el acceso a tu carpeta de Cypress.',\n NO_ACCESS: '🔒 Sin acceso a archivos locales',\n NO_ACCESS_HINT: 'Configura el acceso en ⚙️ Config.',\n NO_FILES: 'Sin archivos',\n SELECT_FILE: '← Selecciona un archivo del árbol',\n IT_LABEL: '🧪 it() a insertar:',\n COPY_IT_BTN: '📋 Copiar it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptores:',\n COPY_ICP_BTN: '📋 Copiar interceptores',\n INSERT_BTN: '💾 Insertar en archivo',\n EDIT_MANUAL_BTN: '✏️ Editar manualmente',\n CLOSE_BTN: '✕ Cerrar',\n NEW_FILE_BTN: '+ Nuevo archivo',\n NEW_FOLDER_BTN: '+ Nueva carpeta',\n REFRESH_BTN: '↻ Actualizar',\n NEW_FILE_PLACEHOLDER: 'nombre-del-test',\n NEW_FOLDER_PLACEHOLDER: 'nombre-de-carpeta',\n NEW_FILE_CONFIRM: 'Crear',\n NEW_FILE_CANCEL: 'Cancelar',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Sin archivo',\n COPY_TITLE: 'Copiar contenido del editor',\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copiar',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: 'Sin cambios respecto al original',\n NO_CHANGES_SHORT: 'Sin cambios',\n LAUNCH_BTN: '▶ Lanzar test',\n LAUNCH_LOCAL_ONLY: 'Muévelo a local para poder probar',\n LAUNCH_RUNNING: '⏳ Ejecutando…',\n LAUNCH_PASSED: '✓ Prueba superada',\n LAUNCH_FAILED: '✗ Prueba fallida',\n LAUNCH_NO_RUNNER: 'No se detectó el runner local (¿lo has arrancado?)',\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Guardar',\n CLOSE_BTN: '✕ Cerrar',\n BACK_TO_EDITOR: '← Volver al editor',\n INSERT_BTN: '🪄 Insertar bloques',\n INSERT_TITLE: 'Insertar it() y beforeEach() en el contenido del editor',\n INSERT_DONE: 'Bloques insertados en el editor',\n INSERT_ERROR: 'No se encontró un bloque describe() válido en el archivo',\n },\n RECORDER: {\n FS_TITLE: '📁 Acceso a ficheros',\n FS_LATER_BTN: 'Ahora no',\n FS_SELECT_BTN: '📁 Seleccionar carpeta',\n FS_SUCCESS_TOAST: '✓ Carpeta de Cypress configurada',\n FS_ERROR_TOAST: 'Error al acceder a la carpeta',\n FS_INTRO_HTML: 'El <strong style=\"color:#e6edf3\">editor avanzado</strong> puede insertar tus tests directamente en los archivos <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\n FS_STRUCTURE_HINT_HTML: 'Selecciona la carpeta que contiene la subcarpeta <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. La extensión espera esta estructura:',\n FS_TREE_PICK_HINT: '← selecciona esta carpeta',\n FS_TREE_READ_HINT: '← la extensión leerá aquí',\n FS_PERMISSION_NOTE: 'El permiso se guarda en el navegador y no se vuelve a solicitar.',\n ASSERTION_SECTION: '➕ Añadir aserción',\n ASSERT_SELECTOR_PH: 'selector, ej: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'valor esperado',\n ASSERT_ADD_BTN: '➕ Añadir',\n FILE_EDITOR_TITLE: '✏️ Editor de archivo',\n FILE_SAVED_TOAST: '✓ Archivo guardado',\n FILE_SAVE_ERROR_TOAST: 'Error al guardar el archivo',\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures escritos en cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'No se pudieron escribir los fixtures (configura la carpeta Cypress)',\n FILE_UPLOAD_MANUAL_TOAST: 'Añade {files} a cypress/fixtures/ antes de ejecutar el test.',\n FILE_UPLOAD_COPIED_TOAST: '{files} copiado/s a cypress/fixtures/.',\n FILE_UPLOAD_COPY_ERROR_TOAST: 'No se pudo copiar {files} a cypress/fixtures/. Añádelo manualmente.',\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Ficheros',\n BTN_COMMANDS: 'Comandos',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pausar (Ctrl+P)',\n RESUME_TITLE: 'Reanudar (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSA',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Detener (Ctrl+R)',\n START_TITLE: 'Grabar (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Grabación en curso',\n SESSION_RESUME_TEXT: 'Hay una grabación activa sin terminar.',\n SESSION_RESUME_COUNT: 'comandos capturados',\n SESSION_CONTINUE_BTN: 'Continuar grabando',\n SESSION_DISCARD_BTN: 'Descartar',\n BTN_HELP: 'Ayuda',\n },\n HELP: {\n TITLE: '❓ Ayuda — Guía rápida',\n INTRO: 'Todo lo que puede hacer el grabador.',\n SEC_RECORDING: '⏺ Grabar',\n RECORDING_1: 'Pulsa ⏺ (o Ctrl+R) para empezar; ⏹ para parar y guardar.',\n RECORDING_2: 'Pausa / reanuda con ⏸ (o Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Atajos de teclado',\n SC_RECORD: 'Ctrl+R — Grabar / detener',\n SC_PAUSE: 'Ctrl+P — Pausar / reanudar',\n SC_TESTS: 'Ctrl+1 — Panel de tests guardados',\n SC_COMMANDS: 'Ctrl+2 — Panel de comandos',\n SC_CONFIG: 'Ctrl+3 — Configuración',\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostrar / ocultar el widget',\n SC_HELP: 'Ctrl+Shift+H — Esta ayuda',\n SEC_CAPTURED: '🎯 Qué se graba',\n CAP_CLICK: 'Click → .click()',\n CAP_DBLCLICK: 'Doble-click → .dblclick()',\n CAP_RIGHTCLICK: 'Click derecho → .rightclick()',\n CAP_TYPE: 'Escribir en un campo → .clear().type(...)',\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Cambio de ruta (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Aserciones',\n ASSERT_1: 'Alt+click sobre un elemento para verificarlo sin ejecutar su acción (texto, valor, checked o visible).',\n ASSERT_2: 'O usa el constructor de aserciones en el panel de Comandos.',\n SEC_PANELS: '🗂 Paneles',\n PANEL_TESTS: '📋 Tests — guardados: filtrar por tag, copiar, combinar, exportar.',\n PANEL_COMMANDS: '⌨️ Comandos — de la grabación actual: reordenar, borrar, añadir aserciones.',\n PANEL_CONFIG: '⚙️ Config — idioma, selector, HTTP, carpeta Cypress, login setup, datos, visibilidad, posición.',\n PANEL_FILES: '📁 Ficheros — inserta tests en tus .cy.ts y lanza el runner.',\n SEC_SELECTOR: '🔎 Selectores',\n SELECTOR_1: 'Elige el atributo preferido (data-cy, data-testid, aria-label, id) en Config.',\n SELECTOR_2: 'Si un click no tiene selector fiable, aparece un picker para elegir el mejor ancestro.',\n SEC_DATA: '💾 Datos',\n DATA_1: 'Exporta tests a JSON (todo / selección / por tags).',\n DATA_2: 'Importa un JSON: se fusiona con lo existente (no se borra nada).',\n SEC_ADVANCED: '🚀 Avanzado',\n ADV_INVISIBLE: 'Modo invisible: start-hidden + Ctrl+Shift+E para grabar en producción sin molestar.',\n ADV_RUNNER: 'Runner local: npx lib-e2e-cypress-runner para lanzar un spec headless desde el editor.',\n ADV_CROSSAPP: 'Cross-app: la grabación sobrevive al cambiar de micro-frontend (mismo origen).',\n ADV_DRAG: 'Arrastra el botón ⏺ para mover el widget; recuerda su posición.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.',\n CLOSE: 'Cerrar',\n TAB_REFERENCE: 'Referencia rápida',\n TAB_GUIDE: 'Guía de uso',\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.',\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","export const I18N_EN = {\n MAIN_FRAME: {\n SETTINGS: 'Settings',\n SHOW_ADVANCED_EDITOR: 'Advanced editor',\n DIALOG_SAVED_TESTS: 'Saved tests',\n DIALOG_COMMANDS: 'Cypress commands previewer',\n DIALOG_SAVE: 'Save recording?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Test description',\n CANCEL: 'Cancel',\n ASK: 'Save the recorded test?',\n YES_CONTINUE: 'Yes, continue',\n NO_DISCARD: 'No, discard',\n DESC_PLACEHOLDER: 'E.g.: Successful login with valid credentials',\n TAGS_LABEL: 'Tags (optional, for later filtering):',\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\n ADD_TAG: '+ Add',\n NO_TAGS: 'No tags',\n SAVE_BTN: '💾 Save',\n SAVE_AND_EDIT: '📝 Save and edit',\n REMOVE_TAG_TITLE: 'Remove',\n NOTES_LABEL: 'Description / Notes (optional):',\n NOTES_PLACEHOLDER: 'What this test validates, preconditions, etc.',\n TICKET_LABEL: 'Ticket / Issue (optional):',\n TICKET_PLACEHOLDER: 'E.g.: PROJ-123, #42',\n TICKET_WARN: 'Invalid ID for the configured provider (will be saved anyway)',\n CONFIRM_DISCARD: 'Are you sure you want to discard this recording? All recorded steps will be lost.',\n CONFIRM_DISCARD_BTN: 'Yes, discard',\n BACK_BTN: 'Go back',\n },\n TEST_EDITOR: {\n NO_TAGS: 'No tags',\n SELECTED_SINGULAR: 'selected',\n SELECTED_PLURAL: 'selected',\n DESCRIBE_PLACEHOLDER: 'describe name (optional)',\n COPY_DESCRIBE: '🗂 Copy describe()',\n MULTI_SELECT: '🗂 Multi-select',\n CANCEL_SELECT: '✕ Cancel',\n COPY_CMDS_BTN: '📋 Copy commands',\n COPY_ICPS_BTN: '📋 Copy interceptors',\n DEFAULT_DESCRIBE: 'Test suite',\n NO_TESTS: 'No saved tests',\n DELETE_TITLE: 'Delete',\n GROUP_BY_TICKET: '🎫 Group by ticket',\n UNGROUP_TICKET: '🎫 Ungroup',\n NO_TICKET: 'No ticket',\n TICKET_LINK_TITLE: 'Open ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Language',\n LANG_FIELD: 'Interface',\n HTTP_SECTION: '⚡ Advanced HTTP',\n HTTP_TITLE: 'Body validations',\n HTTP_SUB: 'GET → response · POST/PUT → request',\n FIXTURE_SECTION: '🧪 HTTP Fixtures',\n FIXTURE_TITLE: 'Record responses as fixtures',\n FIXTURE_SUB: 'GET responses are saved to cypress/fixtures and stubbed via cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Selector strategy',\n SELECTOR_LABEL: 'Preferred attribute for cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (default)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#element)',\n SELECTOR_HINT: 'The recorder will look for this attribute first. If not found, it will try the others.',\n FOLDER_SECTION: '📁 Cypress Folder',\n FOLDER_CONNECTED: 'connected —',\n FOLDER_NOT_SET: 'not configured',\n FOLDER_CHANGE_BTN: '📁 Change folder',\n FOLDER_SELECT_BTN: '📁 Select folder',\n FOLDER_REVOKE_BTN: '✕ Revoke access',\n DATA_SECTION: '💾 Data',\n DATA_DESC: 'Export all your tests to JSON or import a backup.',\n EXPORT_BTN: '⬆️ Export tests',\n EXPORT_DIALOG_TITLE: '⬆️ Export tests',\n EXPORT_MODE_ALL: 'All',\n EXPORT_MODE_MANUAL: 'Manual selection',\n EXPORT_MODE_TAGS: 'By tags',\n EXPORT_ALL_DESC: 'All saved tests will be exported.',\n EXPORT_COUNT: 'To export:',\n EXPORT_CONFIRM: '⬆️ Export',\n EXPORT_CANCEL: 'Cancel',\n EXPORT_EMPTY: 'No tests to export.',\n EXPORT_NO_TAGS: 'No tags available.',\n EXPORT_TAGS_HINT: 'Select one or more tags to preview which tests will be exported.',\n EXPORT_RESULT_LABEL: 'Tests that will be exported:',\n IMPORT_BTN: '⬇️ Import tests',\n FOLDER_UPDATED_TOAST: '✓ Cypress folder updated',\n FOLDER_ERROR_TOAST: 'Error accessing the folder',\n IMPORT_SUCCESS: 'Data imported successfully.',\n IMPORT_ERROR: 'Error importing.',\n JSON_INVALID: 'The file is not valid JSON.',\n JSON_BAD_FORMAT: 'The file does not have the expected format.',\n SMART_SELECTOR_SECTION: '🔍 Smart selector',\n SMART_SELECTOR_TITLE: 'Smart selector',\n SMART_SELECTOR_SUB: 'Shows a picker when clicking elements with no valid selector.',\n START_HIDDEN_SECTION: '👁 Widget visibility',\n START_HIDDEN_TITLE: 'Start hidden',\n START_HIDDEN_SUB: 'The widget starts invisible. Use Ctrl+Shift+E to show or hide it.',\n RESUME_TTL_SECTION: '⏱ Recording continuity',\n RESUME_TTL_LABEL: 'Resume without asking (minutes)',\n RESUME_TTL_HINT: 'If you reload or switch projects, an active recording resumes without asking within this window. After that, you will be asked to continue or discard.',\n WIDGET_POSITION_SECTION: '🧲 Widget position',\n WIDGET_POSITION_HINT: 'Drag the record button to move it out of the way. Its position is remembered.',\n WIDGET_POSITION_RESET_BTN: '↺ Reset position',\n WIDGET_POSITION_RESET_DONE: '✓ Position reset',\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\n ISSUE_TRACKER_TITLE: 'Link tests to tickets',\n ISSUE_TRACKER_SUB: 'Add a ticket ID when saving and generate a clickable link in the test list.',\n ISSUE_TRACKER_PROVIDER: 'Provider',\n ISSUE_TRACKER_BASE_URL: 'Base URL',\n ISSUE_TRACKER_BASE_URL_PH: 'E.g.: https://myproject.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Not configured',\n LOGIN_SETUP_SET_UP_BTN: 'Set up',\n LOGIN_SETUP_TITLE: 'Login setup',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Create scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Select existing file',\n LOGIN_SETUP_FILE_NAME_LABEL: 'File name',\n LOGIN_SETUP_FILE_NAME_PH: 'E.g.: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-scan',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Detected functions',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Block assignment',\n LOGIN_SETUP_NO_FUNCTIONS: 'No exported functions found. Fill in the scaffold and re-scan.',\n LOGIN_SETUP_BEFORE_LABEL: 'before() function (once per suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'beforeEach() function (before every test)',\n LOGIN_SETUP_NONE_OPTION: '— None —',\n LOGIN_SETUP_SUMMARY: 'File: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Save',\n LOGIN_SETUP_CLEAR_BTN: 'Remove configuration',\n LOGIN_SETUP_CANCEL_BTN: 'Cancel',\n LOGIN_SETUP_SOURCE_LABEL: 'Login file source',\n LOGIN_SETUP_CREATE_SUB: 'Generate a scaffold with sample functions',\n LOGIN_SETUP_SELECT_SUB: 'Point to an existing login service file',\n LOGIN_SETUP_INJECT_TITLE: 'Add login blocks?',\n LOGIN_SETUP_INJECT_TEXT: 'This file does not have the configured login blocks. Do you want to add the import and before/beforeEach blocks now?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Yes, add them',\n },\n SELECTOR_PICKER: {\n TITLE: 'Select a DOM element',\n PREVIEW_LABEL: 'navigate',\n CONFIRM_HINT: 'confirm',\n CANCEL_HINT: 'cancel',\n QUALITY_EXCELLENT: 'Excellent — has a testing attribute (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Good — has a valid id',\n QUALITY_ACCEPTABLE: 'Acceptable — CSS classes only',\n QUALITY_POOR: 'Not recommended — tag name or inline style only',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptors',\n COPY_CMDS_BTN: '📋 Copy commands',\n SHOW_INTERCEPTORS: '▼ Show interceptors',\n HIDE_INTERCEPTORS: '▲ Hide interceptors',\n SECTION_COMMANDS: 'Commands',\n NO_CMDS_YET: 'No commands yet',\n NO_ICP_SHORT: 'No interceptors',\n COPY_ICP_BTN: '📋 Copy interceptors',\n UP_TITLE: 'Move up',\n DOWN_TITLE: 'Move down',\n DEL_TITLE: 'Delete',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Reactivate access',\n PERMISSION_EXPIRED: '🔑 Permission expired',\n PERMISSION_EXPIRED_HINT: 'Click to reactivate access to your Cypress folder.',\n NO_ACCESS: '🔒 No access to local files',\n NO_ACCESS_HINT: 'Configure access in ⚙️ Config.',\n NO_FILES: 'No files',\n SELECT_FILE: '← Select a file from the tree',\n IT_LABEL: '🧪 it() to insert:',\n COPY_IT_BTN: '📋 Copy it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptors:',\n COPY_ICP_BTN: '📋 Copy interceptors',\n INSERT_BTN: '💾 Insert into file',\n EDIT_MANUAL_BTN: '✏️ Edit manually',\n CLOSE_BTN: '✕ Close',\n NEW_FILE_BTN: '+ New file',\n NEW_FOLDER_BTN: '+ New folder',\n REFRESH_BTN: '↻ Refresh',\n NEW_FILE_PLACEHOLDER: 'test-name',\n NEW_FOLDER_PLACEHOLDER: 'folder-name',\n NEW_FILE_CONFIRM: 'Create',\n NEW_FILE_CANCEL: 'Cancel',\n },\n FILE_PREVIEW: {\n NO_FILE: 'No file',\n COPY_TITLE: 'Copy editor content',\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copy',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: 'No changes from original',\n NO_CHANGES_SHORT: 'No changes',\n LAUNCH_BTN: '▶ Run test',\n LAUNCH_LOCAL_ONLY: 'Move it to localhost to run tests',\n LAUNCH_RUNNING: '⏳ Running…',\n LAUNCH_PASSED: '✓ Test passed',\n LAUNCH_FAILED: '✗ Test failed',\n LAUNCH_NO_RUNNER: 'No local runner detected (did you start it?)',\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Save',\n CLOSE_BTN: '✕ Close',\n BACK_TO_EDITOR: '← Back to editor',\n INSERT_BTN: '🪄 Insert blocks',\n INSERT_TITLE: 'Insert it() and beforeEach() into the editor content',\n INSERT_DONE: 'Blocks inserted into the editor',\n INSERT_ERROR: 'No valid describe() block found in the file',\n },\n RECORDER: {\n FS_TITLE: '📁 File access',\n FS_LATER_BTN: 'Not now',\n FS_SELECT_BTN: '📁 Select folder',\n FS_SUCCESS_TOAST: '✓ Cypress folder configured',\n FS_ERROR_TOAST: 'Error accessing the folder',\n FS_INTRO_HTML: 'The <strong style=\"color:#e6edf3\">advanced editor</strong> can insert your tests directly into the Cypress <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> files.',\n FS_STRUCTURE_HINT_HTML: 'Select the folder that contains the <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> subfolder. The extension expects this structure:',\n FS_TREE_PICK_HINT: '← select this folder',\n FS_TREE_READ_HINT: '← the extension will read here',\n FS_PERMISSION_NOTE: 'The permission is stored in the browser and will not be requested again.',\n ASSERTION_SECTION: '➕ Add assertion',\n ASSERT_SELECTOR_PH: 'selector, e.g.: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'expected value',\n ASSERT_ADD_BTN: '➕ Add',\n FILE_EDITOR_TITLE: '✏️ File editor',\n FILE_SAVED_TOAST: '✓ File saved',\n FILE_SAVE_ERROR_TOAST: 'Error saving the file',\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures written to cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'Could not write fixtures (configure the Cypress folder)',\n FILE_UPLOAD_MANUAL_TOAST: 'Add {files} to cypress/fixtures/ before running the test.',\n FILE_UPLOAD_COPIED_TOAST: '{files} copied to cypress/fixtures/.',\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Could not copy {files} to cypress/fixtures/. Add it manually.',\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Files',\n BTN_COMMANDS: 'Commands',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pause (Ctrl+P)',\n RESUME_TITLE: 'Resume (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSED',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Stop (Ctrl+R)',\n START_TITLE: 'Record (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Recording in progress',\n SESSION_RESUME_TEXT: 'There is an unfinished active recording.',\n SESSION_RESUME_COUNT: 'commands captured',\n SESSION_CONTINUE_BTN: 'Keep recording',\n SESSION_DISCARD_BTN: 'Discard',\n BTN_HELP: 'Help',\n },\n HELP: {\n TITLE: '❓ Help — Quick guide',\n INTRO: 'Everything the recorder can do.',\n SEC_RECORDING: '⏺ Recording',\n RECORDING_1: 'Press ⏺ (or Ctrl+R) to start; ⏹ to stop and save.',\n RECORDING_2: 'Pause / resume with ⏸ (or Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Keyboard shortcuts',\n SC_RECORD: 'Ctrl+R — Record / stop',\n SC_PAUSE: 'Ctrl+P — Pause / resume',\n SC_TESTS: 'Ctrl+1 — Saved tests panel',\n SC_COMMANDS: 'Ctrl+2 — Commands panel',\n SC_CONFIG: 'Ctrl+3 — Settings',\n SC_VISIBILITY: 'Ctrl+Shift+E — Show / hide the widget',\n SC_HELP: 'Ctrl+Shift+H — This help',\n SEC_CAPTURED: '🎯 What gets recorded',\n CAP_CLICK: 'Click → .click()',\n CAP_DBLCLICK: 'Double-click → .dblclick()',\n CAP_RIGHTCLICK: 'Right-click → .rightclick()',\n CAP_TYPE: 'Type into a field → .clear().type(...)',\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Route change (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Assertions',\n ASSERT_1: 'Alt+click an element to verify it without running its action (text, value, checked or visible).',\n ASSERT_2: 'Or use the assertion builder in the Commands panel.',\n SEC_PANELS: '🗂 Panels',\n PANEL_TESTS: '📋 Tests — saved tests: filter by tag, copy, combine, export.',\n PANEL_COMMANDS: '⌨️ Commands — current recording: reorder, delete, add assertions.',\n PANEL_CONFIG: '⚙️ Config — language, selector, HTTP, Cypress folder, login setup, data, visibility, position.',\n PANEL_FILES: '📁 Files — insert tests into your .cy.ts and launch the runner.',\n SEC_SELECTOR: '🔎 Selectors',\n SELECTOR_1: 'Choose the preferred attribute (data-cy, data-testid, aria-label, id) in Config.',\n SELECTOR_2: 'If a click has no reliable selector, a picker appears to choose the best ancestor.',\n SEC_DATA: '💾 Data',\n DATA_1: 'Export tests to JSON (all / selection / by tags).',\n DATA_2: 'Import a JSON: it merges into your data (nothing is wiped).',\n SEC_ADVANCED: '🚀 Advanced',\n ADV_INVISIBLE: 'Invisible mode: start-hidden + Ctrl+Shift+E to record in production unobtrusively.',\n ADV_RUNNER: 'Local runner: npx lib-e2e-cypress-runner to run a spec headless from the editor.',\n ADV_CROSSAPP: 'Cross-app: the recording survives switching micro-frontend (same origin).',\n ADV_DRAG: 'Drag the ⏺ button to move the widget; its position is remembered.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): point to your login service; the recorder automatically injects before()/beforeEach() blocks into each new test.',\n CLOSE: 'Close',\n TAB_REFERENCE: 'Quick reference',\n TAB_GUIDE: 'Usage guide',\n GUIDE_INTRO: 'How to get the most out of the recorder, and what it does / doesn\\'t cover.',\n G_SEC_WORKFLOW: '🧭 Workflow',\n G_WF_1: '1. Press ⏺ (or Ctrl+R) to start recording.',\n G_WF_2: '2. Use your app like a user: clicks, forms, navigation. Each action becomes a Cypress command.',\n G_WF_3: '3. Add checks with Alt+click on whatever you want to verify.',\n G_WF_4: '4. Press ⏹ to stop; give it a name and tags, and save it.',\n G_WF_5: '5. In 📁 Files, insert the test into a .cy.ts or run it with the local runner.',\n G_SEC_COVERED: '✅ What it covers',\n G_COV_1: 'Clicks, double-click, right-click, text inputs, checkbox/radio, select and Enter/Escape keys.',\n G_COV_2: 'SPA navigation (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'fetch/XHR calls (GET/POST/PUT) → cy.intercept + cy.wait, with optional body validation.',\n G_COV_4: 'Reliable selector (data-cy/testid/aria/id) and a picker when none is obvious.',\n G_COV_5: 'Automatic assertions (Alt+click) and the manual builder.',\n G_COV_6: 'Continuity when switching micro-frontend (same origin), invisible mode and i18n.',\n G_COV_7: 'Login Setup: configure your login function under Ctrl+3 → Login Setup; the recorder adds before()/beforeEach() blocks to every new test.',\n G_SEC_NOTCOVERED: '🚫 What it does NOT cover (yet)',\n G_NC_1: 'Different origins / subdomains (same origin only).',\n G_NC_2: 'File upload (selectFile), drag & drop, and hover.',\n G_NC_3: 'The Tab key (Cypress can\\'t .type() it).',\n G_NC_4: 'DELETE requests (intentionally ignored).',\n G_NC_5: 'Third-party iframes and Shadow DOM may not be captured.',\n },\n};\n","export const I18N_FR = {\n MAIN_FRAME: {\n SETTINGS: 'Paramètres',\n SHOW_ADVANCED_EDITOR: 'Éditeur avancé',\n DIALOG_SAVED_TESTS: 'Tests enregistrés',\n DIALOG_COMMANDS: 'Aperçu des commandes Cypress',\n DIALOG_SAVE: \"Enregistrer l'enregistrement ?\",\n },\n SAVE_TEST: {\n DESC_LABEL: 'Description du test',\n CANCEL: 'Annuler',\n ASK: 'Enregistrer le test ?',\n YES_CONTINUE: 'Oui, continuer',\n NO_DISCARD: 'Non, ignorer',\n DESC_PLACEHOLDER: 'Ex : Connexion réussie avec identifiants valides',\n TAGS_LABEL: 'Étiquettes (optionnel, pour filtrer ensuite) :',\n TAGS_PLACEHOLDER: 'smoke, login, régression…',\n ADD_TAG: '+ Ajouter',\n NO_TAGS: 'Sans étiquettes',\n SAVE_BTN: '💾 Enregistrer',\n SAVE_AND_EDIT: '📝 Enregistrer et éditer',\n REMOVE_TAG_TITLE: 'Retirer',\n NOTES_LABEL: 'Description / Notes (optionnel) :',\n NOTES_PLACEHOLDER: 'Ce que ce test valide, conditions préalables, etc.',\n TICKET_LABEL: 'Ticket / Issue (optionnel) :',\n TICKET_PLACEHOLDER: 'Ex : PROJ-123, #42',\n TICKET_WARN: 'ID non valide pour le fournisseur configuré (sera enregistré quand même)', // TODO: translate\n CONFIRM_DISCARD: 'Êtes-vous sûr de vouloir abandonner cet enregistrement ? Toutes les étapes enregistrées seront perdues.',\n CONFIRM_DISCARD_BTN: 'Oui, abandonner',\n BACK_BTN: 'Retour',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Sans étiquettes',\n SELECTED_SINGULAR: 'sélectionné',\n SELECTED_PLURAL: 'sélectionnés',\n DESCRIBE_PLACEHOLDER: 'Nom du describe (optionnel)',\n COPY_DESCRIBE: '🗂 Copier describe()',\n MULTI_SELECT: '🗂 Multi-sélection',\n CANCEL_SELECT: '✕ Annuler',\n COPY_CMDS_BTN: '📋 Copier les commandes',\n COPY_ICPS_BTN: '📋 Copier les intercepteurs',\n DEFAULT_DESCRIBE: 'Suite de tests',\n NO_TESTS: 'Aucun test enregistré',\n DELETE_TITLE: 'Supprimer',\n GROUP_BY_TICKET: '🎫 Grouper par ticket',\n UNGROUP_TICKET: '🎫 Dégrouper',\n NO_TICKET: 'Sans ticket',\n TICKET_LINK_TITLE: 'Ouvrir le ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Langue',\n LANG_FIELD: 'Interface',\n HTTP_SECTION: '⚡ HTTP Avancé',\n HTTP_TITLE: 'Validations du corps',\n HTTP_SUB: 'GET → réponse · POST/PUT → requête',\n FIXTURE_SECTION: '🧪 Fixtures HTTP',\n FIXTURE_TITLE: 'Enregistrer les réponses comme fixtures',\n FIXTURE_SUB: 'Les GET sont enregistrées dans cypress/fixtures et stubées via cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Stratégie de sélecteur',\n SELECTOR_LABEL: 'Attribut préféré pour cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (par défaut)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#élément)',\n SELECTOR_HINT: \"L'enregistreur cherchera d'abord cet attribut. Si absent, il essaiera les autres.\",\n FOLDER_SECTION: '📁 Dossier Cypress',\n FOLDER_CONNECTED: 'connecté —',\n FOLDER_NOT_SET: 'non configuré',\n FOLDER_CHANGE_BTN: '📁 Changer de dossier',\n FOLDER_SELECT_BTN: '📁 Sélectionner un dossier',\n FOLDER_REVOKE_BTN: \"✕ Révoquer l'accès\",\n DATA_SECTION: '💾 Données',\n DATA_DESC: 'Exportez tous vos tests en JSON ou importez une sauvegarde.',\n EXPORT_BTN: '⬆️ Exporter les tests',\n EXPORT_DIALOG_TITLE: '⬆️ Exporter les tests',\n EXPORT_MODE_ALL: 'Tout',\n EXPORT_MODE_MANUAL: 'Sélection manuelle',\n EXPORT_MODE_TAGS: 'Par tags',\n EXPORT_ALL_DESC: 'Tous les tests enregistrés seront exportés.',\n EXPORT_COUNT: 'À exporter :',\n EXPORT_CONFIRM: '⬆️ Exporter',\n EXPORT_CANCEL: 'Annuler',\n EXPORT_EMPTY: 'Aucun test à exporter.',\n EXPORT_NO_TAGS: 'Aucun tag disponible.',\n EXPORT_TAGS_HINT: 'Sélectionnez un ou plusieurs tags pour voir les tests qui seront exportés.',\n EXPORT_RESULT_LABEL: 'Tests qui seront exportés :',\n IMPORT_BTN: '⬇️ Importer les tests',\n FOLDER_UPDATED_TOAST: '✓ Dossier Cypress mis à jour',\n FOLDER_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\n IMPORT_SUCCESS: 'Données importées avec succès.',\n IMPORT_ERROR: \"Erreur lors de l'importation.\",\n JSON_INVALID: \"Le fichier n'est pas un JSON valide.\",\n JSON_BAD_FORMAT: \"Le fichier n'a pas le format attendu.\",\n SMART_SELECTOR_SECTION: '🔍 Sélecteur intelligent',\n SMART_SELECTOR_TITLE: 'Sélecteur intelligent',\n SMART_SELECTOR_SUB: 'Affiche un sélecteur lors du clic sur des éléments sans sélecteur valide.',\n START_HIDDEN_SECTION: '👁 Visibilité du widget',\n START_HIDDEN_TITLE: 'Démarrer masqué',\n START_HIDDEN_SUB: 'Le widget démarre invisible. Utilisez Ctrl+Shift+E pour l\\'afficher ou le masquer.',\n RESUME_TTL_SECTION: '⏱ Continuité d\\'enregistrement',\n RESUME_TTL_LABEL: 'Reprendre sans demander (minutes)',\n RESUME_TTL_HINT: 'Si vous rechargez ou changez de projet, un enregistrement actif reprend sans demander dans ce délai. Au-delà, il vous demandera de continuer ou d\\'ignorer.',\n WIDGET_POSITION_SECTION: '🧲 Position du widget',\n WIDGET_POSITION_HINT: 'Fais glisser le bouton d\\'enregistrement pour le déplacer. Sa position est mémorisée.',\n WIDGET_POSITION_RESET_BTN: '↺ Réinitialiser la position',\n WIDGET_POSITION_RESET_DONE: '✓ Position réinitialisée',\n ISSUE_TRACKER_SECTION: '🎫 Gestionnaire de tickets',\n ISSUE_TRACKER_TITLE: 'Lier les tests aux tickets',\n ISSUE_TRACKER_SUB: \"Ajoutez un ID de ticket lors de l'enregistrement et générez un lien cliquable.\",\n ISSUE_TRACKER_PROVIDER: 'Fournisseur',\n ISSUE_TRACKER_BASE_URL: 'URL de base',\n ISSUE_TRACKER_BASE_URL_PH: 'Ex : https://monprojet.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Non configuré',\n LOGIN_SETUP_SET_UP_BTN: 'Configurer',\n LOGIN_SETUP_TITLE: 'Configuration du login',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Créer un scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Sélectionner un fichier existant',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nom du fichier',\n LOGIN_SETUP_FILE_NAME_PH: 'Ex : cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-scanner',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Fonctions détectées',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Affectation des blocs',\n LOGIN_SETUP_NO_FUNCTIONS: 'Aucune fonction exportée trouvée. Remplissez le scaffold et re-scannez.',\n LOGIN_SETUP_BEFORE_LABEL: 'Fonction before() (une fois par suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Fonction beforeEach() (avant chaque test)',\n LOGIN_SETUP_NONE_OPTION: '— Aucune —',\n LOGIN_SETUP_SUMMARY: 'Fichier : {file} · before : {before} · beforeEach : {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Enregistrer',\n LOGIN_SETUP_CLEAR_BTN: 'Supprimer la configuration',\n LOGIN_SETUP_CANCEL_BTN: 'Annuler',\n LOGIN_SETUP_SOURCE_LABEL: 'Source du fichier de login',\n LOGIN_SETUP_CREATE_SUB: 'Générer un scaffold avec des fonctions exemples',\n LOGIN_SETUP_SELECT_SUB: 'Pointer vers un fichier de service de login existant',\n LOGIN_SETUP_INJECT_TITLE: 'Ajouter les blocs de login ?',\n LOGIN_SETUP_INJECT_TEXT: 'Ce fichier ne contient pas les blocs de login configurés. Voulez-vous ajouter l\\'import et les blocs before/beforeEach maintenant ?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Oui, ajouter',\n },\n SELECTOR_PICKER: {\n TITLE: 'Sélectionnez un élément du DOM',\n PREVIEW_LABEL: 'naviguer',\n CONFIRM_HINT: 'confirmer',\n CANCEL_HINT: 'annuler',\n QUALITY_EXCELLENT: 'Excellent — attribut de test présent (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Bon — id valide',\n QUALITY_ACCEPTABLE: 'Acceptable — classes CSS uniquement',\n QUALITY_POOR: 'Déconseillé — seulement le nom de balise ou style inline',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Intercepteurs',\n COPY_CMDS_BTN: '📋 Copier les commandes',\n SHOW_INTERCEPTORS: '▼ Voir les intercepteurs',\n HIDE_INTERCEPTORS: '▲ Masquer les intercepteurs',\n SECTION_COMMANDS: 'Commandes',\n NO_CMDS_YET: 'Aucune commande encore',\n NO_ICP_SHORT: 'Aucun intercepteur',\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\n UP_TITLE: 'Monter',\n DOWN_TITLE: 'Descendre',\n DEL_TITLE: 'Supprimer',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: \"🔓 Réactiver l'accès\",\n PERMISSION_EXPIRED: '🔑 Autorisation expirée',\n PERMISSION_EXPIRED_HINT: \"Cliquez pour réactiver l'accès à votre dossier Cypress.\",\n NO_ACCESS: '🔒 Pas d\\'accès aux fichiers locaux',\n NO_ACCESS_HINT: \"Configurez l'accès dans ⚙️ Config.\",\n NO_FILES: 'Aucun fichier',\n SELECT_FILE: \"← Sélectionnez un fichier dans l'arborescence\",\n IT_LABEL: '🧪 it() à insérer :',\n COPY_IT_BTN: '📋 Copier it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() intercepteurs :',\n COPY_ICP_BTN: '📋 Copier les intercepteurs',\n INSERT_BTN: '💾 Insérer dans le fichier',\n EDIT_MANUAL_BTN: '✏️ Éditer manuellement',\n CLOSE_BTN: '✕ Fermer',\n NEW_FILE_BTN: '+ Nouveau fichier',\n NEW_FOLDER_BTN: '+ Nouveau dossier',\n REFRESH_BTN: '↻ Actualiser',\n NEW_FILE_PLACEHOLDER: 'nom-du-test',\n NEW_FOLDER_PLACEHOLDER: 'nom-du-dossier',\n NEW_FILE_CONFIRM: 'Créer',\n NEW_FILE_CANCEL: 'Annuler',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Sans fichier',\n COPY_TITLE: \"Copier le contenu de l'éditeur\",\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copier',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: \"Aucun changement par rapport à l'original\",\n NO_CHANGES_SHORT: 'Aucun changement',\n LAUNCH_BTN: '▶ Lancer le test',\n LAUNCH_LOCAL_ONLY: 'Passe en local pour pouvoir tester',\n LAUNCH_RUNNING: '⏳ Exécution…',\n LAUNCH_PASSED: '✓ Test réussi',\n LAUNCH_FAILED: '✗ Test échoué',\n LAUNCH_NO_RUNNER: \"Aucun runner local détecté (l'avez-vous démarré ?)\",\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Enregistrer',\n CLOSE_BTN: '✕ Fermer',\n BACK_TO_EDITOR: \"← Retour à l'éditeur\",\n INSERT_BTN: '🪄 Insérer les blocs',\n INSERT_TITLE: \"Insérer it() et beforeEach() dans le contenu de l'éditeur\",\n INSERT_DONE: \"Blocs insérés dans l'éditeur\",\n INSERT_ERROR: 'Aucun bloc describe() valide trouvé dans le fichier',\n },\n RECORDER: {\n FS_TITLE: '📁 Accès aux fichiers',\n FS_LATER_BTN: 'Pas maintenant',\n FS_SELECT_BTN: '📁 Sélectionner un dossier',\n FS_SUCCESS_TOAST: '✓ Dossier Cypress configuré',\n FS_ERROR_TOAST: \"Erreur lors de l'accès au dossier\",\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">éditeur avancé</strong> peut insérer vos tests directement dans les fichiers <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> de Cypress.',\n FS_STRUCTURE_HINT_HTML: 'Sélectionnez le dossier qui contient le sous-dossier <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'extension attend cette structure :',\n FS_TREE_PICK_HINT: '← sélectionnez ce dossier',\n FS_TREE_READ_HINT: '← l\\'extension lira ici',\n FS_PERMISSION_NOTE: 'L\\'autorisation est enregistrée dans le navigateur et ne sera plus demandée.',\n ASSERTION_SECTION: '➕ Ajouter une assertion',\n ASSERT_SELECTOR_PH: 'sélecteur, ex : [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'valeur attendue',\n ASSERT_ADD_BTN: '➕ Ajouter',\n FILE_EDITOR_TITLE: '✏️ Éditeur de fichier',\n FILE_SAVED_TOAST: '✓ Fichier enregistré',\n FILE_SAVE_ERROR_TOAST: \"Erreur lors de l'enregistrement\",\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures écrites dans cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'Impossible d\\'écrire les fixtures (configure le dossier Cypress)',\n FILE_UPLOAD_MANUAL_TOAST: 'Ajoutez {files} à cypress/fixtures/ avant d\\'exécuter le test.', // TODO: translate\n FILE_UPLOAD_COPIED_TOAST: '{files} copié(s) dans cypress/fixtures/.', // TODO: translate\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Impossible de copier {files} vers cypress/fixtures/. Ajoutez-le manuellement.', // TODO: translate\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Fichiers',\n BTN_COMMANDS: 'Commandes',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pause (Ctrl+P)',\n RESUME_TITLE: 'Reprendre (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSE',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Arrêter (Ctrl+R)',\n START_TITLE: 'Enregistrer (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Enregistrement en cours',\n SESSION_RESUME_TEXT: 'Un enregistrement actif est inachevé.',\n SESSION_RESUME_COUNT: 'commandes capturées',\n SESSION_CONTINUE_BTN: 'Continuer l\\'enregistrement',\n SESSION_DISCARD_BTN: 'Ignorer',\n BTN_HELP: 'Aide',\n },\n HELP: {\n TITLE: '❓ Aide — Guide rapide',\n INTRO: 'Tout ce que l\\'enregistreur sait faire.',\n SEC_RECORDING: '⏺ Enregistrer',\n RECORDING_1: 'Appuie sur ⏺ (ou Ctrl+R) pour commencer ; ⏹ pour arrêter et enregistrer.',\n RECORDING_2: 'Pause / reprise avec ⏸ (ou Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Raccourcis clavier',\n SC_RECORD: 'Ctrl+R — Enregistrer / arrêter',\n SC_PAUSE: 'Ctrl+P — Pause / reprise',\n SC_TESTS: 'Ctrl+1 — Panneau des tests enregistrés',\n SC_COMMANDS: 'Ctrl+2 — Panneau des commandes',\n SC_CONFIG: 'Ctrl+3 — Paramètres',\n SC_VISIBILITY: 'Ctrl+Shift+E — Afficher / masquer le widget',\n SC_HELP: 'Ctrl+Shift+H — Cette aide',\n SEC_CAPTURED: '🎯 Ce qui est enregistré',\n CAP_CLICK: 'Clic → .click()',\n CAP_DBLCLICK: 'Double-clic → .dblclick()',\n CAP_RIGHTCLICK: 'Clic droit → .rightclick()',\n CAP_TYPE: 'Saisie dans un champ → .clear().type(...)',\n CAP_CHECK: 'Case à cocher / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Entrée / Échap → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Changement de route (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Assertions',\n ASSERT_1: 'Alt+clic sur un élément pour le vérifier sans exécuter son action (texte, valeur, coché ou visible).',\n ASSERT_2: 'Ou utilise le constructeur d\\'assertions dans le panneau Commandes.',\n SEC_PANELS: '🗂 Panneaux',\n PANEL_TESTS: '📋 Tests — enregistrés : filtrer par tag, copier, combiner, exporter.',\n PANEL_COMMANDS: '⌨️ Commandes — enregistrement en cours : réordonner, supprimer, ajouter des assertions.',\n PANEL_CONFIG: '⚙️ Config — langue, sélecteur, HTTP, dossier Cypress, login setup, données, visibilité, position.',\n PANEL_FILES: '📁 Fichiers — insère des tests dans tes .cy.ts et lance le runner.',\n SEC_SELECTOR: '🔎 Sélecteurs',\n SELECTOR_1: 'Choisis l\\'attribut préféré (data-cy, data-testid, aria-label, id) dans Config.',\n SELECTOR_2: 'Si un clic n\\'a pas de sélecteur fiable, un sélecteur apparaît pour choisir le meilleur ancêtre.',\n SEC_DATA: '💾 Données',\n DATA_1: 'Exporte les tests en JSON (tout / sélection / par tags).',\n DATA_2: 'Importe un JSON : il fusionne avec tes données (rien n\\'est effacé).',\n SEC_ADVANCED: '🚀 Avancé',\n ADV_INVISIBLE: 'Mode invisible : start-hidden + Ctrl+Shift+E pour enregistrer en production discrètement.',\n ADV_RUNNER: 'Runner local : npx lib-e2e-cypress-runner pour lancer un spec headless depuis l\\'éditeur.',\n ADV_CROSSAPP: 'Cross-app : l\\'enregistrement survit au changement de micro-frontend (même origine).',\n ADV_DRAG: 'Fais glisser le bouton ⏺ pour déplacer le widget ; sa position est mémorisée.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (fr)\n CLOSE: 'Fermer',\n TAB_REFERENCE: 'Référence rapide',\n TAB_GUIDE: 'Guide d\\'utilisation',\n // TODO: translate (fr) — usage guide body kept in Spanish for now.\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (fr)\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","export const I18N_IT = {\n MAIN_FRAME: {\n SETTINGS: 'Impostazioni',\n SHOW_ADVANCED_EDITOR: 'Editor avanzato',\n DIALOG_SAVED_TESTS: 'Test salvati',\n DIALOG_COMMANDS: 'Anteprima comandi Cypress',\n DIALOG_SAVE: 'Salvare la registrazione?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Descrizione del test',\n CANCEL: 'Annulla',\n ASK: 'Salvare il test registrato?',\n YES_CONTINUE: 'Sì, continua',\n NO_DISCARD: 'No, annulla',\n DESC_PLACEHOLDER: 'Es: Login riuscito con credenziali valide',\n TAGS_LABEL: 'Etichette (opzionale, per filtrare dopo):',\n TAGS_PLACEHOLDER: 'smoke, login, regressione…',\n ADD_TAG: '+ Aggiungi',\n NO_TAGS: 'Nessuna etichetta',\n SAVE_BTN: '💾 Salva',\n SAVE_AND_EDIT: '📝 Salva e modifica',\n REMOVE_TAG_TITLE: 'Rimuovi',\n NOTES_LABEL: 'Descrizione / Note (opzionale):',\n NOTES_PLACEHOLDER: 'Cosa valida questo test, condizioni preliminari, ecc.',\n TICKET_LABEL: 'Ticket / Issue (opzionale):',\n TICKET_PLACEHOLDER: 'Es: PROJ-123, #42',\n TICKET_WARN: 'ID non valido per il provider configurato (verrà salvato comunque)', // TODO: translate\n CONFIRM_DISCARD: 'Sei sicuro di voler scartare questa registrazione? Tutti i passi registrati andranno persi.',\n CONFIRM_DISCARD_BTN: 'Sì, scarta',\n BACK_BTN: 'Indietro',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Nessuna etichetta',\n SELECTED_SINGULAR: 'selezionato',\n SELECTED_PLURAL: 'selezionati',\n DESCRIBE_PLACEHOLDER: 'Nome del describe (opzionale)',\n COPY_DESCRIBE: '🗂 Copia describe()',\n MULTI_SELECT: '🗂 Multi-selezione',\n CANCEL_SELECT: '✕ Annulla',\n COPY_CMDS_BTN: '📋 Copia comandi',\n COPY_ICPS_BTN: '📋 Copia interceptor',\n DEFAULT_DESCRIBE: 'Suite di test',\n NO_TESTS: 'Nessun test salvato',\n DELETE_TITLE: 'Elimina',\n GROUP_BY_TICKET: '🎫 Raggruppa per ticket',\n UNGROUP_TICKET: '🎫 Separa',\n NO_TICKET: 'Senza ticket',\n TICKET_LINK_TITLE: 'Apri ticket',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Lingua',\n LANG_FIELD: 'Interfaccia',\n HTTP_SECTION: '⚡ HTTP Avanzato',\n HTTP_TITLE: 'Validazioni del body',\n HTTP_SUB: 'GET → risposta · POST/PUT → richiesta',\n FIXTURE_SECTION: '🧪 Fixture HTTP',\n FIXTURE_TITLE: 'Registra le risposte come fixture',\n FIXTURE_SUB: 'Le GET vengono salvate in cypress/fixtures e stubbate con cy.intercept({ fixture }).',\n SELECTOR_SECTION: '🎯 Strategia selettore',\n SELECTOR_LABEL: 'Attributo preferito per cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (predefinito)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#elemento)',\n SELECTOR_HINT: 'Il registratore cercherà prima questo attributo. Se assente, proverà gli altri.',\n FOLDER_SECTION: '📁 Cartella Cypress',\n FOLDER_CONNECTED: 'connesso —',\n FOLDER_NOT_SET: 'non configurato',\n FOLDER_CHANGE_BTN: '📁 Cambia cartella',\n FOLDER_SELECT_BTN: '📁 Seleziona cartella',\n FOLDER_REVOKE_BTN: '✕ Revoca accesso',\n DATA_SECTION: '💾 Dati',\n DATA_DESC: 'Esporta tutti i tuoi test in JSON o importa un backup.',\n EXPORT_BTN: '⬆️ Esporta test',\n EXPORT_DIALOG_TITLE: '⬆️ Esporta test',\n EXPORT_MODE_ALL: 'Tutto',\n EXPORT_MODE_MANUAL: 'Selezione manuale',\n EXPORT_MODE_TAGS: 'Per tag',\n EXPORT_ALL_DESC: 'Verranno esportati tutti i test salvati.',\n EXPORT_COUNT: 'Da esportare:',\n EXPORT_CONFIRM: '⬆️ Esporta',\n EXPORT_CANCEL: 'Annulla',\n EXPORT_EMPTY: 'Nessun test da esportare.',\n EXPORT_NO_TAGS: 'Nessun tag disponibile.',\n EXPORT_TAGS_HINT: 'Seleziona uno o più tag per vedere quali test verranno esportati.',\n EXPORT_RESULT_LABEL: 'Test che verranno esportati:',\n IMPORT_BTN: '⬇️ Importa test',\n FOLDER_UPDATED_TOAST: '✓ Cartella Cypress aggiornata',\n FOLDER_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\n IMPORT_SUCCESS: 'Dati importati correttamente.',\n IMPORT_ERROR: \"Errore durante l'importazione.\",\n JSON_INVALID: 'Il file non è un JSON valido.',\n JSON_BAD_FORMAT: 'Il file non ha il formato previsto.',\n SMART_SELECTOR_SECTION: '🔍 Selettore intelligente',\n SMART_SELECTOR_TITLE: 'Selettore intelligente',\n SMART_SELECTOR_SUB: 'Mostra un selettore quando si fa clic su elementi senza selettore valido.',\n START_HIDDEN_SECTION: '👁 Visibilità del widget',\n START_HIDDEN_TITLE: 'Avvia nascosto',\n START_HIDDEN_SUB: 'Il widget si avvia invisibile. Usa Ctrl+Shift+E per mostrarlo o nasconderlo.',\n RESUME_TTL_SECTION: '⏱ Continuità di registrazione',\n RESUME_TTL_LABEL: 'Riprendi senza chiedere (minuti)',\n RESUME_TTL_HINT: 'Se ricarichi o cambi progetto, una registrazione attiva riprende senza chiedere entro questo intervallo. Trascorso, ti chiederà se continuare o annullare.',\n WIDGET_POSITION_SECTION: '🧲 Posizione del widget',\n WIDGET_POSITION_HINT: 'Trascina il pulsante di registrazione per spostarlo. La posizione viene ricordata.',\n WIDGET_POSITION_RESET_BTN: '↺ Reimposta posizione',\n WIDGET_POSITION_RESET_DONE: '✓ Posizione reimpostata',\n ISSUE_TRACKER_SECTION: '🎫 Issue tracker',\n ISSUE_TRACKER_TITLE: 'Collega i test ai ticket',\n ISSUE_TRACKER_SUB: \"Aggiungi un ID ticket al salvataggio e genera un link cliccabile nell'elenco.\",\n ISSUE_TRACKER_PROVIDER: 'Provider',\n ISSUE_TRACKER_BASE_URL: 'URL base',\n ISSUE_TRACKER_BASE_URL_PH: 'Es: https://mioprogetto.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Non configurato',\n LOGIN_SETUP_SET_UP_BTN: 'Configura',\n LOGIN_SETUP_TITLE: 'Configurazione del login',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Crea scaffold',\n LOGIN_SETUP_SELECT_EXISTING: 'Seleziona file esistente',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Nome del file',\n LOGIN_SETUP_FILE_NAME_PH: 'Es: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Re-scansiona',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Funzioni rilevate',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Assegnazione dei blocchi',\n LOGIN_SETUP_NO_FUNCTIONS: 'Nessuna funzione esportata trovata. Compila lo scaffold e ri-scansiona.',\n LOGIN_SETUP_BEFORE_LABEL: 'Funzione before() (una volta per suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'Funzione beforeEach() (prima di ogni test)',\n LOGIN_SETUP_NONE_OPTION: '— Nessuna —',\n LOGIN_SETUP_SUMMARY: 'File: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Salva',\n LOGIN_SETUP_CLEAR_BTN: 'Rimuovi configurazione',\n LOGIN_SETUP_CANCEL_BTN: 'Annulla',\n LOGIN_SETUP_SOURCE_LABEL: 'Sorgente del file di login',\n LOGIN_SETUP_CREATE_SUB: 'Genera uno scaffold con funzioni di esempio',\n LOGIN_SETUP_SELECT_SUB: 'Punta a un file di servizio di login esistente',\n LOGIN_SETUP_INJECT_TITLE: 'Aggiungere i blocchi di login?',\n LOGIN_SETUP_INJECT_TEXT: 'Questo file non contiene i blocchi di login configurati. Vuoi aggiungere l\\'import e i blocchi before/beforeEach ora?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Sì, aggiungi',\n },\n SELECTOR_PICKER: {\n TITLE: 'Seleziona un elemento DOM',\n PREVIEW_LABEL: 'navigare',\n CONFIRM_HINT: 'confermare',\n CANCEL_HINT: 'annullare',\n QUALITY_EXCELLENT: 'Eccellente — attributo di test presente (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Buono — id valido',\n QUALITY_ACCEPTABLE: 'Accettabile — solo classi CSS',\n QUALITY_POOR: 'Sconsigliato — solo tag o stile inline',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptor',\n COPY_CMDS_BTN: '📋 Copia comandi',\n SHOW_INTERCEPTORS: '▼ Vedi interceptor',\n HIDE_INTERCEPTORS: '▲ Nascondi interceptor',\n SECTION_COMMANDS: 'Comandi',\n NO_CMDS_YET: 'Ancora nessun comando',\n NO_ICP_SHORT: 'Nessun interceptor',\n COPY_ICP_BTN: '📋 Copia interceptor',\n UP_TITLE: 'Su',\n DOWN_TITLE: 'Giù',\n DEL_TITLE: 'Elimina',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Riattiva accesso',\n PERMISSION_EXPIRED: '🔑 Autorizzazione scaduta',\n PERMISSION_EXPIRED_HINT: \"Clicca per riattivare l'accesso alla cartella Cypress.\",\n NO_ACCESS: '🔒 Nessun accesso ai file locali',\n NO_ACCESS_HINT: \"Configura l'accesso in ⚙️ Config.\",\n NO_FILES: 'Nessun file',\n SELECT_FILE: \"← Seleziona un file dall'albero\",\n IT_LABEL: '🧪 it() da inserire:',\n COPY_IT_BTN: '📋 Copia it()',\n BEFORE_EACH_LABEL: '🔀 beforeEach() interceptor:',\n COPY_ICP_BTN: '📋 Copia interceptor',\n INSERT_BTN: '💾 Inserisci nel file',\n EDIT_MANUAL_BTN: '✏️ Modifica manualmente',\n CLOSE_BTN: '✕ Chiudi',\n NEW_FILE_BTN: '+ Nuovo file',\n NEW_FOLDER_BTN: '+ Nuova cartella',\n REFRESH_BTN: '↻ Aggiorna',\n NEW_FILE_PLACEHOLDER: 'nome-del-test',\n NEW_FOLDER_PLACEHOLDER: 'nome-cartella',\n NEW_FILE_CONFIRM: 'Crea',\n NEW_FILE_CANCEL: 'Annulla',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Nessun file',\n COPY_TITLE: \"Copia il contenuto dell'editor\",\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Copia',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: \"Nessuna modifica rispetto all'originale\",\n NO_CHANGES_SHORT: 'Nessuna modifica',\n LAUNCH_BTN: '▶ Esegui test',\n LAUNCH_LOCAL_ONLY: 'Spostati in locale per poter testare',\n LAUNCH_RUNNING: '⏳ Esecuzione…',\n LAUNCH_PASSED: '✓ Test superato',\n LAUNCH_FAILED: '✗ Test fallito',\n LAUNCH_NO_RUNNER: \"Nessun runner locale rilevato (l'hai avviato?)\",\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Salva',\n CLOSE_BTN: '✕ Chiudi',\n BACK_TO_EDITOR: \"← Torna all'editor\",\n INSERT_BTN: '🪄 Inserisci blocchi',\n INSERT_TITLE: \"Inserisci it() e beforeEach() nel contenuto dell'editor\",\n INSERT_DONE: \"Blocchi inseriti nell'editor\",\n INSERT_ERROR: 'Nessun blocco describe() valido trovato nel file',\n },\n RECORDER: {\n FS_TITLE: '📁 Accesso ai file',\n FS_LATER_BTN: 'Non ora',\n FS_SELECT_BTN: '📁 Seleziona cartella',\n FS_SUCCESS_TOAST: '✓ Cartella Cypress configurata',\n FS_ERROR_TOAST: \"Errore durante l'accesso alla cartella\",\n FS_INTRO_HTML: 'L\\'<strong style=\"color:#e6edf3\">editor avanzato</strong> può inserire i tuoi test direttamente nei file <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> di Cypress.',\n FS_STRUCTURE_HINT_HTML: 'Seleziona la cartella che contiene la sottocartella <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code>. L\\'estensione si aspetta questa struttura:',\n FS_TREE_PICK_HINT: '← seleziona questa cartella',\n FS_TREE_READ_HINT: '← l\\'estensione leggerà qui',\n FS_PERMISSION_NOTE: 'Il permesso viene salvato nel browser e non sarà richiesto di nuovo.',\n ASSERTION_SECTION: '➕ Aggiungi asserzione',\n ASSERT_SELECTOR_PH: 'selettore, es: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'valore atteso',\n ASSERT_ADD_BTN: '➕ Aggiungi',\n FILE_EDITOR_TITLE: '✏️ Editor di file',\n FILE_SAVED_TOAST: '✓ File salvato',\n FILE_SAVE_ERROR_TOAST: 'Errore durante il salvataggio',\n FIXTURES_WRITTEN_TOAST: '✓ Fixture scritte in cypress/fixtures',\n FIXTURES_NO_FOLDER_TOAST: 'Impossibile scrivere le fixture (configura la cartella Cypress)',\n FILE_UPLOAD_MANUAL_TOAST: 'Aggiungi {files} a cypress/fixtures/ prima di eseguire il test.', // TODO: translate\n FILE_UPLOAD_COPIED_TOAST: '{files} copiato/i in cypress/fixtures/.', // TODO: translate\n FILE_UPLOAD_COPY_ERROR_TOAST: 'Impossibile copiare {files} in cypress/fixtures/. Aggiungilo manualmente.', // TODO: translate\n BTN_CONFIG: 'Config',\n BTN_FILES: 'File',\n BTN_COMMANDS: 'Comandi',\n BTN_TESTS: 'Test',\n PAUSE_TITLE: 'Pausa (Ctrl+P)',\n RESUME_TITLE: 'Riprendi (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSA',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Ferma (Ctrl+R)',\n START_TITLE: 'Registra (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Registrazione in corso',\n SESSION_RESUME_TEXT: 'C\\'è una registrazione attiva non terminata.',\n SESSION_RESUME_COUNT: 'comandi catturati',\n SESSION_CONTINUE_BTN: 'Continua a registrare',\n SESSION_DISCARD_BTN: 'Annulla',\n BTN_HELP: 'Aiuto',\n },\n HELP: {\n TITLE: '❓ Aiuto — Guida rapida',\n INTRO: 'Tutto ciò che il registratore sa fare.',\n SEC_RECORDING: '⏺ Registrare',\n RECORDING_1: 'Premi ⏺ (o Ctrl+R) per iniziare; ⏹ per fermare e salvare.',\n RECORDING_2: 'Pausa / ripresa con ⏸ (o Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Scorciatoie da tastiera',\n SC_RECORD: 'Ctrl+R — Registra / ferma',\n SC_PAUSE: 'Ctrl+P — Pausa / ripresa',\n SC_TESTS: 'Ctrl+1 — Pannello test salvati',\n SC_COMMANDS: 'Ctrl+2 — Pannello comandi',\n SC_CONFIG: 'Ctrl+3 — Impostazioni',\n SC_VISIBILITY: 'Ctrl+Shift+E — Mostra / nascondi il widget',\n SC_HELP: 'Ctrl+Shift+H — Questo aiuto',\n SEC_CAPTURED: '🎯 Cosa viene registrato',\n CAP_CLICK: 'Click → .click()',\n CAP_DBLCLICK: 'Doppio click → .dblclick()',\n CAP_RIGHTCLICK: 'Click destro → .rightclick()',\n CAP_TYPE: 'Digitare in un campo → .clear().type(...)',\n CAP_CHECK: 'Checkbox / radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Invio / Esc → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Cambio di rotta (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Asserzioni',\n ASSERT_1: 'Alt+click su un elemento per verificarlo senza eseguire la sua azione (testo, valore, checked o visibile).',\n ASSERT_2: 'Oppure usa il costruttore di asserzioni nel pannello Comandi.',\n SEC_PANELS: '🗂 Pannelli',\n PANEL_TESTS: '📋 Test — salvati: filtra per tag, copia, combina, esporta.',\n PANEL_COMMANDS: '⌨️ Comandi — registrazione corrente: riordina, elimina, aggiungi asserzioni.',\n PANEL_CONFIG: '⚙️ Config — lingua, selettore, HTTP, cartella Cypress, login setup, dati, visibilità, posizione.',\n PANEL_FILES: '📁 File — inserisci test nei tuoi .cy.ts e avvia il runner.',\n SEC_SELECTOR: '🔎 Selettori',\n SELECTOR_1: 'Scegli l\\'attributo preferito (data-cy, data-testid, aria-label, id) in Config.',\n SELECTOR_2: 'Se un click non ha un selettore affidabile, appare un picker per scegliere l\\'antenato migliore.',\n SEC_DATA: '💾 Dati',\n DATA_1: 'Esporta i test in JSON (tutto / selezione / per tag).',\n DATA_2: 'Importa un JSON: si fonde con i tuoi dati (non si cancella nulla).',\n SEC_ADVANCED: '🚀 Avanzato',\n ADV_INVISIBLE: 'Modalità invisibile: start-hidden + Ctrl+Shift+E per registrare in produzione senza disturbare.',\n ADV_RUNNER: 'Runner locale: npx lib-e2e-cypress-runner per eseguire uno spec headless dall\\'editor.',\n ADV_CROSSAPP: 'Cross-app: la registrazione sopravvive al cambio di micro-frontend (stessa origine).',\n ADV_DRAG: 'Trascina il pulsante ⏺ per spostare il widget; la posizione viene ricordata.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (it)\n CLOSE: 'Chiudi',\n TAB_REFERENCE: 'Riferimento rapido',\n TAB_GUIDE: 'Guida all\\'uso',\n // TODO: translate (it) — usage guide body kept in Spanish for now.\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (it)\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","export const I18N_DE = {\n MAIN_FRAME: {\n SETTINGS: 'Einstellungen',\n SHOW_ADVANCED_EDITOR: 'Erweiterter Editor',\n DIALOG_SAVED_TESTS: 'Gespeicherte Tests',\n DIALOG_COMMANDS: 'Cypress-Befehle Vorschau',\n DIALOG_SAVE: 'Aufzeichnung speichern?',\n },\n SAVE_TEST: {\n DESC_LABEL: 'Testbeschreibung',\n CANCEL: 'Abbrechen',\n ASK: 'Aufgezeichneten Test speichern?',\n YES_CONTINUE: 'Ja, weiter',\n NO_DISCARD: 'Nein, verwerfen',\n DESC_PLACEHOLDER: 'Z. B.: Erfolgreiche Anmeldung mit gültigen Zugangsdaten',\n TAGS_LABEL: 'Tags (optional, zum späteren Filtern):',\n TAGS_PLACEHOLDER: 'smoke, login, regression…',\n ADD_TAG: '+ Hinzufügen',\n NO_TAGS: 'Keine Tags',\n SAVE_BTN: '💾 Speichern',\n SAVE_AND_EDIT: '📝 Speichern und bearbeiten',\n REMOVE_TAG_TITLE: 'Entfernen',\n NOTES_LABEL: 'Beschreibung / Notizen (optional):',\n NOTES_PLACEHOLDER: 'Was dieser Test validiert, Voraussetzungen usw.',\n TICKET_LABEL: 'Ticket / Issue (optional):',\n TICKET_PLACEHOLDER: 'Z. B.: PROJ-123, #42',\n TICKET_WARN: 'Ungültige ID für den konfigurierten Anbieter (wird trotzdem gespeichert)', // TODO: translate\n CONFIRM_DISCARD: 'Sind Sie sicher, dass Sie diese Aufzeichnung verwerfen möchten? Alle aufgezeichneten Schritte gehen verloren.',\n CONFIRM_DISCARD_BTN: 'Ja, verwerfen',\n BACK_BTN: 'Zurück',\n },\n TEST_EDITOR: {\n NO_TAGS: 'Keine Tags',\n SELECTED_SINGULAR: 'ausgewählt',\n SELECTED_PLURAL: 'ausgewählt',\n DESCRIBE_PLACEHOLDER: 'describe-Name (optional)',\n COPY_DESCRIBE: '🗂 describe() kopieren',\n MULTI_SELECT: '🗂 Mehrfachauswahl',\n CANCEL_SELECT: '✕ Abbrechen',\n COPY_CMDS_BTN: '📋 Befehle kopieren',\n COPY_ICPS_BTN: '📋 Interceptors kopieren',\n DEFAULT_DESCRIBE: 'Test-Suite',\n NO_TESTS: 'Keine gespeicherten Tests',\n DELETE_TITLE: 'Löschen',\n GROUP_BY_TICKET: '🎫 Nach Ticket gruppieren',\n UNGROUP_TICKET: '🎫 Gruppierung aufheben',\n NO_TICKET: 'Kein Ticket',\n TICKET_LINK_TITLE: 'Ticket öffnen',\n },\n CONFIG: {\n LANG_SECTION: '🌐 Sprache',\n LANG_FIELD: 'Oberfläche',\n HTTP_SECTION: '⚡ Erweitertes HTTP',\n HTTP_TITLE: 'Body-Validierungen',\n HTTP_SUB: 'GET → Antwort · POST/PUT → Anfrage',\n FIXTURE_SECTION: '🧪 HTTP-Fixtures',\n FIXTURE_TITLE: 'Antworten als Fixtures aufzeichnen',\n FIXTURE_SUB: 'GET-Antworten werden in cypress/fixtures gespeichert und mit cy.intercept({ fixture }) gestubbt.',\n SELECTOR_SECTION: '🎯 Selector-Strategie',\n SELECTOR_LABEL: 'Bevorzugtes Attribut für cy.get()',\n SELECTOR_OPT_DATACY: 'data-cy (Standard)',\n SELECTOR_OPT_TESTID: 'data-testid',\n SELECTOR_OPT_ARIA: 'aria-label',\n SELECTOR_OPT_ID: 'id (#element)',\n SELECTOR_HINT: 'Der Recorder sucht zuerst nach diesem Attribut. Falls nicht gefunden, versucht er die anderen.',\n FOLDER_SECTION: '📁 Cypress-Ordner',\n FOLDER_CONNECTED: 'verbunden —',\n FOLDER_NOT_SET: 'nicht konfiguriert',\n FOLDER_CHANGE_BTN: '📁 Ordner wechseln',\n FOLDER_SELECT_BTN: '📁 Ordner auswählen',\n FOLDER_REVOKE_BTN: '✕ Zugriff widerrufen',\n DATA_SECTION: '💾 Daten',\n DATA_DESC: 'Exportieren Sie alle Tests als JSON oder importieren Sie ein Backup.',\n EXPORT_BTN: '⬆️ Tests exportieren',\n EXPORT_DIALOG_TITLE: '⬆️ Tests exportieren',\n EXPORT_MODE_ALL: 'Alle',\n EXPORT_MODE_MANUAL: 'Manuelle Auswahl',\n EXPORT_MODE_TAGS: 'Nach Tags',\n EXPORT_ALL_DESC: 'Alle gespeicherten Tests werden exportiert.',\n EXPORT_COUNT: 'Zu exportieren:',\n EXPORT_CONFIRM: '⬆️ Exportieren',\n EXPORT_CANCEL: 'Abbrechen',\n EXPORT_EMPTY: 'Keine Tests zum Exportieren.',\n EXPORT_NO_TAGS: 'Keine Tags verfügbar.',\n EXPORT_TAGS_HINT: 'Wähle ein oder mehrere Tags, um zu sehen, welche Tests exportiert werden.',\n EXPORT_RESULT_LABEL: 'Diese Tests werden exportiert:',\n IMPORT_BTN: '⬇️ Tests importieren',\n FOLDER_UPDATED_TOAST: '✓ Cypress-Ordner aktualisiert',\n FOLDER_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\n IMPORT_SUCCESS: 'Daten erfolgreich importiert.',\n IMPORT_ERROR: 'Fehler beim Importieren.',\n JSON_INVALID: 'Die Datei ist kein gültiges JSON.',\n JSON_BAD_FORMAT: 'Die Datei hat nicht das erwartete Format.',\n SMART_SELECTOR_SECTION: '🔍 Intelligenter Selektor',\n SMART_SELECTOR_TITLE: 'Intelligenter Selektor',\n SMART_SELECTOR_SUB: 'Zeigt ein Auswahlfeld, wenn auf Elemente ohne gültigen Selektor geklickt wird.',\n START_HIDDEN_SECTION: '👁 Widget-Sichtbarkeit',\n START_HIDDEN_TITLE: 'Versteckt starten',\n START_HIDDEN_SUB: 'Das Widget startet unsichtbar. Verwenden Sie Ctrl+Shift+E zum Ein-/Ausblenden.',\n RESUME_TTL_SECTION: '⏱ Aufzeichnungskontinuität',\n RESUME_TTL_LABEL: 'Ohne Nachfrage fortsetzen (Minuten)',\n RESUME_TTL_HINT: 'Wenn Sie neu laden oder das Projekt wechseln, wird eine aktive Aufzeichnung innerhalb dieses Zeitfensters ohne Nachfrage fortgesetzt. Danach werden Sie gefragt, ob fortsetzen oder verwerfen.',\n WIDGET_POSITION_SECTION: '🧲 Widget-Position',\n WIDGET_POSITION_HINT: 'Ziehe den Aufnahme-Button, um ihn aus dem Weg zu schieben. Die Position wird gespeichert.',\n WIDGET_POSITION_RESET_BTN: '↺ Position zurücksetzen',\n WIDGET_POSITION_RESET_DONE: '✓ Position zurückgesetzt',\n ISSUE_TRACKER_SECTION: '🎫 Issue-Tracker',\n ISSUE_TRACKER_TITLE: 'Tests mit Tickets verknüpfen',\n ISSUE_TRACKER_SUB: 'Füge beim Speichern eine Ticket-ID hinzu und erstelle einen klickbaren Link.',\n ISSUE_TRACKER_PROVIDER: 'Anbieter',\n ISSUE_TRACKER_BASE_URL: 'Basis-URL',\n ISSUE_TRACKER_BASE_URL_PH: 'Z. B.: https://meinprojekt.atlassian.net',\n LOGIN_SETUP_SECTION: '🔐 Login setup',\n LOGIN_SETUP_NOT_CONFIGURED: 'Nicht konfiguriert',\n LOGIN_SETUP_SET_UP_BTN: 'Einrichten',\n LOGIN_SETUP_TITLE: 'Login-Konfiguration',\n LOGIN_SETUP_CREATE_SCAFFOLD: 'Scaffold erstellen',\n LOGIN_SETUP_SELECT_EXISTING: 'Vorhandene Datei auswählen',\n LOGIN_SETUP_FILE_NAME_LABEL: 'Dateiname',\n LOGIN_SETUP_FILE_NAME_PH: 'Z. B.: cypress/common-services/login.service.ts',\n LOGIN_SETUP_RESCAN: '🔄 Erneut scannen',\n LOGIN_SETUP_FUNCTIONS_DETECTED: 'Erkannte Funktionen',\n LOGIN_SETUP_BLOCK_ASSIGN: 'Blockzuweisung',\n LOGIN_SETUP_NO_FUNCTIONS: 'Keine exportierten Funktionen gefunden. Scaffold ausfüllen und erneut scannen.',\n LOGIN_SETUP_BEFORE_LABEL: 'before()-Funktion (einmal pro Suite)',\n LOGIN_SETUP_BEFORE_EACH_LABEL: 'beforeEach()-Funktion (vor jedem Test)',\n LOGIN_SETUP_NONE_OPTION: '— Keine —',\n LOGIN_SETUP_SUMMARY: 'Datei: {file} · before: {before} · beforeEach: {beforeEach}',\n LOGIN_SETUP_SAVE_BTN: '💾 Speichern',\n LOGIN_SETUP_CLEAR_BTN: 'Konfiguration entfernen',\n LOGIN_SETUP_CANCEL_BTN: 'Abbrechen',\n LOGIN_SETUP_SOURCE_LABEL: 'Quelle der Login-Datei',\n LOGIN_SETUP_CREATE_SUB: 'Scaffold mit Beispielfunktionen erstellen',\n LOGIN_SETUP_SELECT_SUB: 'Auf eine vorhandene Login-Service-Datei verweisen',\n LOGIN_SETUP_INJECT_TITLE: 'Login-Blöcke hinzufügen?',\n LOGIN_SETUP_INJECT_TEXT: 'Diese Datei enthält die konfigurierten Login-Blöcke nicht. Möchten Sie jetzt den Import und die before/beforeEach-Blöcke hinzufügen?',\n LOGIN_SETUP_INJECT_CONFIRM: 'Ja, hinzufügen',\n },\n SELECTOR_PICKER: {\n TITLE: 'DOM-Element auswählen',\n PREVIEW_LABEL: 'navigieren',\n CONFIRM_HINT: 'bestätigen',\n CANCEL_HINT: 'abbrechen',\n QUALITY_EXCELLENT: 'Ausgezeichnet — Test-Attribut vorhanden (data-cy / data-testid / aria-label)',\n QUALITY_GOOD: 'Gut — gültige ID',\n QUALITY_ACCEPTABLE: 'Akzeptabel — nur CSS-Klassen',\n QUALITY_POOR: 'Nicht empfohlen — nur Tag oder Inline-Style',\n },\n TEST_PREVISUALIZER: {\n INTERCEPTORS: 'Interceptors',\n COPY_CMDS_BTN: '📋 Befehle kopieren',\n SHOW_INTERCEPTORS: '▼ Interceptors anzeigen',\n HIDE_INTERCEPTORS: '▲ Interceptors ausblenden',\n SECTION_COMMANDS: 'Befehle',\n NO_CMDS_YET: 'Noch keine Befehle',\n NO_ICP_SHORT: 'Keine Interceptors',\n COPY_ICP_BTN: '📋 Interceptors kopieren',\n UP_TITLE: 'Nach oben',\n DOWN_TITLE: 'Nach unten',\n DEL_TITLE: 'Löschen',\n },\n ADVANCED_EDITOR: {\n REAUTH_BTN: '🔓 Zugriff reaktivieren',\n PERMISSION_EXPIRED: '🔑 Berechtigung abgelaufen',\n PERMISSION_EXPIRED_HINT: 'Klicken Sie, um den Zugriff auf Ihren Cypress-Ordner zu reaktivieren.',\n NO_ACCESS: '🔒 Kein Zugriff auf lokale Dateien',\n NO_ACCESS_HINT: 'Konfigurieren Sie den Zugriff unter ⚙️ Config.',\n NO_FILES: 'Keine Dateien',\n SELECT_FILE: '← Wählen Sie eine Datei aus dem Baum',\n IT_LABEL: '🧪 it() zum Einfügen:',\n COPY_IT_BTN: '📋 it() kopieren',\n BEFORE_EACH_LABEL: '🔀 beforeEach() Interceptors:',\n COPY_ICP_BTN: '📋 Interceptors kopieren',\n INSERT_BTN: '💾 In Datei einfügen',\n EDIT_MANUAL_BTN: '✏️ Manuell bearbeiten',\n CLOSE_BTN: '✕ Schließen',\n NEW_FILE_BTN: '+ Neue Datei',\n NEW_FOLDER_BTN: '+ Neuer Ordner',\n REFRESH_BTN: '↻ Aktualisieren',\n NEW_FILE_PLACEHOLDER: 'test-name',\n NEW_FOLDER_PLACEHOLDER: 'ordnername',\n NEW_FILE_CONFIRM: 'Erstellen',\n NEW_FILE_CANCEL: 'Abbrechen',\n },\n FILE_PREVIEW: {\n NO_FILE: 'Keine Datei',\n COPY_TITLE: 'Editor-Inhalt kopieren',\n BLOCK_IT: '🧪 it()',\n COPY_BTN: '📋 Kopieren',\n BLOCK_BEFORE_EACH: '🔀 beforeEach()',\n NO_CHANGES: 'Keine Änderungen gegenüber dem Original',\n NO_CHANGES_SHORT: 'Keine Änderungen',\n LAUNCH_BTN: '▶ Test starten',\n LAUNCH_LOCAL_ONLY: 'Wechsle zu localhost, um Tests auszuführen',\n LAUNCH_RUNNING: '⏳ Läuft…',\n LAUNCH_PASSED: '✓ Test bestanden',\n LAUNCH_FAILED: '✗ Test fehlgeschlagen',\n LAUNCH_NO_RUNNER: 'Kein lokaler Runner erkannt (gestartet?)',\n DIFF_BTN: '📊 Diff',\n SAVE_BTN: '💾 Speichern',\n CLOSE_BTN: '✕ Schließen',\n BACK_TO_EDITOR: '← Zurück zum Editor',\n INSERT_BTN: '🪄 Blöcke einfügen',\n INSERT_TITLE: 'it() und beforeEach() in den Editor-Inhalt einfügen',\n INSERT_DONE: 'Blöcke in den Editor eingefügt',\n INSERT_ERROR: 'Kein gültiger describe()-Block in der Datei gefunden',\n },\n RECORDER: {\n FS_TITLE: '📁 Dateizugriff',\n FS_LATER_BTN: 'Nicht jetzt',\n FS_SELECT_BTN: '📁 Ordner auswählen',\n FS_SUCCESS_TOAST: '✓ Cypress-Ordner konfiguriert',\n FS_ERROR_TOAST: 'Fehler beim Zugriff auf den Ordner',\n FS_INTRO_HTML: 'Der <strong style=\"color:#e6edf3\">erweiterte Editor</strong> kann Ihre Tests direkt in die Cypress-Dateien <code style=\"background:#0d1117;padding:1px 6px;border-radius:4px;font-size:11px;color:#c9d1d9\">.cy.ts</code> einfügen.',\n FS_STRUCTURE_HINT_HTML: 'Wählen Sie den Ordner, der den Unterordner <code style=\"background:#0d1117;padding:1px 5px;border-radius:4px;font-size:10px;color:#c9d1d9\">e2e/</code> enthält. Die Erweiterung erwartet diese Struktur:',\n FS_TREE_PICK_HINT: '← diesen Ordner auswählen',\n FS_TREE_READ_HINT: '← die Erweiterung liest hier',\n FS_PERMISSION_NOTE: 'Die Berechtigung wird im Browser gespeichert und nicht erneut angefordert.',\n ASSERTION_SECTION: '➕ Assertion hinzufügen',\n ASSERT_SELECTOR_PH: 'Selektor, z. B.: [data-cy=\"btn\"]',\n ASSERT_VALUE_PH: 'erwarteter Wert',\n ASSERT_ADD_BTN: '➕ Hinzufügen',\n FILE_EDITOR_TITLE: '✏️ Datei-Editor',\n FILE_SAVED_TOAST: '✓ Datei gespeichert',\n FILE_SAVE_ERROR_TOAST: 'Fehler beim Speichern',\n FIXTURES_WRITTEN_TOAST: '✓ Fixtures in cypress/fixtures geschrieben',\n FIXTURES_NO_FOLDER_TOAST: 'Fixtures konnten nicht geschrieben werden (Cypress-Ordner konfigurieren)',\n FILE_UPLOAD_MANUAL_TOAST: 'Füge {files} zu cypress/fixtures/ hinzu, bevor du den Test ausführst.', // TODO: translate\n FILE_UPLOAD_COPIED_TOAST: '{files} nach cypress/fixtures/ kopiert.', // TODO: translate\n FILE_UPLOAD_COPY_ERROR_TOAST: '{files} konnte nicht nach cypress/fixtures/ kopiert werden. Füge es manuell hinzu.', // TODO: translate\n BTN_CONFIG: 'Config',\n BTN_FILES: 'Dateien',\n BTN_COMMANDS: 'Befehle',\n BTN_TESTS: 'Tests',\n PAUSE_TITLE: 'Pausieren (Ctrl+P)',\n RESUME_TITLE: 'Fortsetzen (Ctrl+P)',\n BADGE_PAUSED: '⏸ PAUSE',\n BADGE_REC: '● REC',\n STOP_TITLE: 'Stopp (Ctrl+R)',\n START_TITLE: 'Aufzeichnen (Ctrl+R)',\n SESSION_RESUME_TITLE: '⏺ Aufzeichnung läuft',\n SESSION_RESUME_TEXT: 'Es gibt eine nicht abgeschlossene aktive Aufzeichnung.',\n SESSION_RESUME_COUNT: 'erfasste Befehle',\n SESSION_CONTINUE_BTN: 'Weiter aufzeichnen',\n SESSION_DISCARD_BTN: 'Verwerfen',\n BTN_HELP: 'Hilfe',\n },\n HELP: {\n TITLE: '❓ Hilfe — Kurzanleitung',\n INTRO: 'Alles, was der Recorder kann.',\n SEC_RECORDING: '⏺ Aufzeichnen',\n RECORDING_1: 'Drücke ⏺ (oder Ctrl+R) zum Starten; ⏹ zum Stoppen und Speichern.',\n RECORDING_2: 'Pause / Fortsetzen mit ⏸ (oder Ctrl+P).',\n SEC_SHORTCUTS: '⌨️ Tastenkürzel',\n SC_RECORD: 'Ctrl+R — Aufzeichnen / stoppen',\n SC_PAUSE: 'Ctrl+P — Pausieren / fortsetzen',\n SC_TESTS: 'Ctrl+1 — Panel gespeicherte Tests',\n SC_COMMANDS: 'Ctrl+2 — Befehle-Panel',\n SC_CONFIG: 'Ctrl+3 — Einstellungen',\n SC_VISIBILITY: 'Ctrl+Shift+E — Widget ein-/ausblenden',\n SC_HELP: 'Ctrl+Shift+H — Diese Hilfe',\n SEC_CAPTURED: '🎯 Was aufgezeichnet wird',\n CAP_CLICK: 'Klick → .click()',\n CAP_DBLCLICK: 'Doppelklick → .dblclick()',\n CAP_RIGHTCLICK: 'Rechtsklick → .rightclick()',\n CAP_TYPE: 'In ein Feld tippen → .clear().type(...)',\n CAP_CHECK: 'Checkbox / Radio → .check() / .uncheck()',\n CAP_SELECT: '<select> → .select(...)',\n CAP_KEYS: 'Enter / Escape → .type(\"{enter}\") / (\"{esc}\")',\n CAP_ROUTE: 'Routenwechsel (SPA) → cy.url().should(...)',\n CAP_HTTP: 'fetch / XHR → cy.intercept + cy.wait',\n SEC_ASSERT: '✅ Assertions',\n ASSERT_1: 'Alt+Klick auf ein Element, um es zu prüfen, ohne seine Aktion auszulösen (Text, Wert, checked oder sichtbar).',\n ASSERT_2: 'Oder nutze den Assertion-Builder im Befehle-Panel.',\n SEC_PANELS: '🗂 Panels',\n PANEL_TESTS: '📋 Tests — gespeichert: nach Tag filtern, kopieren, kombinieren, exportieren.',\n PANEL_COMMANDS: '⌨️ Befehle — aktuelle Aufzeichnung: umsortieren, löschen, Assertions hinzufügen.',\n PANEL_CONFIG: '⚙️ Config — Sprache, Selektor, HTTP, Cypress-Ordner, Login-Setup, Daten, Sichtbarkeit, Position.',\n PANEL_FILES: '📁 Dateien — Tests in deine .cy.ts einfügen und den Runner starten.',\n SEC_SELECTOR: '🔎 Selektoren',\n SELECTOR_1: 'Wähle das bevorzugte Attribut (data-cy, data-testid, aria-label, id) unter Config.',\n SELECTOR_2: 'Hat ein Klick keinen zuverlässigen Selektor, erscheint ein Picker zur Wahl des besten Vorfahren.',\n SEC_DATA: '💾 Daten',\n DATA_1: 'Tests als JSON exportieren (alle / Auswahl / nach Tags).',\n DATA_2: 'JSON importieren: wird zu deinen Daten hinzugefügt (nichts wird gelöscht).',\n SEC_ADVANCED: '🚀 Erweitert',\n ADV_INVISIBLE: 'Unsichtbarer Modus: start-hidden + Ctrl+Shift+E, um in Produktion unauffällig aufzuzeichnen.',\n ADV_RUNNER: 'Lokaler Runner: npx lib-e2e-cypress-runner, um einen Spec headless aus dem Editor zu starten.',\n ADV_CROSSAPP: 'Cross-App: die Aufzeichnung übersteht den Wechsel des Micro-Frontends (gleicher Origin).',\n ADV_DRAG: 'Ziehe den ⏺-Button, um das Widget zu verschieben; die Position wird gemerkt.',\n ADV_LOGIN: 'Login Setup (Ctrl+3): apunta a tu servicio de login; el grabador inyecta before()/beforeEach() automáticamente en cada test nuevo.', // TODO: translate (de)\n CLOSE: 'Schließen',\n TAB_REFERENCE: 'Kurzreferenz',\n TAB_GUIDE: 'Nutzungsleitfaden',\n // TODO: translate (de) — usage guide body kept in Spanish for now.\n GUIDE_INTRO: 'Cómo sacarle partido al grabador, qué cubre y qué no.',\n G_SEC_WORKFLOW: '🧭 Flujo de trabajo',\n G_WF_1: '1. Pulsa ⏺ (o Ctrl+R) para empezar a grabar.',\n G_WF_2: '2. Usa tu app como un usuario: clicks, formularios, navegación. Cada acción se convierte en un comando Cypress.',\n G_WF_3: '3. Añade verificaciones con Alt+click sobre lo que quieras comprobar.',\n G_WF_4: '4. Pulsa ⏹ para parar; ponle nombre y tags, y guárdalo.',\n G_WF_5: '5. En 📁 Ficheros, inserta el test en un .cy.ts o lánzalo con el runner local.',\n G_SEC_COVERED: '✅ Qué cubre',\n G_COV_1: 'Clicks, doble-click, click derecho, inputs de texto, checkbox/radio, select y teclas Enter/Escape.',\n G_COV_2: 'Navegación SPA (pushState/replaceState/popstate) → cy.url().should(...).',\n G_COV_3: 'Llamadas fetch/XHR (GET/POST/PUT) → cy.intercept + cy.wait, con validación de body opcional.',\n G_COV_4: 'Selector fiable (data-cy/testid/aria/id) y picker cuando no hay uno claro.',\n G_COV_5: 'Aserciones automáticas (Alt+click) y constructor manual.',\n G_COV_6: 'Continuidad al cambiar de micro-frontend (mismo origen), modo invisible e i18n.',\n G_COV_7: 'Login Setup: configura tu función de login en Ctrl+3 → Login Setup y el grabador añade los bloques before()/beforeEach() a cada test nuevo.', // TODO: translate (de)\n G_SEC_NOTCOVERED: '🚫 Qué NO cubre (por ahora)',\n G_NC_1: 'Orígenes distintos / subdominios (solo mismo origen).',\n G_NC_2: 'Subida de ficheros (selectFile), arrastrar y soltar, y hover.',\n G_NC_3: 'La tecla Tab (Cypress no la soporta en .type()).',\n G_NC_4: 'Peticiones DELETE (se ignoran a propósito).',\n G_NC_5: 'iframes y Shadow DOM de terceros pueden no capturarse.',\n },\n};\n","import { type Lang, isLang } from '../models/lang.model';\nimport { Subject } from '../utils/subject';\nimport { I18N_ES } from '../i18n/es';\nimport { I18N_EN } from '../i18n/en';\nimport { I18N_FR } from '../i18n/fr';\nimport { I18N_IT } from '../i18n/it';\nimport { I18N_DE } from '../i18n/de';\n\ntype Translations = typeof I18N_ES;\n\nexport class TranslationService {\n private readonly lang$: Subject<Lang>;\n\n private readonly translations: Record<Lang, Translations> = {\n es: I18N_ES,\n en: I18N_EN,\n fr: I18N_FR,\n it: I18N_IT,\n de: I18N_DE,\n };\n\n constructor() {\n this.lang$ = new Subject<Lang>(this.detectLang());\n }\n\n setLang(lang: Lang): void {\n this.lang$.next(lang);\n }\n\n getLang(): Lang {\n return this.lang$.getValue();\n }\n\n /** Subscribe to language changes; returns an unsubscribe function. */\n onLangChange(fn: (lang: Lang) => void): () => void {\n return this.lang$.subscribe(fn);\n }\n\n translate(key: string): string {\n const keys = key.split('.');\n let value: unknown = this.translations[this.lang$.getValue()];\n for (const k of keys) {\n value = (value as Record<string, unknown>)?.[k];\n if (value === undefined) return key;\n }\n return value as string;\n }\n\n detectLang(): Lang {\n const browserLang = navigator.language.split('-')[0];\n return isLang(browserLang) ? browserLang : 'es';\n }\n}\n\nexport const translationService = new TranslationService();\n","import { type Lang, isLang } from '../models/lang.model';\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\n\nexport class TransformationService {\n toLang(lang: string): Lang {\n return isLang(lang) ? lang : 'en';\n }\n\n generateItDescription(description: string, commands: string[]): string {\n const commandsBlock = commands.map((cmd) => normalizeBlock(cmd, ' ')).join('\\n');\n return `it('${escapeSingleQuotes(description)}', () => {\\n${commandsBlock}\\n});`;\n }\n}\n\nexport const transformationService = new TransformationService();\n","export interface DirectoryNode {\n name: string;\n kind: 'directory';\n children: (DirectoryNode | FileNode)[];\n}\n\nexport interface FileNode {\n name: string;\n kind: 'file';\n}\n\nexport class AdvancedTestTransformationService {\n insertBeforeEach(content: string, interceptors: string, alertFn?: (msg: string) => void): string {\n const match = content.match(/(describe\\s*\\(.*?{)/s);\n if (!match) {\n alertFn?.('ADVANCED_EDITOR.NO_DESCRIBE');\n return '';\n }\n const insertPos = (match.index ?? 0) + match[0].length;\n const beforeEachBlock = `\\n beforeEach(() => {\\n${interceptors} })\\n`;\n return content.slice(0, insertPos) + beforeEachBlock + content.slice(insertPos);\n }\n\n insertItBlock(content: string, itBlock: string, alertFn?: (msg: string) => void): string {\n const idx = content.lastIndexOf('})');\n if (idx === -1) {\n alertFn?.('ADVANCED_EDITOR.NO_END');\n return '';\n }\n return content.slice(0, idx) + '\\n' + itBlock + '\\n' + content.slice(idx);\n }\n\n buildBlockComment(notes: string): string {\n if (!notes.trim()) return '';\n const lines = notes.split('\\n').map(l => ` * ${l}`).join('\\n');\n return `/**\\n${lines}\\n */`;\n }\n\n isFile(file: unknown): boolean {\n return !!file && (file as FileNode).kind === 'file';\n }\n\n async scanDirectory(dirHandle: FileSystemDirectoryHandle): Promise<DirectoryNode> {\n const result: DirectoryNode = { name: dirHandle.name, kind: 'directory', children: [] };\n for await (const entry of dirHandle.values()) {\n if (entry.kind === 'directory') {\n result.children.push(await this.scanDirectory(entry as FileSystemDirectoryHandle));\n } else {\n result.children.push({ name: entry.name, kind: 'file' });\n }\n }\n return result;\n }\n}\n\nexport const advancedTestTransformationService = new AdvancedTestTransformationService();\n","import { INPUT_TYPES } from '../models/input-types.model';\nimport type { ActiveSessionState } from '../models/active-session.model';\nimport { Subject } from '../utils/subject';\nimport { FORBIDDEN_ID_PREFIXES } from '../utils/selector-quality.utils';\nimport { inferAssertionCommand } from '../utils/assertion.utils';\nimport { escapeSingleQuotes, escapeCssAttrValue } from '../utils/code-format.utils';\n\nconst OWN_SELECTOR = '[data-cy=\"lib-e2e-cypress-for-dummys\"]';\n\nexport type SelectorStrategy = 'data-cy' | 'data-testid' | 'aria-label' | 'id';\n\n/** Generates a stable, collision-resistant session id (browser + jsdom safe). */\nfunction createSessionId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n return `sess-${Date.now().toString(36)}-${Math.floor(Math.random() * 1e9).toString(36)}`;\n}\n\nexport class RecordingService {\n private readonly commands$ = new Subject<string[]>([]);\n private readonly interceptors$ = new Subject<string[]>([]);\n private readonly isRecording$ = new Subject<boolean>(false);\n private readonly isPaused$ = new Subject<boolean>(false);\n private readonly selectorNotFound$ = new Subject<{ target: HTMLElement; action: 'click' } | null>(null);\n private readonly inputDebounceTimers = new Map<HTMLElement, ReturnType<typeof setTimeout>>();\n private readonly fixtures = new Map<string, string>();\n private readonly uploadedFiles = new Map<string, ArrayBuffer>();\n private readonly abort = new AbortController();\n\n selectorStrategy: SelectorStrategy = 'data-cy';\n\n /** Stable id of the current live session (null when none has started). */\n sessionId: string | null = null;\n private startedAt = 0;\n\n // Stored originals for history patching cleanup\n private readonly origPushState = history.pushState.bind(history);\n private readonly origReplaceState = history.replaceState.bind(history);\n\n constructor() {\n this.listenToAssertClicks();\n this.listenToClicks();\n this.listenToDoubleClicks();\n this.listenToContextMenu();\n this.listenToInput();\n this.listenToSelect();\n this.listenToKeys();\n this.listenToRouteChanges();\n }\n\n // ── Public API ────────────────────────────────────────────────────────────\n\n startRecording(): void {\n this.clearCommands();\n this.sessionId = createSessionId();\n this.startedAt = Date.now();\n this.isPaused$.next(false);\n this.isRecording$.next(true);\n this.addCommand(`cy.viewport(1900, 1200)`);\n this.addCommand(`cy.visit('${escapeSingleQuotes(window.location.pathname)}')`);\n this.addCommand(`cy.get('[data-cy=\"lib-e2e-cypress-for-dummys\"]').invoke('hide');`);\n }\n\n /**\n * Rehydrates a previously persisted session WITHOUT running the startRecording\n * bootstrap (no viewport/visit/hide). Used to continue a recording across a\n * micro-frontend crossing or a same-origin reload.\n * See docs/specs/006-cross-app-recording-continuity.md.\n */\n restoreSession(state: ActiveSessionState): void {\n this.sessionId = state.sessionId;\n this.startedAt = state.startedAt;\n this.selectorStrategy = state.selectorStrategy;\n this.commands$.next([...state.commands]);\n this.interceptors$.next([...state.interceptors]);\n this.isPaused$.next(state.isPaused);\n // isRecording last so subscribers observe a fully-populated buffer.\n this.isRecording$.next(state.isRecording);\n }\n\n /** Full snapshot of the live session for persistence. */\n getSessionSnapshot(): ActiveSessionState {\n return {\n sessionId: this.sessionId ?? createSessionId(),\n isRecording: this.isRecording$.getValue(),\n isPaused: this.isPaused$.getValue(),\n commands: this.commands$.getValue(),\n interceptors: this.interceptors$.getValue(),\n selectorStrategy: this.selectorStrategy,\n startedAt: this.startedAt,\n updatedAt: Date.now(),\n };\n }\n\n stopRecording(): void {\n this.isPaused$.next(false);\n this.isRecording$.next(false);\n }\n\n toggleRecording(): void {\n if (this.isRecording$.getValue()) {\n this.stopRecording();\n } else {\n this.startRecording();\n }\n }\n\n pauseRecording(): void {\n if (!this.isRecording$.getValue()) return;\n this.isPaused$.next(true);\n }\n\n resumeRecording(): void {\n this.isPaused$.next(false);\n }\n\n togglePause(): void {\n if (this.isPaused$.getValue()) {\n this.resumeRecording();\n } else {\n this.pauseRecording();\n }\n }\n\n addCommand(cmd: string): void {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n this.commands$.next([...this.commands$.getValue(), cmd]);\n }\n\n /** Appends a command regardless of recording/paused state (e.g. assertions added manually). */\n appendCommand(cmd: string): void {\n this.commands$.next([...this.commands$.getValue(), cmd]);\n }\n\n removeCommand(index: number): void {\n const cmds = this.commands$.getValue();\n if (index < 0 || index >= cmds.length) return;\n this.commands$.next([...cmds.slice(0, index), ...cmds.slice(index + 1)]);\n }\n\n moveCommand(from: number, to: number): void {\n const cmds = [...this.commands$.getValue()];\n if (from < 0 || to < 0 || from >= cmds.length || to >= cmds.length || from === to) return;\n const [item] = cmds.splice(from, 1);\n cmds.splice(to, 0, item);\n this.commands$.next(cmds);\n }\n\n removeInterceptor(index: number): void {\n const ints = this.interceptors$.getValue();\n if (index < 0 || index >= ints.length) return;\n this.interceptors$.next([...ints.slice(0, index), ...ints.slice(index + 1)]);\n }\n\n registerInterceptor(method: string, url: string, alias: string, fixtureFile?: string): void {\n // Only capture interceptors while actively recording — otherwise HTTP calls\n // the host app fires before recording starts (the monitor is installed on\n // mount) would leak orphan cy.intercept lines into the saved test.\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n const wildcard = escapeSingleQuotes(this.urlToWildcard(url, method));\n const command = fixtureFile\n ? `cy.intercept('${method}', '${wildcard}', { fixture: '${escapeSingleQuotes(fixtureFile)}' }).as('${alias}')`\n : `cy.intercept('${method}', '${wildcard}').as('${alias}')`;\n const current = this.interceptors$.getValue();\n if (!current.includes(command)) {\n this.interceptors$.next([...current, command]);\n }\n }\n\n /** Registers a captured response as a Cypress fixture (name → JSON content). */\n registerFixture(name: string, content: string): void {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n this.fixtures.set(name, content);\n }\n\n getFixturesSnapshot(): Array<{ name: string; content: string }> {\n return [...this.fixtures.entries()].map(([name, content]) => ({ name, content }));\n }\n\n addUploadedFile(filename: string, bytes: ArrayBuffer): void {\n this.uploadedFiles.set(filename, bytes);\n }\n\n getUploadedFilesSnapshot(): Array<{ filename: string; bytes: ArrayBuffer }> {\n return [...this.uploadedFiles.entries()].map(([filename, bytes]) => ({ filename, bytes }));\n }\n\n clearUploadedFiles(): void {\n this.uploadedFiles.clear();\n }\n\n clearCommands(): void {\n this.commands$.next([]);\n this.interceptors$.next([]);\n this.fixtures.clear();\n this.uploadedFiles.clear();\n }\n\n clearInterceptors(): void {\n this.interceptors$.next([]);\n }\n\n getCommandsSnapshot(): string[] { return this.commands$.getValue(); }\n getInterceptorsSnapshot(): string[] { return this.interceptors$.getValue(); }\n getPausedSnapshot(): boolean { return this.isPaused$.getValue(); }\n\n onCommandsChange(fn: (cmds: string[]) => void): () => void {\n return this.commands$.subscribe(fn);\n }\n\n onInterceptorsChange(fn: (ints: string[]) => void): () => void {\n return this.interceptors$.subscribe(fn);\n }\n\n onRecordingChange(fn: (isRecording: boolean) => void): () => void {\n return this.isRecording$.subscribe(fn);\n }\n\n onPauseChange(fn: (isPaused: boolean) => void): () => void {\n return this.isPaused$.subscribe(fn);\n }\n\n /**\n * Fires a full session snapshot whenever any persisted field changes\n * (commands, interceptors, recording or paused state). Drives the debounced\n * persistence of the live session. Returns a combined unsubscribe.\n */\n onSessionChange(fn: (state: ActiveSessionState) => void): () => void {\n const emit = (): void => fn(this.getSessionSnapshot());\n const unsubs = [\n this.commands$.subscribe(emit),\n this.interceptors$.subscribe(emit),\n this.isRecording$.subscribe(emit),\n this.isPaused$.subscribe(emit),\n ];\n return () => unsubs.forEach((u) => u());\n }\n\n onSelectorNotFound(fn: (target: HTMLElement, action: 'click') => void): () => void {\n return this.selectorNotFound$.subscribe((v) => {\n if (v) fn(v.target, v.action);\n });\n }\n\n destroy(): void {\n this.abort.abort();\n history.pushState = this.origPushState;\n history.replaceState = this.origReplaceState;\n this.inputDebounceTimers.forEach((t) => clearTimeout(t));\n this.inputDebounceTimers.clear();\n }\n\n // ── DOM listeners ─────────────────────────────────────────────────────────\n\n /**\n * Alt+click captures an ASSERTION for the element instead of a click, and\n * suppresses the element's real action. Runs in the capture phase so it fires\n * before the app's handlers and before the bubble-phase click listener below\n * (stopImmediatePropagation prevents a duplicate `.click()`). See spec 009.\n */\n private listenToAssertClicks(): void {\n document.addEventListener(\n 'click',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n if (!(e as MouseEvent).altKey) return;\n const target = e.target as HTMLElement;\n if (!target || this.isOwnElement(target)) return;\n const tag = target.tagName?.toLowerCase();\n if (tag === 'body' || tag === 'html') return;\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return; // no reliable selector → leave it as a normal Alt+click\n const selector = this.getReliableSelector(container);\n if (!selector || this.isOwnSelector(selector)) return;\n // Assert-only: don't let the click perform its action or record a click.\n e.preventDefault();\n e.stopImmediatePropagation();\n const emit = (): void => this.addCommand(inferAssertionCommand(container, selector));\n // A checkbox/radio toggles its `checked` during the click's activation;\n // since we cancelled the action it is restored afterwards, so read the true\n // state on the next microtask rather than the transient toggled value.\n const type = (container.getAttribute('type') ?? '').toLowerCase();\n if (container.tagName.toLowerCase() === 'input' && (type === 'checkbox' || type === 'radio')) {\n queueMicrotask(emit);\n } else {\n emit();\n }\n },\n { capture: true, signal: this.abort.signal }\n );\n }\n\n private listenToClicks(): void {\n document.addEventListener(\n 'click',\n (e: Event) => {\n if (!this.isRecording$.getValue()) return;\n const target = e.target as HTMLElement;\n if (!target || this.isOwnElement(target)) return;\n const tag = target.tagName?.toLowerCase();\n if (tag === 'body' || tag === 'html') return;\n this.handleClickEvent(target);\n },\n { signal: this.abort.signal }\n );\n }\n\n /** Centralised selector resolution for the pointer/key listeners (spec 010). */\n private resolveSelectorFor(target: HTMLElement | null): string | null {\n if (!target || this.isOwnElement(target)) return null;\n const tag = target.tagName?.toLowerCase();\n if (tag === 'body' || tag === 'html') return null;\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return null;\n const selector = this.getReliableSelector(container);\n if (!selector || this.isOwnSelector(selector)) return null;\n return selector;\n }\n\n private listenToDoubleClicks(): void {\n document.addEventListener(\n 'dblclick',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n if ((e as MouseEvent).altKey) return;\n const selector = this.resolveSelectorFor(e.target as HTMLElement);\n if (!selector) return;\n // Collapse the up-to-2 single clicks the browser fired before the dblclick.\n const safeSelector = escapeSingleQuotes(selector);\n const clickCmd = `cy.get('${safeSelector}').click()`;\n let cmds = this.commands$.getValue();\n let removed = 0;\n while (removed < 2 && cmds.length > 0 && cmds[cmds.length - 1] === clickCmd) {\n cmds = cmds.slice(0, -1);\n removed++;\n }\n if (removed > 0) this.commands$.next(cmds);\n this.addCommand(`cy.get('${safeSelector}').dblclick()`);\n },\n { signal: this.abort.signal }\n );\n }\n\n private listenToContextMenu(): void {\n document.addEventListener(\n 'contextmenu',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n const selector = this.resolveSelectorFor(e.target as HTMLElement);\n if (!selector) return;\n this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').rightclick()`);\n },\n { signal: this.abort.signal }\n );\n }\n\n /** Enter → type('{enter}'), Escape → type('{esc}'), only inside a field. */\n private listenToKeys(): void {\n document.addEventListener(\n 'keydown',\n (e: Event) => {\n if (!this.isRecording$.getValue() || this.isPaused$.getValue()) return;\n const key = (e as KeyboardEvent).key;\n if (key !== 'Enter' && key !== 'Escape') return;\n const target = e.target as HTMLElement;\n const tag = target?.tagName?.toLowerCase();\n if (tag !== 'input' && tag !== 'textarea' && tag !== 'select') return;\n const selector = this.resolveSelectorFor(target);\n if (!selector) return;\n // Record the field's pending value before the key press.\n this.flushInputDebounce(target);\n const token = key === 'Enter' ? '{enter}' : '{esc}';\n this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').type('${token}')`);\n },\n { signal: this.abort.signal }\n );\n }\n\n private listenToInput(): void {\n document.addEventListener(\n 'input',\n (e: Event) => {\n if (!this.isRecording$.getValue()) return;\n const target = e.target as HTMLInputElement | HTMLTextAreaElement;\n if (!target || this.isOwnElement(target)) return;\n this.handleInputEvent(target);\n },\n { signal: this.abort.signal }\n );\n }\n\n private listenToSelect(): void {\n document.addEventListener(\n 'change',\n (e: Event) => {\n if (!this.isRecording$.getValue()) return;\n const target = e.target as HTMLInputElement | HTMLSelectElement;\n if (!target || this.isOwnElement(target)) return;\n const tag = target.tagName.toLowerCase();\n if (tag === 'select') {\n this.handleSelectEvent(target as HTMLSelectElement);\n } else if (tag === 'input') {\n const type = (target.getAttribute('type') ?? '').toLowerCase();\n if (type === 'file') {\n void this.handleFileInputChange(target as HTMLInputElement);\n }\n }\n },\n { signal: this.abort.signal }\n );\n }\n\n private async handleFileInputChange(target: HTMLInputElement): Promise<void> {\n if (this.isPaused$.getValue()) return;\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n const selector = this.getReliableSelector(container);\n if (!selector || this.isOwnSelector(selector)) return;\n\n const files = Array.from(target.files ?? []);\n if (!files.length) return;\n\n const paths = files.map(f => `'cypress/fixtures/${escapeSingleQuotes(f.name)}'`);\n const pathArg = paths.length === 1 ? paths[0] : `[${paths.join(', ')}]`;\n this.addCommand(`cy.get('${escapeSingleQuotes(selector)}').selectFile(${pathArg})`);\n\n for (const file of files) {\n const bytes = await this.readFileAsArrayBuffer(file);\n this.addUploadedFile(file.name, bytes);\n }\n }\n\n private readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {\n if (typeof file.arrayBuffer === 'function') {\n return file.arrayBuffer();\n }\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(reader.result as ArrayBuffer);\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(file);\n });\n }\n\n private listenToRouteChanges(): void {\n let lastUrl = window.location.pathname + window.location.search + window.location.hash;\n\n const addUrlCommand = (newUrl: string): void => {\n if (!this.isRecording$.getValue()) return;\n if (newUrl === lastUrl) return;\n this.addCommand(`cy.url().should('include', '${escapeSingleQuotes(newUrl)}')`);\n lastUrl = newUrl;\n };\n\n const wrapMethod = (type: 'pushState' | 'replaceState'): void => {\n const orig = history[type].bind(history);\n history[type] = (data: unknown, unused: string, url?: string | URL | null) => {\n const result = orig(data, unused, url);\n let newUrl = window.location.pathname + window.location.search + window.location.hash;\n if (typeof url === 'string' && url.length > 0) {\n const a = document.createElement('a');\n a.href = url;\n newUrl = a.pathname + a.search + a.hash;\n } else if (url instanceof URL) {\n newUrl = url.pathname + url.search + url.hash;\n }\n addUrlCommand(newUrl);\n return result;\n };\n };\n\n wrapMethod('pushState');\n wrapMethod('replaceState');\n\n window.addEventListener(\n 'popstate',\n () => {\n const newUrl = window.location.pathname + window.location.search + window.location.hash;\n addUrlCommand(newUrl);\n },\n { signal: this.abort.signal }\n );\n }\n\n // ── Click helpers ─────────────────────────────────────────────────────────\n\n private handleClickEvent(target: HTMLElement): void {\n // Bubble up from non-interactive span/div inside button or mat-option\n if (!this.isInteractiveElement(target)) {\n const tag = target.tagName.toLowerCase();\n if (\n (tag === 'span' || tag === 'div') &&\n target.parentElement &&\n (target.parentElement.tagName.toLowerCase() === 'button' ||\n target.parentElement.tagName.toLowerCase() === 'mat-option') &&\n (target.parentElement.hasAttribute('data-cy') || target.parentElement.hasAttribute('id'))\n ) {\n target = target.parentElement;\n }\n const matSelect = target.closest('mat-select');\n if (matSelect) {\n const sel = this.getReliableSelector(matSelect as HTMLElement);\n if (sel) {\n this.addCommand(`cy.get('${sel}').click()`);\n } else {\n this.selectorNotFound$.next({ target: matSelect as HTMLElement, action: 'click' });\n }\n return;\n }\n\n // Ignore decorative/non-interactive elements (divs, paragraphs, headings…).\n // Re-target to the nearest interactive ancestor if one exists.\n if (!this.isInteractiveElement(target)) {\n const interactive = target.closest<HTMLElement>(\n 'button,a,input,select,textarea,label,summary,mat-option,' +\n '[role=\"button\"],[role=\"link\"],[role=\"menuitem\"],[role=\"option\"],[role=\"tab\"]'\n );\n if (!interactive) return;\n target = interactive;\n }\n }\n\n const tag = target.tagName.toLowerCase();\n if (tag === 'input' || tag === 'textarea' || tag === 'select') {\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) { this.selectorNotFound$.next({ target, action: 'click' }); return; }\n // Checkbox/radio → check()/uncheck(); other input clicks stay a no-op (the\n // value is captured via the `input` event). Runs in the bubble phase, so\n // `checked` already reflects the post-click state (spec 010).\n if (tag === 'input') {\n const input = target as HTMLInputElement;\n const type = (input.getAttribute('type') ?? '').toLowerCase();\n if (type === 'checkbox' || type === 'radio') {\n const selector = this.getReliableSelector(container);\n if (selector && !this.isOwnSelector(selector)) {\n const action = type === 'radio' || input.checked ? 'check' : 'uncheck';\n this.addCommand(`cy.get('${selector}').${action}()`);\n }\n }\n }\n return;\n }\n\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) {\n this.selectorNotFound$.next({ target, action: 'click' });\n return;\n }\n\n const selector = this.getReliableSelector(container);\n if (selector === OWN_SELECTOR) return;\n\n if (tag === 'mat-option') {\n this.handleMatOptionClick(target, selector);\n return;\n }\n\n if (!selector) {\n this.selectorNotFound$.next({ target, action: 'click' });\n return;\n }\n\n this.addGenericCommand({\n selector,\n action: (s) => `cy.get('${s}').click()`,\n });\n }\n\n private handleMatOptionClick(target: HTMLElement, selector: string | null): void {\n const matSelect = target.closest('mat-select');\n let dataCy: string | null = null;\n if (matSelect) dataCy = matSelect.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\n if (!dataCy) dataCy = target.closest('[data-cy]')?.getAttribute('data-cy') ?? null;\n if (dataCy) {\n const safeSel = escapeSingleQuotes(`[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`);\n this.addCommand(`cy.get('${safeSel}').click()`);\n return;\n }\n if (selector) {\n this.addCommand(`cy.get('${selector}').eq(0).click()`);\n } else {\n this.selectorNotFound$.next({ target, action: 'click' });\n }\n }\n\n // ── Input helpers ─────────────────────────────────────────────────────────\n\n private handleInputEvent(target: HTMLInputElement | HTMLTextAreaElement): void {\n const tag = target.tagName.toLowerCase();\n const isText = tag === 'textarea' || (tag === 'input' && (INPUT_TYPES as readonly string[]).includes(target.type));\n if (!isText) return;\n\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n\n if (this.inputDebounceTimers.has(target)) {\n clearTimeout(this.inputDebounceTimers.get(target));\n }\n this.inputDebounceTimers.set(\n target,\n setTimeout(() => {\n this.inputDebounceTimers.delete(target);\n this.recordInputValue(target);\n }, 1000)\n );\n }\n\n /** Records a text field's current value as a `clear().type()` command. */\n private recordInputValue(target: HTMLInputElement | HTMLTextAreaElement): void {\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n const selector = this.getReliableSelector(container);\n const value = escapeSingleQuotes(target.value);\n this.addGenericCommand({\n selector,\n action: (s) => `cy.get('${s}').clear().type('${value}')`,\n });\n }\n\n /** Flushes any pending debounced value for an element, recording it now. */\n private flushInputDebounce(target: HTMLElement): void {\n const timer = this.inputDebounceTimers.get(target);\n if (timer === undefined) return;\n clearTimeout(timer);\n this.inputDebounceTimers.delete(target);\n this.recordInputValue(target as HTMLInputElement | HTMLTextAreaElement);\n }\n\n // ── Select helpers ────────────────────────────────────────────────────────\n\n private handleSelectEvent(target: HTMLSelectElement): void {\n const container = target.closest<HTMLElement>('[data-cy], [data-testid], [aria-label], [id]');\n if (!container) return;\n const selector = this.getReliableSelector(container);\n const value = escapeSingleQuotes(target.value);\n this.addGenericCommand({\n selector,\n action: (s) => `cy.get('${s}').select('${value}')`,\n });\n }\n\n // ── Shared helpers ────────────────────────────────────────────────────────\n\n private addGenericCommand(opts: {\n selector: string | null;\n action: (s: string) => string;\n }): void {\n if (!opts.selector || this.isOwnSelector(opts.selector)) return;\n this.addCommand(opts.action(escapeSingleQuotes(opts.selector)));\n }\n\n private getReliableSelector(el: HTMLElement): string | null {\n const strategy = this.selectorStrategy;\n const dataCy = el.getAttribute('data-cy');\n const dataTestid = el.getAttribute('data-testid');\n const ariaLabel = el.getAttribute('aria-label');\n const dataDotCy = el.getAttribute('data.cy');\n\n const rawId = el.id;\n const validId = rawId &&\n rawId.length < 25 &&\n /^[a-zA-Z][\\w-]*$/.test(rawId) &&\n !FORBIDDEN_ID_PREFIXES.some((p) => rawId.startsWith(p)) &&\n !/^\\d+$/.test(rawId) ? rawId : null;\n\n switch (strategy) {\n case 'data-testid':\n if (dataTestid) return `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]`;\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n return validId ? `#${validId}` : null;\n case 'aria-label':\n if (ariaLabel) return `[aria-label=\"${escapeCssAttrValue(ariaLabel)}\"]`;\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n return validId ? `#${validId}` : null;\n case 'id':\n if (validId) return `#${validId}`;\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n return dataTestid ? `[data-testid=\"${escapeCssAttrValue(dataTestid)}\"]` : null;\n default: // 'data-cy'\n if (dataCy) return `[data-cy=\"${escapeCssAttrValue(dataCy)}\"]`;\n if (dataDotCy) return `[data.cy=\"${escapeCssAttrValue(dataDotCy)}\"]`;\n return validId ? `#${validId}` : null;\n }\n }\n\n private isInteractiveElement(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) return false;\n const tag = target.tagName.toLowerCase();\n return ['select', 'option', 'input', 'textarea', 'button'].includes(tag);\n }\n\n private isOwnSelector(selector: string | null): boolean {\n return selector === OWN_SELECTOR;\n }\n\n private isOwnElement(target: HTMLElement): boolean {\n return !!target.closest('[data-cy=\"lib-e2e-cypress-for-dummys\"]');\n }\n\n private urlToWildcard(url: string, method: string): string {\n const u = new URL(url, 'http://localhost');\n if (method.toUpperCase() === 'GET' && u.search) {\n return `**${u.pathname}/**`;\n }\n return `**${u.pathname}`;\n }\n}\n","import { escapeSingleQuotes } from './code-format.utils';\n\n/** Longest visible-text snippet turned into a `contain.text` assertion. */\nconst MAX_TEXT_LENGTH = 60;\n\n/**\n * Infers a sensible Cypress assertion for an element, given the selector already\n * resolved for it (spec 009 — Alt+click assertion capture):\n *\n * - checkbox / radio → should('be.checked' | 'not.be.checked')\n * - input/textarea/select → should('have.value', '<value>') (or be.visible if empty)\n * - short visible text → should('contain.text', '<text>')\n * - otherwise → should('be.visible')\n *\n * All embedded values/text are single-quote escaped so the generated command is\n * always valid JS.\n */\nexport function inferAssertionCommand(el: HTMLElement, selector: string): string {\n const safeSelector = escapeSingleQuotes(selector);\n const should = (body: string): string => `cy.get('${safeSelector}').should(${body})`;\n const tag = el.tagName.toLowerCase();\n\n if (tag === 'input') {\n const input = el as HTMLInputElement;\n const type = (input.getAttribute('type') ?? 'text').toLowerCase();\n if (type === 'checkbox' || type === 'radio') {\n return should(`'${input.checked ? 'be.checked' : 'not.be.checked'}'`);\n }\n return input.value\n ? should(`'have.value', '${escapeSingleQuotes(input.value)}'`)\n : should(`'be.visible'`);\n }\n\n if (tag === 'textarea' || tag === 'select') {\n const value = (el as HTMLTextAreaElement | HTMLSelectElement).value;\n return value\n ? should(`'have.value', '${escapeSingleQuotes(value)}'`)\n : should(`'be.visible'`);\n }\n\n const text = (el.textContent ?? '').replace(/\\s+/g, ' ').trim();\n if (text && text.length <= MAX_TEXT_LENGTH) {\n return should(`'contain.text', '${escapeSingleQuotes(text)}'`);\n }\n return should(`'be.visible'`);\n}\n","import { openDB, type IDBPDatabase } from 'idb';\nimport { DB_SCHEMA } from '../models/db-schema.model';\nimport type { ActiveSessionState } from '../models/active-session.model';\nimport type { LoginSetupConfig } from '../models/login-setup.model';\nimport { normalizeBlock, escapeSingleQuotes } from '../utils/code-format.utils';\nimport { buildTicketComment } from '../utils/ticket.utils';\n\n/** Fixed primary key for the single active-session record. */\nconst ACTIVE_SESSION_ID = 1;\n\ninterface TestRecord { id: number; name: string; createdAt: number; tags?: string[]; notes?: string; ticketId?: string; }\ninterface CommandRecord { id: number; command: string; testId: number; createdAt: number; }\ninterface InterceptorRecord { id: number; interceptor: string; testId: number; createdAt: number; }\ninterface ConfigRecord { id: number; [key: string]: unknown; }\n\nexport interface TestWithDetails extends TestRecord {\n commands: string[];\n interceptors: string[];\n}\n\nexport interface TestDetail extends TestWithDetails {\n cypressCommands: string[];\n itBlock: string;\n interceptorsBlock: string;\n}\n\nexport class PersistenceService {\n private _db: Promise<IDBPDatabase> | null = null;\n\n // dbName is overridable so tests can use unique names for isolation.\n constructor(private readonly dbName: string = DB_SCHEMA.name) {}\n\n private getDB(): Promise<IDBPDatabase> {\n if (!this._db) {\n this._db = openDB(this.dbName, DB_SCHEMA.version, {\n upgrade(database) {\n for (const store of DB_SCHEMA.stores) {\n if (!database.objectStoreNames.contains(store.name)) {\n const os = database.createObjectStore(store.name, {\n keyPath: store.keyPath,\n autoIncrement: store.autoIncrement,\n });\n for (const index of store.indexes) {\n os.createIndex(index.name, index.keyPath, { unique: index.unique });\n }\n }\n }\n },\n });\n }\n return this._db as Promise<IDBPDatabase>;\n }\n\n // ── Tests ─────────────────────────────────────────────────────────────────\n\n async insertTest(name: string, commands: string[] = [], interceptors: string[] = [], tags: string[] = [], notes?: string, ticketId?: string): Promise<number> {\n const db = await this.getDB();\n const record: Omit<TestRecord, 'id'> = { name, createdAt: Date.now(), ...(tags.length ? { tags } : {}), ...(notes ? { notes } : {}), ...(ticketId ? { ticketId } : {}) };\n const id = await db.add('tests', record) as number;\n if (commands.length) await this.insertCommands(commands, id);\n if (interceptors.length) await this.insertInterceptors(interceptors, id);\n return id;\n }\n\n async getAllTests(): Promise<TestWithDetails[]> {\n const db = await this.getDB();\n const tests = await db.getAll('tests') as TestRecord[];\n return Promise.all(\n tests.map(async (test) => ({\n ...test,\n commands: await this.getCommandStrings(test.id),\n interceptors: await this.getInterceptorStrings(test.id),\n }))\n );\n }\n\n async getTestById(testId: number): Promise<TestDetail | null> {\n const db = await this.getDB();\n const record = await db.get('tests', testId) as TestRecord | undefined;\n if (!record) return null;\n\n const commands = await this.getCommandStrings(testId);\n const interceptors = await this.getInterceptorStrings(testId);\n const ticketComment = record.ticketId ? buildTicketComment(record.ticketId) + '\\n' : '';\n const itBlock = `${ticketComment}it('${escapeSingleQuotes(record.name)}', () => {\\n${commands.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\n const interceptorsBlock = interceptors.length\n ? ' // Auto-generated Cypress interceptors\\n' +\n interceptors.map(i => normalizeBlock(i, ' ')).join('\\n') + '\\n'\n : '';\n\n return { ...record, commands, interceptors, cypressCommands: commands, itBlock, interceptorsBlock };\n }\n\n async deleteTest(id: number): Promise<void> {\n const db = await this.getDB();\n await db.delete('tests', id);\n await this.deleteCommandsByTestId(id);\n await this.deleteInterceptorsByTestId(id);\n }\n\n // ── Commands ──────────────────────────────────────────────────────────────\n\n async insertCommands(commands: string[], testId: number): Promise<void> {\n const db = await this.getDB();\n await Promise.all(\n commands.map((command) => db.add('commands', { command, testId, createdAt: Date.now() }))\n );\n }\n\n async getCommandsByTestId(testId: number): Promise<CommandRecord[]> {\n const db = await this.getDB();\n return db.getAllFromIndex('commands', 'testId', testId) as Promise<CommandRecord[]>;\n }\n\n private async getCommandStrings(testId: number): Promise<string[]> {\n return (await this.getCommandsByTestId(testId)).map((r) => r.command).filter(Boolean);\n }\n\n private async deleteCommandsByTestId(testId: number): Promise<void> {\n const db = await this.getDB();\n const rows = await this.getCommandsByTestId(testId);\n const tx = db.transaction('commands', 'readwrite');\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\n await tx.done;\n }\n\n // ── Interceptors ──────────────────────────────────────────────────────────\n\n async insertInterceptors(interceptors: string[], testId: number): Promise<void> {\n const db = await this.getDB();\n await Promise.all(\n interceptors.map((interceptor) => db.add('interceptors', { interceptor, testId, createdAt: Date.now() }))\n );\n }\n\n async getInterceptorsByTestId(testId: number): Promise<InterceptorRecord[]> {\n const db = await this.getDB();\n return db.getAllFromIndex('interceptors', 'testId', testId) as Promise<InterceptorRecord[]>;\n }\n\n private async getInterceptorStrings(testId: number): Promise<string[]> {\n return (await this.getInterceptorsByTestId(testId)).map((r) => r.interceptor).filter(Boolean);\n }\n\n async deleteInterceptorsByTestId(testId: number): Promise<void> {\n const db = await this.getDB();\n const rows = await this.getInterceptorsByTestId(testId);\n const tx = db.transaction('interceptors', 'readwrite');\n await Promise.all(rows.map((r) => tx.store.delete(r.id)));\n await tx.done;\n }\n\n // ── Configuration ─────────────────────────────────────────────────────────\n\n async setConfig(config: Record<string, unknown>): Promise<void> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n const current = records[0] ?? {};\n const merged = { ...current, ...config };\n if ((current as ConfigRecord).id) {\n await db.put('configuration', merged);\n } else {\n await db.add('configuration', merged);\n }\n }\n\n async setConfigKey(key: string, value: unknown): Promise<void> {\n return this.setConfig({ [key]: value });\n }\n\n async getConfig(key: string): Promise<Record<string, unknown> | null> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n if (!records.length) return null;\n const config = records[0];\n return Object.prototype.hasOwnProperty.call(config, key) ? { [key]: config[key] } : null;\n }\n\n async getGeneralConfig(): Promise<ConfigRecord | null> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n return records[0] ?? null;\n }\n\n // ── Login setup config ───────────────────────────────────────────────────\n\n private static readonly LOGIN_SETUP_KEY = 'loginSetupConfig';\n\n async saveLoginSetup(config: LoginSetupConfig): Promise<void> {\n await this.setConfigKey(PersistenceService.LOGIN_SETUP_KEY, JSON.stringify(config));\n }\n\n async getLoginSetup(): Promise<LoginSetupConfig | null> {\n const record = await this.getConfig(PersistenceService.LOGIN_SETUP_KEY);\n if (!record) return null;\n const raw = record[PersistenceService.LOGIN_SETUP_KEY];\n if (typeof raw !== 'string') return null;\n try { return JSON.parse(raw) as LoginSetupConfig; } catch { return null; }\n }\n\n async clearLoginSetup(): Promise<void> {\n const db = await this.getDB();\n const records = await db.getAll('configuration') as ConfigRecord[];\n if (!records.length) return;\n const current = { ...records[0] };\n delete current[PersistenceService.LOGIN_SETUP_KEY];\n await db.put('configuration', current);\n }\n\n // ── Active recording session ──────────────────────────────────────────────\n\n /** Upserts the live recording session (single record, fixed key). */\n async saveActiveSession(state: ActiveSessionState): Promise<void> {\n const db = await this.getDB();\n await db.put('activeSession', { ...state, id: ACTIVE_SESSION_ID });\n }\n\n /** Returns the persisted live session, or null when none is stored. */\n async getActiveSession(): Promise<ActiveSessionState | null> {\n const db = await this.getDB();\n const record = await db.get('activeSession', ACTIVE_SESSION_ID) as (ActiveSessionState & { id: number }) | undefined;\n if (!record) return null;\n const { id: _id, ...state } = record;\n return state as ActiveSessionState;\n }\n\n /** Removes the live session record. Safe to call when none exists. */\n async clearActiveSession(): Promise<void> {\n const db = await this.getDB();\n await db.delete('activeSession', ACTIVE_SESSION_ID);\n }\n\n // ── Bulk operations ───────────────────────────────────────────────────────\n\n async clearAllData(): Promise<void> {\n const db = await this.getDB();\n await Promise.all([\n db.clear('tests'),\n db.clear('commands'),\n db.clear('interceptors'),\n ]);\n }\n\n async ingestFileData(tests: Record<string, unknown>[], interceptors: Record<string, unknown>[]): Promise<void> {\n if (Array.isArray(tests)) {\n const db = await this.getDB();\n for (const test of tests) {\n // Split the nested commands/interceptors back into their own stores,\n // keyed by the freshly-assigned testId — otherwise they would be stored\n // as stray fields and silently lost on read (getAllTests reads them by\n // testId from the commands/interceptors stores).\n const { id: _id, commands, interceptors: testInterceptors, ...record } = test;\n const newId = await db.add('tests', record) as number;\n const cmds = Array.isArray(commands) ? commands as string[] : [];\n const icps = Array.isArray(testInterceptors) ? testInterceptors as string[] : [];\n if (cmds.length) await this.insertCommands(cmds, newId);\n if (icps.length) await this.insertInterceptors(icps, newId);\n }\n }\n // Back-compat: legacy files may carry top-level interceptors with their own testId.\n await this.bulkInsertWithoutId('interceptors', interceptors);\n }\n\n async hasDirectoryAccess(): Promise<boolean> {\n const config = await this.getGeneralConfig();\n return !!config?.['cypressDirectoryHandle'];\n }\n\n async writeUploadedFile(filename: string, bytes: ArrayBuffer): Promise<void> {\n const config = await this.getGeneralConfig();\n const dirHandle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\n if (!dirHandle) throw new Error('No Cypress folder configured');\n\n const perm = dirHandle as unknown as FileSystemHandleWithPermission;\n let state = await perm.queryPermission({ mode: 'readwrite' });\n if (state !== 'granted') state = await perm.requestPermission({ mode: 'readwrite' });\n if (state !== 'granted') throw new Error('Write permission denied');\n\n const fixturesDir = await dirHandle.getDirectoryHandle('fixtures', { create: true });\n const fileHandle = await fixturesDir.getFileHandle(filename, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(bytes);\n await writable.close();\n }\n\n async requestDirectoryPermissions(): Promise<void> {\n if (!('showDirectoryPicker' in window)) {\n throw new Error('File System Access API not supported');\n }\n const dirHandle = await window.showDirectoryPicker();\n await this.setConfigKey('cypressDirectoryHandle', dirHandle);\n await this.setConfigKey('allowReadWriteFiles', 'true');\n }\n\n /**\n * Writes captured fixtures into `cypress/fixtures/` using the configured Cypress\n * folder handle (spec 012). Returns the number written. Throws if no folder is\n * configured or write permission is denied.\n */\n async writeFixtures(fixtures: Array<{ name: string; content: string }>): Promise<number> {\n if (!fixtures.length) return 0;\n const config = await this.getGeneralConfig();\n const dirHandle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\n if (!dirHandle) throw new Error('No Cypress folder configured');\n\n const perm = dirHandle as unknown as FileSystemHandleWithPermission;\n let state = await perm.queryPermission({ mode: 'readwrite' });\n if (state !== 'granted') state = await perm.requestPermission({ mode: 'readwrite' });\n if (state !== 'granted') throw new Error('Write permission denied');\n\n const fixturesDir = await dirHandle.getDirectoryHandle('fixtures', { create: true });\n let written = 0;\n for (const fx of fixtures) {\n const fileHandle = await fixturesDir.getFileHandle(fx.name, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(fx.content);\n await writable.close();\n written++;\n }\n return written;\n }\n\n private async bulkInsertWithoutId(store: string, items: Record<string, unknown>[]): Promise<void> {\n if (!Array.isArray(items)) return;\n const db = await this.getDB();\n for (const item of items) {\n const { id: _id, ...rest } = item;\n await db.add(store, rest);\n }\n }\n}\n","export type IssueTrackerProvider = 'jira' | 'github' | 'gitlab' | 'azure' | 'bitbucket' | 'custom';\n\nexport interface IssueTrackerPreset {\n id: IssueTrackerProvider;\n label: string;\n urlPattern: string;\n idPattern: RegExp;\n}\n\nexport const ISSUE_TRACKER_PRESETS: Record<IssueTrackerProvider, IssueTrackerPreset> = {\n jira: { id: 'jira', label: 'Jira', urlPattern: '{baseUrl}/browse/{id}', idPattern: /^[A-Z][A-Z0-9]+-\\d+$/ },\n github: { id: 'github', label: 'GitHub Issues', urlPattern: '{baseUrl}/issues/{id}', idPattern: /^\\d+$/ },\n gitlab: { id: 'gitlab', label: 'GitLab Issues', urlPattern: '{baseUrl}/-/issues/{id}', idPattern: /^\\d+$/ },\n azure: { id: 'azure', label: 'Azure DevOps', urlPattern: '{baseUrl}/_workitems/edit/{id}', idPattern: /^\\d+$/ },\n bitbucket: { id: 'bitbucket', label: 'Bitbucket Issues',urlPattern: '{baseUrl}/issues/{id}', idPattern: /^\\d+$/ },\n custom: { id: 'custom', label: 'Custom', urlPattern: '{baseUrl}/{id}', idPattern: /.+/ },\n};\n\nexport interface IssueTrackerConfig {\n enabled: boolean;\n provider: IssueTrackerProvider;\n baseUrl: string;\n}\n\nexport const DEFAULT_ISSUE_TRACKER_CONFIG: IssueTrackerConfig = {\n enabled: false,\n provider: 'jira',\n baseUrl: '',\n};\n","import { ISSUE_TRACKER_PRESETS, type IssueTrackerConfig, type IssueTrackerProvider } from '../models/issue-tracker.model';\n\nexport function buildTicketUrl(ticketId: string, config: IssueTrackerConfig): string | null {\n if (!config.enabled || !ticketId.trim() || !config.baseUrl.trim()) return null;\n const preset = ISSUE_TRACKER_PRESETS[config.provider];\n const base = config.baseUrl.replace(/\\/+$/, '');\n return preset.urlPattern.replace('{baseUrl}', base).replace('{id}', encodeURIComponent(ticketId.trim()));\n}\n\nexport function buildTicketComment(ticketId: string): string {\n return `// Ticket: ${ticketId.trim()}`;\n}\n\nexport function isValidTicketId(ticketId: string, provider: IssueTrackerProvider): boolean {\n if (!ticketId.trim()) return false;\n return ISSUE_TRACKER_PRESETS[provider].idPattern.test(ticketId.trim());\n}\n","import { type RecordingService } from './recording.service';\nimport { escapeSingleQuotes } from '../utils/code-format.utils';\nimport { redactSensitiveFields } from '../utils/redact.utils';\n\nconst INTERCEPTED_METHODS = ['GET', 'POST', 'PUT'] as const;\ntype InterceptedMethod = (typeof INTERCEPTED_METHODS)[number];\n\nexport function generateAlias(method: string, url: string): string {\n try {\n const u = new URL(url, 'http://localhost');\n const path = u.pathname\n .replace(/[^a-zA-Z0-9]/g, '-')\n .replace(/-+/g, '-')\n .replace(/(^-)|(-$)/g, '');\n return `${method.toLowerCase()}-${path}`;\n } catch {\n return `${method.toLowerCase()}-intercepted-request`;\n }\n}\n\nconst SAFE_IDENTIFIER = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;\n\nfunction buildValidations(base: string, obj: Record<string, unknown>): string {\n return Object.keys(obj)\n .filter((key) => key !== 'id' && key !== 'uid')\n .map((key) => {\n const accessor = SAFE_IDENTIFIER.test(key)\n ? `.${key}`\n : `['${escapeSingleQuotes(key)}']`;\n return `expect(${base}${accessor}).to.equal(${JSON.stringify(obj[key])});`;\n })\n .join('\\n');\n}\n\nfunction buildCyWaitCommand(\n method: string,\n alias: string,\n extendedHttp: boolean,\n requestBody: Record<string, unknown> | null,\n responseBody: Record<string, unknown> | null\n): string {\n if (extendedHttp && method === 'GET' && responseBody) {\n const validations = buildValidations('interception.response.body', responseBody);\n return `cy.wait('@${alias}').then((interception) => {\\n if (interception.response) {\\n${validations}\\n }\\n})`;\n }\n if (extendedHttp && (method === 'POST' || method === 'PUT') && requestBody) {\n const validations = buildValidations('interception.request.body', requestBody);\n return `cy.wait('@${alias}').then((interception) => {\\n${validations}\\n})`;\n }\n return `cy.wait('@${alias}').then((interception) => { })`;\n}\n\nfunction parseJsonObject(text: string): Record<string, unknown> | null {\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n } catch {\n // Non-JSON or array — fall through\n }\n return null;\n}\n\n/** Returns pretty-printed JSON (objects OR arrays) for a fixture, or null. */\nfunction prettyJsonOrNull(text: string): string | null {\n try {\n const parsed = JSON.parse(text);\n if (parsed && typeof parsed === 'object') return JSON.stringify(parsed, null, 2);\n } catch {\n // not JSON\n }\n return null;\n}\n\nfunction parseRequestBody(init?: RequestInit): Record<string, unknown> | null {\n const body = init?.body;\n if (typeof body === 'string') return parseJsonObject(body);\n return null;\n}\n\nfunction resolveUrl(input: RequestInfo | URL): string {\n if (typeof input === 'string') return input;\n if (input instanceof URL) return input.href;\n return input.url;\n}\n\nfunction resolveMethod(input: RequestInfo | URL, init?: RequestInit): string {\n if (init?.method) return init.method.toUpperCase();\n if (input instanceof Request) return input.method.toUpperCase();\n return 'GET';\n}\n\n// ─── module-level interception handlers ──────────────────────────────────────\n\nasync function _handleFetchInterception(\n recording: RecordingService,\n input: RequestInfo | URL,\n init: RequestInit | undefined,\n responseClone: Response\n): Promise<void> {\n const method = resolveMethod(input, init);\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method)) return;\n\n const url = resolveUrl(input);\n const alias = generateAlias(method, url);\n\n recording.registerInterceptor(method, url, alias);\n\n // Must be synchronous — we are inside an active fetch interception handler.\n // IndexedDB would require await and is not viable here; localStorage is the\n // sync cache kept fresh by initHttpConfig() on recorder mount.\n const extendedHttp = localStorage.getItem('extendedHttpCommands') === 'true';\n const fixtureMode = localStorage.getItem('fixtureMode') === 'true';\n const requestBody = extendedHttp ? parseRequestBody(init) : null;\n\n let responseText: string | null = null;\n let responseBody: Record<string, unknown> | null = null;\n\n if (extendedHttp || (fixtureMode && method === 'GET')) {\n try {\n responseText = await responseClone.text();\n if (extendedHttp) responseBody = parseJsonObject(responseText);\n } catch {\n // Unreadable body — continue without validations\n }\n }\n\n if (fixtureMode && method === 'GET' && responseText !== null) {\n const pretty = prettyJsonOrNull(responseText);\n if (pretty !== null) {\n const redacted = redactSensitiveFields(JSON.parse(pretty));\n recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));\n }\n }\n\n const cmd = buildCyWaitCommand(\n method, alias, extendedHttp,\n requestBody ? redactSensitiveFields(requestBody) as Record<string, unknown> : null,\n responseBody ? redactSensitiveFields(responseBody) as Record<string, unknown> : null,\n );\n recording.addCommand(cmd);\n}\n\nfunction _handleXhrInterception(\n recording: RecordingService,\n method: string,\n url: string,\n requestBody: Record<string, unknown> | null,\n responseText: string\n): void {\n if (!(INTERCEPTED_METHODS as readonly string[]).includes(method as InterceptedMethod)) return;\n\n const alias = generateAlias(method, url);\n\n recording.registerInterceptor(method, url, alias);\n\n // Same sync-cache rationale as in _handleFetchInterception above.\n if (localStorage.getItem('fixtureMode') === 'true' && method === 'GET') {\n const pretty = prettyJsonOrNull(responseText);\n if (pretty !== null) {\n const redacted = redactSensitiveFields(JSON.parse(pretty));\n recording.registerFixture(`${alias}.json`, JSON.stringify(redacted, null, 2));\n }\n }\n\n const extendedHttp = localStorage.getItem('extendedHttpCommands') === 'true';\n const responseBody = extendedHttp ? parseJsonObject(responseText) : null;\n\n const cmd = buildCyWaitCommand(\n method, alias, extendedHttp,\n requestBody ? redactSensitiveFields(requestBody) as Record<string, unknown> : null,\n responseBody ? redactSensitiveFields(responseBody) as Record<string, unknown> : null,\n );\n recording.addCommand(cmd);\n}\n\n// ─── module-level singleton state ────────────────────────────────────────────\n\nlet _refCount = 0;\nlet _originalFetch: typeof window.fetch | null = null;\nlet _originalXHR: typeof XMLHttpRequest | null = null;\nconst _recordings = new Set<RecordingService>();\n\nfunction _patchFetch(): void {\n const orig = window.fetch;\n _originalFetch = orig;\n\n window.fetch = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const response = await orig(input, init);\n try {\n const active = [..._recordings];\n if (active.length > 0) {\n await Promise.all(\n active.map((rec) => _handleFetchInterception(rec, input, init, response.clone()).catch(() => {}))\n );\n }\n } catch {\n // Never let monitoring errors break the actual request\n }\n return response;\n };\n}\n\nfunction _restoreFetch(): void {\n if (!_originalFetch) return;\n window.fetch = _originalFetch;\n _originalFetch = null;\n}\n\nfunction _patchXhr(): void {\n const OrigXHR = window.XMLHttpRequest;\n _originalXHR = OrigXHR;\n\n window.XMLHttpRequest = class extends OrigXHR {\n private _xhrMethod = 'GET';\n private _xhrUrl = '';\n private _xhrRequestBody: Record<string, unknown> | null = null;\n\n override open(\n method: string,\n url: string | URL,\n async = true,\n user?: string | null,\n password?: string | null\n ): void {\n this._xhrMethod = method.toUpperCase();\n this._xhrUrl = url instanceof URL ? url.href : url;\n super.open(method, url as string, async, user, password);\n }\n\n override send(body?: Document | XMLHttpRequestBodyInit | null): void {\n if (typeof body === 'string') {\n this._xhrRequestBody = parseJsonObject(body);\n }\n this.addEventListener('load', () => {\n try {\n for (const rec of _recordings) {\n _handleXhrInterception(rec, this._xhrMethod, this._xhrUrl, this._xhrRequestBody, this.responseText);\n }\n } catch {\n // Never let monitoring errors surface\n }\n });\n super.send(body);\n }\n } as unknown as typeof XMLHttpRequest;\n}\n\nfunction _restoreXhr(): void {\n if (!_originalXHR) return;\n window.XMLHttpRequest = _originalXHR;\n _originalXHR = null;\n}\n\n/** @internal — resets singleton state between test suites; do not use in production code */\nexport function _resetHttpMonitorState(): void {\n _refCount = 0;\n _originalFetch = null;\n _originalXHR = null;\n _recordings.clear();\n}\n\n// ─── HttpMonitor — public API (thin wrapper over the module-level singleton) ─\n\nexport class HttpMonitor {\n constructor(private readonly recording: RecordingService) {}\n\n install(): void {\n _recordings.add(this.recording);\n _refCount++;\n if (_refCount === 1) {\n _patchFetch();\n _patchXhr();\n }\n }\n\n uninstall(): void {\n _recordings.delete(this.recording);\n if (_refCount <= 0) return;\n _refCount--;\n if (_refCount === 0) {\n _restoreFetch();\n _restoreXhr();\n }\n }\n\n isExtendedHttpEnabled(): boolean {\n return localStorage.getItem('extendedHttpCommands') === 'true';\n }\n\n isFixtureModeEnabled(): boolean {\n return localStorage.getItem('fixtureMode') === 'true';\n }\n}\n","// Substrings that unambiguously mark a key as sensitive. Matched against the\n// normalized key (lowercased, non-alphanumerics stripped), so `access_token`,\n// `X-Api-Key` and `refreshToken` all collapse to a form these can catch. These\n// are safe as substrings — none appears inside a common non-sensitive key.\nconst SENSITIVE_SUBSTRINGS = [\n 'password',\n 'passwd',\n 'passphrase',\n 'secret',\n 'token', // access_token, refresh_token, id_token, csrf_token…\n 'apikey', // api_key, x-api-key — NOT bare \"key\" (avoids \"normalKey\")\n 'authorization',\n 'cookie',\n 'credential',\n 'privatekey',\n 'sessionid',\n 'creditcard',\n 'cardnumber',\n 'cvv',\n];\n\n// Short / ambiguous names that would over-match as substrings (e.g. \"auth\" ⊂\n// \"author\", \"pin\" ⊂ \"shipping\"), so they are matched only as the WHOLE key.\nconst SENSITIVE_EXACT = new Set([\n 'auth',\n 'pwd',\n 'pin',\n 'otp',\n 'ssn',\n]);\n\nfunction normalizeKey(key: string): string {\n return key.toLowerCase().replace(/[^a-z0-9]/g, '');\n}\n\nexport function isSensitiveKey(key: string): boolean {\n const normalized = normalizeKey(key);\n if (SENSITIVE_EXACT.has(normalized)) return true;\n return SENSITIVE_SUBSTRINGS.some((s) => normalized.includes(s));\n}\n\n/**\n * Recursively replaces values for sensitive keys with the literal string\n * \"[REDACTED]\". A key is sensitive if, once normalized (lowercased, separators\n * stripped), it contains a known credential substring (password, secret, token,\n * apikey, authorization, cookie, credential, privatekey, sessionid, card data)\n * or exactly equals a short marker (auth, pwd, pin, otp, ssn). Case-insensitive\n * and separator-insensitive so `access_token`, `X-Api-Key`, `clientSecret` and\n * `refreshToken` are all caught.\n *\n * Safe for use before writing fixtures or generating cy.wait validations —\n * credentials never reach generated test code. Returns a new object/array; the\n * original is never mutated.\n */\nexport function redactSensitiveFields(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map(redactSensitiveFields);\n }\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n result[key] = isSensitiveKey(key) ? '[REDACTED]' : redactSensitiveFields(value);\n }\n return result;\n }\n return obj;\n}\n","export const SCROLLBAR_STYLES = `\n.swal2-popup::-webkit-scrollbar,\n.swal2-html-container::-webkit-scrollbar,\n.swal2-content::-webkit-scrollbar,\n.swal2-container::-webkit-scrollbar {\n width: 5px;\n height: 5px;\n background: transparent;\n}\n.swal2-popup::-webkit-scrollbar-thumb,\n.swal2-html-container::-webkit-scrollbar-thumb,\n.swal2-content::-webkit-scrollbar-thumb,\n.swal2-container::-webkit-scrollbar-thumb {\n background: #30363d;\n border-radius: 3px;\n}\n.swal2-popup::-webkit-scrollbar-thumb:hover,\n.swal2-html-container::-webkit-scrollbar-thumb:hover,\n.swal2-content::-webkit-scrollbar-thumb:hover {\n background: #484f58;\n}\n.swal2-popup::-webkit-scrollbar-track,\n.swal2-html-container::-webkit-scrollbar-track,\n.swal2-content::-webkit-scrollbar-track,\n.swal2-container::-webkit-scrollbar-track {\n background: transparent;\n}\n.swal2-popup, .swal2-html-container, .swal2-content, .swal2-container {\n scrollbar-width: thin;\n scrollbar-color: #30363d transparent;\n}\n`;\n\nexport const LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES = `\n.swal2-container, .swal2-popup {\n z-index: 99999 !important;\n}\n.swal2-container {\n padding: 0 !important;\n align-items: center !important;\n justify-content: center !important;\n}\n.swal2-popup {\n background: #161b22 !important;\n color: #e6edf3 !important;\n border-radius: 12px !important;\n box-shadow: 0 24px 64px rgba(0,0,0,0.72), 0 0 0 1px #30363d !important;\n border: none !important;\n padding: 0 !important;\n min-width: 400px;\n max-width: 90vw;\n min-height: 200px;\n max-height: 90vh;\n}\n/* Override SweetAlert2 v11's display:grid on .swal2-popup.swal2-modal */\n.swal2-popup.swal2-modal {\n display: flex !important;\n flex-direction: column !important;\n align-items: stretch !important;\n overflow: hidden !important;\n}\n.swal2-header {\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n overflow: hidden !important;\n}\n.swal2-title {\n color: #e6edf3 !important;\n font-weight: 600 !important;\n font-size: 14px !important;\n background: #161b22;\n padding: 14px 48px 13px 18px !important;\n margin: 0 !important;\n border-bottom: 1px solid #21262d;\n text-align: left !important;\n letter-spacing: 0.1px;\n white-space: nowrap !important;\n overflow: hidden !important;\n text-overflow: ellipsis !important;\n}\n.swal2-close {\n position: absolute !important;\n top: 10px !important;\n right: 12px !important;\n color: #8b949e !important;\n font-size: 1.1rem !important;\n z-index: 1 !important;\n border-radius: 6px !important;\n width: 28px !important;\n height: 28px !important;\n line-height: 28px !important;\n transition: background 0.15s, color 0.15s !important;\n}\n.swal2-close:hover {\n background: #21262d !important;\n color: #e6edf3 !important;\n}\n/* In SweetAlert2 v11, .swal2-html-container is a direct child of .swal2-popup */\n.swal2-html-container {\n flex: 1 !important;\n min-height: 0 !important;\n background: #161b22;\n padding: 0 !important;\n margin: 0 !important;\n width: 100%;\n display: flex !important;\n flex-direction: column !important;\n align-items: stretch;\n box-sizing: border-box;\n overflow: hidden !important;\n /* Left-align modal body text/code (SweetAlert defaults it to centre, which\n inherits into the panels — including their shadow DOM). Titles/buttons keep\n their own alignment. */\n text-align: left !important;\n}\n/* The single wrapper div we inject inside each modal fills the container */\n.swal2-html-container > div {\n flex: 1 !important;\n min-height: 0 !important;\n display: flex !important;\n flex-direction: column !important;\n overflow: hidden !important;\n}\n.swal2-actions, .swal2-footer {\n flex-shrink: 0 !important;\n flex-grow: 0 !important;\n}\n`;\n\nexport function injectStyles(css: string, id: string): void {\n if (document.getElementById(id)) return;\n const style = document.createElement('style');\n style.id = id;\n style.innerHTML = css;\n document.head.appendChild(style);\n}\n","export function makeModalResizable(\n modal: HTMLElement,\n options?: { minWidth?: number; minHeight?: number }\n): () => void {\n if (!modal || modal.querySelector('.modal-resizer')) return () => { /* no-op */ };\n\n const rect = modal.getBoundingClientRect();\n modal.style.position = 'fixed';\n modal.style.top = `${rect.top}px`;\n modal.style.left = `${rect.left}px`;\n modal.style.width = `${rect.width}px`;\n modal.style.margin = '0';\n modal.style.resize = 'both';\n modal.style.overflow = 'hidden';\n modal.style.minWidth = (options?.minWidth ?? 320) + 'px';\n modal.style.minHeight = (options?.minHeight ?? 180) + 'px';\n\n const resizer = document.createElement('div');\n resizer.className = 'modal-resizer';\n resizer.style.position = 'absolute';\n resizer.style.width = '16px';\n resizer.style.height = '16px';\n resizer.style.right = '2px';\n resizer.style.bottom = '2px';\n resizer.style.cursor = 'nwse-resize';\n resizer.style.background = 'rgba(0,0,0,0.1)';\n resizer.style.zIndex = '10';\n modal.appendChild(resizer);\n\n let isResizing = false;\n let lastX = 0;\n let lastY = 0;\n\n const mouseMove = (e: MouseEvent): void => {\n if (!isResizing) return;\n const dx = e.clientX - lastX;\n const dy = e.clientY - lastY;\n lastX = e.clientX;\n lastY = e.clientY;\n const rect = modal.getBoundingClientRect();\n modal.style.width = rect.width + dx + 'px';\n modal.style.height = rect.height + dy + 'px';\n };\n\n const mouseUp = (): void => {\n isResizing = false;\n document.body.style.userSelect = '';\n };\n\n resizer.addEventListener('mousedown', (e) => {\n e.preventDefault();\n isResizing = true;\n lastX = e.clientX;\n lastY = e.clientY;\n document.body.style.userSelect = 'none';\n });\n\n window.addEventListener('mousemove', mouseMove);\n window.addEventListener('mouseup', mouseUp);\n\n return () => {\n window.removeEventListener('mousemove', mouseMove);\n window.removeEventListener('mouseup', mouseUp);\n if (resizer.parentNode) resizer.parentNode.removeChild(resizer);\n };\n}\n\nfunction applyDraggable(swal: HTMLElement, dragArea: HTMLElement): void {\n let isDragging = false;\n let offsetX = 0;\n let offsetY = 0;\n\n dragArea.style.cursor = 'move';\n dragArea.onmousedown = (e: MouseEvent) => {\n isDragging = true;\n const rect = swal.getBoundingClientRect();\n offsetX = e.clientX - rect.left;\n offsetY = e.clientY - rect.top;\n document.onmousemove = (ev: MouseEvent) => {\n if (isDragging) {\n swal.style.position = 'fixed';\n swal.style.margin = '0';\n swal.style.left = `${ev.clientX - offsetX}px`;\n swal.style.top = `${ev.clientY - offsetY}px`;\n }\n };\n document.onmouseup = () => {\n isDragging = false;\n document.onmousemove = null;\n document.onmouseup = null;\n };\n };\n}\n\nfunction resolveDragArea(swal: HTMLElement): HTMLElement | null {\n return (swal.querySelector('.swal2-header') as HTMLElement | null)\n ?? (swal.querySelector('.swal2-title') as HTMLElement | null);\n}\n\nexport function makeSwalDraggable(): void {\n const popups = document.querySelectorAll('.swal2-popup');\n if (!popups.length) return;\n const swal = popups[popups.length - 1] as HTMLElement;\n const dragArea = resolveDragArea(swal);\n if (!dragArea) return;\n applyDraggable(swal, dragArea);\n}\n\nexport function makeSwalDraggableByContentId(contentId: string): void {\n const content = document.getElementById(contentId);\n if (!content) {\n makeSwalDraggable();\n return;\n }\n const swal = (content.closest('.swal2-popup') as HTMLElement | null)\n ?? (document.querySelector('.swal2-popup') as HTMLElement | null);\n if (!swal) return;\n const dragArea = resolveDragArea(swal);\n if (!dragArea) return;\n applyDraggable(swal, dragArea);\n}\n\nexport function setSwal2DataCyAttribute(dataCy = 'lib-e2e-cypress-for-dummys'): void {\n document.querySelector('.swal2-container')?.setAttribute('data-cy', dataCy);\n document.querySelector('.swal2-html-container')?.setAttribute('data-cy', dataCy);\n document.querySelector('.swal2-title')?.setAttribute('data-cy', dataCy);\n}\n\nexport function ensurePopupDimensions(popup: HTMLElement | null, heightPx: number): void {\n if (!popup) return;\n popup.style.height = `${heightPx}px`;\n const htmlContainer = popup.querySelector('.swal2-html-container') as HTMLElement | null;\n if (!htmlContainer) return;\n htmlContainer.style.flex = '1';\n htmlContainer.style.minHeight = '0';\n htmlContainer.style.overflow = 'hidden';\n htmlContainer.style.padding = '0';\n htmlContainer.style.margin = '0';\n htmlContainer.style.display = 'flex';\n htmlContainer.style.flexDirection = 'column';\n}\n","export function showToast(message: string, isSuccess = true): void {\n const toast = document.createElement('div');\n toast.textContent = message;\n toast.style.position = 'fixed';\n toast.style.top = '30px';\n toast.style.right = '30px';\n toast.style.padding = '16px 24px';\n toast.style.background = isSuccess ? '#4caf50' : '#f44336';\n toast.style.color = '#fff';\n toast.style.borderRadius = '8px';\n toast.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)';\n toast.style.zIndex = '9999';\n toast.style.fontSize = '1rem';\n toast.style.fontWeight = 'bold';\n toast.style.pointerEvents = 'none';\n document.body.appendChild(toast);\n setTimeout(() => toast.remove(), 3000);\n}\n","import type { TestWithDetails } from '../services/persistence.service';\n\n/** How the user chose which tests to export. */\nexport type ExportMode = 'all' | 'manual' | 'tags';\n\nexport interface ExportSelectionOptions {\n /** Test ids to include in `manual` mode. */\n ids?: Iterable<number>;\n /** Tags to match in `tags` mode. */\n tags?: Iterable<string>;\n}\n\n/**\n * Returns the subset of tests to export for a given selection mode.\n *\n * - `all` → every test (a shallow copy).\n * - `manual` → tests whose id is in `opts.ids`. Empty/absent ids → none.\n * - `tags` → tests carrying at least one of `opts.tags` (OR semantics).\n * Empty/absent tags → none.\n *\n * Pure: never mutates its inputs.\n */\nexport function selectTestsForExport(\n tests: TestWithDetails[],\n mode: ExportMode,\n opts: ExportSelectionOptions = {},\n): TestWithDetails[] {\n if (mode === 'all') return [...tests];\n\n if (mode === 'manual') {\n const ids = new Set(opts.ids ?? []);\n return tests.filter((t) => ids.has(t.id));\n }\n\n // 'tags' — include a test if it carries ANY of the selected tags (OR).\n const tags = new Set(opts.tags ?? []);\n if (tags.size === 0) return [];\n return tests.filter((t) => (t.tags ?? []).some((tag) => tags.has(tag)));\n}\n","/**\n * True when a hostname refers to the local machine — used to gate dev-only\n * features (e.g. launching a Cypress run via the local runner) so they are\n * offered only when the app is served locally, not from a deployed environment.\n *\n * Treats as local: localhost, *.localhost, 127.0.0.1, ::1, 0.0.0.0, and the\n * empty hostname (e.g. file:// URLs). Case-insensitive.\n */\nexport function isLocalHost(hostname: string): boolean {\n if (!hostname) return true;\n const h = hostname.toLowerCase();\n return (\n h === 'localhost' ||\n h.endsWith('.localhost') ||\n h === '127.0.0.1' ||\n h === '::1' ||\n h === '0.0.0.0'\n );\n}\n","export const TEST_PREVISUALIZER_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; gap: 6px; padding: 10px 12px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d;\n }\n button {\n padding: 5px 12px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s; letter-spacing: 0.1px;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button.active { background: #2f81f7; color: #fff; }\n .section { padding: 10px 12px; flex-shrink: 0; }\n .section.section-cmds { flex: 1; min-height: 0; display: flex; flex-direction: column; }\n .section-title {\n font-size: 10px; font-weight: 600; color: #484f58; text-transform: uppercase;\n letter-spacing: 0.8px; margin-bottom: 7px; flex-shrink: 0;\n }\n .list {\n overflow-y: auto; background: #0d1117;\n border-radius: 8px; padding: 6px 8px;\n border: 1px solid #21262d;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .section-cmds .list { flex: 1; min-height: 0; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .item {\n display: flex; align-items: flex-start; gap: 6px;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n color: #c9d1d9; padding: 4px 8px; border-radius: 4px;\n word-break: break-all; line-height: 1.65;\n border-left: 2px solid transparent;\n transition: background 0.1s, border-color 0.1s;\n }\n .item:hover { background: #161b22; border-left-color: #2f81f7; }\n .cmd-text { flex: 1; }\n .item-actions {\n display: flex; gap: 3px; flex-shrink: 0;\n opacity: 0; transition: opacity 0.15s;\n }\n .item:hover .item-actions { opacity: 1; }\n .btn-step {\n width: 20px; height: 20px; border: none; border-radius: 3px; cursor: pointer;\n font-size: 12px; background: transparent; color: #484f58;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; justify-content: center;\n padding: 0; line-height: 1;\n }\n .btn-step:hover { background: #30363d; color: #e6edf3; }\n .btn-step-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n .empty { color: #484f58; font-size: 12px; padding: 20px 8px; text-align: center; }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport function renderTestPrevisualizer(\n commands: string[],\n interceptors: string[],\n showInterceptors: boolean,\n editable: boolean,\n t: (key: string) => string,\n): string {\n const editControls = (idx: number, total: number) => editable ? `\n <span class=\"item-actions\">\n <button class=\"btn-step\" data-move-up=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.UP_TITLE')}\" ${idx === 0 ? 'disabled style=\"opacity:.3\"' : ''}>↑</button>\n <button class=\"btn-step\" data-move-dn=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DOWN_TITLE')}\" ${idx === total - 1 ? 'disabled style=\"opacity:.3\"' : ''}>↓</button>\n <button class=\"btn-step btn-step-del\" data-del=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button>\n </span>` : '';\n\n const cmdItems = commands.length\n ? commands.map((c, i) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(c)}</span>\n ${editControls(i, commands.length)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_CMDS_YET')}</div>`;\n\n const icpEditControls = (idx: number) => editable\n ? `<span class=\"item-actions\"><button class=\"btn-step btn-step-del\" data-del-icp=\"${idx}\" title=\"${t('TEST_PREVISUALIZER.DEL_TITLE')}\">✕</button></span>`\n : '';\n\n const icpSection = showInterceptors\n ? `<div class=\"section\" data-section=\"interceptors\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.INTERCEPTORS')}</div>\n <div class=\"list\">\n ${\n interceptors.length\n ? interceptors.map((ic, idx) => `\n <div class=\"item\">\n <span class=\"cmd-text\">${escHtml(ic)}</span>\n ${icpEditControls(idx)}\n </div>`).join('')\n : `<div class=\"empty\">${t('TEST_PREVISUALIZER.NO_ICP_SHORT')}</div>`\n }\n </div>\n <button style=\"margin-top:6px\" data-action=\"copy-icp\">${t('TEST_PREVISUALIZER.COPY_ICP_BTN')}</button>\n </div>`\n : '';\n\n return `\n <div class=\"toolbar\">\n <button data-action=\"copy\">${t('TEST_PREVISUALIZER.COPY_CMDS_BTN')}</button>\n <button data-action=\"toggle-icp\" class=\"${showInterceptors ? 'active' : ''}\">\n ${showInterceptors ? t('TEST_PREVISUALIZER.HIDE_INTERCEPTORS') : t('TEST_PREVISUALIZER.SHOW_INTERCEPTORS')} (${interceptors.length})\n </button>\n </div>\n <div class=\"section section-cmds\">\n <div class=\"section-title\">${t('TEST_PREVISUALIZER.SECTION_COMMANDS')} (${commands.length})</div>\n <div class=\"list\" data-ref=\"cmds\">${cmdItems}</div>\n </div>\n ${icpSection}`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { TEST_PREVISUALIZER_STYLES } from './test-previsualizer.styles';\nimport { renderTestPrevisualizer } from './test-previsualizer.template';\n\nexport class TestPrevisualizerElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _commands: string[] = [];\n private _interceptors: string[] = [];\n private _showInterceptors = false;\n editable = false;\n translation: TranslationService = translationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n this.render();\n }\n\n get commands(): string[] {\n return this._commands;\n }\n set commands(v: string[]) {\n this._commands = v;\n this.render();\n }\n\n get interceptors(): string[] {\n return this._interceptors;\n }\n set interceptors(v: string[]) {\n this._interceptors = v;\n this.render();\n }\n\n get showInterceptors(): boolean {\n return this._showInterceptors;\n }\n\n toggleInterceptors(): void {\n this._showInterceptors = !this._showInterceptors;\n this.render();\n }\n\n copyToClipboard(): void {\n const text = this._commands.join('\\n');\n if (!text) return;\n navigator.clipboard?.writeText(text);\n }\n\n copyInterceptorsToClipboard(): void {\n const text = this._interceptors.join('\\n');\n if (!text) return;\n navigator.clipboard?.writeText(text);\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private dispatchDelete(index: number): void {\n this.dispatchEvent(new CustomEvent('deletecommand', { detail: index, bubbles: true, composed: true }));\n }\n\n private dispatchMove(from: number, to: number): void {\n this.dispatchEvent(new CustomEvent('movecommand', { detail: { from, to }, bubbles: true, composed: true }));\n }\n\n private dispatchDeleteInterceptor(index: number): void {\n this.dispatchEvent(new CustomEvent('deleteinterceptor', { detail: index, bubbles: true, composed: true }));\n }\n\n private render(): void {\n this.shadow.innerHTML = `<style>${TEST_PREVISUALIZER_STYLES}</style>${renderTestPrevisualizer(\n this._commands,\n this._interceptors,\n this._showInterceptors,\n this.editable,\n this.t.bind(this),\n )}`;\n\n const cmdsEl = this.shadow.querySelector<HTMLElement>('[data-ref=\"cmds\"]');\n if (cmdsEl) cmdsEl.scrollTop = cmdsEl.scrollHeight;\n\n this.shadow.querySelector('[data-action=\"copy\"]')?.addEventListener('click', () => this.copyToClipboard());\n this.shadow.querySelector('[data-action=\"toggle-icp\"]')?.addEventListener('click', () => this.toggleInterceptors());\n this.shadow.querySelector('[data-action=\"copy-icp\"]')?.addEventListener('click', () => this.copyInterceptorsToClipboard());\n\n if (this.editable) {\n this.shadow.querySelectorAll('[data-del]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.dispatchDelete(Number((btn as HTMLElement).dataset['del']));\n });\n });\n this.shadow.querySelectorAll('[data-move-up]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const idx = Number((btn as HTMLElement).dataset['moveUp']);\n this.dispatchMove(idx, idx - 1);\n });\n });\n this.shadow.querySelectorAll('[data-move-dn]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const idx = Number((btn as HTMLElement).dataset['moveDn']);\n this.dispatchMove(idx, idx + 1);\n });\n });\n this.shadow.querySelectorAll('[data-del-icp]').forEach((btn) => {\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.dispatchDeleteInterceptor(Number((btn as HTMLElement).dataset['delIcp']));\n });\n });\n }\n }\n}\n\nif (!customElements.get('lib-e2e-test-previsualizer')) {\n customElements.define('lib-e2e-test-previsualizer', TestPrevisualizerElement);\n}\n","export const SAVE_TEST_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { padding: 24px 28px; text-align: left; }\n .btn-row { text-align: center; }\n p { margin: 0 0 20px; font-size: 14px; color: #8b949e; line-height: 1.5; }\n .btn-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }\n button {\n padding: 7px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; transition: filter 0.15s, transform 0.1s;\n letter-spacing: 0.1px;\n }\n button:hover { filter: brightness(1.1); }\n button:active { transform: scale(0.97); }\n .btn-primary { background: #2f81f7; color: #fff; }\n .btn-success { background: #3fb950; color: #fff; }\n .btn-danger { background: transparent; color: #f85149; border: 1px solid rgba(248,81,73,0.5); }\n .btn-danger:hover { background: rgba(248,81,73,0.08); filter: none; }\n input[type=\"text\"] {\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\n border-radius: 8px; background: #0d1117; color: #e6edf3;\n font-size: 14px; outline: none; margin-bottom: 4px;\n transition: border-color 0.15s, box-shadow 0.15s;\n }\n input[type=\"text\"]:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\n input[type=\"text\"]::placeholder { color: #484f58; }\n textarea {\n width: 100%; padding: 10px 14px; border: 1px solid #30363d;\n border-radius: 8px; background: #0d1117; color: #e6edf3;\n font-size: 14px; outline: none; margin-bottom: 4px;\n font-family: inherit; resize: vertical; line-height: 1.5;\n transition: border-color 0.15s, box-shadow 0.15s;\n }\n textarea:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.15); }\n textarea::placeholder { color: #484f58; }\n .tag-label {\n font-size: 11px; color: #484f58; text-align: left; margin-bottom: 5px; display: block;\n }\n .tag-input-row { display: flex; gap: 6px; margin-bottom: 8px; }\n .tag-input-row input[type=\"text\"] {\n font-size: 12px; padding: 6px 10px; margin: 0;\n }\n .btn-tag-add {\n padding: 6px 12px; font-size: 12px; background: #21262d; color: #8b949e;\n border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n transition: background 0.15s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-tag-add:hover { background: #30363d; color: #e6edf3; filter: none; }\n .chips { display: flex; flex-wrap: wrap; gap: 5px; min-height: 24px; text-align: left; }\n .chip {\n display: inline-flex; align-items: center; gap: 5px;\n background: rgba(47,129,247,0.15); color: #2f81f7;\n border: 1px solid rgba(47,129,247,0.3); border-radius: 20px;\n padding: 2px 10px 2px 10px; font-size: 11px; font-weight: 500;\n }\n .chip-del {\n cursor: pointer; color: #8b949e; font-size: 12px; line-height: 1;\n transition: color 0.12s; padding: 0; background: none; border: none;\n }\n .chip-del:hover { color: #f85149; filter: none; }\n .discard-warn { color: #e6edf3; font-size: 13px; margin-bottom: 20px; line-height: 1.5; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\n\nexport function renderSaveTestConfirmDiscard(t: (key: string) => string): string {\n return `\n <div class=\"container\">\n <p class=\"discard-warn\">⚠ ${t('SAVE_TEST.CONFIRM_DISCARD')}</p>\n <div class=\"btn-row\">\n <button class=\"btn-danger\" id=\"btn-confirm-discard\">${t('SAVE_TEST.CONFIRM_DISCARD_BTN')}</button>\n <button id=\"btn-back-discard\">${t('SAVE_TEST.BACK_BTN')}</button>\n </div>\n </div>`;\n}\n\nexport function renderSaveTestAsk(t: (key: string) => string): string {\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.ASK')}</p>\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-yes\">${t('SAVE_TEST.YES_CONTINUE')}</button>\n <button class=\"btn-danger\" id=\"btn-no\">${t('SAVE_TEST.NO_DISCARD')}</button>\n </div>\n </div>`;\n}\n\nexport function renderSaveTestDesc(description: string, notes: string, tags: string[], ticketId: string, issueTrackerEnabled: boolean, ticketWarn: boolean, t: (key: string) => string): string {\n const chipsHtml = tags.map((tag) =>\n `<span class=\"chip\">${escHtml(tag)}<button class=\"chip-del\" data-tag=\"${escAttr(tag)}\" title=\"${t('SAVE_TEST.REMOVE_TAG_TITLE')}\">✕</button></span>`\n ).join('');\n\n const ticketHtml = issueTrackerEnabled ? `\n <span class=\"tag-label\">${t('SAVE_TEST.TICKET_LABEL')}</span>\n <input id=\"ticket-input\" type=\"text\" placeholder=\"${escAttr(t('SAVE_TEST.TICKET_PLACEHOLDER'))}\"\n value=\"${escAttr(ticketId)}\" autocomplete=\"off\" />\n ${ticketWarn ? `<span class=\"ticket-warn\">⚠ ${t('SAVE_TEST.TICKET_WARN')}</span>` : ''}` : '';\n\n return `\n <div class=\"container\">\n <p>${t('SAVE_TEST.DESC_LABEL')} (<code>it()</code>):</p>\n <input id=\"desc-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.DESC_PLACEHOLDER')}\"\n value=\"${escAttr(description)}\" autocomplete=\"off\" />\n <span class=\"tag-label\">${t('SAVE_TEST.NOTES_LABEL')}</span>\n <textarea id=\"notes-input\" rows=\"3\" placeholder=\"${escAttr(t('SAVE_TEST.NOTES_PLACEHOLDER'))}\">${escHtml(notes)}</textarea>\n <span class=\"tag-label\">${t('SAVE_TEST.TAGS_LABEL')}</span>\n <div class=\"tag-input-row\">\n <input id=\"tag-input\" type=\"text\" placeholder=\"${t('SAVE_TEST.TAGS_PLACEHOLDER')}\" autocomplete=\"off\" />\n <button class=\"btn-tag-add\" id=\"btn-add-tag\">${t('SAVE_TEST.ADD_TAG')}</button>\n </div>\n <div class=\"chips\" id=\"chips-container\">${chipsHtml || `<span style=\"color:#484f58;font-size:11px\">${t('SAVE_TEST.NO_TAGS')}</span>`}</div>\n ${ticketHtml}\n <div class=\"btn-row\">\n <button class=\"btn-primary\" id=\"btn-confirm\">${t('SAVE_TEST.SAVE_BTN')}</button>\n <button class=\"btn-success\" id=\"btn-export\">${t('SAVE_TEST.SAVE_AND_EDIT')}</button>\n <button class=\"btn-danger\" id=\"btn-cancel\">${t('SAVE_TEST.CANCEL')}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { isValidTicketId } from '../../utils/ticket.utils';\nimport type { IssueTrackerConfig } from '../../models/issue-tracker.model';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG } from '../../models/issue-tracker.model';\nimport { SAVE_TEST_STYLES } from './save-test.styles';\nimport { renderSaveTestAsk, renderSaveTestDesc, renderSaveTestConfirmDiscard } from './save-test.template';\n\nexport class SaveTestElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _step: 'ask' | 'desc' | 'confirm-discard' = 'ask';\n private _stepBeforeDiscard: 'ask' | 'desc' = 'ask';\n description = '';\n notes = '';\n tags: string[] = [];\n ticketId = '';\n issueTrackerConfig: IssueTrackerConfig = DEFAULT_ISSUE_TRACKER_CONFIG;\n translation: TranslationService = translationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void { this.render(); }\n\n get step(): 'ask' | 'desc' | 'confirm-discard' { return this._step; }\n\n askSave(): void { this._step = 'desc'; this.render(); }\n\n confirmSave(): void { this.dispatch('savetest', { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() }); }\n\n confirmSaveAndExport(): void { this.dispatch('saveandexport', { description: this.description.trim(), notes: this.notes, tags: [...this.tags], ticketId: this.ticketId.trim() }); }\n\n cancel(): void {\n this._stepBeforeDiscard = this._step === 'confirm-discard' ? 'ask' : (this._step as 'ask' | 'desc');\n this._step = 'confirm-discard';\n this.render();\n }\n\n confirmDiscard(): void { this.dispatch('savetest', { description: null, notes: '', tags: [], ticketId: '' }); }\n\n backFromDiscard(): void { this._step = this._stepBeforeDiscard; this.render(); }\n\n restartComponent(): void { this._step = 'ask'; this.description = ''; this.notes = ''; this.tags = []; this.ticketId = ''; this.render(); }\n\n addTag(tag: string): void {\n const t = tag.trim().replace(/[,;]/g, '');\n if (t && !this.tags.includes(t)) {\n this.tags = [...this.tags, t];\n this.render();\n }\n }\n\n removeTag(tag: string): void {\n this.tags = this.tags.filter((t) => t !== tag);\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n get ticketIdWarning(): boolean {\n if (!this.ticketId.trim() || !this.issueTrackerConfig.enabled) return false;\n return !isValidTicketId(this.ticketId, this.issueTrackerConfig.provider);\n }\n\n private dispatch(type: string, detail: { description: string | null; notes: string; tags: string[]; ticketId: string }): void {\n this.dispatchEvent(new CustomEvent(type, { detail, bubbles: true, composed: true }));\n }\n\n private render(): void {\n if (this._step === 'confirm-discard') {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestConfirmDiscard(this.t.bind(this))}`;\n this.shadow.getElementById('btn-confirm-discard')?.addEventListener('click', () => this.confirmDiscard());\n this.shadow.getElementById('btn-back-discard')?.addEventListener('click', () => this.backFromDiscard());\n return;\n }\n if (this._step === 'ask') {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestAsk(this.t.bind(this))}`;\n this.shadow.getElementById('btn-yes')?.addEventListener('click', () => this.askSave());\n this.shadow.getElementById('btn-no')?.addEventListener('click', () => this.cancel());\n } else {\n this.shadow.innerHTML = `<style>${SAVE_TEST_STYLES}</style>${renderSaveTestDesc(this.description, this.notes, this.tags, this.ticketId, this.issueTrackerConfig.enabled, this.ticketIdWarning, this.t.bind(this))}`;\n\n const descInput = this.shadow.getElementById('desc-input') as HTMLInputElement;\n const notesInput = this.shadow.getElementById('notes-input') as HTMLTextAreaElement;\n const tagInput = this.shadow.getElementById('tag-input') as HTMLInputElement;\n const ticketInput = this.shadow.getElementById('ticket-input') as HTMLInputElement | null;\n\n descInput.addEventListener('input', () => { this.description = descInput.value; });\n notesInput.addEventListener('input', () => { this.notes = notesInput.value; });\n ticketInput?.addEventListener('input', () => { this.ticketId = ticketInput.value; this.render(); });\n\n const tryAddTag = () => {\n this.addTag(tagInput.value);\n tagInput.value = '';\n };\n this.shadow.getElementById('btn-add-tag')?.addEventListener('click', tryAddTag);\n tagInput.addEventListener('keydown', (e: KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ',') { e.preventDefault(); tryAddTag(); }\n });\n\n this.shadow.querySelectorAll<HTMLButtonElement>('.chip-del').forEach((btn) => {\n btn.addEventListener('click', () => this.removeTag(btn.dataset['tag'] ?? ''));\n });\n\n this.shadow.getElementById('btn-confirm')?.addEventListener('click', () => this.confirmSave());\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.confirmSaveAndExport());\n this.shadow.getElementById('btn-cancel')?.addEventListener('click', () => this.cancel());\n setTimeout(() => descInput.focus(), 60);\n }\n }\n}\n\nif (!customElements.get('lib-e2e-save-test')) {\n customElements.define('lib-e2e-save-test', SaveTestElement);\n}\n","import { PersistenceService } from '../../services/persistence.service';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport { translationService, type TranslationService } from '../../services/translation.service';\nimport { localeForLang } from '../../models/lang.model';\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG, type IssueTrackerConfig } from '../../models/issue-tracker.model';\nimport { TEST_EDITOR_STYLES } from './test-editor.styles';\nimport { renderTestEditor } from './test-editor.template';\n\nexport class TestEditorElement extends HTMLElement {\n private shadow: ShadowRoot;\n persistence!: PersistenceService;\n translation: TranslationService = translationService;\n tests: TestWithDetails[] = [];\n expandedIndex: number | null = null;\n interceptorsByTest: Record<number, string[]> = {};\n activeTag: string | null = null;\n selectMode = false;\n selectedIds: Set<number> = new Set();\n describeName = '';\n groupByTicket = false;\n issueTrackerConfig: IssueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.persistence) this.persistence = new PersistenceService();\n this.loadTests();\n }\n\n async loadTests(): Promise<void> {\n this.tests = await this.persistence.getAllTests();\n this.render();\n }\n\n async deleteTest(id: number): Promise<void> {\n await this.persistence.deleteTest(id);\n this.selectedIds.delete(id);\n await this.loadTests();\n }\n\n toggleExpand(index: number): void {\n this.expandedIndex = this.expandedIndex === index ? null : index;\n if (this.expandedIndex !== null) {\n const test = this.tests[this.expandedIndex];\n if (test?.id && !this.interceptorsByTest[test.id]) {\n this.interceptorsByTest[test.id] = Array.isArray(test.interceptors) ? test.interceptors : [];\n }\n }\n this.render();\n }\n\n hasInterceptors(testId: number): boolean {\n return Array.isArray(this.interceptorsByTest[testId]) && this.interceptorsByTest[testId].length > 0;\n }\n\n toggleGroupByTicket(): void {\n this.groupByTicket = !this.groupByTicket;\n this.render();\n }\n\n toggleSelectMode(): void {\n this.selectMode = !this.selectMode;\n if (!this.selectMode) this.selectedIds.clear();\n this.render();\n }\n\n toggleSelectTest(id: number): void {\n if (this.selectedIds.has(id)) this.selectedIds.delete(id);\n else this.selectedIds.add(id);\n this.render();\n }\n\n generateDescribe(): void {\n const selected = this.tests.filter((t) => this.selectedIds.has(t.id));\n if (!selected.length) return;\n\n const name = this.describeName.trim() || this.t('TEST_EDITOR.DEFAULT_DESCRIBE');\n\n const allInterceptors = [...new Set(\n selected.flatMap((t) => this.interceptorsByTest[t.id] ?? t.interceptors ?? [])\n )];\n\n const beforeEach = allInterceptors.length\n ? ` beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n ${allInterceptors.join('\\n ')}\\n });\\n\\n`\n : '';\n\n const itBlocks = selected\n .map((t) => {\n const cmds = (t.commands ?? []).map((c) => ` ${c}`).join('\\n');\n return ` it('${escapeSingleQuotes(t.name ?? '')}', () => {\\n${cmds}\\n });`;\n })\n .join('\\n\\n');\n\n const block = `describe('${escapeSingleQuotes(name)}', () => {\\n${beforeEach}${itBlocks}\\n});`;\n navigator.clipboard?.writeText(block);\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard?.writeText(text);\n }\n\n get allTags(): string[] {\n const tagSet = new Set<string>();\n this.tests.forEach((t) => (t.tags ?? []).forEach((tag) => tagSet.add(tag)));\n return [...tagSet].sort();\n }\n\n get visibleTests(): TestWithDetails[] {\n const tag = this.activeTag;\n if (!tag) return this.tests;\n return this.tests.filter((t) => (t.tags ?? []).includes(tag));\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private render(): void {\n const tags = this.allTags;\n const visible = this.visibleTests;\n const selectedVisible = visible.filter((t) => this.selectedIds.has(t.id));\n\n this.shadow.innerHTML = `<style>${TEST_EDITOR_STYLES}</style>${renderTestEditor({\n tags,\n visible,\n selectedVisible,\n activeTag: this.activeTag,\n selectMode: this.selectMode,\n selectedIds: this.selectedIds,\n describeName: this.describeName,\n expandedIndex: this.expandedIndex,\n interceptorsByTest: this.interceptorsByTest,\n locale: localeForLang(this.translation.getLang()),\n groupByTicket: this.groupByTicket,\n issueTrackerConfig: this.issueTrackerConfig,\n }, this.t.bind(this))}`;\n\n this.shadow.getElementById('btn-group-ticket')?.addEventListener('click', () => this.toggleGroupByTicket());\n this.shadow.getElementById('btn-select-mode')?.addEventListener('click', () => this.toggleSelectMode());\n\n this.shadow.querySelectorAll('[data-filter-tag]').forEach((el) => {\n el.addEventListener('click', () => {\n const tag = (el as HTMLElement).dataset['filterTag'] ?? '';\n if (!tag) return;\n this.activeTag = this.activeTag === tag ? null : tag;\n this.render();\n });\n });\n\n const descInput = this.shadow.getElementById('describe-name') as HTMLInputElement | null;\n if (descInput) {\n descInput.addEventListener('input', () => { this.describeName = descInput.value; });\n }\n this.shadow.getElementById('btn-gen-describe')?.addEventListener('click', () => {\n this.describeName = descInput?.value ?? this.describeName;\n this.generateDescribe();\n });\n\n this.shadow.querySelectorAll('[data-select]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n this.toggleSelectTest(Number((el as HTMLElement).dataset['select']));\n });\n });\n\n this.shadow.querySelectorAll('[data-action=\"expand\"]').forEach((el) => {\n el.addEventListener('click', () => {\n if (this.selectMode) {\n const row = visible[Number((el as HTMLElement).dataset['idx'])];\n if (row) this.toggleSelectTest(row.id);\n } else {\n this.toggleExpand(Number((el as HTMLElement).dataset['idx']));\n }\n });\n });\n this.shadow.querySelectorAll('[data-action=\"delete\"]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n this.deleteTest(Number((el as HTMLElement).dataset['id']));\n });\n });\n this.shadow.querySelectorAll('[data-action=\"copy-cmds\"]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n const idx = Number((el as HTMLElement).dataset['idx']);\n this.copyToClipboard((visible[idx]?.commands ?? []).join('\\n'));\n });\n });\n this.shadow.querySelectorAll('[data-action=\"copy-icps\"]').forEach((el) => {\n el.addEventListener('click', (ev) => {\n ev.stopPropagation();\n const idx = Number((el as HTMLElement).dataset['idx']);\n const t = visible[idx];\n this.copyToClipboard((this.interceptorsByTest[t?.id] ?? t?.interceptors ?? []).join('\\n'));\n });\n });\n }\n}\n\nif (!customElements.get('lib-e2e-test-editor')) {\n customElements.define('lib-e2e-test-editor', TestEditorElement);\n}\n","export const TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .toolbar {\n display: flex; align-items: center; gap: 6px; padding: 8px 10px; flex-shrink: 0;\n background: #161b22; border-bottom: 1px solid #21262d; flex-wrap: wrap;\n }\n .tag-filter { display: flex; gap: 5px; flex-wrap: wrap; flex: 1; }\n .tag-chip {\n padding: 2px 10px; border-radius: 20px; cursor: pointer; font-size: 11px; font-weight: 500;\n border: 1px solid #30363d; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s, border-color 0.12s;\n }\n .tag-chip:hover { background: #30363d; color: #e6edf3; }\n .tag-chip.active { background: rgba(47,129,247,0.2); color: #2f81f7; border-color: rgba(47,129,247,0.4); }\n .btn-select {\n padding: 4px 12px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-select:hover { background: #30363d; color: #e6edf3; }\n .btn-select.active { background: rgba(47,129,247,0.15); color: #2f81f7; border-color: rgba(47,129,247,0.3); }\n .describe-bar {\n display: flex; align-items: center; gap: 8px; padding: 8px 10px;\n background: rgba(47,129,247,0.06); border-bottom: 1px solid rgba(47,129,247,0.2);\n flex-wrap: wrap;\n }\n .describe-bar input {\n flex: 1; min-width: 150px; padding: 5px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px; color: #e6edf3;\n font-size: 12px; outline: none;\n }\n .describe-bar input:focus { border-color: #2f81f7; }\n .btn-gen-describe {\n padding: 5px 14px; border: 1px solid #2f81f7; border-radius: 6px; cursor: pointer;\n font-size: 11px; font-weight: 500; background: rgba(47,129,247,0.15); color: #2f81f7;\n transition: background 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-gen-describe:hover { background: rgba(47,129,247,0.25); }\n .selected-count { font-size: 11px; color: #8b949e; }\n .describe-bar { flex-shrink: 0; }\n .list { padding: 8px; flex: 1; min-height: 0; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent; }\n .list::-webkit-scrollbar { width: 4px; }\n .list::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .empty { color: #484f58; text-align: center; padding: 32px; font-size: 13px; }\n .row {\n background: #0d1117; border-radius: 8px; margin-bottom: 6px;\n overflow: hidden; border: 1px solid #21262d;\n transition: border-color 0.15s;\n }\n .row:hover { border-color: #30363d; }\n .row.selected-row { border-color: rgba(47,129,247,0.5); }\n .row-header {\n display: flex; align-items: center; gap: 8px;\n padding: 10px 12px; cursor: pointer; user-select: none;\n }\n .row-header:hover { background: rgba(48,54,61,0.3); }\n .test-name { flex: 1; font-size: 13px; font-weight: 500; color: #e6edf3; }\n .test-date { font-size: 10.5px; color: #484f58; margin-right: 4px; }\n .test-tags { display: flex; gap: 4px; margin-right: 4px; }\n .test-tag {\n padding: 1px 7px; border-radius: 20px; font-size: 10px;\n background: rgba(47,129,247,0.1); color: #8b949e; border: 1px solid rgba(47,129,247,0.2);\n }\n .ticket-badge, .ticket-link {\n padding: 1px 7px; border-radius: 20px; font-size: 10px; font-weight: 500;\n background: rgba(210,153,34,0.12); color: #d29922; border: 1px solid rgba(210,153,34,0.3);\n white-space: nowrap; flex-shrink: 0;\n }\n .ticket-link {\n text-decoration: none; cursor: pointer;\n transition: background 0.12s, border-color 0.12s;\n }\n .ticket-link::before { content: '🎫 '; font-size: 9px; }\n .ticket-link:hover { background: rgba(210,153,34,0.22); border-color: rgba(210,153,34,0.55); color: #e3b341; }\n .ticket-badge::before { content: '🎫 '; font-size: 9px; }\n .btn-icon {\n padding: 3px 8px; border: none; border-radius: 6px; cursor: pointer;\n font-size: 11px; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n .btn-icon:hover { background: #30363d; color: #e6edf3; }\n .btn-del:hover { background: rgba(248,81,73,0.15); color: #f85149; }\n input[type=\"checkbox\"] {\n width: 14px; height: 14px; accent-color: #2f81f7; cursor: pointer; flex-shrink: 0;\n }\n .row-body {\n background: #0d1117; padding: 10px 14px;\n border-top: 1px solid #21262d;\n }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .code-preview {\n margin: 0; padding: 10px 12px; background: #161b22;\n border-radius: 6px; border: 1px solid #21262d;\n font-size: 11px; color: #c9d1d9; line-height: 1.7;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n overflow-x: auto; white-space: pre;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .code-preview::-webkit-scrollbar { height: 4px; }\n .code-preview::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .code-preview-icp { margin-top: 8px; }\n .ticket-group { margin-bottom: 8px; }\n .ticket-group-header {\n padding: 4px 10px; margin-bottom: 4px;\n font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.7px;\n color: #d29922; border-left: 3px solid rgba(210,153,34,0.5);\n background: rgba(210,153,34,0.06); border-radius: 0 4px 4px 0;\n }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport { normalizeBlock, escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { buildTicketUrl, buildTicketComment } from '../../utils/ticket.utils';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport type { IssueTrackerConfig } from '../../models/issue-tracker.model';\n\nexport interface TestEditorState {\n tags: string[];\n visible: TestWithDetails[];\n selectedVisible: TestWithDetails[];\n activeTag: string | null;\n selectMode: boolean;\n selectedIds: Set<number>;\n describeName: string;\n expandedIndex: number | null;\n interceptorsByTest: Record<number, string[]>;\n locale: string;\n groupByTicket: boolean;\n issueTrackerConfig: IssueTrackerConfig;\n}\n\nfunction renderTestRow(test: TestWithDetails, i: number, state: TestEditorState, t: (key: string) => string): string {\n const { selectMode, selectedIds, expandedIndex, interceptorsByTest, locale, issueTrackerConfig } = state;\n const expanded = expandedIndex === i;\n const date = new Date(test.createdAt).toLocaleString(locale, { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });\n const icps = interceptorsByTest[test.id] ?? test.interceptors ?? [];\n const tagsHtml = (test.tags ?? []).length\n ? `<span class=\"test-tags\">${(test.tags ?? []).map((tag) => `<span class=\"test-tag\">${escHtml(tag)}</span>`).join('')}</span>`\n : '';\n const checkbox = selectMode\n ? `<input type=\"checkbox\" ${selectedIds.has(test.id) ? 'checked' : ''} data-select=\"${test.id}\" />`\n : '';\n const hasIcps = (test.interceptors ?? []).length > 0;\n const ticketId = (test as TestWithDetails & { ticketId?: string }).ticketId;\n const ticketComment = ticketId ? buildTicketComment(ticketId) + '\\n' : '';\n const itBlockCode = `${ticketComment}it('${escapeSingleQuotes(test.name)}', () => {\\n${(test.commands ?? []).map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});`;\n const icpBlockCode = icps.length ? `beforeEach(() => {\\n // Auto-generated Cypress interceptors\\n${icps.map(c => normalizeBlock(c, ' ')).join('\\n')}\\n});` : '';\n const notesHtml = (expanded && test.notes)\n ? `<p class=\"test-notes\">${escHtml(test.notes)}</p>`\n : '';\n const ticketUrl = ticketId ? buildTicketUrl(ticketId, issueTrackerConfig) : null;\n const ticketHtml = ticketId\n ? ticketUrl\n ? `<a class=\"ticket-link\" href=\"${escAttr(ticketUrl)}\" target=\"_blank\" rel=\"noopener noreferrer\" title=\"${t('TEST_EDITOR.TICKET_LINK_TITLE')}\">${escHtml(ticketId)}</a>`\n : `<span class=\"ticket-badge\">${escHtml(ticketId)}</span>`\n : '';\n\n const body = expanded ? `\n <div class=\"row-body\">\n ${notesHtml}\n <pre class=\"code-preview\">${syntaxHighlight(itBlockCode)}</pre>\n ${icpBlockCode ? `<pre class=\"code-preview code-preview-icp\">${syntaxHighlight(icpBlockCode)}</pre>` : ''}\n </div>` : '';\n\n return `\n <div class=\"row${selectedIds.has(test.id) ? ' selected-row' : ''}\">\n <div class=\"row-header\" data-action=\"expand\" data-idx=\"${i}\">\n ${checkbox}\n <span class=\"test-name\">${escHtml(test.name)}</span>\n ${tagsHtml}\n ${ticketHtml}\n <span class=\"test-date\">${date}</span>\n <button class=\"btn-icon\" data-action=\"copy-cmds\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_CMDS_BTN')}\">${t('TEST_EDITOR.COPY_CMDS_BTN')}</button>\n ${hasIcps ? `<button class=\"btn-icon\" data-action=\"copy-icps\" data-idx=\"${i}\" title=\"${t('TEST_EDITOR.COPY_ICPS_BTN')}\">${t('TEST_EDITOR.COPY_ICPS_BTN')}</button>` : ''}\n <button class=\"btn-icon btn-del\" data-action=\"delete\" data-id=\"${test.id}\" title=\"${t('TEST_EDITOR.DELETE_TITLE')}\">🗑</button>\n </div>\n ${body}\n </div>`;\n}\n\nexport function renderTestEditor(state: TestEditorState, t: (key: string) => string): string {\n const { tags, visible, selectedVisible, activeTag, selectMode, describeName, groupByTicket } = state;\n\n const tagFilterHtml = tags.length\n ? `<div class=\"tag-filter\">\n ${tags.map((tag) => `<button class=\"tag-chip${activeTag === tag ? ' active' : ''}\" data-filter-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}\n </div>`\n : `<div class=\"tag-filter\" style=\"color:#484f58;font-size:11px\">${t('TEST_EDITOR.NO_TAGS')}</div>`;\n\n const describeBarHtml = selectMode && selectedVisible.length > 0\n ? `<div class=\"describe-bar\">\n <span class=\"selected-count\">${selectedVisible.length} ${selectedVisible.length !== 1 ? t('TEST_EDITOR.SELECTED_PLURAL') : t('TEST_EDITOR.SELECTED_SINGULAR')}</span>\n <input id=\"describe-name\" type=\"text\" placeholder=\"${t('TEST_EDITOR.DESCRIBE_PLACEHOLDER')}\" value=\"${escAttr(describeName)}\" />\n <button class=\"btn-gen-describe\" id=\"btn-gen-describe\">${t('TEST_EDITOR.COPY_DESCRIBE')}</button>\n </div>`\n : '';\n\n let rows: string;\n if (groupByTicket) {\n const groups = new Map<string, TestWithDetails[]>();\n for (const test of visible) {\n const key = (test as TestWithDetails & { ticketId?: string }).ticketId?.trim() || '';\n const group = groups.get(key) ?? [];\n group.push(test);\n groups.set(key, group);\n }\n const sortedKeys = [...groups.keys()].sort((a, b) =>\n a === '' ? 1 : b === '' ? -1 : a.localeCompare(b)\n );\n rows = sortedKeys.map((key) => {\n const group = groups.get(key) as TestWithDetails[];\n const header = `<div class=\"ticket-group-header\">${key ? escHtml(key) : t('TEST_EDITOR.NO_TICKET')}</div>`;\n const groupRows = group.map((test) => {\n const i = visible.indexOf(test);\n return renderTestRow(test, i, state, t);\n }).join('');\n return `<div class=\"ticket-group\">${header}${groupRows}</div>`;\n }).join('');\n } else {\n rows = visible.map((test, i) => renderTestRow(test, i, state, t)).join('');\n }\n\n return `\n <div class=\"toolbar\">\n ${tagFilterHtml}\n <button class=\"btn-select${groupByTicket ? ' active' : ''}\" id=\"btn-group-ticket\">\n ${groupByTicket ? t('TEST_EDITOR.UNGROUP_TICKET') : t('TEST_EDITOR.GROUP_BY_TICKET')}\n </button>\n <button class=\"btn-select${selectMode ? ' active' : ''}\" id=\"btn-select-mode\">\n ${selectMode ? t('TEST_EDITOR.CANCEL_SELECT') : t('TEST_EDITOR.MULTI_SELECT')}\n </button>\n </div>\n ${describeBarHtml}\n <div class=\"list\">\n ${visible.length ? rows : `<div class=\"empty\">${t('TEST_EDITOR.NO_TESTS')}</div>`}\n </div>`;\n}\n","import { escHtml } from './html.utils';\n\nconst KEYWORDS = new Set([\n 'describe', 'it', 'xit', 'fit', 'xdescribe', 'fdescribe',\n 'beforeEach', 'afterEach', 'before', 'after', 'context',\n 'const', 'let', 'var', 'function', 'return', 'if', 'else',\n 'import', 'export', 'from', 'new', 'this', 'null', 'undefined',\n 'true', 'false', 'async', 'await', 'of', 'in', 'typeof', 'void',\n]);\n\nconst BUILTINS = new Set(['cy', 'expect', 'assert', 'Cypress', 'chai']);\n\nexport function syntaxHighlight(code: string): string {\n return code.split('\\n').map(highlightLine).join('\\n');\n}\n\nfunction highlightLine(line: string): string {\n let result = '';\n let i = 0;\n const len = line.length;\n\n while (i < len) {\n // Single-line comment\n if (line[i] === '/' && i + 1 < len && line[i + 1] === '/') {\n result += `<span class=\"sh-cmt\">${escHtml(line.slice(i))}</span>`;\n return result;\n }\n // String literal (single, double, or template)\n const q = line[i];\n if (q === \"'\" || q === '\"' || q === '`') {\n let j = i + 1;\n while (j < len) {\n if (line[j] === '\\\\') { j += 2; continue; }\n if (line[j] === q) { j++; break; }\n j++;\n }\n result += `<span class=\"sh-str\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Number (not preceded by identifier character)\n if (/[0-9]/.test(line[i]) && (i === 0 || !/[a-zA-Z_$]/.test(line[i - 1]))) {\n let j = i;\n while (j < len && /[0-9.]/.test(line[j])) j++;\n result += `<span class=\"sh-num\">${escHtml(line.slice(i, j))}</span>`;\n i = j;\n continue;\n }\n // Identifier, keyword, or builtin\n if (/[a-zA-Z_$]/.test(line[i])) {\n let j = i;\n while (j < len && /[a-zA-Z0-9_$]/.test(line[j])) j++;\n const word = line.slice(i, j);\n if (KEYWORDS.has(word)) {\n result += `<span class=\"sh-kw\">${escHtml(word)}</span>`;\n } else if (BUILTINS.has(word)) {\n result += `<span class=\"sh-bi\">${escHtml(word)}</span>`;\n } else {\n result += escHtml(word);\n }\n i = j;\n continue;\n }\n result += escHtml(line[i]);\n i++;\n }\n return result;\n}\n","import type { SelectorStrategy } from '../services/recording.service';\n\n/**\n * A live, in-progress recording session, persisted so it can survive a\n * micro-frontend crossing (single-spa app swap) or an accidental same-origin\n * reload. Only an actively-recording session is ever stored/resumed.\n *\n * The full payload lives in IndexedDB; a lightweight breadcrumb (sessionId +\n * isRecording + updatedAt) is mirrored to localStorage for synchronous detection.\n *\n * See docs/specs/006-cross-app-recording-continuity.md.\n */\nexport interface ActiveSessionState {\n /** Stable id for the session, generated when recording starts. */\n sessionId: string;\n isRecording: boolean;\n isPaused: boolean;\n commands: string[];\n interceptors: string[];\n selectorStrategy: SelectorStrategy;\n /** Epoch ms when the session started recording. */\n startedAt: number;\n /** Epoch ms of the last mutation — acts as the recency heartbeat. */\n updatedAt: number;\n}\n\n/** localStorage key for the synchronous \"is a session active?\" breadcrumb. */\nexport const ACTIVE_SESSION_BREADCRUMB_KEY = 'e2e-active-session';\n\n/** Configuration key (in the `configuration` store) for the resume recency TTL. */\nexport const RESUME_TTL_CONFIG_KEY = 'resumeRecencyTtlMinutes';\n\n/** Default minutes within which an active session resumes silently. */\nexport const DEFAULT_RESUME_TTL_MINUTES = 30;\n","const EXPORT_FN_RE =\n /^(?!\\/\\/).*\\bexport\\s+(?:async\\s+)?function\\s+(\\w+)|^(?!\\/\\/).*\\bexport\\s+const\\s+(\\w+)\\s*=\\s*(?:async\\s*)?\\(/gm;\n\nexport function extractExportedFunctions(fileContent: string): string[] {\n const names: string[] = [];\n let match: RegExpExecArray | null;\n const re = new RegExp(EXPORT_FN_RE.source, EXPORT_FN_RE.flags);\n while ((match = re.exec(fileContent)) !== null) {\n const name = match[1] ?? match[2];\n if (name) names.push(name);\n }\n return names;\n}\n\nexport function buildLoginScaffold(): string {\n return [\n '/**',\n ' * Login service scaffold — fill in your own auth logic.',\n ' * This file is not committed to source control.',\n ' */',\n '',\n 'export function fetchAuthToken() {',\n ' // TODO: implement — retrieve and return your auth token',\n '}',\n '',\n 'export function setupRequestInterceptors() {',\n ' // TODO: implement — configure cy.intercept() or set localStorage/cookies',\n '}',\n '',\n ].join('\\n');\n}\n\nexport function buildLoginImportPath(fromFilePath: string, toServiceFilePath: string): string {\n const fromParts = fromFilePath.replace(/\\\\/g, '/').split('/');\n const toParts = toServiceFilePath.replace(/\\\\/g, '/').split('/');\n\n fromParts.pop(); // remove filename, keep directory segments\n\n // find common prefix length\n let common = 0;\n while (common < fromParts.length && common < toParts.length - 1 && fromParts[common] === toParts[common]) {\n common++;\n }\n\n const ups = fromParts.length - common;\n const downs = toParts.slice(common);\n\n const serviceFile = downs[downs.length - 1].replace(/\\.ts$/, '');\n const prefix = ups === 0 ? '.' : Array(ups).fill('..').join('/');\n const middle = downs.slice(0, -1);\n\n return [prefix, ...middle, serviceFile].join('/');\n}\n\nexport function hasLoginBlocks(content: string, fnNames: string[]): boolean {\n return fnNames.some(fn => new RegExp(`\\\\b${fn}\\\\s*\\\\(`).test(content));\n}\n\nexport function injectLoginBlocksIntoExisting(\n content: string,\n importLine: string,\n beforeBlock: string,\n beforeEachBlock: string,\n): string {\n let result = content;\n\n if (importLine && !content.includes(importLine)) {\n result = `${importLine}\\n\\n${result}`;\n }\n\n const blocks = [beforeBlock, beforeEachBlock].filter(Boolean).join('');\n if (blocks) {\n const describeMatch = result.match(/(describe\\s*\\(.*?{)/s);\n if (describeMatch) {\n const insertPos = (describeMatch.index ?? 0) + describeMatch[0].length;\n result = result.slice(0, insertPos) + '\\n' + blocks + result.slice(insertPos);\n }\n }\n\n return result;\n}\n\nexport function buildLoginBlocks(\n importPath: string,\n beforeFn: string | null,\n beforeEachFn: string | null,\n): { importLine: string; beforeBlock: string; beforeEachBlock: string } {\n if (!beforeFn && !beforeEachFn) {\n return { importLine: '', beforeBlock: '', beforeEachBlock: '' };\n }\n\n const fns = [...new Set([beforeFn, beforeEachFn].filter(Boolean))] as string[];\n const importLine = `import { ${fns.join(', ')} } from '${importPath}';`;\n\n const beforeBlock = beforeFn ? ` before(() => { ${beforeFn}(); });\\n` : '';\n const beforeEachBlock = beforeEachFn ? ` beforeEach(() => { ${beforeEachFn}(); });\\n` : '';\n\n return { importLine, beforeBlock, beforeEachBlock };\n}\n","export const CONFIGURATION_STYLES = `\n :host { display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; max-height: 70vh; overflow-y: auto; scrollbar-width: thin; scrollbar-color: #30363d transparent; }\n * { box-sizing: border-box; }\n\n /* ── Grid container ───────────────────────────────────── */\n .cfg-grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 10px;\n padding: 14px;\n }\n\n /* ── Cards ────────────────────────────────────────────── */\n .card {\n background: #161b22;\n border: 1px solid #21262d;\n border-radius: 10px;\n padding: 14px 16px;\n transition: border-color 0.15s;\n }\n .card:hover { border-color: #30363d; }\n .card-wide { grid-column: 1 / -1; }\n\n /* ── Card header ──────────────────────────────────────── */\n .card-hd {\n display: flex; align-items: center; gap: 7px;\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.8px; color: #484f58; margin-bottom: 12px;\n }\n .card-hd-icon { font-size: 13px; }\n\n /* ── Language ─────────────────────────────────────────── */\n .field-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }\n .field-label { font-size: 12px; color: #8b949e; }\n select {\n background: #0d1117; color: #e6edf3; border: 1px solid #30363d;\n border-radius: 6px; padding: 6px 10px; font-size: 12px; outline: none;\n cursor: pointer; transition: border-color 0.15s; flex-shrink: 0;\n }\n select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n /* ── HTTP toggle ──────────────────────────────────────── */\n .check-row {\n display: flex; align-items: flex-start; gap: 10px;\n cursor: pointer; user-select: none;\n }\n input[type=\"checkbox\"] { width: 15px; height: 15px; margin-top: 2px; cursor: pointer; accent-color: #2f81f7; flex-shrink: 0; }\n .check-title { font-size: 12px; color: #c9d1d9; margin-bottom: 3px; }\n .check-sub { font-size: 10px; color: #484f58; line-height: 1.5; }\n\n /* ── Cypress folder ───────────────────────────────────── */\n .fs-layout { display: flex; gap: 12px; align-items: flex-start; }\n .fs-tree {\n flex-shrink: 0;\n margin: 0; padding: 8px 10px;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n font-size: 10px; color: #c9d1d9; line-height: 1.8;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n }\n .fs-right { display: flex; flex-direction: column; gap: 10px; flex: 1; }\n .fs-status {\n display: flex; align-items: center; gap: 8px;\n font-size: 12px; color: #8b949e;\n background: #0d1117; border: 1px solid #21262d; border-radius: 6px;\n padding: 8px 10px;\n }\n .fs-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }\n .fs-dot.on { background: #3fb950; box-shadow: 0 0 6px rgba(63,185,80,.5); }\n .fs-dot.off { background: #484f58; }\n .fs-folder { color: #e6edf3; font-family: 'Cascadia Code','Fira Code','Consolas',monospace; font-size: 11px; }\n\n /* ── Buttons ──────────────────────────────────────────── */\n .btn-row { display: flex; gap: 8px; flex-wrap: wrap; }\n button {\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n button:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-import {\n display: inline-block;\n padding: 7px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s, border-color 0.15s;\n }\n .btn-import:hover { background: #30363d; color: #e6edf3; border-color: #484f58; }\n .btn-danger { border-color: rgba(248,81,73,.4); color: #f85149; background: transparent; }\n .btn-danger:hover { background: rgba(248,81,73,.08); border-color: #f85149; color: #f85149; }\n .file-input { display: none; }\n\n /* ── Data section desc ────────────────────────────────── */\n .data-desc { font-size: 11px; color: #484f58; margin-bottom: 10px; line-height: 1.5; }\n\n /* ── Export overlay (modal) ───────────────────────────── */\n .export-overlay {\n position: fixed; inset: 0; z-index: 100000;\n background: rgba(1,4,9,0.7);\n display: flex; align-items: center; justify-content: center; padding: 20px;\n }\n .export-modal {\n width: 640px; max-width: 100%; max-height: 86vh;\n display: flex; flex-direction: column;\n background: #161b22; border: 1px solid #30363d; border-radius: 12px;\n box-shadow: 0 12px 40px rgba(0,0,0,0.5); overflow: hidden;\n }\n .export-hd {\n padding: 14px 18px; font-size: 13px; font-weight: 700;\n border-bottom: 1px solid #21262d; color: #e6edf3;\n }\n .export-modes { display: flex; gap: 6px; padding: 12px 18px 0; }\n .export-mode {\n flex: 1; padding: 7px 10px; font-size: 11px; border-radius: 6px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-mode:hover { background: #21262d; color: #e6edf3; }\n .export-mode.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-body {\n padding: 14px 18px; overflow-y: auto; flex: 1; min-height: 160px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .export-tag-hint { font-size: 12px; color: #484f58; margin-top: 12px; }\n .export-result-label {\n font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px;\n font-weight: 600; margin: 14px 0 6px;\n }\n .export-row-static { cursor: default; }\n .export-row-static:hover { background: transparent; }\n .export-all-desc { font-size: 12px; color: #8b949e; }\n .export-empty { font-size: 12px; color: #484f58; text-align: center; padding: 20px; }\n .export-list { display: flex; flex-direction: column; gap: 4px; }\n .export-row {\n display: flex; align-items: center; gap: 8px;\n padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12px; color: #c9d1d9;\n }\n .export-row:hover { background: #0d1117; }\n .export-row-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .export-row-tag {\n font-size: 9px; color: #8b949e; background: #0d1117;\n border: 1px solid #30363d; border-radius: 10px; padding: 1px 7px; flex-shrink: 0;\n }\n .export-tags { display: flex; flex-wrap: wrap; gap: 6px; }\n .export-tag {\n padding: 4px 10px; font-size: 11px; border-radius: 12px;\n background: #0d1117; border: 1px solid #30363d; color: #8b949e;\n }\n .export-tag:hover { background: #21262d; color: #e6edf3; }\n .export-tag.active { background: rgba(47,129,247,0.15); border-color: #2f81f7; color: #2f81f7; }\n .export-ft {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n padding: 12px 18px; border-top: 1px solid #21262d;\n }\n .export-count { font-size: 11px; color: #8b949e; }\n .export-count b { color: #e6edf3; }\n .export-ft-actions { display: flex; gap: 8px; }\n .btn-export-confirm { background: #238636; border-color: #238636; color: #fff; }\n .btn-export-confirm:hover:not(:disabled) { background: #2ea043; border-color: #2ea043; }\n .btn-export-confirm:disabled { opacity: 0.45; cursor: not-allowed; }\n\n /* ── Form-element font reset ──────────────────────────────── */\n input, select, button, textarea { font-family: inherit; }\n\n /* ── Primary action button ────────────────────────────────── */\n .btn-primary { background: #1f6feb; border-color: #1f6feb; color: #fff; }\n .btn-primary:hover { background: #388bfd; border-color: #388bfd; color: #fff; }\n .btn-primary:disabled { opacity: 0.45; cursor: not-allowed; }\n\n /* ── Login Setup overlay ──────────────────────────────────── */\n .ls-modal { max-width: 500px; }\n .ls-hd { display: flex; align-items: center; gap: 8px; }\n .ls-hd-icon { font-size: 15px; }\n\n .ls-body {\n padding: 20px; overflow-y: auto; flex: 1;\n display: flex; flex-direction: column; gap: 20px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n\n .ls-section { display: flex; flex-direction: column; gap: 8px; }\n .ls-section-label {\n font-size: 10px; font-weight: 700; text-transform: uppercase;\n letter-spacing: 0.8px; color: #484f58;\n }\n\n .ls-actions { display: flex; gap: 10px; }\n .ls-action-btn {\n flex: 1; padding: 14px 12px; border-radius: 8px;\n background: #0d1117; border: 1px solid #21262d; color: #8b949e;\n display: flex; flex-direction: column; align-items: center; gap: 6px;\n transition: background 0.15s, border-color 0.15s, color 0.15s;\n }\n .ls-action-btn:hover { background: #161b22; color: #e6edf3; border-color: #388bfd; }\n .ls-action-icon { font-size: 22px; line-height: 1; }\n .ls-action-label { font-size: 12px; font-weight: 600; color: #c9d1d9; }\n .ls-action-btn:hover .ls-action-label { color: #e6edf3; }\n .ls-action-sub { font-size: 10px; color: #484f58; line-height: 1.4; text-align: center; }\n\n .ls-file-row {\n display: flex; align-items: center; gap: 10px;\n padding: 10px 12px; background: #0d1117;\n border: 1px solid #21262d; border-radius: 8px;\n }\n .ls-file-icon { font-size: 14px; flex-shrink: 0; }\n .ls-file-name {\n flex: 1; font-size: 11px; color: #c9d1d9;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n overflow: hidden; text-overflow: ellipsis; white-space: nowrap;\n min-width: 0;\n }\n .ls-btn-rescan {\n flex-shrink: 0; padding: 4px 10px; font-size: 11px;\n background: #161b22; border-color: #30363d; color: #8b949e;\n }\n .ls-btn-rescan:hover { background: #21262d; color: #e6edf3; }\n\n .ls-input {\n width: 100%; padding: 8px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px;\n color: #c9d1d9; font-size: 12px; outline: none; font-family: inherit;\n }\n .ls-input:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n .ls-fns {\n display: flex; flex-wrap: wrap; gap: 6px;\n padding: 10px; background: #0d1117;\n border: 1px solid #21262d; border-radius: 6px; min-height: 38px;\n }\n .ls-fn-chip {\n padding: 3px 10px; font-size: 11px; color: #79c0ff;\n background: rgba(47,129,247,0.1); border: 1px solid rgba(47,129,247,0.2);\n border-radius: 12px; font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n }\n\n .ls-field-block { display: flex; flex-direction: column; gap: 6px; }\n .ls-field-block + .ls-field-block { margin-top: 12px; }\n .ls-label { font-size: 11px; color: #8b949e; }\n .ls-select {\n width: 100%; padding: 8px 10px; background: #0d1117;\n border: 1px solid #30363d; border-radius: 6px;\n color: #c9d1d9; font-size: 12px; outline: none; cursor: pointer;\n }\n .ls-select:focus { border-color: #2f81f7; box-shadow: 0 0 0 3px rgba(47,129,247,0.12); }\n\n .ls-empty-state {\n display: flex; align-items: center; gap: 10px;\n padding: 14px; background: #0d1117; border: 1px solid #21262d;\n border-radius: 8px; font-size: 12px; color: #484f58;\n }\n .ls-empty-icon { font-size: 16px; }\n\n .ls-ft { padding: 14px 20px; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport { ISSUE_TRACKER_PRESETS, type IssueTrackerConfig } from '../../models/issue-tracker.model';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\n\nexport const LANGS = [\n { value: 'es', label: 'Español' },\n { value: 'en', label: 'English' },\n { value: 'fr', label: 'Français' },\n { value: 'it', label: 'Italiano' },\n { value: 'de', label: 'Deutsch' },\n];\n\nexport interface ConfigurationState {\n selectedLanguage: string;\n advancedHttpConfig: boolean;\n fixtureMode: boolean;\n selectorStrategy: string;\n filesystemGranted: boolean;\n cypressFolderName: string | null;\n smartSelectorEnabled: boolean;\n startHidden: boolean;\n resumeTtlMinutes: number;\n isExporting: boolean;\n exportMode: ExportMode;\n exportTests: TestWithDetails[];\n exportSelectedIds: Set<number>;\n exportSelectedTags: Set<string>;\n issueTrackerConfig: IssueTrackerConfig;\n isLoginSetupOpen: boolean;\n loginSetupConfig: LoginSetupConfig | null;\n // draft state — only populated while the overlay is open\n loginSetupDraftPath?: string;\n loginSetupDraftFunctions?: string[];\n loginSetupDraftBeforeFn?: string | null;\n loginSetupDraftBeforeEachFn?: string | null;\n loginSetupDraftHasContent?: boolean;\n}\n\nexport function renderExportOverlay(state: ConfigurationState, t: (key: string) => string): string {\n const { isExporting, exportMode, exportTests, exportSelectedIds, exportSelectedTags } = state;\n if (!isExporting) return '';\n\n const count = selectTestsForExport(exportTests, exportMode, {\n ids: exportSelectedIds,\n tags: exportSelectedTags,\n }).length;\n\n const modeBtn = (mode: ExportMode, key: string) =>\n `<button class=\"export-mode ${exportMode === mode ? 'active' : ''}\" data-export-mode=\"${mode}\">${t(key)}</button>`;\n\n let body: string;\n if (exportTests.length === 0) {\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_EMPTY')}</div>`;\n } else if (exportMode === 'all') {\n body = `<div class=\"export-all-desc\">${t('CONFIG.EXPORT_ALL_DESC')}</div>`;\n } else if (exportMode === 'manual') {\n body = `<div class=\"export-list\">${exportTests.map((test) => `\n <label class=\"export-row\">\n <input type=\"checkbox\" data-export-test=\"${test.id}\" ${exportSelectedIds.has(test.id) ? 'checked' : ''} />\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\n </label>`).join('')}</div>`;\n } else {\n const allTags = [...new Set(exportTests.flatMap((test) => test.tags ?? []))].sort();\n if (!allTags.length) {\n body = `<div class=\"export-empty\">${t('CONFIG.EXPORT_NO_TAGS')}</div>`;\n } else {\n const chips = `<div class=\"export-tags\">${allTags.map((tag) =>\n `<button class=\"export-tag ${exportSelectedTags.has(tag) ? 'active' : ''}\" data-export-tag=\"${escAttr(tag)}\">${escHtml(tag)}</button>`).join('')}</div>`;\n // Preview the tests that the selected tags resolve to, so QA sees exactly\n // what will be exported.\n const matched = selectTestsForExport(exportTests, 'tags', { tags: exportSelectedTags });\n const preview = exportSelectedTags.size === 0\n ? `<div class=\"export-tag-hint\">${t('CONFIG.EXPORT_TAGS_HINT')}</div>`\n : `<div class=\"export-result-label\">${t('CONFIG.EXPORT_RESULT_LABEL')}</div>\n <div class=\"export-list\">${matched.map((test) => `\n <div class=\"export-row export-row-static\">\n <span class=\"export-row-name\">${escHtml(test.name)}</span>\n ${(test.tags ?? []).map((tag) => `<span class=\"export-row-tag\">${escHtml(tag)}</span>`).join('')}\n </div>`).join('')}</div>`;\n body = chips + preview;\n }\n }\n\n return `\n <div class=\"export-overlay\" id=\"export-overlay\">\n <div class=\"export-modal\">\n <div class=\"export-hd\">${t('CONFIG.EXPORT_DIALOG_TITLE')}</div>\n ${exportTests.length ? `<div class=\"export-modes\">\n ${modeBtn('all', 'CONFIG.EXPORT_MODE_ALL')}\n ${modeBtn('manual', 'CONFIG.EXPORT_MODE_MANUAL')}\n ${modeBtn('tags', 'CONFIG.EXPORT_MODE_TAGS')}\n </div>` : ''}\n <div class=\"export-body\">${body}</div>\n <div class=\"export-ft\">\n <span class=\"export-count\">${t('CONFIG.EXPORT_COUNT')} <b>${count}</b></span>\n <span class=\"export-ft-actions\">\n <button id=\"btn-export-confirm\" class=\"btn-export-confirm\" ${count === 0 ? 'disabled' : ''}>${t('CONFIG.EXPORT_CONFIRM')}</button>\n <button id=\"btn-export-cancel\">${t('CONFIG.EXPORT_CANCEL')}</button>\n </span>\n </div>\n </div>\n </div>`;\n}\n\nexport function renderConfiguration(state: ConfigurationState, t: (key: string) => string): string {\n const { selectedLanguage, advancedHttpConfig, fixtureMode, selectorStrategy, filesystemGranted, cypressFolderName, smartSelectorEnabled, startHidden, resumeTtlMinutes, issueTrackerConfig } = state;\n\n const langOptions = LANGS.map(\n (l) => `<option value=\"${l.value}\" ${selectedLanguage === l.value ? 'selected' : ''}>${l.label}</option>`,\n ).join('');\n\n return `\n <div class=\"cfg-grid\">\n\n <!-- Language -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.LANG_SECTION')}</div>\n <div class=\"field-row\">\n <span class=\"field-label\">${t('CONFIG.LANG_FIELD')}</span>\n <select id=\"lang-select\">${langOptions}</select>\n </div>\n </div>\n\n <!-- HTTP Advanced -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.HTTP_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"http-toggle\" ${advancedHttpConfig ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.HTTP_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.HTTP_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- HTTP Fixtures -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.FIXTURE_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"fixture-toggle\" ${fixtureMode ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.FIXTURE_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.FIXTURE_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- Smart Selector -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.SMART_SELECTOR_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"smart-selector-toggle\" ${smartSelectorEnabled ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.SMART_SELECTOR_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.SMART_SELECTOR_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- Start Hidden -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.START_HIDDEN_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"start-hidden-toggle\" ${startHidden ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.START_HIDDEN_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.START_HIDDEN_SUB')}</div>\n </div>\n </label>\n </div>\n\n <!-- Widget position (draggable widget) -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.WIDGET_POSITION_SECTION')}</div>\n <div class=\"check-sub\" style=\"margin-bottom:10px\">${t('CONFIG.WIDGET_POSITION_HINT')}</div>\n <div class=\"btn-row\">\n <button id=\"btn-reset-position\">${t('CONFIG.WIDGET_POSITION_RESET_BTN')}</button>\n </div>\n </div>\n\n <!-- Recording continuity (cross-app resume TTL) -->\n <div class=\"card\">\n <div class=\"card-hd\">${t('CONFIG.RESUME_TTL_SECTION')}</div>\n <div class=\"field-row\">\n <span class=\"field-label\">${t('CONFIG.RESUME_TTL_LABEL')}</span>\n <input type=\"number\" id=\"resume-ttl-input\" min=\"1\" step=\"1\" value=\"${resumeTtlMinutes}\"\n style=\"width:80px;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none\" />\n </div>\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.RESUME_TTL_HINT')}</div>\n </div>\n\n <!-- Selector Strategy -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.SELECTOR_SECTION')}</div>\n <div class=\"field-row\">\n <span class=\"field-label\">${t('CONFIG.SELECTOR_LABEL')}</span>\n <select id=\"selector-strategy\">\n <option value=\"data-cy\" ${selectorStrategy === 'data-cy' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_DATACY')}</option>\n <option value=\"data-testid\" ${selectorStrategy === 'data-testid' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_TESTID')}</option>\n <option value=\"aria-label\" ${selectorStrategy === 'aria-label' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ARIA')}</option>\n <option value=\"id\" ${selectorStrategy === 'id' ? 'selected' : ''}>${t('CONFIG.SELECTOR_OPT_ID')}</option>\n </select>\n </div>\n <div class=\"check-sub\" style=\"margin-top:8px\">${t('CONFIG.SELECTOR_HINT')}</div>\n </div>\n\n <!-- Cypress Folder -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.FOLDER_SECTION')}</div>\n <div class=\"fs-layout\">\n <pre class=\"fs-tree\">cypress/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_PICK_HINT')}</span>\n└── e2e/\n └── *.cy.ts</pre>\n <div class=\"fs-right\">\n <div class=\"fs-status\">\n <span class=\"fs-dot ${filesystemGranted ? 'on' : 'off'}\"></span>\n ${filesystemGranted && cypressFolderName\n ? `<span>${t('CONFIG.FOLDER_CONNECTED')}</span> <span class=\"fs-folder\">📁 ${escHtml(cypressFolderName)}</span>`\n : `<span>${t('CONFIG.FOLDER_NOT_SET')}</span>`}\n </div>\n <div class=\"btn-row\">\n <button id=\"btn-change-folder\">\n ${filesystemGranted ? t('CONFIG.FOLDER_CHANGE_BTN') : t('CONFIG.FOLDER_SELECT_BTN')}\n </button>\n ${filesystemGranted\n ? `<button id=\"btn-revoke\" class=\"btn-danger\">${t('CONFIG.FOLDER_REVOKE_BTN')}</button>`\n : ''}\n </div>\n </div>\n </div>\n </div>\n\n <!-- Issue Tracker -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.ISSUE_TRACKER_SECTION')}</div>\n <label class=\"check-row\">\n <input type=\"checkbox\" id=\"issue-tracker-toggle\" ${issueTrackerConfig.enabled ? 'checked' : ''} />\n <div>\n <div class=\"check-title\">${t('CONFIG.ISSUE_TRACKER_TITLE')}</div>\n <div class=\"check-sub\">${t('CONFIG.ISSUE_TRACKER_SUB')}</div>\n </div>\n </label>\n ${issueTrackerConfig.enabled ? `\n <div class=\"field-row\" style=\"margin-top:10px\">\n <span class=\"field-label\">${t('CONFIG.ISSUE_TRACKER_PROVIDER')}</span>\n <select id=\"issue-tracker-provider\">\n ${Object.values(ISSUE_TRACKER_PRESETS).map((p) =>\n `<option value=\"${p.id}\" ${issueTrackerConfig.provider === p.id ? 'selected' : ''}>${escHtml(p.label)}</option>`\n ).join('')}\n </select>\n </div>\n <div class=\"field-row\" style=\"margin-top:8px\">\n <span class=\"field-label\">${t('CONFIG.ISSUE_TRACKER_BASE_URL')}</span>\n <input id=\"issue-tracker-base-url\" type=\"text\"\n placeholder=\"${escAttr(t('CONFIG.ISSUE_TRACKER_BASE_URL_PH'))}\"\n value=\"${escAttr(issueTrackerConfig.baseUrl)}\"\n style=\"flex:1;padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;color:#c9d1d9;font-size:12px;outline:none\" />\n </div>` : ''}\n </div>\n\n <!-- Login Setup -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.LOGIN_SETUP_SECTION')}</div>\n ${state.loginSetupConfig\n ? `<p style=\"font-size:12px;color:#8b949e;margin:0 0 8px\">${escHtml(state.loginSetupConfig.filePath)}</p>`\n : `<p style=\"font-size:12px;color:#8b949e;margin:0 0 8px\">${t('CONFIG.LOGIN_SETUP_NOT_CONFIGURED')}</p>`}\n <button id=\"btn-open-login-setup\" class=\"btn-sm\">${t('CONFIG.LOGIN_SETUP_SET_UP_BTN')}</button>\n </div>\n\n <!-- Data -->\n <div class=\"card card-wide\">\n <div class=\"card-hd\">${t('CONFIG.DATA_SECTION')}</div>\n <p class=\"data-desc\">${t('CONFIG.DATA_DESC')}</p>\n <div class=\"btn-row\">\n <button id=\"btn-export\">${t('CONFIG.EXPORT_BTN')}</button>\n <label style=\"cursor:pointer;margin:0\">\n <span class=\"btn-import\">${t('CONFIG.IMPORT_BTN')}</span>\n <input type=\"file\" class=\"file-input\" id=\"file-input\" accept=\".json\" />\n </label>\n </div>\n </div>\n\n </div>${renderExportOverlay(state, t)}${renderLoginSetupOverlay(state, t)}`;\n}\n\nfunction renderLoginSetupOverlay(state: ConfigurationState, t: (key: string) => string): string {\n if (!state.isLoginSetupOpen) return '';\n\n const cfg = state.loginSetupConfig;\n const path = state.loginSetupDraftPath ?? cfg?.filePath ?? '';\n const fns = state.loginSetupDraftFunctions ?? cfg?.detectedFunctions ?? [];\n const beforeFn = state.loginSetupDraftBeforeFn !== undefined\n ? state.loginSetupDraftBeforeFn : (cfg?.beforeFn ?? null);\n const beforeEachFn = state.loginSetupDraftBeforeEachFn !== undefined\n ? state.loginSetupDraftBeforeEachFn : (cfg?.beforeEachFn ?? null);\n const hasContent = state.loginSetupDraftHasContent ?? !!(cfg?.fileContent);\n\n const fnOption = (name: string | null, selected: string | null) =>\n `<option value=\"${escAttr(name ?? '')}\" ${selected === name ? 'selected' : ''}>${name ? escHtml(name) : t('CONFIG.LOGIN_SETUP_NONE_OPTION')}</option>`;\n\n const fnDropdown = (id: string, label: string, selected: string | null) => `\n <div class=\"ls-field-block\">\n <label class=\"ls-label\" for=\"${id}\">${escHtml(label)}</label>\n <select id=\"${id}\" class=\"ls-select\">\n ${fnOption(null, selected)}\n ${fns.map((fn) => fnOption(fn, selected)).join('')}\n </select>\n </div>`;\n\n const functionsSection = hasContent\n ? (fns.length > 0\n ? `<div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_FUNCTIONS_DETECTED')}</span>\n <div class=\"ls-fns\">${fns.map((fn) => `<span class=\"ls-fn-chip\">${escHtml(fn)}</span>`).join('')}</div>\n </div>\n <div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_BLOCK_ASSIGN')}</span>\n ${fnDropdown('login-setup-before-fn', t('CONFIG.LOGIN_SETUP_BEFORE_LABEL'), beforeFn)}\n ${fnDropdown('login-setup-before-each-fn', t('CONFIG.LOGIN_SETUP_BEFORE_EACH_LABEL'), beforeEachFn)}\n </div>`\n : `<div class=\"ls-empty-state\">\n <span class=\"ls-empty-icon\">🔍</span>\n <span>${t('CONFIG.LOGIN_SETUP_NO_FUNCTIONS')}</span>\n </div>`)\n : '';\n\n const fileSection = hasContent\n ? `<div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_FILE_NAME_LABEL')}</span>\n <div class=\"ls-file-row\">\n <span class=\"ls-file-icon\">📄</span>\n <span class=\"ls-file-name\">${escHtml(path)}</span>\n <button id=\"btn-login-setup-rescan\" class=\"ls-btn-rescan\">${t('CONFIG.LOGIN_SETUP_RESCAN')}</button>\n </div>\n </div>`\n : `<div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_FILE_NAME_LABEL')}</span>\n <input id=\"login-setup-filepath\" type=\"text\" class=\"ls-input\"\n placeholder=\"${escAttr(t('CONFIG.LOGIN_SETUP_FILE_NAME_PH'))}\"\n value=\"${escAttr(path)}\" />\n </div>`;\n\n return `\n <div class=\"export-overlay\" id=\"login-setup-overlay\">\n <div class=\"export-modal ls-modal\">\n\n <div class=\"export-hd ls-hd\">\n <span class=\"ls-hd-icon\">🔐</span>\n ${t('CONFIG.LOGIN_SETUP_TITLE')}\n </div>\n\n <div class=\"ls-body\">\n\n <div class=\"ls-section\">\n <span class=\"ls-section-label\">${t('CONFIG.LOGIN_SETUP_SOURCE_LABEL')}</span>\n <div class=\"ls-actions\">\n <button id=\"btn-login-setup-create-scaffold\" class=\"ls-action-btn\">\n <span class=\"ls-action-icon\">✨</span>\n <span class=\"ls-action-label\">${t('CONFIG.LOGIN_SETUP_CREATE_SCAFFOLD')}</span>\n <span class=\"ls-action-sub\">${t('CONFIG.LOGIN_SETUP_CREATE_SUB')}</span>\n </button>\n <button id=\"btn-login-setup-pick-file\" class=\"ls-action-btn\">\n <span class=\"ls-action-icon\">📂</span>\n <span class=\"ls-action-label\">${t('CONFIG.LOGIN_SETUP_SELECT_EXISTING')}</span>\n <span class=\"ls-action-sub\">${t('CONFIG.LOGIN_SETUP_SELECT_SUB')}</span>\n </button>\n </div>\n </div>\n\n ${fileSection}\n\n ${functionsSection}\n\n </div>\n\n <div class=\"export-ft ls-ft\">\n <button id=\"btn-login-setup-clear\" class=\"btn-danger\">${t('CONFIG.LOGIN_SETUP_CLEAR_BTN')}</button>\n <span class=\"export-ft-actions\">\n <button id=\"btn-login-setup-cancel\">${t('CONFIG.LOGIN_SETUP_CANCEL_BTN')}</button>\n <button id=\"btn-login-setup-save\" class=\"btn-primary\">${t('CONFIG.LOGIN_SETUP_SAVE_BTN')}</button>\n </span>\n </div>\n\n </div>\n </div>`;\n}\n","import { PersistenceService } from '../../services/persistence.service';\nimport type { TestWithDetails } from '../../services/persistence.service';\nimport { TranslationService } from '../../services/translation.service';\nimport type { Lang } from '../../models/lang.model';\nimport type { SelectorStrategy } from '../../services/recording.service';\nimport { RESUME_TTL_CONFIG_KEY, DEFAULT_RESUME_TTL_MINUTES } from '../../models/active-session.model';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG, type IssueTrackerConfig, type IssueTrackerProvider } from '../../models/issue-tracker.model';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\nimport { extractExportedFunctions, buildLoginScaffold } from '../../utils/login-setup.utils';\nimport { showToast } from '../../utils/toast.utils';\nimport { selectTestsForExport, type ExportMode } from '../../utils/export-selection.utils';\nimport { CONFIGURATION_STYLES } from './configuration.styles';\nimport { renderConfiguration } from './configuration.template';\n\nexport class ConfigurationElement extends HTMLElement {\n private shadow: ShadowRoot;\n persistence!: PersistenceService;\n translation!: TranslationService;\n selectedLanguage = 'es';\n advancedHttpConfig = false;\n fixtureMode = false;\n selectorStrategy: SelectorStrategy = 'data-cy';\n smartSelectorEnabled = true;\n startHidden = false;\n resumeTtlMinutes = DEFAULT_RESUME_TTL_MINUTES;\n isExporting = false;\n exportMode: ExportMode = 'all';\n exportTests: TestWithDetails[] = [];\n exportSelectedIds: Set<number> = new Set();\n exportSelectedTags: Set<string> = new Set();\n issueTrackerConfig: IssueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };\n isLoginSetupOpen = false;\n loginSetupConfig: LoginSetupConfig | null = null;\n loginSetupDraftPath = '';\n loginSetupDraftFunctions: string[] = [];\n loginSetupDraftBeforeFn: string | null = null;\n loginSetupDraftBeforeEachFn: string | null = null;\n loginSetupDraftHasContent = false;\n private loginSetupDraftHandle: FileSystemFileHandle | null = null;\n private loginSetupDraftContent = '';\n private filesystemGranted = false;\n private cypressFolderName: string | null = null;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n // Read from localStorage (sync cache) — see initHttpConfig() in the recorder.\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\n this.fixtureMode = localStorage.getItem('fixtureMode') === 'true';\n }\n\n connectedCallback(): void {\n if (!this.persistence) this.persistence = new PersistenceService();\n if (!this.translation) this.translation = new TranslationService();\n this.loadConfig();\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private async loadConfig(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n if (config?.['language']) {\n this.selectedLanguage = config['language'] as string;\n this.translation.setLang(this.selectedLanguage as Lang);\n }\n this.advancedHttpConfig = localStorage.getItem('extendedHttpCommands') === 'true';\n this.fixtureMode = localStorage.getItem('fixtureMode') === 'true';\n this.selectorStrategy = (config?.['selectorStrategy'] as SelectorStrategy) ?? 'data-cy';\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\n this.startHidden = config?.['startHidden'] === 'true';\n // Only override when the key exists — otherwise an async load could clobber a\n // value just set via onResumeTtlChange (same pattern as `language`).\n const ttlRaw = config?.[RESUME_TTL_CONFIG_KEY];\n if (ttlRaw !== undefined && ttlRaw !== null) {\n const ttl = Number(ttlRaw);\n this.resumeTtlMinutes = Number.isFinite(ttl) && ttl > 0 ? ttl : DEFAULT_RESUME_TTL_MINUTES;\n }\n this.filesystemGranted = config?.['allowReadWriteFiles'] === 'true';\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | undefined;\n this.cypressFolderName = handle?.name ?? null;\n this.issueTrackerConfig = {\n enabled: config?.['issueTrackerEnabled'] === 'true',\n provider: (config?.['issueTrackerProvider'] as IssueTrackerProvider) ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,\n baseUrl: (config?.['issueTrackerBaseUrl'] as string) ?? '',\n };\n this.loginSetupConfig = await this.persistence.getLoginSetup();\n this.render();\n }\n\n async onLanguageChange(lang: string): Promise<void> {\n this.selectedLanguage = lang;\n this.translation.setLang(lang as Lang);\n await this.persistence.setConfig({ language: lang });\n this.render();\n }\n\n onAdvancedHttpConfigChange(checked: boolean): void {\n this.advancedHttpConfig = checked;\n // Write to both: localStorage for immediate sync access by HttpMonitor,\n // IndexedDB as persistent source of truth mirrored on recorder mount.\n localStorage.setItem('extendedHttpCommands', checked ? 'true' : 'false');\n this.persistence.setConfig({ extendedHttpCommands: checked ? 'true' : 'false' });\n this.render();\n }\n\n onFixtureModeChange(checked: boolean): void {\n this.fixtureMode = checked;\n // Same dual-write pattern as extendedHttpCommands — see above.\n localStorage.setItem('fixtureMode', checked ? 'true' : 'false');\n this.persistence.setConfig({ fixtureMode: checked ? 'true' : 'false' });\n this.render();\n }\n\n async onStartHiddenChange(checked: boolean): Promise<void> {\n this.startHidden = checked;\n await this.persistence.setConfig({ startHidden: checked ? 'true' : 'false' });\n this.dispatchEvent(new CustomEvent('starthiddenchange', { detail: checked, bubbles: true, composed: true }));\n this.render();\n }\n\n async onResumeTtlChange(minutes: number): Promise<void> {\n const safe = Number.isFinite(minutes) && minutes > 0 ? Math.round(minutes) : DEFAULT_RESUME_TTL_MINUTES;\n this.resumeTtlMinutes = safe;\n await this.persistence.setConfig({ [RESUME_TTL_CONFIG_KEY]: safe });\n this.render();\n }\n\n onResetWidgetPosition(): void {\n this.dispatchEvent(new CustomEvent('resetwidgetposition', { bubbles: true, composed: true }));\n showToast(this.t('CONFIG.WIDGET_POSITION_RESET_DONE'));\n }\n\n async onSmartSelectorChange(enabled: boolean): Promise<void> {\n this.smartSelectorEnabled = enabled;\n await this.persistence.setConfig({ smartSelectorEnabled: enabled ? 'true' : 'false' });\n this.dispatchEvent(new CustomEvent('smartselectorchange', { detail: enabled, bubbles: true, composed: true }));\n this.render();\n }\n\n async onSelectorStrategyChange(strategy: SelectorStrategy): Promise<void> {\n this.selectorStrategy = strategy;\n await this.persistence.setConfig({ selectorStrategy: strategy });\n this.dispatchEvent(new CustomEvent('selectorstrategychange', { detail: strategy, bubbles: true, composed: true }));\n this.render();\n }\n\n async onIssueTrackerEnabledChange(enabled: boolean): Promise<void> {\n this.issueTrackerConfig = { ...this.issueTrackerConfig, enabled };\n await this.persistence.setConfig({ issueTrackerEnabled: enabled ? 'true' : 'false' });\n this.dispatchEvent(new CustomEvent('issuetrackerchange', { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));\n this.render();\n }\n\n async onIssueTrackerProviderChange(provider: IssueTrackerProvider): Promise<void> {\n this.issueTrackerConfig = { ...this.issueTrackerConfig, provider };\n await this.persistence.setConfig({ issueTrackerProvider: provider });\n this.dispatchEvent(new CustomEvent('issuetrackerchange', { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));\n this.render();\n }\n\n async onIssueTrackerBaseUrlChange(baseUrl: string): Promise<void> {\n this.issueTrackerConfig = { ...this.issueTrackerConfig, baseUrl };\n await this.persistence.setConfig({ issueTrackerBaseUrl: baseUrl });\n this.dispatchEvent(new CustomEvent('issuetrackerchange', { detail: { ...this.issueTrackerConfig }, bubbles: true, composed: true }));\n }\n\n openLoginSetupPanel(): void {\n this.isLoginSetupOpen = true;\n const cfg = this.loginSetupConfig;\n this.loginSetupDraftHandle = null;\n this.loginSetupDraftContent = cfg?.fileContent ?? '';\n this.loginSetupDraftPath = cfg?.filePath ?? '';\n this.loginSetupDraftFunctions = cfg?.detectedFunctions ?? [];\n this.loginSetupDraftBeforeFn = cfg?.beforeFn ?? null;\n this.loginSetupDraftBeforeEachFn = cfg?.beforeEachFn ?? null;\n this.loginSetupDraftHasContent = !!(cfg?.fileContent);\n this.render();\n }\n\n closeLoginSetupPanel(): void {\n this.isLoginSetupOpen = false;\n this.render();\n }\n\n async saveLoginSetupConfig(config: LoginSetupConfig): Promise<void> {\n await this.persistence.saveLoginSetup(config);\n this.loginSetupConfig = config;\n this.isLoginSetupOpen = false;\n this.render();\n }\n\n async clearLoginSetupConfig(): Promise<void> {\n await this.persistence.clearLoginSetup();\n this.loginSetupConfig = null;\n this.render();\n }\n\n async loginSetupPickFile(): Promise<void> {\n type OpenPicker = (opts: object) => Promise<FileSystemFileHandle[]>;\n const currentPath = (this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null)?.value.trim() ?? '';\n try {\n const [handle] = await (window as unknown as { showOpenFilePicker: OpenPicker }).showOpenFilePicker({\n types: [{ description: 'TypeScript files', accept: { 'text/plain': ['.ts'] } }],\n multiple: false,\n });\n this.loginSetupDraftHandle = handle;\n const file = await handle.getFile();\n this.loginSetupDraftContent = await file.text();\n this.loginSetupDraftHasContent = true;\n this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;\n this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);\n this.render();\n } catch (e) {\n if ((e as DOMException)?.name !== 'AbortError') showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\n }\n }\n\n async loginSetupCreateScaffold(): Promise<void> {\n type SavePicker = (opts: object) => Promise<FileSystemFileHandle>;\n const currentPath = (this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null)?.value.trim() ?? '';\n try {\n const handle = await (window as unknown as { showSaveFilePicker: SavePicker }).showSaveFilePicker({\n suggestedName: 'login.service.ts',\n types: [{ description: 'TypeScript files', accept: { 'text/plain': ['.ts'] } }],\n });\n const content = buildLoginScaffold();\n const writable = await handle.createWritable();\n await writable.write(content);\n await writable.close();\n this.loginSetupDraftHandle = handle;\n this.loginSetupDraftContent = content;\n this.loginSetupDraftHasContent = true;\n this.loginSetupDraftPath = currentPath || `cypress/common-services/${handle.name}`;\n this.loginSetupDraftFunctions = extractExportedFunctions(content);\n this.render();\n } catch (e) {\n if ((e as DOMException)?.name !== 'AbortError') showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\n }\n }\n\n async loginSetupRescan(): Promise<void> {\n const currentPath = (this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null)?.value.trim();\n if (currentPath !== undefined) this.loginSetupDraftPath = currentPath;\n try {\n if (this.loginSetupDraftHandle) {\n const file = await this.loginSetupDraftHandle.getFile();\n this.loginSetupDraftContent = await file.text();\n }\n this.loginSetupDraftFunctions = extractExportedFunctions(this.loginSetupDraftContent);\n this.render();\n } catch { /* silently ignore */ }\n }\n\n async changeFolder(): Promise<void> {\n try {\n await this.persistence.requestDirectoryPermissions();\n await this.loadConfig();\n showToast(this.t('CONFIG.FOLDER_UPDATED_TOAST'));\n } catch (e: unknown) {\n if ((e as DOMException)?.name !== 'AbortError') {\n showToast(this.t('CONFIG.FOLDER_ERROR_TOAST'), false);\n }\n }\n }\n\n async revokeAccess(): Promise<void> {\n await this.persistence.setConfig({ allowReadWriteFiles: 'false', cypressDirectoryHandle: null });\n this.filesystemGranted = false;\n this.cypressFolderName = null;\n this.render();\n }\n\n private downloadTests(tests: TestWithDetails[]): void {\n const blob = new Blob([JSON.stringify({ tests, interceptors: [] }, null, 2)], { type: 'application/json' });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'e2e-cypress-export.json';\n a.click();\n URL.revokeObjectURL(url);\n }\n\n /** Downloads every saved test (used by the \"Todo\" mode and as a direct API). */\n async exportAllData(): Promise<void> {\n const tests = await this.persistence.getAllTests();\n this.downloadTests(tests);\n }\n\n /** Opens the export selection dialog, loading the current tests. */\n async openExportDialog(): Promise<void> {\n this.exportTests = await this.persistence.getAllTests();\n this.exportMode = 'all';\n this.exportSelectedIds = new Set();\n this.exportSelectedTags = new Set();\n this.isExporting = true;\n this.render();\n }\n\n cancelExport(): void {\n this.isExporting = false;\n this.exportSelectedIds.clear();\n this.exportSelectedTags.clear();\n this.render();\n }\n\n setExportMode(mode: ExportMode): void {\n this.exportMode = mode;\n this.render();\n }\n\n toggleExportTest(id: number): void {\n if (this.exportSelectedIds.has(id)) this.exportSelectedIds.delete(id);\n else this.exportSelectedIds.add(id);\n this.render();\n }\n\n toggleExportTag(tag: string): void {\n if (this.exportSelectedTags.has(tag)) this.exportSelectedTags.delete(tag);\n else this.exportSelectedTags.add(tag);\n this.render();\n }\n\n /** Downloads the tests resolved by the current mode + selection. No-op if empty. */\n confirmExport(): void {\n const subset = selectTestsForExport(this.exportTests, this.exportMode, {\n ids: this.exportSelectedIds,\n tags: this.exportSelectedTags,\n });\n if (!subset.length) return;\n this.downloadTests(subset);\n this.isExporting = false;\n this.exportSelectedIds.clear();\n this.exportSelectedTags.clear();\n this.render();\n }\n\n async importAllData(file: File): Promise<void> {\n const text = await file.text();\n let data: { tests: Record<string, unknown>[]; interceptors: Record<string, unknown>[] };\n try {\n data = JSON.parse(text);\n } catch {\n throw new Error(this.t('CONFIG.JSON_INVALID'));\n }\n if (!data || !Array.isArray(data.tests) || !Array.isArray(data.interceptors)) {\n throw new Error(this.t('CONFIG.JSON_BAD_FORMAT'));\n }\n // Merge: append the imported tests to whatever is already stored — never wipe\n // existing data (see docs/specs/004-merge-on-import.md).\n await this.persistence.ingestFileData(data.tests, data.interceptors);\n }\n\n private render(): void {\n this.shadow.innerHTML = `<style>${CONFIGURATION_STYLES}</style>${renderConfiguration({\n selectedLanguage: this.selectedLanguage,\n advancedHttpConfig: this.advancedHttpConfig,\n fixtureMode: this.fixtureMode,\n selectorStrategy: this.selectorStrategy,\n filesystemGranted: this.filesystemGranted,\n cypressFolderName: this.cypressFolderName,\n smartSelectorEnabled: this.smartSelectorEnabled,\n startHidden: this.startHidden,\n resumeTtlMinutes: this.resumeTtlMinutes,\n isExporting: this.isExporting,\n exportMode: this.exportMode,\n exportTests: this.exportTests,\n exportSelectedIds: this.exportSelectedIds,\n exportSelectedTags: this.exportSelectedTags,\n issueTrackerConfig: this.issueTrackerConfig,\n isLoginSetupOpen: this.isLoginSetupOpen,\n loginSetupConfig: this.loginSetupConfig,\n loginSetupDraftPath: this.loginSetupDraftPath,\n loginSetupDraftFunctions: this.loginSetupDraftFunctions,\n loginSetupDraftBeforeFn: this.loginSetupDraftBeforeFn,\n loginSetupDraftBeforeEachFn: this.loginSetupDraftBeforeEachFn,\n loginSetupDraftHasContent: this.loginSetupDraftHasContent,\n }, this.t.bind(this))}`;\n ;(this.shadow.getElementById('lang-select') as HTMLSelectElement).addEventListener('change', (e) =>\n this.onLanguageChange((e.target as HTMLSelectElement).value),\n )\n ;(this.shadow.getElementById('http-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onAdvancedHttpConfigChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('fixture-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onFixtureModeChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('smart-selector-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onSmartSelectorChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('start-hidden-toggle') as HTMLInputElement).addEventListener('change', (e) =>\n this.onStartHiddenChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('resume-ttl-input') as HTMLInputElement).addEventListener('change', (e) =>\n this.onResumeTtlChange(Number((e.target as HTMLInputElement).value)),\n )\n ;this.shadow.getElementById('btn-reset-position')?.addEventListener('click', () => this.onResetWidgetPosition())\n ;(this.shadow.getElementById('selector-strategy') as HTMLSelectElement).addEventListener('change', (e) =>\n this.onSelectorStrategyChange((e.target as HTMLSelectElement).value as SelectorStrategy),\n );\n\n ;(this.shadow.getElementById('issue-tracker-toggle') as HTMLInputElement)?.addEventListener('change', (e) =>\n this.onIssueTrackerEnabledChange((e.target as HTMLInputElement).checked),\n )\n ;(this.shadow.getElementById('issue-tracker-provider') as HTMLSelectElement)?.addEventListener('change', (e) =>\n this.onIssueTrackerProviderChange((e.target as HTMLSelectElement).value as IssueTrackerProvider),\n )\n ;(this.shadow.getElementById('issue-tracker-base-url') as HTMLInputElement)?.addEventListener('change', (e) =>\n this.onIssueTrackerBaseUrlChange((e.target as HTMLInputElement).value),\n )\n ;this.shadow.getElementById('btn-change-folder')?.addEventListener('click', () => this.changeFolder());\n this.shadow.getElementById('btn-revoke')?.addEventListener('click', () => this.revokeAccess());\n this.shadow.getElementById('btn-export')?.addEventListener('click', () => this.openExportDialog());\n\n this.shadow.getElementById('btn-export-confirm')?.addEventListener('click', () => this.confirmExport());\n this.shadow.getElementById('btn-export-cancel')?.addEventListener('click', () => this.cancelExport());\n this.shadow.querySelectorAll('[data-export-mode]').forEach((el) =>\n el.addEventListener('click', () => this.setExportMode((el as HTMLElement).dataset['exportMode'] as ExportMode)),\n );\n this.shadow.querySelectorAll('[data-export-test]').forEach((el) =>\n el.addEventListener('change', () => this.toggleExportTest(Number((el as HTMLElement).dataset['exportTest']))),\n );\n this.shadow.querySelectorAll('[data-export-tag]').forEach((el) =>\n el.addEventListener('click', () => this.toggleExportTag((el as HTMLElement).dataset['exportTag'] ?? '')),\n );\n this.shadow.getElementById('btn-open-login-setup')?.addEventListener('click', () => this.openLoginSetupPanel());\n this.shadow.getElementById('btn-login-setup-cancel')?.addEventListener('click', () => this.closeLoginSetupPanel());\n this.shadow.getElementById('btn-login-setup-pick-file')?.addEventListener('click', () => this.loginSetupPickFile());\n this.shadow.getElementById('btn-login-setup-create-scaffold')?.addEventListener('click', () => this.loginSetupCreateScaffold());\n this.shadow.getElementById('btn-login-setup-rescan')?.addEventListener('click', () => this.loginSetupRescan());\n this.shadow.getElementById('btn-login-setup-clear')?.addEventListener('click', () => this.clearLoginSetupConfig());\n this.shadow.getElementById('btn-login-setup-save')?.addEventListener('click', async () => {\n const pathEl = this.shadow.getElementById('login-setup-filepath') as HTMLInputElement | null;\n const beforeEl = this.shadow.getElementById('login-setup-before-fn') as HTMLSelectElement | null;\n const beforeEachEl = this.shadow.getElementById('login-setup-before-each-fn') as HTMLSelectElement | null;\n await this.saveLoginSetupConfig({\n enabled: true,\n filePath: pathEl?.value.trim() ?? this.loginSetupDraftPath,\n fileContent: this.loginSetupDraftContent,\n detectedFunctions: this.loginSetupDraftFunctions,\n beforeFn: beforeEl?.value || null,\n beforeEachFn: beforeEachEl?.value || null,\n });\n });\n\n ;(this.shadow.getElementById('file-input') as HTMLInputElement).addEventListener('change', async (e) => {\n const file = (e.target as HTMLInputElement).files?.[0];\n if (!file) return;\n try {\n await this.importAllData(file);\n showToast(this.t('CONFIG.IMPORT_SUCCESS'));\n } catch (err: unknown) {\n showToast((err as Error).message ?? this.t('CONFIG.IMPORT_ERROR'), false);\n }\n const target = e.target as HTMLInputElement | null;\n if (target) target.value = '';\n });\n }\n}\n\nif (!customElements.get('lib-e2e-configuration')) {\n customElements.define('lib-e2e-configuration', ConfigurationElement);\n}\n","import Swal from 'sweetalert2';\nimport { PersistenceService } from '../../services/persistence.service';\nimport { TranslationService } from '../../services/translation.service';\nimport { AdvancedTestTransformationService } from '../../services/advanced-test.transformation.service';\nimport { escapeSingleQuotes } from '../../utils/code-format.utils';\nimport { buildLoginBlocks, buildLoginImportPath, hasLoginBlocks, injectLoginBlocksIntoExisting } from '../../utils/login-setup.utils';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\nimport { ADVANCED_TEST_EDITOR_STYLES } from './advanced-test-editor.styles';\nimport { renderNoPermission, renderAdvancedEditor, findFileHandleRecursive } from './advanced-test-editor.template';\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\n\nexport class AdvancedTestEditorElement extends HTMLElement {\n private shadow: ShadowRoot;\n private readonly transformationService = new AdvancedTestTransformationService();\n\n persistence!: PersistenceService;\n translation!: TranslationService;\n testId?: number;\n\n e2eTree: Array<DirectoryNode | FileNode> = [];\n selectedFile: unknown = null;\n saveButtonEnabled = false;\n selectedFileHandle: FileSystemFileHandle | null = null;\n selectedFileContent: string | null = null;\n testItBlock = '';\n interceptorsBlock = '';\n testNotes = '';\n isPreviewMode = false;\n previewFileName: string | null = null;\n previewFileContent: string | null = null;\n isCreatingFile = false;\n isCreatingFolder = false;\n collapsedDirs: Set<string> = new Set();\n sidebarWidth = 220;\n loginSetupConfig: LoginSetupConfig | null = null;\n private hasPermission = false;\n private needsReauth = false;\n private _dirHandle: FileSystemDirectoryHandle | null = null;\n private _e2eHandle: FileSystemDirectoryHandle | null = null;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.persistence) this.persistence = new PersistenceService();\n if (!this.translation) this.translation = new TranslationService();\n this.init();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n private async init(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n const allowed = config?.['allowReadWriteFiles'] === 'true';\n\n if (!allowed) {\n this.hasPermission = false;\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\n this.render();\n return;\n }\n\n const handle = config?.['cypressDirectoryHandle'] as FileSystemDirectoryHandle | null;\n if (!handle) {\n this.hasPermission = false;\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\n this.render();\n return;\n }\n\n // queryPermission does NOT require a user gesture\n const perm = await (handle as unknown as FileSystemHandleWithPermission).queryPermission({ mode: 'readwrite' });\n this._dirHandle = handle;\n this.hasPermission = perm === 'granted';\n this.needsReauth = perm === 'prompt';\n\n if (this.testId !== undefined) await this.loadCypressCommandsForTest(this.testId);\n if (this.hasPermission) await this.getFoldersData();\n this.render();\n }\n\n async getFoldersData(): Promise<void> {\n if (!this.hasPermission || !this._dirHandle) return;\n try {\n for await (const entry of this._dirHandle.values()) {\n if (entry.kind === 'directory' && entry.name === 'e2e') {\n this._e2eHandle = entry as FileSystemDirectoryHandle;\n const tree = await this.transformationService.scanDirectory(this._e2eHandle);\n this.e2eTree = tree.children ?? [];\n this.render();\n return;\n }\n }\n } catch { /* silently skip permission errors */ }\n }\n\n async createNewFile(rawName: string): Promise<void> {\n if (!this._e2eHandle) return;\n const name = rawName.trim().replace(/\\.cy\\.ts$/, '');\n if (!name) return;\n const fileName = `${name}.cy.ts`;\n\n const cfg = this.loginSetupConfig;\n if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {\n const e2eName = this._e2eHandle.name ?? 'e2e';\n const fromPath = `cypress/${e2eName}/${fileName}`;\n const importPath = buildLoginImportPath(fromPath, cfg.filePath);\n const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(\n importPath, cfg.beforeFn, cfg.beforeEachFn,\n );\n const header = importLine ? `${importLine}\\n\\n` : '';\n const inner = [beforeBlock, beforeEachBlock].filter(Boolean).join('');\n const template = `${header}describe('${escapeSingleQuotes(name)}', () => {\\n${inner}\\n it('should ', () => {\\n\\n });\\n\\n});\\n`;\n try {\n const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(template);\n await writable.close();\n } catch { /* silently ignore */ }\n } else {\n const template = `describe('${escapeSingleQuotes(name)}', () => {\\n\\n it('should ', () => {\\n\\n });\\n\\n});\\n`;\n try {\n const fileHandle = await this._e2eHandle.getFileHandle(fileName, { create: true });\n const writable = await fileHandle.createWritable();\n await writable.write(template);\n await writable.close();\n } catch { /* silently ignore */ }\n }\n this.isCreatingFile = false;\n await this.getFoldersData();\n }\n\n async createNewFolder(rawName: string): Promise<void> {\n if (!this._e2eHandle) return;\n const name = rawName.trim().replace(/[/\\\\]/g, '');\n if (!name) return;\n try {\n await this._e2eHandle.getDirectoryHandle(name, { create: true });\n } catch { /* silently ignore if folder already exists or permission denied */ }\n this.isCreatingFolder = false;\n await this.getFoldersData();\n }\n\n async refreshTree(): Promise<void> {\n await this.getFoldersData();\n }\n\n async saveCommandsToFile(): Promise<void> {\n if (!this.selectedFileHandle || !this.selectedFileContent || !this.testItBlock) return;\n let content = this.selectedFileContent;\n if (this.interceptorsBlock) {\n content = this.transformationService.insertBeforeEach(content, this.interceptorsBlock);\n }\n const comment = this.testNotes ? this.transformationService.buildBlockComment(this.testNotes) + '\\n' : '';\n content = this.transformationService.insertItBlock(content, comment + this.testItBlock);\n if (!content) return;\n\n const cfg = this.loginSetupConfig;\n if (cfg?.enabled && (cfg.beforeFn || cfg.beforeEachFn)) {\n const fns = [cfg.beforeFn, cfg.beforeEachFn].filter(Boolean) as string[];\n if (!hasLoginBlocks(content, fns)) {\n const e2eName = this._e2eHandle?.name ?? 'e2e';\n const fileName = (this.selectedFile as { name: string } | null)?.name ?? '';\n const fromPath = `cypress/${e2eName}/${fileName}`;\n const importPath = buildLoginImportPath(fromPath, cfg.filePath);\n const { importLine, beforeBlock, beforeEachBlock } = buildLoginBlocks(importPath, cfg.beforeFn, cfg.beforeEachFn);\n const result = await Swal.fire({\n title: this.t('CONFIG.LOGIN_SETUP_INJECT_TITLE'),\n html: `<div style=\"padding:10px 18px 14px;color:#8b949e;font-size:13px;line-height:1.6;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif\">${this.t('CONFIG.LOGIN_SETUP_INJECT_TEXT')}</div>`,\n icon: 'question',\n showCancelButton: true,\n confirmButtonText: this.t('CONFIG.LOGIN_SETUP_INJECT_CONFIRM'),\n cancelButtonText: this.t('CONFIG.LOGIN_SETUP_CANCEL_BTN'),\n confirmButtonColor: '#1f6feb',\n width: 460,\n });\n if (result.isConfirmed) {\n content = injectLoginBlocksIntoExisting(content, importLine, beforeBlock, beforeEachBlock);\n }\n }\n }\n\n const writable = await this.selectedFileHandle.createWritable();\n await writable.write(content);\n await writable.close();\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\n }\n\n async onFileClick(file: unknown): Promise<void> {\n if (!this.transformationService.isFile(file)) return;\n this.selectedFile = file;\n this.saveButtonEnabled = true;\n\n if (!this._dirHandle) return;\n const handle = await findFileHandleRecursive(this._dirHandle, (file as { name: string }).name);\n if (!handle) return;\n this.selectedFileHandle = handle;\n const fileObj = await handle.getFile();\n this.selectedFileContent = await fileObj.text();\n this.render();\n }\n\n markFileAsSelected(file: unknown): void {\n this.selectedFile = file;\n }\n\n async loadCypressCommandsForTest(testId: number): Promise<void> {\n const test = await this.persistence.getTestById(testId);\n if (test) {\n this.testItBlock = test.itBlock ?? '';\n this.interceptorsBlock = test.interceptorsBlock ?? '';\n this.testNotes = test.notes ?? '';\n } else {\n this.testItBlock = '';\n this.interceptorsBlock = '';\n this.testNotes = '';\n }\n this.render();\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard?.writeText(text);\n }\n\n openEditManually(): void {\n if (!this.selectedFileHandle || !this.selectedFileContent) return;\n this.dispatchEvent(new CustomEvent('openfileeditor', {\n detail: {\n handle: this.selectedFileHandle,\n content: this.selectedFileContent,\n fileName: (this.selectedFile as { name?: string } | null)?.name ?? '',\n testId: this.testId,\n itBlock: this.testItBlock,\n interceptorsBlock: this.interceptorsBlock,\n notes: this.testNotes,\n },\n bubbles: true,\n composed: true,\n }));\n }\n\n toggleDir(path: string): void {\n if (this.collapsedDirs.has(path)) {\n this.collapsedDirs.delete(path);\n } else {\n this.collapsedDirs.add(path);\n }\n this.render();\n }\n\n private setupResizeHandle(): void {\n const handle = this.shadow.getElementById('resize-handle');\n const sidebar = this.shadow.querySelector('.sidebar') as HTMLElement | null;\n if (!handle || !sidebar) return;\n\n let startX = 0;\n let startWidth = 0;\n\n const onMouseMove = (e: MouseEvent) => {\n const delta = e.clientX - startX;\n const newWidth = Math.max(140, Math.min(500, startWidth + delta));\n this.sidebarWidth = newWidth;\n sidebar.style.width = `${newWidth}px`;\n };\n\n const onMouseUp = () => {\n document.removeEventListener('mousemove', onMouseMove);\n document.removeEventListener('mouseup', onMouseUp);\n document.body.style.cursor = '';\n document.body.style.userSelect = '';\n handle.classList.remove('dragging');\n };\n\n handle.addEventListener('mousedown', (e: MouseEvent) => {\n startX = e.clientX;\n startWidth = sidebar.offsetWidth;\n document.addEventListener('mousemove', onMouseMove);\n document.addEventListener('mouseup', onMouseUp);\n document.body.style.cursor = 'col-resize';\n document.body.style.userSelect = 'none';\n handle.classList.add('dragging');\n e.preventDefault();\n });\n }\n\n closePreview(): void {\n this.isPreviewMode = false;\n this.previewFileName = null;\n this.previewFileContent = null;\n if (this.testId !== undefined) {\n this.dispatchEvent(new CustomEvent('closemodal', { bubbles: true, composed: true }));\n }\n this.render();\n }\n\n private render(): void {\n if (!this.hasPermission) {\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderNoPermission(this.needsReauth, this.t.bind(this))}`;\n\n this.shadow.getElementById('btn-reauth')?.addEventListener('click', async () => {\n if (!this._dirHandle) return;\n const perm = await (this._dirHandle as unknown as FileSystemHandleWithPermission).requestPermission({ mode: 'readwrite' });\n if (perm === 'granted') {\n this.hasPermission = true;\n this.needsReauth = false;\n await this.getFoldersData();\n this.render();\n }\n });\n return;\n }\n\n this.shadow.innerHTML = `<style>${ADVANCED_TEST_EDITOR_STYLES}</style>${renderAdvancedEditor({\n e2eTree: this.e2eTree,\n selectedFile: this.selectedFile,\n selectedFileContent: this.selectedFileContent,\n testItBlock: this.testItBlock,\n interceptorsBlock: this.interceptorsBlock,\n testNotes: this.testNotes,\n saveButtonEnabled: this.saveButtonEnabled,\n isCreatingFile: this.isCreatingFile,\n isCreatingFolder: this.isCreatingFolder,\n collapsedDirs: this.collapsedDirs,\n sidebarWidth: this.sidebarWidth,\n }, this.t.bind(this))}`;\n\n this.shadow.querySelectorAll('[data-file]').forEach((el) => {\n el.addEventListener('click', () => {\n const data = (el as HTMLElement).dataset['file'];\n if (data) this.onFileClick(JSON.parse(data));\n });\n });\n this.shadow.querySelectorAll('[data-dir-path]').forEach((el) => {\n el.addEventListener('click', () => {\n const path = (el as HTMLElement).dataset['dirPath'];\n if (path) this.toggleDir(path);\n });\n });\n this.setupResizeHandle();\n this.shadow.getElementById('btn-save')\n ?.addEventListener('click', () => this.saveCommandsToFile());\n this.shadow.getElementById('btn-edit')\n ?.addEventListener('click', () => this.openEditManually());\n this.shadow.getElementById('btn-copy-it')\n ?.addEventListener('click', () => this.copyToClipboard(this.testItBlock));\n this.shadow.getElementById('btn-copy-interceptors')\n ?.addEventListener('click', () => this.copyToClipboard(this.interceptorsBlock));\n this.shadow.getElementById('btn-close')\n ?.addEventListener('click', () => this.closePreview());\n this.shadow.getElementById('btn-new-file')\n ?.addEventListener('click', () => {\n this.isCreatingFile = !this.isCreatingFile;\n this.isCreatingFolder = false;\n this.render();\n if (this.isCreatingFile) this.shadow.getElementById('input-new-file')?.focus();\n });\n this.shadow.getElementById('btn-new-folder')\n ?.addEventListener('click', () => {\n this.isCreatingFolder = !this.isCreatingFolder;\n this.isCreatingFile = false;\n this.render();\n if (this.isCreatingFolder) this.shadow.getElementById('input-new-folder')?.focus();\n });\n this.shadow.getElementById('btn-refresh')\n ?.addEventListener('click', () => this.refreshTree());\n this.shadow.getElementById('btn-new-file-confirm')\n ?.addEventListener('click', () => {\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\n this.createNewFile(input?.value ?? '');\n });\n this.shadow.getElementById('btn-new-file-cancel')\n ?.addEventListener('click', () => {\n this.isCreatingFile = false;\n this.render();\n });\n const input = this.shadow.getElementById('input-new-file') as HTMLInputElement | null;\n input?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n this.createNewFile(input.value);\n } else if (e.key === 'Escape') {\n this.isCreatingFile = false;\n this.render();\n }\n });\n this.shadow.getElementById('btn-new-folder-confirm')\n ?.addEventListener('click', () => {\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\n this.createNewFolder(folderInput?.value ?? '');\n });\n this.shadow.getElementById('btn-new-folder-cancel')\n ?.addEventListener('click', () => {\n this.isCreatingFolder = false;\n this.render();\n });\n const folderInput = this.shadow.getElementById('input-new-folder') as HTMLInputElement | null;\n folderInput?.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n this.createNewFolder(folderInput.value);\n } else if (e.key === 'Escape') {\n this.isCreatingFolder = false;\n this.render();\n }\n });\n }\n}\n\nif (!customElements.get('lib-e2e-advanced-test-editor')) {\n customElements.define('lib-e2e-advanced-test-editor', AdvancedTestEditorElement);\n}\n","export const ADVANCED_TEST_EDITOR_STYLES = `\n :host { display: flex; flex-direction: column; flex: 1; min-height: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; overflow: hidden; }\n * { box-sizing: border-box; }\n .layout { display: flex; flex: 1; min-height: 0; }\n .sidebar {\n border-right: none; display: flex; flex-direction: column;\n background: #0d1117; flex-shrink: 0; min-width: 140px; max-width: 500px;\n }\n .tree-scroll {\n flex: 1; overflow-y: auto; padding: 6px 4px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .tree-scroll::-webkit-scrollbar { width: 4px; }\n .tree-scroll::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .resize-handle {\n width: 4px; background: #21262d; cursor: col-resize; flex-shrink: 0;\n transition: background 0.15s;\n }\n .resize-handle:hover, .resize-handle.dragging { background: #2f81f7; }\n .main { flex: 1; display: flex; flex-direction: column; overflow: hidden; background: #161b22; min-width: 0; }\n .no-perm {\n padding: 28px; color: #484f58; font-size: 13px; text-align: center;\n display: flex; flex-direction: column; align-items: center; gap: 12px; line-height: 1.6;\n }\n .tree-item {\n padding: 4px 6px; border-radius: 4px; cursor: pointer;\n font-size: 12px; color: #8b949e; white-space: nowrap;\n overflow: hidden; text-overflow: ellipsis;\n transition: background 0.12s, color 0.12s;\n display: flex; align-items: center; gap: 4px; user-select: none;\n }\n .tree-item:hover { background: #161b22; color: #c9d1d9; }\n .tree-item.selected { background: rgba(47,129,247,0.12); color: #2f81f7; }\n .tree-item.dir { color: #e3b341; font-weight: 600; }\n .tree-item.dir:hover { background: rgba(227,179,65,0.08); color: #f0c040; }\n .dir-arrow { font-size: 8px; color: #484f58; width: 10px; flex-shrink: 0; line-height: 1; }\n .tree-connector { display: block; width: 1px; background: #21262d; margin-left: 13px; height: 100%; }\n .content-area {\n flex: 1; padding: 12px 14px; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .content-area::-webkit-scrollbar { width: 4px; }\n .content-area::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .file-name { font-size: 11px; color: #484f58; margin-bottom: 8px; font-family: monospace; }\n pre {\n background: #0d1117; padding: 12px; border-radius: 8px;\n font-size: 11px; color: #c9d1d9; margin: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n line-height: 1.7; border: 1px solid #21262d;\n white-space: pre; overflow-x: auto; overflow-y: auto;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n pre::-webkit-scrollbar { width: 4px; height: 4px; }\n pre::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .pre-block { font-size: 10.5px; }\n .pre-icp .sh-str { color: #85e89d; }\n .sh-kw { color: #ff7b72; }\n .sh-bi { color: #d2a8ff; }\n .sh-str { color: #a5d6ff; }\n .sh-cmt { color: #8b949e; font-style: italic; }\n .sh-num { color: #79c0ff; }\n .footer {\n padding: 10px 14px; border-top: 1px solid #21262d;\n display: flex; gap: 8px; justify-content: flex-end; background: #161b22;\n }\n button {\n padding: 6px 16px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n button:disabled { opacity: 0.35; cursor: default; }\n .btn-save { background: #2f81f7; border-color: #2f81f7; color: #fff; }\n .btn-save:hover { background: #1f6feb; border-color: #1f6feb; color: #fff; }\n .btn-save:disabled { background: #21262d; border-color: #30363d; color: #8b949e; }\n .placeholder { color: #484f58; font-size: 13px; padding: 28px; text-align: center; }\n .test-notes {\n margin: 0 0 10px; padding: 8px 12px;\n background: rgba(47,129,247,0.06); border-left: 3px solid rgba(47,129,247,0.4);\n border-radius: 0 6px 6px 0; font-size: 12px; color: #8b949e;\n line-height: 1.6; white-space: pre-wrap; word-break: break-word;\n }\n .block-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }\n .btn-copy {\n padding: 3px 10px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; flex-shrink: 0;\n }\n .btn-copy:hover { background: #30363d; color: #e6edf3; }\n .sidebar-toolbar {\n display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 6px 4px;\n border-bottom: 1px solid #21262d; flex-shrink: 0; background: #0d1117;\n }\n .btn-toolbar {\n flex: 1 1 calc(50% - 2px); padding: 4px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #161b22; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap; overflow: hidden;\n text-overflow: ellipsis;\n }\n .btn-toolbar.btn-full { flex: 1 1 100%; }\n .btn-toolbar:hover { background: #30363d; color: #e6edf3; }\n .btn-toolbar.btn-new { color: #3fb950; border-color: #238636; }\n .btn-toolbar.btn-new:hover { background: #238636; color: #fff; }\n .btn-toolbar.btn-new-folder { color: #d29922; border-color: #9e6a03; }\n .btn-toolbar.btn-new-folder:hover { background: #9e6a03; color: #fff; }\n .new-file-form {\n padding: 6px; border-bottom: 1px solid #21262d; display: flex; flex-direction: column; gap: 4px;\n }\n .new-file-form input {\n width: 100%; padding: 4px 7px; background: #0d1117; border: 1px solid #30363d;\n border-radius: 5px; color: #e6edf3; font-size: 11px; font-family: monospace;\n outline: none;\n }\n .new-file-form input:focus { border-color: #2f81f7; }\n .new-file-form .ext { font-size: 9px; color: #484f58; padding: 0 2px; }\n .new-file-actions { display: flex; gap: 4px; }\n .btn-confirm { flex: 1; padding: 3px 6px; border: 1px solid #238636; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #238636; color: #fff; transition: background 0.12s; }\n .btn-confirm:hover { background: #2ea043; }\n .btn-cancel-form { flex: 1; padding: 3px 6px; border: 1px solid #30363d; border-radius: 5px; cursor: pointer; font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e; transition: background 0.12s; }\n .btn-cancel-form:hover { background: #30363d; color: #e6edf3; }\n`;\n","import { escHtml, escAttr } from '../../utils/html.utils';\nimport { syntaxHighlight } from '../../utils/syntax-highlight.utils';\nimport type { DirectoryNode, FileNode } from '../../services/advanced-test.transformation.service';\n\nexport interface AdvancedEditorState {\n e2eTree: Array<DirectoryNode | FileNode>;\n selectedFile: unknown;\n selectedFileContent: string | null;\n testItBlock: string;\n interceptorsBlock: string;\n testNotes: string;\n saveButtonEnabled: boolean;\n isCreatingFile: boolean;\n isCreatingFolder: boolean;\n collapsedDirs: Set<string>;\n sidebarWidth: number;\n}\n\nexport function renderNoPermission(needsReauth: boolean, t: (key: string) => string): string {\n const reauthBtn = needsReauth\n ? `<button id=\"btn-reauth\"\n style=\"margin-top:14px;padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\n ${t('ADVANCED_EDITOR.REAUTH_BTN')}\n </button>`\n : '';\n\n return `\n <div class=\"no-perm\">\n <div>${needsReauth ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED') : t('ADVANCED_EDITOR.NO_ACCESS')}</div>\n <div style=\"font-size:11px\">${needsReauth\n ? t('ADVANCED_EDITOR.PERMISSION_EXPIRED_HINT')\n : t('ADVANCED_EDITOR.NO_ACCESS_HINT')}</div>\n ${reauthBtn}\n </div>`;\n}\n\nexport function renderAdvancedEditor(state: AdvancedEditorState, t: (key: string) => string): string {\n const { e2eTree, selectedFile, selectedFileContent, testItBlock, interceptorsBlock, testNotes, saveButtonEnabled, isCreatingFile, isCreatingFolder, collapsedDirs, sidebarWidth } = state;\n\n const treeHtml = e2eTree.length\n ? renderTree(e2eTree, selectedFile, collapsedDirs)\n : `<div class=\"tree-item\" style=\"color:#6c7a99\">${t('ADVANCED_EDITOR.NO_FILES')}</div>`;\n\n const contentHtml = selectedFileContent\n ? `<div class=\"file-name\">📄 ${escHtml((selectedFile as { name?: string } | null)?.name ?? '')}</div>\n <pre class=\"pre-file\">${syntaxHighlight(selectedFileContent.slice(0, 6000))}${selectedFileContent.length > 6000 ? '\\n...' : ''}</pre>`\n : `<div class=\"placeholder\">${t('ADVANCED_EDITOR.SELECT_FILE')}</div>`;\n\n const notesHtml = (testItBlock && testNotes)\n ? `<p class=\"test-notes\">${escHtml(testNotes)}</p>`\n : '';\n\n const itHtml = testItBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.IT_LABEL')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_IT_BTN')}</button>\n </div>\n <pre class=\"pre-block\">${syntaxHighlight(testItBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const interceptorsHtml = interceptorsBlock\n ? `<div style=\"margin-top:10px\">\n <div class=\"file-name block-header\">\n <span>${t('ADVANCED_EDITOR.BEFORE_EACH_LABEL')}</span>\n <button id=\"btn-copy-interceptors\" class=\"btn-copy\">${t('ADVANCED_EDITOR.COPY_ICP_BTN')}</button>\n </div>\n <pre class=\"pre-block pre-icp\">${syntaxHighlight(interceptorsBlock.slice(0, 3000))}</pre>\n </div>` : '';\n\n const newFileForm = isCreatingFile\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-file\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FILE_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <span class=\"ext\">.cy.ts</span>\n <div class=\"new-file-actions\">\n <button id=\"btn-new-file-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-file-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const newFolderForm = isCreatingFolder\n ? `<div class=\"new-file-form\">\n <input id=\"input-new-folder\" type=\"text\" placeholder=\"${escHtml(t('ADVANCED_EDITOR.NEW_FOLDER_PLACEHOLDER'))}\" autocomplete=\"off\" />\n <div class=\"new-file-actions\">\n <button id=\"btn-new-folder-confirm\" class=\"btn-confirm\">${t('ADVANCED_EDITOR.NEW_FILE_CONFIRM')}</button>\n <button id=\"btn-new-folder-cancel\" class=\"btn-cancel-form\">${t('ADVANCED_EDITOR.NEW_FILE_CANCEL')}</button>\n </div>\n </div>`\n : '';\n\n const toolbar = `\n <div class=\"sidebar-toolbar\">\n <button id=\"btn-new-file\" class=\"btn-toolbar btn-new\">${t('ADVANCED_EDITOR.NEW_FILE_BTN')}</button>\n <button id=\"btn-new-folder\" class=\"btn-toolbar btn-new-folder\">${t('ADVANCED_EDITOR.NEW_FOLDER_BTN')}</button>\n <button id=\"btn-refresh\" class=\"btn-toolbar btn-full\">${t('ADVANCED_EDITOR.REFRESH_BTN')}</button>\n </div>`;\n\n return `\n <div class=\"layout\">\n <div class=\"sidebar\" style=\"width:${sidebarWidth}px\">\n ${toolbar}\n ${newFileForm}\n ${newFolderForm}\n <div class=\"tree-scroll\">${treeHtml}</div>\n </div>\n <div id=\"resize-handle\" class=\"resize-handle\"></div>\n <div class=\"main\">\n <div class=\"content-area\">${contentHtml}${notesHtml}${itHtml}${interceptorsHtml}</div>\n <div class=\"footer\">\n <button id=\"btn-save\" class=\"btn-save\"\n ${!saveButtonEnabled || !testItBlock ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.INSERT_BTN')}\n </button>\n <button id=\"btn-edit\" ${!saveButtonEnabled ? 'disabled' : ''}>\n ${t('ADVANCED_EDITOR.EDIT_MANUAL_BTN')}\n </button>\n <button id=\"btn-close\">${t('ADVANCED_EDITOR.CLOSE_BTN')}</button>\n </div>\n </div>\n </div>`;\n}\n\nexport function renderTree(\n nodes: Array<DirectoryNode | FileNode>,\n selected: unknown,\n collapsedDirs: Set<string>,\n indent = 0,\n parentPath = '',\n): string {\n return nodes.map((n) => {\n const currentPath = parentPath ? `${parentPath}/${n.name}` : n.name;\n const isFile = n.kind === 'file';\n const pad = `padding-left:${6 + indent * 14}px`;\n\n if (!isFile) {\n const dir = n as DirectoryNode;\n const hasChildren = (dir.children?.length ?? 0) > 0;\n const isCollapsed = collapsedDirs.has(currentPath);\n const arrow = hasChildren ? (isCollapsed ? '▶' : '▼') : '·';\n const dirHtml = `<div class=\"tree-item dir\" style=\"${pad}\" data-dir-path=\"${escAttr(currentPath)}\">\n <span class=\"dir-arrow\">${arrow}</span>📁 ${escHtml(n.name)}\n </div>`;\n if (!hasChildren || isCollapsed) return dirHtml;\n return dirHtml + renderTree(dir.children, selected, collapsedDirs, indent + 1, currentPath);\n }\n\n const isSel = (selected as { name?: string } | null)?.name === n.name;\n const cls = `tree-item${isSel ? ' selected' : ''}`;\n const data = JSON.stringify({ kind: n.kind, name: n.name }).replace(/\"/g, '"');\n return `<div class=\"${cls}\" style=\"${pad}\" data-file=\"${data}\">📄 ${escHtml(n.name)}</div>`;\n }).join('');\n}\n\nexport async function findFileHandleRecursive(\n dir: FileSystemDirectoryHandle,\n name: string,\n): Promise<FileSystemFileHandle | null> {\n for await (const entry of dir.values()) {\n if (entry.kind === 'file' && entry.name === name) return entry as FileSystemFileHandle;\n if (entry.kind === 'directory') {\n const found = await findFileHandleRecursive(entry as FileSystemDirectoryHandle, name);\n if (found) return found;\n }\n }\n return null;\n}\n","export const FILE_PREVIEW_STYLES = `\n :host { display: block; height: 100%; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; color: #e6edf3; }\n * { box-sizing: border-box; }\n .container { display: flex; flex-direction: column; height: 100%; }\n .header {\n display: flex; align-items: center; gap: 8px;\n padding: 8px 12px; border-bottom: 1px solid #21262d;\n background: #161b22;\n }\n .file-name { flex: 1; font-size: 12px; color: #8b949e;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; }\n .body { display: flex; flex: 1; overflow: hidden; min-height: 0; }\n .editor {\n flex: 1; min-width: 0; padding: 14px;\n background: #0d1117; color: #c9d1d9; border: none; outline: none;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 12px;\n line-height: 1.7; resize: none;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .editor::-webkit-scrollbar { width: 5px; }\n .editor::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .blocks-panel {\n width: 260px; flex-shrink: 0; border-left: 1px solid #21262d;\n background: #0d1117; padding: 10px 12px; overflow-y: auto;\n display: flex; flex-direction: column; gap: 10px;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .blocks-panel::-webkit-scrollbar { width: 4px; }\n .blocks-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 2px; }\n .block-section { display: flex; flex-direction: column; gap: 4px; }\n .block-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 2px; }\n .block-label { font-size: 10px; color: #484f58; text-transform: uppercase; letter-spacing: 0.6px; font-weight: 600; }\n .btn-copy-sm {\n padding: 2px 8px; border: 1px solid #30363d; border-radius: 4px; cursor: pointer;\n font-size: 10px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.12s, color 0.12s; white-space: nowrap;\n }\n .btn-copy-sm:hover { background: #30363d; color: #e6edf3; }\n .block-pre {\n margin: 0; padding: 6px 8px; background: #161b22;\n border-radius: 5px; border: 1px solid #21262d;\n font-size: 10px; color: #c9d1d9; line-height: 1.6;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace;\n max-height: 280px; overflow-y: auto; white-space: pre-wrap; word-break: break-all;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel {\n flex: 1; overflow-y: auto; background: #0d1117; border-left: 1px solid #21262d;\n padding: 8px 0; min-width: 0;\n font-family: 'Cascadia Code', 'Fira Code', 'Consolas', monospace; font-size: 11px;\n line-height: 1.6;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .diff-panel::-webkit-scrollbar { width: 5px; }\n .diff-panel::-webkit-scrollbar-thumb { background: #30363d; border-radius: 3px; }\n .diff-line {\n display: flex; gap: 0; white-space: pre; padding: 0 12px;\n }\n .diff-line.added { background: rgba(63,185,80,0.12); color: #3fb950; }\n .diff-line.removed { background: rgba(248,81,73,0.1); color: #f85149; }\n .diff-line.same { color: #484f58; }\n .diff-sign { width: 14px; flex-shrink: 0; user-select: none; }\n .diff-empty { color: #484f58; font-size: 12px; padding: 20px; text-align: center; }\n .footer {\n display: flex; gap: 8px; padding: 8px 12px;\n border-top: 1px solid #21262d; justify-content: flex-end;\n background: #161b22;\n }\n button {\n padding: 6px 14px; border: 1px solid #30363d; border-radius: 6px; cursor: pointer;\n font-size: 12px; font-weight: 500; background: #21262d; color: #8b949e;\n transition: background 0.15s, color 0.12s;\n }\n button:hover { background: #30363d; color: #e6edf3; }\n .btn-save { background: #3fb950; border-color: #3fb950; color: #fff; }\n .btn-save:hover { background: #2ea043; border-color: #2ea043; }\n .btn-launch { background: transparent; border-color: #e3b341; color: #e3b341; }\n .btn-launch:hover { background: rgba(227,179,65,0.1); }\n .btn-launch:disabled { opacity: 0.45; cursor: not-allowed; }\n .btn-launch:disabled:hover { background: transparent; }\n .launch-hint { font-size: 10px; color: #8b6d3b; align-self: center; }\n .btn-insert { background: transparent; border-color: #a371f7; color: #a371f7; }\n .btn-insert:hover { background: rgba(163,113,247,0.12); color: #c8a8ff; }\n .btn-diff-active { background: rgba(47,129,247,0.15); border-color: rgba(47,129,247,0.4); color: #2f81f7; }\n\n /* ── Run result panel ─────────────────────────────────── */\n .run-result {\n border-top: 1px solid #21262d; padding: 8px 12px; background: #0d1117;\n max-height: 220px; overflow-y: auto; flex-shrink: 0;\n scrollbar-width: thin; scrollbar-color: #30363d transparent;\n }\n .run-status { font-size: 12px; font-weight: 600; }\n .run-passed .run-status { color: #3fb950; }\n .run-failed .run-status { color: #f85149; }\n .run-running .run-status { color: #e3b341; }\n .run-error .run-status { color: #f85149; }\n .run-output {\n margin: 6px 0 0; padding: 8px 10px; background: #161b22; border: 1px solid #21262d;\n border-radius: 5px; font-size: 10px; color: #c9d1d9; line-height: 1.5;\n font-family: 'Cascadia Code','Fira Code','Consolas',monospace;\n white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow-y: auto;\n }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\nexport type DiffEntry = { type: 'same' | 'added' | 'removed'; line: string };\n\nexport function computeDiff(original: string, modified: string): DiffEntry[] {\n const MAX_LINES = 600;\n const a = original.split('\\n').slice(0, MAX_LINES);\n const b = modified.split('\\n').slice(0, MAX_LINES);\n const m = a.length, n = b.length;\n\n const dp: number[][] = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));\n for (let i = 1; i <= m; i++) {\n for (let j = 1; j <= n; j++) {\n dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]);\n }\n }\n\n const result: DiffEntry[] = [];\n let i = m, j = n;\n while (i > 0 || j > 0) {\n if (i > 0 && j > 0 && a[i - 1] === b[j - 1]) {\n result.unshift({ type: 'same', line: a[i - 1] });\n i--; j--;\n } else if (j > 0 && (i === 0 || dp[i][j - 1] >= dp[i - 1][j])) {\n result.unshift({ type: 'added', line: b[j - 1] });\n j--;\n } else {\n result.unshift({ type: 'removed', line: a[i - 1] });\n i--;\n }\n }\n return result;\n}\n\nexport function buildDiffHtml(original: string, current: string, t: (key: string) => string): string {\n if (original === current) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES')}</div>`;\n\n const diff = computeDiff(original, current);\n if (!diff.length) return `<div class=\"diff-empty\">${t('FILE_PREVIEW.NO_CHANGES_SHORT')}</div>`;\n\n const CONTEXT = 2;\n const compressed: DiffEntry[] = [];\n let sameRun = 0;\n for (let idx = 0; idx < diff.length; idx++) {\n if (diff[idx].type === 'same') {\n sameRun++;\n if (sameRun <= CONTEXT) compressed.push(diff[idx]);\n else if (idx + 1 < diff.length && diff[idx + 1].type !== 'same') {\n if (sameRun > CONTEXT * 2) compressed.push({ type: 'same', line: '…' });\n compressed.push(diff[idx]);\n }\n } else {\n sameRun = 0;\n compressed.push(diff[idx]);\n }\n }\n\n return compressed.map(({ type, line }) => {\n const sign = type === 'added' ? '+' : type === 'removed' ? '−' : ' ';\n return `<div class=\"diff-line ${type}\"><span class=\"diff-sign\">${sign}</span><span>${escHtml(line)}</span></div>`;\n }).join('');\n}\n\nexport type RunState = 'idle' | 'running' | 'passed' | 'failed' | 'error';\n\nexport interface FilePreviewState {\n fileName: string | null;\n showDiff: boolean;\n fileContent: string | null;\n originalContent: string | null;\n currentContent: string;\n itBlock: string;\n interceptorsBlock: string;\n closeLabel: string;\n isLocal: boolean;\n runState: RunState;\n runOutput: string;\n}\n\nconst RUN_STATUS_KEY: Record<Exclude<RunState, 'idle'>, string> = {\n running: 'FILE_PREVIEW.LAUNCH_RUNNING',\n passed: 'FILE_PREVIEW.LAUNCH_PASSED',\n failed: 'FILE_PREVIEW.LAUNCH_FAILED',\n error: 'FILE_PREVIEW.LAUNCH_NO_RUNNER',\n};\n\nexport function renderFilePreview(state: FilePreviewState, t: (key: string) => string): string {\n const { fileName, showDiff, fileContent, originalContent, currentContent, itBlock, interceptorsBlock, closeLabel, isLocal, runState, runOutput } = state;\n\n const blocksPanelHtml = (itBlock || interceptorsBlock) ? `\n <div class=\"blocks-panel\">\n ${itBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_IT')}</span>\n <button id=\"btn-copy-it\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\">${escHtml(itBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n ${interceptorsBlock ? `\n <div class=\"block-section\">\n <div class=\"block-row\">\n <span class=\"block-label\">${t('FILE_PREVIEW.BLOCK_BEFORE_EACH')}</span>\n <button id=\"btn-copy-icp\" class=\"btn-copy-sm\">${t('FILE_PREVIEW.COPY_BTN')}</button>\n </div>\n <pre class=\"block-pre\" style=\"color:#3fb950\">${escHtml(interceptorsBlock.slice(0, 2000))}</pre>\n </div>` : ''}\n </div>` : '';\n\n const hasChanges = originalContent !== null && originalContent !== (fileContent ?? '');\n const hasBlocks = !!(itBlock || interceptorsBlock);\n\n const launchBtnHtml = isLocal\n ? `<button id=\"btn-launch\" class=\"btn-launch\" ${runState === 'running' ? 'disabled' : ''}>${runState === 'running' ? t('FILE_PREVIEW.LAUNCH_RUNNING') : t('FILE_PREVIEW.LAUNCH_BTN')}</button>`\n : `<button class=\"btn-launch\" disabled title=\"${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}\">${t('FILE_PREVIEW.LAUNCH_BTN')}</button>\n <span class=\"launch-hint\">${t('FILE_PREVIEW.LAUNCH_LOCAL_ONLY')}</span>`;\n\n const runResultHtml = runState !== 'idle'\n ? `<div class=\"run-result run-${runState}\">\n <span class=\"run-status\">${t(RUN_STATUS_KEY[runState])}</span>\n ${runOutput ? `<pre class=\"run-output\">${escHtml(runOutput.slice(0, 8000))}</pre>` : ''}\n </div>`\n : '';\n\n return `\n <div class=\"container\">\n <div class=\"header\">\n <span class=\"file-name\">📄 ${fileName ? escHtml(fileName) : t('FILE_PREVIEW.NO_FILE')}</span>\n <button id=\"btn-copy\" title=\"${t('FILE_PREVIEW.COPY_TITLE')}\">📋</button>\n </div>\n <div class=\"body\">\n ${showDiff\n ? `<div class=\"diff-panel\" id=\"diff-panel\">${buildDiffHtml(originalContent ?? '', currentContent, t)}</div>`\n : `<textarea class=\"editor\" id=\"editor\" spellcheck=\"false\">${escHtml(fileContent ?? '')}</textarea>`}\n ${blocksPanelHtml}\n </div>\n ${runResultHtml}\n <div class=\"footer\">\n ${launchBtnHtml}\n ${hasChanges ? `<button id=\"btn-diff\" class=\"${showDiff ? 'btn-diff-active' : ''}\">${t('FILE_PREVIEW.DIFF_BTN')}</button>` : ''}\n ${hasBlocks && !showDiff ? `<button id=\"btn-insert\" class=\"btn-insert\" title=\"${t('FILE_PREVIEW.INSERT_TITLE')}\">${t('FILE_PREVIEW.INSERT_BTN')}</button>` : ''}\n <button id=\"btn-save\" class=\"btn-save\">${t('FILE_PREVIEW.SAVE_BTN')}</button>\n <button id=\"btn-close\">${escHtml(closeLabel || t('FILE_PREVIEW.CLOSE_BTN'))}</button>\n </div>\n </div>`;\n}\n","import { translationService, type TranslationService } from '../../services/translation.service';\nimport { advancedTestTransformationService } from '../../services/advanced-test.transformation.service';\nimport { showToast } from '../../utils/toast.utils';\nimport { isLocalHost } from '../../utils/host.utils';\nimport { FILE_PREVIEW_STYLES } from './file-preview.styles';\nimport { renderFilePreview, type RunState } from './file-preview.template';\n\nexport class FilePreviewElement extends HTMLElement {\n private shadow: ShadowRoot;\n private textarea: HTMLTextAreaElement | null = null;\n\n fileName: string | null = null;\n closeLabel = '';\n translation: TranslationService = translationService;\n itBlock = '';\n interceptorsBlock = '';\n notes = '';\n commands: string[] = [];\n interceptors: string[] = [];\n /** Endpoint of the local Cypress runner. Configurable; defaults to the bundled runner's port. */\n runnerUrl = 'http://localhost:8123/run-test';\n /** Whether the app is served locally — gates the launch button. Overridable for tests. */\n isLocal = isLocalHost(window.location.hostname);\n private _fileContent: string | null = null;\n private _originalContent: string | null = null;\n private _showDiff = false;\n private _runState: RunState = 'idle';\n private _runOutput = '';\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.closeLabel) this.closeLabel = this.translation.translate('FILE_PREVIEW.CLOSE_BTN');\n this.render();\n }\n\n private t(key: string): string { return this.translation.translate(key); }\n\n get fileContent(): string | null { return this._fileContent; }\n set fileContent(v: string | null) {\n if (this._originalContent === null) this._originalContent = v;\n this._fileContent = v;\n if (this.textarea) this.textarea.value = v ?? '';\n else this.render();\n }\n\n saveFile(): void {\n const content = this.textarea?.value ?? this._fileContent ?? '';\n this.dispatchEvent(new CustomEvent('save', { detail: content, bubbles: true, composed: true }));\n }\n\n onClose(): void {\n this.dispatchEvent(new CustomEvent('close', { bubbles: true, composed: true }));\n }\n\n /**\n * Runs the current spec headless via the local runner and shows the result.\n * No-op off localhost. Never throws — connection failures surface as an\n * \"error\" state + toast instead of an unhandled rejection.\n */\n async launchTest(specPath?: string): Promise<void> {\n if (!this.isLocal) return;\n const path = specPath ?? this.fileName ?? '';\n if (!path) return;\n\n this._runState = 'running';\n this._runOutput = '';\n this.render();\n\n try {\n const response = await fetch(this.runnerUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ specPath: path }),\n });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n const result = await response.json() as { success?: boolean; output?: string };\n this._runOutput = result.output ?? '';\n this._runState = result.success ? 'passed' : 'failed';\n } catch {\n this._runState = 'error';\n this._runOutput = '';\n showToast(this.t('FILE_PREVIEW.LAUNCH_NO_RUNNER'), false);\n }\n this.render();\n }\n\n copyToClipboard(text: string): void {\n navigator.clipboard?.writeText(text);\n }\n\n toggleDiff(): void {\n this._showDiff = !this._showDiff;\n this.render();\n }\n\n /**\n * Merges the it() and beforeEach() blocks into the current editor content\n * using the same logic as the automatic \"Insert into file\" action, so the\n * user does not have to copy/paste manually. Leaves the content untouched\n * (and warns) when the file has no valid describe() block to insert into.\n */\n insertBlocks(): void {\n const base = this.textarea?.value ?? this._fileContent ?? '';\n let content = base;\n if (this.interceptorsBlock) {\n const merged = advancedTestTransformationService.insertBeforeEach(content, this.interceptorsBlock);\n if (merged) content = merged;\n }\n if (this.itBlock) {\n const comment = this.notes ? advancedTestTransformationService.buildBlockComment(this.notes) + '\\n' : '';\n const merged = advancedTestTransformationService.insertItBlock(content, comment + this.itBlock);\n if (merged) content = merged;\n }\n if (content === base) {\n showToast(this.t('FILE_PREVIEW.INSERT_ERROR'), false);\n return;\n }\n this._fileContent = content;\n this.render();\n showToast(this.t('FILE_PREVIEW.INSERT_DONE'));\n }\n\n private render(): void {\n this.shadow.innerHTML = `<style>${FILE_PREVIEW_STYLES}</style>${renderFilePreview({\n fileName: this.fileName,\n showDiff: this._showDiff,\n fileContent: this._fileContent,\n originalContent: this._originalContent,\n currentContent: this.textarea?.value ?? this._fileContent ?? '',\n itBlock: this.itBlock,\n interceptorsBlock: this.interceptorsBlock,\n closeLabel: this.closeLabel,\n isLocal: this.isLocal,\n runState: this._runState,\n runOutput: this._runOutput,\n }, this.t.bind(this))}`;\n\n this.textarea = this.shadow.getElementById('editor') as HTMLTextAreaElement | null;\n if (this.textarea) {\n const ta = this.textarea;\n this.textarea.addEventListener('input', () => {\n this._fileContent = ta.value;\n });\n }\n this.shadow.getElementById('btn-save')?.addEventListener('click', () => this.saveFile());\n this.shadow.getElementById('btn-close')?.addEventListener('click', () => this.onClose());\n this.shadow.getElementById('btn-launch')?.addEventListener('click', () => this.launchTest());\n this.shadow.getElementById('btn-copy')?.addEventListener('click', () => {\n this.copyToClipboard(this.textarea?.value ?? this._fileContent ?? '');\n });\n this.shadow.getElementById('btn-diff')?.addEventListener('click', () => this.toggleDiff());\n this.shadow.getElementById('btn-insert')?.addEventListener('click', () => this.insertBlocks());\n this.shadow.getElementById('btn-copy-it')?.addEventListener('click', () => {\n this.copyToClipboard(this.itBlock);\n });\n this.shadow.getElementById('btn-copy-icp')?.addEventListener('click', () => {\n this.copyToClipboard(this.interceptorsBlock);\n });\n }\n}\n\nif (!customElements.get('lib-e2e-file-preview')) {\n customElements.define('lib-e2e-file-preview', FilePreviewElement);\n}\n","export const HELP_PANEL_STYLES = `\n :host { display: block; }\n *, *::before, *::after { box-sizing: border-box; }\n\n .help-tabs {\n display: flex;\n gap: 4px;\n border-bottom: 1px solid #21262d;\n margin-bottom: 8px;\n }\n .help-tab {\n appearance: none;\n border: none;\n background: transparent;\n color: #8b949e;\n font-size: 12px;\n font-weight: 600;\n padding: 8px 12px;\n cursor: pointer;\n border-bottom: 2px solid transparent;\n margin-bottom: -1px;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n transition: color .12s, border-color .12s;\n }\n .help-tab:hover { color: #c9d1d9; }\n .help-tab.active { color: #e6edf3; border-bottom-color: #2f81f7; }\n\n .help-panel {\n max-height: 60vh;\n overflow-y: auto;\n padding: 4px 6px 8px;\n color: #c9d1d9;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-size: 13px;\n line-height: 1.55;\n }\n\n .help-intro {\n margin: 0 0 12px;\n color: #8b949e;\n font-size: 12px;\n }\n\n .help-sec { margin: 0 0 14px; }\n\n .help-sec-hd {\n margin: 0 0 6px;\n font-size: 12px;\n font-weight: 700;\n color: #e6edf3;\n letter-spacing: .3px;\n border-bottom: 1px solid #21262d;\n padding-bottom: 4px;\n }\n\n .help-list {\n margin: 0;\n padding: 0;\n list-style: none;\n }\n\n .help-list li {\n padding: 3px 0 3px 14px;\n position: relative;\n color: #c9d1d9;\n }\n\n .help-list li::before {\n content: '·';\n position: absolute;\n left: 3px;\n color: #2f81f7;\n font-weight: 700;\n }\n`;\n","import { escHtml } from '../../utils/html.utils';\n\n/**\n * Pure render function for the in-app Help panel (spec 011). Two tabs — a quick\n * reference (cheat-sheet) and a verbose usage guide (workflow + coverage). All\n * text comes from the HELP.* i18n section and is escaped (values contain literal\n * `<select>` etc. that would otherwise be parsed as HTML).\n */\n\nexport type HelpTab = 'reference' | 'guide';\n\ninterface Section { title: string; items: string[] }\n\nconst REFERENCE_SECTIONS: Section[] = [\n { title: 'HELP.SEC_RECORDING', items: ['HELP.RECORDING_1', 'HELP.RECORDING_2'] },\n {\n title: 'HELP.SEC_SHORTCUTS',\n items: ['HELP.SC_RECORD', 'HELP.SC_PAUSE', 'HELP.SC_TESTS', 'HELP.SC_COMMANDS', 'HELP.SC_CONFIG', 'HELP.SC_VISIBILITY', 'HELP.SC_HELP'],\n },\n {\n title: 'HELP.SEC_CAPTURED',\n items: ['HELP.CAP_CLICK', 'HELP.CAP_DBLCLICK', 'HELP.CAP_RIGHTCLICK', 'HELP.CAP_TYPE', 'HELP.CAP_CHECK', 'HELP.CAP_SELECT', 'HELP.CAP_KEYS', 'HELP.CAP_ROUTE', 'HELP.CAP_HTTP'],\n },\n { title: 'HELP.SEC_ASSERT', items: ['HELP.ASSERT_1', 'HELP.ASSERT_2'] },\n { title: 'HELP.SEC_PANELS', items: ['HELP.PANEL_TESTS', 'HELP.PANEL_COMMANDS', 'HELP.PANEL_CONFIG', 'HELP.PANEL_FILES'] },\n { title: 'HELP.SEC_SELECTOR', items: ['HELP.SELECTOR_1', 'HELP.SELECTOR_2'] },\n { title: 'HELP.SEC_DATA', items: ['HELP.DATA_1', 'HELP.DATA_2'] },\n { title: 'HELP.SEC_ADVANCED', items: ['HELP.ADV_INVISIBLE', 'HELP.ADV_RUNNER', 'HELP.ADV_CROSSAPP', 'HELP.ADV_DRAG', 'HELP.ADV_LOGIN'] },\n];\n\nconst GUIDE_SECTIONS: Section[] = [\n { title: 'HELP.G_SEC_WORKFLOW', items: ['HELP.G_WF_1', 'HELP.G_WF_2', 'HELP.G_WF_3', 'HELP.G_WF_4', 'HELP.G_WF_5'] },\n { title: 'HELP.G_SEC_COVERED', items: ['HELP.G_COV_1', 'HELP.G_COV_2', 'HELP.G_COV_3', 'HELP.G_COV_4', 'HELP.G_COV_5', 'HELP.G_COV_6', 'HELP.G_COV_7'] },\n { title: 'HELP.G_SEC_NOTCOVERED', items: ['HELP.G_NC_1', 'HELP.G_NC_2', 'HELP.G_NC_3', 'HELP.G_NC_4', 'HELP.G_NC_5'] },\n];\n\nfunction sectionsHtml(sections: Section[], t: (key: string) => string): string {\n return sections\n .map(\n (s) => `\n <section class=\"help-sec\">\n <h3 class=\"help-sec-hd\">${escHtml(t(s.title))}</h3>\n <ul class=\"help-list\">${s.items.map((k) => `<li>${escHtml(t(k))}</li>`).join('')}</ul>\n </section>`,\n )\n .join('');\n}\n\nexport function renderHelpPanel(t: (key: string) => string, activeTab: HelpTab = 'reference'): string {\n const tab = (id: HelpTab, key: string): string =>\n `<button class=\"help-tab ${activeTab === id ? 'active' : ''}\" data-tab=\"${id}\">${escHtml(t(key))}</button>`;\n\n const body =\n activeTab === 'guide'\n ? `<p class=\"help-intro\">${escHtml(t('HELP.GUIDE_INTRO'))}</p>${sectionsHtml(GUIDE_SECTIONS, t)}`\n : `<p class=\"help-intro\">${escHtml(t('HELP.INTRO'))}</p>${sectionsHtml(REFERENCE_SECTIONS, t)}`;\n\n return `\n <div class=\"help-root\">\n <div class=\"help-tabs\" role=\"tablist\">\n ${tab('reference', 'HELP.TAB_REFERENCE')}\n ${tab('guide', 'HELP.TAB_GUIDE')}\n </div>\n <div class=\"help-panel\" data-tab-panel=\"${activeTab}\">${body}</div>\n </div>`;\n}\n","import { TranslationService } from '../../services/translation.service';\nimport { HELP_PANEL_STYLES } from './help-panel.styles';\nimport { renderHelpPanel, type HelpTab } from './help-panel.template';\n\n/**\n * `<help-panel>` — an in-app guide (spec 011). Two tabs: a quick reference\n * cheat-sheet and a verbose usage guide (workflow + coverage). Content is driven\n * by the HELP.* i18n keys.\n */\nexport class HelpPanelElement extends HTMLElement {\n private shadow: ShadowRoot;\n private activeTab: HelpTab = 'reference';\n translation!: TranslationService;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if (!this.translation) this.translation = new TranslationService();\n this.render();\n }\n\n private render(): void {\n this.shadow.innerHTML =\n `<style>${HELP_PANEL_STYLES}</style>${renderHelpPanel(this.translation.translate.bind(this.translation), this.activeTab)}`;\n this.shadow.querySelectorAll<HTMLElement>('[data-tab]').forEach((btn) => {\n btn.addEventListener('click', () => {\n this.activeTab = (btn.dataset['tab'] as HelpTab) ?? 'reference';\n this.render();\n });\n });\n }\n}\n\nif (!customElements.get('lib-e2e-help-panel')) {\n customElements.define('lib-e2e-help-panel', HelpPanelElement);\n}\n","import Swal, { type SweetAlertOptions } from 'sweetalert2';\nimport { getRecorderStyles } from './lib-e2e-recorder.styles';\nimport { renderRecorderWidget } from './lib-e2e-recorder.template';\nimport { injectAssertionBuilder } from './assertion-builder';\nimport { mountFilesystemSetupContent } from './filesystem-setup';\nimport { mountComponentInSwal } from '../../utils/swal-mount.utils';\nimport { RecordingService, type SelectorStrategy } from '../../services/recording.service';\nimport { PersistenceService } from '../../services/persistence.service';\nimport { TranslationService } from '../../services/translation.service';\nimport { HttpMonitor } from '../../services/http-monitor';\nimport {\n injectStyles,\n LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES,\n SCROLLBAR_STYLES,\n} from '../../utils/styles.utils';\nimport {\n makeModalResizable,\n makeSwalDraggable,\n setSwal2DataCyAttribute,\n ensurePopupDimensions,\n} from '../../utils/modal.utils';\nimport type { Lang } from '../../models/lang.model';\nimport type { LoginSetupConfig } from '../../models/login-setup.model';\nimport {\n type ActiveSessionState,\n ACTIVE_SESSION_BREADCRUMB_KEY,\n RESUME_TTL_CONFIG_KEY,\n DEFAULT_RESUME_TTL_MINUTES,\n} from '../../models/active-session.model';\nimport {\n type ExpandDirection,\n type Point,\n DRAG_THRESHOLD,\n clampTogglePosition,\n resolveExpandDirection,\n defaultTogglePosition,\n boxTopLeftFor,\n} from '../../utils/widget-position.utils';\nimport { showToast } from '../../utils/toast.utils';\nimport { DEFAULT_ISSUE_TRACKER_CONFIG, type IssueTrackerConfig, type IssueTrackerProvider } from '../../models/issue-tracker.model';\nimport { toFixtureInterceptors, simplifyFixtureWaits } from '../../utils/fixture-convert.utils';\n\n/**\n * Minimal property/event shapes for dynamically-created child custom elements.\n * Not extending HTMLElement avoids conflicts with the strict EventListener signature;\n * cast to Node/HTMLElement only for actual DOM insertion.\n */\ninterface PrevisualizerEl {\n translation: TranslationService; commands: string[]; interceptors: string[]; editable: boolean;\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\n}\ninterface TestEditorEl { persistence: PersistenceService; translation: TranslationService; issueTrackerConfig: IssueTrackerConfig; groupByTicket: boolean; }\ninterface SaveTestEl {\n translation: TranslationService;\n issueTrackerConfig: IssueTrackerConfig;\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\n}\ninterface ConfigEl {\n persistence: PersistenceService; translation: TranslationService;\n addEventListener(type: string, listener: (e: CustomEvent) => void): void;\n}\ninterface AdvancedEditorEl {\n persistence: PersistenceService; translation: TranslationService; testId?: number;\n loginSetupConfig: LoginSetupConfig | null;\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\n}\ninterface FilePreviewEl {\n translation: TranslationService; fileContent: string | null; fileName: string | null;\n closeLabel: string; itBlock: string; interceptorsBlock: string; notes: string;\n addEventListener(type: string, listener: (e: CustomEvent) => void | Promise<void>): void;\n}\ninterface SelectorPickerEl {\n targetElement: HTMLElement; recording: RecordingService; translation: TranslationService;\n}\ninterface HelpPanelEl { translation: TranslationService }\n\nexport class LibE2eRecorderElement extends HTMLElement {\n private shadow: ShadowRoot;\n private _isDisabled = false;\n private keydownHandler!: (e: KeyboardEvent) => void;\n private recordingUnsub?: () => void;\n private commandsUnsub?: () => void;\n private interceptorsUnsub?: () => void;\n private pauseUnsub?: () => void;\n private selectorNotFoundUnsub?: () => void;\n private langUnsub?: () => void;\n private sessionUnsub?: () => void;\n private sessionSaveTimer?: ReturnType<typeof setTimeout>;\n private controlFirstTimeData = true;\n\n // ── draggable widget (spec 007) ──\n private togglePos: Point | null = null;\n private expandDir: ExpandDirection = 'up-left';\n private dragState?: { startX: number; startY: number; origX: number; origY: number; moved: boolean };\n private suppressNextToggleClick = false;\n private widgetPointerMove?: (e: MouseEvent) => void;\n private widgetPointerUp?: () => void;\n private widgetResize?: () => void;\n private _previsualizerRef: { commands: string[]; interceptors: string[] } | null = null;\n private httpMonitor?: HttpMonitor;\n private smartSelectorEnabled = true;\n private _needsRecordingRebuild = false;\n private issueTrackerConfig: IssueTrackerConfig = { ...DEFAULT_ISSUE_TRACKER_CONFIG };\n\n recording!: RecordingService;\n persistence!: PersistenceService;\n translation!: TranslationService;\n\n isVisible = false;\n isRecording = false;\n isPaused = false;\n cypressCommands: string[] = [];\n interceptors: string[] = [];\n\n isCommandsDialogOpen = false;\n isSavedTestsDialogOpen = false;\n isSaveTestDialogOpen = false;\n isSettingsDialogOpen = false;\n isAdvancedEditorDialogOpen = false;\n isHelpDialogOpen = false;\n\n constructor() {\n super();\n this.shadow = this.attachShadow({ mode: 'open' });\n }\n\n connectedCallback(): void {\n if ('Cypress' in window) {\n this._isDisabled = true;\n return;\n }\n if (!this.getAttribute('data-cy')) {\n this.setAttribute('data-cy', 'lib-e2e-cypress-for-dummys');\n }\n // Build a fresh recording service on first connect, or rebuild after a\n // disconnect destroyed the previous one (its listeners are dead). spec 008.\n if (!this.recording || this._needsRecordingRebuild) {\n this.recording = new RecordingService();\n this._needsRecordingRebuild = false;\n }\n if (!this.persistence) this.persistence = new PersistenceService();\n if (!this.translation) this.translation = new TranslationService();\n\n this.httpMonitor = new HttpMonitor(this.recording);\n this.httpMonitor.install();\n\n injectStyles(LIB_E2E_CYPRESS_FOR_DUMMYS_SWAL2_STYLES, 'lib-e2e-swal2-styles');\n injectStyles(SCROLLBAR_STYLES, 'lib-e2e-scrollbar-styles');\n\n this.initHttpConfig();\n this.initLanguage();\n this.initFilesystemAccess();\n this.initSelectorStrategy();\n this.initSubscriptions();\n this.render();\n this.initVisibility();\n this.initSessionContinuity();\n this.initWidgetPosition();\n\n this.keydownHandler = (e: KeyboardEvent) => this.handleKeyboardEvent(e);\n window.addEventListener('keydown', this.keydownHandler);\n\n // Draggable widget (spec 007): pointer move/up tracked at window level so the\n // drag keeps working even if the cursor leaves the toggle button.\n this.widgetPointerMove = (e: MouseEvent) => this.onWidgetPointerMove(e);\n this.widgetPointerUp = () => this.onWidgetPointerUp();\n this.widgetResize = () => this.applyWidgetPosition();\n window.addEventListener('pointermove', this.widgetPointerMove as EventListener);\n window.addEventListener('pointerup', this.widgetPointerUp);\n window.addEventListener('resize', this.widgetResize);\n }\n\n disconnectedCallback(): void {\n if (this._isDisabled) return;\n window.removeEventListener('keydown', this.keydownHandler);\n // Final flush: if a recording is in progress, persist it synchronously-ish\n // before tearing the service down, so an unmount (single-spa per-sub-project\n // placement) does not lose the last commands. The realm survives client-side\n // navigation, so this async write completes even after the element is gone.\n this.flushActiveSessionOnDisconnect();\n this.recordingUnsub?.();\n this.commandsUnsub?.();\n this.interceptorsUnsub?.();\n this.pauseUnsub?.();\n this.selectorNotFoundUnsub?.();\n this.langUnsub?.();\n this.sessionUnsub?.();\n if (this.widgetPointerMove) window.removeEventListener('pointermove', this.widgetPointerMove as EventListener);\n if (this.widgetPointerUp) window.removeEventListener('pointerup', this.widgetPointerUp);\n if (this.widgetResize) window.removeEventListener('resize', this.widgetResize);\n this.httpMonitor?.uninstall();\n this.recording.destroy();\n // The service's AbortController is now spent (DOM listeners are dead) and the\n // patched history methods are restored. Flag a rebuild so a reconnect of the\n // SAME element gets a FRESH service + monitor (the buffer is recovered from\n // IndexedDB by initSessionContinuity, spec 006). We do NOT null the reference\n // here — the Subjects stay functional, so any in-flight async (e.g. a deferred\n // save calling clearCommands) won't hit `undefined`.\n this._needsRecordingRebuild = true;\n }\n\n // HttpMonitor reads extendedHttpCommands and fixtureMode synchronously inside\n // fetch/XHR interception handlers, so they must live in localStorage (sync).\n // IndexedDB is the persistent source of truth; this method mirrors it into\n // localStorage on every mount so the sync cache is always fresh.\n private async initHttpConfig(): Promise<void> {\n const config = await this.persistence.getConfig('extendedHttpCommands');\n if (config === null) {\n await this.persistence.setConfig({ extendedHttpCommands: 'true' });\n localStorage.setItem('extendedHttpCommands', 'true');\n } else {\n localStorage.setItem('extendedHttpCommands', (config['extendedHttpCommands'] as string) ?? 'true');\n }\n const fx = await this.persistence.getConfig('fixtureMode');\n localStorage.setItem('fixtureMode', (fx?.['fixtureMode'] as string) ?? 'false');\n }\n\n private async initLanguage(): Promise<void> {\n const config = await this.persistence.getConfig('language');\n const lang = config?.['language'] as Lang | undefined;\n this.translation.setLang(lang ?? this.translation.detectLang());\n }\n\n private initSubscriptions(): void {\n this.recordingUnsub = this.recording.onRecordingChange((val) => {\n this.isRecording = val;\n if (!val && !this.controlFirstTimeData) {\n this.saveRecordingHistory();\n // Stopping the recording ends the cross-app session: only an actively\n // recording session is ever persisted/resumed (spec 006, Q2).\n this.clearSessionPersistence();\n this.showSaveTestDialog();\n }\n this.controlFirstTimeData = false;\n this.render();\n });\n // Persist the live session incrementally so it survives a micro-frontend\n // crossing or a same-origin reload (spec 006).\n this.sessionUnsub = this.recording.onSessionChange((state) => this.persistActiveSession(state));\n this.commandsUnsub = this.recording.onCommandsChange((cmds) => {\n this.cypressCommands = cmds;\n if (this._previsualizerRef) this._previsualizerRef.commands = cmds;\n });\n this.interceptorsUnsub = this.recording.onInterceptorsChange((icps) => {\n this.interceptors = icps;\n if (this._previsualizerRef) this._previsualizerRef.interceptors = icps;\n });\n this.pauseUnsub = this.recording.onPauseChange((paused) => {\n this.isPaused = paused;\n this.render();\n });\n this.selectorNotFoundUnsub = this.recording.onSelectorNotFound((target) => {\n if (this.smartSelectorEnabled) this.showSelectorPicker(target);\n });\n // Re-render the widget chrome when the UI language changes so labels update live.\n this.langUnsub = this.translation.onLangChange(() => this.render());\n }\n\n private showSelectorPicker(target: HTMLElement): void {\n import('../../components/selector-picker/selector-picker').then(() => {\n const existing = document.querySelector('lib-e2e-selector-picker');\n if (existing) existing.remove();\n\n const picker = document.createElement('lib-e2e-selector-picker') as unknown as SelectorPickerEl;\n picker.targetElement = target;\n picker.recording = this.recording;\n picker.translation = this.translation;\n document.body.appendChild(picker as unknown as Node);\n });\n }\n\n private async initVisibility(): Promise<void> {\n if (this.hasAttribute('start-hidden')) {\n // Attribute overrides DB: presence → hidden, explicit \"false\" → visible\n this.isVisible = this.getAttribute('start-hidden') === 'false';\n this.style.display = this.isVisible ? '' : 'none';\n return;\n }\n const config = await this.persistence.getGeneralConfig();\n this.isVisible = config?.['startHidden'] !== 'true';\n this.style.display = this.isVisible ? '' : 'none';\n }\n\n private async initSelectorStrategy(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n const strategy = config?.['selectorStrategy'] as string | undefined;\n if (strategy) this.recording.selectorStrategy = strategy as SelectorStrategy;\n this.smartSelectorEnabled = config?.['smartSelectorEnabled'] !== 'false';\n this.issueTrackerConfig = {\n enabled: config?.['issueTrackerEnabled'] === 'true',\n provider: (config?.['issueTrackerProvider'] as IssueTrackerProvider) ?? DEFAULT_ISSUE_TRACKER_CONFIG.provider,\n baseUrl: (config?.['issueTrackerBaseUrl'] as string) ?? '',\n };\n }\n\n // ── cross-app session continuity (spec 006) ───────────────────────────────\n\n /**\n * On mount, detect a persisted live recording session and either resume it\n * silently (recent) or prompt continue/discard (stale). No-op when there is\n * no actively-recording session.\n */\n private async initSessionContinuity(): Promise<void> {\n if (this._isDisabled) return;\n const session = await this.persistence.getActiveSession();\n if (!session || !session.isRecording) return;\n const ttlMin = await this.getResumeTtlMinutes();\n const ageMs = Date.now() - session.updatedAt;\n if (ageMs <= ttlMin * 60_000) {\n this.resumeSessionState(session);\n } else {\n this.promptResumeOrDiscard(session);\n }\n }\n\n private async getResumeTtlMinutes(): Promise<number> {\n const config = await this.persistence.getConfig(RESUME_TTL_CONFIG_KEY);\n const raw = config?.[RESUME_TTL_CONFIG_KEY];\n const n = typeof raw === 'number' ? raw : Number(raw);\n return Number.isFinite(n) && n > 0 ? n : DEFAULT_RESUME_TTL_MINUTES;\n }\n\n /** Rehydrates the recorder from a persisted session (no bootstrap re-emitted). */\n private resumeSessionState(session: ActiveSessionState): void {\n this.recording.restoreSession(session);\n this.cypressCommands = session.commands;\n this.interceptors = session.interceptors;\n this.controlFirstTimeData = false;\n this.render();\n }\n\n private async promptResumeOrDiscard(session: ActiveSessionState): Promise<void> {\n const t = this.translation.translate.bind(this.translation);\n const result = await Swal.fire({\n title: t('RECORDER.SESSION_RESUME_TITLE'),\n html:\n `<div style=\"padding:8px 4px;color:#8b949e;font-size:13px;line-height:1.6\">` +\n `<p>${t('RECORDER.SESSION_RESUME_TEXT')}</p>` +\n `<p style=\"margin-top:6px;color:#c9d1d9\"><b>${session.commands.length}</b> ${t('RECORDER.SESSION_RESUME_COUNT')}</p>` +\n `</div>`,\n showCancelButton: true,\n confirmButtonText: t('RECORDER.SESSION_CONTINUE_BTN'),\n cancelButtonText: t('RECORDER.SESSION_DISCARD_BTN'),\n color: '#e6edf3',\n });\n if (result && (result as { isConfirmed?: boolean }).isConfirmed) {\n this.resumeSessionState(session);\n } else {\n this.discardSession();\n }\n }\n\n /** Debounced persistence of the live session; clears it the moment recording stops. */\n private persistActiveSession(state: ActiveSessionState): void {\n if (this._isDisabled) return;\n if (!state.isRecording) {\n this.clearSessionPersistence();\n return;\n }\n this.writeSessionBreadcrumb(state);\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\n this.sessionSaveTimer = setTimeout(() => {\n const snap = this.recording.getSessionSnapshot();\n if (snap.isRecording) this.persistence.saveActiveSession(snap).catch(() => { /* storage errors are non-fatal */ });\n }, 300);\n }\n\n private writeSessionBreadcrumb(state: ActiveSessionState): void {\n try {\n localStorage.setItem(ACTIVE_SESSION_BREADCRUMB_KEY, JSON.stringify({\n sessionId: state.sessionId,\n isRecording: state.isRecording,\n updatedAt: state.updatedAt,\n }));\n } catch { /* ignore storage errors */ }\n }\n\n private flushActiveSessionOnDisconnect(): void {\n const snap = this.recording.getSessionSnapshot();\n if (!snap.isRecording) return;\n if (this.sessionSaveTimer) clearTimeout(this.sessionSaveTimer);\n this.writeSessionBreadcrumb(snap);\n this.persistence.saveActiveSession(snap).catch(() => { /* non-fatal */ });\n }\n\n private clearSessionPersistence(): void {\n if (this.sessionSaveTimer) { clearTimeout(this.sessionSaveTimer); this.sessionSaveTimer = undefined; }\n try { localStorage.removeItem(ACTIVE_SESSION_BREADCRUMB_KEY); } catch { /* ignore */ }\n this.persistence.clearActiveSession().catch(() => { /* non-fatal */ });\n }\n\n /** True when a synchronous breadcrumb marks an active recording session. */\n hasActiveSession(): boolean {\n try {\n const raw = localStorage.getItem(ACTIVE_SESSION_BREADCRUMB_KEY);\n if (!raw) return false;\n return !!(JSON.parse(raw) as { isRecording?: boolean }).isRecording;\n } catch { return false; }\n }\n\n /** Programmatically resume the persisted session, if any. */\n resumeSession(): void {\n this.persistence.getActiveSession().then((s) => { if (s) this.resumeSessionState(s); });\n }\n\n /** Discard the persisted live session (breadcrumb + DB record). */\n discardSession(): void {\n this.clearSessionPersistence();\n }\n\n // ── draggable widget (spec 007) ────────────────────────────────────────────\n\n /** Loads a previously saved widget position and applies it. */\n private async initWidgetPosition(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n const pos = config?.['widgetPosition'] as Partial<Point> | null | undefined;\n if (pos && typeof pos.x === 'number' && typeof pos.y === 'number') {\n this.togglePos = { x: pos.x, y: pos.y };\n }\n this.applyWidgetPosition();\n }\n\n /** Positions the `.widget` box from the (clamped) toggle centre and orients the arc. */\n private applyWidgetPosition(): void {\n const widget = this.shadow.querySelector('.widget') as HTMLElement | null;\n if (!widget) return;\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const centre = this.togglePos ?? defaultTogglePosition(vw, vh);\n const clamped = clampTogglePosition(centre.x, centre.y, vw, vh);\n this.expandDir = resolveExpandDirection(clamped.x, clamped.y, vw, vh);\n const topLeft = boxTopLeftFor(clamped, this.expandDir);\n widget.style.left = `${topLeft.x}px`;\n widget.style.top = `${topLeft.y}px`;\n widget.style.right = 'auto';\n widget.style.bottom = 'auto';\n widget.setAttribute('data-expand', this.expandDir);\n }\n\n private beginWidgetDrag(e: MouseEvent): void {\n // Clear any stale suppression from a previous drag that ended off the toggle\n // (no click fired there), so this fresh press can't swallow a genuine click.\n this.suppressNextToggleClick = false;\n const origin = this.togglePos ?? defaultTogglePosition(window.innerWidth, window.innerHeight);\n this.dragState = { startX: e.clientX, startY: e.clientY, origX: origin.x, origY: origin.y, moved: false };\n }\n\n private onWidgetPointerMove(e: MouseEvent): void {\n if (!this.dragState) return;\n const dx = e.clientX - this.dragState.startX;\n const dy = e.clientY - this.dragState.startY;\n if (!this.dragState.moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;\n this.dragState.moved = true;\n this.togglePos = { x: this.dragState.origX + dx, y: this.dragState.origY + dy };\n this.applyWidgetPosition();\n }\n\n private onWidgetPointerUp(): void {\n if (!this.dragState) return;\n const moved = this.dragState.moved;\n this.dragState = undefined;\n if (!moved || !this.togglePos) return;\n // It was a drag, not a click: suppress the click that fires next and persist.\n this.suppressNextToggleClick = true;\n const clamped = clampTogglePosition(this.togglePos.x, this.togglePos.y, window.innerWidth, window.innerHeight);\n this.togglePos = clamped;\n this.persistence.setConfig({ widgetPosition: clamped }).catch(() => { /* non-fatal */ });\n }\n\n /** Resets the widget to its default corner and clears the saved position. */\n resetWidgetPosition(): void {\n this.togglePos = null;\n this.persistence.setConfig({ widgetPosition: null }).catch(() => { /* non-fatal */ });\n this.applyWidgetPosition();\n }\n\n toggle(): void {\n this.recording.toggleRecording();\n }\n\n togglePause(): void {\n this.recording.togglePause();\n }\n\n setLanguage(lang?: string): void {\n const resolved = lang ? (lang as Lang) : this.translation.detectLang();\n this.translation.setLang(resolved);\n }\n\n handleKeyboardEvent(event: KeyboardEvent): void {\n if (!event.ctrlKey) return;\n const key = event.key.toLowerCase();\n if (key === 'e' && event.shiftKey) { event.preventDefault(); this.toggleVisibility(); return; }\n if (!this.isVisible) return;\n if (key === 'r') { event.preventDefault(); this.toggle(); }\n else if (key === 'p') { event.preventDefault(); this.togglePause(); }\n else if (key === '1') { event.preventDefault(); this.showSavedTestsDialog(); }\n else if (key === '2') { event.preventDefault(); this.showCommandsDialog(); }\n else if (key === '3') { event.preventDefault(); this.showSettingsDialog(); }\n else if (key === 'h' && event.shiftKey) { event.preventDefault(); this.showHelpDialog(); }\n }\n\n toggleVisibility(): void {\n this.isVisible = !this.isVisible;\n this.style.display = this.isVisible ? '' : 'none';\n }\n\n // ── recording history (task 5) ────────────────────────────────────────────\n\n private saveRecordingHistory(): void {\n if (!this.cypressCommands.length) return;\n try {\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\n existing.unshift({ commands: this.cypressCommands, interceptors: this.interceptors, savedAt: Date.now() });\n if (existing.length > 5) existing.splice(5);\n localStorage.setItem('e2e-recording-history', JSON.stringify(existing));\n } catch { /* ignore storage errors */ }\n }\n\n recoverLastRecording(): void {\n try {\n const existing = JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\n if (!existing.length) return;\n const { commands, interceptors } = existing[0];\n commands.forEach((cmd: string) => this.recording.appendCommand(cmd));\n (interceptors as string[]).forEach((_icp: string) => { /* interceptors are not appendable the same way */ });\n } catch { /* ignore */ }\n }\n\n clearRecordingHistory(): void {\n localStorage.removeItem('e2e-recording-history');\n }\n\n getRecordingHistory(): Array<{ commands: string[]; interceptors: string[]; savedAt: number }> {\n try {\n return JSON.parse(localStorage.getItem('e2e-recording-history') ?? '[]');\n } catch { return []; }\n }\n\n // ── filesystem setup ─────────────────────────────────────────────────────\n\n private async initFilesystemAccess(): Promise<void> {\n const config = await this.persistence.getGeneralConfig();\n // Only show if the user has never made a choice (key doesn't exist yet)\n if (config && 'allowReadWriteFiles' in config) return;\n this.showFilesystemSetupDialog();\n }\n\n private showFilesystemSetupDialog(): void {\n const t = this.translation.translate.bind(this.translation);\n Swal.fire({\n title: t('RECORDER.FS_TITLE'),\n html: '<div id=\"fs-setup-content\"></div>',\n showCloseButton: true,\n showConfirmButton: false,\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n const container = document.getElementById('fs-setup-content');\n if (!container) return;\n mountFilesystemSetupContent(\n container,\n t,\n async () => {\n await this.persistence.setConfigKey('allowReadWriteFiles', 'false');\n Swal.close();\n },\n async () => {\n try {\n await this.persistence.requestDirectoryPermissions();\n Swal.close();\n showToast(t('RECORDER.FS_SUCCESS_TOAST'));\n } catch (e: unknown) {\n if ((e as DOMException)?.name !== 'AbortError') {\n showToast(t('RECORDER.FS_ERROR_TOAST'), false);\n }\n // AbortError = user cancelled the picker, leave dialog open\n }\n },\n );\n },\n });\n }\n\n // ── dialogs ──────────────────────────────────────────────────────────────\n\n showCommandsDialog(): void {\n this.openSwalDialog(\n 'isCommandsDialogOpen',\n 'commands-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.DIALOG_COMMANDS'),\n html: '<div id=\"commands-modal-content\" style=\"min-height:250px;padding:0\"></div>',\n showCloseButton: true, allowOutsideClick: false, backdrop: false, width: 640,\n },\n (container) => {\n const child = mountComponentInSwal<PrevisualizerEl>('lib-e2e-test-previsualizer', container, {\n translation: this.translation,\n commands: this.cypressCommands,\n interceptors: this.interceptors,\n editable: true,\n }, [\n { name: 'deletecommand', handler: (e) => this.recording.removeCommand(e.detail) },\n { name: 'movecommand', handler: (e) => this.recording.moveCommand(e.detail.from, e.detail.to) },\n { name: 'deleteinterceptor', handler: (e) => this.recording.removeInterceptor(e.detail) },\n ]);\n this._previsualizerRef = child;\n injectAssertionBuilder(container, this.translation.translate.bind(this.translation), (cmd) => this.recording.appendCommand(cmd));\n },\n {\n // Make the container click-through so the page underneath remains interactive\n onDidOpenPreamble: () => {\n const swalContainer = document.querySelector('.swal2-container') as HTMLElement | null;\n if (swalContainer) {\n swalContainer.style.pointerEvents = 'none';\n const popup = swalContainer.querySelector('.swal2-popup') as HTMLElement | null;\n if (popup) popup.style.pointerEvents = 'all';\n }\n },\n onWillClose: () => { this._previsualizerRef = null; },\n },\n );\n }\n\n showSavedTestsDialog(): void {\n this.openSwalDialog(\n 'isSavedTestsDialogOpen',\n 'saved-tests-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVED_TESTS'),\n html: '<div id=\"saved-tests-modal-content\" style=\"min-height:250px;padding:0\"></div>',\n showCloseButton: true, width: 680,\n },\n (container) => {\n mountComponentInSwal<TestEditorEl>('lib-e2e-test-editor', container, {\n persistence: this.persistence,\n translation: this.translation,\n issueTrackerConfig: this.issueTrackerConfig,\n });\n },\n );\n }\n\n showSaveTestDialog(): void {\n this.openSwalDialog(\n 'isSaveTestDialogOpen',\n 'save-test-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.DIALOG_SAVE'),\n html: '<div id=\"save-test-modal-content\" style=\"padding:0\"></div>',\n showCloseButton: false, allowOutsideClick: false, allowEscapeKey: false,\n },\n (container) => {\n mountComponentInSwal<SaveTestEl>('lib-e2e-save-test', container, {\n translation: this.translation,\n issueTrackerConfig: this.issueTrackerConfig,\n }, [\n { name: 'savetest', handler: (e) => {\n const { description, notes, tags, ticketId } = e.detail ?? {};\n this.onSaveTest(description ?? null, tags ?? [], notes ?? '', ticketId ?? '');\n Swal.close();\n }},\n { name: 'saveandexport', handler: (e) => {\n const { description, notes, tags, ticketId } = e.detail ?? {};\n this.onSaveAndExportTest(description ?? null, tags ?? [], notes ?? '', ticketId ?? '');\n Swal.close();\n }},\n ]);\n },\n { skipResize: true },\n );\n }\n\n showSettingsDialog(): void {\n this.openSwalDialog(\n 'isSettingsDialogOpen',\n 'settings-modal-content',\n {\n title: this.translation.translate('MAIN_FRAME.SETTINGS'),\n html: '<div id=\"settings-modal-content\" style=\"padding:0\"></div>',\n showCloseButton: true, width: 520,\n },\n (container) => {\n mountComponentInSwal<ConfigEl>('lib-e2e-configuration', container, {\n persistence: this.persistence,\n translation: this.translation,\n }, [\n { name: 'smartselectorchange', handler: (e) => { this.smartSelectorEnabled = e.detail; } },\n { name: 'starthiddenchange', handler: (e) => {\n this.isVisible = !e.detail;\n this.style.display = this.isVisible ? '' : 'none';\n }},\n { name: 'resetwidgetposition', handler: () => this.resetWidgetPosition() },\n { name: 'issuetrackerchange', handler: (e) => { this.issueTrackerConfig = e.detail as IssueTrackerConfig; } },\n ]);\n },\n );\n }\n\n showHelpDialog(): void {\n this.openSwalDialog(\n 'isHelpDialogOpen',\n 'help-modal-content',\n {\n title: this.translation.translate('HELP.TITLE'),\n html: '<div id=\"help-modal-content\" style=\"padding:0\"></div>',\n showCloseButton: true, width: 560,\n },\n (container) => {\n mountComponentInSwal<HelpPanelEl>('lib-e2e-help-panel', container, {\n translation: this.translation,\n });\n },\n );\n }\n\n showAdvancedEditorDialog(testId?: number): void {\n this.toggleModal('isAdvancedEditorDialogOpen', () => {\n Swal.fire({\n title: this.translation.translate('MAIN_FRAME.SHOW_ADVANCED_EDITOR'),\n html: '<div id=\"advanced-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\n showCloseButton: true,\n showConfirmButton: false,\n allowOutsideClick: false,\n width: 780,\n color: '#e6edf3',\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n ensurePopupDimensions(Swal.getPopup(), 600);\n const container = document.getElementById('advanced-editor-modal-content');\n if (!container) return;\n const child = mountComponentInSwal<AdvancedEditorEl>('lib-e2e-advanced-test-editor', container, {\n persistence: this.persistence,\n translation: this.translation,\n ...(testId !== undefined ? { testId } : {}),\n }, [\n { name: 'selectorstrategychange', handler: (e) => { this.recording.selectorStrategy = e.detail; } },\n { name: 'closemodal', handler: () => Swal.close() },\n { name: 'openfileeditor', handler: (e) => {\n Swal.close();\n setTimeout(() => this.showFileEditorDialog(\n e.detail.handle, e.detail.content, e.detail.fileName, e.detail.testId,\n e.detail.itBlock, e.detail.interceptorsBlock, e.detail.notes,\n ), 150);\n }},\n ]);\n void this.persistence.getLoginSetup().then(cfg => { child.loginSetupConfig = cfg; });\n },\n willClose: () => { this.isAdvancedEditorDialogOpen = false; },\n });\n setTimeout(() => {\n const popup = Swal.getPopup();\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 0 });\n }, 0);\n });\n }\n\n private showFileEditorDialog(\n handle: FileSystemFileHandle,\n content: string,\n fileName: string,\n testId?: number,\n itBlock = '',\n interceptorsBlock = '',\n notes = '',\n ): void {\n Swal.fire({\n title: this.translation.translate('RECORDER.FILE_EDITOR_TITLE'),\n html: '<div id=\"file-editor-modal-content\" style=\"flex:1;min-height:0;display:flex;flex-direction:column;padding:0\"></div>',\n showCloseButton: false,\n showConfirmButton: false,\n allowOutsideClick: false,\n width: 1100,\n color: '#e6edf3',\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n // Give the code editor a tall default height (otherwise the popup collapses\n // to its ~210px min-height and the user has to resize it every time).\n ensurePopupDimensions(Swal.getPopup(), 640);\n const container = document.getElementById('file-editor-modal-content');\n if (!container) return;\n mountComponentInSwal<FilePreviewEl>('lib-e2e-file-preview', container, {\n translation: this.translation,\n fileContent: content,\n fileName,\n closeLabel: this.translation.translate('FILE_PREVIEW.BACK_TO_EDITOR'),\n itBlock,\n interceptorsBlock,\n notes,\n }, [\n { name: 'close', handler: () => {\n Swal.close();\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\n }},\n { name: 'save', handler: async (e) => {\n try {\n const writable = await handle.createWritable();\n await writable.write(e.detail);\n await writable.close();\n showToast(this.translation.translate('RECORDER.FILE_SAVED_TOAST'));\n } catch {\n showToast(this.translation.translate('RECORDER.FILE_SAVE_ERROR_TOAST'), false);\n }\n Swal.close();\n setTimeout(() => this.showAdvancedEditorDialog(testId), 150);\n }},\n ]);\n },\n });\n this.resizePopup();\n }\n\n // ── save handlers ─────────────────────────────────────────────────────────\n\n private async onSaveTest(description: string | null, tags: string[] = [], notes = '', ticketId = ''): Promise<void> {\n if (!description) return;\n // Plain save → IndexedDB only, spy interceptors with inline validations.\n // No fixture files written regardless of fixture mode (spec 012).\n await this.persistence.insertTest(description, this.cypressCommands, this.interceptors, tags, notes, ticketId || undefined);\n\n const uploadedFiles = this.recording.getUploadedFilesSnapshot();\n if (uploadedFiles.length > 0) {\n const filenames = uploadedFiles.map(f => f.filename).join(', ');\n showToast(\n this.translation.translate('RECORDER.FILE_UPLOAD_MANUAL_TOAST').replace('{files}', filenames),\n false,\n );\n }\n\n this.recording.clearCommands();\n this.clearRecordingHistory();\n this.cypressCommands = [];\n this.interceptors = [];\n }\n\n private async onSaveAndExportTest(description: string | null, tags: string[] = [], notes = '', ticketId = ''): Promise<void> {\n if (!description) return;\n\n const fixtures = this.recording.getFixturesSnapshot();\n const isFixtureMode = this.httpMonitor?.isFixtureModeEnabled() ?? false;\n let finalInterceptors = this.interceptors;\n let finalCommands = this.cypressCommands;\n\n // Fixture mode + Save-and-Edit: attempt to write fixture files and convert\n // spy interceptors to fixture stubs. Falls back to spy on no folder/permission.\n if (isFixtureMode && fixtures.length > 0) {\n try {\n const n = await this.persistence.writeFixtures(fixtures);\n finalInterceptors = toFixtureInterceptors(this.interceptors, fixtures);\n finalCommands = simplifyFixtureWaits(this.cypressCommands, fixtures);\n showToast(`${this.translation.translate('RECORDER.FIXTURES_WRITTEN_TOAST')} (${n})`);\n } catch {\n showToast(this.translation.translate('RECORDER.FIXTURES_NO_FOLDER_TOAST'), false);\n }\n }\n\n const uploadedFiles = this.recording.getUploadedFilesSnapshot();\n if (uploadedFiles.length > 0) {\n const filenames = uploadedFiles.map(f => f.filename).join(', ');\n const hasAccess = await this.persistence.hasDirectoryAccess();\n if (hasAccess) {\n try {\n for (const uf of uploadedFiles) {\n await this.persistence.writeUploadedFile(uf.filename, uf.bytes);\n }\n showToast(this.translation.translate('RECORDER.FILE_UPLOAD_COPIED_TOAST').replace('{files}', filenames));\n } catch {\n showToast(\n this.translation.translate('RECORDER.FILE_UPLOAD_COPY_ERROR_TOAST').replace('{files}', filenames),\n false,\n );\n }\n } else {\n showToast(\n this.translation.translate('RECORDER.FILE_UPLOAD_MANUAL_TOAST').replace('{files}', filenames),\n false,\n );\n }\n }\n\n const id = await this.persistence.insertTest(description, finalCommands, finalInterceptors, tags, notes, ticketId || undefined);\n this.recording.clearCommands();\n this.clearRecordingHistory();\n this.cypressCommands = [];\n this.interceptors = [];\n setTimeout(() => this.showAdvancedEditorDialog(id), 300);\n }\n\n // ── helpers ───────────────────────────────────────────────────────────────\n\n private toggleModal(flag: keyof this, openFn: () => void): void {\n if (this[flag]) {\n Swal.close();\n (this as Record<string, unknown>)[flag as string] = false;\n return;\n }\n (this as Record<string, unknown>)[flag as string] = true;\n openFn();\n }\n\n private resizePopup(): void {\n setTimeout(() => {\n const popup = Swal.getPopup();\n if (popup) makeModalResizable(popup, { minWidth: 400, minHeight: 200 });\n }, 0);\n }\n\n private openSwalDialog(\n flag: keyof this,\n contentId: string,\n swalOptions: SweetAlertOptions,\n onMount: (container: HTMLElement) => void,\n extra?: { onDidOpenPreamble?: () => void; onWillClose?: () => void; skipResize?: boolean },\n ): void {\n this.toggleModal(flag, () => {\n Swal.fire({\n showConfirmButton: false,\n color: '#e6edf3',\n ...swalOptions,\n didOpen: () => {\n makeSwalDraggable();\n setSwal2DataCyAttribute();\n extra?.onDidOpenPreamble?.();\n const container = document.getElementById(contentId);\n if (!container) return;\n onMount(container);\n },\n willClose: () => {\n (this as Record<string, unknown>)[flag as string] = false;\n extra?.onWillClose?.();\n },\n });\n if (!extra?.skipResize) this.resizePopup();\n });\n }\n\n private render(): void {\n const rec = this.isRecording;\n const paused = this.isPaused;\n this.style.display = this.isVisible ? '' : 'none';\n this.shadow.innerHTML = `<style>${getRecorderStyles(rec, paused)}</style>${renderRecorderWidget(rec, paused, this.translation.translate.bind(this.translation))}`;\n const toggleBtn = this.shadow.querySelector('[data-action=\"toggle\"]');\n toggleBtn?.addEventListener('click', () => {\n // A drag ends with a click event we must swallow so it doesn't toggle recording.\n if (this.suppressNextToggleClick) { this.suppressNextToggleClick = false; return; }\n this.toggle();\n });\n toggleBtn?.addEventListener('pointerdown', (e) => this.beginWidgetDrag(e as MouseEvent));\n this.shadow.querySelector('[data-action=\"pause\"]')\n ?.addEventListener('click', () => this.togglePause());\n this.shadow.querySelector('[data-action=\"tests\"]')\n ?.addEventListener('click', () => this.showSavedTestsDialog());\n this.shadow.querySelector('[data-action=\"commands\"]')\n ?.addEventListener('click', () => this.showCommandsDialog());\n this.shadow.querySelector('[data-action=\"config\"]')\n ?.addEventListener('click', () => this.showSettingsDialog());\n this.shadow.querySelector('[data-action=\"browse\"]')\n ?.addEventListener('click', () => this.showAdvancedEditorDialog());\n this.shadow.querySelector('[data-action=\"help\"]')\n ?.addEventListener('click', () => this.showHelpDialog());\n // Re-apply the dragged position/orientation after every re-render.\n this.applyWidgetPosition();\n }\n}\n\nif (!customElements.get('lib-e2e-recorder')) {\n customElements.define('lib-e2e-recorder', LibE2eRecorderElement);\n}\n","import type { ExpandDirection } from '../../utils/widget-position.utils';\n\nconst DIRECTIONS: ExpandDirection[] = ['up-left', 'up-right', 'down-left', 'down-right'];\n\n/**\n * Per-direction anchors for the toggle/pause buttons and the action-menu popover.\n * The menu opens on the side of the FAB that faces the viewport interior, so it\n * stays on-screen wherever the (draggable) widget is dropped (spec 007 + 012).\n */\nfunction directionBlocks(): string {\n return DIRECTIONS.map((dir) => {\n const tv = dir.startsWith('up') ? 'bottom' : 'top'; // FAB vertical side\n const th = dir.endsWith('left') ? 'right' : 'left'; // FAB horizontal side\n const ov = tv === 'bottom' ? 'top' : 'bottom';\n const oh = th === 'right' ? 'left' : 'right';\n const sel = `.widget[data-expand=\"${dir}\"]`;\n return `\n ${sel} .btn-toggle { ${tv}: 24px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\n ${sel} .btn-pause { ${tv}: 78px; ${th}: 24px; ${ov}: auto; ${oh}: auto; }\n ${sel} .action-menu { ${tv}: 118px; ${th}: 8px; ${ov}: auto; ${oh}: auto; transform-origin: ${tv} ${th}; }\n `;\n }).join('\\n');\n}\n\nexport function getRecorderStyles(rec: boolean, paused: boolean): string {\n return `\n :host { all: initial; }\n *, *::before, *::after { box-sizing: border-box; }\n\n /*\n * Hit area. Position (left/top) is set from JS so the widget can be dragged;\n * data-expand orients the action-menu popover toward the viewport interior.\n * The menu is a DOM child, so hovering it keeps :host(.widget):hover alive even\n * though it visually overflows this box. Defaults to bottom-right.\n */\n .widget {\n position: fixed;\n bottom: 0;\n right: 0;\n width: 190px;\n height: 190px;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n }\n\n /* ── Toggle (FAB) ─────────────────────────────────── */\n .btn-toggle {\n position: absolute;\n bottom: 24px;\n right: 24px;\n width: 44px;\n height: 44px;\n border-radius: 50%;\n border: none;\n cursor: grab;\n touch-action: none;\n font-size: 19px;\n background: ${rec\n ? 'linear-gradient(135deg,#f85149 0%,#da3633 100%)'\n : 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'};\n color: #fff;\n box-shadow: ${rec\n ? '0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13)'\n : '0 4px 20px rgba(47,129,247,.45),0 0 0 4px rgba(47,129,247,.11)'};\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform .18s, box-shadow .2s;\n z-index: 2;\n ${rec ? 'animation: toggle-pulse 2s ease-in-out infinite;' : ''}\n }\n .btn-toggle:hover { transform: scale(1.1); }\n .btn-toggle:active { transform: scale(0.93); cursor: grabbing; }\n\n @keyframes toggle-pulse {\n 0%,100% { box-shadow: 0 4px 20px rgba(248,81,73,.55),0 0 0 4px rgba(248,81,73,.13); }\n 50% { box-shadow: 0 6px 28px rgba(248,81,73,.75),0 0 0 8px rgba(248,81,73,.06); }\n }\n\n /* ── Pause button ────────────────────────────────── */\n .btn-pause {\n position: absolute;\n bottom: 78px;\n right: 24px;\n width: 34px;\n height: 34px;\n border-radius: 50%;\n border: none;\n cursor: pointer;\n font-size: 15px;\n display: ${rec ? 'flex' : 'none'};\n align-items: center;\n justify-content: center;\n background: ${paused\n ? 'linear-gradient(135deg,#2f81f7 0%,#1f6feb 100%)'\n : 'rgba(13,17,23,0.85)'};\n color: ${paused ? '#fff' : '#e3b341'};\n box-shadow: 0 2px 12px rgba(0,0,0,.4), 0 0 0 1px rgba(48,54,61,.8);\n transition: transform .15s, background .2s, color .2s;\n z-index: 2;\n }\n .btn-pause:hover { transform: scale(1.12); }\n .btn-pause:active { transform: scale(0.93); }\n\n /* ── Action menu (labelled grid popover) ─────────── */\n .action-menu {\n position: absolute;\n display: grid;\n grid-template-columns: repeat(3, 1fr);\n gap: 4px;\n padding: 8px;\n width: 174px;\n background: rgba(13,17,23,.97);\n border: 1px solid rgba(48,54,61,.9);\n border-radius: 12px;\n box-shadow: 0 8px 28px rgba(0,0,0,.5);\n backdrop-filter: blur(14px);\n -webkit-backdrop-filter: blur(14px);\n opacity: 0;\n transform: scale(0.9);\n pointer-events: none;\n transition: opacity .16s, transform .2s cubic-bezier(.34,1.56,.64,1);\n z-index: 3;\n }\n .widget:hover .action-menu {\n opacity: 1;\n transform: scale(1);\n pointer-events: all;\n }\n\n .action-item {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: flex-start;\n gap: 3px;\n padding: 8px 4px;\n border: none;\n border-radius: 8px;\n cursor: pointer;\n background: transparent;\n color: #c9d1d9;\n font-size: 18px;\n line-height: 1;\n transition: background .12s;\n }\n .action-item:hover { background: #21262d; }\n .action-item .label {\n font-size: 9px;\n font-weight: 500;\n color: #8b949e;\n white-space: nowrap;\n }\n .action-item:hover .label { color: #e6edf3; }\n\n /* Per-direction anchors */\n ${directionBlocks()}\n\n /* ── REC / PAUSED badge ──────────────────────────── */\n .rec-badge {\n position: fixed;\n top: 14px;\n left: 50%;\n transform: translateX(-50%);\n background: ${paused\n ? 'linear-gradient(90deg,#e3b341,#d29922)'\n : 'linear-gradient(90deg,#f85149,#da3633)'};\n color: #fff;\n padding: 3px 16px;\n border-radius: 20px;\n font-size: 10px;\n font-weight: 700;\n letter-spacing: 2px;\n text-transform: uppercase;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n box-shadow: ${paused\n ? '0 4px 16px rgba(227,179,65,.4)'\n : '0 4px 16px rgba(248,81,73,.4)'};\n display: ${rec ? 'block' : 'none'};\n ${!paused ? 'animation: rec-pulse 1.8s ease-in-out infinite;' : ''}\n }\n @keyframes rec-pulse {\n 0%,100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n `;\n}\n","export function renderRecorderWidget(rec: boolean, paused: boolean, t: (key: string) => string): string {\n return `\n <div class=\"widget\">\n <div class=\"action-menu\">\n <button class=\"action-item\" data-action=\"config\">\n <span class=\"ico\">⚙️</span><span class=\"label\">${t('RECORDER.BTN_CONFIG')}</span></button>\n <button class=\"action-item\" data-action=\"browse\">\n <span class=\"ico\">📁</span><span class=\"label\">${t('RECORDER.BTN_FILES')}</span></button>\n <button class=\"action-item\" data-action=\"commands\">\n <span class=\"ico\">⌨️</span><span class=\"label\">${t('RECORDER.BTN_COMMANDS')}</span></button>\n <button class=\"action-item\" data-action=\"tests\">\n <span class=\"ico\">📋</span><span class=\"label\">${t('RECORDER.BTN_TESTS')}</span></button>\n <button class=\"action-item\" data-action=\"help\">\n <span class=\"ico\">❓</span><span class=\"label\">${t('RECORDER.BTN_HELP')}</span></button>\n </div>\n <button class=\"btn-pause\" data-action=\"pause\"\n title=\"${paused ? t('RECORDER.RESUME_TITLE') : t('RECORDER.PAUSE_TITLE')}\">\n ${paused ? '▶' : '⏸'}\n </button>\n <button class=\"btn-toggle\" data-action=\"toggle\"\n title=\"${rec ? t('RECORDER.STOP_TITLE') : t('RECORDER.START_TITLE')}\">\n ${rec ? '⏹' : '⏺'}\n </button>\n </div>\n <div class=\"rec-badge\">${paused ? t('RECORDER.BADGE_PAUSED') : t('RECORDER.BADGE_REC')}</div>`;\n}\n","import { escapeSingleQuotes } from '../../utils/code-format.utils';\n\nconst NO_VALUE_ASSERTIONS = new Set(['be.visible', 'not.exist', 'be.disabled', 'be.checked']);\n\nexport function injectAssertionBuilder(\n container: HTMLElement,\n t: (key: string) => string,\n onAddCommand: (cmd: string) => void,\n): void {\n container.insertAdjacentHTML('beforeend', `\n <div id=\"assertion-builder\"\n style=\"padding:10px 12px;border-top:1px solid #21262d;background:#0d1117\">\n <div style=\"font-size:10px;color:#484f58;text-transform:uppercase;letter-spacing:.8px;font-weight:600;margin-bottom:8px\">\n ${t('RECORDER.ASSERTION_SECTION')}\n </div>\n <div style=\"display:flex;gap:6px;flex-wrap:wrap;align-items:flex-end\">\n <input id=\"assert-selector\" type=\"text\"\n placeholder=\"${t('RECORDER.ASSERT_SELECTOR_PH').replace(/\"/g, '"')}\"\n style=\"flex:2;min-width:140px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none;\n font-family:'Cascadia Code','Fira Code',monospace\"/>\n <select id=\"assert-type\"\n style=\"padding:5px 8px;background:#161b22;border:1px solid #30363d;border-radius:5px;\n color:#c9d1d9;font-size:11px;outline:none;cursor:pointer;flex-shrink:0\">\n <option value=\"be.visible\">be.visible</option>\n <option value=\"not.exist\">not.exist</option>\n <option value=\"be.disabled\">be.disabled</option>\n <option value=\"be.checked\">be.checked</option>\n <option value=\"contain.text\">contain.text</option>\n <option value=\"have.value\">have.value</option>\n <option value=\"have.length\">have.length</option>\n <option value=\"have.class\">have.class</option>\n <option value=\"have.attr\">have.attr</option>\n </select>\n <input id=\"assert-value\" type=\"text\" placeholder=\"${t('RECORDER.ASSERT_VALUE_PH')}\"\n style=\"flex:2;min-width:110px;padding:5px 8px;background:#161b22;border:1px solid #30363d;\n border-radius:5px;color:#c9d1d9;font-size:11px;outline:none\"/>\n <button id=\"btn-add-assertion\"\n style=\"padding:5px 12px;border:none;border-radius:5px;cursor:pointer;\n font-size:11px;font-weight:500;background:#2f81f7;color:#fff;\n white-space:nowrap;flex-shrink:0\">\n ${t('RECORDER.ASSERT_ADD_BTN')}\n </button>\n </div>\n </div>`);\n\n document.getElementById('btn-add-assertion')?.addEventListener('click', () => {\n const sel = (document.getElementById('assert-selector') as HTMLInputElement).value.trim();\n const type = (document.getElementById('assert-type') as HTMLSelectElement).value;\n const val = (document.getElementById('assert-value') as HTMLInputElement).value.trim();\n if (!sel) return;\n const s = escapeSingleQuotes(sel);\n const v = escapeSingleQuotes(val);\n const cmd = NO_VALUE_ASSERTIONS.has(type) || !val\n ? `cy.get('${s}').should('${type}')`\n : `cy.get('${s}').should('${type}', '${v}')`;\n onAddCommand(cmd);\n (document.getElementById('assert-selector') as HTMLInputElement).value = '';\n (document.getElementById('assert-value') as HTMLInputElement).value = '';\n });\n}\n","export function mountFilesystemSetupContent(\n container: HTMLElement,\n t: (key: string) => string,\n onSkip: () => Promise<void>,\n onSelect: () => Promise<void>,\n): void {\n container.innerHTML = `\n <div style=\"padding:16px 20px 20px;color:#8b949e;font-size:13px;line-height:1.7\">\n <p>${t('RECORDER.FS_INTRO_HTML')}</p>\n <p style=\"margin-top:10px;margin-bottom:6px;font-size:11px;color:#8b949e\">\n ${t('RECORDER.FS_STRUCTURE_HINT_HTML')}\n </p>\n <pre style=\"margin:0;padding:10px 14px;background:#0d1117;border:1px solid #21262d;\n border-radius:8px;font-size:11px;color:#c9d1d9;line-height:1.8;\n font-family:'Cascadia Code','Fira Code','Consolas',monospace\">\ncypress/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_PICK_HINT')}</span>\n└── e2e/ <span style=\"color:#484f58\">${t('RECORDER.FS_TREE_READ_HINT')}</span>\n └── *.cy.ts</pre>\n <p style=\"margin-top:8px;font-size:11px;color:#484f58\">\n ${t('RECORDER.FS_PERMISSION_NOTE')}\n </p>\n <div style=\"display:flex;gap:8px;justify-content:flex-end;margin-top:20px\">\n <button id=\"fs-skip\"\n style=\"padding:7px 16px;border:1px solid #30363d;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:transparent;color:#8b949e\">\n ${t('RECORDER.FS_LATER_BTN')}\n </button>\n <button id=\"fs-select\"\n style=\"padding:7px 16px;border:none;border-radius:6px;cursor:pointer;\n font-size:12px;font-weight:500;background:#2f81f7;color:#fff\">\n ${t('RECORDER.FS_SELECT_BTN')}\n </button>\n </div>\n </div>`;\n\n document.getElementById('fs-skip')?.addEventListener('click', () => { void onSkip(); });\n document.getElementById('fs-select')?.addEventListener('click', () => { void onSelect(); });\n}\n","export function mountComponentInSwal<T extends object>(\n tagName: string,\n container: HTMLElement,\n props: Partial<T>,\n events?: Array<{ name: string; handler: (e: CustomEvent) => void }>,\n): T {\n const el = document.createElement(tagName) as unknown as T;\n Object.assign(el, props);\n container.appendChild(el as unknown as Node);\n for (const { name, handler } of events ?? []) {\n (el as unknown as EventTarget).addEventListener(name, handler as EventListener);\n }\n return el;\n}\n","/**\n * Geometry helpers for the draggable recording widget (spec 007).\n * Pure functions — no DOM — so the drag/clamp/expansion logic is unit-testable\n * without real layout (jsdom returns 0-sized rects).\n */\n\nexport type ExpandDirection = 'up-left' | 'up-right' | 'down-left' | 'down-right';\n\nexport interface Point {\n x: number;\n y: number;\n}\n\n/** Toggle radius (44/2) + small gap, so the toggle never touches the edge. */\nexport const TOGGLE_MARGIN = 30;\n\n/** Pixels the pointer must travel before a press becomes a drag (vs a click). */\nexport const DRAG_THRESHOLD = 5;\n\n/** Distance, in px, from the bottom-right edges of the original (default) anchor. */\nconst DEFAULT_EDGE_OFFSET = 46;\n\n/**\n * Toggle-centre offset inside the 190×190 widget box, per expansion direction.\n * The toggle sits at the box corner nearest the screen edge so the arc always\n * expands toward the viewport interior (and stays inside the box / on screen).\n */\nexport function boxOffsetForDirection(dir: ExpandDirection): Point {\n return {\n x: dir.endsWith('left') ? 144 : 46,\n y: dir.startsWith('up') ? 144 : 46,\n };\n}\n\n/** Clamps the toggle-centre so the toggle button stays fully on screen. */\nexport function clampTogglePosition(\n x: number,\n y: number,\n vw: number,\n vh: number,\n margin: number = TOGGLE_MARGIN,\n): Point {\n const maxX = Math.max(margin, vw - margin);\n const maxY = Math.max(margin, vh - margin);\n return {\n x: Math.min(Math.max(x, margin), maxX),\n y: Math.min(Math.max(y, margin), maxY),\n };\n}\n\n/**\n * Chooses the radial expansion direction so the menu opens toward the centre of\n * the viewport (top half → expand down; left half → expand right).\n */\nexport function resolveExpandDirection(x: number, y: number, vw: number, vh: number): ExpandDirection {\n const vertical = y < vh / 2 ? 'down' : 'up';\n const horizontal = x < vw / 2 ? 'right' : 'left';\n return `${vertical}-${horizontal}` as ExpandDirection;\n}\n\n/** Default toggle-centre (bottom-right corner), matching the original CSS anchor. */\nexport function defaultTogglePosition(vw: number, vh: number): Point {\n return { x: vw - DEFAULT_EDGE_OFFSET, y: vh - DEFAULT_EDGE_OFFSET };\n}\n\n/** Box top-left for a given (clamped) toggle-centre and direction. */\nexport function boxTopLeftFor(toggleCentre: Point, dir: ExpandDirection): Point {\n const off = boxOffsetForDirection(dir);\n return { x: toggleCentre.x - off.x, y: toggleCentre.y - off.y };\n}\n","/**\n * Converts spy-style `cy.intercept(...)` strings to fixture-stub form when a\n * matching fixture exists, and simplifies the corresponding `cy.wait(...)` commands\n * by stripping inline body-validation callbacks (the data is now stubbed).\n *\n * These conversions are applied at save-and-export time (spec 012) so that:\n * - recording always uses spy interceptors (no decision about save mode needed);\n * - fixture stubs are only emitted when the user clicks \"Save and Edit\" AND the\n * Cypress folder has write permission.\n */\n\n/**\n * For each spy interceptor whose alias has a matching fixture, inserts the\n * `{ fixture: '<alias>.json' }` response body.\n *\n * Input: `cy.intercept('GET', '**\\/api').as('get-api')`\n * Output: `cy.intercept('GET', '**\\/api', { fixture: 'get-api.json' }).as('get-api')`\n */\nexport function toFixtureInterceptors(\n interceptors: string[],\n fixtures: Array<{ name: string }>,\n): string[] {\n const fixtureNames = new Set(fixtures.map((f) => f.name));\n return interceptors.map((icp) => {\n const match = icp.match(/\\.as\\('([^']+)'\\)$/);\n if (!match) return icp;\n const fixtureFile = `${match[1]}.json`;\n if (!fixtureNames.has(fixtureFile)) return icp;\n return icp.replace(/\\)\\.as\\(/, `, { fixture: '${fixtureFile}' }).as(`);\n });\n}\n\n/**\n * For each `cy.wait('@alias')` command whose alias maps to a captured fixture,\n * replaces any inline body-validation callback with the no-op form.\n *\n * Input: `cy.wait('@get-api').then((interception) => { expect(...) ... })`\n * Output: `cy.wait('@get-api').then((interception) => { })`\n */\nexport function simplifyFixtureWaits(\n commands: string[],\n fixtures: Array<{ name: string }>,\n): string[] {\n const fixtureAliases = new Set(fixtures.map((f) => f.name.replace(/\\.json$/, '')));\n return commands.map((cmd) => {\n const match = cmd.match(/^cy\\.wait\\('@([^']+)'\\)/);\n if (!match || !fixtureAliases.has(match[1])) return cmd;\n return `cy.wait('@${match[1]}').then((interception) => { })`;\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,IAAI,GAAW,GAAmB;AACzC,SAAO,GAAG;AAAE,UAAM,IAAI;AAAG,QAAI,IAAI;AAAG,QAAI;AAAA,EAAG;AAC3C,SAAO;AACT;AAOO,SAAS,mBAAmB,OAAuB;AACxD,SAAO,MAAM,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AACzD;AASO,SAAS,mBAAmB,OAAuB;AACxD,SAAO,MAAM,QAAQ,MAAM,KAAK;AAClC;AAeO,SAAS,eAAe,MAAc,YAA4B;AACvE,QAAM,QAAQ,KAAK,MAAM,IAAI,EAAE,IAAI,OAAK,EAAE,QAAQ,CAAC;AACnD,QAAM,WAAW,MAAM,OAAO,OAAK,EAAE,KAAK,EAAE,SAAS,CAAC;AACtD,MAAI,CAAC,SAAS,OAAQ,QAAO;AAE7B,QAAM,UAAU,SAAS,IAAI,OAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM;AACjE,QAAM,YAAY,KAAK,IAAI,GAAG,OAAO;AACrC,QAAM,aAAa,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,OAAK,IAAI,SAAS,EAAE,OAAO,OAAK,IAAI,CAAC,CAAC,CAAC;AAClF,QAAM,OAAO,WAAW,SAAS,IAAI,WAAW,OAAO,GAAG,IAAI;AAE9D,SAAO,MACJ,IAAI,OAAK;AACR,QAAI,CAAC,EAAE,KAAK,EAAG,QAAO;AACtB,UAAM,QAAQ,KAAK,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,aAAa,IAAI;AAC7E,WAAO,aAAa,KAAK,OAAO,KAAK,IAAI,EAAE,UAAU;AAAA,EACvD,CAAC,EACA,KAAK,IAAI;AACd;AAvDA;AAAA;AAAA;AAAA;AAAA;;;ACSO,SAAS,mBAAmB,IAAkC;AACnE,MACE,GAAG,aAAa,SAAS,KACzB,GAAG,aAAa,aAAa,KAC7B,GAAG,aAAa,YAAY,GAC5B;AACA,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,GAAG;AACjB,MACE,SACA,MAAM,SAAS,MACf,mBAAmB,KAAK,KAAK,KAC7B,CAAC,sBAAsB,KAAK,CAAC,MAAM,MAAM,WAAW,CAAC,CAAC,KACtD,CAAC,QAAQ,KAAK,KAAK,GACnB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,OAAO,GAAG,cAAc,YAAY,GAAG,UAAU,KAAK,EAAE,SAAS,GAAG;AACtE,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAGO,SAAS,oBAAoB,IAAyB;AAC3D,QAAM,SAAS,GAAG,aAAa,SAAS;AACxC,MAAI,OAAQ,QAAO,aAAa,mBAAmB,MAAM,CAAC;AAE1D,QAAM,aAAa,GAAG,aAAa,aAAa;AAChD,MAAI,WAAY,QAAO,iBAAiB,mBAAmB,UAAU,CAAC;AAEtE,QAAM,YAAY,GAAG,aAAa,YAAY;AAC9C,MAAI,UAAW,QAAO,gBAAgB,mBAAmB,SAAS,CAAC;AAEnE,QAAM,QAAQ,GAAG;AACjB,MACE,SACA,MAAM,SAAS,MACf,mBAAmB,KAAK,KAAK,KAC7B,CAAC,sBAAsB,KAAK,CAAC,MAAM,MAAM,WAAW,CAAC,CAAC,KACtD,CAAC,QAAQ,KAAK,KAAK,GACnB;AACA,WAAO,IAAI,KAAK;AAAA,EAClB;AAEA,MAAI,OAAO,GAAG,cAAc,YAAY,GAAG,UAAU,KAAK,EAAE,SAAS,GAAG;AACtE,UAAM,UAAU,GAAG,UAAU,KAAK,EAAE,MAAM,KAAK;AAC/C,WAAO,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE;AAAA,EAC5C;AAEA,SAAO,GAAG,QAAQ,YAAY;AAChC;AAGO,SAAS,eAAe,IAAyB;AACtD,aAAW,QAAQ,CAAC,WAAW,eAAe,YAAY,GAAG;AAC3D,UAAM,IAAI,GAAG,aAAa,IAAI;AAC9B,QAAI,EAAG,QAAO,GAAG,IAAI,KAAK,CAAC;AAAA,EAC7B;AACA,MAAI,GAAG,GAAI,QAAO,OAAO,GAAG,EAAE;AAC9B,MAAI,GAAG,aAAa,GAAG,UAAU,KAAK,GAAG;AACvC,WAAO,GAAG,UAAU,KAAK,EAAE,MAAM,KAAK,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE;AAAA,EACrE;AACA,SAAO;AACT;AAWO,SAAS,kBAAkB,IAA4B;AAC5D,SAAO;AAAA,IACL,SAAS,mBAAmB,EAAE;AAAA,IAC9B,UAAU,oBAAoB,EAAE;AAAA,IAChC,KAAK,GAAG,QAAQ,YAAY;AAAA,IAC5B,MAAM,eAAe,EAAE;AAAA,EACzB;AACF;AA/FA,IAIa;AAJb;AAAA;AAAA;AAAA;AAIO,IAAM,wBAAwB;AAAA,MACnC;AAAA,MAAQ;AAAA,MAAQ;AAAA,MAAM;AAAA,MAAO;AAAA,MAC7B;AAAA,MAAY;AAAA,MAAS;AAAA,MAAU;AAAA,MAAU;AAAA,IAC3C;AAAA;AAAA;;;ACPA,IAAa;AAAb;AAAA;AAAA;AAAO,IAAM,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA/B,SAAS,QAAQ,GAAmB;AACzC,SAAO,EAAE,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AAC5E;AAEO,SAAS,QAAQ,GAAmB;AACzC,SAAO,EAAE,QAAQ,MAAM,QAAQ,EAAE,QAAQ,MAAM,MAAM;AACvD;AANA;AAAA;AAAA;AAAA;AAAA;;;ACiBO,SAAS,iBACd,MACA,eACA,GACQ;AACR,SAAO,KAAK,IAAI,CAAC,KAAK,MAAM;AAC1B,UAAM,aAAa,MAAM;AACzB,UAAM,SAAS,IAAI,YAAY;AAE/B,WAAO;AAAA,uBACY,aAAa,cAAc,EAAE,eAAe,CAAC,kCAAkC,UAAU;AAAA,qCAC3E,cAAc,IAAI,OAAO,CAAC,YAAY,QAAQ,EAAE,2BAA2B,IAAI,QAAQ,YAAY,CAAC,EAAE,CAAC,CAAC;AAAA,YACjI,cAAc,IAAI,OAAO,CAAC;AAAA;AAAA,qCAED,QAAQ,IAAI,GAAG,CAAC;AAAA,UAC3C,IAAI,OAAO,4BAA4B,QAAQ,IAAI,IAAI,CAAC,YAAY,kCAAkC;AAAA,yCACvE,QAAQ,IAAI,QAAQ,CAAC;AAAA,UACpD,SAAS,qCAAqC,QAAQ,EAAE,8BAA8B,CAAC,CAAC,oBAAe,EAAE;AAAA;AAAA,EAEjH,CAAC,EAAE,KAAK,EAAE;AACZ;AAEO,SAAS,aACd,MACA,eACA,GACQ;AACR,SAAO;AAAA;AAAA,4BAEmB,QAAQ,EAAE,uBAAuB,CAAC,CAAC;AAAA;AAAA,UAErD,iBAAiB,MAAM,eAAe,CAAC,CAAC;AAAA;AAAA;AAAA,qDAGP,QAAQ,EAAE,+BAA+B,CAAC,CAAC;AAAA,8CACxC,QAAQ,EAAE,8BAA8B,CAAC,CAAC;AAAA,4CAC5C,QAAQ,EAAE,6BAA6B,CAAC,CAAC;AAAA;AAAA;AAGrF;AAxDA,IAGM,eAOA;AAVN;AAAA;AAAA;AACA;AAEA,IAAM,gBAAiD;AAAA,MACrD,WAAY;AAAA,MACZ,MAAY;AAAA,MACZ,YAAY;AAAA,MACZ,MAAY;AAAA,IACd;AAEA,IAAM,gBAAiD;AAAA,MACrD,WAAY;AAAA,MACZ,MAAY;AAAA,MACZ,YAAY;AAAA,MACZ,MAAY;AAAA,IACd;AAAA;AAAA;;;ACfA;AAAA;AAAA;AAAA;AAAA,IAOM,aACA,eAEO;AAVb;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAEA,IAAM,cAAc;AACpB,IAAM,gBAAgB;AAEf,IAAM,wBAAN,cAAoC,YAAY;AAAA,MACrD,gBAAoC;AAAA,MACpC;AAAA,MACA;AAAA,MAEQ;AAAA,MACA,YAA2B,CAAC;AAAA,MAC5B,OAAoB,CAAC;AAAA,MACrB,gBAAgB;AAAA,MAChB,aAAkD;AAAA,MAClD,iBAAsC;AAAA,MACtC,aAAkC;AAAA,MAE1C,cAAc;AACZ,cAAM;AACN,aAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,MAClD;AAAA,MAEA,oBAA0B;AACxB,aAAK,aAAa,WAAW,4BAA4B;AACzD,aAAK,YAAY,KAAK,eAAe;AACrC,aAAK,OAAO,KAAK,UAAU,IAAI,iBAAiB;AAChD,aAAK,gBAAgB,KAAK,cAAc;AACxC,aAAK,OAAO;AACZ,aAAK,kBAAkB;AACvB,aAAK,wBAAwB;AAC7B,aAAK,4BAA4B;AAAA,MACnC;AAAA,MAEA,uBAA6B;AAC3B,aAAK,kBAAkB;AACvB,aAAK,iBAAiB;AACtB,aAAK,aAAa;AAAA,MACpB;AAAA,MAEQ,EAAE,KAAqB;AAC7B,eAAO,KAAK,aAAa,UAAU,GAAG,KAAK;AAAA,MAC7C;AAAA;AAAA,MAIQ,iBAAgC;AACtC,cAAM,QAAuB,CAAC;AAC9B,YAAI,UAA8B,KAAK;AAEvC,eAAO,WAAW,QAAQ,QAAQ,YAAY,MAAM,UAAU,MAAM,SAAS,eAAe;AAC1F,cAAI,QAAQ,aAAa,SAAS,MAAM,aAAa;AACnD,sBAAU,QAAQ;AAClB;AAAA,UACF;AACA,gBAAM,KAAK,OAAO;AAClB,oBAAU,QAAQ;AAAA,QACpB;AAEA,eAAO;AAAA,MACT;AAAA,MAEQ,gBAAwB;AAC9B,iBAAS,IAAI,GAAG,IAAI,KAAK,KAAK,QAAQ,KAAK;AACzC,gBAAM,IAAI,KAAK,KAAK,CAAC,EAAE;AACvB,cAAI,MAAM,eAAe,MAAM,UAAU,MAAM,aAAc,QAAO;AAAA,QACtE;AACA,eAAO;AAAA,MACT;AAAA;AAAA,MAIQ,SAAe;AACrB,aAAK,OAAO,YAAY,UAAU,sBAAsB,WAAW;AAAA,UACjE,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,EAAE,KAAK,IAAI;AAAA,QAClB,CAAC;AAAA,MACH;AAAA;AAAA,MAIQ,oBAA0B;AAChC,aAAK,aAAa,CAAC,MAAqB;AACtC,cAAI,EAAE,QAAQ,aAAa;AACzB,cAAE,gBAAgB;AAClB,cAAE,eAAe;AACjB,iBAAK,iBAAiB,KAAK,gBAAgB,KAAK,KAAK,UAAU;AAC/D,iBAAK,OAAO;AACZ,iBAAK,wBAAwB;AAAA,UAC/B,WAAW,EAAE,QAAQ,WAAW;AAC9B,cAAE,gBAAgB;AAClB,cAAE,eAAe;AACjB,iBAAK,iBAAiB,KAAK,gBAAgB,IAAI,KAAK,UAAU,UAAU,KAAK,UAAU;AACvF,iBAAK,OAAO;AACZ,iBAAK,wBAAwB;AAAA,UAC/B,WAAW,EAAE,QAAQ,SAAS;AAC5B,cAAE,gBAAgB;AAClB,iBAAK,QAAQ,KAAK,aAAa;AAAA,UACjC,WAAW,EAAE,QAAQ,UAAU;AAC7B,cAAE,gBAAgB;AAClB,iBAAK,OAAO;AAAA,UACd;AAAA,QACF;AACA,eAAO,iBAAiB,WAAW,KAAK,YAAY,EAAE,SAAS,KAAK,CAAC;AAAA,MACvE;AAAA,MAEQ,oBAA0B;AAChC,YAAI,KAAK,YAAY;AACnB,iBAAO,oBAAoB,WAAW,KAAK,YAAY,EAAE,SAAS,KAAK,CAAC;AACxE,eAAK,aAAa;AAAA,QACpB;AAAA,MACF;AAAA;AAAA,MAIQ,0BAAgC;AACtC,aAAK,OAAO,iBAAiB,YAAY,EAAE,QAAQ,CAAC,QAAQ;AAC1D,UAAC,IAAoB,iBAAiB,SAAS,MAAM;AACnD,kBAAM,MAAM,SAAU,IAAoB,QAAQ,KAAK,KAAK,KAAK,EAAE;AACnE,iBAAK,QAAQ,GAAG;AAAA,UAClB,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA;AAAA,MAIQ,8BAAoC;AAC1C,aAAK,iBAAiB,KAAK,UAAU,kBAAkB,CAAC,gBAAgB;AACtE,cAAI,CAAC,YAAa,MAAK,cAAc;AAAA,QACvC,CAAC;AACD,aAAK,aAAa,KAAK,UAAU,cAAc,CAAC,aAAa;AAC3D,cAAI,SAAU,MAAK,cAAc;AAAA,QACnC,CAAC;AAAA,MACH;AAAA;AAAA,MAIQ,QAAQ,OAAqB;AACnC,cAAM,MAAM,KAAK,KAAK,KAAK;AAC3B,YAAI,CAAC,IAAK;AACV,cAAM,UAAU,WAAW,mBAAmB,IAAI,QAAQ,CAAC;AAC3D,aAAK,UAAU,cAAc,OAAO;AACpC,aAAK,cAAc,IAAI,YAAY,kBAAkB,EAAE,QAAQ,SAAS,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACxG,aAAK,cAAc;AAAA,MACrB;AAAA,MAEQ,SAAe;AACrB,aAAK,cAAc,IAAI,YAAY,mBAAmB,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACxF,aAAK,cAAc;AAAA,MACrB;AAAA,MAEQ,gBAAsB;AAC5B,aAAK,kBAAkB;AACvB,aAAK,iBAAiB;AACtB,aAAK,aAAa;AAClB,aAAK,iBAAiB;AACtB,aAAK,aAAa;AAClB,aAAK,OAAO;AAAA,MACd;AAAA,IACF;AAEA,QAAI,CAAC,eAAe,IAAI,yBAAyB,GAAG;AAClD,qBAAe,OAAO,2BAA2B,qBAAqB;AAAA,IACxE;AAAA;AAAA;;;ACzKA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACEO,IAAM,kBAA0B,CAAC,MAAM,MAAM,MAAM,MAAM,IAAI;AAE7D,SAAS,OAAO,OAA8B;AACnD,SAAO,gBAAgB,SAAS,KAAa;AAC/C;AAGO,IAAM,iBAAuC;AAAA,EAClD,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGO,SAAS,cAAc,MAAsB;AAClD,SAAO,OAAO,IAAI,IAAI,eAAe,IAAI,IAAI;AAC/C;;;ACpBO,IAAM,cAAc;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;;;ACUO,IAAM,YAAsB;AAAA,EACjC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA,IACN;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,eAAe;AAAA,MACf,SAAS;AAAA,QACP,EAAE,MAAM,QAAa,SAAS,QAAa,QAAQ,MAAM;AAAA,QACzD,EAAE,MAAM,aAAa,SAAS,aAAa,QAAQ,MAAM;AAAA,MAC3D;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,eAAe;AAAA,MACf,SAAS;AAAA,QACP,EAAE,MAAM,WAAa,SAAS,WAAa,QAAQ,MAAM;AAAA,QACzD,EAAE,MAAM,UAAa,SAAS,UAAa,QAAQ,MAAM;AAAA,QACzD,EAAE,MAAM,aAAa,SAAS,aAAa,QAAQ,MAAM;AAAA,MAC3D;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,eAAe;AAAA,MACf,SAAS;AAAA,QACP,EAAE,MAAM,eAAe,SAAS,eAAe,QAAQ,MAAM;AAAA,QAC7D,EAAE,MAAM,UAAe,SAAS,UAAe,QAAQ,MAAM;AAAA,QAC7D,EAAE,MAAM,aAAe,SAAS,aAAe,QAAQ,MAAM;AAAA,MAC/D;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,eAAe;AAAA,MACf,SAAS;AAAA,QACP,EAAE,MAAM,YAAwB,SAAS,YAAwB,QAAQ,MAAM;AAAA,QAC/E,EAAE,MAAM,wBAAwB,SAAS,wBAAwB,QAAQ,MAAM;AAAA,QAC/E,EAAE,MAAM,uBAAwB,SAAS,uBAAwB,QAAQ,MAAM;AAAA,MACjF;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,MAIE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,eAAe;AAAA,MACf,SAAS,CAAC;AAAA,IACZ;AAAA,EACF;AACF;AAEO,IAAM,iBAAiB,UAAU,OAAO,IAAI,OAAK,EAAE,IAAI;;;AC1EvD,IAAM,UAAN,MAAiB;AAAA,EACd;AAAA,EACA,YAAY,oBAAI,IAAoB;AAAA,EAE5C,YAAY,cAAiB;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,KAAK,OAAgB;AACnB,SAAK,SAAS;AACd,SAAK,UAAU,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;AAAA,EACxC;AAAA,EAEA,WAAc;AACZ,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,UAAU,IAAgC;AACxC,SAAK,UAAU,IAAI,EAAE;AACrB,WAAO,MAAM,KAAK,UAAU,OAAO,EAAE;AAAA,EACvC;AACF;;;ACrBO,IAAM,UAAU;AAAA,EACrB,YAAY;AAAA,IACV,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,WAAW;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,mBAAmB;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,2BAA2B;AAAA,IAC3B,4BAA4B;AAAA,IAC5B,uBAAuB;AAAA,IACvB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,IAC3B,qBAAqB;AAAA,IACrB,4BAA4B;AAAA,IAC5B,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,oBAAoB;AAAA,IACpB,gCAAgC;AAAA,IAChC,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,+BAA+B;AAAA,IAC/B,yBAAyB;AAAA,IACzB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,cAAc;AAAA,EAChB;AAAA,EACA,oBAAoB;AAAA,IAClB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,iBAAiB;AAAA,IACf,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,yBAAyB;AAAA,IACzB,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,8BAA8B;AAAA,IAC9B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA,IACX,OAAO;AAAA,IACP,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;;;AC5TO,IAAM,UAAU;AAAA,EACrB,YAAY;AAAA,IACV,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,WAAW;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,mBAAmB;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,2BAA2B;AAAA,IAC3B,4BAA4B;AAAA,IAC5B,uBAAuB;AAAA,IACvB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,IAC3B,qBAAqB;AAAA,IACrB,4BAA4B;AAAA,IAC5B,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,oBAAoB;AAAA,IACpB,gCAAgC;AAAA,IAChC,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,+BAA+B;AAAA,IAC/B,yBAAyB;AAAA,IACzB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,cAAc;AAAA,EAChB;AAAA,EACA,oBAAoB;AAAA,IAClB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,iBAAiB;AAAA,IACf,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,yBAAyB;AAAA,IACzB,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,8BAA8B;AAAA,IAC9B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA,IACX,OAAO;AAAA,IACP,eAAe;AAAA,IACf,WAAW;AAAA,IACX,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;;;AC5TO,IAAM,UAAU;AAAA,EACrB,YAAY;AAAA,IACV,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,WAAW;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,mBAAmB;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,2BAA2B;AAAA,IAC3B,4BAA4B;AAAA,IAC5B,uBAAuB;AAAA,IACvB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,IAC3B,qBAAqB;AAAA,IACrB,4BAA4B;AAAA,IAC5B,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,oBAAoB;AAAA,IACpB,gCAAgC;AAAA,IAChC,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,+BAA+B;AAAA,IAC/B,yBAAyB;AAAA,IACzB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,cAAc;AAAA,EAChB;AAAA,EACA,oBAAoB;AAAA,IAClB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,iBAAiB;AAAA,IACf,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,yBAAyB;AAAA,IACzB,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA;AAAA,IAC1B,0BAA0B;AAAA;AAAA,IAC1B,8BAA8B;AAAA;AAAA,IAC9B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA;AAAA,IACX,OAAO;AAAA,IACP,eAAe;AAAA,IACf,WAAW;AAAA;AAAA,IAEX,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA;AAAA,IACT,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;;;AC7TO,IAAM,UAAU;AAAA,EACrB,YAAY;AAAA,IACV,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,WAAW;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,mBAAmB;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,2BAA2B;AAAA,IAC3B,4BAA4B;AAAA,IAC5B,uBAAuB;AAAA,IACvB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,IAC3B,qBAAqB;AAAA,IACrB,4BAA4B;AAAA,IAC5B,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,oBAAoB;AAAA,IACpB,gCAAgC;AAAA,IAChC,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,+BAA+B;AAAA,IAC/B,yBAAyB;AAAA,IACzB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,cAAc;AAAA,EAChB;AAAA,EACA,oBAAoB;AAAA,IAClB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,iBAAiB;AAAA,IACf,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,yBAAyB;AAAA,IACzB,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA;AAAA,IAC1B,0BAA0B;AAAA;AAAA,IAC1B,8BAA8B;AAAA;AAAA,IAC9B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA;AAAA,IACX,OAAO;AAAA,IACP,eAAe;AAAA,IACf,WAAW;AAAA;AAAA,IAEX,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA;AAAA,IACT,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;;;AC7TO,IAAM,UAAU;AAAA,EACrB,YAAY;AAAA,IACV,UAAU;AAAA,IACV,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,aAAa;AAAA,EACf;AAAA,EACA,WAAW;AAAA,IACT,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,KAAK;AAAA,IACL,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,SAAS;AAAA,IACT,SAAS;AAAA,IACT,UAAU;AAAA,IACV,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,eAAe;AAAA,IACf,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,WAAW;AAAA,IACX,mBAAmB;AAAA,EACrB;AAAA,EACA,QAAQ;AAAA,IACN,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,aAAa;AAAA,IACb,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,YAAY;AAAA,IACZ,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,sBAAsB;AAAA,IACtB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,oBAAoB;AAAA,IACpB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,2BAA2B;AAAA,IAC3B,4BAA4B;AAAA,IAC5B,uBAAuB;AAAA,IACvB,qBAAqB;AAAA,IACrB,mBAAmB;AAAA,IACnB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,2BAA2B;AAAA,IAC3B,qBAAqB;AAAA,IACrB,4BAA4B;AAAA,IAC5B,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,6BAA6B;AAAA,IAC7B,0BAA0B;AAAA,IAC1B,oBAAoB;AAAA,IACpB,gCAAgC;AAAA,IAChC,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA,IAC1B,+BAA+B;AAAA,IAC/B,yBAAyB;AAAA,IACzB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,yBAAyB;AAAA,IACzB,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAiB;AAAA,IACf,OAAO;AAAA,IACP,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,cAAc;AAAA,EAChB;AAAA,EACA,oBAAoB;AAAA,IAClB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,WAAW;AAAA,EACb;AAAA,EACA,iBAAiB;AAAA,IACf,YAAY;AAAA,IACZ,oBAAoB;AAAA,IACpB,yBAAyB;AAAA,IACzB,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,aAAa;AAAA,IACb,UAAU;AAAA,IACV,aAAa;AAAA,IACb,mBAAmB;AAAA,IACnB,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,iBAAiB;AAAA,IACjB,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,wBAAwB;AAAA,IACxB,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,EACnB;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,UAAU;AAAA,IACV,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAAA,EACA,UAAU;AAAA,IACR,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe;AAAA,IACf,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,wBAAwB;AAAA,IACxB,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,iBAAiB;AAAA,IACjB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,IAClB,uBAAuB;AAAA,IACvB,wBAAwB;AAAA,IACxB,0BAA0B;AAAA,IAC1B,0BAA0B;AAAA;AAAA,IAC1B,0BAA0B;AAAA;AAAA,IAC1B,8BAA8B;AAAA;AAAA,IAC9B,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAW;AAAA,IACX,aAAa;AAAA,IACb,cAAc;AAAA,IACd,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,sBAAsB;AAAA,IACtB,sBAAsB;AAAA,IACtB,qBAAqB;AAAA,IACrB,UAAU;AAAA,EACZ;AAAA,EACA,MAAM;AAAA,IACJ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,WAAW;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,eAAe;AAAA,IACf,SAAS;AAAA,IACT,cAAc;AAAA,IACd,WAAW;AAAA,IACX,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,UAAU;AAAA,IACV,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,WAAW;AAAA,IACX,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,UAAU;AAAA,IACV,WAAW;AAAA;AAAA,IACX,OAAO;AAAA,IACP,eAAe;AAAA,IACf,WAAW;AAAA;AAAA,IAEX,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,eAAe;AAAA,IACf,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA;AAAA,IACT,kBAAkB;AAAA,IAClB,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AACF;;;ACnTO,IAAM,qBAAN,MAAyB;AAAA,EACb;AAAA,EAEA,eAA2C;AAAA,IAC1D,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,EACN;AAAA,EAEA,cAAc;AACZ,SAAK,QAAQ,IAAI,QAAc,KAAK,WAAW,CAAC;AAAA,EAClD;AAAA,EAEA,QAAQ,MAAkB;AACxB,SAAK,MAAM,KAAK,IAAI;AAAA,EACtB;AAAA,EAEA,UAAgB;AACd,WAAO,KAAK,MAAM,SAAS;AAAA,EAC7B;AAAA;AAAA,EAGA,aAAa,IAAsC;AACjD,WAAO,KAAK,MAAM,UAAU,EAAE;AAAA,EAChC;AAAA,EAEA,UAAU,KAAqB;AAC7B,UAAM,OAAO,IAAI,MAAM,GAAG;AAC1B,QAAI,QAAiB,KAAK,aAAa,KAAK,MAAM,SAAS,CAAC;AAC5D,eAAW,KAAK,MAAM;AACpB,cAAS,QAAoC,CAAC;AAC9C,UAAI,UAAU,OAAW,QAAO;AAAA,IAClC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,aAAmB;AACjB,UAAM,cAAc,UAAU,SAAS,MAAM,GAAG,EAAE,CAAC;AACnD,WAAO,OAAO,WAAW,IAAI,cAAc;AAAA,EAC7C;AACF;AAEO,IAAM,qBAAqB,IAAI,mBAAmB;;;ACrDzD;AAEO,IAAM,wBAAN,MAA4B;AAAA,EACjC,OAAO,MAAoB;AACzB,WAAO,OAAO,IAAI,IAAI,OAAO;AAAA,EAC/B;AAAA,EAEA,sBAAsB,aAAqB,UAA4B;AACrE,UAAM,gBAAgB,SAAS,IAAI,CAAC,QAAQ,eAAe,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI;AAChF,WAAO,OAAO,mBAAmB,WAAW,CAAC;AAAA,EAAe,aAAa;AAAA;AAAA,EAC3E;AACF;AAEO,IAAM,wBAAwB,IAAI,sBAAsB;;;ACHxD,IAAM,oCAAN,MAAwC;AAAA,EAC7C,iBAAiB,SAAiB,cAAsB,SAAyC;AAC/F,UAAM,QAAQ,QAAQ,MAAM,sBAAsB;AAClD,QAAI,CAAC,OAAO;AACV,gBAAU,6BAA6B;AACvC,aAAO;AAAA,IACT;AACA,UAAM,aAAa,MAAM,SAAS,KAAK,MAAM,CAAC,EAAE;AAChD,UAAM,kBAAkB;AAAA;AAAA,EAA2B,YAAY;AAAA;AAC/D,WAAO,QAAQ,MAAM,GAAG,SAAS,IAAI,kBAAkB,QAAQ,MAAM,SAAS;AAAA,EAChF;AAAA,EAEA,cAAc,SAAiB,SAAiB,SAAyC;AACvF,UAAM,MAAM,QAAQ,YAAY,IAAI;AACpC,QAAI,QAAQ,IAAI;AACd,gBAAU,wBAAwB;AAClC,aAAO;AAAA,IACT;AACA,WAAO,QAAQ,MAAM,GAAG,GAAG,IAAI,OAAO,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,EAC1E;AAAA,EAEA,kBAAkB,OAAuB;AACvC,QAAI,CAAC,MAAM,KAAK,EAAG,QAAO;AAC1B,UAAM,QAAQ,MAAM,MAAM,IAAI,EAAE,IAAI,OAAK,MAAM,CAAC,EAAE,EAAE,KAAK,IAAI;AAC7D,WAAO;AAAA,EAAQ,KAAK;AAAA;AAAA,EACtB;AAAA,EAEA,OAAO,MAAwB;AAC7B,WAAO,CAAC,CAAC,QAAS,KAAkB,SAAS;AAAA,EAC/C;AAAA,EAEA,MAAM,cAAc,WAA8D;AAChF,UAAM,SAAwB,EAAE,MAAM,UAAU,MAAM,MAAM,aAAa,UAAU,CAAC,EAAE;AACtF,qBAAiB,SAAS,UAAU,OAAO,GAAG;AAC5C,UAAI,MAAM,SAAS,aAAa;AAC9B,eAAO,SAAS,KAAK,MAAM,KAAK,cAAc,KAAkC,CAAC;AAAA,MACnF,OAAO;AACL,eAAO,SAAS,KAAK,EAAE,MAAM,MAAM,MAAM,MAAM,OAAO,CAAC;AAAA,MACzD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;AAEO,IAAM,oCAAoC,IAAI,kCAAkC;;;ACpDvF;;;ACHA;AAGA,IAAM,kBAAkB;AAcjB,SAAS,sBAAsB,IAAiB,UAA0B;AAC/E,QAAM,eAAe,mBAAmB,QAAQ;AAChD,QAAM,SAAS,CAAC,SAAyB,WAAW,YAAY,aAAa,IAAI;AACjF,QAAM,MAAM,GAAG,QAAQ,YAAY;AAEnC,MAAI,QAAQ,SAAS;AACnB,UAAM,QAAQ;AACd,UAAM,QAAQ,MAAM,aAAa,MAAM,KAAK,QAAQ,YAAY;AAChE,QAAI,SAAS,cAAc,SAAS,SAAS;AAC3C,aAAO,OAAO,IAAI,MAAM,UAAU,eAAe,gBAAgB,GAAG;AAAA,IACtE;AACA,WAAO,MAAM,QACT,OAAO,kBAAkB,mBAAmB,MAAM,KAAK,CAAC,GAAG,IAC3D,OAAO,cAAc;AAAA,EAC3B;AAEA,MAAI,QAAQ,cAAc,QAAQ,UAAU;AAC1C,UAAM,QAAS,GAA+C;AAC9D,WAAO,QACH,OAAO,kBAAkB,mBAAmB,KAAK,CAAC,GAAG,IACrD,OAAO,cAAc;AAAA,EAC3B;AAEA,QAAM,QAAQ,GAAG,eAAe,IAAI,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC9D,MAAI,QAAQ,KAAK,UAAU,iBAAiB;AAC1C,WAAO,OAAO,oBAAoB,mBAAmB,IAAI,CAAC,GAAG;AAAA,EAC/D;AACA,SAAO,OAAO,cAAc;AAC9B;;;ADxCA;AAEA,IAAM,eAAe;AAKrB,SAAS,kBAA0B;AACjC,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC5E,WAAO,OAAO,WAAW;AAAA,EAC3B;AACA,SAAO,QAAQ,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG,EAAE,SAAS,EAAE,CAAC;AACxF;AAEO,IAAM,mBAAN,MAAuB;AAAA,EACX,YAAY,IAAI,QAAkB,CAAC,CAAC;AAAA,EACpC,gBAAgB,IAAI,QAAkB,CAAC,CAAC;AAAA,EACxC,eAAe,IAAI,QAAiB,KAAK;AAAA,EACzC,YAAY,IAAI,QAAiB,KAAK;AAAA,EACtC,oBAAoB,IAAI,QAAyD,IAAI;AAAA,EACrF,sBAAsB,oBAAI,IAAgD;AAAA,EAC1E,WAAW,oBAAI,IAAoB;AAAA,EACnC,gBAAgB,oBAAI,IAAyB;AAAA,EAC7C,QAAQ,IAAI,gBAAgB;AAAA,EAE7C,mBAAqC;AAAA;AAAA,EAGrC,YAA2B;AAAA,EACnB,YAAY;AAAA;AAAA,EAGH,gBAAgB,QAAQ,UAAU,KAAK,OAAO;AAAA,EAC9C,mBAAmB,QAAQ,aAAa,KAAK,OAAO;AAAA,EAErE,cAAc;AACZ,SAAK,qBAAqB;AAC1B,SAAK,eAAe;AACpB,SAAK,qBAAqB;AAC1B,SAAK,oBAAoB;AACzB,SAAK,cAAc;AACnB,SAAK,eAAe;AACpB,SAAK,aAAa;AAClB,SAAK,qBAAqB;AAAA,EAC5B;AAAA;AAAA,EAIA,iBAAuB;AACrB,SAAK,cAAc;AACnB,SAAK,YAAY,gBAAgB;AACjC,SAAK,YAAY,KAAK,IAAI;AAC1B,SAAK,UAAU,KAAK,KAAK;AACzB,SAAK,aAAa,KAAK,IAAI;AAC3B,SAAK,WAAW,yBAAyB;AACzC,SAAK,WAAW,aAAa,mBAAmB,OAAO,SAAS,QAAQ,CAAC,IAAI;AAC7E,SAAK,WAAW,kEAAkE;AAAA,EACpF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAe,OAAiC;AAC9C,SAAK,YAAY,MAAM;AACvB,SAAK,YAAY,MAAM;AACvB,SAAK,mBAAmB,MAAM;AAC9B,SAAK,UAAU,KAAK,CAAC,GAAG,MAAM,QAAQ,CAAC;AACvC,SAAK,cAAc,KAAK,CAAC,GAAG,MAAM,YAAY,CAAC;AAC/C,SAAK,UAAU,KAAK,MAAM,QAAQ;AAElC,SAAK,aAAa,KAAK,MAAM,WAAW;AAAA,EAC1C;AAAA;AAAA,EAGA,qBAAyC;AACvC,WAAO;AAAA,MACL,WAAW,KAAK,aAAa,gBAAgB;AAAA,MAC7C,aAAa,KAAK,aAAa,SAAS;AAAA,MACxC,UAAU,KAAK,UAAU,SAAS;AAAA,MAClC,UAAU,KAAK,UAAU,SAAS;AAAA,MAClC,cAAc,KAAK,cAAc,SAAS;AAAA,MAC1C,kBAAkB,KAAK;AAAA,MACvB,WAAW,KAAK;AAAA,MAChB,WAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,gBAAsB;AACpB,SAAK,UAAU,KAAK,KAAK;AACzB,SAAK,aAAa,KAAK,KAAK;AAAA,EAC9B;AAAA,EAEA,kBAAwB;AACtB,QAAI,KAAK,aAAa,SAAS,GAAG;AAChC,WAAK,cAAc;AAAA,IACrB,OAAO;AACL,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,iBAAuB;AACrB,QAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AACnC,SAAK,UAAU,KAAK,IAAI;AAAA,EAC1B;AAAA,EAEA,kBAAwB;AACtB,SAAK,UAAU,KAAK,KAAK;AAAA,EAC3B;AAAA,EAEA,cAAoB;AAClB,QAAI,KAAK,UAAU,SAAS,GAAG;AAC7B,WAAK,gBAAgB;AAAA,IACvB,OAAO;AACL,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,WAAW,KAAmB;AAC5B,QAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,SAAK,UAAU,KAAK,CAAC,GAAG,KAAK,UAAU,SAAS,GAAG,GAAG,CAAC;AAAA,EACzD;AAAA;AAAA,EAGA,cAAc,KAAmB;AAC/B,SAAK,UAAU,KAAK,CAAC,GAAG,KAAK,UAAU,SAAS,GAAG,GAAG,CAAC;AAAA,EACzD;AAAA,EAEA,cAAc,OAAqB;AACjC,UAAM,OAAO,KAAK,UAAU,SAAS;AACrC,QAAI,QAAQ,KAAK,SAAS,KAAK,OAAQ;AACvC,SAAK,UAAU,KAAK,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK,GAAG,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EACzE;AAAA,EAEA,YAAY,MAAc,IAAkB;AAC1C,UAAM,OAAO,CAAC,GAAG,KAAK,UAAU,SAAS,CAAC;AAC1C,QAAI,OAAO,KAAK,KAAK,KAAK,QAAQ,KAAK,UAAU,MAAM,KAAK,UAAU,SAAS,GAAI;AACnF,UAAM,CAAC,IAAI,IAAI,KAAK,OAAO,MAAM,CAAC;AAClC,SAAK,OAAO,IAAI,GAAG,IAAI;AACvB,SAAK,UAAU,KAAK,IAAI;AAAA,EAC1B;AAAA,EAEA,kBAAkB,OAAqB;AACrC,UAAM,OAAO,KAAK,cAAc,SAAS;AACzC,QAAI,QAAQ,KAAK,SAAS,KAAK,OAAQ;AACvC,SAAK,cAAc,KAAK,CAAC,GAAG,KAAK,MAAM,GAAG,KAAK,GAAG,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC;AAAA,EAC7E;AAAA,EAEA,oBAAoB,QAAgB,KAAa,OAAe,aAA4B;AAI1F,QAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,UAAM,WAAW,mBAAmB,KAAK,cAAc,KAAK,MAAM,CAAC;AACnE,UAAM,UAAU,cACZ,iBAAiB,MAAM,OAAO,QAAQ,kBAAkB,mBAAmB,WAAW,CAAC,YAAY,KAAK,OACxG,iBAAiB,MAAM,OAAO,QAAQ,UAAU,KAAK;AACzD,UAAM,UAAU,KAAK,cAAc,SAAS;AAC5C,QAAI,CAAC,QAAQ,SAAS,OAAO,GAAG;AAC9B,WAAK,cAAc,KAAK,CAAC,GAAG,SAAS,OAAO,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA;AAAA,EAGA,gBAAgB,MAAc,SAAuB;AACnD,QAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,SAAK,SAAS,IAAI,MAAM,OAAO;AAAA,EACjC;AAAA,EAEA,sBAAgE;AAC9D,WAAO,CAAC,GAAG,KAAK,SAAS,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,OAAO,OAAO,EAAE,MAAM,QAAQ,EAAE;AAAA,EAClF;AAAA,EAEA,gBAAgB,UAAkB,OAA0B;AAC1D,SAAK,cAAc,IAAI,UAAU,KAAK;AAAA,EACxC;AAAA,EAEA,2BAA4E;AAC1E,WAAO,CAAC,GAAG,KAAK,cAAc,QAAQ,CAAC,EAAE,IAAI,CAAC,CAAC,UAAU,KAAK,OAAO,EAAE,UAAU,MAAM,EAAE;AAAA,EAC3F;AAAA,EAEA,qBAA2B;AACzB,SAAK,cAAc,MAAM;AAAA,EAC3B;AAAA,EAEA,gBAAsB;AACpB,SAAK,UAAU,KAAK,CAAC,CAAC;AACtB,SAAK,cAAc,KAAK,CAAC,CAAC;AAC1B,SAAK,SAAS,MAAM;AACpB,SAAK,cAAc,MAAM;AAAA,EAC3B;AAAA,EAEA,oBAA0B;AACxB,SAAK,cAAc,KAAK,CAAC,CAAC;AAAA,EAC5B;AAAA,EAEA,sBAAiC;AAAE,WAAO,KAAK,UAAU,SAAS;AAAA,EAAG;AAAA,EACrE,0BAAoC;AAAE,WAAO,KAAK,cAAc,SAAS;AAAA,EAAG;AAAA,EAC5E,oBAAiC;AAAE,WAAO,KAAK,UAAU,SAAS;AAAA,EAAG;AAAA,EAErE,iBAAiB,IAA0C;AACzD,WAAO,KAAK,UAAU,UAAU,EAAE;AAAA,EACpC;AAAA,EAEA,qBAAqB,IAA0C;AAC7D,WAAO,KAAK,cAAc,UAAU,EAAE;AAAA,EACxC;AAAA,EAEA,kBAAkB,IAAgD;AAChE,WAAO,KAAK,aAAa,UAAU,EAAE;AAAA,EACvC;AAAA,EAEA,cAAc,IAA6C;AACzD,WAAO,KAAK,UAAU,UAAU,EAAE;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,gBAAgB,IAAqD;AACnE,UAAM,OAAO,MAAY,GAAG,KAAK,mBAAmB,CAAC;AACrD,UAAM,SAAS;AAAA,MACb,KAAK,UAAU,UAAU,IAAI;AAAA,MAC7B,KAAK,cAAc,UAAU,IAAI;AAAA,MACjC,KAAK,aAAa,UAAU,IAAI;AAAA,MAChC,KAAK,UAAU,UAAU,IAAI;AAAA,IAC/B;AACA,WAAO,MAAM,OAAO,QAAQ,CAAC,MAAM,EAAE,CAAC;AAAA,EACxC;AAAA,EAEA,mBAAmB,IAAgE;AACjF,WAAO,KAAK,kBAAkB,UAAU,CAAC,MAAM;AAC7C,UAAI,EAAG,IAAG,EAAE,QAAQ,EAAE,MAAM;AAAA,IAC9B,CAAC;AAAA,EACH;AAAA,EAEA,UAAgB;AACd,SAAK,MAAM,MAAM;AACjB,YAAQ,YAAY,KAAK;AACzB,YAAQ,eAAe,KAAK;AAC5B,SAAK,oBAAoB,QAAQ,CAAC,MAAM,aAAa,CAAC,CAAC;AACvD,SAAK,oBAAoB,MAAM;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,uBAA6B;AACnC,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,YAAI,CAAE,EAAiB,OAAQ;AAC/B,cAAM,SAAS,EAAE;AACjB,YAAI,CAAC,UAAU,KAAK,aAAa,MAAM,EAAG;AAC1C,cAAM,MAAM,OAAO,SAAS,YAAY;AACxC,YAAI,QAAQ,UAAU,QAAQ,OAAQ;AACtC,cAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,YAAI,CAAC,UAAW;AAChB,cAAM,WAAW,KAAK,oBAAoB,SAAS;AACnD,YAAI,CAAC,YAAY,KAAK,cAAc,QAAQ,EAAG;AAE/C,UAAE,eAAe;AACjB,UAAE,yBAAyB;AAC3B,cAAM,OAAO,MAAY,KAAK,WAAW,sBAAsB,WAAW,QAAQ,CAAC;AAInF,cAAM,QAAQ,UAAU,aAAa,MAAM,KAAK,IAAI,YAAY;AAChE,YAAI,UAAU,QAAQ,YAAY,MAAM,YAAY,SAAS,cAAc,SAAS,UAAU;AAC5F,yBAAe,IAAI;AAAA,QACrB,OAAO;AACL,eAAK;AAAA,QACP;AAAA,MACF;AAAA,MACA,EAAE,SAAS,MAAM,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,iBAAuB;AAC7B,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AACnC,cAAM,SAAS,EAAE;AACjB,YAAI,CAAC,UAAU,KAAK,aAAa,MAAM,EAAG;AAC1C,cAAM,MAAM,OAAO,SAAS,YAAY;AACxC,YAAI,QAAQ,UAAU,QAAQ,OAAQ;AACtC,aAAK,iBAAiB,MAAM;AAAA,MAC9B;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA,EAGQ,mBAAmB,QAA2C;AACpE,QAAI,CAAC,UAAU,KAAK,aAAa,MAAM,EAAG,QAAO;AACjD,UAAM,MAAM,OAAO,SAAS,YAAY;AACxC,QAAI,QAAQ,UAAU,QAAQ,OAAQ,QAAO;AAC7C,UAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,QAAI,CAAC,UAAW,QAAO;AACvB,UAAM,WAAW,KAAK,oBAAoB,SAAS;AACnD,QAAI,CAAC,YAAY,KAAK,cAAc,QAAQ,EAAG,QAAO;AACtD,WAAO;AAAA,EACT;AAAA,EAEQ,uBAA6B;AACnC,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,YAAK,EAAiB,OAAQ;AAC9B,cAAM,WAAW,KAAK,mBAAmB,EAAE,MAAqB;AAChE,YAAI,CAAC,SAAU;AAEf,cAAM,eAAe,mBAAmB,QAAQ;AAChD,cAAM,WAAW,WAAW,YAAY;AACxC,YAAI,OAAO,KAAK,UAAU,SAAS;AACnC,YAAI,UAAU;AACd,eAAO,UAAU,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK,SAAS,CAAC,MAAM,UAAU;AAC3E,iBAAO,KAAK,MAAM,GAAG,EAAE;AACvB;AAAA,QACF;AACA,YAAI,UAAU,EAAG,MAAK,UAAU,KAAK,IAAI;AACzC,aAAK,WAAW,WAAW,YAAY,eAAe;AAAA,MACxD;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,sBAA4B;AAClC,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,cAAM,WAAW,KAAK,mBAAmB,EAAE,MAAqB;AAChE,YAAI,CAAC,SAAU;AACf,aAAK,WAAW,WAAW,mBAAmB,QAAQ,CAAC,iBAAiB;AAAA,MAC1E;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA,EAGQ,eAAqB;AAC3B,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,KAAK,KAAK,UAAU,SAAS,EAAG;AAChE,cAAM,MAAO,EAAoB;AACjC,YAAI,QAAQ,WAAW,QAAQ,SAAU;AACzC,cAAM,SAAS,EAAE;AACjB,cAAM,MAAM,QAAQ,SAAS,YAAY;AACzC,YAAI,QAAQ,WAAW,QAAQ,cAAc,QAAQ,SAAU;AAC/D,cAAM,WAAW,KAAK,mBAAmB,MAAM;AAC/C,YAAI,CAAC,SAAU;AAEf,aAAK,mBAAmB,MAAM;AAC9B,cAAM,QAAQ,QAAQ,UAAU,YAAY;AAC5C,aAAK,WAAW,WAAW,mBAAmB,QAAQ,CAAC,YAAY,KAAK,IAAI;AAAA,MAC9E;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,gBAAsB;AAC5B,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AACnC,cAAM,SAAS,EAAE;AACjB,YAAI,CAAC,UAAU,KAAK,aAAa,MAAM,EAAG;AAC1C,aAAK,iBAAiB,MAAM;AAAA,MAC9B;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,iBAAuB;AAC7B,aAAS;AAAA,MACP;AAAA,MACA,CAAC,MAAa;AACZ,YAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AACnC,cAAM,SAAS,EAAE;AACjB,YAAI,CAAC,UAAU,KAAK,aAAa,MAAM,EAAG;AAC1C,cAAM,MAAM,OAAO,QAAQ,YAAY;AACvC,YAAI,QAAQ,UAAU;AACpB,eAAK,kBAAkB,MAA2B;AAAA,QACpD,WAAW,QAAQ,SAAS;AAC1B,gBAAM,QAAQ,OAAO,aAAa,MAAM,KAAK,IAAI,YAAY;AAC7D,cAAI,SAAS,QAAQ;AACnB,iBAAK,KAAK,sBAAsB,MAA0B;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAc,sBAAsB,QAAyC;AAC3E,QAAI,KAAK,UAAU,SAAS,EAAG;AAC/B,UAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,QAAI,CAAC,UAAW;AAChB,UAAM,WAAW,KAAK,oBAAoB,SAAS;AACnD,QAAI,CAAC,YAAY,KAAK,cAAc,QAAQ,EAAG;AAE/C,UAAM,QAAQ,MAAM,KAAK,OAAO,SAAS,CAAC,CAAC;AAC3C,QAAI,CAAC,MAAM,OAAQ;AAEnB,UAAM,QAAQ,MAAM,IAAI,OAAK,qBAAqB,mBAAmB,EAAE,IAAI,CAAC,GAAG;AAC/E,UAAM,UAAU,MAAM,WAAW,IAAI,MAAM,CAAC,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC;AACpE,SAAK,WAAW,WAAW,mBAAmB,QAAQ,CAAC,iBAAiB,OAAO,GAAG;AAElF,eAAW,QAAQ,OAAO;AACxB,YAAM,QAAQ,MAAM,KAAK,sBAAsB,IAAI;AACnD,WAAK,gBAAgB,KAAK,MAAM,KAAK;AAAA,IACvC;AAAA,EACF;AAAA,EAEQ,sBAAsB,MAAkC;AAC9D,QAAI,OAAO,KAAK,gBAAgB,YAAY;AAC1C,aAAO,KAAK,YAAY;AAAA,IAC1B;AACA,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,SAAS,IAAI,WAAW;AAC9B,aAAO,SAAS,MAAM,QAAQ,OAAO,MAAqB;AAC1D,aAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAC1C,aAAO,kBAAkB,IAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA,EAEQ,uBAA6B;AACnC,QAAI,UAAU,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS;AAElF,UAAM,gBAAgB,CAAC,WAAyB;AAC9C,UAAI,CAAC,KAAK,aAAa,SAAS,EAAG;AACnC,UAAI,WAAW,QAAS;AACxB,WAAK,WAAW,+BAA+B,mBAAmB,MAAM,CAAC,IAAI;AAC7E,gBAAU;AAAA,IACZ;AAEA,UAAM,aAAa,CAAC,SAA6C;AAC/D,YAAM,OAAO,QAAQ,IAAI,EAAE,KAAK,OAAO;AACvC,cAAQ,IAAI,IAAI,CAAC,MAAe,QAAgB,QAA8B;AAC5E,cAAM,SAAS,KAAK,MAAM,QAAQ,GAAG;AACrC,YAAI,SAAS,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS;AACjF,YAAI,OAAO,QAAQ,YAAY,IAAI,SAAS,GAAG;AAC7C,gBAAM,IAAI,SAAS,cAAc,GAAG;AACpC,YAAE,OAAO;AACT,mBAAS,EAAE,WAAW,EAAE,SAAS,EAAE;AAAA,QACrC,WAAW,eAAe,KAAK;AAC7B,mBAAS,IAAI,WAAW,IAAI,SAAS,IAAI;AAAA,QAC3C;AACA,sBAAc,MAAM;AACpB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,eAAW,WAAW;AACtB,eAAW,cAAc;AAEzB,WAAO;AAAA,MACL;AAAA,MACA,MAAM;AACJ,cAAM,SAAS,OAAO,SAAS,WAAW,OAAO,SAAS,SAAS,OAAO,SAAS;AACnF,sBAAc,MAAM;AAAA,MACtB;AAAA,MACA,EAAE,QAAQ,KAAK,MAAM,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA,EAIQ,iBAAiB,QAA2B;AAElD,QAAI,CAAC,KAAK,qBAAqB,MAAM,GAAG;AACtC,YAAMA,OAAM,OAAO,QAAQ,YAAY;AACvC,WACGA,SAAQ,UAAUA,SAAQ,UAC3B,OAAO,kBACN,OAAO,cAAc,QAAQ,YAAY,MAAM,YAC9C,OAAO,cAAc,QAAQ,YAAY,MAAM,kBAChD,OAAO,cAAc,aAAa,SAAS,KAAK,OAAO,cAAc,aAAa,IAAI,IACvF;AACA,iBAAS,OAAO;AAAA,MAClB;AACA,YAAM,YAAY,OAAO,QAAQ,YAAY;AAC7C,UAAI,WAAW;AACb,cAAM,MAAM,KAAK,oBAAoB,SAAwB;AAC7D,YAAI,KAAK;AACP,eAAK,WAAW,WAAW,GAAG,YAAY;AAAA,QAC5C,OAAO;AACL,eAAK,kBAAkB,KAAK,EAAE,QAAQ,WAA0B,QAAQ,QAAQ,CAAC;AAAA,QACnF;AACA;AAAA,MACF;AAIA,UAAI,CAAC,KAAK,qBAAqB,MAAM,GAAG;AACtC,cAAM,cAAc,OAAO;AAAA,UACzB;AAAA,QAEF;AACA,YAAI,CAAC,YAAa;AAClB,iBAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,MAAM,OAAO,QAAQ,YAAY;AACvC,QAAI,QAAQ,WAAW,QAAQ,cAAc,QAAQ,UAAU;AAC7D,YAAMC,aAAY,OAAO,QAAqB,8CAA8C;AAC5F,UAAI,CAACA,YAAW;AAAE,aAAK,kBAAkB,KAAK,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAAG;AAAA,MAAQ;AAIpF,UAAI,QAAQ,SAAS;AACnB,cAAM,QAAQ;AACd,cAAM,QAAQ,MAAM,aAAa,MAAM,KAAK,IAAI,YAAY;AAC5D,YAAI,SAAS,cAAc,SAAS,SAAS;AAC3C,gBAAMC,YAAW,KAAK,oBAAoBD,UAAS;AACnD,cAAIC,aAAY,CAAC,KAAK,cAAcA,SAAQ,GAAG;AAC7C,kBAAM,SAAS,SAAS,WAAW,MAAM,UAAU,UAAU;AAC7D,iBAAK,WAAW,WAAWA,SAAQ,MAAM,MAAM,IAAI;AAAA,UACrD;AAAA,QACF;AAAA,MACF;AACA;AAAA,IACF;AAEA,UAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,QAAI,CAAC,WAAW;AACd,WAAK,kBAAkB,KAAK,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AACvD;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,oBAAoB,SAAS;AACnD,QAAI,aAAa,aAAc;AAE/B,QAAI,QAAQ,cAAc;AACxB,WAAK,qBAAqB,QAAQ,QAAQ;AAC1C;AAAA,IACF;AAEA,QAAI,CAAC,UAAU;AACb,WAAK,kBAAkB,KAAK,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AACvD;AAAA,IACF;AAEA,SAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,QAAQ,CAAC,MAAM,WAAW,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH;AAAA,EAEQ,qBAAqB,QAAqB,UAA+B;AAC/E,UAAM,YAAY,OAAO,QAAQ,YAAY;AAC7C,QAAI,SAAwB;AAC5B,QAAI,UAAW,UAAS,UAAU,QAAQ,WAAW,GAAG,aAAa,SAAS,KAAK;AACnF,QAAI,CAAC,OAAQ,UAAS,OAAO,QAAQ,WAAW,GAAG,aAAa,SAAS,KAAK;AAC9E,QAAI,QAAQ;AACV,YAAM,UAAU,mBAAmB,aAAa,mBAAmB,MAAM,CAAC,IAAI;AAC9E,WAAK,WAAW,WAAW,OAAO,YAAY;AAC9C;AAAA,IACF;AACA,QAAI,UAAU;AACZ,WAAK,WAAW,WAAW,QAAQ,kBAAkB;AAAA,IACvD,OAAO;AACL,WAAK,kBAAkB,KAAK,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAAA,IACzD;AAAA,EACF;AAAA;AAAA,EAIQ,iBAAiB,QAAsD;AAC7E,UAAM,MAAM,OAAO,QAAQ,YAAY;AACvC,UAAM,SAAS,QAAQ,cAAe,QAAQ,WAAY,YAAkC,SAAS,OAAO,IAAI;AAChH,QAAI,CAAC,OAAQ;AAEb,UAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,QAAI,CAAC,UAAW;AAEhB,QAAI,KAAK,oBAAoB,IAAI,MAAM,GAAG;AACxC,mBAAa,KAAK,oBAAoB,IAAI,MAAM,CAAC;AAAA,IACnD;AACA,SAAK,oBAAoB;AAAA,MACvB;AAAA,MACA,WAAW,MAAM;AACf,aAAK,oBAAoB,OAAO,MAAM;AACtC,aAAK,iBAAiB,MAAM;AAAA,MAC9B,GAAG,GAAI;AAAA,IACT;AAAA,EACF;AAAA;AAAA,EAGQ,iBAAiB,QAAsD;AAC7E,UAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,QAAI,CAAC,UAAW;AAChB,UAAM,WAAW,KAAK,oBAAoB,SAAS;AACnD,UAAM,QAAQ,mBAAmB,OAAO,KAAK;AAC7C,SAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,QAAQ,CAAC,MAAM,WAAW,CAAC,oBAAoB,KAAK;AAAA,IACtD,CAAC;AAAA,EACH;AAAA;AAAA,EAGQ,mBAAmB,QAA2B;AACpD,UAAM,QAAQ,KAAK,oBAAoB,IAAI,MAAM;AACjD,QAAI,UAAU,OAAW;AACzB,iBAAa,KAAK;AAClB,SAAK,oBAAoB,OAAO,MAAM;AACtC,SAAK,iBAAiB,MAAgD;AAAA,EACxE;AAAA;AAAA,EAIQ,kBAAkB,QAAiC;AACzD,UAAM,YAAY,OAAO,QAAqB,8CAA8C;AAC5F,QAAI,CAAC,UAAW;AAChB,UAAM,WAAW,KAAK,oBAAoB,SAAS;AACnD,UAAM,QAAQ,mBAAmB,OAAO,KAAK;AAC7C,SAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,QAAQ,CAAC,MAAM,WAAW,CAAC,cAAc,KAAK;AAAA,IAChD,CAAC;AAAA,EACH;AAAA;AAAA,EAIQ,kBAAkB,MAGjB;AACP,QAAI,CAAC,KAAK,YAAY,KAAK,cAAc,KAAK,QAAQ,EAAG;AACzD,SAAK,WAAW,KAAK,OAAO,mBAAmB,KAAK,QAAQ,CAAC,CAAC;AAAA,EAChE;AAAA,EAEQ,oBAAoB,IAAgC;AAC1D,UAAM,WAAW,KAAK;AACtB,UAAM,SAAa,GAAG,aAAa,SAAS;AAC5C,UAAM,aAAa,GAAG,aAAa,aAAa;AAChD,UAAM,YAAa,GAAG,aAAa,YAAY;AAC/C,UAAM,YAAa,GAAG,aAAa,SAAS;AAE5C,UAAM,QAAQ,GAAG;AACjB,UAAM,UAAU,SACd,MAAM,SAAS,MACf,mBAAmB,KAAK,KAAK,KAC7B,CAAC,sBAAsB,KAAK,CAAC,MAAM,MAAM,WAAW,CAAC,CAAC,KACtD,CAAC,QAAQ,KAAK,KAAK,IAAI,QAAQ;AAEjC,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,YAAI,WAAY,QAAO,iBAAiB,mBAAmB,UAAU,CAAC;AACtE,YAAI,OAAY,QAAO,aAAa,mBAAmB,MAAM,CAAC;AAC9D,eAAO,UAAW,IAAI,OAAO,KAAK;AAAA,MACpC,KAAK;AACH,YAAI,UAAY,QAAO,gBAAgB,mBAAmB,SAAS,CAAC;AACpE,YAAI,OAAY,QAAO,aAAa,mBAAmB,MAAM,CAAC;AAC9D,eAAO,UAAW,IAAI,OAAO,KAAK;AAAA,MACpC,KAAK;AACH,YAAI,QAAY,QAAO,IAAI,OAAO;AAClC,YAAI,OAAY,QAAO,aAAa,mBAAmB,MAAM,CAAC;AAC9D,eAAO,aAAa,iBAAiB,mBAAmB,UAAU,CAAC,OAAO;AAAA,MAC5E;AACE,YAAI,OAAY,QAAO,aAAa,mBAAmB,MAAM,CAAC;AAC9D,YAAI,UAAY,QAAO,aAAa,mBAAmB,SAAS,CAAC;AACjE,eAAO,UAAW,IAAI,OAAO,KAAK;AAAA,IACtC;AAAA,EACF;AAAA,EAEQ,qBAAqB,QAAqC;AAChE,QAAI,EAAE,kBAAkB,aAAc,QAAO;AAC7C,UAAM,MAAM,OAAO,QAAQ,YAAY;AACvC,WAAO,CAAC,UAAU,UAAU,SAAS,YAAY,QAAQ,EAAE,SAAS,GAAG;AAAA,EACzE;AAAA,EAEQ,cAAc,UAAkC;AACtD,WAAO,aAAa;AAAA,EACtB;AAAA,EAEQ,aAAa,QAA8B;AACjD,WAAO,CAAC,CAAC,OAAO,QAAQ,wCAAwC;AAAA,EAClE;AAAA,EAEQ,cAAc,KAAa,QAAwB;AACzD,UAAM,IAAI,IAAI,IAAI,KAAK,kBAAkB;AACzC,QAAI,OAAO,YAAY,MAAM,SAAS,EAAE,QAAQ;AAC9C,aAAO,KAAK,EAAE,QAAQ;AAAA,IACxB;AACA,WAAO,KAAK,EAAE,QAAQ;AAAA,EACxB;AACF;;;AEnsBA,iBAA0C;AAI1C;;;ACKO,IAAM,wBAA0E;AAAA,EACrF,MAAW,EAAE,IAAI,QAAa,OAAO,QAAmB,YAAY,yBAAkC,WAAW,uBAAuB;AAAA,EACxI,QAAW,EAAE,IAAI,UAAa,OAAO,iBAAmB,YAAY,yBAAkC,WAAW,QAAQ;AAAA,EACzH,QAAW,EAAE,IAAI,UAAa,OAAO,iBAAmB,YAAY,2BAAkC,WAAW,QAAQ;AAAA,EACzH,OAAW,EAAE,IAAI,SAAa,OAAO,gBAAmB,YAAY,kCAAkC,WAAW,QAAQ;AAAA,EACzH,WAAW,EAAE,IAAI,aAAa,OAAO,oBAAmB,YAAY,yBAAkC,WAAW,QAAQ;AAAA,EACzH,QAAW,EAAE,IAAI,UAAa,OAAO,UAAmB,YAAY,kBAAkC,WAAW,KAAK;AACxH;AAQO,IAAM,+BAAmD;AAAA,EAC9D,SAAU;AAAA,EACV,UAAU;AAAA,EACV,SAAU;AACZ;;;AC1BO,SAAS,eAAe,UAAkB,QAA2C;AAC1F,MAAI,CAAC,OAAO,WAAW,CAAC,SAAS,KAAK,KAAK,CAAC,OAAO,QAAQ,KAAK,EAAG,QAAO;AAC1E,QAAM,SAAU,sBAAsB,OAAO,QAAQ;AACrD,QAAM,OAAU,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AACjD,SAAO,OAAO,WAAW,QAAQ,aAAa,IAAI,EAAE,QAAQ,QAAQ,mBAAmB,SAAS,KAAK,CAAC,CAAC;AACzG;AAEO,SAAS,mBAAmB,UAA0B;AAC3D,SAAO,cAAc,SAAS,KAAK,CAAC;AACtC;AAEO,SAAS,gBAAgB,UAAkB,UAAyC;AACzF,MAAI,CAAC,SAAS,KAAK,EAAG,QAAO;AAC7B,SAAO,sBAAsB,QAAQ,EAAE,UAAU,KAAK,SAAS,KAAK,CAAC;AACvE;;;AFRA,IAAM,oBAAoB;AAkBnB,IAAM,qBAAN,MAAM,oBAAmB;AAAA;AAAA,EAI9B,YAA6B,SAAiB,UAAU,MAAM;AAAjC;AAAA,EAAkC;AAAA,EAAlC;AAAA,EAHrB,MAAoC;AAAA,EAKpC,QAA+B;AACrC,QAAI,CAAC,KAAK,KAAK;AACb,WAAK,UAAM,mBAAO,KAAK,QAAQ,UAAU,SAAS;AAAA,QAChD,QAAQ,UAAU;AAChB,qBAAW,SAAS,UAAU,QAAQ;AACpC,gBAAI,CAAC,SAAS,iBAAiB,SAAS,MAAM,IAAI,GAAG;AACnD,oBAAM,KAAK,SAAS,kBAAkB,MAAM,MAAM;AAAA,gBAChD,SAAS,MAAM;AAAA,gBACf,eAAe,MAAM;AAAA,cACvB,CAAC;AACD,yBAAW,SAAS,MAAM,SAAS;AACjC,mBAAG,YAAY,MAAM,MAAM,MAAM,SAAS,EAAE,QAAQ,MAAM,OAAO,CAAC;AAAA,cACpE;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAIA,MAAM,WAAW,MAAc,WAAqB,CAAC,GAAG,eAAyB,CAAC,GAAG,OAAiB,CAAC,GAAG,OAAgB,UAAoC;AAC5J,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,SAAiC,EAAE,MAAM,WAAW,KAAK,IAAI,GAAG,GAAI,KAAK,SAAS,EAAE,KAAK,IAAI,CAAC,GAAI,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,GAAI,GAAI,WAAW,EAAE,SAAS,IAAI,CAAC,EAAG;AACvK,UAAM,KAAK,MAAM,GAAG,IAAI,SAAS,MAAM;AACvC,QAAI,SAAS,OAAY,OAAM,KAAK,eAAe,UAAU,EAAE;AAC/D,QAAI,aAAa,OAAQ,OAAM,KAAK,mBAAmB,cAAc,EAAE;AACvE,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAA0C;AAC9C,UAAM,KAAQ,MAAM,KAAK,MAAM;AAC/B,UAAM,QAAQ,MAAM,GAAG,OAAO,OAAO;AACrC,WAAO,QAAQ;AAAA,MACb,MAAM,IAAI,OAAO,UAAU;AAAA,QACzB,GAAG;AAAA,QACH,UAAc,MAAM,KAAK,kBAAkB,KAAK,EAAE;AAAA,QAClD,cAAc,MAAM,KAAK,sBAAsB,KAAK,EAAE;AAAA,MACxD,EAAE;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,QAA4C;AAC5D,UAAM,KAAS,MAAM,KAAK,MAAM;AAChC,UAAM,SAAS,MAAM,GAAG,IAAI,SAAS,MAAM;AAC3C,QAAI,CAAC,OAAQ,QAAO;AAEpB,UAAM,WAAe,MAAM,KAAK,kBAAkB,MAAM;AACxD,UAAM,eAAe,MAAM,KAAK,sBAAsB,MAAM;AAC5D,UAAM,gBAAgB,OAAO,WAAW,mBAAmB,OAAO,QAAQ,IAAI,OAAO;AACrF,UAAM,UAAU,GAAG,aAAa,OAAO,mBAAmB,OAAO,IAAI,CAAC;AAAA,EAAe,SAAS,IAAI,OAAK,eAAe,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AAC1I,UAAM,oBAAoB,aAAa,SACnC,+CACA,aAAa,IAAI,OAAK,eAAe,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,IAAI,OAC5D;AAEJ,WAAO,EAAE,GAAG,QAAQ,UAAU,cAAc,iBAAiB,UAAU,SAAS,kBAAkB;AAAA,EACpG;AAAA,EAEA,MAAM,WAAW,IAA2B;AAC1C,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,GAAG,OAAO,SAAS,EAAE;AAC3B,UAAM,KAAK,uBAAuB,EAAE;AACpC,UAAM,KAAK,2BAA2B,EAAE;AAAA,EAC1C;AAAA;AAAA,EAIA,MAAM,eAAe,UAAoB,QAA+B;AACtE,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,QAAQ;AAAA,MACZ,SAAS,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,EAAE,SAAS,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC,CAAC;AAAA,IAC1F;AAAA,EACF;AAAA,EAEA,MAAM,oBAAoB,QAA0C;AAClE,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,GAAG,gBAAgB,YAAY,UAAU,MAAM;AAAA,EACxD;AAAA,EAEA,MAAc,kBAAkB,QAAmC;AACjE,YAAQ,MAAM,KAAK,oBAAoB,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,OAAO;AAAA,EACtF;AAAA,EAEA,MAAc,uBAAuB,QAA+B;AAClE,UAAM,KAAO,MAAM,KAAK,MAAM;AAC9B,UAAM,OAAO,MAAM,KAAK,oBAAoB,MAAM;AAClD,UAAM,KAAO,GAAG,YAAY,YAAY,WAAW;AACnD,UAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,EAAE,EAAE,CAAC,CAAC;AACxD,UAAM,GAAG;AAAA,EACX;AAAA;AAAA,EAIA,MAAM,mBAAmB,cAAwB,QAA+B;AAC9E,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,QAAQ;AAAA,MACZ,aAAa,IAAI,CAAC,gBAAgB,GAAG,IAAI,gBAAgB,EAAE,aAAa,QAAQ,WAAW,KAAK,IAAI,EAAE,CAAC,CAAC;AAAA,IAC1G;AAAA,EACF;AAAA,EAEA,MAAM,wBAAwB,QAA8C;AAC1E,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,WAAO,GAAG,gBAAgB,gBAAgB,UAAU,MAAM;AAAA,EAC5D;AAAA,EAEA,MAAc,sBAAsB,QAAmC;AACrE,YAAQ,MAAM,KAAK,wBAAwB,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,OAAO,OAAO;AAAA,EAC9F;AAAA,EAEA,MAAM,2BAA2B,QAA+B;AAC9D,UAAM,KAAO,MAAM,KAAK,MAAM;AAC9B,UAAM,OAAO,MAAM,KAAK,wBAAwB,MAAM;AACtD,UAAM,KAAO,GAAG,YAAY,gBAAgB,WAAW;AACvD,UAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,MAAM,GAAG,MAAM,OAAO,EAAE,EAAE,CAAC,CAAC;AACxD,UAAM,GAAG;AAAA,EACX;AAAA;AAAA,EAIA,MAAM,UAAU,QAAgD;AAC9D,UAAM,KAAU,MAAM,KAAK,MAAM;AACjC,UAAM,UAAU,MAAM,GAAG,OAAO,eAAe;AAC/C,UAAM,UAAU,QAAQ,CAAC,KAAK,CAAC;AAC/B,UAAM,SAAU,EAAE,GAAG,SAAS,GAAG,OAAO;AACxC,QAAK,QAAyB,IAAI;AAChC,YAAM,GAAG,IAAI,iBAAiB,MAAM;AAAA,IACtC,OAAO;AACL,YAAM,GAAG,IAAI,iBAAiB,MAAM;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,KAAa,OAA+B;AAC7D,WAAO,KAAK,UAAU,EAAE,CAAC,GAAG,GAAG,MAAM,CAAC;AAAA,EACxC;AAAA,EAEA,MAAM,UAAU,KAAsD;AACpE,UAAM,KAAU,MAAM,KAAK,MAAM;AACjC,UAAM,UAAU,MAAM,GAAG,OAAO,eAAe;AAC/C,QAAI,CAAC,QAAQ,OAAQ,QAAO;AAC5B,UAAM,SAAS,QAAQ,CAAC;AACxB,WAAO,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,IAAI,EAAE,CAAC,GAAG,GAAG,OAAO,GAAG,EAAE,IAAI;AAAA,EACtF;AAAA,EAEA,MAAM,mBAAiD;AACrD,UAAM,KAAU,MAAM,KAAK,MAAM;AACjC,UAAM,UAAU,MAAM,GAAG,OAAO,eAAe;AAC/C,WAAO,QAAQ,CAAC,KAAK;AAAA,EACvB;AAAA;AAAA,EAIA,OAAwB,kBAAkB;AAAA,EAE1C,MAAM,eAAe,QAAyC;AAC5D,UAAM,KAAK,aAAa,oBAAmB,iBAAiB,KAAK,UAAU,MAAM,CAAC;AAAA,EACpF;AAAA,EAEA,MAAM,gBAAkD;AACtD,UAAM,SAAS,MAAM,KAAK,UAAU,oBAAmB,eAAe;AACtE,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,MAAM,OAAO,oBAAmB,eAAe;AACrD,QAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,QAAI;AAAE,aAAO,KAAK,MAAM,GAAG;AAAA,IAAuB,QAAQ;AAAE,aAAO;AAAA,IAAM;AAAA,EAC3E;AAAA,EAEA,MAAM,kBAAiC;AACrC,UAAM,KAAU,MAAM,KAAK,MAAM;AACjC,UAAM,UAAU,MAAM,GAAG,OAAO,eAAe;AAC/C,QAAI,CAAC,QAAQ,OAAQ;AACrB,UAAM,UAAU,EAAE,GAAG,QAAQ,CAAC,EAAE;AAChC,WAAO,QAAQ,oBAAmB,eAAe;AACjD,UAAM,GAAG,IAAI,iBAAiB,OAAO;AAAA,EACvC;AAAA;AAAA;AAAA,EAKA,MAAM,kBAAkB,OAA0C;AAChE,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,GAAG,IAAI,iBAAiB,EAAE,GAAG,OAAO,IAAI,kBAAkB,CAAC;AAAA,EACnE;AAAA;AAAA,EAGA,MAAM,mBAAuD;AAC3D,UAAM,KAAS,MAAM,KAAK,MAAM;AAChC,UAAM,SAAS,MAAM,GAAG,IAAI,iBAAiB,iBAAiB;AAC9D,QAAI,CAAC,OAAQ,QAAO;AACpB,UAAM,EAAE,IAAI,KAAK,GAAG,MAAM,IAAI;AAC9B,WAAO;AAAA,EACT;AAAA;AAAA,EAGA,MAAM,qBAAoC;AACxC,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,GAAG,OAAO,iBAAiB,iBAAiB;AAAA,EACpD;AAAA;AAAA,EAIA,MAAM,eAA8B;AAClC,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,UAAM,QAAQ,IAAI;AAAA,MAChB,GAAG,MAAM,OAAO;AAAA,MAChB,GAAG,MAAM,UAAU;AAAA,MACnB,GAAG,MAAM,cAAc;AAAA,IACzB,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,eAAe,OAAkC,cAAwD;AAC7G,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,YAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,iBAAW,QAAQ,OAAO;AAKxB,cAAM,EAAE,IAAI,KAAK,UAAU,cAAc,kBAAkB,GAAG,OAAO,IAAI;AACzE,cAAM,QAAQ,MAAM,GAAG,IAAI,SAAS,MAAM;AAC1C,cAAM,OAAO,MAAM,QAAQ,QAAQ,IAAI,WAAuB,CAAC;AAC/D,cAAM,OAAO,MAAM,QAAQ,gBAAgB,IAAI,mBAA+B,CAAC;AAC/E,YAAI,KAAK,OAAQ,OAAM,KAAK,eAAe,MAAM,KAAK;AACtD,YAAI,KAAK,OAAQ,OAAM,KAAK,mBAAmB,MAAM,KAAK;AAAA,MAC5D;AAAA,IACF;AAEA,UAAM,KAAK,oBAAoB,gBAAgB,YAAY;AAAA,EAC7D;AAAA,EAEA,MAAM,qBAAuC;AAC3C,UAAM,SAAS,MAAM,KAAK,iBAAiB;AAC3C,WAAO,CAAC,CAAC,SAAS,wBAAwB;AAAA,EAC5C;AAAA,EAEA,MAAM,kBAAkB,UAAkB,OAAmC;AAC3E,UAAM,SAAS,MAAM,KAAK,iBAAiB;AAC3C,UAAM,YAAY,SAAS,wBAAwB;AACnD,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,8BAA8B;AAE9D,UAAM,OAAO;AACb,QAAI,QAAQ,MAAM,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5D,QAAI,UAAU,UAAW,SAAQ,MAAM,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACnF,QAAI,UAAU,UAAW,OAAM,IAAI,MAAM,yBAAyB;AAElE,UAAM,cAAc,MAAM,UAAU,mBAAmB,YAAY,EAAE,QAAQ,KAAK,CAAC;AACnF,UAAM,aAAa,MAAM,YAAY,cAAc,UAAU,EAAE,QAAQ,KAAK,CAAC;AAC7E,UAAM,WAAW,MAAM,WAAW,eAAe;AACjD,UAAM,SAAS,MAAM,KAAK;AAC1B,UAAM,SAAS,MAAM;AAAA,EACvB;AAAA,EAEA,MAAM,8BAA6C;AACjD,QAAI,EAAE,yBAAyB,SAAS;AACtC,YAAM,IAAI,MAAM,sCAAsC;AAAA,IACxD;AACA,UAAM,YAAY,MAAM,OAAO,oBAAoB;AACnD,UAAM,KAAK,aAAa,0BAA0B,SAAS;AAC3D,UAAM,KAAK,aAAa,uBAAuB,MAAM;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,cAAc,UAAqE;AACvF,QAAI,CAAC,SAAS,OAAQ,QAAO;AAC7B,UAAM,SAAS,MAAM,KAAK,iBAAiB;AAC3C,UAAM,YAAY,SAAS,wBAAwB;AACnD,QAAI,CAAC,UAAW,OAAM,IAAI,MAAM,8BAA8B;AAE9D,UAAM,OAAO;AACb,QAAI,QAAQ,MAAM,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC5D,QAAI,UAAU,UAAW,SAAQ,MAAM,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACnF,QAAI,UAAU,UAAW,OAAM,IAAI,MAAM,yBAAyB;AAElE,UAAM,cAAc,MAAM,UAAU,mBAAmB,YAAY,EAAE,QAAQ,KAAK,CAAC;AACnF,QAAI,UAAU;AACd,eAAW,MAAM,UAAU;AACzB,YAAM,aAAa,MAAM,YAAY,cAAc,GAAG,MAAM,EAAE,QAAQ,KAAK,CAAC;AAC5E,YAAM,WAAW,MAAM,WAAW,eAAe;AACjD,YAAM,SAAS,MAAM,GAAG,OAAO;AAC/B,YAAM,SAAS,MAAM;AACrB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,oBAAoB,OAAe,OAAiD;AAChG,QAAI,CAAC,MAAM,QAAQ,KAAK,EAAG;AAC3B,UAAM,KAAK,MAAM,KAAK,MAAM;AAC5B,eAAW,QAAQ,OAAO;AACxB,YAAM,EAAE,IAAI,KAAK,GAAG,KAAK,IAAI;AAC7B,YAAM,GAAG,IAAI,OAAO,IAAI;AAAA,IAC1B;AAAA,EACF;AACF;;;AGzUA;;;ACGA,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EACA;AAAA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAIA,IAAM,kBAAkB,oBAAI,IAAI;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAED,SAAS,aAAa,KAAqB;AACzC,SAAO,IAAI,YAAY,EAAE,QAAQ,cAAc,EAAE;AACnD;AAEO,SAAS,eAAe,KAAsB;AACnD,QAAM,aAAa,aAAa,GAAG;AACnC,MAAI,gBAAgB,IAAI,UAAU,EAAG,QAAO;AAC5C,SAAO,qBAAqB,KAAK,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC;AAChE;AAeO,SAAS,sBAAsB,KAAuB;AAC3D,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,qBAAqB;AAAA,EACtC;AACA,MAAI,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAC3C,UAAM,SAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,GAA8B,GAAG;AACzE,aAAO,GAAG,IAAI,eAAe,GAAG,IAAI,eAAe,sBAAsB,KAAK;AAAA,IAChF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;;;AD9DA,IAAM,sBAAsB,CAAC,OAAO,QAAQ,KAAK;AAG1C,SAAS,cAAc,QAAgB,KAAqB;AACjE,MAAI;AACF,UAAM,IAAI,IAAI,IAAI,KAAK,kBAAkB;AACzC,UAAM,OAAO,EAAE,SACZ,QAAQ,iBAAiB,GAAG,EAC5B,QAAQ,OAAO,GAAG,EAClB,QAAQ,cAAc,EAAE;AAC3B,WAAO,GAAG,OAAO,YAAY,CAAC,IAAI,IAAI;AAAA,EACxC,QAAQ;AACN,WAAO,GAAG,OAAO,YAAY,CAAC;AAAA,EAChC;AACF;AAEA,IAAM,kBAAkB;AAExB,SAAS,iBAAiB,MAAc,KAAsC;AAC5E,SAAO,OAAO,KAAK,GAAG,EACnB,OAAO,CAAC,QAAQ,QAAQ,QAAQ,QAAQ,KAAK,EAC7C,IAAI,CAAC,QAAQ;AACZ,UAAM,WAAW,gBAAgB,KAAK,GAAG,IACrC,IAAI,GAAG,KACP,KAAK,mBAAmB,GAAG,CAAC;AAChC,WAAO,UAAU,IAAI,GAAG,QAAQ,cAAc,KAAK,UAAU,IAAI,GAAG,CAAC,CAAC;AAAA,EACxE,CAAC,EACA,KAAK,IAAI;AACd;AAEA,SAAS,mBACP,QACA,OACA,cACA,aACA,cACQ;AACR,MAAI,gBAAgB,WAAW,SAAS,cAAc;AACpD,UAAM,cAAc,iBAAiB,8BAA8B,YAAY;AAC/E,WAAO,aAAa,KAAK;AAAA;AAAA,EAAgE,WAAW;AAAA;AAAA;AAAA,EACtG;AACA,MAAI,iBAAiB,WAAW,UAAU,WAAW,UAAU,aAAa;AAC1E,UAAM,cAAc,iBAAiB,6BAA6B,WAAW;AAC7E,WAAO,aAAa,KAAK;AAAA,EAAgC,WAAW;AAAA;AAAA,EACtE;AACA,SAAO,aAAa,KAAK;AAC3B;AAEA,SAAS,gBAAgB,MAA8C;AACrE,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAGA,SAAS,iBAAiB,MAA6B;AACrD,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,QAAI,UAAU,OAAO,WAAW,SAAU,QAAO,KAAK,UAAU,QAAQ,MAAM,CAAC;AAAA,EACjF,QAAQ;AAAA,EAER;AACA,SAAO;AACT;AAEA,SAAS,iBAAiB,MAAoD;AAC5E,QAAM,OAAO,MAAM;AACnB,MAAI,OAAO,SAAS,SAAU,QAAO,gBAAgB,IAAI;AACzD,SAAO;AACT;AAEA,SAAS,WAAW,OAAkC;AACpD,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI,iBAAiB,IAAK,QAAO,MAAM;AACvC,SAAO,MAAM;AACf;AAEA,SAAS,cAAc,OAA0B,MAA4B;AAC3E,MAAI,MAAM,OAAQ,QAAO,KAAK,OAAO,YAAY;AACjD,MAAI,iBAAiB,QAAS,QAAO,MAAM,OAAO,YAAY;AAC9D,SAAO;AACT;AAIA,eAAe,yBACb,WACA,OACA,MACA,eACe;AACf,QAAM,SAAS,cAAc,OAAO,IAAI;AACxC,MAAI,CAAE,oBAA0C,SAAS,MAAM,EAAG;AAElE,QAAM,MAAM,WAAW,KAAK;AAC5B,QAAM,QAAQ,cAAc,QAAQ,GAAG;AAEvC,YAAU,oBAAoB,QAAQ,KAAK,KAAK;AAKhD,QAAM,eAAe,aAAa,QAAQ,sBAAsB,MAAM;AACtE,QAAM,cAAc,aAAa,QAAQ,aAAa,MAAM;AAC5D,QAAM,cAAc,eAAe,iBAAiB,IAAI,IAAI;AAE5D,MAAI,eAA8B;AAClC,MAAI,eAA+C;AAEnD,MAAI,gBAAiB,eAAe,WAAW,OAAQ;AACrD,QAAI;AACF,qBAAe,MAAM,cAAc,KAAK;AACxC,UAAI,aAAc,gBAAe,gBAAgB,YAAY;AAAA,IAC/D,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,MAAI,eAAe,WAAW,SAAS,iBAAiB,MAAM;AAC5D,UAAM,SAAS,iBAAiB,YAAY;AAC5C,QAAI,WAAW,MAAM;AACnB,YAAM,WAAW,sBAAsB,KAAK,MAAM,MAAM,CAAC;AACzD,gBAAU,gBAAgB,GAAG,KAAK,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF;AAEA,QAAM,MAAM;AAAA,IACV;AAAA,IAAQ;AAAA,IAAO;AAAA,IACf,cAAc,sBAAsB,WAAW,IAA+B;AAAA,IAC9E,eAAe,sBAAsB,YAAY,IAA+B;AAAA,EAClF;AACA,YAAU,WAAW,GAAG;AAC1B;AAEA,SAAS,uBACP,WACA,QACA,KACA,aACA,cACM;AACN,MAAI,CAAE,oBAA0C,SAAS,MAA2B,EAAG;AAEvF,QAAM,QAAQ,cAAc,QAAQ,GAAG;AAEvC,YAAU,oBAAoB,QAAQ,KAAK,KAAK;AAGhD,MAAI,aAAa,QAAQ,aAAa,MAAM,UAAU,WAAW,OAAO;AACtE,UAAM,SAAS,iBAAiB,YAAY;AAC5C,QAAI,WAAW,MAAM;AACnB,YAAM,WAAW,sBAAsB,KAAK,MAAM,MAAM,CAAC;AACzD,gBAAU,gBAAgB,GAAG,KAAK,SAAS,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,IAC9E;AAAA,EACF;AAEA,QAAM,eAAe,aAAa,QAAQ,sBAAsB,MAAM;AACtE,QAAM,eAAe,eAAe,gBAAgB,YAAY,IAAI;AAEpE,QAAM,MAAM;AAAA,IACV;AAAA,IAAQ;AAAA,IAAO;AAAA,IACf,cAAc,sBAAsB,WAAW,IAA+B;AAAA,IAC9E,eAAe,sBAAsB,YAAY,IAA+B;AAAA,EAClF;AACA,YAAU,WAAW,GAAG;AAC1B;AAIA,IAAI,YAAY;AAChB,IAAI,iBAA6C;AACjD,IAAI,eAA6C;AACjD,IAAM,cAAc,oBAAI,IAAsB;AAE9C,SAAS,cAAoB;AAC3B,QAAM,OAAO,OAAO;AACpB,mBAAiB;AAEjB,SAAO,QAAQ,OAAO,OAA0B,SAA0C;AACxF,UAAM,WAAW,MAAM,KAAK,OAAO,IAAI;AACvC,QAAI;AACF,YAAM,SAAS,CAAC,GAAG,WAAW;AAC9B,UAAI,OAAO,SAAS,GAAG;AACrB,cAAM,QAAQ;AAAA,UACZ,OAAO,IAAI,CAAC,QAAQ,yBAAyB,KAAK,OAAO,MAAM,SAAS,MAAM,CAAC,EAAE,MAAM,MAAM;AAAA,UAAC,CAAC,CAAC;AAAA,QAClG;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AACA,WAAO;AAAA,EACT;AACF;AAEA,SAAS,gBAAsB;AAC7B,MAAI,CAAC,eAAgB;AACrB,SAAO,QAAQ;AACf,mBAAiB;AACnB;AAEA,SAAS,YAAkB;AACzB,QAAM,UAAU,OAAO;AACvB,iBAAe;AAEf,SAAO,iBAAiB,cAAc,QAAQ;AAAA,IACpC,aAAa;AAAA,IACb,UAAU;AAAA,IACV,kBAAkD;AAAA,IAEjD,KACP,QACA,KACA,QAAQ,MACR,MACA,UACM;AACN,WAAK,aAAa,OAAO,YAAY;AACrC,WAAK,UAAU,eAAe,MAAM,IAAI,OAAO;AAC/C,YAAM,KAAK,QAAQ,KAAe,OAAO,MAAM,QAAQ;AAAA,IACzD;AAAA,IAES,KAAK,MAAuD;AACnE,UAAI,OAAO,SAAS,UAAU;AAC5B,aAAK,kBAAkB,gBAAgB,IAAI;AAAA,MAC7C;AACA,WAAK,iBAAiB,QAAQ,MAAM;AAClC,YAAI;AACF,qBAAW,OAAO,aAAa;AAC7B,mCAAuB,KAAK,KAAK,YAAY,KAAK,SAAS,KAAK,iBAAiB,KAAK,YAAY;AAAA,UACpG;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF,CAAC;AACD,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACF;AAEA,SAAS,cAAoB;AAC3B,MAAI,CAAC,aAAc;AACnB,SAAO,iBAAiB;AACxB,iBAAe;AACjB;AAYO,IAAM,cAAN,MAAkB;AAAA,EACvB,YAA6B,WAA6B;AAA7B;AAAA,EAA8B;AAAA,EAA9B;AAAA,EAE7B,UAAgB;AACd,gBAAY,IAAI,KAAK,SAAS;AAC9B;AACA,QAAI,cAAc,GAAG;AACnB,kBAAY;AACZ,gBAAU;AAAA,IACZ;AAAA,EACF;AAAA,EAEA,YAAkB;AAChB,gBAAY,OAAO,KAAK,SAAS;AACjC,QAAI,aAAa,EAAG;AACpB;AACA,QAAI,cAAc,GAAG;AACnB,oBAAc;AACd,kBAAY;AAAA,IACd;AAAA,EACF;AAAA,EAEA,wBAAiC;AAC/B,WAAO,aAAa,QAAQ,sBAAsB,MAAM;AAAA,EAC1D;AAAA,EAEA,uBAAgC;AAC9B,WAAO,aAAa,QAAQ,aAAa,MAAM;AAAA,EACjD;AACF;;;AEtSO,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCzB,IAAM,0CAA0C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgGhD,SAAS,aAAa,KAAa,IAAkB;AAC1D,MAAI,SAAS,eAAe,EAAE,EAAG;AACjC,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,KAAK;AACX,QAAM,YAAY;AAClB,WAAS,KAAK,YAAY,KAAK;AACjC;;;ACvIO,SAAS,mBACd,OACA,SACY;AACZ,MAAI,CAAC,SAAS,MAAM,cAAc,gBAAgB,EAAG,QAAO,MAAM;AAAA,EAAc;AAEhF,QAAM,OAAO,MAAM,sBAAsB;AACzC,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,MAAM,GAAG,KAAK,GAAG;AAC7B,QAAM,MAAM,OAAO,GAAG,KAAK,IAAI;AAC/B,QAAM,MAAM,QAAQ,GAAG,KAAK,KAAK;AACjC,QAAM,MAAM,SAAS;AACrB,QAAM,MAAM,SAAS;AACrB,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,YAAY,SAAS,YAAY,OAAO;AACpD,QAAM,MAAM,aAAa,SAAS,aAAa,OAAO;AAEtD,QAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,UAAQ,YAAY;AACpB,UAAQ,MAAM,WAAW;AACzB,UAAQ,MAAM,QAAQ;AACtB,UAAQ,MAAM,SAAS;AACvB,UAAQ,MAAM,QAAQ;AACtB,UAAQ,MAAM,SAAS;AACvB,UAAQ,MAAM,SAAS;AACvB,UAAQ,MAAM,aAAa;AAC3B,UAAQ,MAAM,SAAS;AACvB,QAAM,YAAY,OAAO;AAEzB,MAAI,aAAa;AACjB,MAAI,QAAQ;AACZ,MAAI,QAAQ;AAEZ,QAAM,YAAY,CAAC,MAAwB;AACzC,QAAI,CAAC,WAAY;AACjB,UAAM,KAAK,EAAE,UAAU;AACvB,UAAM,KAAK,EAAE,UAAU;AACvB,YAAQ,EAAE;AACV,YAAQ,EAAE;AACV,UAAMC,QAAO,MAAM,sBAAsB;AACzC,UAAM,MAAM,QAAQA,MAAK,QAAQ,KAAK;AACtC,UAAM,MAAM,SAASA,MAAK,SAAS,KAAK;AAAA,EAC1C;AAEA,QAAM,UAAU,MAAY;AAC1B,iBAAa;AACb,aAAS,KAAK,MAAM,aAAa;AAAA,EACnC;AAEA,UAAQ,iBAAiB,aAAa,CAAC,MAAM;AAC3C,MAAE,eAAe;AACjB,iBAAa;AACb,YAAQ,EAAE;AACV,YAAQ,EAAE;AACV,aAAS,KAAK,MAAM,aAAa;AAAA,EACnC,CAAC;AAED,SAAO,iBAAiB,aAAa,SAAS;AAC9C,SAAO,iBAAiB,WAAW,OAAO;AAE1C,SAAO,MAAM;AACX,WAAO,oBAAoB,aAAa,SAAS;AACjD,WAAO,oBAAoB,WAAW,OAAO;AAC7C,QAAI,QAAQ,WAAY,SAAQ,WAAW,YAAY,OAAO;AAAA,EAChE;AACF;AAEA,SAAS,eAAe,MAAmB,UAA6B;AACtE,MAAI,aAAa;AACjB,MAAI,UAAU;AACd,MAAI,UAAU;AAEd,WAAS,MAAM,SAAS;AACxB,WAAS,cAAc,CAAC,MAAkB;AACxC,iBAAa;AACb,UAAM,OAAO,KAAK,sBAAsB;AACxC,cAAU,EAAE,UAAU,KAAK;AAC3B,cAAU,EAAE,UAAU,KAAK;AAC3B,aAAS,cAAc,CAAC,OAAmB;AACzC,UAAI,YAAY;AACd,aAAK,MAAM,WAAW;AACtB,aAAK,MAAM,SAAS;AACpB,aAAK,MAAM,OAAO,GAAG,GAAG,UAAU,OAAO;AACzC,aAAK,MAAM,MAAM,GAAG,GAAG,UAAU,OAAO;AAAA,MAC1C;AAAA,IACF;AACA,aAAS,YAAY,MAAM;AACzB,mBAAa;AACb,eAAS,cAAc;AACvB,eAAS,YAAY;AAAA,IACvB;AAAA,EACF;AACF;AAEA,SAAS,gBAAgB,MAAuC;AAC9D,SAAQ,KAAK,cAAc,eAAe,KACpC,KAAK,cAAc,cAAc;AACzC;AAEO,SAAS,oBAA0B;AACxC,QAAM,SAAS,SAAS,iBAAiB,cAAc;AACvD,MAAI,CAAC,OAAO,OAAQ;AACpB,QAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,QAAM,WAAW,gBAAgB,IAAI;AACrC,MAAI,CAAC,SAAU;AACf,iBAAe,MAAM,QAAQ;AAC/B;AAgBO,SAAS,wBAAwB,SAAS,8BAAoC;AACnF,WAAS,cAAc,kBAAkB,GAAG,aAAa,WAAW,MAAM;AAC1E,WAAS,cAAc,uBAAuB,GAAG,aAAa,WAAW,MAAM;AAC/E,WAAS,cAAc,cAAc,GAAG,aAAa,WAAW,MAAM;AACxE;AAEO,SAAS,sBAAsB,OAA2B,UAAwB;AACvF,MAAI,CAAC,MAAO;AACZ,QAAM,MAAM,SAAS,GAAG,QAAQ;AAChC,QAAM,gBAAgB,MAAM,cAAc,uBAAuB;AACjE,MAAI,CAAC,cAAe;AACpB,gBAAc,MAAM,OAAO;AAC3B,gBAAc,MAAM,YAAY;AAChC,gBAAc,MAAM,WAAW;AAC/B,gBAAc,MAAM,UAAU;AAC9B,gBAAc,MAAM,SAAS;AAC7B,gBAAc,MAAM,UAAU;AAC9B,gBAAc,MAAM,gBAAgB;AACtC;;;AC5IO,SAAS,UAAU,SAAiB,YAAY,MAAY;AACjE,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,cAAc;AACpB,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,MAAM;AAClB,QAAM,MAAM,QAAQ;AACpB,QAAM,MAAM,UAAU;AACtB,QAAM,MAAM,aAAa,YAAY,YAAY;AACjD,QAAM,MAAM,QAAQ;AACpB,QAAM,MAAM,eAAe;AAC3B,QAAM,MAAM,YAAY;AACxB,QAAM,MAAM,SAAS;AACrB,QAAM,MAAM,WAAW;AACvB,QAAM,MAAM,aAAa;AACzB,QAAM,MAAM,gBAAgB;AAC5B,WAAS,KAAK,YAAY,KAAK;AAC/B,aAAW,MAAM,MAAM,OAAO,GAAG,GAAI;AACvC;;;ACKO,SAAS,qBACd,OACA,MACA,OAA+B,CAAC,GACb;AACnB,MAAI,SAAS,MAAO,QAAO,CAAC,GAAG,KAAK;AAEpC,MAAI,SAAS,UAAU;AACrB,UAAM,MAAM,IAAI,IAAI,KAAK,OAAO,CAAC,CAAC;AAClC,WAAO,MAAM,OAAO,CAAC,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;AAAA,EAC1C;AAGA,QAAM,OAAO,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;AACpC,MAAI,KAAK,SAAS,EAAG,QAAO,CAAC;AAC7B,SAAO,MAAM,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,KAAK,IAAI,GAAG,CAAC,CAAC;AACxE;;;AC9BO,SAAS,YAAY,UAA2B;AACrD,MAAI,CAAC,SAAU,QAAO;AACtB,QAAM,IAAI,SAAS,YAAY;AAC/B,SACE,MAAM,eACN,EAAE,SAAS,YAAY,KACvB,MAAM,eACN,MAAM,SACN,MAAM;AAEV;;;AxB6BA;;;AyB/CO,IAAM,4BAA4B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAzC;AAEO,SAAS,wBACd,UACA,cACA,kBACA,UACA,GACQ;AACR,QAAM,eAAe,CAAC,KAAa,UAAkB,WAAW;AAAA;AAAA,+CAEnB,GAAG,YAAY,EAAE,6BAA6B,CAAC,KAAK,QAAQ,IAAI,gCAAgC,EAAE;AAAA,+CAClG,GAAG,YAAY,EAAE,+BAA+B,CAAC,KAAK,QAAQ,QAAQ,IAAI,gCAAgC,EAAE;AAAA,wDACnG,GAAG,YAAY,EAAE,8BAA8B,CAAC;AAAA,eACzF;AAEb,QAAM,WAAW,SAAS,SACtB,SAAS,IAAI,CAAC,GAAG,MAAM;AAAA;AAAA,mCAEM,QAAQ,CAAC,CAAC;AAAA,YACjC,aAAa,GAAG,SAAS,MAAM,CAAC;AAAA,eAC7B,EAAE,KAAK,EAAE,IAClB,sBAAsB,EAAE,gCAAgC,CAAC;AAE7D,QAAM,kBAAkB,CAAC,QAAgB,WACrC,kFAAkF,GAAG,YAAY,EAAE,8BAA8B,CAAC,6BAClI;AAEJ,QAAM,aAAa,mBACf;AAAA,qCAC+B,EAAE,iCAAiC,CAAC;AAAA;AAAA,YAG7D,aAAa,SACT,aAAa,IAAI,CAAC,IAAI,QAAQ;AAAA;AAAA,6CAED,QAAQ,EAAE,CAAC;AAAA,sBAClC,gBAAgB,GAAG,CAAC;AAAA,yBACjB,EAAE,KAAK,EAAE,IAClB,sBAAsB,EAAE,iCAAiC,CAAC,QAChE;AAAA;AAAA,gEAEsD,EAAE,iCAAiC,CAAC;AAAA,gBAE9F;AAEJ,SAAO;AAAA;AAAA,mCAE0B,EAAE,kCAAkC,CAAC;AAAA,gDACxB,mBAAmB,WAAW,EAAE;AAAA,UACtE,mBAAmB,EAAE,sCAAsC,IAAI,EAAE,sCAAsC,CAAC,KAAK,aAAa,MAAM;AAAA;AAAA;AAAA;AAAA,mCAIvG,EAAE,qCAAqC,CAAC,KAAK,SAAS,MAAM;AAAA,0CACrD,QAAQ;AAAA;AAAA,MAE5C,UAAU;AAChB;;;ACtDO,IAAM,2BAAN,cAAuC,YAAY;AAAA,EAChD;AAAA,EACA,YAAsB,CAAC;AAAA,EACvB,gBAA0B,CAAC;AAAA,EAC3B,oBAAoB;AAAA,EAC5B,WAAW;AAAA,EACX,cAAkC;AAAA,EAElC,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AACxB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,IAAI,WAAqB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAI,SAAS,GAAa;AACxB,SAAK,YAAY;AACjB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,IAAI,eAAyB;AAC3B,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAI,aAAa,GAAa;AAC5B,SAAK,gBAAgB;AACrB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,IAAI,mBAA4B;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,qBAA2B;AACzB,SAAK,oBAAoB,CAAC,KAAK;AAC/B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,kBAAwB;AACtB,UAAM,OAAO,KAAK,UAAU,KAAK,IAAI;AACrC,QAAI,CAAC,KAAM;AACX,cAAU,WAAW,UAAU,IAAI;AAAA,EACrC;AAAA,EAEA,8BAAoC;AAClC,UAAM,OAAO,KAAK,cAAc,KAAK,IAAI;AACzC,QAAI,CAAC,KAAM;AACX,cAAU,WAAW,UAAU,IAAI;AAAA,EACrC;AAAA,EAEQ,EAAE,KAAqB;AAAE,WAAO,KAAK,YAAY,UAAU,GAAG;AAAA,EAAG;AAAA,EAEjE,eAAe,OAAqB;AAC1C,SAAK,cAAc,IAAI,YAAY,iBAAiB,EAAE,QAAQ,OAAO,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EACvG;AAAA,EAEQ,aAAa,MAAc,IAAkB;AACnD,SAAK,cAAc,IAAI,YAAY,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EAC5G;AAAA,EAEQ,0BAA0B,OAAqB;AACrD,SAAK,cAAc,IAAI,YAAY,qBAAqB,EAAE,QAAQ,OAAO,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EAC3G;AAAA,EAEQ,SAAe;AACrB,SAAK,OAAO,YAAY,UAAU,yBAAyB,WAAW;AAAA,MACpE,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK,EAAE,KAAK,IAAI;AAAA,IAClB,CAAC;AAED,UAAM,SAAS,KAAK,OAAO,cAA2B,mBAAmB;AACzE,QAAI,OAAQ,QAAO,YAAY,OAAO;AAEtC,SAAK,OAAO,cAAc,sBAAsB,GAAG,iBAAiB,SAAS,MAAM,KAAK,gBAAgB,CAAC;AACzG,SAAK,OAAO,cAAc,4BAA4B,GAAG,iBAAiB,SAAS,MAAM,KAAK,mBAAmB,CAAC;AAClH,SAAK,OAAO,cAAc,0BAA0B,GAAG,iBAAiB,SAAS,MAAM,KAAK,4BAA4B,CAAC;AAEzH,QAAI,KAAK,UAAU;AACjB,WAAK,OAAO,iBAAiB,YAAY,EAAE,QAAQ,CAAC,QAAQ;AAC1D,YAAI,iBAAiB,SAAS,CAAC,MAAM;AACnC,YAAE,gBAAgB;AAClB,eAAK,eAAe,OAAQ,IAAoB,QAAQ,KAAK,CAAC,CAAC;AAAA,QACjE,CAAC;AAAA,MACH,CAAC;AACD,WAAK,OAAO,iBAAiB,gBAAgB,EAAE,QAAQ,CAAC,QAAQ;AAC9D,YAAI,iBAAiB,SAAS,CAAC,MAAM;AACnC,YAAE,gBAAgB;AAClB,gBAAM,MAAM,OAAQ,IAAoB,QAAQ,QAAQ,CAAC;AACzD,eAAK,aAAa,KAAK,MAAM,CAAC;AAAA,QAChC,CAAC;AAAA,MACH,CAAC;AACD,WAAK,OAAO,iBAAiB,gBAAgB,EAAE,QAAQ,CAAC,QAAQ;AAC9D,YAAI,iBAAiB,SAAS,CAAC,MAAM;AACnC,YAAE,gBAAgB;AAClB,gBAAM,MAAM,OAAQ,IAAoB,QAAQ,QAAQ,CAAC;AACzD,eAAK,aAAa,KAAK,MAAM,CAAC;AAAA,QAChC,CAAC;AAAA,MACH,CAAC;AACD,WAAK,OAAO,iBAAiB,gBAAgB,EAAE,QAAQ,CAAC,QAAQ;AAC9D,YAAI,iBAAiB,SAAS,CAAC,MAAM;AACnC,YAAE,gBAAgB;AAClB,eAAK,0BAA0B,OAAQ,IAAoB,QAAQ,QAAQ,CAAC,CAAC;AAAA,QAC/E,CAAC;AAAA,MACH,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,4BAA4B,GAAG;AACrD,iBAAe,OAAO,8BAA8B,wBAAwB;AAC9E;;;ACzHO,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAhC;AAEO,SAAS,6BAA6B,GAAoC;AAC/E,SAAO;AAAA;AAAA,uCAEyB,EAAE,2BAA2B,CAAC;AAAA;AAAA,8DAEF,EAAE,+BAA+B,CAAC;AAAA,wCACxD,EAAE,oBAAoB,CAAC;AAAA;AAAA;AAG/D;AAEO,SAAS,kBAAkB,GAAoC;AACpE,SAAO;AAAA;AAAA,WAEE,EAAE,eAAe,CAAC;AAAA;AAAA,mDAEsB,EAAE,wBAAwB,CAAC;AAAA,kDAC5B,EAAE,sBAAsB,CAAC;AAAA;AAAA;AAG3E;AAEO,SAAS,mBAAmB,aAAqB,OAAe,MAAgB,UAAkB,qBAA8B,YAAqB,GAAoC;AAC9L,QAAM,YAAY,KAAK;AAAA,IAAI,CAAC,QAC1B,sBAAsB,QAAQ,GAAG,CAAC,sCAAsC,QAAQ,GAAG,CAAC,YAAY,EAAE,4BAA4B,CAAC;AAAA,EACjI,EAAE,KAAK,EAAE;AAET,QAAM,aAAa,sBAAsB;AAAA,gCACX,EAAE,wBAAwB,CAAC;AAAA,0DACD,QAAQ,EAAE,8BAA8B,CAAC,CAAC;AAAA,sBAC9E,QAAQ,QAAQ,CAAC;AAAA,QAC/B,aAAa,oCAA+B,EAAE,uBAAuB,CAAC,YAAY,EAAE,KAAK;AAE/F,SAAO;AAAA;AAAA,WAEE,EAAE,sBAAsB,CAAC;AAAA,wDACoB,EAAE,4BAA4B,CAAC;AAAA,sBACjE,QAAQ,WAAW,CAAC;AAAA,gCACV,EAAE,uBAAuB,CAAC;AAAA,yDACD,QAAQ,EAAE,6BAA6B,CAAC,CAAC,KAAK,QAAQ,KAAK,CAAC;AAAA,gCACrF,EAAE,sBAAsB,CAAC;AAAA;AAAA,yDAEA,EAAE,4BAA4B,CAAC;AAAA,uDACjC,EAAE,mBAAmB,CAAC;AAAA;AAAA,gDAE7B,aAAa,8CAA8C,EAAE,mBAAmB,CAAC,SAAS;AAAA,QAClI,UAAU;AAAA;AAAA,uDAEqC,EAAE,oBAAoB,CAAC;AAAA,sDACxB,EAAE,yBAAyB,CAAC;AAAA,sDAC5B,EAAE,kBAAkB,CAAC;AAAA;AAAA;AAG3E;;;AChDO,IAAM,kBAAN,cAA8B,YAAY;AAAA,EACvC;AAAA,EACA,QAA4C;AAAA,EAC5C,qBAAqC;AAAA,EAC7C,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,OAAiB,CAAC;AAAA,EAClB,WAAW;AAAA,EACX,qBAAyC;AAAA,EACzC,cAAkC;AAAA,EAElC,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AAAE,SAAK,OAAO;AAAA,EAAG;AAAA,EAE3C,IAAI,OAA2C;AAAE,WAAO,KAAK;AAAA,EAAO;AAAA,EAEpE,UAAgB;AAAE,SAAK,QAAQ;AAAQ,SAAK,OAAO;AAAA,EAAG;AAAA,EAEtD,cAAoB;AAAE,SAAK,SAAS,YAAY,EAAE,aAAa,KAAK,YAAY,KAAK,GAAG,OAAO,KAAK,OAAO,MAAM,CAAC,GAAG,KAAK,IAAI,GAAG,UAAU,KAAK,SAAS,KAAK,EAAE,CAAC;AAAA,EAAG;AAAA,EAEpK,uBAA6B;AAAE,SAAK,SAAS,iBAAiB,EAAE,aAAa,KAAK,YAAY,KAAK,GAAG,OAAO,KAAK,OAAO,MAAM,CAAC,GAAG,KAAK,IAAI,GAAG,UAAU,KAAK,SAAS,KAAK,EAAE,CAAC;AAAA,EAAG;AAAA,EAElL,SAAe;AACb,SAAK,qBAAqB,KAAK,UAAU,oBAAoB,QAAS,KAAK;AAC3E,SAAK,QAAQ;AACb,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,iBAAuB;AAAE,SAAK,SAAS,YAAY,EAAE,aAAa,MAAM,OAAO,IAAI,MAAM,CAAC,GAAG,UAAU,GAAG,CAAC;AAAA,EAAG;AAAA,EAE9G,kBAAwB;AAAE,SAAK,QAAQ,KAAK;AAAoB,SAAK,OAAO;AAAA,EAAG;AAAA,EAE/E,mBAAyB;AAAE,SAAK,QAAQ;AAAO,SAAK,cAAc;AAAI,SAAK,QAAQ;AAAI,SAAK,OAAO,CAAC;AAAG,SAAK,WAAW;AAAI,SAAK,OAAO;AAAA,EAAG;AAAA,EAE1I,OAAO,KAAmB;AACxB,UAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,SAAS,EAAE;AACxC,QAAI,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC,GAAG;AAC/B,WAAK,OAAO,CAAC,GAAG,KAAK,MAAM,CAAC;AAC5B,WAAK,OAAO;AAAA,IACd;AAAA,EACF;AAAA,EAEA,UAAU,KAAmB;AAC3B,SAAK,OAAO,KAAK,KAAK,OAAO,CAAC,MAAM,MAAM,GAAG;AAC7C,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,EAAE,KAAqB;AAAE,WAAO,KAAK,YAAY,UAAU,GAAG;AAAA,EAAG;AAAA,EAEzE,IAAI,kBAA2B;AAC7B,QAAI,CAAC,KAAK,SAAS,KAAK,KAAK,CAAC,KAAK,mBAAmB,QAAS,QAAO;AACtE,WAAO,CAAC,gBAAgB,KAAK,UAAU,KAAK,mBAAmB,QAAQ;AAAA,EACzE;AAAA,EAEQ,SAAS,MAAc,QAA+F;AAC5H,SAAK,cAAc,IAAI,YAAY,MAAM,EAAE,QAAQ,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EACrF;AAAA,EAEQ,SAAe;AACrB,QAAI,KAAK,UAAU,mBAAmB;AACpC,WAAK,OAAO,YAAY,UAAU,gBAAgB,WAAW,6BAA6B,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AAC5G,WAAK,OAAO,eAAe,qBAAqB,GAAG,iBAAiB,SAAS,MAAM,KAAK,eAAe,CAAC;AACxG,WAAK,OAAO,eAAe,kBAAkB,GAAG,iBAAiB,SAAS,MAAM,KAAK,gBAAgB,CAAC;AACtG;AAAA,IACF;AACA,QAAI,KAAK,UAAU,OAAO;AACxB,WAAK,OAAO,YAAY,UAAU,gBAAgB,WAAW,kBAAkB,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AACjG,WAAK,OAAO,eAAe,SAAS,GAAG,iBAAiB,SAAS,MAAM,KAAK,QAAQ,CAAC;AACrF,WAAK,OAAO,eAAe,QAAQ,GAAG,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AAAA,IACrF,OAAO;AACL,WAAK,OAAO,YAAY,UAAU,gBAAgB,WAAW,mBAAmB,KAAK,aAAa,KAAK,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,mBAAmB,SAAS,KAAK,iBAAiB,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AAEjN,YAAM,YAAc,KAAK,OAAO,eAAe,YAAY;AAC3D,YAAM,aAAc,KAAK,OAAO,eAAe,aAAa;AAC5D,YAAM,WAAc,KAAK,OAAO,eAAe,WAAW;AAC1D,YAAM,cAAc,KAAK,OAAO,eAAe,cAAc;AAE7D,gBAAU,iBAAiB,SAAS,MAAM;AAAE,aAAK,cAAc,UAAU;AAAA,MAAO,CAAC;AACjF,iBAAW,iBAAiB,SAAS,MAAM;AAAE,aAAK,QAAQ,WAAW;AAAA,MAAO,CAAC;AAC7E,mBAAa,iBAAiB,SAAS,MAAM;AAAE,aAAK,WAAW,YAAY;AAAO,aAAK,OAAO;AAAA,MAAG,CAAC;AAElG,YAAM,YAAY,MAAM;AACtB,aAAK,OAAO,SAAS,KAAK;AAC1B,iBAAS,QAAQ;AAAA,MACnB;AACA,WAAK,OAAO,eAAe,aAAa,GAAG,iBAAiB,SAAS,SAAS;AAC9E,eAAS,iBAAiB,WAAW,CAAC,MAAqB;AACzD,YAAI,EAAE,QAAQ,WAAW,EAAE,QAAQ,KAAK;AAAE,YAAE,eAAe;AAAG,oBAAU;AAAA,QAAG;AAAA,MAC7E,CAAC;AAED,WAAK,OAAO,iBAAoC,WAAW,EAAE,QAAQ,CAAC,QAAQ;AAC5E,YAAI,iBAAiB,SAAS,MAAM,KAAK,UAAU,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;AAAA,MAC9E,CAAC;AAED,WAAK,OAAO,eAAe,aAAa,GAAG,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AAC7F,WAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,MAAM,KAAK,qBAAqB,CAAC;AACrG,WAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,MAAM,KAAK,OAAO,CAAC;AACvF,iBAAW,MAAM,UAAU,MAAM,GAAG,EAAE;AAAA,IACxC;AAAA,EACF;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,mBAAmB,GAAG;AAC5C,iBAAe,OAAO,qBAAqB,eAAe;AAC5D;;;AC/GA;;;ACJO,IAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAlC;;;ACAA;AAEA,IAAM,WAAW,oBAAI,IAAI;AAAA,EACvB;AAAA,EAAY;AAAA,EAAM;AAAA,EAAO;AAAA,EAAO;AAAA,EAAa;AAAA,EAC7C;AAAA,EAAc;AAAA,EAAa;AAAA,EAAU;AAAA,EAAS;AAAA,EAC9C;AAAA,EAAS;AAAA,EAAO;AAAA,EAAO;AAAA,EAAY;AAAA,EAAU;AAAA,EAAM;AAAA,EACnD;AAAA,EAAU;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAQ;AAAA,EACnD;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAM;AAAA,EAAM;AAAA,EAAU;AAC3D,CAAC;AAED,IAAM,WAAW,oBAAI,IAAI,CAAC,MAAM,UAAU,UAAU,WAAW,MAAM,CAAC;AAE/D,SAAS,gBAAgB,MAAsB;AACpD,SAAO,KAAK,MAAM,IAAI,EAAE,IAAI,aAAa,EAAE,KAAK,IAAI;AACtD;AAEA,SAAS,cAAc,MAAsB;AAC3C,MAAI,SAAS;AACb,MAAI,IAAI;AACR,QAAM,MAAM,KAAK;AAEjB,SAAO,IAAI,KAAK;AAEd,QAAI,KAAK,CAAC,MAAM,OAAO,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,KAAK;AACzD,gBAAU,wBAAwB,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC;AACxD,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,KAAK,CAAC;AAChB,QAAI,MAAM,OAAO,MAAM,OAAO,MAAM,KAAK;AACvC,UAAI,IAAI,IAAI;AACZ,aAAO,IAAI,KAAK;AACd,YAAI,KAAK,CAAC,MAAM,MAAM;AAAE,eAAK;AAAG;AAAA,QAAU;AAC1C,YAAI,KAAK,CAAC,MAAM,GAAG;AAAE;AAAK;AAAA,QAAO;AACjC;AAAA,MACF;AACA,gBAAU,wBAAwB,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,UAAI;AACJ;AAAA,IACF;AAEA,QAAI,QAAQ,KAAK,KAAK,CAAC,CAAC,MAAM,MAAM,KAAK,CAAC,aAAa,KAAK,KAAK,IAAI,CAAC,CAAC,IAAI;AACzE,UAAI,IAAI;AACR,aAAO,IAAI,OAAO,SAAS,KAAK,KAAK,CAAC,CAAC,EAAG;AAC1C,gBAAU,wBAAwB,QAAQ,KAAK,MAAM,GAAG,CAAC,CAAC,CAAC;AAC3D,UAAI;AACJ;AAAA,IACF;AAEA,QAAI,aAAa,KAAK,KAAK,CAAC,CAAC,GAAG;AAC9B,UAAI,IAAI;AACR,aAAO,IAAI,OAAO,gBAAgB,KAAK,KAAK,CAAC,CAAC,EAAG;AACjD,YAAM,OAAO,KAAK,MAAM,GAAG,CAAC;AAC5B,UAAI,SAAS,IAAI,IAAI,GAAG;AACtB,kBAAU,uBAAuB,QAAQ,IAAI,CAAC;AAAA,MAChD,WAAW,SAAS,IAAI,IAAI,GAAG;AAC7B,kBAAU,uBAAuB,QAAQ,IAAI,CAAC;AAAA,MAChD,OAAO;AACL,kBAAU,QAAQ,IAAI;AAAA,MACxB;AACA,UAAI;AACJ;AAAA,IACF;AACA,cAAU,QAAQ,KAAK,CAAC,CAAC;AACzB;AAAA,EACF;AACA,SAAO;AACT;;;ADjEA;AAoBA,SAAS,cAAc,MAAuB,GAAW,OAAwB,GAAoC;AACnH,QAAM,EAAE,YAAY,aAAa,eAAe,oBAAoB,QAAQ,mBAAmB,IAAI;AACnG,QAAM,WAAW,kBAAkB;AACnC,QAAM,OAAO,IAAI,KAAK,KAAK,SAAS,EAAE,eAAe,QAAQ,EAAE,KAAK,WAAW,OAAO,WAAW,MAAM,WAAW,QAAQ,UAAU,CAAC;AACrI,QAAM,OAAO,mBAAmB,KAAK,EAAE,KAAK,KAAK,gBAAgB,CAAC;AAClE,QAAM,YAAY,KAAK,QAAQ,CAAC,GAAG,SAC/B,4BAA4B,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,0BAA0B,QAAQ,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,YACnH;AACJ,QAAM,WAAW,aACb,0BAA0B,YAAY,IAAI,KAAK,EAAE,IAAI,YAAY,EAAE,iBAAiB,KAAK,EAAE,SAC3F;AACJ,QAAM,WAAW,KAAK,gBAAgB,CAAC,GAAG,SAAS;AACnD,QAAM,WAAY,KAAiD;AACnE,QAAM,gBAAgB,WAAW,mBAAmB,QAAQ,IAAI,OAAO;AACvE,QAAM,cAAc,GAAG,aAAa,OAAO,mBAAmB,KAAK,IAAI,CAAC;AAAA,GAAgB,KAAK,YAAY,CAAC,GAAG,IAAI,OAAK,eAAe,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA;AACzJ,QAAM,eAAe,KAAK,SAAS;AAAA;AAAA,EAAiE,KAAK,IAAI,OAAK,eAAe,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,OAAU;AAC/J,QAAM,YAAa,YAAY,KAAK,QAChC,yBAAyB,QAAQ,KAAK,KAAK,CAAC,SAC5C;AACJ,QAAM,YAAY,WAAW,eAAe,UAAU,kBAAkB,IAAI;AAC5E,QAAM,aAAa,WACf,YACE,gCAAgC,QAAQ,SAAS,CAAC,sDAAsD,EAAE,+BAA+B,CAAC,KAAK,QAAQ,QAAQ,CAAC,SAChK,8BAA8B,QAAQ,QAAQ,CAAC,YACjD;AAEJ,QAAM,OAAO,WAAW;AAAA;AAAA,QAElB,SAAS;AAAA,kCACiB,gBAAgB,WAAW,CAAC;AAAA,QACtD,eAAe,8CAA8C,gBAAgB,YAAY,CAAC,WAAW,EAAE;AAAA,cACjG;AAEZ,SAAO;AAAA,qBACY,YAAY,IAAI,KAAK,EAAE,IAAI,kBAAkB,EAAE;AAAA,+DACL,CAAC;AAAA,UACtD,QAAQ;AAAA,kCACgB,QAAQ,KAAK,IAAI,CAAC;AAAA,UAC1C,QAAQ;AAAA,UACR,UAAU;AAAA,kCACc,IAAI;AAAA,qEAC+B,CAAC,YAAY,EAAE,2BAA2B,CAAC,KAAK,EAAE,2BAA2B,CAAC;AAAA,UACzI,UAAU,8DAA8D,CAAC,YAAY,EAAE,2BAA2B,CAAC,KAAK,EAAE,2BAA2B,CAAC,cAAc,EAAE;AAAA,yEACvG,KAAK,EAAE,YAAY,EAAE,0BAA0B,CAAC;AAAA;AAAA,QAEjH,IAAI;AAAA;AAEZ;AAEO,SAAS,iBAAiB,OAAwB,GAAoC;AAC3F,QAAM,EAAE,MAAM,SAAS,iBAAiB,WAAW,YAAY,cAAc,cAAc,IAAI;AAE/F,QAAM,gBAAgB,KAAK,SACvB;AAAA,UACI,KAAK,IAAI,CAAC,QAAQ,0BAA0B,cAAc,MAAM,YAAY,EAAE,sBAAsB,QAAQ,GAAG,CAAC,KAAK,QAAQ,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC;AAAA,iBAE1J,gEAAgE,EAAE,qBAAqB,CAAC;AAE5F,QAAM,kBAAkB,cAAc,gBAAgB,SAAS,IAC3D;AAAA,uCACiC,gBAAgB,MAAM,IAAI,gBAAgB,WAAW,IAAI,EAAE,6BAA6B,IAAI,EAAE,+BAA+B,CAAC;AAAA,6DACxG,EAAE,kCAAkC,CAAC,YAAY,QAAQ,YAAY,CAAC;AAAA,iEAClE,EAAE,2BAA2B,CAAC;AAAA,gBAEzF;AAEJ,MAAI;AACJ,MAAI,eAAe;AACjB,UAAM,SAAS,oBAAI,IAA+B;AAClD,eAAW,QAAQ,SAAS;AAC1B,YAAM,MAAO,KAAiD,UAAU,KAAK,KAAK;AAClF,YAAM,QAAQ,OAAO,IAAI,GAAG,KAAK,CAAC;AAClC,YAAM,KAAK,IAAI;AACf,aAAO,IAAI,KAAK,KAAK;AAAA,IACvB;AACA,UAAM,aAAa,CAAC,GAAG,OAAO,KAAK,CAAC,EAAE;AAAA,MAAK,CAAC,GAAG,MAC7C,MAAM,KAAK,IAAI,MAAM,KAAK,KAAK,EAAE,cAAc,CAAC;AAAA,IAClD;AACA,WAAO,WAAW,IAAI,CAAC,QAAQ;AAC7B,YAAM,QAAQ,OAAO,IAAI,GAAG;AAC5B,YAAM,SAAS,oCAAoC,MAAM,QAAQ,GAAG,IAAI,EAAE,uBAAuB,CAAC;AAClG,YAAM,YAAY,MAAM,IAAI,CAAC,SAAS;AACpC,cAAM,IAAI,QAAQ,QAAQ,IAAI;AAC9B,eAAO,cAAc,MAAM,GAAG,OAAO,CAAC;AAAA,MACxC,CAAC,EAAE,KAAK,EAAE;AACV,aAAO,6BAA6B,MAAM,GAAG,SAAS;AAAA,IACxD,CAAC,EAAE,KAAK,EAAE;AAAA,EACZ,OAAO;AACL,WAAO,QAAQ,IAAI,CAAC,MAAM,MAAM,cAAc,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE;AAAA,EAC3E;AAEA,SAAO;AAAA;AAAA,QAED,aAAa;AAAA,iCACY,gBAAgB,YAAY,EAAE;AAAA,UACrD,gBAAgB,EAAE,4BAA4B,IAAI,EAAE,6BAA6B,CAAC;AAAA;AAAA,iCAE3D,aAAa,YAAY,EAAE;AAAA,UAClD,aAAa,EAAE,2BAA2B,IAAI,EAAE,0BAA0B,CAAC;AAAA;AAAA;AAAA,MAG/E,eAAe;AAAA;AAAA,QAEb,QAAQ,SAAS,OAAO,sBAAsB,EAAE,sBAAsB,CAAC,QAAQ;AAAA;AAEvF;;;AFtHO,IAAM,oBAAN,cAAgC,YAAY;AAAA,EACzC;AAAA,EACR;AAAA,EACA,cAAkC;AAAA,EAClC,QAA2B,CAAC;AAAA,EAC5B,gBAA+B;AAAA,EAC/B,qBAA+C,CAAC;AAAA,EAChD,YAA2B;AAAA,EAC3B,aAAa;AAAA,EACb,cAA2B,oBAAI,IAAI;AAAA,EACnC,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,qBAAyC,EAAE,GAAG,6BAA6B;AAAA,EAE3E,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AACxB,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,YAA2B;AAC/B,SAAK,QAAQ,MAAM,KAAK,YAAY,YAAY;AAChD,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,WAAW,IAA2B;AAC1C,UAAM,KAAK,YAAY,WAAW,EAAE;AACpC,SAAK,YAAY,OAAO,EAAE;AAC1B,UAAM,KAAK,UAAU;AAAA,EACvB;AAAA,EAEA,aAAa,OAAqB;AAChC,SAAK,gBAAgB,KAAK,kBAAkB,QAAQ,OAAO;AAC3D,QAAI,KAAK,kBAAkB,MAAM;AAC/B,YAAM,OAAO,KAAK,MAAM,KAAK,aAAa;AAC1C,UAAI,MAAM,MAAM,CAAC,KAAK,mBAAmB,KAAK,EAAE,GAAG;AACjD,aAAK,mBAAmB,KAAK,EAAE,IAAI,MAAM,QAAQ,KAAK,YAAY,IAAI,KAAK,eAAe,CAAC;AAAA,MAC7F;AAAA,IACF;AACA,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,gBAAgB,QAAyB;AACvC,WAAO,MAAM,QAAQ,KAAK,mBAAmB,MAAM,CAAC,KAAK,KAAK,mBAAmB,MAAM,EAAE,SAAS;AAAA,EACpG;AAAA,EAEA,sBAA4B;AAC1B,SAAK,gBAAgB,CAAC,KAAK;AAC3B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,mBAAyB;AACvB,SAAK,aAAa,CAAC,KAAK;AACxB,QAAI,CAAC,KAAK,WAAY,MAAK,YAAY,MAAM;AAC7C,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,iBAAiB,IAAkB;AACjC,QAAI,KAAK,YAAY,IAAI,EAAE,EAAG,MAAK,YAAY,OAAO,EAAE;AAAA,QACnD,MAAK,YAAY,IAAI,EAAE;AAC5B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,mBAAyB;AACvB,UAAM,WAAW,KAAK,MAAM,OAAO,CAAC,MAAM,KAAK,YAAY,IAAI,EAAE,EAAE,CAAC;AACpE,QAAI,CAAC,SAAS,OAAQ;AAEtB,UAAM,OAAO,KAAK,aAAa,KAAK,KAAK,KAAK,EAAE,8BAA8B;AAE9E,UAAM,kBAAkB,CAAC,GAAG,IAAI;AAAA,MAC9B,SAAS,QAAQ,CAAC,MAAM,KAAK,mBAAmB,EAAE,EAAE,KAAK,EAAE,gBAAgB,CAAC,CAAC;AAAA,IAC/E,CAAC;AAED,UAAM,aAAa,gBAAgB,SAC/B;AAAA;AAAA,MAAyE,gBAAgB,KAAK,QAAQ,CAAC;AAAA;AAAA;AAAA,IACvG;AAEJ,UAAM,WAAW,SACd,IAAI,CAAC,MAAM;AACV,YAAM,QAAQ,EAAE,YAAY,CAAC,GAAG,IAAI,CAAC,MAAM,OAAO,CAAC,EAAE,EAAE,KAAK,IAAI;AAChE,aAAO,SAAS,mBAAmB,EAAE,QAAQ,EAAE,CAAC;AAAA,EAAe,IAAI;AAAA;AAAA,IACrE,CAAC,EACA,KAAK,MAAM;AAEd,UAAM,QAAQ,aAAa,mBAAmB,IAAI,CAAC;AAAA,EAAe,UAAU,GAAG,QAAQ;AAAA;AACvF,cAAU,WAAW,UAAU,KAAK;AAAA,EACtC;AAAA,EAEA,gBAAgB,MAAoB;AAClC,cAAU,WAAW,UAAU,IAAI;AAAA,EACrC;AAAA,EAEA,IAAI,UAAoB;AACtB,UAAM,SAAS,oBAAI,IAAY;AAC/B,SAAK,MAAM,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,QAAQ,OAAO,IAAI,GAAG,CAAC,CAAC;AAC1E,WAAO,CAAC,GAAG,MAAM,EAAE,KAAK;AAAA,EAC1B;AAAA,EAEA,IAAI,eAAkC;AACpC,UAAM,MAAM,KAAK;AACjB,QAAI,CAAC,IAAK,QAAO,KAAK;AACtB,WAAO,KAAK,MAAM,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,GAAG,SAAS,GAAG,CAAC;AAAA,EAC9D;AAAA,EAEQ,EAAE,KAAqB;AAAE,WAAO,KAAK,YAAY,UAAU,GAAG;AAAA,EAAG;AAAA,EAEjE,SAAe;AACrB,UAAM,OAAO,KAAK;AAClB,UAAM,UAAU,KAAK;AACrB,UAAM,kBAAkB,QAAQ,OAAO,CAAC,MAAM,KAAK,YAAY,IAAI,EAAE,EAAE,CAAC;AAExE,SAAK,OAAO,YAAY,UAAU,kBAAkB,WAAW,iBAAiB;AAAA,MAC9E;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW,KAAK;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,cAAc,KAAK;AAAA,MACnB,eAAe,KAAK;AAAA,MACpB,oBAAoB,KAAK;AAAA,MACzB,QAAQ,cAAc,KAAK,YAAY,QAAQ,CAAC;AAAA,MAChD,eAAe,KAAK;AAAA,MACpB,oBAAoB,KAAK;AAAA,IAC3B,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AAErB,SAAK,OAAO,eAAe,kBAAkB,GAAG,iBAAiB,SAAS,MAAM,KAAK,oBAAoB,CAAC;AAC1G,SAAK,OAAO,eAAe,iBAAiB,GAAG,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAEtG,SAAK,OAAO,iBAAiB,mBAAmB,EAAE,QAAQ,CAAC,OAAO;AAChE,SAAG,iBAAiB,SAAS,MAAM;AACjC,cAAM,MAAO,GAAmB,QAAQ,WAAW,KAAK;AACxD,YAAI,CAAC,IAAK;AACV,aAAK,YAAY,KAAK,cAAc,MAAM,OAAO;AACjD,aAAK,OAAO;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAED,UAAM,YAAY,KAAK,OAAO,eAAe,eAAe;AAC5D,QAAI,WAAW;AACb,gBAAU,iBAAiB,SAAS,MAAM;AAAE,aAAK,eAAe,UAAU;AAAA,MAAO,CAAC;AAAA,IACpF;AACA,SAAK,OAAO,eAAe,kBAAkB,GAAG,iBAAiB,SAAS,MAAM;AAC9E,WAAK,eAAe,WAAW,SAAS,KAAK;AAC7C,WAAK,iBAAiB;AAAA,IACxB,CAAC;AAED,SAAK,OAAO,iBAAiB,eAAe,EAAE,QAAQ,CAAC,OAAO;AAC5D,SAAG,iBAAiB,SAAS,CAAC,OAAO;AACnC,WAAG,gBAAgB;AACnB,aAAK,iBAAiB,OAAQ,GAAmB,QAAQ,QAAQ,CAAC,CAAC;AAAA,MACrE,CAAC;AAAA,IACH,CAAC;AAED,SAAK,OAAO,iBAAiB,wBAAwB,EAAE,QAAQ,CAAC,OAAO;AACrE,SAAG,iBAAiB,SAAS,MAAM;AACjC,YAAI,KAAK,YAAY;AACnB,gBAAM,MAAM,QAAQ,OAAQ,GAAmB,QAAQ,KAAK,CAAC,CAAC;AAC9D,cAAI,IAAK,MAAK,iBAAiB,IAAI,EAAE;AAAA,QACvC,OAAO;AACL,eAAK,aAAa,OAAQ,GAAmB,QAAQ,KAAK,CAAC,CAAC;AAAA,QAC9D;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AACD,SAAK,OAAO,iBAAiB,wBAAwB,EAAE,QAAQ,CAAC,OAAO;AACrE,SAAG,iBAAiB,SAAS,CAAC,OAAO;AACnC,WAAG,gBAAgB;AACnB,aAAK,WAAW,OAAQ,GAAmB,QAAQ,IAAI,CAAC,CAAC;AAAA,MAC3D,CAAC;AAAA,IACH,CAAC;AACD,SAAK,OAAO,iBAAiB,2BAA2B,EAAE,QAAQ,CAAC,OAAO;AACxE,SAAG,iBAAiB,SAAS,CAAC,OAAO;AACnC,WAAG,gBAAgB;AACnB,cAAM,MAAM,OAAQ,GAAmB,QAAQ,KAAK,CAAC;AACrD,aAAK,iBAAiB,QAAQ,GAAG,GAAG,YAAY,CAAC,GAAG,KAAK,IAAI,CAAC;AAAA,MAChE,CAAC;AAAA,IACH,CAAC;AACD,SAAK,OAAO,iBAAiB,2BAA2B,EAAE,QAAQ,CAAC,OAAO;AACxE,SAAG,iBAAiB,SAAS,CAAC,OAAO;AACnC,WAAG,gBAAgB;AACnB,cAAM,MAAM,OAAQ,GAAmB,QAAQ,KAAK,CAAC;AACrD,cAAM,IAAI,QAAQ,GAAG;AACrB,aAAK,iBAAiB,KAAK,mBAAmB,GAAG,EAAE,KAAK,GAAG,gBAAgB,CAAC,GAAG,KAAK,IAAI,CAAC;AAAA,MAC3F,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,qBAAqB,GAAG;AAC9C,iBAAe,OAAO,uBAAuB,iBAAiB;AAChE;;;AIhLO,IAAM,gCAAgC;AAGtC,IAAM,wBAAwB;AAG9B,IAAM,6BAA6B;;;ACjC1C,IAAM,eACJ;AAEK,SAAS,yBAAyB,aAA+B;AACtE,QAAM,QAAkB,CAAC;AACzB,MAAI;AACJ,QAAM,KAAK,IAAI,OAAO,aAAa,QAAQ,aAAa,KAAK;AAC7D,UAAQ,QAAQ,GAAG,KAAK,WAAW,OAAO,MAAM;AAC9C,UAAM,OAAO,MAAM,CAAC,KAAK,MAAM,CAAC;AAChC,QAAI,KAAM,OAAM,KAAK,IAAI;AAAA,EAC3B;AACA,SAAO;AACT;AAEO,SAAS,qBAA6B;AAC3C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;AAEO,SAAS,qBAAqB,cAAsB,mBAAmC;AAC5F,QAAM,YAAY,aAAa,QAAQ,OAAO,GAAG,EAAE,MAAM,GAAG;AAC5D,QAAM,UAAY,kBAAkB,QAAQ,OAAO,GAAG,EAAE,MAAM,GAAG;AAEjE,YAAU,IAAI;AAGd,MAAI,SAAS;AACb,SAAO,SAAS,UAAU,UAAU,SAAS,QAAQ,SAAS,KAAK,UAAU,MAAM,MAAM,QAAQ,MAAM,GAAG;AACxG;AAAA,EACF;AAEA,QAAM,MAAQ,UAAU,SAAS;AACjC,QAAM,QAAQ,QAAQ,MAAM,MAAM;AAElC,QAAM,cAAc,MAAM,MAAM,SAAS,CAAC,EAAE,QAAQ,SAAS,EAAE;AAC/D,QAAM,SAAS,QAAQ,IAAI,MAAM,MAAM,GAAG,EAAE,KAAK,IAAI,EAAE,KAAK,GAAG;AAC/D,QAAM,SAAS,MAAM,MAAM,GAAG,EAAE;AAEhC,SAAO,CAAC,QAAQ,GAAG,QAAQ,WAAW,EAAE,KAAK,GAAG;AAClD;AAEO,SAAS,eAAe,SAAiB,SAA4B;AAC1E,SAAO,QAAQ,KAAK,QAAM,IAAI,OAAO,MAAM,EAAE,SAAS,EAAE,KAAK,OAAO,CAAC;AACvE;AAEO,SAAS,8BACd,SACA,YACA,aACA,iBACQ;AACR,MAAI,SAAS;AAEb,MAAI,cAAc,CAAC,QAAQ,SAAS,UAAU,GAAG;AAC/C,aAAS,GAAG,UAAU;AAAA;AAAA,EAAO,MAAM;AAAA,EACrC;AAEA,QAAM,SAAS,CAAC,aAAa,eAAe,EAAE,OAAO,OAAO,EAAE,KAAK,EAAE;AACrE,MAAI,QAAQ;AACV,UAAM,gBAAgB,OAAO,MAAM,sBAAsB;AACzD,QAAI,eAAe;AACjB,YAAM,aAAa,cAAc,SAAS,KAAK,cAAc,CAAC,EAAE;AAChE,eAAS,OAAO,MAAM,GAAG,SAAS,IAAI,OAAO,SAAS,OAAO,MAAM,SAAS;AAAA,IAC9E;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,iBACd,YACA,UACA,cACsE;AACtE,MAAI,CAAC,YAAY,CAAC,cAAc;AAC9B,WAAO,EAAE,YAAY,IAAI,aAAa,IAAI,iBAAiB,GAAG;AAAA,EAChE;AAEA,QAAM,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,UAAU,YAAY,EAAE,OAAO,OAAO,CAAC,CAAC;AACjE,QAAM,aAAa,YAAY,IAAI,KAAK,IAAI,CAAC,YAAY,UAAU;AAEnE,QAAM,cAAkB,WAAe,oBAAoB,QAAQ;AAAA,IAAc;AACjF,QAAM,kBAAkB,eAAe,wBAAwB,YAAY;AAAA,IAAc;AAEzF,SAAO,EAAE,YAAY,aAAa,gBAAgB;AACpD;;;AClGO,IAAM,uBAAuB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACApC;AAMO,IAAM,QAAQ;AAAA,EACnB,EAAE,OAAO,MAAM,OAAO,aAAU;AAAA,EAChC,EAAE,OAAO,MAAM,OAAO,UAAU;AAAA,EAChC,EAAE,OAAO,MAAM,OAAO,cAAW;AAAA,EACjC,EAAE,OAAO,MAAM,OAAO,WAAW;AAAA,EACjC,EAAE,OAAO,MAAM,OAAO,UAAU;AAClC;AA4BO,SAAS,oBAAoB,OAA2B,GAAoC;AACjG,QAAM,EAAE,aAAa,YAAY,aAAa,mBAAmB,mBAAmB,IAAI;AACxF,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,QAAQ,qBAAqB,aAAa,YAAY;AAAA,IAC1D,KAAK;AAAA,IACL,MAAM;AAAA,EACR,CAAC,EAAE;AAEH,QAAM,UAAU,CAAC,MAAkB,QACjC,8BAA8B,eAAe,OAAO,WAAW,EAAE,uBAAuB,IAAI,KAAK,EAAE,GAAG,CAAC;AAEzG,MAAI;AACJ,MAAI,YAAY,WAAW,GAAG;AAC5B,WAAO,6BAA6B,EAAE,qBAAqB,CAAC;AAAA,EAC9D,WAAW,eAAe,OAAO;AAC/B,WAAO,gCAAgC,EAAE,wBAAwB,CAAC;AAAA,EACpE,WAAW,eAAe,UAAU;AAClC,WAAO,4BAA4B,YAAY,IAAI,CAAC,SAAS;AAAA;AAAA,qDAEZ,KAAK,EAAE,KAAK,kBAAkB,IAAI,KAAK,EAAE,IAAI,YAAY,EAAE;AAAA,0CACtE,QAAQ,KAAK,IAAI,CAAC;AAAA,aAC/C,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,gCAAgC,QAAQ,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC;AAAA,iBACzF,EAAE,KAAK,EAAE,CAAC;AAAA,EACzB,OAAO;AACL,UAAM,UAAU,CAAC,GAAG,IAAI,IAAI,YAAY,QAAQ,CAAC,SAAS,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK;AAClF,QAAI,CAAC,QAAQ,QAAQ;AACnB,aAAO,6BAA6B,EAAE,uBAAuB,CAAC;AAAA,IAChE,OAAO;AACL,YAAM,QAAQ,4BAA4B,QAAQ,IAAI,CAAC,QACrD,6BAA6B,mBAAmB,IAAI,GAAG,IAAI,WAAW,EAAE,sBAAsB,QAAQ,GAAG,CAAC,KAAK,QAAQ,GAAG,CAAC,WAAW,EAAE,KAAK,EAAE,CAAC;AAGlJ,YAAM,UAAU,qBAAqB,aAAa,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACtF,YAAM,UAAU,mBAAmB,SAAS,IACxC,gCAAgC,EAAE,yBAAyB,CAAC,WAC5D,oCAAoC,EAAE,4BAA4B,CAAC;AAAA,sCACvC,QAAQ,IAAI,CAAC,SAAS;AAAA;AAAA,+CAEb,QAAQ,KAAK,IAAI,CAAC;AAAA,kBAC/C,KAAK,QAAQ,CAAC,GAAG,IAAI,CAAC,QAAQ,gCAAgC,QAAQ,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC;AAAA,oBAC3F,EAAE,KAAK,EAAE,CAAC;AACxB,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAEA,SAAO;AAAA;AAAA;AAAA,iCAGwB,EAAE,4BAA4B,CAAC;AAAA,UACtD,YAAY,SAAS;AAAA,YACnB,QAAQ,OAAO,wBAAwB,CAAC;AAAA,YACxC,QAAQ,UAAU,2BAA2B,CAAC;AAAA,YAC9C,QAAQ,QAAQ,yBAAyB,CAAC;AAAA,kBACpC,EAAE;AAAA,mCACe,IAAI;AAAA;AAAA,uCAEA,EAAE,qBAAqB,CAAC,OAAO,KAAK;AAAA;AAAA,yEAEF,UAAU,IAAI,aAAa,EAAE,IAAI,EAAE,uBAAuB,CAAC;AAAA,6CACvF,EAAE,sBAAsB,CAAC;AAAA;AAAA;AAAA;AAAA;AAKtE;AAEO,SAAS,oBAAoB,OAA2B,GAAoC;AACjG,QAAM,EAAE,kBAAkB,oBAAoB,aAAa,kBAAkB,mBAAmB,mBAAmB,sBAAsB,aAAa,kBAAkB,mBAAmB,IAAI;AAE/L,QAAM,cAAc,MAAM;AAAA,IACxB,CAAC,MAAM,kBAAkB,EAAE,KAAK,KAAK,qBAAqB,EAAE,QAAQ,aAAa,EAAE,IAAI,EAAE,KAAK;AAAA,EAChG,EAAE,KAAK,EAAE;AAET,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKsB,EAAE,qBAAqB,CAAC;AAAA;AAAA,sCAEjB,EAAE,mBAAmB,CAAC;AAAA,qCACvB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAMjB,EAAE,qBAAqB,CAAC;AAAA;AAAA,oDAEH,qBAAqB,YAAY,EAAE;AAAA;AAAA,uCAEhD,EAAE,mBAAmB,CAAC;AAAA,qCACxB,EAAE,iBAAiB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAO1B,EAAE,wBAAwB,CAAC;AAAA;AAAA,uDAEH,cAAc,YAAY,EAAE;AAAA;AAAA,uCAE5C,EAAE,sBAAsB,CAAC;AAAA,qCAC3B,EAAE,oBAAoB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAO7B,EAAE,+BAA+B,CAAC;AAAA;AAAA,8DAEH,uBAAuB,YAAY,EAAE;AAAA;AAAA,uCAE5D,EAAE,6BAA6B,CAAC;AAAA,qCAClC,EAAE,2BAA2B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAOpC,EAAE,6BAA6B,CAAC;AAAA;AAAA,4DAEH,cAAc,YAAY,EAAE;AAAA;AAAA,uCAEjD,EAAE,2BAA2B,CAAC;AAAA,qCAChC,EAAE,yBAAyB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAOlC,EAAE,gCAAgC,CAAC;AAAA,4DACN,EAAE,6BAA6B,CAAC;AAAA;AAAA,4CAEhD,EAAE,kCAAkC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAMlD,EAAE,2BAA2B,CAAC;AAAA;AAAA,sCAEvB,EAAE,yBAAyB,CAAC;AAAA,+EACa,gBAAgB;AAAA;AAAA;AAAA,wDAGvC,EAAE,wBAAwB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKpD,EAAE,yBAAyB,CAAC;AAAA;AAAA,sCAErB,EAAE,uBAAuB,CAAC;AAAA;AAAA,0CAEtB,qBAAqB,YAAgB,aAAa,EAAE,IAAI,EAAE,4BAA4B,CAAC;AAAA,0CACvF,qBAAqB,gBAAgB,aAAa,EAAE,IAAI,EAAE,4BAA4B,CAAC;AAAA,0CACvF,qBAAqB,eAAgB,aAAa,EAAE,IAAI,EAAE,0BAA0B,CAAC;AAAA,0CACrF,qBAAqB,OAAgB,aAAa,EAAE,IAAI,EAAE,wBAAwB,CAAC;AAAA;AAAA;AAAA,wDAGrE,EAAE,sBAAsB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKlD,EAAE,uBAAuB,CAAC;AAAA;AAAA,uEAEc,EAAE,4BAA4B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,oCAKlE,oBAAoB,OAAO,KAAK;AAAA,gBACpD,qBAAqB,oBACnB,SAAS,EAAE,yBAAyB,CAAC,kDAA2C,QAAQ,iBAAiB,CAAC,YAC1G,SAAS,EAAE,uBAAuB,CAAC,SAAS;AAAA;AAAA;AAAA;AAAA,kBAI5C,oBAAoB,EAAE,0BAA0B,IAAI,EAAE,0BAA0B,CAAC;AAAA;AAAA,gBAEnF,oBACE,8CAA8C,EAAE,0BAA0B,CAAC,cAC3E,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+BAQW,EAAE,8BAA8B,CAAC;AAAA;AAAA,6DAEH,mBAAmB,UAAU,YAAY,EAAE;AAAA;AAAA,uCAEjE,EAAE,4BAA4B,CAAC;AAAA,qCACjC,EAAE,0BAA0B,CAAC;AAAA;AAAA;AAAA,UAGxD,mBAAmB,UAAU;AAAA;AAAA,sCAED,EAAE,+BAA+B,CAAC;AAAA;AAAA,cAE1D,OAAO,OAAO,qBAAqB,EAAE;AAAA,IAAI,CAAC,MAC1C,kBAAkB,EAAE,EAAE,KAAK,mBAAmB,aAAa,EAAE,KAAK,aAAa,EAAE,IAAI,QAAQ,EAAE,KAAK,CAAC;AAAA,EACvG,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,sCAIgB,EAAE,+BAA+B,CAAC;AAAA;AAAA,gCAExC,QAAQ,EAAE,kCAAkC,CAAC,CAAC;AAAA,0BACpD,QAAQ,mBAAmB,OAAO,CAAC;AAAA;AAAA,kBAE3C,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA,+BAKW,EAAE,4BAA4B,CAAC;AAAA,UACpD,MAAM,mBACJ,0DAA0D,QAAQ,MAAM,iBAAiB,QAAQ,CAAC,SAClG,0DAA0D,EAAE,mCAAmC,CAAC,MAAM;AAAA,2DACvD,EAAE,+BAA+B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,+BAK9D,EAAE,qBAAqB,CAAC;AAAA,+BACxB,EAAE,kBAAkB,CAAC;AAAA;AAAA,oCAEhB,EAAE,mBAAmB,CAAC;AAAA;AAAA,uCAEnB,EAAE,mBAAmB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAMjD,oBAAoB,OAAO,CAAC,CAAC,GAAG,wBAAwB,OAAO,CAAC,CAAC;AAC7E;AAEA,SAAS,wBAAwB,OAA2B,GAAoC;AAC9F,MAAI,CAAC,MAAM,iBAAkB,QAAO;AAEpC,QAAM,MAAM,MAAM;AAClB,QAAM,OAAe,MAAM,uBAA4B,KAAK,YAAqB;AACjF,QAAM,MAAe,MAAM,4BAA4B,KAAK,qBAAqB,CAAC;AAClF,QAAM,WAAe,MAAM,4BAA6B,SACpD,MAAM,0BAA4B,KAAK,YAAa;AACxD,QAAM,eAAe,MAAM,gCAAgC,SACvD,MAAM,8BAA+B,KAAK,gBAAgB;AAC9D,QAAM,aAAe,MAAM,6BAA6B,CAAC,CAAE,KAAK;AAEhE,QAAM,WAAW,CAAC,MAAqB,aACrC,kBAAkB,QAAQ,QAAQ,EAAE,CAAC,KAAK,aAAa,OAAO,aAAa,EAAE,IAAI,OAAO,QAAQ,IAAI,IAAI,EAAE,gCAAgC,CAAC;AAE7I,QAAM,aAAa,CAAC,IAAY,OAAe,aAA4B;AAAA;AAAA,qCAExC,EAAE,KAAK,QAAQ,KAAK,CAAC;AAAA,oBACtC,EAAE;AAAA,UACZ,SAAS,MAAM,QAAQ,CAAC;AAAA,UACxB,IAAI,IAAI,CAAC,OAAO,SAAS,IAAI,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAIxD,QAAM,mBAAmB,aACpB,IAAI,SAAS,IACV;AAAA,8CACoC,EAAE,uCAAuC,CAAC;AAAA,mCACrD,IAAI,IAAI,CAAC,OAAO,4BAA4B,QAAQ,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA,8CAG/D,EAAE,iCAAiC,CAAC;AAAA,eACnE,WAAW,yBAAyB,EAAE,iCAAiC,GAAG,QAAQ,CAAC;AAAA,eACnF,WAAW,8BAA8B,EAAE,sCAAsC,GAAG,YAAY,CAAC;AAAA,qBAEtG;AAAA;AAAA,qBAEW,EAAE,iCAAiC,CAAC;AAAA,qBAEnD;AAEJ,QAAM,cAAc,aAChB;AAAA,0CACoC,EAAE,oCAAoC,CAAC;AAAA;AAAA;AAAA,wCAGzC,QAAQ,IAAI,CAAC;AAAA,uEACkB,EAAE,2BAA2B,CAAC;AAAA;AAAA,iBAG/F;AAAA,0CACoC,EAAE,oCAAoC,CAAC;AAAA;AAAA,0BAEvD,QAAQ,EAAE,iCAAiC,CAAC,CAAC;AAAA,oBACnD,QAAQ,IAAI,CAAC;AAAA;AAG/B,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMC,EAAE,0BAA0B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2CAMI,EAAE,iCAAiC,CAAC;AAAA;AAAA;AAAA;AAAA,8CAIjC,EAAE,oCAAoC,CAAC;AAAA,4CACzC,EAAE,+BAA+B,CAAC;AAAA;AAAA;AAAA;AAAA,8CAIhC,EAAE,oCAAoC,CAAC;AAAA,4CACzC,EAAE,+BAA+B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,UAKpE,WAAW;AAAA;AAAA,UAEX,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA,gEAKsC,EAAE,8BAA8B,CAAC;AAAA;AAAA,gDAEjD,EAAE,+BAA+B,CAAC;AAAA,kEAChB,EAAE,6BAA6B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAMlG;;;ACtXO,IAAM,uBAAN,cAAmC,YAAY;AAAA,EAC5C;AAAA,EACR;AAAA,EACA;AAAA,EACA,mBAAmB;AAAA,EACnB,qBAAqB;AAAA,EACrB,cAAc;AAAA,EACd,mBAAqC;AAAA,EACrC,uBAAuB;AAAA,EACvB,cAAc;AAAA,EACd,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,aAAyB;AAAA,EACzB,cAAiC,CAAC;AAAA,EAClC,oBAAiC,oBAAI,IAAI;AAAA,EACzC,qBAAkC,oBAAI,IAAI;AAAA,EAC1C,qBAAyC,EAAE,GAAG,6BAA6B;AAAA,EAC3E,mBAAmB;AAAA,EACnB,mBAA4C;AAAA,EAC5C,sBAAsB;AAAA,EACtB,2BAAqC,CAAC;AAAA,EACtC,0BAAyC;AAAA,EACzC,8BAA6C;AAAA,EAC7C,4BAA4B;AAAA,EACpB,wBAAqD;AAAA,EACrD,yBAAyB;AAAA,EACzB,oBAAoB;AAAA,EACpB,oBAAmC;AAAA,EAE3C,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAEhD,SAAK,qBAAqB,aAAa,QAAQ,sBAAsB,MAAM;AAC3E,SAAK,cAAc,aAAa,QAAQ,aAAa,MAAM;AAAA,EAC7D;AAAA,EAEA,oBAA0B;AACxB,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,SAAK,WAAW;AAChB,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,EAAE,KAAqB;AAAE,WAAO,KAAK,YAAY,UAAU,GAAG;AAAA,EAAG;AAAA,EAEzE,MAAc,aAA4B;AACxC,UAAM,SAAS,MAAM,KAAK,YAAY,iBAAiB;AACvD,QAAI,SAAS,UAAU,GAAG;AACxB,WAAK,mBAAmB,OAAO,UAAU;AACzC,WAAK,YAAY,QAAQ,KAAK,gBAAwB;AAAA,IACxD;AACA,SAAK,qBAAqB,aAAa,QAAQ,sBAAsB,MAAM;AAC3E,SAAK,cAAc,aAAa,QAAQ,aAAa,MAAM;AAC3D,SAAK,mBAAoB,SAAS,kBAAkB,KAA0B;AAC9E,SAAK,uBAAuB,SAAS,sBAAsB,MAAM;AACjE,SAAK,cAAc,SAAS,aAAa,MAAM;AAG/C,UAAM,SAAS,SAAS,qBAAqB;AAC7C,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,YAAM,MAAM,OAAO,MAAM;AACzB,WAAK,mBAAmB,OAAO,SAAS,GAAG,KAAK,MAAM,IAAI,MAAM;AAAA,IAClE;AACA,SAAK,oBAAoB,SAAS,qBAAqB,MAAM;AAC7D,UAAM,SAAS,SAAS,wBAAwB;AAChD,SAAK,oBAAoB,QAAQ,QAAQ;AACzC,SAAK,qBAAqB;AAAA,MACxB,SAAU,SAAS,qBAAqB,MAAO;AAAA,MAC/C,UAAW,SAAS,sBAAsB,KAA8B,6BAA6B;AAAA,MACrG,SAAW,SAAS,qBAAqB,KAAiB;AAAA,IAC5D;AACA,SAAK,mBAAmB,MAAM,KAAK,YAAY,cAAc;AAC7D,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,iBAAiB,MAA6B;AAClD,SAAK,mBAAmB;AACxB,SAAK,YAAY,QAAQ,IAAY;AACrC,UAAM,KAAK,YAAY,UAAU,EAAE,UAAU,KAAK,CAAC;AACnD,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,2BAA2B,SAAwB;AACjD,SAAK,qBAAqB;AAG1B,iBAAa,QAAQ,wBAAwB,UAAU,SAAS,OAAO;AACvE,SAAK,YAAY,UAAU,EAAE,sBAAsB,UAAU,SAAS,QAAQ,CAAC;AAC/E,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,oBAAoB,SAAwB;AAC1C,SAAK,cAAc;AAEnB,iBAAa,QAAQ,eAAe,UAAU,SAAS,OAAO;AAC9D,SAAK,YAAY,UAAU,EAAE,aAAa,UAAU,SAAS,QAAQ,CAAC;AACtE,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,oBAAoB,SAAiC;AACzD,SAAK,cAAc;AACnB,UAAM,KAAK,YAAY,UAAU,EAAE,aAAa,UAAU,SAAS,QAAQ,CAAC;AAC5E,SAAK,cAAc,IAAI,YAAY,qBAAqB,EAAE,QAAQ,SAAS,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAC3G,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,kBAAkB,SAAgC;AACtD,UAAM,OAAO,OAAO,SAAS,OAAO,KAAK,UAAU,IAAI,KAAK,MAAM,OAAO,IAAI;AAC7E,SAAK,mBAAmB;AACxB,UAAM,KAAK,YAAY,UAAU,EAAE,CAAC,qBAAqB,GAAG,KAAK,CAAC;AAClE,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,wBAA8B;AAC5B,SAAK,cAAc,IAAI,YAAY,uBAAuB,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAC5F,cAAU,KAAK,EAAE,mCAAmC,CAAC;AAAA,EACvD;AAAA,EAEA,MAAM,sBAAsB,SAAiC;AAC3D,SAAK,uBAAuB;AAC5B,UAAM,KAAK,YAAY,UAAU,EAAE,sBAAsB,UAAU,SAAS,QAAQ,CAAC;AACrF,SAAK,cAAc,IAAI,YAAY,uBAAuB,EAAE,QAAQ,SAAS,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAC7G,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,yBAAyB,UAA2C;AACxE,SAAK,mBAAmB;AACxB,UAAM,KAAK,YAAY,UAAU,EAAE,kBAAkB,SAAS,CAAC;AAC/D,SAAK,cAAc,IAAI,YAAY,0BAA0B,EAAE,QAAQ,UAAU,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACjH,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,4BAA4B,SAAiC;AACjE,SAAK,qBAAqB,EAAE,GAAG,KAAK,oBAAoB,QAAQ;AAChE,UAAM,KAAK,YAAY,UAAU,EAAE,qBAAqB,UAAU,SAAS,QAAQ,CAAC;AACpF,SAAK,cAAc,IAAI,YAAY,sBAAsB,EAAE,QAAQ,EAAE,GAAG,KAAK,mBAAmB,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACnI,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,6BAA6B,UAA+C;AAChF,SAAK,qBAAqB,EAAE,GAAG,KAAK,oBAAoB,SAAS;AACjE,UAAM,KAAK,YAAY,UAAU,EAAE,sBAAsB,SAAS,CAAC;AACnE,SAAK,cAAc,IAAI,YAAY,sBAAsB,EAAE,QAAQ,EAAE,GAAG,KAAK,mBAAmB,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACnI,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,4BAA4B,SAAgC;AAChE,SAAK,qBAAqB,EAAE,GAAG,KAAK,oBAAoB,QAAQ;AAChE,UAAM,KAAK,YAAY,UAAU,EAAE,qBAAqB,QAAQ,CAAC;AACjE,SAAK,cAAc,IAAI,YAAY,sBAAsB,EAAE,QAAQ,EAAE,GAAG,KAAK,mBAAmB,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EACrI;AAAA,EAEA,sBAA4B;AAC1B,SAAK,mBAAmB;AACxB,UAAM,MAAM,KAAK;AACjB,SAAK,wBAAwB;AAC7B,SAAK,yBAAyB,KAAK,eAAe;AAClD,SAAK,sBAAsB,KAAK,YAAY;AAC5C,SAAK,2BAA2B,KAAK,qBAAqB,CAAC;AAC3D,SAAK,0BAA0B,KAAK,YAAY;AAChD,SAAK,8BAA8B,KAAK,gBAAgB;AACxD,SAAK,4BAA4B,CAAC,CAAE,KAAK;AACzC,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,uBAA6B;AAC3B,SAAK,mBAAmB;AACxB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,qBAAqB,QAAyC;AAClE,UAAM,KAAK,YAAY,eAAe,MAAM;AAC5C,SAAK,mBAAmB;AACxB,SAAK,mBAAmB;AACxB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,wBAAuC;AAC3C,UAAM,KAAK,YAAY,gBAAgB;AACvC,SAAK,mBAAmB;AACxB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,qBAAoC;AAExC,UAAM,cAAe,KAAK,OAAO,eAAe,sBAAsB,GAA+B,MAAM,KAAK,KAAK;AACrH,QAAI;AACF,YAAM,CAAC,MAAM,IAAI,MAAO,OAAyD,mBAAmB;AAAA,QAClG,OAAO,CAAC,EAAE,aAAa,oBAAoB,QAAQ,EAAE,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC;AAAA,QAC9E,UAAU;AAAA,MACZ,CAAC;AACD,WAAK,wBAAwB;AAC7B,YAAM,OAAO,MAAM,OAAO,QAAQ;AAClC,WAAK,yBAAyB,MAAM,KAAK,KAAK;AAC9C,WAAK,4BAA4B;AACjC,WAAK,sBAAsB,eAAe,2BAA2B,OAAO,IAAI;AAChF,WAAK,2BAA2B,yBAAyB,KAAK,sBAAsB;AACpF,WAAK,OAAO;AAAA,IACd,SAAS,GAAG;AACV,UAAK,GAAoB,SAAS,aAAc,WAAU,KAAK,EAAE,2BAA2B,GAAG,KAAK;AAAA,IACtG;AAAA,EACF;AAAA,EAEA,MAAM,2BAA0C;AAE9C,UAAM,cAAe,KAAK,OAAO,eAAe,sBAAsB,GAA+B,MAAM,KAAK,KAAK;AACrH,QAAI;AACF,YAAM,SAAS,MAAO,OAAyD,mBAAmB;AAAA,QAChG,eAAe;AAAA,QACf,OAAO,CAAC,EAAE,aAAa,oBAAoB,QAAQ,EAAE,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC;AAAA,MAChF,CAAC;AACD,YAAM,UAAU,mBAAmB;AACnC,YAAM,WAAW,MAAM,OAAO,eAAe;AAC7C,YAAM,SAAS,MAAM,OAAO;AAC5B,YAAM,SAAS,MAAM;AACrB,WAAK,wBAAwB;AAC7B,WAAK,yBAAyB;AAC9B,WAAK,4BAA4B;AACjC,WAAK,sBAAsB,eAAe,2BAA2B,OAAO,IAAI;AAChF,WAAK,2BAA2B,yBAAyB,OAAO;AAChE,WAAK,OAAO;AAAA,IACd,SAAS,GAAG;AACV,UAAK,GAAoB,SAAS,aAAc,WAAU,KAAK,EAAE,2BAA2B,GAAG,KAAK;AAAA,IACtG;AAAA,EACF;AAAA,EAEA,MAAM,mBAAkC;AACtC,UAAM,cAAe,KAAK,OAAO,eAAe,sBAAsB,GAA+B,MAAM,KAAK;AAChH,QAAI,gBAAgB,OAAW,MAAK,sBAAsB;AAC1D,QAAI;AACF,UAAI,KAAK,uBAAuB;AAC9B,cAAM,OAAO,MAAM,KAAK,sBAAsB,QAAQ;AACtD,aAAK,yBAAyB,MAAM,KAAK,KAAK;AAAA,MAChD;AACA,WAAK,2BAA2B,yBAAyB,KAAK,sBAAsB;AACpF,WAAK,OAAO;AAAA,IACd,QAAQ;AAAA,IAAwB;AAAA,EAClC;AAAA,EAEA,MAAM,eAA8B;AAClC,QAAI;AACF,YAAM,KAAK,YAAY,4BAA4B;AACnD,YAAM,KAAK,WAAW;AACtB,gBAAU,KAAK,EAAE,6BAA6B,CAAC;AAAA,IACjD,SAAS,GAAY;AACnB,UAAK,GAAoB,SAAS,cAAc;AAC9C,kBAAU,KAAK,EAAE,2BAA2B,GAAG,KAAK;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,eAA8B;AAClC,UAAM,KAAK,YAAY,UAAU,EAAE,qBAAqB,SAAS,wBAAwB,KAAK,CAAC;AAC/F,SAAK,oBAAoB;AACzB,SAAK,oBAAoB;AACzB,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,cAAc,OAAgC;AACpD,UAAM,OAAO,IAAI,KAAK,CAAC,KAAK,UAAU,EAAE,OAAO,cAAc,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,EAAE,MAAM,mBAAmB,CAAC;AAC1G,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,UAAM,IAAI,SAAS,cAAc,GAAG;AACpC,MAAE,OAAO;AACT,MAAE,WAAW;AACb,MAAE,MAAM;AACR,QAAI,gBAAgB,GAAG;AAAA,EACzB;AAAA;AAAA,EAGA,MAAM,gBAA+B;AACnC,UAAM,QAAQ,MAAM,KAAK,YAAY,YAAY;AACjD,SAAK,cAAc,KAAK;AAAA,EAC1B;AAAA;AAAA,EAGA,MAAM,mBAAkC;AACtC,SAAK,cAAc,MAAM,KAAK,YAAY,YAAY;AACtD,SAAK,aAAa;AAClB,SAAK,oBAAoB,oBAAI,IAAI;AACjC,SAAK,qBAAqB,oBAAI,IAAI;AAClC,SAAK,cAAc;AACnB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,eAAqB;AACnB,SAAK,cAAc;AACnB,SAAK,kBAAkB,MAAM;AAC7B,SAAK,mBAAmB,MAAM;AAC9B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,cAAc,MAAwB;AACpC,SAAK,aAAa;AAClB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,iBAAiB,IAAkB;AACjC,QAAI,KAAK,kBAAkB,IAAI,EAAE,EAAG,MAAK,kBAAkB,OAAO,EAAE;AAAA,QAC/D,MAAK,kBAAkB,IAAI,EAAE;AAClC,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,gBAAgB,KAAmB;AACjC,QAAI,KAAK,mBAAmB,IAAI,GAAG,EAAG,MAAK,mBAAmB,OAAO,GAAG;AAAA,QACnE,MAAK,mBAAmB,IAAI,GAAG;AACpC,SAAK,OAAO;AAAA,EACd;AAAA;AAAA,EAGA,gBAAsB;AACpB,UAAM,SAAS,qBAAqB,KAAK,aAAa,KAAK,YAAY;AAAA,MACrE,KAAK,KAAK;AAAA,MACV,MAAM,KAAK;AAAA,IACb,CAAC;AACD,QAAI,CAAC,OAAO,OAAQ;AACpB,SAAK,cAAc,MAAM;AACzB,SAAK,cAAc;AACnB,SAAK,kBAAkB,MAAM;AAC7B,SAAK,mBAAmB,MAAM;AAC9B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,cAAc,MAA2B;AAC7C,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,QAAI;AACJ,QAAI;AACF,aAAO,KAAK,MAAM,IAAI;AAAA,IACxB,QAAQ;AACN,YAAM,IAAI,MAAM,KAAK,EAAE,qBAAqB,CAAC;AAAA,IAC/C;AACA,QAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,KAAK,KAAK,KAAK,CAAC,MAAM,QAAQ,KAAK,YAAY,GAAG;AAC5E,YAAM,IAAI,MAAM,KAAK,EAAE,wBAAwB,CAAC;AAAA,IAClD;AAGA,UAAM,KAAK,YAAY,eAAe,KAAK,OAAO,KAAK,YAAY;AAAA,EACrE;AAAA,EAEQ,SAAe;AACrB,SAAK,OAAO,YAAY,UAAU,oBAAoB,WAAW,oBAAoB;AAAA,MACnF,kBAAkB,KAAK;AAAA,MACvB,oBAAoB,KAAK;AAAA,MACzB,aAAa,KAAK;AAAA,MAClB,kBAAkB,KAAK;AAAA,MACvB,mBAAmB,KAAK;AAAA,MACxB,mBAAmB,KAAK;AAAA,MACxB,sBAAsB,KAAK;AAAA,MAC3B,aAAa,KAAK;AAAA,MAClB,kBAAkB,KAAK;AAAA,MACvB,aAAa,KAAK;AAAA,MAClB,YAAY,KAAK;AAAA,MACjB,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA,MACxB,oBAAoB,KAAK;AAAA,MACzB,oBAAoB,KAAK;AAAA,MACzB,kBAAkB,KAAK;AAAA,MACvB,kBAAkB,KAAK;AAAA,MACvB,qBAAqB,KAAK;AAAA,MAC1B,0BAA0B,KAAK;AAAA,MAC/B,yBAAyB,KAAK;AAAA,MAC9B,6BAA6B,KAAK;AAAA,MAClC,2BAA2B,KAAK;AAAA,IAClC,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AACrB;AAAC,IAAC,KAAK,OAAO,eAAe,aAAa,EAAwB;AAAA,MAAiB;AAAA,MAAU,CAAC,MAC5F,KAAK,iBAAkB,EAAE,OAA6B,KAAK;AAAA,IAC7D;AACC,IAAC,KAAK,OAAO,eAAe,aAAa,EAAuB;AAAA,MAAiB;AAAA,MAAU,CAAC,MAC3F,KAAK,2BAA4B,EAAE,OAA4B,OAAO;AAAA,IACxE;AACC,IAAC,KAAK,OAAO,eAAe,gBAAgB,EAAuB;AAAA,MAAiB;AAAA,MAAU,CAAC,MAC9F,KAAK,oBAAqB,EAAE,OAA4B,OAAO;AAAA,IACjE;AACC,IAAC,KAAK,OAAO,eAAe,uBAAuB,EAAuB;AAAA,MAAiB;AAAA,MAAU,CAAC,MACrG,KAAK,sBAAuB,EAAE,OAA4B,OAAO;AAAA,IACnE;AACC,IAAC,KAAK,OAAO,eAAe,qBAAqB,EAAuB;AAAA,MAAiB;AAAA,MAAU,CAAC,MACnG,KAAK,oBAAqB,EAAE,OAA4B,OAAO;AAAA,IACjE;AACC,IAAC,KAAK,OAAO,eAAe,kBAAkB,EAAuB;AAAA,MAAiB;AAAA,MAAU,CAAC,MAChG,KAAK,kBAAkB,OAAQ,EAAE,OAA4B,KAAK,CAAC;AAAA,IACrE;AACC,SAAK,OAAO,eAAe,oBAAoB,GAAG,iBAAiB,SAAS,MAAM,KAAK,sBAAsB,CAAC;AAC9G,IAAC,KAAK,OAAO,eAAe,mBAAmB,EAAwB;AAAA,MAAiB;AAAA,MAAU,CAAC,MAClG,KAAK,yBAA0B,EAAE,OAA6B,KAAyB;AAAA,IACzF;AAEA;AAAC,IAAC,KAAK,OAAO,eAAe,sBAAsB,GAAwB;AAAA,MAAiB;AAAA,MAAU,CAAC,MACrG,KAAK,4BAA6B,EAAE,OAA4B,OAAO;AAAA,IACzE;AACC,IAAC,KAAK,OAAO,eAAe,wBAAwB,GAAyB;AAAA,MAAiB;AAAA,MAAU,CAAC,MACxG,KAAK,6BAA8B,EAAE,OAA6B,KAA6B;AAAA,IACjG;AACC,IAAC,KAAK,OAAO,eAAe,wBAAwB,GAAwB;AAAA,MAAiB;AAAA,MAAU,CAAC,MACvG,KAAK,4BAA6B,EAAE,OAA4B,KAAK;AAAA,IACvE;AACC,SAAK,OAAO,eAAe,mBAAmB,GAAG,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AACrG,SAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AAC7F,SAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAEjG,SAAK,OAAO,eAAe,oBAAoB,GAAG,iBAAiB,SAAS,MAAM,KAAK,cAAc,CAAC;AACtG,SAAK,OAAO,eAAe,mBAAmB,GAAG,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AACpG,SAAK,OAAO,iBAAiB,oBAAoB,EAAE;AAAA,MAAQ,CAAC,OAC1D,GAAG,iBAAiB,SAAS,MAAM,KAAK,cAAe,GAAmB,QAAQ,YAAY,CAAe,CAAC;AAAA,IAChH;AACA,SAAK,OAAO,iBAAiB,oBAAoB,EAAE;AAAA,MAAQ,CAAC,OAC1D,GAAG,iBAAiB,UAAU,MAAM,KAAK,iBAAiB,OAAQ,GAAmB,QAAQ,YAAY,CAAC,CAAC,CAAC;AAAA,IAC9G;AACA,SAAK,OAAO,iBAAiB,mBAAmB,EAAE;AAAA,MAAQ,CAAC,OACzD,GAAG,iBAAiB,SAAS,MAAM,KAAK,gBAAiB,GAAmB,QAAQ,WAAW,KAAK,EAAE,CAAC;AAAA,IACzG;AACA,SAAK,OAAO,eAAe,sBAAsB,GAAG,iBAAiB,SAAS,MAAM,KAAK,oBAAoB,CAAC;AAC9G,SAAK,OAAO,eAAe,wBAAwB,GAAG,iBAAiB,SAAS,MAAM,KAAK,qBAAqB,CAAC;AACjH,SAAK,OAAO,eAAe,2BAA2B,GAAG,iBAAiB,SAAS,MAAM,KAAK,mBAAmB,CAAC;AAClH,SAAK,OAAO,eAAe,iCAAiC,GAAG,iBAAiB,SAAS,MAAM,KAAK,yBAAyB,CAAC;AAC9H,SAAK,OAAO,eAAe,wBAAwB,GAAG,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAC7G,SAAK,OAAO,eAAe,uBAAuB,GAAG,iBAAiB,SAAS,MAAM,KAAK,sBAAsB,CAAC;AACjH,SAAK,OAAO,eAAe,sBAAsB,GAAG,iBAAiB,SAAS,YAAY;AACxF,YAAM,SAAgB,KAAK,OAAO,eAAe,sBAAsB;AACvE,YAAM,WAAgB,KAAK,OAAO,eAAe,uBAAuB;AACxE,YAAM,eAAgB,KAAK,OAAO,eAAe,4BAA4B;AAC7E,YAAM,KAAK,qBAAqB;AAAA,QAC9B,SAAS;AAAA,QACT,UAAmB,QAAQ,MAAM,KAAK,KAAO,KAAK;AAAA,QAClD,aAAmB,KAAK;AAAA,QACxB,mBAAmB,KAAK;AAAA,QACxB,UAAmB,UAAU,SAAgB;AAAA,QAC7C,cAAmB,cAAc,SAAY;AAAA,MAC/C,CAAC;AAAA,IACH,CAAC;AAED;AAAC,IAAC,KAAK,OAAO,eAAe,YAAY,EAAuB,iBAAiB,UAAU,OAAO,MAAM;AACtG,YAAM,OAAQ,EAAE,OAA4B,QAAQ,CAAC;AACrD,UAAI,CAAC,KAAM;AACX,UAAI;AACF,cAAM,KAAK,cAAc,IAAI;AAC7B,kBAAU,KAAK,EAAE,uBAAuB,CAAC;AAAA,MAC3C,SAAS,KAAc;AACrB,kBAAW,IAAc,WAAW,KAAK,EAAE,qBAAqB,GAAG,KAAK;AAAA,MAC1E;AACA,YAAM,SAAS,EAAE;AACjB,UAAI,OAAQ,QAAO,QAAQ;AAAA,IAC7B,CAAC;AAAA,EACH;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,uBAAuB,GAAG;AAChD,iBAAe,OAAO,yBAAyB,oBAAoB;AACrE;;;AC9cA,yBAAiB;AAIjB;;;ACJO,IAAM,8BAA8B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACA3C;AAkBO,SAAS,mBAAmB,aAAsB,GAAoC;AAC3F,QAAM,YAAY,cACd;AAAA;AAAA;AAAA,WAGK,EAAE,4BAA4B,CAAC;AAAA,oBAEpC;AAEJ,SAAO;AAAA;AAAA,aAEI,cAAc,EAAE,oCAAoC,IAAI,EAAE,2BAA2B,CAAC;AAAA,oCAC/D,cAC1B,EAAE,yCAAyC,IAC3C,EAAE,gCAAgC,CAAC;AAAA,QACrC,SAAS;AAAA;AAEjB;AAEO,SAAS,qBAAqB,OAA4B,GAAoC;AACnG,QAAM,EAAE,SAAS,cAAc,qBAAqB,aAAa,mBAAmB,WAAW,mBAAmB,gBAAgB,kBAAkB,eAAe,aAAa,IAAI;AAEpL,QAAM,WAAW,QAAQ,SACrB,WAAW,SAAS,cAAc,aAAa,IAC/C,gDAAgD,EAAE,0BAA0B,CAAC;AAEjF,QAAM,cAAc,sBAChB,oCAA6B,QAAS,cAA2C,QAAQ,EAAE,CAAC;AAAA,+BACnE,gBAAgB,oBAAoB,MAAM,GAAG,GAAI,CAAC,CAAC,GAAG,oBAAoB,SAAS,MAAO,UAAU,EAAE,WAC/H,4BAA4B,EAAE,6BAA6B,CAAC;AAEhE,QAAM,YAAa,eAAe,YAC9B,yBAAyB,QAAQ,SAAS,CAAC,SAC3C;AAEJ,QAAM,SAAS,cACX;AAAA;AAAA,mBAEa,EAAE,0BAA0B,CAAC;AAAA,uDACO,EAAE,6BAA6B,CAAC;AAAA;AAAA,kCAErD,gBAAgB,YAAY,MAAM,GAAG,GAAI,CAAC,CAAC;AAAA,iBAC5D;AAEf,QAAM,mBAAmB,oBACrB;AAAA;AAAA,mBAEa,EAAE,mCAAmC,CAAC;AAAA,iEACQ,EAAE,8BAA8B,CAAC;AAAA;AAAA,0CAExD,gBAAgB,kBAAkB,MAAM,GAAG,GAAI,CAAC,CAAC;AAAA,iBAC1E;AAEf,QAAM,cAAc,iBAChB;AAAA,+DACyD,QAAQ,EAAE,sCAAsC,CAAC,CAAC;AAAA;AAAA;AAAA,mEAG9C,EAAE,kCAAkC,CAAC;AAAA,sEAClC,EAAE,iCAAiC,CAAC;AAAA;AAAA,iBAGpG;AAEJ,QAAM,gBAAgB,mBAClB;AAAA,iEAC2D,QAAQ,EAAE,wCAAwC,CAAC,CAAC;AAAA;AAAA,qEAEhD,EAAE,kCAAkC,CAAC;AAAA,wEAClC,EAAE,iCAAiC,CAAC;AAAA;AAAA,iBAGtG;AAEJ,QAAM,UAAU;AAAA;AAAA,8DAE4C,EAAE,8BAA8B,CAAC;AAAA,uEACxB,EAAE,gCAAgC,CAAC;AAAA,8DAC5C,EAAE,6BAA6B,CAAC;AAAA;AAG5F,SAAO;AAAA;AAAA,0CAEiC,YAAY;AAAA,UAC5C,OAAO;AAAA,UACP,WAAW;AAAA,UACX,aAAa;AAAA,mCACY,QAAQ;AAAA;AAAA;AAAA;AAAA,oCAIP,WAAW,GAAG,SAAS,GAAG,MAAM,GAAG,gBAAgB;AAAA;AAAA;AAAA,cAGzE,CAAC,qBAAqB,CAAC,cAAc,aAAa,EAAE;AAAA,cACpD,EAAE,4BAA4B,CAAC;AAAA;AAAA,kCAEX,CAAC,oBAAoB,aAAa,EAAE;AAAA,cACxD,EAAE,iCAAiC,CAAC;AAAA;AAAA,mCAEf,EAAE,2BAA2B,CAAC;AAAA;AAAA;AAAA;AAIjE;AAEO,SAAS,WACd,OACA,UACA,eACA,SAAS,GACT,aAAa,IACL;AACR,SAAO,MAAM,IAAI,CAAC,MAAM;AACtB,UAAM,cAAc,aAAa,GAAG,UAAU,IAAI,EAAE,IAAI,KAAK,EAAE;AAC/D,UAAM,SAAS,EAAE,SAAS;AAC1B,UAAM,MAAM,gBAAgB,IAAI,SAAS,EAAE;AAE3C,QAAI,CAAC,QAAQ;AACX,YAAM,MAAM;AACZ,YAAM,eAAe,IAAI,UAAU,UAAU,KAAK;AAClD,YAAM,cAAc,cAAc,IAAI,WAAW;AACjD,YAAM,QAAQ,cAAe,cAAc,WAAM,WAAO;AACxD,YAAM,UAAU,qCAAqC,GAAG,oBAAoB,QAAQ,WAAW,CAAC;AAAA,kCACpE,KAAK,oBAAa,QAAQ,EAAE,IAAI,CAAC;AAAA;AAE7D,UAAI,CAAC,eAAe,YAAa,QAAO;AACxC,aAAO,UAAU,WAAW,IAAI,UAAU,UAAU,eAAe,SAAS,GAAG,WAAW;AAAA,IAC5F;AAEA,UAAM,QAAS,UAAuC,SAAS,EAAE;AACjE,UAAM,MAAM,YAAY,QAAQ,cAAc,EAAE;AAChD,UAAM,OAAO,KAAK,UAAU,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,KAAK,CAAC,EAAE,QAAQ,MAAM,QAAQ;AAClF,WAAO,eAAe,GAAG,YAAY,GAAG,gBAAgB,IAAI,eAAQ,QAAQ,EAAE,IAAI,CAAC;AAAA,EACrF,CAAC,EAAE,KAAK,EAAE;AACZ;AAEA,eAAsB,wBACpB,KACA,MACsC;AACtC,mBAAiB,SAAS,IAAI,OAAO,GAAG;AACtC,QAAI,MAAM,SAAS,UAAU,MAAM,SAAS,KAAM,QAAO;AACzD,QAAI,MAAM,SAAS,aAAa;AAC9B,YAAM,QAAQ,MAAM,wBAAwB,OAAoC,IAAI;AACpF,UAAI,MAAO,QAAO;AAAA,IACpB;AAAA,EACF;AACA,SAAO;AACT;;;AF5JO,IAAM,4BAAN,cAAwC,YAAY;AAAA,EACjD;AAAA,EACS,wBAAwB,IAAI,kCAAkC;AAAA,EAE/E;AAAA,EACA;AAAA,EACA;AAAA,EAEA,UAA2C,CAAC;AAAA,EAC5C,eAAwB;AAAA,EACxB,oBAAoB;AAAA,EACpB,qBAAkD;AAAA,EAClD,sBAAqC;AAAA,EACrC,cAAc;AAAA,EACd,oBAAoB;AAAA,EACpB,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,kBAAiC;AAAA,EACjC,qBAAoC;AAAA,EACpC,iBAAiB;AAAA,EACjB,mBAAmB;AAAA,EACnB,gBAA6B,oBAAI,IAAI;AAAA,EACrC,eAAe;AAAA,EACf,mBAA4C;AAAA,EACpC,gBAAgB;AAAA,EAChB,cAAc;AAAA,EACd,aAA+C;AAAA,EAC/C,aAA+C;AAAA,EAEvD,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AACxB,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,SAAK,KAAK;AAAA,EACZ;AAAA,EAEQ,EAAE,KAAqB;AAAE,WAAO,KAAK,YAAY,UAAU,GAAG;AAAA,EAAG;AAAA,EAEzE,MAAc,OAAsB;AAClC,UAAM,SAAS,MAAM,KAAK,YAAY,iBAAiB;AACvD,UAAM,UAAU,SAAS,qBAAqB,MAAM;AAEpD,QAAI,CAAC,SAAS;AACZ,WAAK,gBAAgB;AACrB,UAAI,KAAK,WAAW,OAAW,OAAM,KAAK,2BAA2B,KAAK,MAAM;AAChF,WAAK,OAAO;AACZ;AAAA,IACF;AAEA,UAAM,SAAS,SAAS,wBAAwB;AAChD,QAAI,CAAC,QAAQ;AACX,WAAK,gBAAgB;AACrB,UAAI,KAAK,WAAW,OAAW,OAAM,KAAK,2BAA2B,KAAK,MAAM;AAChF,WAAK,OAAO;AACZ;AAAA,IACF;AAGA,UAAM,OAAO,MAAO,OAAqD,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9G,SAAK,aAAa;AAClB,SAAK,gBAAgB,SAAS;AAC9B,SAAK,cAAe,SAAS;AAE7B,QAAI,KAAK,WAAW,OAAW,OAAM,KAAK,2BAA2B,KAAK,MAAM;AAChF,QAAI,KAAK,cAAe,OAAM,KAAK,eAAe;AAClD,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAM,iBAAgC;AACpC,QAAI,CAAC,KAAK,iBAAiB,CAAC,KAAK,WAAY;AAC7C,QAAI;AACF,uBAAiB,SAAS,KAAK,WAAW,OAAO,GAAG;AAClD,YAAI,MAAM,SAAS,eAAe,MAAM,SAAS,OAAO;AACtD,eAAK,aAAa;AAClB,gBAAM,OAAO,MAAM,KAAK,sBAAsB,cAAc,KAAK,UAAU;AAC3E,eAAK,UAAU,KAAK,YAAY,CAAC;AACjC,eAAK,OAAO;AACZ;AAAA,QACF;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAAwC;AAAA,EAClD;AAAA,EAEA,MAAM,cAAc,SAAgC;AAClD,QAAI,CAAC,KAAK,WAAY;AACtB,UAAM,OAAO,QAAQ,KAAK,EAAE,QAAQ,aAAa,EAAE;AACnD,QAAI,CAAC,KAAM;AACX,UAAM,WAAW,GAAG,IAAI;AAExB,UAAM,MAAM,KAAK;AACjB,QAAI,KAAK,YAAY,IAAI,YAAY,IAAI,eAAe;AACtD,YAAM,UAAU,KAAK,WAAW,QAAQ;AACxC,YAAM,WAAW,WAAW,OAAO,IAAI,QAAQ;AAC/C,YAAM,aAAa,qBAAqB,UAAU,IAAI,QAAQ;AAC9D,YAAM,EAAE,YAAY,aAAa,gBAAgB,IAAI;AAAA,QACnD;AAAA,QAAY,IAAI;AAAA,QAAU,IAAI;AAAA,MAChC;AACA,YAAM,SAAS,aAAa,GAAG,UAAU;AAAA;AAAA,IAAS;AAClD,YAAM,QAAQ,CAAC,aAAa,eAAe,EAAE,OAAO,OAAO,EAAE,KAAK,EAAE;AACpE,YAAM,WAAW,GAAG,MAAM,aAAa,mBAAmB,IAAI,CAAC;AAAA,EAAe,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACnF,UAAI;AACF,cAAM,aAAa,MAAM,KAAK,WAAW,cAAc,UAAU,EAAE,QAAQ,KAAK,CAAC;AACjF,cAAM,WAAW,MAAM,WAAW,eAAe;AACjD,cAAM,SAAS,MAAM,QAAQ;AAC7B,cAAM,SAAS,MAAM;AAAA,MACvB,QAAQ;AAAA,MAAwB;AAAA,IAClC,OAAO;AACL,YAAM,WAAW,aAAa,mBAAmB,IAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACtD,UAAI;AACF,cAAM,aAAa,MAAM,KAAK,WAAW,cAAc,UAAU,EAAE,QAAQ,KAAK,CAAC;AACjF,cAAM,WAAW,MAAM,WAAW,eAAe;AACjD,cAAM,SAAS,MAAM,QAAQ;AAC7B,cAAM,SAAS,MAAM;AAAA,MACvB,QAAQ;AAAA,MAAwB;AAAA,IAClC;AACA,SAAK,iBAAiB;AACtB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAAA,EAEA,MAAM,gBAAgB,SAAgC;AACpD,QAAI,CAAC,KAAK,WAAY;AACtB,UAAM,OAAO,QAAQ,KAAK,EAAE,QAAQ,UAAU,EAAE;AAChD,QAAI,CAAC,KAAM;AACX,QAAI;AACF,YAAM,KAAK,WAAW,mBAAmB,MAAM,EAAE,QAAQ,KAAK,CAAC;AAAA,IACjE,QAAQ;AAAA,IAAsE;AAC9E,SAAK,mBAAmB;AACxB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAAA,EAEA,MAAM,cAA6B;AACjC,UAAM,KAAK,eAAe;AAAA,EAC5B;AAAA,EAEA,MAAM,qBAAoC;AACxC,QAAI,CAAC,KAAK,sBAAsB,CAAC,KAAK,uBAAuB,CAAC,KAAK,YAAa;AAChF,QAAI,UAAU,KAAK;AACnB,QAAI,KAAK,mBAAmB;AAC1B,gBAAU,KAAK,sBAAsB,iBAAiB,SAAS,KAAK,iBAAiB;AAAA,IACvF;AACA,UAAM,UAAU,KAAK,YAAY,KAAK,sBAAsB,kBAAkB,KAAK,SAAS,IAAI,OAAO;AACvG,cAAU,KAAK,sBAAsB,cAAc,SAAS,UAAU,KAAK,WAAW;AACtF,QAAI,CAAC,QAAS;AAEd,UAAM,MAAM,KAAK;AACjB,QAAI,KAAK,YAAY,IAAI,YAAY,IAAI,eAAe;AACtD,YAAM,MAAM,CAAC,IAAI,UAAU,IAAI,YAAY,EAAE,OAAO,OAAO;AAC3D,UAAI,CAAC,eAAe,SAAS,GAAG,GAAG;AACjC,cAAM,UAAU,KAAK,YAAY,QAAQ;AACzC,cAAM,WAAY,KAAK,cAA0C,QAAQ;AACzE,cAAM,WAAW,WAAW,OAAO,IAAI,QAAQ;AAC/C,cAAM,aAAa,qBAAqB,UAAU,IAAI,QAAQ;AAC9D,cAAM,EAAE,YAAY,aAAa,gBAAgB,IAAI,iBAAiB,YAAY,IAAI,UAAU,IAAI,YAAY;AAChH,cAAM,SAAS,MAAM,mBAAAC,QAAK,KAAK;AAAA,UAC7B,OAAO,KAAK,EAAE,iCAAiC;AAAA,UAC/C,MAAM,uJAAuJ,KAAK,EAAE,gCAAgC,CAAC;AAAA,UACrM,MAAM;AAAA,UACN,kBAAkB;AAAA,UAClB,mBAAmB,KAAK,EAAE,mCAAmC;AAAA,UAC7D,kBAAkB,KAAK,EAAE,+BAA+B;AAAA,UACxD,oBAAoB;AAAA,UACpB,OAAO;AAAA,QACT,CAAC;AACD,YAAI,OAAO,aAAa;AACtB,oBAAU,8BAA8B,SAAS,YAAY,aAAa,eAAe;AAAA,QAC3F;AAAA,MACF;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,KAAK,mBAAmB,eAAe;AAC9D,UAAM,SAAS,MAAM,OAAO;AAC5B,UAAM,SAAS,MAAM;AACrB,SAAK,cAAc,IAAI,YAAY,cAAc,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EACrF;AAAA,EAEA,MAAM,YAAY,MAA8B;AAC9C,QAAI,CAAC,KAAK,sBAAsB,OAAO,IAAI,EAAG;AAC9C,SAAK,eAAe;AACpB,SAAK,oBAAoB;AAEzB,QAAI,CAAC,KAAK,WAAY;AACtB,UAAM,SAAS,MAAM,wBAAwB,KAAK,YAAa,KAA0B,IAAI;AAC7F,QAAI,CAAC,OAAQ;AACb,SAAK,qBAAqB;AAC1B,UAAM,UAAU,MAAM,OAAO,QAAQ;AACrC,SAAK,sBAAsB,MAAM,QAAQ,KAAK;AAC9C,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,mBAAmB,MAAqB;AACtC,SAAK,eAAe;AAAA,EACtB;AAAA,EAEA,MAAM,2BAA2B,QAA+B;AAC9D,UAAM,OAAO,MAAM,KAAK,YAAY,YAAY,MAAM;AACtD,QAAI,MAAM;AACR,WAAK,cAAc,KAAK,WAAW;AACnC,WAAK,oBAAoB,KAAK,qBAAqB;AACnD,WAAK,YAAY,KAAK,SAAS;AAAA,IACjC,OAAO;AACL,WAAK,cAAc;AACnB,WAAK,oBAAoB;AACzB,WAAK,YAAY;AAAA,IACnB;AACA,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,gBAAgB,MAAoB;AAClC,cAAU,WAAW,UAAU,IAAI;AAAA,EACrC;AAAA,EAEA,mBAAyB;AACvB,QAAI,CAAC,KAAK,sBAAsB,CAAC,KAAK,oBAAqB;AAC3D,SAAK,cAAc,IAAI,YAAY,kBAAkB;AAAA,MACnD,QAAQ;AAAA,QACN,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,QACd,UAAW,KAAK,cAA2C,QAAQ;AAAA,QACnE,QAAQ,KAAK;AAAA,QACb,SAAS,KAAK;AAAA,QACd,mBAAmB,KAAK;AAAA,QACxB,OAAO,KAAK;AAAA,MACd;AAAA,MACA,SAAS;AAAA,MACT,UAAU;AAAA,IACZ,CAAC,CAAC;AAAA,EACJ;AAAA,EAEA,UAAU,MAAoB;AAC5B,QAAI,KAAK,cAAc,IAAI,IAAI,GAAG;AAChC,WAAK,cAAc,OAAO,IAAI;AAAA,IAChC,OAAO;AACL,WAAK,cAAc,IAAI,IAAI;AAAA,IAC7B;AACA,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,oBAA0B;AAChC,UAAM,SAAS,KAAK,OAAO,eAAe,eAAe;AACzD,UAAM,UAAU,KAAK,OAAO,cAAc,UAAU;AACpD,QAAI,CAAC,UAAU,CAAC,QAAS;AAEzB,QAAI,SAAS;AACb,QAAI,aAAa;AAEjB,UAAM,cAAc,CAAC,MAAkB;AACrC,YAAM,QAAQ,EAAE,UAAU;AAC1B,YAAM,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,aAAa,KAAK,CAAC;AAChE,WAAK,eAAe;AACpB,cAAQ,MAAM,QAAQ,GAAG,QAAQ;AAAA,IACnC;AAEA,UAAM,YAAY,MAAM;AACtB,eAAS,oBAAoB,aAAa,WAAW;AACrD,eAAS,oBAAoB,WAAW,SAAS;AACjD,eAAS,KAAK,MAAM,SAAS;AAC7B,eAAS,KAAK,MAAM,aAAa;AACjC,aAAO,UAAU,OAAO,UAAU;AAAA,IACpC;AAEA,WAAO,iBAAiB,aAAa,CAAC,MAAkB;AACtD,eAAS,EAAE;AACX,mBAAa,QAAQ;AACrB,eAAS,iBAAiB,aAAa,WAAW;AAClD,eAAS,iBAAiB,WAAW,SAAS;AAC9C,eAAS,KAAK,MAAM,SAAS;AAC7B,eAAS,KAAK,MAAM,aAAa;AACjC,aAAO,UAAU,IAAI,UAAU;AAC/B,QAAE,eAAe;AAAA,IACnB,CAAC;AAAA,EACH;AAAA,EAEA,eAAqB;AACnB,SAAK,gBAAgB;AACrB,SAAK,kBAAkB;AACvB,SAAK,qBAAqB;AAC1B,QAAI,KAAK,WAAW,QAAW;AAC7B,WAAK,cAAc,IAAI,YAAY,cAAc,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,IACrF;AACA,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,SAAe;AACrB,QAAI,CAAC,KAAK,eAAe;AACvB,WAAK,OAAO,YAAY,UAAU,2BAA2B,WAAW,mBAAmB,KAAK,aAAa,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AAE/H,WAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,YAAY;AAC9E,YAAI,CAAC,KAAK,WAAY;AACtB,cAAM,OAAO,MAAO,KAAK,WAAyD,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACzH,YAAI,SAAS,WAAW;AACtB,eAAK,gBAAgB;AACrB,eAAK,cAAgB;AACrB,gBAAM,KAAK,eAAe;AAC1B,eAAK,OAAO;AAAA,QACd;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAEA,SAAK,OAAO,YAAY,UAAU,2BAA2B,WAAW,qBAAqB;AAAA,MAC3F,SAAS,KAAK;AAAA,MACd,cAAc,KAAK;AAAA,MACnB,qBAAqB,KAAK;AAAA,MAC1B,aAAa,KAAK;AAAA,MAClB,mBAAmB,KAAK;AAAA,MACxB,WAAW,KAAK;AAAA,MAChB,mBAAmB,KAAK;AAAA,MACxB,gBAAgB,KAAK;AAAA,MACrB,kBAAkB,KAAK;AAAA,MACvB,eAAe,KAAK;AAAA,MACpB,cAAc,KAAK;AAAA,IACrB,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AAErB,SAAK,OAAO,iBAAiB,aAAa,EAAE,QAAQ,CAAC,OAAO;AAC1D,SAAG,iBAAiB,SAAS,MAAM;AACjC,cAAM,OAAQ,GAAmB,QAAQ,MAAM;AAC/C,YAAI,KAAM,MAAK,YAAY,KAAK,MAAM,IAAI,CAAC;AAAA,MAC7C,CAAC;AAAA,IACH,CAAC;AACD,SAAK,OAAO,iBAAiB,iBAAiB,EAAE,QAAQ,CAAC,OAAO;AAC9D,SAAG,iBAAiB,SAAS,MAAM;AACjC,cAAM,OAAQ,GAAmB,QAAQ,SAAS;AAClD,YAAI,KAAM,MAAK,UAAU,IAAI;AAAA,MAC/B,CAAC;AAAA,IACH,CAAC;AACD,SAAK,kBAAkB;AACvB,SAAK,OAAO,eAAe,UAAU,GACjC,iBAAiB,SAAS,MAAM,KAAK,mBAAmB,CAAC;AAC7D,SAAK,OAAO,eAAe,UAAU,GACjC,iBAAiB,SAAS,MAAM,KAAK,iBAAiB,CAAC;AAC3D,SAAK,OAAO,eAAe,aAAa,GACpC,iBAAiB,SAAS,MAAM,KAAK,gBAAgB,KAAK,WAAW,CAAC;AAC1E,SAAK,OAAO,eAAe,uBAAuB,GAC9C,iBAAiB,SAAS,MAAM,KAAK,gBAAgB,KAAK,iBAAiB,CAAC;AAChF,SAAK,OAAO,eAAe,WAAW,GAClC,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AACvD,SAAK,OAAO,eAAe,cAAc,GACrC,iBAAiB,SAAS,MAAM;AAChC,WAAK,iBAAiB,CAAC,KAAK;AAC5B,WAAK,mBAAmB;AACxB,WAAK,OAAO;AACZ,UAAI,KAAK,eAAgB,MAAK,OAAO,eAAe,gBAAgB,GAAG,MAAM;AAAA,IAC/E,CAAC;AACH,SAAK,OAAO,eAAe,gBAAgB,GACvC,iBAAiB,SAAS,MAAM;AAChC,WAAK,mBAAmB,CAAC,KAAK;AAC9B,WAAK,iBAAiB;AACtB,WAAK,OAAO;AACZ,UAAI,KAAK,iBAAkB,MAAK,OAAO,eAAe,kBAAkB,GAAG,MAAM;AAAA,IACnF,CAAC;AACH,SAAK,OAAO,eAAe,aAAa,GACpC,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AACtD,SAAK,OAAO,eAAe,sBAAsB,GAC7C,iBAAiB,SAAS,MAAM;AAChC,YAAMC,SAAQ,KAAK,OAAO,eAAe,gBAAgB;AACzD,WAAK,cAAcA,QAAO,SAAS,EAAE;AAAA,IACvC,CAAC;AACH,SAAK,OAAO,eAAe,qBAAqB,GAC5C,iBAAiB,SAAS,MAAM;AAChC,WAAK,iBAAiB;AACtB,WAAK,OAAO;AAAA,IACd,CAAC;AACH,UAAM,QAAQ,KAAK,OAAO,eAAe,gBAAgB;AACzD,WAAO,iBAAiB,WAAW,CAAC,MAAM;AACxC,UAAI,EAAE,QAAQ,SAAS;AACrB,aAAK,cAAc,MAAM,KAAK;AAAA,MAChC,WAAW,EAAE,QAAQ,UAAU;AAC7B,aAAK,iBAAiB;AACtB,aAAK,OAAO;AAAA,MACd;AAAA,IACF,CAAC;AACD,SAAK,OAAO,eAAe,wBAAwB,GAC/C,iBAAiB,SAAS,MAAM;AAChC,YAAMC,eAAc,KAAK,OAAO,eAAe,kBAAkB;AACjE,WAAK,gBAAgBA,cAAa,SAAS,EAAE;AAAA,IAC/C,CAAC;AACH,SAAK,OAAO,eAAe,uBAAuB,GAC9C,iBAAiB,SAAS,MAAM;AAChC,WAAK,mBAAmB;AACxB,WAAK,OAAO;AAAA,IACd,CAAC;AACH,UAAM,cAAc,KAAK,OAAO,eAAe,kBAAkB;AACjE,iBAAa,iBAAiB,WAAW,CAAC,MAAM;AAC9C,UAAI,EAAE,QAAQ,SAAS;AACrB,aAAK,gBAAgB,YAAY,KAAK;AAAA,MACxC,WAAW,EAAE,QAAQ,UAAU;AAC7B,aAAK,mBAAmB;AACxB,aAAK,OAAO;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACH;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,8BAA8B,GAAG;AACvD,iBAAe,OAAO,gCAAgC,yBAAyB;AACjF;;;AG1ZO,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAnC;AAIO,SAAS,YAAY,UAAkB,UAA+B;AAC3E,QAAM,YAAY;AAClB,QAAM,IAAI,SAAS,MAAM,IAAI,EAAE,MAAM,GAAG,SAAS;AACjD,QAAM,IAAI,SAAS,MAAM,IAAI,EAAE,MAAM,GAAG,SAAS;AACjD,QAAM,IAAI,EAAE,QAAQ,IAAI,EAAE;AAE1B,QAAM,KAAiB,MAAM,KAAK,EAAE,QAAQ,IAAI,EAAE,GAAG,MAAM,IAAI,MAAM,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;AACnF,WAASC,KAAI,GAAGA,MAAK,GAAGA,MAAK;AAC3B,aAASC,KAAI,GAAGA,MAAK,GAAGA,MAAK;AAC3B,SAAGD,EAAC,EAAEC,EAAC,IAAI,EAAED,KAAI,CAAC,MAAM,EAAEC,KAAI,CAAC,IAAI,GAAGD,KAAI,CAAC,EAAEC,KAAI,CAAC,IAAI,IAAI,KAAK,IAAI,GAAGD,KAAI,CAAC,EAAEC,EAAC,GAAG,GAAGD,EAAC,EAAEC,KAAI,CAAC,CAAC;AAAA,IAC/F;AAAA,EACF;AAEA,QAAM,SAAsB,CAAC;AAC7B,MAAI,IAAI,GAAG,IAAI;AACf,SAAO,IAAI,KAAK,IAAI,GAAG;AACrB,QAAI,IAAI,KAAK,IAAI,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG;AAC3C,aAAO,QAAQ,EAAE,MAAM,QAAQ,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;AAC/C;AAAK;AAAA,IACP,WAAW,IAAI,MAAM,MAAM,KAAK,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,IAAI;AAC7D,aAAO,QAAQ,EAAE,MAAM,SAAS,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;AAChD;AAAA,IACF,OAAO;AACL,aAAO,QAAQ,EAAE,MAAM,WAAW,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;AAClD;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAEO,SAAS,cAAc,UAAkB,SAAiB,GAAoC;AACnG,MAAI,aAAa,QAAS,QAAO,2BAA2B,EAAE,yBAAyB,CAAC;AAExF,QAAM,OAAO,YAAY,UAAU,OAAO;AAC1C,MAAI,CAAC,KAAK,OAAQ,QAAO,2BAA2B,EAAE,+BAA+B,CAAC;AAEtF,QAAM,UAAU;AAChB,QAAM,aAA0B,CAAC;AACjC,MAAI,UAAU;AACd,WAAS,MAAM,GAAG,MAAM,KAAK,QAAQ,OAAO;AAC1C,QAAI,KAAK,GAAG,EAAE,SAAS,QAAQ;AAC7B;AACA,UAAI,WAAW,QAAS,YAAW,KAAK,KAAK,GAAG,CAAC;AAAA,eACxC,MAAM,IAAI,KAAK,UAAU,KAAK,MAAM,CAAC,EAAE,SAAS,QAAQ;AAC/D,YAAI,UAAU,UAAU,EAAG,YAAW,KAAK,EAAE,MAAM,QAAQ,MAAM,SAAI,CAAC;AACtE,mBAAW,KAAK,KAAK,GAAG,CAAC;AAAA,MAC3B;AAAA,IACF,OAAO;AACL,gBAAU;AACV,iBAAW,KAAK,KAAK,GAAG,CAAC;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO,WAAW,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM;AACxC,UAAM,OAAO,SAAS,UAAU,MAAM,SAAS,YAAY,WAAM;AACjE,WAAO,yBAAyB,IAAI,6BAA6B,IAAI,gBAAgB,QAAQ,IAAI,CAAC;AAAA,EACpG,CAAC,EAAE,KAAK,EAAE;AACZ;AAkBA,IAAM,iBAA4D;AAAA,EAChE,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AACT;AAEO,SAAS,kBAAkB,OAAyB,GAAoC;AAC7F,QAAM,EAAE,UAAU,UAAU,aAAa,iBAAiB,gBAAgB,SAAS,mBAAmB,YAAY,SAAS,UAAU,UAAU,IAAI;AAEnJ,QAAM,kBAAmB,WAAW,oBAAqB;AAAA;AAAA,QAEnD,UAAU;AAAA;AAAA;AAAA,sCAGoB,EAAE,uBAAuB,CAAC;AAAA,yDACP,EAAE,uBAAuB,CAAC;AAAA;AAAA,iCAElD,QAAQ,QAAQ,MAAM,GAAG,GAAI,CAAC,CAAC;AAAA,gBAChD,EAAE;AAAA,QACV,oBAAoB;AAAA;AAAA;AAAA,sCAGU,EAAE,gCAAgC,CAAC;AAAA,0DACf,EAAE,uBAAuB,CAAC;AAAA;AAAA,uDAE7B,QAAQ,kBAAkB,MAAM,GAAG,GAAI,CAAC,CAAC;AAAA,gBAChF,EAAE;AAAA,cACJ;AAEZ,QAAM,aAAa,oBAAoB,QAAQ,qBAAqB,eAAe;AACnF,QAAM,YAAY,CAAC,EAAE,WAAW;AAEhC,QAAM,gBAAgB,UAClB,8CAA8C,aAAa,YAAY,aAAa,EAAE,IAAI,aAAa,YAAY,EAAE,6BAA6B,IAAI,EAAE,yBAAyB,CAAC,cAClL,8CAA8C,EAAE,gCAAgC,CAAC,KAAK,EAAE,yBAAyB,CAAC;AAAA,mCACrF,EAAE,gCAAgC,CAAC;AAEpE,QAAM,gBAAgB,aAAa,SAC/B,8BAA8B,QAAQ;AAAA,oCACR,EAAE,eAAe,QAAQ,CAAC,CAAC;AAAA,WACpD,YAAY,2BAA2B,QAAQ,UAAU,MAAM,GAAG,GAAI,CAAC,CAAC,WAAW,EAAE;AAAA,iBAE1F;AAEJ,SAAO;AAAA;AAAA;AAAA,4CAG4B,WAAW,QAAQ,QAAQ,IAAI,EAAE,sBAAsB,CAAC;AAAA,uCACtD,EAAE,yBAAyB,CAAC;AAAA;AAAA;AAAA,UAGzD,WACE,2CAA2C,cAAc,mBAAmB,IAAI,gBAAgB,CAAC,CAAC,WAClG,2DAA2D,QAAQ,eAAe,EAAE,CAAC,aAAa;AAAA,UACpG,eAAe;AAAA;AAAA,QAEjB,aAAa;AAAA;AAAA,UAEX,aAAa;AAAA,UACb,aAAa,gCAAgC,WAAW,oBAAoB,EAAE,KAAK,EAAE,uBAAuB,CAAC,cAAc,EAAE;AAAA,UAC7H,aAAa,CAAC,WAAW,qDAAqD,EAAE,2BAA2B,CAAC,KAAK,EAAE,yBAAyB,CAAC,cAAc,EAAE;AAAA,iDACtH,EAAE,uBAAuB,CAAC;AAAA,iCAC1C,QAAQ,cAAc,EAAE,wBAAwB,CAAC,CAAC;AAAA;AAAA;AAGnF;;;AC1IO,IAAM,qBAAN,cAAiC,YAAY;AAAA,EAC1C;AAAA,EACA,WAAuC;AAAA,EAE/C,WAA0B;AAAA,EAC1B,aAAa;AAAA,EACb,cAAkC;AAAA,EAClC,UAAU;AAAA,EACV,oBAAoB;AAAA,EACpB,QAAQ;AAAA,EACR,WAAqB,CAAC;AAAA,EACtB,eAAyB,CAAC;AAAA;AAAA,EAE1B,YAAY;AAAA;AAAA,EAEZ,UAAU,YAAY,OAAO,SAAS,QAAQ;AAAA,EACtC,eAA8B;AAAA,EAC9B,mBAAkC;AAAA,EAClC,YAAY;AAAA,EACZ,YAAsB;AAAA,EACtB,aAAa;AAAA,EAErB,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AACxB,QAAI,CAAC,KAAK,WAAY,MAAK,aAAa,KAAK,YAAY,UAAU,wBAAwB;AAC3F,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,EAAE,KAAqB;AAAE,WAAO,KAAK,YAAY,UAAU,GAAG;AAAA,EAAG;AAAA,EAEzE,IAAI,cAA6B;AAAE,WAAO,KAAK;AAAA,EAAc;AAAA,EAC7D,IAAI,YAAY,GAAkB;AAChC,QAAI,KAAK,qBAAqB,KAAM,MAAK,mBAAmB;AAC5D,SAAK,eAAe;AACpB,QAAI,KAAK,SAAU,MAAK,SAAS,QAAQ,KAAK;AAAA,QACzC,MAAK,OAAO;AAAA,EACnB;AAAA,EAEA,WAAiB;AACf,UAAM,UAAU,KAAK,UAAU,SAAS,KAAK,gBAAgB;AAC7D,SAAK,cAAc,IAAI,YAAY,QAAQ,EAAE,QAAQ,SAAS,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EAChG;AAAA,EAEA,UAAgB;AACd,SAAK,cAAc,IAAI,YAAY,SAAS,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,WAAW,UAAkC;AACjD,QAAI,CAAC,KAAK,QAAS;AACnB,UAAM,OAAO,YAAY,KAAK,YAAY;AAC1C,QAAI,CAAC,KAAM;AAEX,SAAK,YAAY;AACjB,SAAK,aAAa;AAClB,SAAK,OAAO;AAEZ,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,UAAU,KAAK,CAAC;AAAA,MACzC,CAAC;AACD,UAAI,CAAC,SAAS,GAAI,OAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,EAAE;AAC3D,YAAM,SAAS,MAAM,SAAS,KAAK;AACnC,WAAK,aAAa,OAAO,UAAU;AACnC,WAAK,YAAY,OAAO,UAAU,WAAW;AAAA,IAC/C,QAAQ;AACN,WAAK,YAAY;AACjB,WAAK,aAAa;AAClB,gBAAU,KAAK,EAAE,+BAA+B,GAAG,KAAK;AAAA,IAC1D;AACA,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,gBAAgB,MAAoB;AAClC,cAAU,WAAW,UAAU,IAAI;AAAA,EACrC;AAAA,EAEA,aAAmB;AACjB,SAAK,YAAY,CAAC,KAAK;AACvB,SAAK,OAAO;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eAAqB;AACnB,UAAM,OAAO,KAAK,UAAU,SAAS,KAAK,gBAAgB;AAC1D,QAAI,UAAU;AACd,QAAI,KAAK,mBAAmB;AAC1B,YAAM,SAAS,kCAAkC,iBAAiB,SAAS,KAAK,iBAAiB;AACjG,UAAI,OAAQ,WAAU;AAAA,IACxB;AACA,QAAI,KAAK,SAAS;AAChB,YAAM,UAAU,KAAK,QAAQ,kCAAkC,kBAAkB,KAAK,KAAK,IAAI,OAAO;AACtG,YAAM,SAAS,kCAAkC,cAAc,SAAS,UAAU,KAAK,OAAO;AAC9F,UAAI,OAAQ,WAAU;AAAA,IACxB;AACA,QAAI,YAAY,MAAM;AACpB,gBAAU,KAAK,EAAE,2BAA2B,GAAG,KAAK;AACpD;AAAA,IACF;AACA,SAAK,eAAe;AACpB,SAAK,OAAO;AACZ,cAAU,KAAK,EAAE,0BAA0B,CAAC;AAAA,EAC9C;AAAA,EAEQ,SAAe;AACrB,SAAK,OAAO,YAAY,UAAU,mBAAmB,WAAW,kBAAkB;AAAA,MAChF,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,MACf,aAAa,KAAK;AAAA,MAClB,iBAAiB,KAAK;AAAA,MACtB,gBAAgB,KAAK,UAAU,SAAS,KAAK,gBAAgB;AAAA,MAC7D,SAAS,KAAK;AAAA,MACd,mBAAmB,KAAK;AAAA,MACxB,YAAY,KAAK;AAAA,MACjB,SAAS,KAAK;AAAA,MACd,UAAU,KAAK;AAAA,MACf,WAAW,KAAK;AAAA,IAClB,GAAG,KAAK,EAAE,KAAK,IAAI,CAAC,CAAC;AAErB,SAAK,WAAW,KAAK,OAAO,eAAe,QAAQ;AACnD,QAAI,KAAK,UAAU;AACjB,YAAM,KAAK,KAAK;AAChB,WAAK,SAAS,iBAAiB,SAAS,MAAM;AAC5C,aAAK,eAAe,GAAG;AAAA,MACzB,CAAC;AAAA,IACH;AACA,SAAK,OAAO,eAAe,UAAU,GAAG,iBAAiB,SAAS,MAAM,KAAK,SAAS,CAAC;AACvF,SAAK,OAAO,eAAe,WAAW,GAAG,iBAAiB,SAAS,MAAM,KAAK,QAAQ,CAAC;AACvF,SAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,MAAM,KAAK,WAAW,CAAC;AAC3F,SAAK,OAAO,eAAe,UAAU,GAAG,iBAAiB,SAAS,MAAM;AACtE,WAAK,gBAAgB,KAAK,UAAU,SAAS,KAAK,gBAAgB,EAAE;AAAA,IACtE,CAAC;AACD,SAAK,OAAO,eAAe,UAAU,GAAG,iBAAiB,SAAS,MAAM,KAAK,WAAW,CAAC;AACzF,SAAK,OAAO,eAAe,YAAY,GAAG,iBAAiB,SAAS,MAAM,KAAK,aAAa,CAAC;AAC7F,SAAK,OAAO,eAAe,aAAa,GAAG,iBAAiB,SAAS,MAAM;AACzE,WAAK,gBAAgB,KAAK,OAAO;AAAA,IACnC,CAAC;AACD,SAAK,OAAO,eAAe,cAAc,GAAG,iBAAiB,SAAS,MAAM;AAC1E,WAAK,gBAAgB,KAAK,iBAAiB;AAAA,IAC7C,CAAC;AAAA,EACH;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,sBAAsB,GAAG;AAC/C,iBAAe,OAAO,wBAAwB,kBAAkB;AAClE;;;ACvKO,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAjC;AAaA,IAAM,qBAAgC;AAAA,EACpC,EAAE,OAAO,sBAAsB,OAAO,CAAC,oBAAoB,kBAAkB,EAAE;AAAA,EAC/E;AAAA,IACE,OAAO;AAAA,IACP,OAAO,CAAC,kBAAkB,iBAAiB,iBAAiB,oBAAoB,kBAAkB,sBAAsB,cAAc;AAAA,EACxI;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,CAAC,kBAAkB,qBAAqB,uBAAuB,iBAAiB,kBAAkB,mBAAmB,iBAAiB,kBAAkB,eAAe;AAAA,EAChL;AAAA,EACA,EAAE,OAAO,mBAAmB,OAAO,CAAC,iBAAiB,eAAe,EAAE;AAAA,EACtE,EAAE,OAAO,mBAAmB,OAAO,CAAC,oBAAoB,uBAAuB,qBAAqB,kBAAkB,EAAE;AAAA,EACxH,EAAE,OAAO,qBAAqB,OAAO,CAAC,mBAAmB,iBAAiB,EAAE;AAAA,EAC5E,EAAE,OAAO,iBAAiB,OAAO,CAAC,eAAe,aAAa,EAAE;AAAA,EAChE,EAAE,OAAO,qBAAqB,OAAO,CAAC,sBAAsB,mBAAmB,qBAAqB,iBAAiB,gBAAgB,EAAE;AACzI;AAEA,IAAM,iBAA4B;AAAA,EAChC,EAAE,OAAO,uBAAuB,OAAO,CAAC,eAAe,eAAe,eAAe,eAAe,aAAa,EAAE;AAAA,EACnH,EAAE,OAAO,sBAAsB,OAAO,CAAC,gBAAgB,gBAAgB,gBAAgB,gBAAgB,gBAAgB,gBAAgB,cAAc,EAAE;AAAA,EACvJ,EAAE,OAAO,yBAAyB,OAAO,CAAC,eAAe,eAAe,eAAe,eAAe,aAAa,EAAE;AACvH;AAEA,SAAS,aAAa,UAAqB,GAAoC;AAC7E,SAAO,SACJ;AAAA,IACC,CAAC,MAAM;AAAA;AAAA,oCAEuB,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;AAAA,kCACrB,EAAE,MAAM,IAAI,CAAC,MAAM,OAAO,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA,EAEtF,EACC,KAAK,EAAE;AACZ;AAEO,SAAS,gBAAgB,GAA4B,YAAqB,aAAqB;AACpG,QAAM,MAAM,CAAC,IAAa,QACxB,2BAA2B,cAAc,KAAK,WAAW,EAAE,eAAe,EAAE,KAAK,QAAQ,EAAE,GAAG,CAAC,CAAC;AAElG,QAAM,OACJ,cAAc,UACV,yBAAyB,QAAQ,EAAE,kBAAkB,CAAC,CAAC,OAAO,aAAa,gBAAgB,CAAC,CAAC,KAC7F,yBAAyB,QAAQ,EAAE,YAAY,CAAC,CAAC,OAAO,aAAa,oBAAoB,CAAC,CAAC;AAEjG,SAAO;AAAA;AAAA;AAAA,UAGC,IAAI,aAAa,oBAAoB,CAAC;AAAA,UACtC,IAAI,SAAS,gBAAgB,CAAC;AAAA;AAAA,gDAEQ,SAAS,KAAK,IAAI;AAAA;AAElE;;;ACxDO,IAAM,mBAAN,cAA+B,YAAY;AAAA,EACxC;AAAA,EACA,YAAqB;AAAA,EAC7B;AAAA,EAEA,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AACxB,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,SAAK,OAAO;AAAA,EACd;AAAA,EAEQ,SAAe;AACrB,SAAK,OAAO,YACV,UAAU,iBAAiB,WAAW,gBAAgB,KAAK,YAAY,UAAU,KAAK,KAAK,WAAW,GAAG,KAAK,SAAS,CAAC;AAC1H,SAAK,OAAO,iBAA8B,YAAY,EAAE,QAAQ,CAAC,QAAQ;AACvE,UAAI,iBAAiB,SAAS,MAAM;AAClC,aAAK,YAAa,IAAI,QAAQ,KAAK,KAAiB;AACpD,aAAK,OAAO;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,oBAAoB,GAAG;AAC7C,iBAAe,OAAO,sBAAsB,gBAAgB;AAC9D;;;ACtCA,IAAAC,sBAA6C;;;ACE7C,IAAM,aAAgC,CAAC,WAAW,YAAY,aAAa,YAAY;AAOvF,SAAS,kBAA0B;AACjC,SAAO,WAAW,IAAI,CAAC,QAAQ;AAC7B,UAAM,KAAK,IAAI,WAAW,IAAI,IAAI,WAAW;AAC7C,UAAM,KAAK,IAAI,SAAS,MAAM,IAAI,UAAU;AAC5C,UAAM,KAAK,OAAO,WAAW,QAAQ;AACrC,UAAM,KAAK,OAAO,UAAU,SAAS;AACrC,UAAM,MAAM,wBAAwB,GAAG;AACvC,WAAO;AAAA,QACH,GAAG,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE;AAAA,QAC/D,GAAG,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE;AAAA,QAC/D,GAAG,mBAAmB,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,6BAA6B,EAAE,IAAI,EAAE;AAAA;AAAA,EAE1G,CAAC,EAAE,KAAK,IAAI;AACd;AAEO,SAAS,kBAAkB,KAAc,QAAyB;AACvE,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAgCW,MACV,oDACA,iDAAiD;AAAA;AAAA,oBAEvC,MACV,iEACA,gEAAgE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMlE,MAAM,qDAAqD,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAqBpD,MAAM,SAAS,MAAM;AAAA;AAAA;AAAA,oBAGlB,SACV,oDACA,qBAAqB;AAAA,eAChB,SAAS,SAAS,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MA4DpC,gBAAgB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAQH,SACV,2CACA,wCAAwC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAU9B,SACV,mCACA,+BAA+B;AAAA,iBACxB,MAAM,UAAU,MAAM;AAAA,QAC/B,CAAC,SAAS,oDAAoD,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOxE;;;AC3LO,SAAS,qBAAqB,KAAc,QAAiB,GAAoC;AACtG,SAAO;AAAA;AAAA;AAAA;AAAA,qEAIkD,EAAE,qBAAqB,CAAC;AAAA;AAAA,kEAExB,EAAE,oBAAoB,CAAC;AAAA;AAAA,qEAEvB,EAAE,uBAAuB,CAAC;AAAA;AAAA,kEAE1B,EAAE,oBAAoB,CAAC;AAAA;AAAA,+DAExB,EAAE,mBAAmB,CAAC;AAAA;AAAA;AAAA,uBAGzD,SAAS,EAAE,uBAAuB,IAAI,EAAE,sBAAsB,CAAC;AAAA,UAC5E,SAAS,WAAM,QAAG;AAAA;AAAA;AAAA,uBAGL,MAAM,EAAE,qBAAqB,IAAI,EAAE,sBAAsB,CAAC;AAAA,UACvE,MAAM,WAAM,QAAG;AAAA;AAAA;AAAA,6BAGI,SAAS,EAAE,uBAAuB,IAAI,EAAE,oBAAoB,CAAC;AAC1F;;;ACzBA;AAEA,IAAM,sBAAsB,oBAAI,IAAI,CAAC,cAAc,aAAa,eAAe,YAAY,CAAC;AAErF,SAAS,uBACd,WACA,GACA,cACM;AACN,YAAU,mBAAmB,aAAa;AAAA;AAAA;AAAA;AAAA,UAIlC,EAAE,4BAA4B,CAAC;AAAA;AAAA;AAAA;AAAA,yBAIhB,EAAE,6BAA6B,EAAE,QAAQ,MAAM,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,4DAiBrB,EAAE,0BAA0B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAO7E,EAAE,yBAAyB,CAAC;AAAA;AAAA;AAAA,WAG7B;AAET,WAAS,eAAe,mBAAmB,GAAG,iBAAiB,SAAS,MAAM;AAC5E,UAAM,MAAQ,SAAS,eAAe,iBAAiB,EAAuB,MAAM,KAAK;AACzF,UAAM,OAAQ,SAAS,eAAe,aAAa,EAA4B;AAC/E,UAAM,MAAQ,SAAS,eAAe,cAAc,EAA0B,MAAM,KAAK;AACzF,QAAI,CAAC,IAAK;AACV,UAAM,IAAI,mBAAmB,GAAG;AAChC,UAAM,IAAI,mBAAmB,GAAG;AAChC,UAAM,MAAM,oBAAoB,IAAI,IAAI,KAAK,CAAC,MAC1C,WAAW,CAAC,cAAc,IAAI,OAC9B,WAAW,CAAC,cAAc,IAAI,OAAO,CAAC;AAC1C,iBAAa,GAAG;AAChB,IAAC,SAAS,eAAe,iBAAiB,EAAuB,QAAQ;AACzE,IAAC,SAAS,eAAe,cAAc,EAA0B,QAAQ;AAAA,EAC3E,CAAC;AACH;;;AC5DO,SAAS,4BACd,WACA,GACA,QACA,UACM;AACN,YAAU,YAAY;AAAA;AAAA,WAEb,EAAE,wBAAwB,CAAC;AAAA;AAAA,UAE5B,EAAE,iCAAiC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,+CAKC,EAAE,4BAA4B,CAAC;AAAA,8DAC/B,EAAE,4BAA4B,CAAC;AAAA;AAAA;AAAA,UAGpE,EAAE,6BAA6B,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAM9B,EAAE,uBAAuB,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,YAK1B,EAAE,wBAAwB,CAAC;AAAA;AAAA;AAAA;AAKrC,WAAS,eAAe,SAAS,GAAG,iBAAiB,SAAS,MAAM;AAAE,SAAK,OAAO;AAAA,EAAG,CAAC;AACtF,WAAS,eAAe,WAAW,GAAG,iBAAiB,SAAS,MAAM;AAAE,SAAK,SAAS;AAAA,EAAG,CAAC;AAC5F;;;ACrCO,SAAS,qBACd,SACA,WACA,OACA,QACG;AACH,QAAM,KAAK,SAAS,cAAc,OAAO;AACzC,SAAO,OAAO,IAAI,KAAK;AACvB,YAAU,YAAY,EAAqB;AAC3C,aAAW,EAAE,MAAM,QAAQ,KAAK,UAAU,CAAC,GAAG;AAC5C,IAAC,GAA8B,iBAAiB,MAAM,OAAwB;AAAA,EAChF;AACA,SAAO;AACT;;;ACCO,IAAM,gBAAgB;AAGtB,IAAM,iBAAiB;AAG9B,IAAM,sBAAsB;AAOrB,SAAS,sBAAsB,KAA6B;AACjE,SAAO;AAAA,IACL,GAAG,IAAI,SAAS,MAAM,IAAI,MAAM;AAAA,IAChC,GAAG,IAAI,WAAW,IAAI,IAAI,MAAM;AAAA,EAClC;AACF;AAGO,SAAS,oBACd,GACA,GACA,IACA,IACA,SAAiB,eACV;AACP,QAAM,OAAO,KAAK,IAAI,QAAQ,KAAK,MAAM;AACzC,QAAM,OAAO,KAAK,IAAI,QAAQ,KAAK,MAAM;AACzC,SAAO;AAAA,IACL,GAAG,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,IAAI;AAAA,IACrC,GAAG,KAAK,IAAI,KAAK,IAAI,GAAG,MAAM,GAAG,IAAI;AAAA,EACvC;AACF;AAMO,SAAS,uBAAuB,GAAW,GAAW,IAAY,IAA6B;AACpG,QAAM,WAAW,IAAI,KAAK,IAAI,SAAS;AACvC,QAAM,aAAa,IAAI,KAAK,IAAI,UAAU;AAC1C,SAAO,GAAG,QAAQ,IAAI,UAAU;AAClC;AAGO,SAAS,sBAAsB,IAAY,IAAmB;AACnE,SAAO,EAAE,GAAG,KAAK,qBAAqB,GAAG,KAAK,oBAAoB;AACpE;AAGO,SAAS,cAAc,cAAqB,KAA6B;AAC9E,QAAM,MAAM,sBAAsB,GAAG;AACrC,SAAO,EAAE,GAAG,aAAa,IAAI,IAAI,GAAG,GAAG,aAAa,IAAI,IAAI,EAAE;AAChE;;;ACnDO,SAAS,sBACd,cACA,UACU;AACV,QAAM,eAAe,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC;AACxD,SAAO,aAAa,IAAI,CAAC,QAAQ;AAC/B,UAAM,QAAQ,IAAI,MAAM,oBAAoB;AAC5C,QAAI,CAAC,MAAO,QAAO;AACnB,UAAM,cAAc,GAAG,MAAM,CAAC,CAAC;AAC/B,QAAI,CAAC,aAAa,IAAI,WAAW,EAAG,QAAO;AAC3C,WAAO,IAAI,QAAQ,YAAY,iBAAiB,WAAW,UAAU;AAAA,EACvE,CAAC;AACH;AASO,SAAS,qBACd,UACA,UACU;AACV,QAAM,iBAAiB,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK,QAAQ,WAAW,EAAE,CAAC,CAAC;AACjF,SAAO,SAAS,IAAI,CAAC,QAAQ;AAC3B,UAAM,QAAQ,IAAI,MAAM,yBAAyB;AACjD,QAAI,CAAC,SAAS,CAAC,eAAe,IAAI,MAAM,CAAC,CAAC,EAAG,QAAO;AACpD,WAAO,aAAa,MAAM,CAAC,CAAC;AAAA,EAC9B,CAAC;AACH;;;AP2BO,IAAM,wBAAN,cAAoC,YAAY;AAAA,EAC7C;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,uBAAuB;AAAA;AAAA,EAGvB,YAA0B;AAAA,EAC1B,YAA6B;AAAA,EAC7B;AAAA,EACA,0BAA0B;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAA2E;AAAA,EAC3E;AAAA,EACA,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,EACzB,qBAAyC,EAAE,GAAG,6BAA6B;AAAA,EAEnF;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,WAAW;AAAA,EACX,kBAA4B,CAAC;AAAA,EAC7B,eAAyB,CAAC;AAAA,EAE1B,uBAAuB;AAAA,EACvB,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,uBAAuB;AAAA,EACvB,6BAA6B;AAAA,EAC7B,mBAAmB;AAAA,EAEnB,cAAc;AACZ,UAAM;AACN,SAAK,SAAS,KAAK,aAAa,EAAE,MAAM,OAAO,CAAC;AAAA,EAClD;AAAA,EAEA,oBAA0B;AACxB,QAAI,aAAa,QAAQ;AACvB,WAAK,cAAc;AACnB;AAAA,IACF;AACA,QAAI,CAAC,KAAK,aAAa,SAAS,GAAG;AACjC,WAAK,aAAa,WAAW,4BAA4B;AAAA,IAC3D;AAGA,QAAI,CAAC,KAAK,aAAa,KAAK,wBAAwB;AAClD,WAAK,YAAY,IAAI,iBAAiB;AACtC,WAAK,yBAAyB;AAAA,IAChC;AACA,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AACjE,QAAI,CAAC,KAAK,YAAa,MAAK,cAAc,IAAI,mBAAmB;AAEjE,SAAK,cAAc,IAAI,YAAY,KAAK,SAAS;AACjD,SAAK,YAAY,QAAQ;AAEzB,iBAAa,yCAAyC,sBAAsB;AAC5E,iBAAa,kBAAkB,0BAA0B;AAEzD,SAAK,eAAe;AACpB,SAAK,aAAa;AAClB,SAAK,qBAAqB;AAC1B,SAAK,qBAAqB;AAC1B,SAAK,kBAAkB;AACvB,SAAK,OAAO;AACZ,SAAK,eAAe;AACpB,SAAK,sBAAsB;AAC3B,SAAK,mBAAmB;AAExB,SAAK,iBAAiB,CAAC,MAAqB,KAAK,oBAAoB,CAAC;AACtE,WAAO,iBAAiB,WAAW,KAAK,cAAc;AAItD,SAAK,oBAAoB,CAAC,MAAkB,KAAK,oBAAoB,CAAC;AACtE,SAAK,kBAAkB,MAAM,KAAK,kBAAkB;AACpD,SAAK,eAAe,MAAM,KAAK,oBAAoB;AACnD,WAAO,iBAAiB,eAAe,KAAK,iBAAkC;AAC9E,WAAO,iBAAiB,aAAa,KAAK,eAAe;AACzD,WAAO,iBAAiB,UAAU,KAAK,YAAY;AAAA,EACrD;AAAA,EAEA,uBAA6B;AAC3B,QAAI,KAAK,YAAa;AACtB,WAAO,oBAAoB,WAAW,KAAK,cAAc;AAKzD,SAAK,+BAA+B;AACpC,SAAK,iBAAiB;AACtB,SAAK,gBAAgB;AACrB,SAAK,oBAAoB;AACzB,SAAK,aAAa;AAClB,SAAK,wBAAwB;AAC7B,SAAK,YAAY;AACjB,SAAK,eAAe;AACpB,QAAI,KAAK,kBAAmB,QAAO,oBAAoB,eAAe,KAAK,iBAAkC;AAC7G,QAAI,KAAK,gBAAiB,QAAO,oBAAoB,aAAa,KAAK,eAAe;AACtF,QAAI,KAAK,aAAc,QAAO,oBAAoB,UAAU,KAAK,YAAY;AAC7E,SAAK,aAAa,UAAU;AAC5B,SAAK,UAAU,QAAQ;AAOvB,SAAK,yBAAyB;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,iBAAgC;AAC5C,UAAM,SAAS,MAAM,KAAK,YAAY,UAAU,sBAAsB;AACtE,QAAI,WAAW,MAAM;AACnB,YAAM,KAAK,YAAY,UAAU,EAAE,sBAAsB,OAAO,CAAC;AACjE,mBAAa,QAAQ,wBAAwB,MAAM;AAAA,IACrD,OAAO;AACL,mBAAa,QAAQ,wBAAyB,OAAO,sBAAsB,KAAgB,MAAM;AAAA,IACnG;AACA,UAAM,KAAK,MAAM,KAAK,YAAY,UAAU,aAAa;AACzD,iBAAa,QAAQ,eAAgB,KAAK,aAAa,KAAgB,OAAO;AAAA,EAChF;AAAA,EAEA,MAAc,eAA8B;AAC1C,UAAM,SAAS,MAAM,KAAK,YAAY,UAAU,UAAU;AAC1D,UAAM,OAAO,SAAS,UAAU;AAChC,SAAK,YAAY,QAAQ,QAAQ,KAAK,YAAY,WAAW,CAAC;AAAA,EAChE;AAAA,EAEQ,oBAA0B;AAChC,SAAK,iBAAiB,KAAK,UAAU,kBAAkB,CAAC,QAAQ;AAC9D,WAAK,cAAc;AACnB,UAAI,CAAC,OAAO,CAAC,KAAK,sBAAsB;AACtC,aAAK,qBAAqB;AAG1B,aAAK,wBAAwB;AAC7B,aAAK,mBAAmB;AAAA,MAC1B;AACA,WAAK,uBAAuB;AAC5B,WAAK,OAAO;AAAA,IACd,CAAC;AAGD,SAAK,eAAe,KAAK,UAAU,gBAAgB,CAAC,UAAU,KAAK,qBAAqB,KAAK,CAAC;AAC9F,SAAK,gBAAgB,KAAK,UAAU,iBAAiB,CAAC,SAAS;AAC7D,WAAK,kBAAkB;AACvB,UAAI,KAAK,kBAAmB,MAAK,kBAAkB,WAAW;AAAA,IAChE,CAAC;AACD,SAAK,oBAAoB,KAAK,UAAU,qBAAqB,CAAC,SAAS;AACrE,WAAK,eAAe;AACpB,UAAI,KAAK,kBAAmB,MAAK,kBAAkB,eAAe;AAAA,IACpE,CAAC;AACD,SAAK,aAAa,KAAK,UAAU,cAAc,CAAC,WAAW;AACzD,WAAK,WAAW;AAChB,WAAK,OAAO;AAAA,IACd,CAAC;AACD,SAAK,wBAAwB,KAAK,UAAU,mBAAmB,CAAC,WAAW;AACzE,UAAI,KAAK,qBAAsB,MAAK,mBAAmB,MAAM;AAAA,IAC/D,CAAC;AAED,SAAK,YAAY,KAAK,YAAY,aAAa,MAAM,KAAK,OAAO,CAAC;AAAA,EACpE;AAAA,EAEQ,mBAAmB,QAA2B;AACpD,oFAA2D,KAAK,MAAM;AACpE,YAAM,WAAW,SAAS,cAAc,yBAAyB;AACjE,UAAI,SAAU,UAAS,OAAO;AAE9B,YAAM,SAAS,SAAS,cAAc,yBAAyB;AAC/D,aAAO,gBAAgB;AACvB,aAAO,YAAY,KAAK;AACxB,aAAO,cAAc,KAAK;AAC1B,eAAS,KAAK,YAAY,MAAyB;AAAA,IACrD,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,iBAAgC;AAC5C,QAAI,KAAK,aAAa,cAAc,GAAG;AAErC,WAAK,YAAY,KAAK,aAAa,cAAc,MAAM;AACvD,WAAK,MAAM,UAAU,KAAK,YAAY,KAAK;AAC3C;AAAA,IACF;AACA,UAAM,SAAS,MAAM,KAAK,YAAY,iBAAiB;AACvD,SAAK,YAAY,SAAS,aAAa,MAAM;AAC7C,SAAK,MAAM,UAAU,KAAK,YAAY,KAAK;AAAA,EAC7C;AAAA,EAEA,MAAc,uBAAsC;AAClD,UAAM,SAAS,MAAM,KAAK,YAAY,iBAAiB;AACvD,UAAM,WAAW,SAAS,kBAAkB;AAC5C,QAAI,SAAU,MAAK,UAAU,mBAAmB;AAChD,SAAK,uBAAuB,SAAS,sBAAsB,MAAM;AACjE,SAAK,qBAAqB;AAAA,MACxB,SAAU,SAAS,qBAAqB,MAAO;AAAA,MAC/C,UAAW,SAAS,sBAAsB,KAA8B,6BAA6B;AAAA,MACrG,SAAW,SAAS,qBAAqB,KAAiB;AAAA,IAC5D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,wBAAuC;AACnD,QAAI,KAAK,YAAa;AACtB,UAAM,UAAU,MAAM,KAAK,YAAY,iBAAiB;AACxD,QAAI,CAAC,WAAW,CAAC,QAAQ,YAAa;AACtC,UAAM,SAAS,MAAM,KAAK,oBAAoB;AAC9C,UAAM,QAAQ,KAAK,IAAI,IAAI,QAAQ;AACnC,QAAI,SAAS,SAAS,KAAQ;AAC5B,WAAK,mBAAmB,OAAO;AAAA,IACjC,OAAO;AACL,WAAK,sBAAsB,OAAO;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,MAAc,sBAAuC;AACnD,UAAM,SAAS,MAAM,KAAK,YAAY,UAAU,qBAAqB;AACrE,UAAM,MAAM,SAAS,qBAAqB;AAC1C,UAAM,IAAI,OAAO,QAAQ,WAAW,MAAM,OAAO,GAAG;AACpD,WAAO,OAAO,SAAS,CAAC,KAAK,IAAI,IAAI,IAAI;AAAA,EAC3C;AAAA;AAAA,EAGQ,mBAAmB,SAAmC;AAC5D,SAAK,UAAU,eAAe,OAAO;AACrC,SAAK,kBAAkB,QAAQ;AAC/B,SAAK,eAAe,QAAQ;AAC5B,SAAK,uBAAuB;AAC5B,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,MAAc,sBAAsB,SAA4C;AAC9E,UAAM,IAAI,KAAK,YAAY,UAAU,KAAK,KAAK,WAAW;AAC1D,UAAM,SAAS,MAAM,oBAAAC,QAAK,KAAK;AAAA,MAC7B,OAAO,EAAE,+BAA+B;AAAA,MACxC,MACE,gFACM,EAAE,8BAA8B,CAAC,kDACO,QAAQ,SAAS,MAAM,QAAQ,EAAE,+BAA+B,CAAC;AAAA,MAEjH,kBAAkB;AAAA,MAClB,mBAAmB,EAAE,+BAA+B;AAAA,MACpD,kBAAkB,EAAE,8BAA8B;AAAA,MAClD,OAAO;AAAA,IACT,CAAC;AACD,QAAI,UAAW,OAAqC,aAAa;AAC/D,WAAK,mBAAmB,OAAO;AAAA,IACjC,OAAO;AACL,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA,EAGQ,qBAAqB,OAAiC;AAC5D,QAAI,KAAK,YAAa;AACtB,QAAI,CAAC,MAAM,aAAa;AACtB,WAAK,wBAAwB;AAC7B;AAAA,IACF;AACA,SAAK,uBAAuB,KAAK;AACjC,QAAI,KAAK,iBAAkB,cAAa,KAAK,gBAAgB;AAC7D,SAAK,mBAAmB,WAAW,MAAM;AACvC,YAAM,OAAO,KAAK,UAAU,mBAAmB;AAC/C,UAAI,KAAK,YAAa,MAAK,YAAY,kBAAkB,IAAI,EAAE,MAAM,MAAM;AAAA,MAAqC,CAAC;AAAA,IACnH,GAAG,GAAG;AAAA,EACR;AAAA,EAEQ,uBAAuB,OAAiC;AAC9D,QAAI;AACF,mBAAa,QAAQ,+BAA+B,KAAK,UAAU;AAAA,QACjE,WAAW,MAAM;AAAA,QACjB,aAAa,MAAM;AAAA,QACnB,WAAW,MAAM;AAAA,MACnB,CAAC,CAAC;AAAA,IACJ,QAAQ;AAAA,IAA8B;AAAA,EACxC;AAAA,EAEQ,iCAAuC;AAC7C,UAAM,OAAO,KAAK,UAAU,mBAAmB;AAC/C,QAAI,CAAC,KAAK,YAAa;AACvB,QAAI,KAAK,iBAAkB,cAAa,KAAK,gBAAgB;AAC7D,SAAK,uBAAuB,IAAI;AAChC,SAAK,YAAY,kBAAkB,IAAI,EAAE,MAAM,MAAM;AAAA,IAAkB,CAAC;AAAA,EAC1E;AAAA,EAEQ,0BAAgC;AACtC,QAAI,KAAK,kBAAkB;AAAE,mBAAa,KAAK,gBAAgB;AAAG,WAAK,mBAAmB;AAAA,IAAW;AACrG,QAAI;AAAE,mBAAa,WAAW,6BAA6B;AAAA,IAAG,QAAQ;AAAA,IAAe;AACrF,SAAK,YAAY,mBAAmB,EAAE,MAAM,MAAM;AAAA,IAAkB,CAAC;AAAA,EACvE;AAAA;AAAA,EAGA,mBAA4B;AAC1B,QAAI;AACF,YAAM,MAAM,aAAa,QAAQ,6BAA6B;AAC9D,UAAI,CAAC,IAAK,QAAO;AACjB,aAAO,CAAC,CAAE,KAAK,MAAM,GAAG,EAAgC;AAAA,IAC1D,QAAQ;AAAE,aAAO;AAAA,IAAO;AAAA,EAC1B;AAAA;AAAA,EAGA,gBAAsB;AACpB,SAAK,YAAY,iBAAiB,EAAE,KAAK,CAAC,MAAM;AAAE,UAAI,EAAG,MAAK,mBAAmB,CAAC;AAAA,IAAG,CAAC;AAAA,EACxF;AAAA;AAAA,EAGA,iBAAuB;AACrB,SAAK,wBAAwB;AAAA,EAC/B;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAoC;AAChD,UAAM,SAAS,MAAM,KAAK,YAAY,iBAAiB;AACvD,UAAM,MAAM,SAAS,gBAAgB;AACrC,QAAI,OAAO,OAAO,IAAI,MAAM,YAAY,OAAO,IAAI,MAAM,UAAU;AACjE,WAAK,YAAY,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,EAAE;AAAA,IACxC;AACA,SAAK,oBAAoB;AAAA,EAC3B;AAAA;AAAA,EAGQ,sBAA4B;AAClC,UAAM,SAAS,KAAK,OAAO,cAAc,SAAS;AAClD,QAAI,CAAC,OAAQ;AACb,UAAM,KAAK,OAAO;AAClB,UAAM,KAAK,OAAO;AAClB,UAAM,SAAS,KAAK,aAAa,sBAAsB,IAAI,EAAE;AAC7D,UAAM,UAAU,oBAAoB,OAAO,GAAG,OAAO,GAAG,IAAI,EAAE;AAC9D,SAAK,YAAY,uBAAuB,QAAQ,GAAG,QAAQ,GAAG,IAAI,EAAE;AACpE,UAAM,UAAU,cAAc,SAAS,KAAK,SAAS;AACrD,WAAO,MAAM,OAAO,GAAG,QAAQ,CAAC;AAChC,WAAO,MAAM,MAAM,GAAG,QAAQ,CAAC;AAC/B,WAAO,MAAM,QAAQ;AACrB,WAAO,MAAM,SAAS;AACtB,WAAO,aAAa,eAAe,KAAK,SAAS;AAAA,EACnD;AAAA,EAEQ,gBAAgB,GAAqB;AAG3C,SAAK,0BAA0B;AAC/B,UAAM,SAAS,KAAK,aAAa,sBAAsB,OAAO,YAAY,OAAO,WAAW;AAC5F,SAAK,YAAY,EAAE,QAAQ,EAAE,SAAS,QAAQ,EAAE,SAAS,OAAO,OAAO,GAAG,OAAO,OAAO,GAAG,OAAO,MAAM;AAAA,EAC1G;AAAA,EAEQ,oBAAoB,GAAqB;AAC/C,QAAI,CAAC,KAAK,UAAW;AACrB,UAAM,KAAK,EAAE,UAAU,KAAK,UAAU;AACtC,UAAM,KAAK,EAAE,UAAU,KAAK,UAAU;AACtC,QAAI,CAAC,KAAK,UAAU,SAAS,KAAK,MAAM,IAAI,EAAE,IAAI,eAAgB;AAClE,SAAK,UAAU,QAAQ;AACvB,SAAK,YAAY,EAAE,GAAG,KAAK,UAAU,QAAQ,IAAI,GAAG,KAAK,UAAU,QAAQ,GAAG;AAC9E,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEQ,oBAA0B;AAChC,QAAI,CAAC,KAAK,UAAW;AACrB,UAAM,QAAQ,KAAK,UAAU;AAC7B,SAAK,YAAY;AACjB,QAAI,CAAC,SAAS,CAAC,KAAK,UAAW;AAE/B,SAAK,0BAA0B;AAC/B,UAAM,UAAU,oBAAoB,KAAK,UAAU,GAAG,KAAK,UAAU,GAAG,OAAO,YAAY,OAAO,WAAW;AAC7G,SAAK,YAAY;AACjB,SAAK,YAAY,UAAU,EAAE,gBAAgB,QAAQ,CAAC,EAAE,MAAM,MAAM;AAAA,IAAkB,CAAC;AAAA,EACzF;AAAA;AAAA,EAGA,sBAA4B;AAC1B,SAAK,YAAY;AACjB,SAAK,YAAY,UAAU,EAAE,gBAAgB,KAAK,CAAC,EAAE,MAAM,MAAM;AAAA,IAAkB,CAAC;AACpF,SAAK,oBAAoB;AAAA,EAC3B;AAAA,EAEA,SAAe;AACb,SAAK,UAAU,gBAAgB;AAAA,EACjC;AAAA,EAEA,cAAoB;AAClB,SAAK,UAAU,YAAY;AAAA,EAC7B;AAAA,EAEA,YAAY,MAAqB;AAC/B,UAAM,WAAW,OAAQ,OAAgB,KAAK,YAAY,WAAW;AACrE,SAAK,YAAY,QAAQ,QAAQ;AAAA,EACnC;AAAA,EAEA,oBAAoB,OAA4B;AAC9C,QAAI,CAAC,MAAM,QAAS;AACpB,UAAM,MAAM,MAAM,IAAI,YAAY;AAClC,QAAI,QAAQ,OAAO,MAAM,UAAU;AAAE,YAAM,eAAe;AAAG,WAAK,iBAAiB;AAAG;AAAA,IAAQ;AAC9F,QAAI,CAAC,KAAK,UAAW;AACrB,QAAI,QAAQ,KAAU;AAAE,YAAM,eAAe;AAAG,WAAK,OAAO;AAAA,IAAG,WACtD,QAAQ,KAAK;AAAE,YAAM,eAAe;AAAG,WAAK,YAAY;AAAA,IAAG,WAC3D,QAAQ,KAAK;AAAE,YAAM,eAAe;AAAG,WAAK,qBAAqB;AAAA,IAAG,WACpE,QAAQ,KAAK;AAAE,YAAM,eAAe;AAAG,WAAK,mBAAmB;AAAA,IAAG,WAClE,QAAQ,KAAK;AAAE,YAAM,eAAe;AAAG,WAAK,mBAAmB;AAAA,IAAG,WAClE,QAAQ,OAAO,MAAM,UAAU;AAAE,YAAM,eAAe;AAAG,WAAK,eAAe;AAAA,IAAG;AAAA,EAC3F;AAAA,EAEA,mBAAyB;AACvB,SAAK,YAAY,CAAC,KAAK;AACvB,SAAK,MAAM,UAAU,KAAK,YAAY,KAAK;AAAA,EAC7C;AAAA;AAAA,EAIQ,uBAA6B;AACnC,QAAI,CAAC,KAAK,gBAAgB,OAAQ;AAClC,QAAI;AACF,YAAM,WAAW,KAAK,MAAM,aAAa,QAAQ,uBAAuB,KAAK,IAAI;AACjF,eAAS,QAAQ,EAAE,UAAU,KAAK,iBAAiB,cAAc,KAAK,cAAc,SAAS,KAAK,IAAI,EAAE,CAAC;AACzG,UAAI,SAAS,SAAS,EAAG,UAAS,OAAO,CAAC;AAC1C,mBAAa,QAAQ,yBAAyB,KAAK,UAAU,QAAQ,CAAC;AAAA,IACxE,QAAQ;AAAA,IAA8B;AAAA,EACxC;AAAA,EAEA,uBAA6B;AAC3B,QAAI;AACF,YAAM,WAAW,KAAK,MAAM,aAAa,QAAQ,uBAAuB,KAAK,IAAI;AACjF,UAAI,CAAC,SAAS,OAAQ;AACtB,YAAM,EAAE,UAAU,aAAa,IAAI,SAAS,CAAC;AAC7C,eAAS,QAAQ,CAAC,QAAgB,KAAK,UAAU,cAAc,GAAG,CAAC;AACnE,MAAC,aAA0B,QAAQ,CAAC,SAAiB;AAAA,MAAqD,CAAC;AAAA,IAC7G,QAAQ;AAAA,IAAe;AAAA,EACzB;AAAA,EAEA,wBAA8B;AAC5B,iBAAa,WAAW,uBAAuB;AAAA,EACjD;AAAA,EAEA,sBAA8F;AAC5F,QAAI;AACF,aAAO,KAAK,MAAM,aAAa,QAAQ,uBAAuB,KAAK,IAAI;AAAA,IACzE,QAAQ;AAAE,aAAO,CAAC;AAAA,IAAG;AAAA,EACvB;AAAA;AAAA,EAIA,MAAc,uBAAsC;AAClD,UAAM,SAAS,MAAM,KAAK,YAAY,iBAAiB;AAEvD,QAAI,UAAU,yBAAyB,OAAQ;AAC/C,SAAK,0BAA0B;AAAA,EACjC;AAAA,EAEQ,4BAAkC;AACxC,UAAM,IAAI,KAAK,YAAY,UAAU,KAAK,KAAK,WAAW;AAC1D,wBAAAA,QAAK,KAAK;AAAA,MACR,OAAO,EAAE,mBAAmB;AAAA,MAC5B,MAAM;AAAA,MACN,iBAAiB;AAAA,MACjB,mBAAmB;AAAA,MACnB,SAAS,MAAM;AACb,0BAAkB;AAClB,gCAAwB;AACxB,cAAM,YAAY,SAAS,eAAe,kBAAkB;AAC5D,YAAI,CAAC,UAAW;AAChB;AAAA,UACE;AAAA,UACA;AAAA,UACA,YAAY;AACV,kBAAM,KAAK,YAAY,aAAa,uBAAuB,OAAO;AAClE,gCAAAA,QAAK,MAAM;AAAA,UACb;AAAA,UACA,YAAY;AACV,gBAAI;AACF,oBAAM,KAAK,YAAY,4BAA4B;AACnD,kCAAAA,QAAK,MAAM;AACX,wBAAU,EAAE,2BAA2B,CAAC;AAAA,YAC1C,SAAS,GAAY;AACnB,kBAAK,GAAoB,SAAS,cAAc;AAC9C,0BAAU,EAAE,yBAAyB,GAAG,KAAK;AAAA,cAC/C;AAAA,YAEF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA,EAIA,qBAA2B;AACzB,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,QACE,OAAO,KAAK,YAAY,UAAU,4BAA4B;AAAA,QAC9D,MAAM;AAAA,QACN,iBAAiB;AAAA,QAAM,mBAAmB;AAAA,QAAO,UAAU;AAAA,QAAO,OAAO;AAAA,MAC3E;AAAA,MACA,CAAC,cAAc;AACb,cAAM,QAAQ,qBAAsC,8BAA8B,WAAW;AAAA,UAC3F,aAAa,KAAK;AAAA,UAClB,UAAU,KAAK;AAAA,UACf,cAAc,KAAK;AAAA,UACnB,UAAU;AAAA,QACZ,GAAG;AAAA,UACD,EAAE,MAAM,iBAAiB,SAAS,CAAC,MAAM,KAAK,UAAU,cAAc,EAAE,MAAM,EAAE;AAAA,UAChF,EAAE,MAAM,eAAe,SAAS,CAAC,MAAM,KAAK,UAAU,YAAY,EAAE,OAAO,MAAM,EAAE,OAAO,EAAE,EAAE;AAAA,UAC9F,EAAE,MAAM,qBAAqB,SAAS,CAAC,MAAM,KAAK,UAAU,kBAAkB,EAAE,MAAM,EAAE;AAAA,QAC1F,CAAC;AACD,aAAK,oBAAoB;AACzB,+BAAuB,WAAW,KAAK,YAAY,UAAU,KAAK,KAAK,WAAW,GAAG,CAAC,QAAQ,KAAK,UAAU,cAAc,GAAG,CAAC;AAAA,MACjI;AAAA,MACA;AAAA;AAAA,QAEE,mBAAmB,MAAM;AACvB,gBAAM,gBAAgB,SAAS,cAAc,kBAAkB;AAC/D,cAAI,eAAe;AACjB,0BAAc,MAAM,gBAAgB;AACpC,kBAAM,QAAQ,cAAc,cAAc,cAAc;AACxD,gBAAI,MAAO,OAAM,MAAM,gBAAgB;AAAA,UACzC;AAAA,QACF;AAAA,QACA,aAAa,MAAM;AAAE,eAAK,oBAAoB;AAAA,QAAM;AAAA,MACtD;AAAA,IACF;AAAA,EACF;AAAA,EAEA,uBAA6B;AAC3B,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,QACE,OAAO,KAAK,YAAY,UAAU,+BAA+B;AAAA,QACjE,MAAM;AAAA,QACN,iBAAiB;AAAA,QAAM,OAAO;AAAA,MAChC;AAAA,MACA,CAAC,cAAc;AACb,6BAAmC,uBAAuB,WAAW;AAAA,UACnE,aAAa,KAAK;AAAA,UAClB,aAAa,KAAK;AAAA,UAClB,oBAAoB,KAAK;AAAA,QAC3B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,qBAA2B;AACzB,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,QACE,OAAO,KAAK,YAAY,UAAU,wBAAwB;AAAA,QAC1D,MAAM;AAAA,QACN,iBAAiB;AAAA,QAAO,mBAAmB;AAAA,QAAO,gBAAgB;AAAA,MACpE;AAAA,MACA,CAAC,cAAc;AACb,6BAAiC,qBAAqB,WAAW;AAAA,UAC/D,aAAa,KAAK;AAAA,UAClB,oBAAoB,KAAK;AAAA,QAC3B,GAAG;AAAA,UACD,EAAE,MAAM,YAAY,SAAS,CAAC,MAAM;AAClC,kBAAM,EAAE,aAAa,OAAO,MAAM,SAAS,IAAI,EAAE,UAAU,CAAC;AAC5D,iBAAK,WAAW,eAAe,MAAM,QAAQ,CAAC,GAAG,SAAS,IAAI,YAAY,EAAE;AAC5E,gCAAAA,QAAK,MAAM;AAAA,UACb,EAAC;AAAA,UACD,EAAE,MAAM,iBAAiB,SAAS,CAAC,MAAM;AACvC,kBAAM,EAAE,aAAa,OAAO,MAAM,SAAS,IAAI,EAAE,UAAU,CAAC;AAC5D,iBAAK,oBAAoB,eAAe,MAAM,QAAQ,CAAC,GAAG,SAAS,IAAI,YAAY,EAAE;AACrF,gCAAAA,QAAK,MAAM;AAAA,UACb,EAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA,MACA,EAAE,YAAY,KAAK;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,qBAA2B;AACzB,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,QACE,OAAO,KAAK,YAAY,UAAU,qBAAqB;AAAA,QACvD,MAAM;AAAA,QACN,iBAAiB;AAAA,QAAM,OAAO;AAAA,MAChC;AAAA,MACA,CAAC,cAAc;AACb,6BAA+B,yBAAyB,WAAW;AAAA,UACjE,aAAa,KAAK;AAAA,UAClB,aAAa,KAAK;AAAA,QACpB,GAAG;AAAA,UACD,EAAE,MAAM,uBAAuB,SAAS,CAAC,MAAM;AAAE,iBAAK,uBAAuB,EAAE;AAAA,UAAQ,EAAE;AAAA,UACzF,EAAE,MAAM,qBAAqB,SAAS,CAAC,MAAM;AAC3C,iBAAK,YAAY,CAAC,EAAE;AACpB,iBAAK,MAAM,UAAU,KAAK,YAAY,KAAK;AAAA,UAC7C,EAAC;AAAA,UACD,EAAE,MAAM,uBAAuB,SAAS,MAAM,KAAK,oBAAoB,EAAE;AAAA,UACzE,EAAE,MAAM,sBAAsB,SAAS,CAAC,MAAM;AAAE,iBAAK,qBAAqB,EAAE;AAAA,UAA8B,EAAE;AAAA,QAC9G,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,iBAAuB;AACrB,SAAK;AAAA,MACH;AAAA,MACA;AAAA,MACA;AAAA,QACE,OAAO,KAAK,YAAY,UAAU,YAAY;AAAA,QAC9C,MAAM;AAAA,QACN,iBAAiB;AAAA,QAAM,OAAO;AAAA,MAChC;AAAA,MACA,CAAC,cAAc;AACb,6BAAkC,sBAAsB,WAAW;AAAA,UACjE,aAAa,KAAK;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,yBAAyB,QAAuB;AAC9C,SAAK,YAAY,8BAA8B,MAAM;AACnD,0BAAAA,QAAK,KAAK;AAAA,QACR,OAAO,KAAK,YAAY,UAAU,iCAAiC;AAAA,QACnE,MAAM;AAAA,QACN,iBAAiB;AAAA,QACjB,mBAAmB;AAAA,QACnB,mBAAmB;AAAA,QACnB,OAAO;AAAA,QACP,OAAO;AAAA,QACP,SAAS,MAAM;AACb,4BAAkB;AAClB,kCAAwB;AACxB,gCAAsB,oBAAAA,QAAK,SAAS,GAAG,GAAG;AAC1C,gBAAM,YAAY,SAAS,eAAe,+BAA+B;AACzE,cAAI,CAAC,UAAW;AAChB,gBAAM,QAAQ,qBAAuC,gCAAgC,WAAW;AAAA,YAC9F,aAAa,KAAK;AAAA,YAClB,aAAa,KAAK;AAAA,YAClB,GAAI,WAAW,SAAY,EAAE,OAAO,IAAI,CAAC;AAAA,UAC3C,GAAG;AAAA,YACD,EAAE,MAAM,0BAA0B,SAAS,CAAC,MAAM;AAAE,mBAAK,UAAU,mBAAmB,EAAE;AAAA,YAAQ,EAAE;AAAA,YAClG,EAAE,MAAM,cAAc,SAAS,MAAM,oBAAAA,QAAK,MAAM,EAAE;AAAA,YAClD,EAAE,MAAM,kBAAkB,SAAS,CAAC,MAAM;AACxC,kCAAAA,QAAK,MAAM;AACX,yBAAW,MAAM,KAAK;AAAA,gBACpB,EAAE,OAAO;AAAA,gBAAQ,EAAE,OAAO;AAAA,gBAAS,EAAE,OAAO;AAAA,gBAAU,EAAE,OAAO;AAAA,gBAC/D,EAAE,OAAO;AAAA,gBAAS,EAAE,OAAO;AAAA,gBAAmB,EAAE,OAAO;AAAA,cACzD,GAAG,GAAG;AAAA,YACR,EAAC;AAAA,UACH,CAAC;AACD,eAAK,KAAK,YAAY,cAAc,EAAE,KAAK,SAAO;AAAE,kBAAM,mBAAmB;AAAA,UAAK,CAAC;AAAA,QACrF;AAAA,QACA,WAAW,MAAM;AAAE,eAAK,6BAA6B;AAAA,QAAO;AAAA,MAC9D,CAAC;AACD,iBAAW,MAAM;AACf,cAAM,QAAQ,oBAAAA,QAAK,SAAS;AAC5B,YAAI,MAAO,oBAAmB,OAAO,EAAE,UAAU,KAAK,WAAW,EAAE,CAAC;AAAA,MACtE,GAAG,CAAC;AAAA,IACN,CAAC;AAAA,EACH;AAAA,EAEQ,qBACN,QACA,SACA,UACA,QACA,UAAU,IACV,oBAAoB,IACpB,QAAQ,IACF;AACN,wBAAAA,QAAK,KAAK;AAAA,MACR,OAAO,KAAK,YAAY,UAAU,4BAA4B;AAAA,MAC9D,MAAM;AAAA,MACN,iBAAiB;AAAA,MACjB,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,MACnB,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS,MAAM;AACb,0BAAkB;AAClB,gCAAwB;AAGxB,8BAAsB,oBAAAA,QAAK,SAAS,GAAG,GAAG;AAC1C,cAAM,YAAY,SAAS,eAAe,2BAA2B;AACrE,YAAI,CAAC,UAAW;AAChB,6BAAoC,wBAAwB,WAAW;AAAA,UACrE,aAAa,KAAK;AAAA,UAClB,aAAa;AAAA,UACb;AAAA,UACA,YAAY,KAAK,YAAY,UAAU,6BAA6B;AAAA,UACpE;AAAA,UACA;AAAA,UACA;AAAA,QACF,GAAG;AAAA,UACD,EAAE,MAAM,SAAS,SAAS,MAAM;AAC9B,gCAAAA,QAAK,MAAM;AACX,uBAAW,MAAM,KAAK,yBAAyB,MAAM,GAAG,GAAG;AAAA,UAC7D,EAAC;AAAA,UACD,EAAE,MAAM,QAAQ,SAAS,OAAO,MAAM;AACpC,gBAAI;AACF,oBAAM,WAAW,MAAM,OAAO,eAAe;AAC7C,oBAAM,SAAS,MAAM,EAAE,MAAM;AAC7B,oBAAM,SAAS,MAAM;AACrB,wBAAU,KAAK,YAAY,UAAU,2BAA2B,CAAC;AAAA,YACnE,QAAQ;AACN,wBAAU,KAAK,YAAY,UAAU,gCAAgC,GAAG,KAAK;AAAA,YAC/E;AACA,gCAAAA,QAAK,MAAM;AACX,uBAAW,MAAM,KAAK,yBAAyB,MAAM,GAAG,GAAG;AAAA,UAC7D,EAAC;AAAA,QACH,CAAC;AAAA,MACH;AAAA,IACF,CAAC;AACD,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA,EAIA,MAAc,WAAW,aAA4B,OAAiB,CAAC,GAAG,QAAQ,IAAI,WAAW,IAAmB;AAClH,QAAI,CAAC,YAAa;AAGlB,UAAM,KAAK,YAAY,WAAW,aAAa,KAAK,iBAAiB,KAAK,cAAc,MAAM,OAAO,YAAY,MAAS;AAE1H,UAAM,gBAAgB,KAAK,UAAU,yBAAyB;AAC9D,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,YAAY,cAAc,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAC9D;AAAA,QACE,KAAK,YAAY,UAAU,mCAAmC,EAAE,QAAQ,WAAW,SAAS;AAAA,QAC5F;AAAA,MACF;AAAA,IACF;AAEA,SAAK,UAAU,cAAc;AAC7B,SAAK,sBAAsB;AAC3B,SAAK,kBAAkB,CAAC;AACxB,SAAK,eAAe,CAAC;AAAA,EACvB;AAAA,EAEA,MAAc,oBAAoB,aAA4B,OAAiB,CAAC,GAAG,QAAQ,IAAI,WAAW,IAAmB;AAC3H,QAAI,CAAC,YAAa;AAElB,UAAM,WAAW,KAAK,UAAU,oBAAoB;AACpD,UAAM,gBAAgB,KAAK,aAAa,qBAAqB,KAAK;AAClE,QAAI,oBAAoB,KAAK;AAC7B,QAAI,gBAAgB,KAAK;AAIzB,QAAI,iBAAiB,SAAS,SAAS,GAAG;AACxC,UAAI;AACF,cAAM,IAAI,MAAM,KAAK,YAAY,cAAc,QAAQ;AACvD,4BAAoB,sBAAsB,KAAK,cAAc,QAAQ;AACrE,wBAAgB,qBAAqB,KAAK,iBAAiB,QAAQ;AACnE,kBAAU,GAAG,KAAK,YAAY,UAAU,iCAAiC,CAAC,KAAK,CAAC,GAAG;AAAA,MACrF,QAAQ;AACN,kBAAU,KAAK,YAAY,UAAU,mCAAmC,GAAG,KAAK;AAAA,MAClF;AAAA,IACF;AAEA,UAAM,gBAAgB,KAAK,UAAU,yBAAyB;AAC9D,QAAI,cAAc,SAAS,GAAG;AAC5B,YAAM,YAAY,cAAc,IAAI,OAAK,EAAE,QAAQ,EAAE,KAAK,IAAI;AAC9D,YAAM,YAAY,MAAM,KAAK,YAAY,mBAAmB;AAC5D,UAAI,WAAW;AACb,YAAI;AACF,qBAAW,MAAM,eAAe;AAC9B,kBAAM,KAAK,YAAY,kBAAkB,GAAG,UAAU,GAAG,KAAK;AAAA,UAChE;AACA,oBAAU,KAAK,YAAY,UAAU,mCAAmC,EAAE,QAAQ,WAAW,SAAS,CAAC;AAAA,QACzG,QAAQ;AACN;AAAA,YACE,KAAK,YAAY,UAAU,uCAAuC,EAAE,QAAQ,WAAW,SAAS;AAAA,YAChG;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AACL;AAAA,UACE,KAAK,YAAY,UAAU,mCAAmC,EAAE,QAAQ,WAAW,SAAS;AAAA,UAC5F;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,KAAK,MAAM,KAAK,YAAY,WAAW,aAAa,eAAe,mBAAmB,MAAM,OAAO,YAAY,MAAS;AAC9H,SAAK,UAAU,cAAc;AAC7B,SAAK,sBAAsB;AAC3B,SAAK,kBAAkB,CAAC;AACxB,SAAK,eAAe,CAAC;AACrB,eAAW,MAAM,KAAK,yBAAyB,EAAE,GAAG,GAAG;AAAA,EACzD;AAAA;AAAA,EAIQ,YAAY,MAAkB,QAA0B;AAC9D,QAAI,KAAK,IAAI,GAAG;AACd,0BAAAA,QAAK,MAAM;AACX,MAAC,KAAiC,IAAc,IAAI;AACpD;AAAA,IACF;AACA,IAAC,KAAiC,IAAc,IAAI;AACpD,WAAO;AAAA,EACT;AAAA,EAEQ,cAAoB;AAC1B,eAAW,MAAM;AACf,YAAM,QAAQ,oBAAAA,QAAK,SAAS;AAC5B,UAAI,MAAO,oBAAmB,OAAO,EAAE,UAAU,KAAK,WAAW,IAAI,CAAC;AAAA,IACxE,GAAG,CAAC;AAAA,EACN;AAAA,EAEQ,eACN,MACA,WACA,aACA,SACA,OACM;AACN,SAAK,YAAY,MAAM,MAAM;AAC3B,0BAAAA,QAAK,KAAK;AAAA,QACR,mBAAmB;AAAA,QACnB,OAAO;AAAA,QACP,GAAG;AAAA,QACH,SAAS,MAAM;AACb,4BAAkB;AAClB,kCAAwB;AACxB,iBAAO,oBAAoB;AAC3B,gBAAM,YAAY,SAAS,eAAe,SAAS;AACnD,cAAI,CAAC,UAAW;AAChB,kBAAQ,SAAS;AAAA,QACnB;AAAA,QACA,WAAW,MAAM;AACf,UAAC,KAAiC,IAAc,IAAI;AACpD,iBAAO,cAAc;AAAA,QACvB;AAAA,MACF,CAAC;AACD,UAAI,CAAC,OAAO,WAAY,MAAK,YAAY;AAAA,IAC3C,CAAC;AAAA,EACH;AAAA,EAEQ,SAAe;AACrB,UAAM,MAAS,KAAK;AACpB,UAAM,SAAS,KAAK;AACpB,SAAK,MAAM,UAAU,KAAK,YAAY,KAAK;AAC3C,SAAK,OAAO,YAAY,UAAU,kBAAkB,KAAK,MAAM,CAAC,WAAW,qBAAqB,KAAK,QAAQ,KAAK,YAAY,UAAU,KAAK,KAAK,WAAW,CAAC,CAAC;AAC/J,UAAM,YAAY,KAAK,OAAO,cAAc,wBAAwB;AACpE,eAAW,iBAAiB,SAAS,MAAM;AAEzC,UAAI,KAAK,yBAAyB;AAAE,aAAK,0BAA0B;AAAO;AAAA,MAAQ;AAClF,WAAK,OAAO;AAAA,IACd,CAAC;AACD,eAAW,iBAAiB,eAAe,CAAC,MAAM,KAAK,gBAAgB,CAAe,CAAC;AACvF,SAAK,OAAO,cAAc,uBAAuB,GAC7C,iBAAiB,SAAS,MAAM,KAAK,YAAY,CAAC;AACtD,SAAK,OAAO,cAAc,uBAAuB,GAC7C,iBAAiB,SAAS,MAAM,KAAK,qBAAqB,CAAC;AAC/D,SAAK,OAAO,cAAc,0BAA0B,GAChD,iBAAiB,SAAS,MAAM,KAAK,mBAAmB,CAAC;AAC7D,SAAK,OAAO,cAAc,wBAAwB,GAC9C,iBAAiB,SAAS,MAAM,KAAK,mBAAmB,CAAC;AAC7D,SAAK,OAAO,cAAc,wBAAwB,GAC9C,iBAAiB,SAAS,MAAM,KAAK,yBAAyB,CAAC;AACnE,SAAK,OAAO,cAAc,sBAAsB,GAC5C,iBAAiB,SAAS,MAAM,KAAK,eAAe,CAAC;AAEzD,SAAK,oBAAoB;AAAA,EAC3B;AACF;AAEA,IAAI,CAAC,eAAe,IAAI,kBAAkB,GAAG;AAC3C,iBAAe,OAAO,oBAAoB,qBAAqB;AACjE;;;AjDh8BO,IAAM,UAAU;","names":["tag","container","selector","rect","Swal","input","folderInput","i","j","import_sweetalert2","Swal"]}
|