flexdesk 0.18.0 → 0.18.2
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/CHANGELOG.md +58 -0
- package/css/flexdesk.css +83 -5
- package/css/tokens.css +7 -0
- package/dist/charts.js +78 -12
- package/dist/charts.js.map +2 -2
- package/dist/{chunk-5W4EEKSK.js → chunk-3BLIVOFD.js} +3 -3
- package/dist/{chunk-P74F6I6P.js → chunk-4X4SY3CP.js} +4 -4
- package/dist/{chunk-P74F6I6P.js.map → chunk-4X4SY3CP.js.map} +2 -2
- package/dist/{chunk-ZL3VKINP.js → chunk-HL3IIHU3.js} +494 -3
- package/dist/{chunk-ZL3VKINP.js.map → chunk-HL3IIHU3.js.map} +4 -4
- package/dist/{chunk-RKVYIXDC.js → chunk-NFZJ6P42.js} +19 -500
- package/dist/chunk-NFZJ6P42.js.map +7 -0
- package/dist/{chunk-U5GKJUOC.js → chunk-QRBOIUU3.js} +5 -6
- package/dist/chunk-QRBOIUU3.js.map +7 -0
- package/dist/flexdesk.css +83 -5
- package/dist/flow.js +22 -10
- package/dist/flow.js.map +2 -2
- package/dist/git.js +3 -3
- package/dist/tiles.js +4 -4
- package/dist/tokens.css +7 -0
- package/dist/widgets.js +226 -58
- package/dist/widgets.js.map +2 -2
- package/dist/wm.js +2 -2
- package/docs/components/charts.md +40 -0
- package/docs/components/chat-shell.md +8 -2
- package/docs/components/filter-builder.md +52 -6
- package/docs/components/flow-editors.md +20 -0
- package/docs/components/forms-and-dialogs.md +8 -0
- package/docs/components/input-fields.md +24 -0
- package/docs/components/menus.md +4 -0
- package/docs/components/shell.md +4 -0
- package/docs/components/workspace-picker.md +46 -2
- package/package.json +1 -1
- package/src/charts/plot_config_editor.js +92 -6
- package/src/charts/plot_grid.js +6 -1
- package/src/flow/kit/settings_panel.js +24 -9
- package/src/ui/components/chat_shell.js +7 -1
- package/src/ui/components/context_menu.js +8 -2
- package/src/ui/components/filter_builder.js +53 -28
- package/src/ui/components/filter_model.js +86 -18
- package/src/ui/components/inline_renamer.js +10 -5
- package/src/ui/components/modal.js +25 -8
- package/src/ui/components/workspace_picker.js +125 -27
- package/src/ui/utils/tooltip_service.js +81 -14
- package/dist/chunk-RKVYIXDC.js.map +0 -7
- package/dist/chunk-U5GKJUOC.js.map +0 -7
- /package/dist/{chunk-5W4EEKSK.js.map → chunk-3BLIVOFD.js.map} +0 -0
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/ui/components/sortable_list.js", "../src/ui/components/color_list_field.js", "../src/ui/components/option_list.js", "../src/ui/components/combobox.js", "../src/ui/components/modal.js", "../src/ui/components/context_menu.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * Sortable List Component\n * Location: ui/components/sortable_list.js\n *\n * Purpose: Provide a reusable list component with add, remove, reorder, and rename\n * capabilities. Used for named inputs in function nodes, rules in switch nodes, etc.\n *\n * Features:\n * - Add/remove items\n * - Drag-and-drop reordering\n * - Inline rename\n * - Custom item renderer\n * - Persistence via onChange callback\n *\n * Reordering is delegated to the shared DragReorder module (the same\n * ghost + drop-placeholder technique used by the tab bars and the schema\n * editor) so the reorder behaviour is implemented once.\n */\n\nimport { DragReorder } from './drag_reorder.js';\n\n/** The class every row carries, and therefore what DragReorder must match. */\nconst ROW_CLASS = 'twm-sortable-list__row';\nconst ROW_SELECTOR = `.${ROW_CLASS}`;\nconst HANDLE_CLASS = 'twm-sortable-list__handle';\nconst HANDLE_SELECTOR = `.${HANDLE_CLASS}`;\n\nexport class SortableList {\n /**\n * Create a sortable list.\n * @param {Object} options - Configuration options\n * @param {string} options.containerId - Unique ID for the container\n * @param {Array} options.items - Initial items array\n * @param {Function} options.onChange - Called with updated items array when list changes\n * @param {Function} options.renderItem - Custom renderer for item content (receives item, index, callbacks)\n * @param {Function} options.createItem - Factory function to create new items\n * @param {string} options.emptyMessage - Message to show when list is empty\n * @param {string} options.addButtonText - Text for add button\n * @param {boolean} options.allowReorder - Whether to allow drag-and-drop reordering\n * @param {boolean} options.allowRemove - Whether to allow removing items\n * @param {number} options.minItems - Minimum number of items (blocks removal if at min)\n */\n constructor({\n containerId,\n items = [],\n onChange = null,\n renderItem = null,\n createItem = null,\n emptyMessage = 'No items',\n addButtonText = 'Add Item',\n allowReorder = true,\n allowRemove = true,\n minItems = 0,\n } = {}) {\n this.containerId = containerId || `sortable-list-${Date.now()}`;\n this.items = Array.isArray(items) ? [...items] : [];\n this.onChange = typeof onChange === 'function' ? onChange : null;\n this.renderItem = typeof renderItem === 'function' ? renderItem : this.#defaultRenderItem.bind(this);\n this.createItem = typeof createItem === 'function' ? createItem : this.#defaultCreateItem.bind(this);\n this.emptyMessage = emptyMessage;\n this.addButtonText = addButtonText;\n this.allowReorder = allowReorder;\n this.allowRemove = allowRemove;\n this.minItems = minItems;\n\n this.root = null;\n this.listEl = null;\n this._dragReorder = null;\n this._pressedHandle = false;\n }\n\n /**\n * Render the sortable list.\n * @returns {HTMLElement} The root container element\n */\n render() {\n if (this.root) {\n this.#refresh();\n return this.root;\n }\n\n this.root = document.createElement('div');\n this.root.className = 'twm-sortable-list';\n this.root.id = this.containerId;\n\n this.listEl = document.createElement('div');\n this.listEl.className = 'twm-sortable-list__items';\n\n this.root.appendChild(this.listEl);\n\n // Only show add button if addButtonText is provided\n if (this.addButtonText) {\n const addBtn = document.createElement('button');\n addBtn.type = 'button';\n addBtn.className = 'twm-sortable-list__add';\n addBtn.innerHTML = `<span class=\"material-symbols-outlined\">add</span> ${this.#escapeHtml(this.addButtonText)}`;\n addBtn.addEventListener('click', () => this.addItem());\n this.root.appendChild(addBtn);\n }\n\n this.#refresh();\n return this.root;\n }\n\n /**\n * Get current items.\n * @returns {Array} Copy of items array\n */\n getItems() {\n return [...this.items];\n }\n\n /**\n * Set items and re-render.\n * @param {Array} items - New items array\n */\n setItems(items) {\n this.items = Array.isArray(items) ? [...items] : [];\n this.#refresh();\n }\n\n /**\n * Add a new item.\n */\n addItem() {\n const newItem = this.createItem(this.items.length);\n this.items.push(newItem);\n this.#notifyChange();\n this.#refresh();\n }\n\n /**\n * Remove an item by index.\n * @param {number} index - Index of item to remove\n */\n removeItem(index) {\n if (index < 0 || index >= this.items.length) return;\n if (this.items.length <= this.minItems) return;\n \n this.items.splice(index, 1);\n this.#notifyChange();\n this.#refresh();\n }\n\n /**\n * Update an item at index.\n * @param {number} index - Index of item to update\n * @param {Object} updates - Properties to merge into item\n */\n updateItem(index, updates) {\n if (index < 0 || index >= this.items.length) return;\n \n this.items[index] = { ...this.items[index], ...updates };\n this.#notifyChange();\n }\n\n /**\n * Move an item from one index to another.\n * @param {number} fromIndex - Source index\n * @param {number} toIndex - Destination index\n */\n moveItem(fromIndex, toIndex) {\n if (fromIndex < 0 || fromIndex >= this.items.length) return;\n if (toIndex < 0 || toIndex >= this.items.length) return;\n if (fromIndex === toIndex) return;\n\n const [item] = this.items.splice(fromIndex, 1);\n this.items.splice(toIndex, 0, item);\n this.#notifyChange();\n this.#refresh();\n }\n\n /**\n * Dispose the component.\n */\n dispose() {\n this._dragReorder?.destroy();\n this._dragReorder = null;\n this.root = null;\n this.listEl = null;\n this.items = [];\n }\n\n // \u2500\u2500\u2500 Private Methods \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #refresh() {\n if (!this.listEl) return;\n\n this.listEl.innerHTML = '';\n\n if (this.items.length === 0) {\n const empty = document.createElement('div');\n empty.className = 'twm-sortable-list__empty';\n empty.textContent = this.emptyMessage;\n this.listEl.appendChild(empty);\n return;\n }\n\n this.items.forEach((item, index) => {\n const row = this.#createRow(item, index);\n this.listEl.appendChild(row);\n });\n\n // Drag-to-reorder via the shared DragReorder module (ghost +\n // placeholder). Created once, bound to the persistent list\n // element; re-attached after each refresh to wire the rebuilt\n // rows. Drag is restricted to the grip handle.\n //\n // The item selector is ROW_SELECTOR, the class #createRow puts on\n // every row: a selector that matches no row makes nothing draggable.\n //\n // The handle restriction cannot read `dragstart`'s target: a browser\n // fires `dragstart` at the draggable element itself (the row), never\n // at the child the pointer went down on. So the press is recorded on\n // `mousedown` (which does target the handle) and the guard reads that.\n if (this.allowReorder) {\n if (!this._dragReorder) {\n this.listEl.addEventListener('mousedown', (e) => {\n this._pressedHandle = !!e.target.closest?.(HANDLE_SELECTOR);\n });\n this._dragReorder = new DragReorder({\n container: this.listEl,\n itemSelector: ROW_SELECTOR,\n keyAttr: 'index',\n axis: 'y',\n indicatorClass: 'twm-sortable-list__drop',\n draggableGuard: () => {\n const fromHandle = this._pressedHandle;\n this._pressedHandle = false;\n return fromHandle;\n },\n onReorder: (order) => this.#applyReorder(order),\n });\n }\n this._dragReorder.attach();\n }\n }\n\n /** Reorder `items` to match the new DOM order produced by a drag,\n * then notify + re-render. `order` holds the rows' pre-drag\n * `data-index` values in their new arrangement. */\n #applyReorder(order) {\n const next = order\n .map((i) => this.items[Number(i)])\n .filter((it) => it !== undefined);\n if (next.length !== this.items.length) return; // guard against drift\n this.items = next;\n this.#notifyChange();\n this.#refresh();\n }\n\n #createRow(item, index) {\n const row = document.createElement('div');\n row.className = ROW_CLASS;\n row.dataset.index = index;\n\n // Drag handle (if reordering enabled). The drag mechanics are\n // owned by the shared DragReorder instance (see #refresh); the\n // handle is just the grab affordance the drag is restricted to.\n if (this.allowReorder) {\n const handle = document.createElement('div');\n handle.className = HANDLE_CLASS;\n handle.innerHTML = '<span class=\"material-symbols-outlined\">drag_indicator</span>';\n row.appendChild(handle);\n }\n\n // Item content (custom renderer)\n const content = document.createElement('div');\n content.className = 'twm-sortable-list__content';\n \n const callbacks = {\n update: (updates) => this.updateItem(index, updates),\n remove: () => this.removeItem(index),\n moveUp: () => this.moveItem(index, index - 1),\n moveDown: () => this.moveItem(index, index + 1),\n };\n \n this.renderItem(content, item, index, callbacks);\n row.appendChild(content);\n\n // Remove button (if removal enabled)\n if (this.allowRemove) {\n const canRemove = this.items.length > this.minItems;\n const removeBtn = document.createElement('button');\n removeBtn.type = 'button';\n removeBtn.className = 'twm-sortable-list__remove';\n removeBtn.disabled = !canRemove;\n removeBtn.title = canRemove ? 'Remove' : `Minimum ${this.minItems} items required`;\n removeBtn.innerHTML = '<span class=\"material-symbols-outlined\">close</span>';\n removeBtn.addEventListener('click', () => {\n if (canRemove) this.removeItem(index);\n });\n row.appendChild(removeBtn);\n }\n\n return row;\n }\n\n #defaultRenderItem(container, item, index, callbacks) {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'twm-sortable-list__input';\n input.value = item.name ?? item.label ?? '';\n input.placeholder = `Item ${index + 1}`;\n input.addEventListener('change', () => {\n callbacks.update({ name: input.value });\n });\n container.appendChild(input);\n }\n\n #defaultCreateItem(index) {\n return {\n id: `item_${Date.now()}_${Math.random().toString(36).substr(2, 6)}`,\n name: `item${index + 1}`,\n };\n }\n\n #notifyChange() {\n if (this.onChange) {\n this.onChange([...this.items]);\n }\n }\n\n\n #escapeHtml(str) {\n return String(str ?? '')\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>');\n }\n}\n", "/**\n * ColorListField \u2014 an ordered list of colours: add, remove, and reorder by\n * the grip (drag) or the up / down buttons, each row a `ColorField`.\n *\n * const list = new ColorListField({\n * value: ['#1f77b4', 'rgb(255, 127, 14)'],\n * onChange: (colors, { commit }) => { ... },\n * });\n * host.appendChild(list.render());\n * list.getValue(); // ['#1f77b4', '#ff7f0e'] \u2014 or null, see below\n *\n * The list is a `SortableList` (the same add / remove / drag-reorder every\n * list in the library uses) whose rows render a `ColorField` and a pair of\n * move buttons, so the order can be changed without a pointer.\n *\n * `getValue()` is the colours in their current order as lowercase `#rrggbb`,\n * or `null` while any row holds something that is not a hex colour \u2014\n * `invalidIndexes()` says which. Empty rows count as invalid: a list entry\n * with no colour is not a colour.\n *\n * Given a `name`, the list also carries a hidden `<input name>` whose value is\n * the rows as JSON, and fires `input` on it for every edit and `change` for\n * every committed one (a row's `change`, add, remove, move). That is the\n * surface a host form listens on; `openForm` reads the list through\n * `getValue()`, not through that input.\n */\n\nimport { SortableList } from './sortable_list.js';\nimport { ColorField, isHexColor, normalizeHex } from './color_field.js';\nimport { fireEvent } from '../utils/fire_event.js';\n\nlet _seq = 0;\n\n/** A row's text as `#rrggbb`, or null when it is not a hex colour. */\nconst hexOf = (text) => {\n const t = String(text ?? '').trim();\n return isHexColor(t) ? normalizeHex(t) : null;\n};\n\nexport class ColorListField {\n /**\n * @param {Object} [o]\n * @param {string[]} [o.value] initial colours (hex or rgb())\n * @param {string[]} [o.presets] preset colours offered on every row\n * @param {string} [o.newColor] colour a newly added row starts on\n * @param {string} [o.addLabel] text of the add button\n * @param {string} [o.name] `name` of the hidden input, for a host form\n * @param {Function} [o.onChange] `(colors, { commit })`, colors as `getValue()`\n */\n constructor({\n value = [], presets = [], newColor = '#000000', addLabel = 'Add colour',\n name = null, onChange = null,\n } = {}) {\n this.presets = Array.isArray(presets) ? presets : [];\n // Converted once, as #toItems does, so an added row is what it shows.\n this.newColor = normalizeHex(String(newColor ?? '')) ?? String(newColor ?? '');\n this.addLabel = addLabel;\n this.name = name;\n this.onChange = typeof onChange === 'function' ? onChange : null;\n\n /** Row index -> its ColorField; always exactly the rendered rows. */\n this._fields = [];\n /** Whether the SortableList change being reported is a committed one. */\n this._commit = true;\n /** True while a row's own edit is written into the list's items. */\n this._rowEdit = false;\n this.list = new SortableList({\n items: this.#toItems(value),\n addButtonText: addLabel,\n emptyMessage: 'No colours',\n createItem: () => ({ id: ++_seq, text: this.newColor }),\n renderItem: (container, item, index, callbacks) =>\n this.#renderRow(container, item, index, callbacks),\n // Every SortableList change but a row's own edit (add, remove,\n // move, drag) is followed by a refresh that rebuilds all rows \u2014\n // down to none \u2014 so the old fields go first.\n onChange: () => {\n if (!this._rowEdit) this.#dropFields();\n this.#emit(this._commit);\n },\n });\n this.root = null;\n this.input = null;\n }\n\n render() {\n if (this.root) return this.root;\n const root = document.createElement('div');\n root.className = 'twm-color-list';\n if (this.name) {\n const input = document.createElement('input');\n input.type = 'hidden';\n input.name = this.name;\n root.appendChild(input);\n this.input = input;\n }\n root.appendChild(this.list.render());\n this.root = root;\n this.#writeInput();\n return root;\n }\n\n /** The colours in order as `#rrggbb`, or null while any row is not one. */\n getValue() {\n const out = this.getTexts().map(hexOf);\n return out.includes(null) ? null : out;\n }\n\n /** The rows' text as it stands, valid or not. */\n getTexts() {\n return this.list.getItems().map((item) => String(item.text ?? ''));\n }\n\n /** Indexes of the rows that do not hold a hex colour. */\n invalidIndexes() {\n const bad = [];\n this.getTexts().forEach((text, i) => { if (!hexOf(text)) bad.push(i); });\n return bad;\n }\n\n /** Replace the colours without firing `onChange`. */\n setValue(colors) {\n this.#dropFields();\n this.list.setItems(this.#toItems(colors));\n this.#writeInput();\n }\n\n /** Focus the first invalid row, else the first row, else the add button. */\n focus() {\n const bad = this.invalidIndexes()[0];\n const field = this._fields[bad ?? 0];\n if (field) { field.focus(); return; }\n this.root?.querySelector('.twm-sortable-list__add')?.focus();\n }\n\n dispose() {\n this.#dropFields();\n this.list.dispose();\n this.root = null;\n this.input = null;\n }\n\n #toItems(colors) {\n // A colour that converts is kept as its hex; anything else is kept as\n // typed, so it shows \u2014 and is reported \u2014 rather than vanishing.\n return (Array.isArray(colors) ? colors : []).map((c) => ({\n id: ++_seq,\n text: normalizeHex(String(c ?? '')) ?? String(c ?? ''),\n }));\n }\n\n /** Dispose every row's field: the rows are about to be rebuilt. */\n #dropFields() {\n for (const f of this._fields) f?.dispose();\n this._fields = [];\n }\n\n #renderRow(container, item, index, callbacks) {\n const count = this.list.getItems().length;\n\n const row = document.createElement('div');\n row.className = 'twm-color-list__row';\n const field = new ColorField({\n value: item.text,\n presets: this.presets,\n label: `Colour ${index + 1}`,\n // Every edit goes into the list's items, so the list never holds\n // a stale row; `_commit` tells its onChange which kind it was.\n onChange: (_v, { commit }) => {\n this._commit = commit;\n this._rowEdit = true;\n try { callbacks.update({ text: field.getText() }); }\n finally { this._commit = true; this._rowEdit = false; }\n },\n });\n this._fields[index] = field;\n row.appendChild(field.render());\n\n const move = (icon, label, disabled, fn) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'twm-color-list__move';\n btn.title = label;\n btn.setAttribute('aria-label', label);\n btn.disabled = disabled;\n const glyph = document.createElement('span');\n glyph.className = 'material-symbols-outlined';\n glyph.setAttribute('aria-hidden', 'true');\n glyph.textContent = icon;\n btn.appendChild(glyph);\n btn.addEventListener('click', fn);\n row.appendChild(btn);\n };\n move('arrow_upward', 'Move up', index === 0, callbacks.moveUp);\n move('arrow_downward', 'Move down', index === count - 1, callbacks.moveDown);\n container.appendChild(row);\n }\n\n #writeInput() {\n if (this.input) this.input.value = JSON.stringify(this.getTexts());\n }\n\n #emit(commit) {\n this.#writeInput();\n if (this.input) {\n fireEvent(this.input, 'input', { bubbles: true });\n if (commit) fireEvent(this.input, 'change', { bubbles: true });\n }\n this.onChange?.(this.getValue(), { commit });\n }\n}\n", "/**\n * THE ROWS `createSelect`, `createCombobox` AND `createTagInput`'s SUGGESTIONS\n * DRAW: a `role=\"listbox\"` of options, each with a glyph, a label, a second line,\n * a hint at the end of the row and, when disabled, its reason; `{ group, options }`\n * sections under a heading; one active row that the arrow keys walk.\n *\n * Focus never comes here. The text box or trigger that holds it names the active\n * row with `aria-activedescendant` (`onActive`), and a press on a row is\n * prevented from taking focus, so that a list row can be chosen with the box\n * still holding the caret, and no blur closes the list under the pointer.\n *\n * `aria-selected` says which row IS the current value; the active row is a class.\n * They are different things in a select, where the highlight walks away from the\n * value and comes back. Every word is built with `textContent`: these lists carry\n * text users wrote.\n *\n * An internal part: not exported from `@flexdesk/widgets`.\n */\n\nlet SEQ = 0;\n\nfunction node(tag, className, text) {\n const n = document.createElement(tag);\n if (className) n.className = className;\n if (text !== undefined && text !== null) n.textContent = String(text);\n return n;\n}\n\n/** `text` with the first run of `needle` in a `<mark>`, so it is plain why a row is offered. */\nfunction marked(target, text, needle) {\n const at = needle ? text.toLowerCase().indexOf(needle.toLowerCase()) : -1;\n if (at < 0) { target.textContent = text; return; }\n target.append(text.slice(0, at), node('mark', 'twm-option-list__match', text.slice(at, at + needle.length)),\n text.slice(at + needle.length));\n}\n\n/**\n * @param {object} o\n * @param {(option: object) => void} o.onPick A row was clicked. Never a disabled one.\n * @param {(id: string|null) => void} [o.onActive] The active row's id changed.\n */\nexport function createOptionList({ onPick, onActive = null }) {\n const id = `twm-option-list-${++SEQ}`;\n const el = node('div', 'twm-option-list');\n el.id = id;\n el.setAttribute('role', 'listbox');\n\n /** Every row drawn: `{ option, row }`. */\n let rows = [];\n let active = -1;\n\n const paintActive = () => {\n rows.forEach(({ row }, i) => row.classList.toggle('twm-option-list__row--active', i === active));\n const row = rows[active]?.row;\n // jsdom does not implement it, and a test harness is no reason to drop it.\n row?.scrollIntoView?.({ block: 'nearest' });\n onActive?.(row ? row.id : null);\n };\n\n const rowFor = (option, { glyphs, mark, isCurrent }) => {\n const row = node('div', 'twm-option-list__row');\n row.id = `${id}-${rows.length}`;\n row.setAttribute('role', 'option');\n row.setAttribute('aria-selected', String(!!isCurrent?.(option)));\n if (option.disabled) row.setAttribute('aria-disabled', 'true');\n row.title = option.description ? `${option.label} \u2014 ${option.description}` : option.label;\n if (glyphs) {\n const glyph = node('span', 'twm-option-list__glyph material-symbols-outlined', option.icon || '');\n glyph.setAttribute('aria-hidden', 'true');\n row.appendChild(glyph);\n }\n const words = node('span', 'twm-option-list__words');\n const label = node('span', 'twm-option-list__label');\n marked(label, option.label, mark);\n words.appendChild(label);\n if (option.description) words.appendChild(node('span', 'twm-option-list__description', option.description));\n if (option.disabled && option.reason) words.appendChild(node('span', 'twm-choice__reason', option.reason));\n row.appendChild(words);\n if (option.hint) row.appendChild(node('span', 'twm-option-list__hint', option.hint));\n return row;\n };\n\n const enabled = () => rows.map((r, i) => (r.option.disabled ? -1 : i)).filter((i) => i >= 0);\n\n // A press on the list leaves focus where it is. See the header.\n el.addEventListener('mousedown', (ev) => ev.preventDefault());\n el.addEventListener('click', (ev) => {\n const row = ev.target.closest?.('[role=\"option\"]');\n const hit = rows.find((r) => r.row === row);\n if (hit && !hit.option.disabled) onPick(hit.option);\n });\n\n return {\n el,\n id,\n /**\n * Draw `sections` (`[{ heading, items }]`, as `choiceSections` gives them).\n * @param {object} [opts]\n * @param {string} [opts.mark] The text to mark in each label.\n * @param {(option: object) => boolean} [opts.isCurrent] Is this the current value?\n */\n setRows(sections, { mark = '', isCurrent = null } = {}) {\n rows = [];\n active = -1;\n el.replaceChildren();\n const glyphs = sections.some((s) => s.items.some((o) => o.icon));\n for (const { heading, items } of sections) {\n let parent = el;\n if (heading != null) {\n parent = node('div', 'twm-option-list__section');\n parent.setAttribute('role', 'group');\n parent.setAttribute('aria-label', heading);\n const title = node('div', 'twm-choice__group', heading);\n title.setAttribute('aria-hidden', 'true');\n parent.appendChild(title);\n el.appendChild(parent);\n }\n for (const option of items) {\n const row = rowFor(option, { glyphs, mark, isCurrent });\n rows.push({ option, row });\n parent.appendChild(row);\n }\n }\n paintActive();\n },\n /** One line of text in place of the rows: nothing matched, still loading, a failure. */\n setMessage(text) {\n rows = [];\n active = -1;\n el.replaceChildren(node('div', 'twm-option-list__message', text));\n paintActive();\n },\n /** How many rows are drawn. */\n get size() { return rows.length; },\n /** The drawn options, in order. */\n options: () => rows.map((r) => r.option),\n /** The active row's option, or null. */\n activeOption: () => rows[active]?.option ?? null,\n /** Make row `index` active; -1, or a row that is disabled, makes none active. */\n setActive(index) {\n active = rows[index] && !rows[index].option.disabled ? index : -1;\n paintActive();\n },\n /** The next row that may be chosen, by `step`, wrapping. From none: the first or the last. */\n move(step) {\n const stops = enabled();\n if (!stops.length) return;\n const at = stops.indexOf(active);\n const next = at < 0 ? (step > 0 ? 0 : stops.length - 1) : (at + step + stops.length) % stops.length;\n active = stops[next];\n paintActive();\n },\n /** The first (`step` 1) or last (`step` -1) row that may be chosen. */\n moveToEnd(step) {\n const stops = enabled();\n active = stops.length ? stops[step > 0 ? 0 : stops.length - 1] : -1;\n paintActive();\n },\n };\n}\n", "/**\n * createCombobox \u2014 A TEXT BOX THAT ALSO OFFERS A LIST. (0.18.0)\n *\n * `createSelect` picks from a list; a bare `<input>` has nothing to pick from. A\n * value that may be anything but usually is one of a few known ones (a code, a\n * unit, a name) needs both at once.\n *\n * THE BOX HOLDS THE VALUE. The text in the input is what the caller gets back. An\n * option's `label` is what the LIST shows for it, and choosing a row puts the row's\n * `value` in the box. A field whose value is an opaque id with a separate name is\n * `createSelect`'s job: free text into an id is not a feature.\n *\n * THE TYPED TEXT IS REPORTED ON EVERY KEYSTROKE. In a dialog, \"type a value, click\n * Save\" is the normal gesture, and a control that only reports on blur is one click\n * from saving the previous value. `normalise` is therefore applied to what is\n * reported every time but rewrites the BOX only when the text is settled (on a pick,\n * Enter, Tab or blur), because rewriting an input's value moves the caret. Once, at\n * construction, a value `normalise` changed is reported as well: otherwise the box\n * shows one thing and the caller's model holds another.\n *\n * WHICH ROW ENTER TAKES. `autoHighlight` makes the first surviving row active so\n * Enter completes what was typed, and the list searches the label, the description\n * and `keywords` too. Together those have a wrong answer in them: a well-formed code\n * typed in full can be a substring of another row's description, and Enter would\n * take that row. Whether the typed text is ITSELF a well-formed value separates the\n * two cases, and only the caller knows that shape: `isCandidate`.\n *\n * ESCAPE AND ENTER ARE SWALLOWED WHILE THE LIST IS OPEN, and only then, so they\n * close the list and not the dialog around it. Closed, both bubble untouched.\n *\n * `validate` WARNS, it does not refuse: what is wrong with the settled value is said\n * under the box and the value is still reported.\n */\nimport { openAnchoredLayer } from './anchored_layer.js';\nimport { fireEvent } from '../utils/fire_event.js';\nimport { choiceSections, filterSections, shownValue } from './choice_controls.js';\nimport { createOptionList } from './option_list.js';\n\n/** Ms between a keystroke and asking a function of options, by default. */\nconst DEBOUNCE_MS = 150;\n\nlet SEQ = 0;\n\n/**\n * The list under a text box of your own, and everything that makes it behave: the\n * panel, the filter, async answers, the keys, `aria-*` on the box. `createCombobox`\n * and `createTagInput`'s suggestions are this.\n *\n * `options` is an array (filtered here) or `(query, { signal }) => array | Promise`,\n * which does its own filtering: it is asked after `debounce` ms; an answer that is\n * no longer the latest is dropped, and `signal` aborts when a newer one is asked for.\n *\n * Attach it BEFORE your own `keydown` listeners on the box: with a row active,\n * Enter is taken here and yours do not see it.\n *\n * @param {HTMLInputElement} input\n * @param {object} o\n * @param {Array|Function} o.options\n * @param {(option: object) => void} o.onPick A row was chosen (normalised; the entry\n * as you gave it is `option.source`).\n * @param {HTMLElement} [o.anchor] What the list hangs from; else the box.\n * @param {(option: object) => boolean} [o.isCurrent] Is this row the current value?\n * @param {boolean} [o.autoHighlight] Make a row active as the reader types.\n * @param {(typed: string) => boolean} [o.isCandidate] See the file's header.\n * @param {(text: string) => string} [o.normalise] What a typed text and a row's value are compared as.\n * @param {boolean} [o.openOnFocus] Focus opens the list.\n * @param {boolean} [o.passEnter] Enter with no row active closes the list and is left to\n * your listeners; by default it is swallowed.\n * @param {string} [o.loadingText] While a function of options is answering, with no rows to show.\n * @param {string} [o.errorText] When it failed.\n * @param {number} [o.debounce]\n * @param {string} [o.panelClassName]\n * @param {() => void} [o.onSettle] Enter with no row active, or Tab: the text stays as typed.\n * @returns {{isOpen: boolean, open: Function, close: Function, takeActive: () => boolean,\n * setOptions: Function, destroy: Function}}\n * `takeActive` chooses the active row and says whether there was one, for a key of\n * your own that also means \"this one\" (the tag input's comma).\n */\nexport function attachInputOptions(input, {\n options = [], onPick, anchor = null, isCurrent = null, autoHighlight = false, isCandidate = null,\n normalise = (text) => text, openOnFocus = false, passEnter = false, loadingText = 'Loading\u2026',\n errorText = 'Could not load the options.', debounce = DEBOUNCE_MS, panelClassName = '', onSettle = null,\n} = {}) {\n let source = options;\n let layer = null;\n /** The reader wants the list open; a late answer must not open what they closed. */\n let wanted = false;\n /** `null`: opened without typing, which shows everything. A string filters. */\n let query = null;\n let asked = 0;\n let timer = null;\n let controller = null;\n /** A pick is settling: its `input.focus()` is not a reader asking for the list. */\n let picking = false;\n\n const list = createOptionList({\n onPick: (option) => take(option),\n onActive: (id) => {\n if (id) input.setAttribute('aria-activedescendant', id);\n else input.removeAttribute('aria-activedescendant');\n },\n });\n const panel = document.createElement('div');\n panel.className = `twm-option-panel${panelClassName ? ` ${panelClassName}` : ''}`;\n panel.appendChild(list.el);\n\n // Not the browser's own autofill list on top of ours.\n input.setAttribute('autocomplete', 'off');\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-expanded', 'false');\n input.setAttribute('aria-controls', list.id);\n\n const show = () => {\n if (layer) { layer.place(); return; }\n layer = openAnchoredLayer({\n anchor: anchor || input, el: panel, gap: 4, matchWidth: true, returnFocus: false,\n onClose() {\n layer = null;\n wanted = false;\n input.setAttribute('aria-expanded', 'false');\n input.removeAttribute('aria-activedescendant');\n },\n });\n // The box is not on the page: there is no list, and nothing to come back to.\n if (!layer) { wanted = false; return; }\n input.setAttribute('aria-expanded', 'true');\n };\n\n /** Whatever is being asked is no longer wanted. */\n function forget() {\n clearTimeout(timer);\n asked += 1;\n controller?.abort();\n controller = null;\n }\n\n function close(reason = 'closed') {\n wanted = false;\n forget();\n layer?.close(reason);\n }\n\n /** Which row Enter would take, when `autoHighlight` is on. See the file's header. */\n function highlight(typed) {\n const text = normalise(typed.trim());\n if (!autoHighlight || !text) { list.setActive(-1); return; }\n const exact = list.options().findIndex((o) => normalise(shownValue(o.value)) === text);\n if (exact >= 0) list.setActive(exact);\n else if (isCandidate?.(text)) list.setActive(-1);\n else list.moveToEnd(1);\n }\n\n function drawRows(sections) {\n if (!wanted) return;\n // NOTHING TO SUGGEST, NOTHING TO SHOW. An empty panel under the box reads as a\n // broken control; an unlisted value is fine. Still wanted: the next answer may have rows.\n if (!sections.length) {\n layer?.close('empty');\n wanted = true;\n return;\n }\n const text = query ?? '';\n list.setRows(sections, { mark: normalise(text.trim()), isCurrent });\n show();\n highlight(text);\n }\n\n function ask(text) {\n controller = new AbortController();\n const token = asked;\n const failed = (err) => {\n if (token !== asked) return;\n console.warn('[createCombobox] options failed', err);\n if (!wanted) return;\n list.setMessage(errorText);\n show();\n };\n let answer;\n try { answer = source(text, { signal: controller.signal }); }\n catch (err) { failed(err); return; }\n if (typeof answer?.then !== 'function') { drawRows(choiceSections(answer)); return; }\n // Rows already drawn stay until the answer, so the list does not flicker per keystroke.\n if (!list.size && wanted) { list.setMessage(loadingText); show(); }\n answer.then((rows) => { if (token === asked) drawRows(choiceSections(rows)); }, failed);\n }\n\n /** The list, for the current query. */\n function refresh() {\n forget();\n if (typeof source !== 'function') {\n const all = choiceSections(source);\n drawRows(query === null ? all : filterSections(all, query));\n return;\n }\n const text = query ?? '';\n if (query === null || debounce <= 0) { ask(text); return; }\n const token = asked;\n timer = setTimeout(() => { if (token === asked) ask(text); }, debounce);\n }\n\n function take(option) {\n close('pick');\n picking = true;\n onPick?.(option);\n picking = false;\n }\n\n /** The active row is chosen, if the list is open and has one. */\n function takeActive() {\n const option = layer && list.activeOption();\n if (!option) return false;\n take(option);\n return true;\n }\n\n const openFor = (text) => { query = text; wanted = true; refresh(); };\n\n const onInput = () => openFor(input.value);\n const onClick = () => openFor(null);\n const onFocus = () => { if (openOnFocus && !layer && !picking) openFor(input.value || null); };\n const onBlur = () => close('blur');\n const onKey = (ev) => {\n if (ev.isComposing) return;\n if (ev.key === 'ArrowDown' || ev.key === 'ArrowUp') {\n ev.preventDefault();\n ev.stopPropagation();\n if (!layer) openFor(null);\n list.move(ev.key === 'ArrowDown' ? 1 : -1);\n return;\n }\n if (ev.key === 'Enter') {\n if (!layer) return; // the dialog's Enter, untouched\n if (takeActive()) {\n ev.preventDefault();\n ev.stopImmediatePropagation();\n return;\n }\n close();\n if (passEnter) return;\n ev.preventDefault();\n ev.stopPropagation();\n onSettle?.();\n return;\n }\n if (ev.key === 'Tab') {\n close('blur');\n onSettle?.();\n }\n };\n\n input.addEventListener('input', onInput);\n input.addEventListener('click', onClick);\n input.addEventListener('focus', onFocus);\n input.addEventListener('blur', onBlur);\n input.addEventListener('keydown', onKey);\n\n return {\n get isOpen() { return !!layer; },\n /** Open it showing everything, or for `text`. */\n open(text = null) { openFor(text); },\n close,\n takeActive,\n /** Replace the options; an open list redraws. */\n setOptions(next) {\n source = next;\n if (wanted) refresh();\n },\n destroy() {\n close();\n input.removeEventListener('input', onInput);\n input.removeEventListener('click', onClick);\n input.removeEventListener('focus', onFocus);\n input.removeEventListener('blur', onBlur);\n input.removeEventListener('keydown', onKey);\n },\n };\n}\n\n/**\n * @param {object} config\n * @param {Array|Function} [config.options] What `createSelect` takes: the list is a\n * SUGGESTION, never a constraint. Or `(query, { signal }) => array | Promise` for\n * options found as the reader types: it filters them itself, and is asked with `''`\n * when the list opens without typing.\n * @param {string} [config.value]\n * @param {(value: string, option: object|null) => void} [config.onChange] On every\n * keystroke and pick, and once at construction when `normalise` changed the value it\n * was handed. `option` is the entry as you gave it when one was picked, else `null`.\n * @param {string} [config.className] Extra classes on the root.\n * @param {string} [config.panelClassName]\n * @param {string} [config.placeholder]\n * @param {string} [config.title] The input's tooltip.\n * @param {string} [config.ariaLabel] When no `<label>` names the control.\n * @param {string} [config.name] The input's name.\n * @param {boolean} [config.disabled]\n * @param {(text: string) => string} [config.normalise] Upper-casing a code, say.\n * @param {boolean} [config.autoHighlight=true] See the file's header.\n * @param {(typed: string) => boolean} [config.isCandidate] See the file's header.\n * @param {(value: string) => string|null} [config.validate] What is wrong with the settled value.\n * @param {string} [config.loadingText]\n * @param {string} [config.errorText]\n * @param {number} [config.debounce=150] Ms before a function of options is asked.\n * @returns {{el: HTMLElement, input: HTMLInputElement, value: string, error: string|null,\n * isOpen: boolean, setOptions: Function, open: Function, close: Function,\n * focus: Function, destroy: Function}}\n */\nexport function createCombobox({\n options = [], value = '', onChange = null, className = '', panelClassName = '', placeholder = '', title = '',\n ariaLabel = '', name = null, disabled = false, normalise = (text) => text, autoHighlight = true, isCandidate = null,\n validate = null, loadingText, errorText, debounce,\n} = {}) {\n const handed = String(value ?? '');\n let current = normalise(handed);\n\n const el = document.createElement('div');\n el.className = `twm-combobox${className ? ` ${className}` : ''}`;\n\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'twm-combobox__input';\n input.spellcheck = false;\n input.value = current;\n input.disabled = !!disabled;\n if (name) input.name = name;\n if (placeholder) input.placeholder = placeholder;\n if (title) input.title = title;\n if (ariaLabel) input.setAttribute('aria-label', ariaLabel);\n\n const error = document.createElement('p');\n error.className = 'twm-combobox__error';\n error.hidden = true;\n error.id = `twm-combobox-error-${++SEQ}`;\n el.append(input, error);\n\n function report(next, option) {\n const settled = normalise(String(next ?? ''));\n if (settled === current) return;\n current = settled;\n onChange?.(current, option ?? null);\n }\n\n const clearValidity = () => {\n error.hidden = true;\n error.textContent = '';\n input.removeAttribute('aria-invalid');\n input.removeAttribute('aria-describedby');\n };\n\n /** The complaint appears when the text is settled: \"too short\" is noise mid-word. */\n function paintValidity() {\n const message = validate && current ? (validate(current) || null) : null;\n if (!message) { clearValidity(); return; }\n error.textContent = message;\n error.hidden = false;\n input.setAttribute('aria-invalid', 'true');\n input.setAttribute('aria-describedby', error.id);\n }\n\n /** Put the canonical text in the box. Only when it is settled: see the file's header. */\n function settle() {\n report(input.value, null);\n if (input.value !== current) input.value = current;\n paintValidity();\n }\n\n // Before the list's own listener: it marks the current value in the rows it draws.\n input.addEventListener('input', () => {\n // EVERY KEYSTROKE REACHES THE CALLER. See the file's header.\n report(input.value, null);\n clearValidity();\n });\n\n const menu = attachInputOptions(input, {\n options,\n autoHighlight,\n isCandidate,\n normalise,\n panelClassName,\n loadingText,\n errorText,\n debounce,\n isCurrent: (o) => normalise(shownValue(o.value)) === current,\n onSettle: settle,\n onPick(option) {\n input.value = shownValue(option.value);\n report(option.value, option.source);\n settle();\n input.focus();\n // A value set by script fires nothing; a surrounding form listens for this.\n fireEvent(input, 'change', { bubbles: true });\n },\n });\n\n input.addEventListener('blur', settle);\n\n paintValidity();\n if (onChange && current !== handed) onChange(current, null);\n\n return {\n el,\n input,\n get value() { return current; },\n set value(next) {\n current = normalise(String(next ?? ''));\n input.value = current;\n paintValidity();\n },\n /** The complaint on screen, or `null`. A caller that wants to refuse Save has this. */\n get error() { return error.hidden ? null : error.textContent; },\n get isOpen() { return menu.isOpen; },\n setOptions: menu.setOptions,\n /** Open the list showing everything, or for `text`. */\n open: menu.open,\n close: () => menu.close(),\n focus() { input.focus(); },\n destroy() {\n menu.destroy();\n el.remove();\n },\n };\n}\n", "/**\n * Modal helpers \u2014 prompt with form, yes/no confirm.\n *\n * Built on the canonical `ManagedWindow` (with `modal: true`) so dialogs\n * go through the same window system as everything else: same chrome,\n * same backdrop, same Esc-to-close behaviour, same z-stacking.\n *\n * Returns Promises that resolve with the form data (or null on cancel)\n * / a boolean (confirm).\n *\n * Field schema:\n * { name, label, type='text', default, step?, min?, max?, options?, required?,\n * placeholder?, hint?, validator?, rows?, create?, pick?, displayFor?,\n * onText?, offText?, disabled?, compact? }\n *\n * - type: 'text' | 'number' | 'password' | 'select' | 'textarea' |\n * 'checkbox' | 'toggle' | 'picker' | 'checklist' | 'radio' |\n * 'color' | 'colorList'\n * - hint: small dim help line rendered under the field\n * - validator: fn(value, allValues) => string | null (inline error)\n * - min / max: a `number` field's bounds \u2014 the input's own `min` / `max`\n * attributes, and on submit a value outside them is refused with a field\n * error under that field (\"Must be between 2 and 200.\"), not the browser's\n * bubble. An empty, non-required field is not out of range.\n * - rows: number of textarea rows (only used for type='textarea')\n * - toggle: a `ToggleField` switch, submitted as a boolean like a checkbox;\n * `onText` / `offText` label its state, `disabled` and `compact` pass\n * through to it\n *\n * Options \u2014 `select`, `checklist` and `radio` take `options`: bare values, or\n * `{ value, label?, disabled?, reason?, description? }`. A value comes back AS\n * ITSELF \u2014 an option whose value is the number 2 submits 2, not '2' \u2014 and a\n * default matches an option of the same text (`'2'` selects 2). A `disabled`\n * option is shown with its `reason` and is never the submitted value: it is not\n * selected by a default or by `api.set`, the reader cannot pick it, and a\n * submit that finds one selected anyway is refused with a field error.\n * `{ group: 'Heading', options: [...] }` in a select's list is an `<optgroup>`;\n * in a checklist or radio it is a `.twm-choice__group` heading over its\n * options. A combobox (a `select` with `create`) offers a group's enabled\n * options, flattened, and an entry naming a disabled one \u2014 a default or an\n * `api.set` \u2014 leaves the box empty.\n *\n * - `checklist`: toggle chips; submits the ARRAY of chosen values in the\n * list's order (`[]` for none). `required` means at least one.\n * - `radio`: one radio row per option, each with its `description` under it;\n * submits the chosen value, or null. `required` means one is chosen.\n *\n * These three are drawn by `choice_controls.js` \u2014 the same select, chips and\n * radio list as the flow kit's settings widgets, so there is one of each.\n *\n * Section dividers \u2014 entries of the form `{ section: 'Label' }` are\n * rendered as a small uppercase heading that groups the fields below\n * them. Useful for longer forms. A section that also carries a `name`\n * can be hidden and shown by `onFieldChange`'s `setVisible`.\n *\n * Rows \u2014 an entry of the form `{ row: [field, field, ...] }` puts its fields\n * side by side (a min and a max, say). Each is an ordinary field: its own\n * label, hint, error, `setVisible`, value and submitted key \u2014 the row is\n * layout only and has no name. Its inputs are equally wide (up to each\n * control's own padding): the space left after the labels is shared equally.\n * A form whose widest row has three or more fields opens wider (about 230px\n * per field; at least 640px, otherwise at most 90% of the window).\n * The row stacks its fields when the form is narrower than 360px (a\n * container query on `.twm-modal__form`).\n *\n * Picker \u2014 a value the user LOOKS UP rather than types (an id chosen in a\n * search dialog, say). The row shows a read-only box and a search button;\n * the button (or a click on the box) awaits `pick(currentValue)`, which\n * resolves to `{ value, label }`, a bare value, or null to leave the field\n * alone. The value is what is submitted, the label is what is shown, and\n * `displayFor(value)` gives the label for the value the form opens with:\n *\n * {\n * name: 'parent', label: 'Parent', type: 'picker',\n * pick: async (current) => ({ value: 'EPIC-0001', label: 'EPIC-0001 \u2014 Auth' }),\n * displayFor: (value) => titleOf(value),\n * }\n *\n * Dependent-property pick-or-create \u2014 a `select` field that carries a\n * `create` spec renders as a `createCombobox` instead of a\n * dropdown: the user picks an existing option OR types a new value.\n * On submit, a value that isn't an existing option is created via\n * `create.onCreate(value)` before the form resolves:\n *\n * {\n * name: 'asset_kind', label: 'Asset kind', type: 'select',\n * options: [...], // existing values (autocomplete)\n * create: {\n * onCreate: async (typed) => finalValue | null, // make the entity\n * hint: 'new asset kind', // shown when the typed value is new\n * },\n * }\n *\n * `create: true` is the degenerate case \u2014 \"pick one of these, or type\n * anything\" \u2014 where the typed value IS the value and there is no entity to\n * create, so there is no \"will create\" hint either. A bare `true` used to\n * reach `f.create.onCreate(v)` and fail the submit with \"onCreate is not a\n * function\", blaming the user for typing their own name.\n *\n * Colours \u2014 `type: 'color'` is a `ColorField` (swatch + native picker, a hex\n * box kept in step, `presets?` as swatch buttons) and submits lowercase\n * `#rrggbb`, or `''` when left empty. `type: 'colorList'` is a\n * `ColorListField` (add, remove, reorder; `presets?` on every row) and submits\n * an ordered array of `#rrggbb`. An `rgb()` default is shown as its hex. A box\n * that holds no hex colour is a field error and the form does not resolve;\n * `required` on either is checked by the form, not the browser:\n *\n * { name: 'accent', label: 'Accent', type: 'color', default: 'rgb(31,119,180)',\n * presets: ['#1f77b4', '#ff7f0e'] }\n * { name: 'palette', label: 'Palette', type: 'colorList', default: ['#1f77b4'] }\n */\n\nimport { ManagedWindow } from '../../ui/components/managed_window.js';\nimport { ToggleField } from '../../ui/components/toggle_field.js';\nimport { ColorField } from './color_field.js';\nimport { ColorListField } from './color_list_field.js';\nimport { choiceList, findChoice, flatChoices, selectBox, toggleChips } from './choice_controls.js';\nimport { createCombobox } from './combobox.js';\nimport { modalHost, setModalHost } from '../utils/modal_host.js';\nimport { fireEvent } from '../utils/fire_event.js';\n\nexport { setModalHost, modalHost };\n\nlet _modalSeq = 1;\n\n/**\n * @param {object} o\n * @param {Function?} o.onFieldChange `(name, value, api)` \u2014 called after any\n * field's `change`, and ONCE on open with `name === null` so the form starts\n * consistent with its defaults. `api` is\n * `{ setVisible(name, on), get(name), set(name, value), setOptions(name,\n * options) }`, addressing fields and named sections by name. `get` reads the\n * control as it stands (a checkbox or toggle as a boolean, a select or radio as its\n * option's own value \u2014 a select with no option selected as '', a radio\n * with none as null \u2014 a combobox as the value of the option its text names,\n * exactly as it submits, or as its text when it names none \u2014 a checklist as\n * the array of chosen values, a colorList as the array of its rows' text,\n * everything else \u2014 a colour too \u2014 as its string). An option\n * whose value IS the given one wins over one that only has its text, here,\n * in `set` and in defaults. `set` writes it (a value a select or radio does not\n * offer, or offers only disabled, clears it; so does a disabled option's\n * value in a combobox) and does NOT call\n * `onFieldChange` back, so a hook that fills one field from another cannot\n * loop. `setOptions` replaces the options of a `select` (a combobox's too),\n * `checklist` or `radio` while the form is open, keeping the current value\n * when the new list still offers it enabled \u2014 otherwise a select falls to its\n * first enabled option, a radio to none, and a checklist drops what is gone.\n * It does not call `onFieldChange` back either.\n *\n * It exists for the form whose Type select spans two record kinds and must\n * show the fields of the kind actually chosen. Rebuilding the form on every\n * change would lose what the user had already typed, so every field is\n * built once and the irrelevant rows are hidden. A hidden row keeps its\n * value and is still submitted \u2014 the caller drops what its chosen kind does\n * not use; a disabled option it holds submits as no value ('' for a select\n * or combobox, null for a radio) \u2014 but it is not ASKED about: its `required` and its `validator`\n * stand down until it is shown again, because a constraint on a field the\n * user cannot see is a submit button that silently does nothing.\n *\n * Absent \u2014 every caller before it \u2014 nothing here runs.\n */\nexport function openForm({ title, fields = [], defaults = {}, submitLabel = 'OK', onFieldChange = null } = {}) {\n return new Promise((resolve) => {\n // Build the form body \u2014 same markup as the legacy overlay,\n // minus the outer .ea-modal wrapper (ManagedWindow owns the\n // chrome now).\n const body = document.createElement('div');\n body.className = 'twm-modal__body-host';\n body.innerHTML = `\n <form class=\"twm-modal__form\">\n <div class=\"twm-modal__fields\">\n ${fields.map((f) => _renderEntry(f, defaults)).join('')}\n </div>\n <div class=\"twm-modal__error\" data-role=\"form-error\" hidden></div>\n <div class=\"twm-modal__actions\">\n <button type=\"button\" class=\"twm-btn\" data-action=\"cancel\">Cancel</button>\n <button type=\"submit\" class=\"twm-btn twm-btn--primary\">${submitLabel}</button>\n </div>\n </form>\n `;\n\n const win = new ManagedWindow({\n container: modalHost(),\n id: `twm-modal-${_modalSeq++}`,\n title: title || 'Dialog',\n icon: 'edit_note',\n content: body,\n modal: true,\n canMinimize: false,\n canMaximize: false,\n canResize: false,\n canDrag: true,\n defaultWidth: _estimateWidth(fields),\n defaultHeight: _estimateHeight(fields),\n onClose: () => {\n disposeControls();\n if (!_resolved) { _resolved = true; resolve(null); }\n },\n });\n\n let _resolved = false;\n const close = (result) => {\n if (_resolved) return;\n _resolved = true;\n resolve(result);\n try { win.close({ force: true }); } catch {}\n disposeControls();\n };\n\n const errEl = body.querySelector('[data-role=\"form-error\"]');\n const showError = (msg) => {\n if (!errEl) return;\n errEl.textContent = msg;\n errEl.hidden = !msg;\n };\n body.querySelector('[data-action=\"cancel\"]')?.addEventListener('click', () => close(null));\n\n const formFields = _formFields(fields);\n // The options each field offers NOW \u2014 `setOptions` replaces them, the\n // caller's field object is never written to.\n const optionsOf = new Map(formFields.map((f) => [f.name, f.options]));\n for (const f of formFields) {\n if (f.type === 'picker') _wirePicker(body, f);\n }\n const rowHidden = (name) => !!body.querySelector(`[data-field-row=\"${name}\"]`)?.hidden;\n\n const clearFieldError = (name) => {\n const row = body.querySelector(`[data-field-row=\"${name}\"]`);\n const errEl = body.querySelector(`[data-field-error=\"${name}\"]`);\n if (row) row.classList.remove('twm-is-invalid');\n if (errEl) { errEl.textContent = ''; errEl.hidden = true; }\n };\n const setFieldError = (name, msg) => {\n const row = body.querySelector(`[data-field-row=\"${name}\"]`);\n const errEl = body.querySelector(`[data-field-error=\"${name}\"]`);\n if (row) row.classList.add('twm-is-invalid');\n if (errEl) { errEl.textContent = msg; errEl.hidden = false; }\n };\n // Fields that are components, not markup \u2014 toggles, selects,\n // checklists, radios and colours \u2014 are mounted into the slot their\n // row left (`_mountControl`) and read back through it: a toggle as a\n // boolean, a choice as its option's own value, a colour as its hex. `onChoice` is what a checklist or\n // radio calls when the reader changes it (a toggle or select is a\n // named control and is heard by the loops below).\n let onChoice = (name) => clearFieldError(name);\n const controls = new Map();\n for (const f of formFields) {\n const c = _mountControl(body, f, defaults[f.name] ?? f.default, (name) => onChoice(name));\n if (c) controls.set(f.name, c);\n }\n function disposeControls() {\n for (const c of controls.values()) c.dispose?.();\n controls.clear();\n }\n win.show();\n /** The option a combobox entry names \u2014 the one whose value IS it, else the\n * one whose value has its text \u2014 or undefined. `get` and the submit both\n * read a combobox through this, so they agree (`'2'` is option `2`). */\n const comboOption = (f, text) => findChoice(flatChoices(optionsOf.get(f.name)), text, true);\n /** A disabled option's reason ('' with none) when one is the value, else null. */\n const unavailable = (f) => controls.get(f.name)?.unavailable() ?? null;\n\n // Clear per-field errors on input so the user sees the row recover.\n for (const f of formFields) {\n const el = body.querySelector(`[name=\"${f.name}\"]`);\n el?.addEventListener('input', () => clearFieldError(f.name));\n el?.addEventListener('change', () => clearFieldError(f.name));\n // The browser refuses a number outside its min / max before the\n // submit handler runs; its bubble is replaced by the field error\n // the submit would have shown.\n if (f.type === 'number' && _bounded(f)) {\n el?.addEventListener('invalid', (e) => {\n if (!el.validity.rangeUnderflow && !el.validity.rangeOverflow) return;\n e.preventDefault();\n setFieldError(f.name, _rangeMessage(f));\n });\n }\n }\n\n // Adaptive fields \u2014 see `onFieldChange` above.\n if (typeof onFieldChange === 'function') {\n const fieldOf = (name) => formFields.find((f) => f.name === name) || null;\n const api = {\n setVisible(name, on) {\n const row = body.querySelector(`[data-field-row=\"${name}\"]`);\n if (!row) return;\n // The attribute alone loses to `.twm-modal__row { display:\n // grid }` in any stylesheet that has not got the `[hidden]`\n // rule flexdesk.css carries, so the inline style says it too.\n row.hidden = !on;\n row.style.display = on ? '' : 'none';\n clearFieldError(name);\n // A required control nobody can see blocks the submit with\n // no message the user can find, and so does a number out\n // of its min or max. Remembered on the control, so showing\n // the row gives back exactly what it had.\n for (const el of row.querySelectorAll('input, select, textarea')) {\n if (!on && el.required) { el.required = false; el.dataset.twmRequired = '1'; }\n else if (on && el.dataset.twmRequired) { el.required = true; delete el.dataset.twmRequired; }\n for (const [attr, key] of [['min', 'twmMin'], ['max', 'twmMax']]) {\n if (!on && el.hasAttribute(attr)) { el.dataset[key] = el.getAttribute(attr); el.removeAttribute(attr); }\n else if (on && el.dataset[key] != null) { el.setAttribute(attr, el.dataset[key]); delete el.dataset[key]; }\n }\n }\n },\n get(name) {\n if (controls.has(name)) return controls.get(name).read();\n const el = body.querySelector(`[name=\"${name}\"]`);\n if (!el) return undefined;\n if (el.type === 'checkbox') return !!el.checked;\n return el.value;\n },\n set(name, value) {\n if (controls.has(name)) { controls.get(name).write(value); return; }\n const el = body.querySelector(`[name=\"${name}\"]`);\n if (!el) return;\n if (el.type === 'checkbox') { el.checked = !!value; return; }\n const f = fieldOf(name);\n el.value = value == null ? '' : String(value);\n if (f?.type === 'picker') {\n const display = body.querySelector(`[data-picker-display=\"${name}\"]`);\n if (display) display.value = _pickerLabel(f, el.value);\n }\n },\n setOptions(name, options) {\n const c = controls.get(name);\n if (!c?.setOptions) return;\n optionsOf.set(name, options);\n c.setOptions(options);\n },\n };\n const fire = (name) => {\n try { onFieldChange(name, name == null ? undefined : api.get(name), api); }\n catch (err) { console.error('[modal] onFieldChange threw', err); }\n };\n for (const f of formFields) {\n const el = body.querySelector(`[name=\"${f.name}\"]`);\n el?.addEventListener('change', () => fire(f.name));\n }\n onChoice = (name) => { clearFieldError(name); fire(name); };\n // Once on open, so a preselected value is reflected immediately\n // rather than only after the user touches something.\n fire(null);\n }\n\n body.querySelector('form').addEventListener('submit', async (e) => {\n e.preventDefault();\n const submitBtn = body.querySelector('button[type=\"submit\"]');\n showError('');\n const data = {};\n for (const f of formFields) {\n const control = controls.get(f.name);\n const el = control ? null : body.querySelector(`[name=\"${f.name}\"]`);\n if (!control && !el) continue;\n let v;\n if (control) {\n // A colour reads as its text but submits as its hex.\n v = control.submit ? control.submit() : control.read();\n // An option with no value submits '', as an empty select does.\n if (v === undefined) v = f.type === 'select' ? '' : null;\n } else if (f.type === 'checkbox') {\n v = !!el.checked;\n } else if (f.type === 'number') {\n v = (el.value === '' ? null : Number(el.value));\n } else {\n v = el.value;\n }\n if (f.type === 'select' && f.create) {\n const spec = _createSpec(f);\n // A typed value that is an option's text IS that option,\n // with the option's own value (a number stays a number).\n const match = comboOption(f, v);\n if (match) v = match.value;\n else if (v) {\n if (submitBtn) submitBtn.disabled = true;\n let created;\n let failMsg = null;\n try { created = await spec.onCreate(v); }\n catch (err) { created = null; failMsg = err?.message || String(err); }\n if (submitBtn) submitBtn.disabled = false;\n if (created == null) {\n const hint = spec.hint || f.label.toLowerCase();\n showError(failMsg\n ? `Couldn't create ${hint} \"${v}\": ${failMsg}`\n : `Couldn't create ${hint} \"${v}\". See the toast for details.`);\n return;\n }\n v = created;\n }\n }\n data[f.name] = v;\n }\n // Per-field validators run after collection so they can see\n // peer values (e.g. confirm-password matches password).\n let firstBadName = null;\n for (const f of formFields) {\n clearFieldError(f.name);\n if (rowHidden(f.name)) {\n // Not asked about \u2014 but a disabled option is still never\n // the value: a hidden row holding one submits no value.\n if (unavailable(f) != null) data[f.name] = f.type === 'radio' ? null : '';\n continue;\n }\n const v = data[f.name];\n // A picker's value lives in a hidden input, and a checklist or\n // radio is no single control, so the browser's own `required`\n // check never sees them \u2014 they are checked here.\n let msg = f.required && _missing(f, v) ? 'Required.' : null;\n if (!msg && _outOfRange(f, v)) msg = _rangeMessage(f);\n if (!msg) {\n const reason = unavailable(f);\n if (reason != null) msg = reason ? `Not available: ${reason}` : 'Not available.';\n }\n if (!msg) msg = controls.get(f.name)?.error?.() ?? null;\n if (!msg && typeof f.validator === 'function') {\n try { msg = f.validator(v, data); } catch (err) { msg = err?.message || String(err); }\n }\n if (msg) {\n setFieldError(f.name, msg);\n if (!firstBadName) firstBadName = f.name;\n }\n }\n if (firstBadName) {\n controls.get(firstBadName)?.focus();\n body.querySelector(`[data-picker=\"${firstBadName}\"]`)?.focus();\n body.querySelector(`[name=\"${firstBadName}\"]:not([type=\"hidden\"])`)?.focus();\n return;\n }\n close(data);\n });\n\n // Focus first field on next frame so the managed-window mount\n // settles before we steal focus.\n // Not a picker's hidden value, and not a field in a row that\n // `onFieldChange` hid on open.\n requestAnimationFrame(() => {\n const first = [...body.querySelectorAll('input:not([type=\"hidden\"]), select, textarea')]\n .find((el) => !el.closest('[data-field-row]')?.hidden);\n first?.focus();\n });\n });\n}\n\n\n/**\n * `openConfirm` \u2014 a yes/no modal. Resolves `true` on confirm, `false` on\n * cancel, Esc, X or backdrop.\n *\n * `message`, `confirmLabel` and `cancelLabel` are TEXT, never markup: callers\n * put user-named things in them (\"Delete flow \"<name>\"?\"), so they are set\n * with `textContent` and a `<` in a name shows as a `<`. A `\\n` in `message`\n * breaks the line (`white-space: pre-line` on `.twm-modal__body--text`).\n */\nexport function openConfirm({\n title, message, confirmLabel = 'OK',\n cancelLabel = 'Cancel',\n danger = false, icon = null,\n} = {}) {\n return new Promise((resolve) => {\n const body = document.createElement('div');\n body.className = 'twm-modal__body-host';\n\n const messageEl = document.createElement('div');\n messageEl.className = 'twm-modal__body twm-modal__body--text';\n messageEl.textContent = message == null ? '' : String(message);\n\n const actionsEl = document.createElement('div');\n actionsEl.className = 'twm-modal__actions';\n const button = (action, className, label) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = className;\n btn.dataset.action = action;\n btn.textContent = label == null ? '' : String(label);\n actionsEl.appendChild(btn);\n };\n button('cancel', 'twm-btn', cancelLabel);\n button('confirm', danger ? 'twm-btn twm-btn--danger' : 'twm-btn twm-btn--primary', confirmLabel);\n\n body.append(messageEl, actionsEl);\n\n let _resolved = false;\n const win = new ManagedWindow({\n container: modalHost(),\n id: `twm-confirm-${_modalSeq++}`,\n title: title || 'Confirm',\n icon: icon || (danger ? 'warning' : 'help'),\n content: body,\n modal: true,\n canMinimize: false,\n canMaximize: false,\n canResize: false,\n canDrag: true,\n defaultWidth: 380,\n defaultHeight: 180,\n onClose: () => { if (!_resolved) { _resolved = true; resolve(false); } },\n });\n win.show();\n const close = (v) => {\n if (_resolved) return;\n _resolved = true;\n resolve(v);\n try { win.close({ force: true }); } catch {}\n };\n body.querySelector('[data-action=\"cancel\"]').addEventListener('click', () => close(false));\n body.querySelector('[data-action=\"confirm\"]').addEventListener('click', () => close(true));\n requestAnimationFrame(() => {\n body.querySelector(`[data-action=\"${danger ? 'cancel' : 'confirm'}\"]`)?.focus();\n });\n });\n}\n\n\n/**\n * `openModal` \u2014 rich-content modal. The third helper alongside\n * `openForm` (field-based) and `openConfirm` (yes/no).\n *\n * Use when the modal body is arbitrary DOM the caller renders itself\n * \u2014 a chart, a Monaco editor, a table, a diff view. The shell still\n * goes through ManagedWindow so the chrome, focus trap, Esc handling,\n * and z-stacking match every other modal in the app.\n *\n * Schema:\n * - `title` window title (string)\n * - `icon` optional material-symbols-outlined glyph for the\n * title bar; defaults to `info`\n * - `content` HTMLElement appended into the body. Caller owns\n * rendering \u2014 `openModal` doesn't size or style the\n * internal content beyond making it scrollable.\n * - `actions` `[{ label, value, primary?, danger?, icon? }, \u2026]`. If\n * omitted, defaults to a single `[Close]` action that\n * resolves with `null`. The first action with\n * `primary: true` is the rightmost; otherwise the\n * last action wins. Esc / X / backdrop resolve with\n * `null` regardless of what's in `actions`. `icon` is\n * an optional material-symbols-outlined ligature drawn\n * BEFORE the label; when it is given the label lives in\n * a `.twm-btn__label` span, because an icon font's\n * ligature name is itself text and would otherwise be\n * read back as part of the label.\n * - `width`,\n * `height` initial size in px. Defaults: 640 \u00D7 480.\n * - `onMount` optional `(contentEl) => void` invoked once after\n * the content is appended \u2014 handy when the caller\n * needs the bounding rect to size a chart / Monaco /\n * SVG inside the body.\n * - `backdropBlur` backdrop blur radius in px (`0` disables it).\n * - `backdropOpacity` backdrop dim, 0 (clear) \u2026 1 (opaque). Use a low\n * value (with `backdropBlur: 0`) to keep the background\n * legible \u2014 e.g. a live-applied editor where you want to\n * watch the content behind update. Omit both to inherit\n * the default look (blur 2px over a 50% dim).\n * - `maximizable` C29. Draw a maximise button in the title bar.\n * Default `false`, which is byte-for-byte what every\n * existing caller has always got.\n * - `onMaximizeChange` `(maximized, contentEl) => void`, called on each\n * flip. Only useful with `maximizable`.\n * - `beforeClose` `() => boolean | Promise<boolean>`: asked when Esc or\n * the X would dismiss; answering false keeps the modal open. An\n * action button does not ask it.\n *\n * \u2550\u2550 C29. WHY A DIALOG'S MAXIMISE IS THE GEOMETRIC ONE \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * Everywhere else in this library maximise means BACK TO TILE: the window\n * stops being a window and its content returns to the tile it came out of.\n * That is R14, it is the product owner's ruling \u2014 *\"maximize here means back\n * to tile\"* \u2014 and it holds for the chrome button, the title bar's\n * double-click, an embedder's window menu and the aero-snap top edge alike.\n *\n * A DIALOG HAS NO TILE. It was never lifted out of one; it is modal, it owns\n * the screen until it resolves, and \"back to tile\" names a destination that\n * does not exist for it. So here maximise can only mean the rectangle, and\n * that is not a contradiction of the ruling but its boundary: THE RULING IS\n * ABOUT WINDOWS THAT CAME FROM A TILE. Do not \"fix\" this into a dock \u2014 there\n * is nothing to dock into, and `bringBackWindow` would refuse it anyway.\n *\n * Mechanically that means setting no `onMaximize` at all rather than reaching\n * for `toggleMaximize({claimable: false})`: with nothing claiming the gesture,\n * the ordinary path IS the rectangle, and the escape hatch is for consumers\n * who have claimed it.\n *\n * The dialog stays a dialog while maximised \u2014 `modal: true` is untouched, so\n * the backdrop, the Esc handler and the Tab focus trap (all of which hang off\n * `this.element` and the top-most-window test, not off geometry) go on working\n * exactly as they did.\n *\n * Returns a Promise resolving with the chosen action's `value`, or\n * `null` if the user dismissed the modal.\n */\nexport function openModal({\n title = 'Dialog',\n icon = 'info',\n content = null,\n actions = null,\n width = 640,\n height = 480,\n onMount = null,\n backdropBlur = undefined,\n backdropOpacity = undefined,\n maximizable = false,\n onMaximizeChange = null,\n beforeClose = null,\n} = {}) {\n return new Promise((resolve) => {\n const body = document.createElement('div');\n body.className = 'twm-modal__body-host';\n\n const bodyInner = document.createElement('div');\n bodyInner.className = 'twm-modal__body twm-modal__body--rich';\n if (content instanceof HTMLElement) bodyInner.appendChild(content);\n body.appendChild(bodyInner);\n\n // Actions row \u2014 default = single Close button. Esc / backdrop /\n // X all bypass this and resolve with null.\n const acts = Array.isArray(actions) && actions.length > 0\n ? actions\n : [{ label: 'Close', value: null }];\n const actionsEl = document.createElement('div');\n actionsEl.className = 'twm-modal__actions';\n acts.forEach((a, i) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n let cls = 'twm-btn';\n if (a.primary) cls += ' twm-btn--primary';\n if (a.danger) cls += ' twm-btn--danger';\n btn.className = cls;\n // C26. AN ACTION MAY CARRY A GLYPH \u2014 additively, and only when it\n // asks for one. Without `icon` the button is byte-identical to what\n // every existing caller gets today: one text node, so a consumer\n // reading `btn.textContent` to find its own button keeps working.\n //\n // With one, the label moves into its own span so that reading it\n // back is still possible: an icon font's ligature name IS text\n // content (\"save\" renders as a glyph but reads as the word), so a\n // bare `textContent` on a button with an icon would answer\n // \"saveSave\". `.twm-btn__label` is the answer to \"what does this\n // button say\", and `aria-hidden` on the glyph is what keeps a screen\n // reader from saying the ligature name out loud beside the label.\n if (a.icon) {\n const glyph = document.createElement('span');\n glyph.className = 'material-symbols-outlined twm-btn__glyph';\n glyph.textContent = String(a.icon);\n glyph.setAttribute('aria-hidden', 'true');\n const text = document.createElement('span');\n text.className = 'twm-btn__label';\n text.textContent = String(a.label || '');\n btn.append(glyph, text);\n } else {\n btn.textContent = String(a.label || '');\n }\n btn.dataset.actionIdx = String(i);\n // C27. AN ACTION MAY START DISABLED, and be enabled later.\n //\n // Every action here dismisses the dialog and resolves the promise \u2014\n // that is the documented contract, and it is why a caller cannot\n // \"refuse\" a submit: by the time it sees the value, the form and\n // everything typed into it are gone. So a dialog whose primary\n // action is not yet valid has had exactly two options: let the user\n // press it and lose their work to a toast, or reach into this markup\n // from outside, which is the coupling C6 exists to remove.\n //\n // `disabled` plus the controller handed to `onMount` is the third.\n // Absent \u2014 every existing caller \u2014 the button is enabled exactly as\n // before.\n if (a.disabled) btn.disabled = true;\n if (a.value !== undefined && a.value !== null) {\n btn.dataset.actionValue = String(a.value);\n }\n actionsEl.appendChild(btn);\n });\n body.appendChild(actionsEl);\n\n let _resolved = false;\n // DECLARED BEFORE THE WINDOW, INSTALLED AFTER IT. `onClose` below closes\n // over `_dropMaxListener`, and `show()` runs between the two \u2014 so\n // leaving the declaration down where the listener is installed would\n // stretch a temporal dead zone across a call that could come back\n // through `onClose`. The cost of getting that wrong is a ReferenceError\n // inside a dismissal, which is the least debuggable place in this file.\n let _onMax = null;\n const _dropMaxListener = () => {\n if (!_onMax) return;\n window.removeEventListener('managed-window-maximized', _onMax);\n _onMax = null;\n };\n const win = new ManagedWindow({\n container: modalHost(),\n id: `twm-modal-${_modalSeq++}`,\n title,\n icon,\n content: body,\n modal: true,\n backdropBlur,\n backdropOpacity,\n canMinimize: false,\n // C29. OPT-IN, and `false` is still the default \u2014 a confirmation\n // and a two-field form have nothing to do with the extra room, and\n // a button that grows a dialog nobody wanted grown is noise in the\n // one place a user looks for the X. `onMaximize` is deliberately\n // NOT set: see the C29 note in the header \u2014 with nothing claiming\n // the gesture, `toggleMaximize` runs the rectangle, which is the\n // only thing maximise can mean for a window with no tile.\n canMaximize: !!maximizable,\n canResize: true,\n canDrag: true,\n defaultWidth: width,\n defaultHeight: height,\n beforeClose,\n // Esc, the X and the backdrop all land here without passing through\n // `close`, so the listener is dropped here as well as there \u2014 the\n // three dismissals a user reaches for most are exactly the ones\n // that would otherwise leak it.\n onClose: () => {\n _dropMaxListener();\n if (!_resolved) { _resolved = true; resolve(null); }\n },\n });\n win.show();\n\n // C29. THE STATE, FOR A CALLER WHOSE LAYOUT DEPENDS ON IT.\n //\n // `managed-window-maximized` (C16) is the framework's own edge and it\n // is global, so it is filtered on the id \u2014 the alternative, wrapping\n // `win.toggleMaximize`, would miss `_restoreState`'s replay of a\n // persisted maximised window and any consumer calling the method\n // directly. Removed on close: a dialog is short-lived and twenty of\n // them over a session leaving listeners behind is a leak with no\n // symptom until the twenty-first.\n //\n // The CSS half needs no listener at all \u2014 `ManagedWindow` toggles\n // `.twm-managed-window--maximized` on its own element, which is an\n // ancestor of everything in here, so a stylesheet can respond without\n // any of this. The callback is for the layout a stylesheet cannot\n // reach: content whose height was fixed by the CALLER's own rules.\n if (maximizable && typeof onMaximizeChange === 'function') {\n _onMax = (e) => {\n if (e.detail?.id !== win.id) return;\n try { onMaximizeChange(!!e.detail.maximized, bodyInner); }\n catch (err) { console.warn('[modal] onMaximizeChange threw', err); }\n };\n window.addEventListener('managed-window-maximized', _onMax);\n }\n\n const close = (value) => {\n if (_resolved) return;\n _resolved = true;\n _dropMaxListener();\n resolve(value);\n try { win.close({ force: true }); } catch {}\n };\n actionsEl.addEventListener('click', (e) => {\n const btn = e.target.closest('[data-action-idx]');\n if (!btn) return;\n const idx = Number(btn.dataset.actionIdx);\n const a = acts[idx];\n if (!a) return;\n // `keepOpen` actions are side-effects (Copy, Apply\n // Without Close, etc.): if the action's `onClick` returns\n // anything (or just runs), the modal stays open. Use this\n // for Copy buttons and the like.\n if (a.keepOpen) {\n // `onClick` receives `close` so the handler can\n // validate, do an async side-effect, and only then\n // dismiss the modal with whatever value it chooses.\n // Returning early without calling `close` leaves the\n // modal open (which is the whole point of keepOpen).\n try { a.onClick?.(close); } catch (err) { console.warn(err); }\n return;\n }\n close(a.value);\n });\n\n /**\n * C27. What `onMount` is handed alongside the body, so a form can keep\n * its own submit honest without knowing this file's markup.\n *\n * Addressed by an action's VALUE rather than its index: an index is a\n * fact about the order the caller happened to list them in, and a caller\n * that inserted a \"Save and add another\" in the middle would silently\n * start disabling Cancel.\n */\n const controls = {\n // NOT `CSS.escape`. It is a browser global that jsdom does not\n // provide, and this file is mounted under jsdom by four render\n // tests \u2014 so reaching for it turns \"the dialog is valid\" into a\n // ReferenceError in every one of them, and into nothing at all in a\n // headless consumer. An attribute selector needs `\"` and `\\`\n // escaped and nothing else.\n actionButton: (value) => actionsEl.querySelector(\n `[data-action-value=\"${String(value).replace(/[\"\\\\]/g, '\\\\$&')}\"]`),\n setActionEnabled(value, enabled) {\n const btn = controls.actionButton(value);\n if (btn) btn.disabled = !enabled;\n return !!btn;\n },\n };\n\n // onMount runs after the next frame so layout has settled and\n // the inner content has a real bounding box for sizing.\n if (typeof onMount === 'function') {\n requestAnimationFrame(() => {\n try { onMount(bodyInner, controls); } catch (err) { console.warn(err); }\n });\n }\n // C28. THE FIRST FIELD, IF THERE IS ONE. Otherwise the primary button.\n //\n // A dialog that asks for a name should let you type it: *\"on any 'new'\n // dialog I would like to have the first input focused by default, so\n // that I can directly start typing.\"* Focusing the action button first\n // means every new table, project and column begins with a click into a\n // field that was the only place the caret could sensibly have been.\n //\n // The button remains the fallback, which is what keeps Enter useful on\n // a dialog that asks nothing \u2014 a confirmation has no field, and there\n // the primary action IS the answer.\n //\n // DISABLED CONTROLS ARE SKIPPED, and so is anything `readonly`: a form\n // whose first control is a read-only statement panel (C27's disabled\n // primary is the sibling case) would swallow the caret into a box that\n // cannot take it.\n requestAnimationFrame(() => {\n const field = bodyInner.querySelector(\n 'input:not([type=\"hidden\"]):not([disabled]):not([readonly]),'\n + ' textarea:not([disabled]):not([readonly]),'\n + ' select:not([disabled])');\n if (field) {\n field.focus();\n // The caret at the END of whatever is already there, not\n // selecting it: an edit dialog opens on a value the user means\n // to amend, and a selected value is one keystroke from gone.\n try { field.setSelectionRange?.(field.value.length, field.value.length); }\n catch { /* a `select`, or an input type with no selection */ }\n return;\n }\n const idx = acts.findIndex((a) => a.primary);\n const which = idx >= 0 ? idx : acts.length - 1;\n actionsEl.querySelector(`[data-action-idx=\"${which}\"]`)?.focus();\n });\n });\n}\n\n\n// \u2500\u2500\u2500 helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nfunction _estimateHeight(fields) {\n // Header (~36) + actions row (~46) + section dividers (~32 each)\n // + per-field rows (~46 text, ~140 textarea, ~32 checkbox)\n // + body padding. Clamped to 200..80vh. A `{ row }` is as tall as its\n // tallest field.\n const height = (f) => {\n if (f.section) return 32;\n const hint = f.hint ? 16 : 0;\n if (f.type === 'textarea') return 32 + (Number(f.rows) || 4) * 18 + hint;\n if (f.type === 'checkbox' || f.type === 'toggle') return 32 + hint;\n if (f.type === 'colorList') {\n const n = Array.isArray(f.default) ? f.default.length : 0;\n return 46 + Math.max(n, 1) * 40 + 40 + hint;\n }\n if (f.type === 'color') return 46 + (Array.isArray(f.presets) && f.presets.length ? 28 : 0) + hint;\n if (f.type === 'radio') {\n const opts = flatChoices(f.options);\n return 12 + opts.reduce((h, o) => h + 22 + (o.description || o.reason ? 16 : 0), 0) + hint;\n }\n return 46 + hint;\n };\n let body = 0;\n for (const f of fields) {\n body += Array.isArray(f?.row) ? Math.max(0, ..._formFields(f.row).map(height)) : height(f);\n }\n const base = 36 + 46 + 28 + body;\n const max = Math.floor(window.innerHeight * 0.8);\n return Math.max(200, Math.min(base, max));\n}\n\nfunction _estimateWidth(fields) {\n // Forms with a textarea, a colour list, a section divider or a row of\n // fields get the wider layout so multi-line content + grouped fields\n // breathe; otherwise 480 px is enough for label + single-line input pairs.\n // A row of three or more fields needs more than 640 px for inputs of a\n // usable width (BUG-0050): ~230 px per field (its label and input) past the\n // label column, clamped to 90% of the window.\n const widest = Math.max(0, ...fields.filter((f) => Array.isArray(f?.row)).map((f) => _formFields(f.row).length));\n if (widest >= 3) return Math.max(640, Math.min(170 + widest * 230, Math.floor(window.innerWidth * 0.9)));\n const wide = fields.some((f) => f && (f.type === 'textarea' || f.type === 'colorList' || f.section || Array.isArray(f.row)));\n return wide ? 640 : 480;\n}\n\n/** The fields of a form's entries, rows opened up, headings left out. */\nfunction _formFields(entries) {\n return entries.flatMap((e) => (Array.isArray(e?.row) ? e.row : [e])).filter((f) => f && f.section == null);\n}\n\n/** Does a field carry a `min` or a `max`? */\nfunction _bounded(f) {\n return f.min != null || f.max != null;\n}\n\n/** Is a `number` field's submitted value outside its `min` / `max`? */\nfunction _outOfRange(f, v) {\n if (f.type !== 'number' || !_bounded(f) || v == null || Number.isNaN(v)) return false;\n return (f.min != null && v < Number(f.min)) || (f.max != null && v > Number(f.max));\n}\n\n/** The field error for a number outside its bounds. */\nfunction _rangeMessage(f) {\n if (f.min != null && f.max != null) return `Must be between ${f.min} and ${f.max}.`;\n return f.min != null ? `Must be at least ${f.min}.` : `Must be at most ${f.max}.`;\n}\n\n/** A combobox's offered options: enabled, groups flattened. */\nfunction _offered(options) {\n return flatChoices(options).filter((o) => !o.disabled);\n}\n\n/**\n * A `select` with `create`: `createCombobox` over the enabled options. The box holds\n * the text; `read` is the value of the option that text names, else the text. A\n * disabled option is not offered, and a default or `write` naming one leaves the box\n * empty; typed all the same, it is `unavailable`.\n */\nfunction _mountCombobox(slot, f, value) {\n let options = f.options;\n const named = (text) => findChoice(flatChoices(options), text, true);\n const shown = (v) => (v == null || named(v)?.disabled ? '' : String(v));\n\n const hint = document.createElement('span');\n hint.className = 'twm-combobox__hint';\n hint.hidden = true;\n // With `create: true` the typed value simply IS the value \u2014 there is no\n // entity being made, so promising to \"create\" one is a lie that reads as\n // a warning.\n const noun = f.create === true ? null : _createSpec(f).hint || 'new entry';\n const updateHint = () => {\n const v = c.value.trim();\n const isNew = noun && v && !flatChoices(options).some((o) => String(o.value) === v);\n if (isNew) hint.textContent = `\u21B3 will create ${noun} \u201C${v}\u201D`;\n hint.hidden = !isNew;\n };\n\n const c = createCombobox({\n options: _offered(options),\n value: shown(value),\n name: f.name,\n placeholder: f.placeholder ?? 'type to pick or create\u2026',\n // Enter keeps what was typed: this field exists to accept a value nobody listed.\n autoHighlight: false,\n onChange: () => updateHint(),\n });\n if (f.required) c.input.required = true;\n c.el.appendChild(hint);\n slot.replaceWith(c.el);\n updateHint();\n return {\n read() {\n const o = named(c.value);\n return o ? o.value : c.value;\n },\n write(v) { c.value = shown(v); updateHint(); },\n focus: c.focus,\n unavailable() {\n const o = c.value === '' ? undefined : named(c.value);\n return o?.disabled ? (o.reason || '') : null;\n },\n setOptions(next) {\n options = next;\n c.setOptions(_offered(next));\n updateHint();\n },\n dispose: c.destroy,\n };\n}\n\n/**\n * Mount a field that is a component rather than markup \u2014 a `toggle`, a\n * `select`, `checklist` or `radio` drawn by `choice_controls.js`, a `select`\n * with `create` drawn by `createCombobox`, or a `color` / `colorList` \u2014 into the\n * `data-control-slot` its row left, and hand back what the form needs of it:\n * `{ read(), write(v), focus(), unavailable(), submit?(), error?(),\n * setOptions?(options), dispose?() }`. `unavailable()` is the reason (or '')\n * when the selected option is disabled, else null. `submit()`, where given,\n * is the value submitted when it differs from what `read()` shows (a colour's\n * hex, null while its box holds none), and `error()` is the field's own\n * message for a value it cannot submit, else null. `onChange(name)` hears the\n * reader's choice on a checklist or radio; a toggle or select is a named\n * control, heard as one. Null for any other field.\n */\nfunction _mountControl(host, f, value, onChange) {\n const slot = host.querySelector(`[data-control-slot=\"${f.name}\"]`);\n if (!slot) return null;\n if (f.type === 'toggle') {\n // Mounted INTO the slot: the slot is the row's `.twm-modal__toggle`\n // cell, and the switch's own root is the <label>.\n const toggle = new ToggleField({\n name: f.name,\n checked: value === true || value === 'true',\n ariaLabel: f.label || f.name,\n onText: f.onText ?? null,\n offText: f.offText ?? null,\n disabled: !!f.disabled,\n compact: !!f.compact,\n });\n slot.appendChild(toggle.render());\n return {\n read: () => toggle.get(),\n write: (v) => toggle.set(v),\n focus: () => toggle.input?.focus(),\n unavailable: () => null,\n dispose: () => toggle.dispose(),\n };\n }\n if (f.type === 'color' || f.type === 'colorList') {\n // Read as their text as it stands (a list as its rows' text), submitted\n // as hex: `getValue()` is null while a box holds no hex colour.\n const c = f.type === 'color'\n ? new ColorField({ name: f.name, value: value ?? '', presets: f.presets, label: f.label })\n : new ColorListField({ name: f.name, value: value ?? [], presets: f.presets });\n slot.replaceWith(c.render());\n const list = f.type === 'colorList';\n return {\n read: () => (list ? c.getTexts() : c.getText()),\n submit: () => c.getValue(),\n write: (v) => c.setValue(v),\n focus: () => c.focus(),\n unavailable: () => null,\n error: () => {\n if (c.getValue() !== null) return null;\n if (!list) return 'Not a hex colour: use #rgb or #rrggbb.';\n const bad = c.invalidIndexes().map((i) => i + 1).join(', ');\n return `Not a hex colour (row ${bad}): use #rgb or #rrggbb.`;\n },\n dispose: () => c.dispose(),\n };\n }\n if (f.type === 'select' && f.create) return _mountCombobox(slot, f, value);\n const common = { keepMissing: false, loose: true };\n const disabledReason = (entry) => (entry?.disabled ? (entry.reason || '') : null);\n if (f.type === 'select') {\n const c = selectBox(f.options, value, { ...common, valueAttr: 'value', className: '' });\n c.box.name = f.name;\n if (f.required) c.box.required = true;\n slot.replaceWith(c.box);\n return {\n // No option selected reads '', as an empty select always has (and\n // as it submits); a selected option reads as its own value.\n read: () => (c.entry() ? c.entry().value : ''),\n // A value the list does not offer enabled clears the select, as\n // writing an unknown `.value` always has (it then submits '').\n write: (v) => { if (!c.select(v)) c.box.selectedIndex = -1; },\n focus: () => c.box.focus(),\n unavailable: () => disabledReason(c.entry()),\n setOptions: c.setOptions,\n };\n }\n const list = (v) => (Array.isArray(v) ? v : (v == null || v === '' ? [] : [v]));\n if (f.type === 'checklist') {\n const c = toggleChips({ ...common, options: f.options, value: list(value), label: f.label || f.name,\n onChange: () => onChange(f.name) });\n slot.replaceWith(c.el);\n return {\n read: c.valueOf,\n write: (v) => c.setValue(list(v)),\n focus: () => c.el.querySelector('button:not(:disabled)')?.focus(),\n unavailable: () => null, // a disabled chip cannot be pressed, by hand or by set\n setOptions: c.setOptions,\n };\n }\n const c = choiceList({ ...common, options: f.options, value, label: f.label || f.name,\n name: `twm-form-${_modalSeq}-${f.name}`, onChange: () => onChange(f.name) });\n slot.replaceWith(c.el);\n return {\n read: () => c.valueOf() ?? null,\n write: (v) => { c.select(v); },\n focus: c.focus,\n unavailable: () => disabledReason(c.entry()),\n setOptions: c.setOptions,\n };\n}\n\n/** Is a `required` field without a value the browser cannot check for itself? */\nfunction _missing(f, v) {\n if (f.type === 'picker') return !v;\n if (f.type === 'checklist') return !Array.isArray(v) || v.length === 0;\n if (f.type === 'radio') return v == null;\n // A colour that is not a hex (null) is its own error, not a missing one.\n if (f.type === 'color') return v === '';\n if (f.type === 'colorList') return Array.isArray(v) && v.length === 0;\n return false;\n}\n\n/** Normalise a `create` spec. `true` means the typed value is accepted as-is. */\nfunction _createSpec(f) {\n if (!f || !f.create) return null;\n if (f.create === true) return { onCreate: async (v) => v, hint: null };\n return {\n onCreate: typeof f.create.onCreate === 'function' ? f.create.onCreate : async (v) => v,\n hint: f.create.hint ?? null,\n };\n}\n\n/** What a picker shows for `value`: the caller's `displayFor`, else the value. */\nfunction _pickerLabel(f, value) {\n if (typeof f.displayFor !== 'function') return value == null ? '' : String(value);\n try { return String(f.displayFor(value) ?? ''); }\n catch (err) { console.warn('[modal] displayFor threw', err); return String(value ?? ''); }\n}\n\n/** Hook a picker field's search button up to the caller's `pick()`, and keep\n * the hidden value and the visible display in step. */\nfunction _wirePicker(host, f) {\n const hidden = host.querySelector(`input[type=\"hidden\"][name=\"${f.name}\"]`);\n const display = host.querySelector(`[data-picker-display=\"${f.name}\"]`);\n const btn = host.querySelector(`[data-picker=\"${f.name}\"]`);\n if (!hidden || !display || !btn || typeof f.pick !== 'function') return;\n\n let busy = false;\n const open = async () => {\n if (busy) return; // one search at a time\n busy = true;\n let picked;\n try { picked = await f.pick(hidden.value); }\n catch (err) { console.warn('[modal] pick threw', err); picked = null; }\n finally { busy = false; }\n if (picked == null) return; // cancelled \u2014 leave it alone\n const isPair = typeof picked === 'object';\n hidden.value = String((isPair ? picked.value : picked) ?? '');\n display.value = isPair && picked.label != null\n ? String(picked.label) : _pickerLabel(f, hidden.value);\n // A hidden input fires no `change` of its own; this is the one the\n // field-error clear and `onFieldChange` listen for.\n fireEvent(hidden, 'change', { bubbles: true });\n };\n btn.addEventListener('click', open);\n // The read-only box is the obvious thing to click; make it work too.\n display.addEventListener('click', open);\n}\n\n\nfunction _renderEntry(f, defaults) {\n if (f && f.section != null) {\n // A named section is addressable by `setVisible`, so a heading can be\n // hidden along with the group it introduces.\n const attr = f.name ? ` data-field-row=\"${f.name}\"` : '';\n return `<div class=\"twm-modal__section\"${attr}>${_esc(f.section)}</div>`;\n }\n // A row is layout only: each field in it is rendered exactly as it would\n // be on its own line, with its own `data-field-row`.\n if (Array.isArray(f?.row)) {\n const cells = _formFields(f.row).map((g) => _renderField(g, defaults[g.name] ?? g.default));\n return `<div class=\"twm-modal__field-group\">${cells.join('')}</div>`;\n }\n return _renderField(f, defaults[f.name] ?? f.default);\n}\n\nfunction _renderField(f, value) {\n const required = f.required ? 'required' : '';\n const rowMod = (f.type === 'textarea' || f.type === 'checklist' || f.type === 'radio')\n ? ' twm-modal__row--multiline' : '';\n const hintHtml = f.hint\n ? `<div class=\"twm-modal__hint--field\">${_esc(f.hint)}</div>` : '';\n const errHtml = `<div class=\"twm-modal__field-error\" data-field-error=\"${f.name}\" hidden></div>`;\n const wrap = (inner, tag = 'label') => `\n <${tag} class=\"twm-modal__row${rowMod}\" data-field-row=\"${f.name}\">\n <span>${_esc(f.label || '')}</span>\n ${inner}\n ${hintHtml}\n ${errHtml}\n </${tag}>\n `;\n // A component's place, filled once the markup is in (`_mountControl`).\n const slot = `<span data-control-slot=\"${f.name}\"></span>`;\n\n if (f.type === 'checkbox') {\n const checked = (value === true || value === 'true') ? 'checked' : '';\n return `\n <label class=\"twm-modal__row\" data-field-row=\"${f.name}\">\n <span></span>\n <span class=\"twm-modal__check\">\n <input name=\"${f.name}\" type=\"checkbox\" ${checked}>\n <span>${_esc(f.label || '')}</span>\n </span>\n ${hintHtml}\n ${errHtml}\n </label>\n `;\n }\n\n // A group of controls is not one labelable control: a `<label>` round it\n // would hand every click on the row to its first chip or radio.\n if (f.type === 'checklist' || f.type === 'radio') return wrap(slot, 'div');\n\n // A div, not a label: the switch's own root is the <label>, and a label\n // may not hold another.\n if (f.type === 'toggle') {\n return wrap(`<span class=\"twm-modal__toggle\" data-control-slot=\"${f.name}\"></span>`, 'div');\n }\n\n if (f.type === 'textarea') {\n const v = value == null ? '' : String(value);\n const rows = f.rows != null ? `rows=\"${Number(f.rows) || 4}\"` : 'rows=\"4\"';\n const placeholder = f.placeholder ? `placeholder=\"${_esc(f.placeholder)}\"` : '';\n return wrap(`<textarea name=\"${f.name}\" ${rows} ${placeholder} ${required}>${_esc(v)}</textarea>`);\n }\n\n if (f.type === 'color' || f.type === 'colorList') {\n // The component is mounted into the slot by `_mountControl`. A list\n // is a group of controls, so its row is not a <label>: a label would\n // hand every click on it to the first row's swatch.\n if (f.type === 'color') return wrap(slot);\n return `\n <div class=\"twm-modal__row twm-modal__row--multiline\" data-field-row=\"${f.name}\" role=\"group\" aria-label=\"${_esc(f.label || '')}\">\n <span>${_esc(f.label || '')}</span>\n ${slot}\n ${hintHtml}\n ${errHtml}\n </div>\n `;\n }\n const v = value == null ? '' : String(value);\n if (f.type === 'picker') {\n // The display text and the stored value are different things (an id\n // vs. \"EPIC-0001 \u2014 Auth rewrite\"), so the value rides in a hidden\n // input \u2014 the one the submit reads by name \u2014 and the visible box is\n // read-only.\n const placeholder = f.placeholder ? `placeholder=\"${_esc(f.placeholder)}\"` : '';\n return wrap(`\n <div class=\"twm-picker\">\n <input type=\"hidden\" name=\"${f.name}\" value=\"${_esc(v)}\">\n <input class=\"twm-picker__display\" data-picker-display=\"${f.name}\" type=\"text\"\n value=\"${_esc(_pickerLabel(f, v))}\" ${placeholder} readonly>\n <button type=\"button\" class=\"twm-btn twm-picker__btn\" data-picker=\"${f.name}\"\n aria-label=\"Search\" title=\"Search\">\n <span class=\"material-symbols-outlined\" aria-hidden=\"true\">search</span>\n </button>\n </div>\n `);\n }\n if (f.type === 'select') return wrap(slot);\n const step = f.step != null ? `step=\"${f.step}\"` : '';\n const placeholder = f.placeholder ? `placeholder=\"${_esc(f.placeholder)}\"` : '';\n const type = (f.type === 'number' || f.type === 'password') ? f.type : 'text';\n // Attributes only a bounded number has, so no other input's markup moves.\n let bounds = '';\n if (f.type === 'number' && f.min != null) bounds += ` min=\"${_esc(f.min)}\"`;\n if (f.type === 'number' && f.max != null) bounds += ` max=\"${_esc(f.max)}\"`;\n return wrap(`<input name=\"${f.name}\" type=\"${type}\" value=\"${_esc(v)}\" ${step}${bounds} ${placeholder} ${required}>`);\n}\n\nfunction _esc(s) {\n return String(s == null ? '' : s)\n .replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n", "/**\n * context_menu.js \u2014 small popup menu in the `.context-menu` idiom the\n * DataTable's own right-click menu uses (./data_table.js).\n *\n * Usage:\n * showContextMenu(x, y, [\n * { label: 'Open', icon: 'open_in_new', action: 'open' },\n * { separator: true },\n * { label: 'Delete', icon: 'delete', action: 'delete', danger: true },\n * ], (action) => { ... });\n *\n * The menu auto-closes on outside click / scroll / Escape.\n *\n * \u2500\u2500 It is operable by keyboard \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Items were bare `<div>`s with a click listener: no role, no tab stop, no\n * arrow-key movement, and `showContextMenu` never moved focus into the menu.\n * A consumer that opened this from Shift+F10 \u2014 the rail in Tables does \u2014 put a\n * menu on screen that the keyboard could only dismiss. Every command in it was\n * unreachable without a pointer, and nothing said so.\n *\n * So an item is a `<button role=\"menuitem\">`, the first enabled one takes focus\n * when the menu opens, Up/Down/Home/End move between them and wrap, Enter and\n * Space activate, Escape closes, and focus returns to whatever had it before.\n * Disabled items are skipped by the arrows rather than focusable-but-inert.\n * `<button>` rather than a div with `tabindex`: the browser then gives Enter and\n * Space for free and screen readers announce it without further help.\n *\n * \u2500\u2500 It stays inside the window (BUG-0040) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * The top was clamped at 0 but nothing capped the height, so a long menu ran\n * off the bottom and could not scroll. `placeMenuInViewport` caps it at the\n * window's height less a margin; it scrolls inside, the arrows scroll the\n * focused item into view, and scrolling the menu itself does not close it.\n */\n\nimport { modalHost } from './modal.js';\nimport { placeMenuInViewport, moveMenuFocus, focusMenuItem } from '../utils/menu_viewport.js';\n\nlet _activeMenu = null;\nlet _returnFocusTo = null;\n\nexport function showContextMenu(x, y, items, onAction) {\n hideContextMenu();\n\n // Whatever had focus when the menu opened gets it back when the menu\n // closes. Without this a keyboard user who presses Escape is returned to\n // `document.body` and has to tab back to where they were.\n _returnFocusTo = document.activeElement;\n\n const menu = document.createElement('div');\n menu.className = 'twm-context-menu ea-context-menu';\n menu.setAttribute('role', 'menu');\n\n for (const it of items) {\n if (it.separator) {\n const sep = document.createElement('div');\n sep.className = 'twm-context-menu__separator';\n sep.setAttribute('role', 'separator');\n menu.appendChild(sep);\n continue;\n }\n const row = document.createElement('button');\n row.type = 'button';\n row.setAttribute('role', 'menuitem');\n let cls = 'twm-context-menu-item';\n if (it.danger) cls += ' twm-delete-node';\n if (it.disabled) cls += ' disabled';\n row.className = cls;\n if (it.disabled) {\n row.disabled = true;\n row.setAttribute('aria-disabled', 'true');\n }\n // A DISABLED ROW WITH NO EXPLANATION IS A DEAD CONTROL. `title` was\n // accepted by callers and rendered by nothing \u2014 the item was built with\n // one, the row silently dropped it, and the user got a greyed line with\n // no way to learn why. It is the same shape as the classes this\n // repository keeps finding: no error, no throw, and invisible to every\n // test that checks the row is disabled.\n if (it.title) row.title = it.title;\n row.innerHTML = `\n <span class=\"material-symbols-outlined\">${it.icon || ''}</span>\n <span>${escapeHtml(it.label)}</span>\n `;\n if (!it.disabled) {\n row.addEventListener('click', (e) => {\n e.stopPropagation();\n hideContextMenu();\n onAction?.(it.action);\n });\n }\n menu.appendChild(row);\n }\n\n // C25. THE SAME QUESTION A MODAL ASKS: which window is the user in? A\n // consumer spanning two browser windows sets the host when its focus moves;\n // null \u2014 every consumer today \u2014 is `document.body`, exactly as before. A\n // menu in the wrong window is worse than a modal in the wrong window,\n // because it is positioned at coordinates from the OTHER one.\n (modalHost() || document.body).appendChild(menu);\n menu.style.display = 'block';\n _activeMenu = menu;\n\n // Position inside the window, scrolling when taller than it (BUG-0040).\n placeMenuInViewport(menu, x, y);\n\n // Close on outside click / scroll / Escape. A scroll INSIDE the menu is\n // the menu being read, not the page moving under it.\n setTimeout(() => {\n document.addEventListener('mousedown', _outsideHandler, { once: true, capture: true });\n }, 0);\n document.addEventListener('keydown', _keyHandler);\n window.addEventListener('scroll', _scrollHandler, { capture: true });\n\n // Focus the first item the keyboard can actually use. `preventScroll` so a\n // menu opened near the bottom of a long page does not jump it.\n focusMenuItem(_enabledItems(menu)[0]);\n}\n\nexport function hideContextMenu() {\n if (!_activeMenu) return;\n const returnTo = _returnFocusTo;\n const held = _activeMenu.contains(document.activeElement);\n _activeMenu.remove();\n _activeMenu = null;\n _returnFocusTo = null;\n document.removeEventListener('keydown', _keyHandler);\n window.removeEventListener('scroll', _scrollHandler, { capture: true });\n // Only take focus back if the menu still had it. A click elsewhere has\n // already moved focus deliberately and must not be undone.\n if (held && returnTo?.isConnected) returnTo.focus?.({ preventScroll: true });\n}\n\nfunction _enabledItems(menu) {\n return [...menu.querySelectorAll('.twm-context-menu-item:not(.disabled)')];\n}\n\n/** Up/Down/Home/End move; the list WRAPS, which is what a menu of four items\n * wants and what every desktop menu does. Enter and Space are the button's\n * own, so they are not bound here. */\nfunction _keyHandler(e) {\n if (!_activeMenu) return;\n if (e.key === 'Escape') { e.preventDefault(); hideContextMenu(); return; }\n moveMenuFocus(e, _enabledItems(_activeMenu));\n}\n\nfunction _scrollHandler(e) {\n if (_activeMenu && e.target?.nodeType && _activeMenu.contains(e.target)) return;\n hideContextMenu();\n}\n\nfunction _outsideHandler(e) {\n if (_activeMenu && !_activeMenu.contains(e.target)) hideContextMenu();\n}\n\nfunction escapeHtml(s) {\n return String(s).replace(/[&<>\"']/g, (c) => ({\n '&': '&', '<': '<', '>': '>', '\"': '"', \"'\": ''',\n }[c]));\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsBA,IAAM,YAAY;AAClB,IAAM,eAAe,IAAI,SAAS;AAClC,IAAM,eAAe;AACrB,IAAM,kBAAkB,IAAI,YAAY;AAEjC,IAAM,eAAN,MAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAetB,YAAY;AAAA,IACR;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,WAAW;AAAA,IACX,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,WAAW;AAAA,EACf,IAAI,CAAC,GAAG;AACJ,SAAK,cAAc,eAAe,iBAAiB,KAAK,IAAI,CAAC;AAC7D,SAAK,QAAQ,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC;AAClD,SAAK,WAAW,OAAO,aAAa,aAAa,WAAW;AAC5D,SAAK,aAAa,OAAO,eAAe,aAAa,aAAa,KAAK,mBAAmB,KAAK,IAAI;AACnG,SAAK,aAAa,OAAO,eAAe,aAAa,aAAa,KAAK,mBAAmB,KAAK,IAAI;AACnG,SAAK,eAAe;AACpB,SAAK,gBAAgB;AACrB,SAAK,eAAe;AACpB,SAAK,cAAc;AACnB,SAAK,WAAW;AAEhB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,eAAe;AACpB,SAAK,iBAAiB;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS;AACL,QAAI,KAAK,MAAM;AACX,WAAK,SAAS;AACd,aAAO,KAAK;AAAA,IAChB;AAEA,SAAK,OAAO,SAAS,cAAc,KAAK;AACxC,SAAK,KAAK,YAAY;AACtB,SAAK,KAAK,KAAK,KAAK;AAEpB,SAAK,SAAS,SAAS,cAAc,KAAK;AAC1C,SAAK,OAAO,YAAY;AAExB,SAAK,KAAK,YAAY,KAAK,MAAM;AAGjC,QAAI,KAAK,eAAe;AACpB,YAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,aAAO,OAAO;AACd,aAAO,YAAY;AACnB,aAAO,YAAY,sDAAsD,KAAK,YAAY,KAAK,aAAa,CAAC;AAC7G,aAAO,iBAAiB,SAAS,MAAM,KAAK,QAAQ,CAAC;AACrD,WAAK,KAAK,YAAY,MAAM;AAAA,IAChC;AAEA,SAAK,SAAS;AACd,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW;AACP,WAAO,CAAC,GAAG,KAAK,KAAK;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,SAAS,OAAO;AACZ,SAAK,QAAQ,MAAM,QAAQ,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC;AAClD,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACN,UAAM,UAAU,KAAK,WAAW,KAAK,MAAM,MAAM;AACjD,SAAK,MAAM,KAAK,OAAO;AACvB,SAAK,cAAc;AACnB,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW,OAAO;AACd,QAAI,QAAQ,KAAK,SAAS,KAAK,MAAM,OAAQ;AAC7C,QAAI,KAAK,MAAM,UAAU,KAAK,SAAU;AAExC,SAAK,MAAM,OAAO,OAAO,CAAC;AAC1B,SAAK,cAAc;AACnB,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAW,OAAO,SAAS;AACvB,QAAI,QAAQ,KAAK,SAAS,KAAK,MAAM,OAAQ;AAE7C,SAAK,MAAM,KAAK,IAAI,EAAE,GAAG,KAAK,MAAM,KAAK,GAAG,GAAG,QAAQ;AACvD,SAAK,cAAc;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAS,WAAW,SAAS;AACzB,QAAI,YAAY,KAAK,aAAa,KAAK,MAAM,OAAQ;AACrD,QAAI,UAAU,KAAK,WAAW,KAAK,MAAM,OAAQ;AACjD,QAAI,cAAc,QAAS;AAE3B,UAAM,CAAC,IAAI,IAAI,KAAK,MAAM,OAAO,WAAW,CAAC;AAC7C,SAAK,MAAM,OAAO,SAAS,GAAG,IAAI;AAClC,SAAK,cAAc;AACnB,SAAK,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AACN,SAAK,cAAc,QAAQ;AAC3B,SAAK,eAAe;AACpB,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,QAAQ,CAAC;AAAA,EAClB;AAAA;AAAA,EAIA,WAAW;AACP,QAAI,CAAC,KAAK,OAAQ;AAElB,SAAK,OAAO,YAAY;AAExB,QAAI,KAAK,MAAM,WAAW,GAAG;AACzB,YAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,YAAM,YAAY;AAClB,YAAM,cAAc,KAAK;AACzB,WAAK,OAAO,YAAY,KAAK;AAC7B;AAAA,IACJ;AAEA,SAAK,MAAM,QAAQ,CAAC,MAAM,UAAU;AAChC,YAAM,MAAM,KAAK,WAAW,MAAM,KAAK;AACvC,WAAK,OAAO,YAAY,GAAG;AAAA,IAC/B,CAAC;AAcD,QAAI,KAAK,cAAc;AACnB,UAAI,CAAC,KAAK,cAAc;AACpB,aAAK,OAAO,iBAAiB,aAAa,CAAC,MAAM;AAC7C,eAAK,iBAAiB,CAAC,CAAC,EAAE,OAAO,UAAU,eAAe;AAAA,QAC9D,CAAC;AACD,aAAK,eAAe,IAAI,YAAY;AAAA,UAChC,WAAW,KAAK;AAAA,UAChB,cAAc;AAAA,UACd,SAAS;AAAA,UACT,MAAM;AAAA,UACN,gBAAgB;AAAA,UAChB,gBAAgB,MAAM;AAClB,kBAAM,aAAa,KAAK;AACxB,iBAAK,iBAAiB;AACtB,mBAAO;AAAA,UACX;AAAA,UACA,WAAW,CAAC,UAAU,KAAK,cAAc,KAAK;AAAA,QAClD,CAAC;AAAA,MACL;AACA,WAAK,aAAa,OAAO;AAAA,IAC7B;AAAA,EACJ;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,OAAO;AACjB,UAAM,OAAO,MACR,IAAI,CAAC,MAAM,KAAK,MAAM,OAAO,CAAC,CAAC,CAAC,EAChC,OAAO,CAAC,OAAO,OAAO,MAAS;AACpC,QAAI,KAAK,WAAW,KAAK,MAAM,OAAQ;AACvC,SAAK,QAAQ;AACb,SAAK,cAAc;AACnB,SAAK,SAAS;AAAA,EAClB;AAAA,EAEA,WAAW,MAAM,OAAO;AACpB,UAAM,MAAM,SAAS,cAAc,KAAK;AACxC,QAAI,YAAY;AAChB,QAAI,QAAQ,QAAQ;AAKpB,QAAI,KAAK,cAAc;AACnB,YAAM,SAAS,SAAS,cAAc,KAAK;AAC3C,aAAO,YAAY;AACnB,aAAO,YAAY;AACnB,UAAI,YAAY,MAAM;AAAA,IAC1B;AAGA,UAAM,UAAU,SAAS,cAAc,KAAK;AAC5C,YAAQ,YAAY;AAEpB,UAAM,YAAY;AAAA,MACd,QAAQ,CAAC,YAAY,KAAK,WAAW,OAAO,OAAO;AAAA,MACnD,QAAQ,MAAM,KAAK,WAAW,KAAK;AAAA,MACnC,QAAQ,MAAM,KAAK,SAAS,OAAO,QAAQ,CAAC;AAAA,MAC5C,UAAU,MAAM,KAAK,SAAS,OAAO,QAAQ,CAAC;AAAA,IAClD;AAEA,SAAK,WAAW,SAAS,MAAM,OAAO,SAAS;AAC/C,QAAI,YAAY,OAAO;AAGvB,QAAI,KAAK,aAAa;AAClB,YAAM,YAAY,KAAK,MAAM,SAAS,KAAK;AAC3C,YAAM,YAAY,SAAS,cAAc,QAAQ;AACjD,gBAAU,OAAO;AACjB,gBAAU,YAAY;AACtB,gBAAU,WAAW,CAAC;AACtB,gBAAU,QAAQ,YAAY,WAAW,WAAW,KAAK,QAAQ;AACjE,gBAAU,YAAY;AACtB,gBAAU,iBAAiB,SAAS,MAAM;AACtC,YAAI,UAAW,MAAK,WAAW,KAAK;AAAA,MACxC,CAAC;AACD,UAAI,YAAY,SAAS;AAAA,IAC7B;AAEA,WAAO;AAAA,EACX;AAAA,EAEA,mBAAmB,WAAW,MAAM,OAAO,WAAW;AAClD,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,OAAO;AACb,UAAM,YAAY;AAClB,UAAM,QAAQ,KAAK,QAAQ,KAAK,SAAS;AACzC,UAAM,cAAc,QAAQ,QAAQ,CAAC;AACrC,UAAM,iBAAiB,UAAU,MAAM;AACnC,gBAAU,OAAO,EAAE,MAAM,MAAM,MAAM,CAAC;AAAA,IAC1C,CAAC;AACD,cAAU,YAAY,KAAK;AAAA,EAC/B;AAAA,EAEA,mBAAmB,OAAO;AACtB,WAAO;AAAA,MACH,IAAI,QAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,MACjE,MAAM,OAAO,QAAQ,CAAC;AAAA,IAC1B;AAAA,EACJ;AAAA,EAEA,gBAAgB;AACZ,QAAI,KAAK,UAAU;AACf,WAAK,SAAS,CAAC,GAAG,KAAK,KAAK,CAAC;AAAA,IACjC;AAAA,EACJ;AAAA,EAGA,YAAY,KAAK;AACb,WAAO,OAAO,OAAO,EAAE,EAClB,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM;AAAA,EAC7B;AACJ;;;AC3SA,IAAI,OAAO;AAGX,IAAM,QAAQ,CAAC,SAAS;AACpB,QAAM,IAAI,OAAO,QAAQ,EAAE,EAAE,KAAK;AAClC,SAAO,WAAW,CAAC,IAAI,aAAa,CAAC,IAAI;AAC7C;AAEO,IAAM,iBAAN,MAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUxB,YAAY;AAAA,IACR,QAAQ,CAAC;AAAA,IAAG,UAAU,CAAC;AAAA,IAAG,WAAW;AAAA,IAAW,WAAW;AAAA,IAC3D,OAAO;AAAA,IAAM,WAAW;AAAA,EAC5B,IAAI,CAAC,GAAG;AACJ,SAAK,UAAU,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC;AAEnD,SAAK,WAAW,aAAa,OAAO,YAAY,EAAE,CAAC,KAAK,OAAO,YAAY,EAAE;AAC7E,SAAK,WAAW;AAChB,SAAK,OAAO;AACZ,SAAK,WAAW,OAAO,aAAa,aAAa,WAAW;AAG5D,SAAK,UAAU,CAAC;AAEhB,SAAK,UAAU;AAEf,SAAK,WAAW;AAChB,SAAK,OAAO,IAAI,aAAa;AAAA,MACzB,OAAO,KAAK,SAAS,KAAK;AAAA,MAC1B,eAAe;AAAA,MACf,cAAc;AAAA,MACd,YAAY,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,KAAK,SAAS;AAAA,MACrD,YAAY,CAAC,WAAW,MAAM,OAAO,cACjC,KAAK,WAAW,WAAW,MAAM,OAAO,SAAS;AAAA;AAAA;AAAA;AAAA,MAIrD,UAAU,MAAM;AACZ,YAAI,CAAC,KAAK,SAAU,MAAK,YAAY;AACrC,aAAK,MAAM,KAAK,OAAO;AAAA,MAC3B;AAAA,IACJ,CAAC;AACD,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACjB;AAAA,EAEA,SAAS;AACL,QAAI,KAAK,KAAM,QAAO,KAAK;AAC3B,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,QAAI,KAAK,MAAM;AACX,YAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,YAAM,OAAO;AACb,YAAM,OAAO,KAAK;AAClB,WAAK,YAAY,KAAK;AACtB,WAAK,QAAQ;AAAA,IACjB;AACA,SAAK,YAAY,KAAK,KAAK,OAAO,CAAC;AACnC,SAAK,OAAO;AACZ,SAAK,YAAY;AACjB,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,WAAW;AACP,UAAM,MAAM,KAAK,SAAS,EAAE,IAAI,KAAK;AACrC,WAAO,IAAI,SAAS,IAAI,IAAI,OAAO;AAAA,EACvC;AAAA;AAAA,EAGA,WAAW;AACP,WAAO,KAAK,KAAK,SAAS,EAAE,IAAI,CAAC,SAAS,OAAO,KAAK,QAAQ,EAAE,CAAC;AAAA,EACrE;AAAA;AAAA,EAGA,iBAAiB;AACb,UAAM,MAAM,CAAC;AACb,SAAK,SAAS,EAAE,QAAQ,CAAC,MAAM,MAAM;AAAE,UAAI,CAAC,MAAM,IAAI,EAAG,KAAI,KAAK,CAAC;AAAA,IAAG,CAAC;AACvE,WAAO;AAAA,EACX;AAAA;AAAA,EAGA,SAAS,QAAQ;AACb,SAAK,YAAY;AACjB,SAAK,KAAK,SAAS,KAAK,SAAS,MAAM,CAAC;AACxC,SAAK,YAAY;AAAA,EACrB;AAAA;AAAA,EAGA,QAAQ;AACJ,UAAM,MAAM,KAAK,eAAe,EAAE,CAAC;AACnC,UAAM,QAAQ,KAAK,QAAQ,OAAO,CAAC;AACnC,QAAI,OAAO;AAAE,YAAM,MAAM;AAAG;AAAA,IAAQ;AACpC,SAAK,MAAM,cAAc,yBAAyB,GAAG,MAAM;AAAA,EAC/D;AAAA,EAEA,UAAU;AACN,SAAK,YAAY;AACjB,SAAK,KAAK,QAAQ;AAClB,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACjB;AAAA,EAEA,SAAS,QAAQ;AAGb,YAAQ,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,MACrD,IAAI,EAAE;AAAA,MACN,MAAM,aAAa,OAAO,KAAK,EAAE,CAAC,KAAK,OAAO,KAAK,EAAE;AAAA,IACzD,EAAE;AAAA,EACN;AAAA;AAAA,EAGA,cAAc;AACV,eAAW,KAAK,KAAK,QAAS,IAAG,QAAQ;AACzC,SAAK,UAAU,CAAC;AAAA,EACpB;AAAA,EAEA,WAAW,WAAW,MAAM,OAAO,WAAW;AAC1C,UAAM,QAAQ,KAAK,KAAK,SAAS,EAAE;AAEnC,UAAM,MAAM,SAAS,cAAc,KAAK;AACxC,QAAI,YAAY;AAChB,UAAM,QAAQ,IAAI,WAAW;AAAA,MACzB,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,OAAO,UAAU,QAAQ,CAAC;AAAA;AAAA;AAAA,MAG1B,UAAU,CAAC,IAAI,EAAE,OAAO,MAAM;AAC1B,aAAK,UAAU;AACf,aAAK,WAAW;AAChB,YAAI;AAAE,oBAAU,OAAO,EAAE,MAAM,MAAM,QAAQ,EAAE,CAAC;AAAA,QAAG,UACnD;AAAU,eAAK,UAAU;AAAM,eAAK,WAAW;AAAA,QAAO;AAAA,MAC1D;AAAA,IACJ,CAAC;AACD,SAAK,QAAQ,KAAK,IAAI;AACtB,QAAI,YAAY,MAAM,OAAO,CAAC;AAE9B,UAAM,OAAO,CAAC,MAAM,OAAO,UAAU,OAAO;AACxC,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,OAAO;AACX,UAAI,YAAY;AAChB,UAAI,QAAQ;AACZ,UAAI,aAAa,cAAc,KAAK;AACpC,UAAI,WAAW;AACf,YAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,YAAM,YAAY;AAClB,YAAM,aAAa,eAAe,MAAM;AACxC,YAAM,cAAc;AACpB,UAAI,YAAY,KAAK;AACrB,UAAI,iBAAiB,SAAS,EAAE;AAChC,UAAI,YAAY,GAAG;AAAA,IACvB;AACA,SAAK,gBAAgB,WAAW,UAAU,GAAG,UAAU,MAAM;AAC7D,SAAK,kBAAkB,aAAa,UAAU,QAAQ,GAAG,UAAU,QAAQ;AAC3E,cAAU,YAAY,GAAG;AAAA,EAC7B;AAAA,EAEA,cAAc;AACV,QAAI,KAAK,MAAO,MAAK,MAAM,QAAQ,KAAK,UAAU,KAAK,SAAS,CAAC;AAAA,EACrE;AAAA,EAEA,MAAM,QAAQ;AACV,SAAK,YAAY;AACjB,QAAI,KAAK,OAAO;AACZ,gBAAU,KAAK,OAAO,SAAS,EAAE,SAAS,KAAK,CAAC;AAChD,UAAI,OAAQ,WAAU,KAAK,OAAO,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,IACjE;AACA,SAAK,WAAW,KAAK,SAAS,GAAG,EAAE,OAAO,CAAC;AAAA,EAC/C;AACJ;;;AC/LA,IAAI,MAAM;AAEV,SAAS,KAAK,KAAK,WAAW,MAAM;AAChC,QAAM,IAAI,SAAS,cAAc,GAAG;AACpC,MAAI,UAAW,GAAE,YAAY;AAC7B,MAAI,SAAS,UAAa,SAAS,KAAM,GAAE,cAAc,OAAO,IAAI;AACpE,SAAO;AACX;AAGA,SAAS,OAAO,QAAQ,MAAM,QAAQ;AAClC,QAAM,KAAK,SAAS,KAAK,YAAY,EAAE,QAAQ,OAAO,YAAY,CAAC,IAAI;AACvE,MAAI,KAAK,GAAG;AAAE,WAAO,cAAc;AAAM;AAAA,EAAQ;AACjD,SAAO;AAAA,IAAO,KAAK,MAAM,GAAG,EAAE;AAAA,IAAG,KAAK,QAAQ,0BAA0B,KAAK,MAAM,IAAI,KAAK,OAAO,MAAM,CAAC;AAAA,IAC5F,KAAK,MAAM,KAAK,OAAO,MAAM;AAAA,EAAC;AAChD;AAOO,SAAS,iBAAiB,EAAE,QAAQ,WAAW,KAAK,GAAG;AAC1D,QAAM,KAAK,mBAAmB,EAAE,GAAG;AACnC,QAAM,KAAK,KAAK,OAAO,iBAAiB;AACxC,KAAG,KAAK;AACR,KAAG,aAAa,QAAQ,SAAS;AAGjC,MAAI,OAAO,CAAC;AACZ,MAAI,SAAS;AAEb,QAAM,cAAc,MAAM;AACtB,SAAK,QAAQ,CAAC,EAAE,KAAAA,KAAI,GAAG,MAAMA,KAAI,UAAU,OAAO,gCAAgC,MAAM,MAAM,CAAC;AAC/F,UAAM,MAAM,KAAK,MAAM,GAAG;AAE1B,SAAK,iBAAiB,EAAE,OAAO,UAAU,CAAC;AAC1C,eAAW,MAAM,IAAI,KAAK,IAAI;AAAA,EAClC;AAEA,QAAM,SAAS,CAAC,QAAQ,EAAE,QAAQ,MAAM,UAAU,MAAM;AACpD,UAAM,MAAM,KAAK,OAAO,sBAAsB;AAC9C,QAAI,KAAK,GAAG,EAAE,IAAI,KAAK,MAAM;AAC7B,QAAI,aAAa,QAAQ,QAAQ;AACjC,QAAI,aAAa,iBAAiB,OAAO,CAAC,CAAC,YAAY,MAAM,CAAC,CAAC;AAC/D,QAAI,OAAO,SAAU,KAAI,aAAa,iBAAiB,MAAM;AAC7D,QAAI,QAAQ,OAAO,cAAc,GAAG,OAAO,KAAK,WAAM,OAAO,WAAW,KAAK,OAAO;AACpF,QAAI,QAAQ;AACR,YAAM,QAAQ,KAAK,QAAQ,oDAAoD,OAAO,QAAQ,EAAE;AAChG,YAAM,aAAa,eAAe,MAAM;AACxC,UAAI,YAAY,KAAK;AAAA,IACzB;AACA,UAAM,QAAQ,KAAK,QAAQ,wBAAwB;AACnD,UAAM,QAAQ,KAAK,QAAQ,wBAAwB;AACnD,WAAO,OAAO,OAAO,OAAO,IAAI;AAChC,UAAM,YAAY,KAAK;AACvB,QAAI,OAAO,YAAa,OAAM,YAAY,KAAK,QAAQ,gCAAgC,OAAO,WAAW,CAAC;AAC1G,QAAI,OAAO,YAAY,OAAO,OAAQ,OAAM,YAAY,KAAK,QAAQ,sBAAsB,OAAO,MAAM,CAAC;AACzG,QAAI,YAAY,KAAK;AACrB,QAAI,OAAO,KAAM,KAAI,YAAY,KAAK,QAAQ,yBAAyB,OAAO,IAAI,CAAC;AACnF,WAAO;AAAA,EACX;AAEA,QAAM,UAAU,MAAM,KAAK,IAAI,CAAC,GAAG,MAAO,EAAE,OAAO,WAAW,KAAK,CAAE,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC;AAG3F,KAAG,iBAAiB,aAAa,CAAC,OAAO,GAAG,eAAe,CAAC;AAC5D,KAAG,iBAAiB,SAAS,CAAC,OAAO;AACjC,UAAM,MAAM,GAAG,OAAO,UAAU,iBAAiB;AACjD,UAAM,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG;AAC1C,QAAI,OAAO,CAAC,IAAI,OAAO,SAAU,QAAO,IAAI,MAAM;AAAA,EACtD,CAAC;AAED,SAAO;AAAA,IACH;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOA,QAAQ,UAAU,EAAE,OAAO,IAAI,YAAY,KAAK,IAAI,CAAC,GAAG;AACpD,aAAO,CAAC;AACR,eAAS;AACT,SAAG,gBAAgB;AACnB,YAAM,SAAS,SAAS,KAAK,CAAC,MAAM,EAAE,MAAM,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC;AAC/D,iBAAW,EAAE,SAAS,MAAM,KAAK,UAAU;AACvC,YAAI,SAAS;AACb,YAAI,WAAW,MAAM;AACjB,mBAAS,KAAK,OAAO,0BAA0B;AAC/C,iBAAO,aAAa,QAAQ,OAAO;AACnC,iBAAO,aAAa,cAAc,OAAO;AACzC,gBAAM,QAAQ,KAAK,OAAO,qBAAqB,OAAO;AACtD,gBAAM,aAAa,eAAe,MAAM;AACxC,iBAAO,YAAY,KAAK;AACxB,aAAG,YAAY,MAAM;AAAA,QACzB;AACA,mBAAW,UAAU,OAAO;AACxB,gBAAM,MAAM,OAAO,QAAQ,EAAE,QAAQ,MAAM,UAAU,CAAC;AACtD,eAAK,KAAK,EAAE,QAAQ,IAAI,CAAC;AACzB,iBAAO,YAAY,GAAG;AAAA,QAC1B;AAAA,MACJ;AACA,kBAAY;AAAA,IAChB;AAAA;AAAA,IAEA,WAAW,MAAM;AACb,aAAO,CAAC;AACR,eAAS;AACT,SAAG,gBAAgB,KAAK,OAAO,4BAA4B,IAAI,CAAC;AAChE,kBAAY;AAAA,IAChB;AAAA;AAAA,IAEA,IAAI,OAAO;AAAE,aAAO,KAAK;AAAA,IAAQ;AAAA;AAAA,IAEjC,SAAS,MAAM,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA;AAAA,IAEvC,cAAc,MAAM,KAAK,MAAM,GAAG,UAAU;AAAA;AAAA,IAE5C,UAAU,OAAO;AACb,eAAS,KAAK,KAAK,KAAK,CAAC,KAAK,KAAK,EAAE,OAAO,WAAW,QAAQ;AAC/D,kBAAY;AAAA,IAChB;AAAA;AAAA,IAEA,KAAK,MAAM;AACP,YAAM,QAAQ,QAAQ;AACtB,UAAI,CAAC,MAAM,OAAQ;AACnB,YAAM,KAAK,MAAM,QAAQ,MAAM;AAC/B,YAAM,OAAO,KAAK,IAAK,OAAO,IAAI,IAAI,MAAM,SAAS,KAAM,KAAK,OAAO,MAAM,UAAU,MAAM;AAC7F,eAAS,MAAM,IAAI;AACnB,kBAAY;AAAA,IAChB;AAAA;AAAA,IAEA,UAAU,MAAM;AACZ,YAAM,QAAQ,QAAQ;AACtB,eAAS,MAAM,SAAS,MAAM,OAAO,IAAI,IAAI,MAAM,SAAS,CAAC,IAAI;AACjE,kBAAY;AAAA,IAChB;AAAA,EACJ;AACJ;;;ACxHA,IAAM,cAAc;AAEpB,IAAIC,OAAM;AAqCH,SAAS,mBAAmB,OAAO;AAAA,EACtC,UAAU,CAAC;AAAA,EAAG;AAAA,EAAQ,SAAS;AAAA,EAAM,YAAY;AAAA,EAAM,gBAAgB;AAAA,EAAO,cAAc;AAAA,EAC5F,YAAY,CAAC,SAAS;AAAA,EAAM,cAAc;AAAA,EAAO,YAAY;AAAA,EAAO,cAAc;AAAA,EAClF,YAAY;AAAA,EAA+B,WAAW;AAAA,EAAa,iBAAiB;AAAA,EAAI,WAAW;AACvG,IAAI,CAAC,GAAG;AACJ,MAAI,SAAS;AACb,MAAI,QAAQ;AAEZ,MAAI,SAAS;AAEb,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,QAAQ;AACZ,MAAI,aAAa;AAEjB,MAAI,UAAU;AAEd,QAAM,OAAO,iBAAiB;AAAA,IAC1B,QAAQ,CAAC,WAAW,KAAK,MAAM;AAAA,IAC/B,UAAU,CAAC,OAAO;AACd,UAAI,GAAI,OAAM,aAAa,yBAAyB,EAAE;AAAA,UACjD,OAAM,gBAAgB,uBAAuB;AAAA,IACtD;AAAA,EACJ,CAAC;AACD,QAAM,QAAQ,SAAS,cAAc,KAAK;AAC1C,QAAM,YAAY,mBAAmB,iBAAiB,IAAI,cAAc,KAAK,EAAE;AAC/E,QAAM,YAAY,KAAK,EAAE;AAGzB,QAAM,aAAa,gBAAgB,KAAK;AACxC,QAAM,aAAa,QAAQ,UAAU;AACrC,QAAM,aAAa,qBAAqB,MAAM;AAC9C,QAAM,aAAa,iBAAiB,OAAO;AAC3C,QAAM,aAAa,iBAAiB,KAAK,EAAE;AAE3C,QAAM,OAAO,MAAM;AACf,QAAI,OAAO;AAAE,YAAM,MAAM;AAAG;AAAA,IAAQ;AACpC,YAAQ,kBAAkB;AAAA,MACtB,QAAQ,UAAU;AAAA,MAAO,IAAI;AAAA,MAAO,KAAK;AAAA,MAAG,YAAY;AAAA,MAAM,aAAa;AAAA,MAC3E,UAAU;AACN,gBAAQ;AACR,iBAAS;AACT,cAAM,aAAa,iBAAiB,OAAO;AAC3C,cAAM,gBAAgB,uBAAuB;AAAA,MACjD;AAAA,IACJ,CAAC;AAED,QAAI,CAAC,OAAO;AAAE,eAAS;AAAO;AAAA,IAAQ;AACtC,UAAM,aAAa,iBAAiB,MAAM;AAAA,EAC9C;AAGA,WAAS,SAAS;AACd,iBAAa,KAAK;AAClB,aAAS;AACT,gBAAY,MAAM;AAClB,iBAAa;AAAA,EACjB;AAEA,WAAS,MAAM,SAAS,UAAU;AAC9B,aAAS;AACT,WAAO;AACP,WAAO,MAAM,MAAM;AAAA,EACvB;AAGA,WAAS,UAAU,OAAO;AACtB,UAAM,OAAO,UAAU,MAAM,KAAK,CAAC;AACnC,QAAI,CAAC,iBAAiB,CAAC,MAAM;AAAE,WAAK,UAAU,EAAE;AAAG;AAAA,IAAQ;AAC3D,UAAM,QAAQ,KAAK,QAAQ,EAAE,UAAU,CAAC,MAAM,UAAU,WAAW,EAAE,KAAK,CAAC,MAAM,IAAI;AACrF,QAAI,SAAS,EAAG,MAAK,UAAU,KAAK;AAAA,aAC3B,cAAc,IAAI,EAAG,MAAK,UAAU,EAAE;AAAA,QAC1C,MAAK,UAAU,CAAC;AAAA,EACzB;AAEA,WAAS,SAAS,UAAU;AACxB,QAAI,CAAC,OAAQ;AAGb,QAAI,CAAC,SAAS,QAAQ;AAClB,aAAO,MAAM,OAAO;AACpB,eAAS;AACT;AAAA,IACJ;AACA,UAAM,OAAO,SAAS;AACtB,SAAK,QAAQ,UAAU,EAAE,MAAM,UAAU,KAAK,KAAK,CAAC,GAAG,UAAU,CAAC;AAClE,SAAK;AACL,cAAU,IAAI;AAAA,EAClB;AAEA,WAAS,IAAI,MAAM;AACf,iBAAa,IAAI,gBAAgB;AACjC,UAAM,QAAQ;AACd,UAAM,SAAS,CAAC,QAAQ;AACpB,UAAI,UAAU,MAAO;AACrB,cAAQ,KAAK,mCAAmC,GAAG;AACnD,UAAI,CAAC,OAAQ;AACb,WAAK,WAAW,SAAS;AACzB,WAAK;AAAA,IACT;AACA,QAAI;AACJ,QAAI;AAAE,eAAS,OAAO,MAAM,EAAE,QAAQ,WAAW,OAAO,CAAC;AAAA,IAAG,SACrD,KAAK;AAAE,aAAO,GAAG;AAAG;AAAA,IAAQ;AACnC,QAAI,OAAO,QAAQ,SAAS,YAAY;AAAE,eAAS,eAAe,MAAM,CAAC;AAAG;AAAA,IAAQ;AAEpF,QAAI,CAAC,KAAK,QAAQ,QAAQ;AAAE,WAAK,WAAW,WAAW;AAAG,WAAK;AAAA,IAAG;AAClE,WAAO,KAAK,CAAC,SAAS;AAAE,UAAI,UAAU,MAAO,UAAS,eAAe,IAAI,CAAC;AAAA,IAAG,GAAG,MAAM;AAAA,EAC1F;AAGA,WAAS,UAAU;AACf,WAAO;AACP,QAAI,OAAO,WAAW,YAAY;AAC9B,YAAM,MAAM,eAAe,MAAM;AACjC,eAAS,UAAU,OAAO,MAAM,eAAe,KAAK,KAAK,CAAC;AAC1D;AAAA,IACJ;AACA,UAAM,OAAO,SAAS;AACtB,QAAI,UAAU,QAAQ,YAAY,GAAG;AAAE,UAAI,IAAI;AAAG;AAAA,IAAQ;AAC1D,UAAM,QAAQ;AACd,YAAQ,WAAW,MAAM;AAAE,UAAI,UAAU,MAAO,KAAI,IAAI;AAAA,IAAG,GAAG,QAAQ;AAAA,EAC1E;AAEA,WAAS,KAAK,QAAQ;AAClB,UAAM,MAAM;AACZ,cAAU;AACV,aAAS,MAAM;AACf,cAAU;AAAA,EACd;AAGA,WAAS,aAAa;AAClB,UAAM,SAAS,SAAS,KAAK,aAAa;AAC1C,QAAI,CAAC,OAAQ,QAAO;AACpB,SAAK,MAAM;AACX,WAAO;AAAA,EACX;AAEA,QAAM,UAAU,CAAC,SAAS;AAAE,YAAQ;AAAM,aAAS;AAAM,YAAQ;AAAA,EAAG;AAEpE,QAAM,UAAU,MAAM,QAAQ,MAAM,KAAK;AACzC,QAAM,UAAU,MAAM,QAAQ,IAAI;AAClC,QAAM,UAAU,MAAM;AAAE,QAAI,eAAe,CAAC,SAAS,CAAC,QAAS,SAAQ,MAAM,SAAS,IAAI;AAAA,EAAG;AAC7F,QAAM,SAAS,MAAM,MAAM,MAAM;AACjC,QAAM,QAAQ,CAAC,OAAO;AAClB,QAAI,GAAG,YAAa;AACpB,QAAI,GAAG,QAAQ,eAAe,GAAG,QAAQ,WAAW;AAChD,SAAG,eAAe;AAClB,SAAG,gBAAgB;AACnB,UAAI,CAAC,MAAO,SAAQ,IAAI;AACxB,WAAK,KAAK,GAAG,QAAQ,cAAc,IAAI,EAAE;AACzC;AAAA,IACJ;AACA,QAAI,GAAG,QAAQ,SAAS;AACpB,UAAI,CAAC,MAAO;AACZ,UAAI,WAAW,GAAG;AACd,WAAG,eAAe;AAClB,WAAG,yBAAyB;AAC5B;AAAA,MACJ;AACA,YAAM;AACN,UAAI,UAAW;AACf,SAAG,eAAe;AAClB,SAAG,gBAAgB;AACnB,iBAAW;AACX;AAAA,IACJ;AACA,QAAI,GAAG,QAAQ,OAAO;AAClB,YAAM,MAAM;AACZ,iBAAW;AAAA,IACf;AAAA,EACJ;AAEA,QAAM,iBAAiB,SAAS,OAAO;AACvC,QAAM,iBAAiB,SAAS,OAAO;AACvC,QAAM,iBAAiB,SAAS,OAAO;AACvC,QAAM,iBAAiB,QAAQ,MAAM;AACrC,QAAM,iBAAiB,WAAW,KAAK;AAEvC,SAAO;AAAA,IACH,IAAI,SAAS;AAAE,aAAO,CAAC,CAAC;AAAA,IAAO;AAAA;AAAA,IAE/B,KAAK,OAAO,MAAM;AAAE,cAAQ,IAAI;AAAA,IAAG;AAAA,IACnC;AAAA,IACA;AAAA;AAAA,IAEA,WAAW,MAAM;AACb,eAAS;AACT,UAAI,OAAQ,SAAQ;AAAA,IACxB;AAAA,IACA,UAAU;AACN,YAAM;AACN,YAAM,oBAAoB,SAAS,OAAO;AAC1C,YAAM,oBAAoB,SAAS,OAAO;AAC1C,YAAM,oBAAoB,SAAS,OAAO;AAC1C,YAAM,oBAAoB,QAAQ,MAAM;AACxC,YAAM,oBAAoB,WAAW,KAAK;AAAA,IAC9C;AAAA,EACJ;AACJ;AA8BO,SAAS,eAAe;AAAA,EAC3B,UAAU,CAAC;AAAA,EAAG,QAAQ;AAAA,EAAI,WAAW;AAAA,EAAM,YAAY;AAAA,EAAI,iBAAiB;AAAA,EAAI,cAAc;AAAA,EAAI,QAAQ;AAAA,EAC1G,YAAY;AAAA,EAAI,OAAO;AAAA,EAAM,WAAW;AAAA,EAAO,YAAY,CAAC,SAAS;AAAA,EAAM,gBAAgB;AAAA,EAAM,cAAc;AAAA,EAC/G,WAAW;AAAA,EAAM;AAAA,EAAa;AAAA,EAAW;AAC7C,IAAI,CAAC,GAAG;AACJ,QAAM,SAAS,OAAO,SAAS,EAAE;AACjC,MAAI,UAAU,UAAU,MAAM;AAE9B,QAAM,KAAK,SAAS,cAAc,KAAK;AACvC,KAAG,YAAY,eAAe,YAAY,IAAI,SAAS,KAAK,EAAE;AAE9D,QAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,OAAO;AACb,QAAM,YAAY;AAClB,QAAM,aAAa;AACnB,QAAM,QAAQ;AACd,QAAM,WAAW,CAAC,CAAC;AACnB,MAAI,KAAM,OAAM,OAAO;AACvB,MAAI,YAAa,OAAM,cAAc;AACrC,MAAI,MAAO,OAAM,QAAQ;AACzB,MAAI,UAAW,OAAM,aAAa,cAAc,SAAS;AAEzD,QAAM,QAAQ,SAAS,cAAc,GAAG;AACxC,QAAM,YAAY;AAClB,QAAM,SAAS;AACf,QAAM,KAAK,sBAAsB,EAAEA,IAAG;AACtC,KAAG,OAAO,OAAO,KAAK;AAEtB,WAAS,OAAO,MAAM,QAAQ;AAC1B,UAAM,UAAU,UAAU,OAAO,QAAQ,EAAE,CAAC;AAC5C,QAAI,YAAY,QAAS;AACzB,cAAU;AACV,eAAW,SAAS,UAAU,IAAI;AAAA,EACtC;AAEA,QAAM,gBAAgB,MAAM;AACxB,UAAM,SAAS;AACf,UAAM,cAAc;AACpB,UAAM,gBAAgB,cAAc;AACpC,UAAM,gBAAgB,kBAAkB;AAAA,EAC5C;AAGA,WAAS,gBAAgB;AACrB,UAAM,UAAU,YAAY,UAAW,SAAS,OAAO,KAAK,OAAQ;AACpE,QAAI,CAAC,SAAS;AAAE,oBAAc;AAAG;AAAA,IAAQ;AACzC,UAAM,cAAc;AACpB,UAAM,SAAS;AACf,UAAM,aAAa,gBAAgB,MAAM;AACzC,UAAM,aAAa,oBAAoB,MAAM,EAAE;AAAA,EACnD;AAGA,WAAS,SAAS;AACd,WAAO,MAAM,OAAO,IAAI;AACxB,QAAI,MAAM,UAAU,QAAS,OAAM,QAAQ;AAC3C,kBAAc;AAAA,EAClB;AAGA,QAAM,iBAAiB,SAAS,MAAM;AAElC,WAAO,MAAM,OAAO,IAAI;AACxB,kBAAc;AAAA,EAClB,CAAC;AAED,QAAM,OAAO,mBAAmB,OAAO;AAAA,IACnC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,CAAC,MAAM,UAAU,WAAW,EAAE,KAAK,CAAC,MAAM;AAAA,IACrD,UAAU;AAAA,IACV,OAAO,QAAQ;AACX,YAAM,QAAQ,WAAW,OAAO,KAAK;AACrC,aAAO,OAAO,OAAO,OAAO,MAAM;AAClC,aAAO;AACP,YAAM,MAAM;AAEZ,gBAAU,OAAO,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,IAChD;AAAA,EACJ,CAAC;AAED,QAAM,iBAAiB,QAAQ,MAAM;AAErC,gBAAc;AACd,MAAI,YAAY,YAAY,OAAQ,UAAS,SAAS,IAAI;AAE1D,SAAO;AAAA,IACH;AAAA,IACA;AAAA,IACA,IAAI,QAAQ;AAAE,aAAO;AAAA,IAAS;AAAA,IAC9B,IAAI,MAAM,MAAM;AACZ,gBAAU,UAAU,OAAO,QAAQ,EAAE,CAAC;AACtC,YAAM,QAAQ;AACd,oBAAc;AAAA,IAClB;AAAA;AAAA,IAEA,IAAI,QAAQ;AAAE,aAAO,MAAM,SAAS,OAAO,MAAM;AAAA,IAAa;AAAA,IAC9D,IAAI,SAAS;AAAE,aAAO,KAAK;AAAA,IAAQ;AAAA,IACnC,YAAY,KAAK;AAAA;AAAA,IAEjB,MAAM,KAAK;AAAA,IACX,OAAO,MAAM,KAAK,MAAM;AAAA,IACxB,QAAQ;AAAE,YAAM,MAAM;AAAA,IAAG;AAAA,IACzB,UAAU;AACN,WAAK,QAAQ;AACb,SAAG,OAAO;AAAA,IACd;AAAA,EACJ;AACJ;;;AC1SA,IAAI,YAAY;AAsCT,SAAS,SAAS,EAAE,OAAO,SAAS,CAAC,GAAG,WAAW,CAAC,GAAG,cAAc,MAAM,gBAAgB,KAAK,IAAI,CAAC,GAAG;AAC3G,SAAO,IAAI,QAAQ,CAAC,YAAY;AAI5B,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AACjB,SAAK,YAAY;AAAA;AAAA;AAAA,sBAGH,OAAO,IAAI,CAAC,MAAM,aAAa,GAAG,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,6EAKE,WAAW;AAAA;AAAA;AAAA;AAKhF,UAAM,MAAM,IAAI,cAAc;AAAA,MAC1B,WAAW,UAAU;AAAA,MACrB,IAAI,aAAa,WAAW;AAAA,MAC5B,OAAO,SAAS;AAAA,MAChB,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,cAAc,eAAe,MAAM;AAAA,MACnC,eAAe,gBAAgB,MAAM;AAAA,MACrC,SAAS,MAAM;AACX,wBAAgB;AAChB,YAAI,CAAC,WAAW;AAAE,sBAAY;AAAM,kBAAQ,IAAI;AAAA,QAAG;AAAA,MACvD;AAAA,IACJ,CAAC;AAED,QAAI,YAAY;AAChB,UAAM,QAAQ,CAAC,WAAW;AACtB,UAAI,UAAW;AACf,kBAAY;AACZ,cAAQ,MAAM;AACd,UAAI;AAAE,YAAI,MAAM,EAAE,OAAO,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAC;AAC3C,sBAAgB;AAAA,IACpB;AAEA,UAAM,QAAQ,KAAK,cAAc,0BAA0B;AAC3D,UAAM,YAAY,CAAC,QAAQ;AACvB,UAAI,CAAC,MAAO;AACZ,YAAM,cAAc;AACpB,YAAM,SAAS,CAAC;AAAA,IACpB;AACA,SAAK,cAAc,wBAAwB,GAAG,iBAAiB,SAAS,MAAM,MAAM,IAAI,CAAC;AAEzF,UAAM,aAAa,YAAY,MAAM;AAGrC,UAAM,YAAY,IAAI,IAAI,WAAW,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AACpE,eAAW,KAAK,YAAY;AACxB,UAAI,EAAE,SAAS,SAAU,aAAY,MAAM,CAAC;AAAA,IAChD;AACA,UAAM,YAAY,CAAC,SAAS,CAAC,CAAC,KAAK,cAAc,oBAAoB,IAAI,IAAI,GAAG;AAEhF,UAAM,kBAAkB,CAAC,SAAS;AAC9B,YAAM,MAAM,KAAK,cAAc,oBAAoB,IAAI,IAAI;AAC3D,YAAMC,SAAQ,KAAK,cAAc,sBAAsB,IAAI,IAAI;AAC/D,UAAI,IAAK,KAAI,UAAU,OAAO,gBAAgB;AAC9C,UAAIA,QAAO;AAAE,QAAAA,OAAM,cAAc;AAAI,QAAAA,OAAM,SAAS;AAAA,MAAM;AAAA,IAC9D;AACA,UAAM,gBAAgB,CAAC,MAAM,QAAQ;AACjC,YAAM,MAAM,KAAK,cAAc,oBAAoB,IAAI,IAAI;AAC3D,YAAMA,SAAQ,KAAK,cAAc,sBAAsB,IAAI,IAAI;AAC/D,UAAI,IAAK,KAAI,UAAU,IAAI,gBAAgB;AAC3C,UAAIA,QAAO;AAAE,QAAAA,OAAM,cAAc;AAAK,QAAAA,OAAM,SAAS;AAAA,MAAO;AAAA,IAChE;AAOA,QAAI,WAAW,CAAC,SAAS,gBAAgB,IAAI;AAC7C,UAAM,WAAW,oBAAI,IAAI;AACzB,eAAW,KAAK,YAAY;AACxB,YAAM,IAAI,cAAc,MAAM,GAAG,SAAS,EAAE,IAAI,KAAK,EAAE,SAAS,CAAC,SAAS,SAAS,IAAI,CAAC;AACxF,UAAI,EAAG,UAAS,IAAI,EAAE,MAAM,CAAC;AAAA,IACjC;AACA,aAAS,kBAAkB;AACvB,iBAAW,KAAK,SAAS,OAAO,EAAG,GAAE,UAAU;AAC/C,eAAS,MAAM;AAAA,IACnB;AACA,QAAI,KAAK;AAIT,UAAM,cAAc,CAAC,GAAG,SAAS,WAAW,YAAY,UAAU,IAAI,EAAE,IAAI,CAAC,GAAG,MAAM,IAAI;AAE1F,UAAM,cAAc,CAAC,MAAM,SAAS,IAAI,EAAE,IAAI,GAAG,YAAY,KAAK;AAGlE,eAAW,KAAK,YAAY;AACxB,YAAM,KAAK,KAAK,cAAc,UAAU,EAAE,IAAI,IAAI;AAClD,UAAI,iBAAiB,SAAS,MAAM,gBAAgB,EAAE,IAAI,CAAC;AAC3D,UAAI,iBAAiB,UAAU,MAAM,gBAAgB,EAAE,IAAI,CAAC;AAI5D,UAAI,EAAE,SAAS,YAAY,SAAS,CAAC,GAAG;AACpC,YAAI,iBAAiB,WAAW,CAAC,MAAM;AACnC,cAAI,CAAC,GAAG,SAAS,kBAAkB,CAAC,GAAG,SAAS,cAAe;AAC/D,YAAE,eAAe;AACjB,wBAAc,EAAE,MAAM,cAAc,CAAC,CAAC;AAAA,QAC1C,CAAC;AAAA,MACL;AAAA,IACJ;AAGA,QAAI,OAAO,kBAAkB,YAAY;AACrC,YAAM,UAAU,CAAC,SAAS,WAAW,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK;AACrE,YAAM,MAAM;AAAA,QACR,WAAW,MAAM,IAAI;AACjB,gBAAM,MAAM,KAAK,cAAc,oBAAoB,IAAI,IAAI;AAC3D,cAAI,CAAC,IAAK;AAIV,cAAI,SAAS,CAAC;AACd,cAAI,MAAM,UAAU,KAAK,KAAK;AAC9B,0BAAgB,IAAI;AAKpB,qBAAW,MAAM,IAAI,iBAAiB,yBAAyB,GAAG;AAC9D,gBAAI,CAAC,MAAM,GAAG,UAAU;AAAE,iBAAG,WAAW;AAAO,iBAAG,QAAQ,cAAc;AAAA,YAAK,WACpE,MAAM,GAAG,QAAQ,aAAa;AAAE,iBAAG,WAAW;AAAM,qBAAO,GAAG,QAAQ;AAAA,YAAa;AAC5F,uBAAW,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,OAAO,QAAQ,GAAG,CAAC,OAAO,QAAQ,CAAC,GAAG;AAC9D,kBAAI,CAAC,MAAM,GAAG,aAAa,IAAI,GAAG;AAAE,mBAAG,QAAQ,GAAG,IAAI,GAAG,aAAa,IAAI;AAAG,mBAAG,gBAAgB,IAAI;AAAA,cAAG,WAC9F,MAAM,GAAG,QAAQ,GAAG,KAAK,MAAM;AAAE,mBAAG,aAAa,MAAM,GAAG,QAAQ,GAAG,CAAC;AAAG,uBAAO,GAAG,QAAQ,GAAG;AAAA,cAAG;AAAA,YAC9G;AAAA,UACJ;AAAA,QACJ;AAAA,QACA,IAAI,MAAM;AACN,cAAI,SAAS,IAAI,IAAI,EAAG,QAAO,SAAS,IAAI,IAAI,EAAE,KAAK;AACvD,gBAAM,KAAK,KAAK,cAAc,UAAU,IAAI,IAAI;AAChD,cAAI,CAAC,GAAI,QAAO;AAChB,cAAI,GAAG,SAAS,WAAY,QAAO,CAAC,CAAC,GAAG;AACxC,iBAAO,GAAG;AAAA,QACd;AAAA,QACA,IAAI,MAAM,OAAO;AACb,cAAI,SAAS,IAAI,IAAI,GAAG;AAAE,qBAAS,IAAI,IAAI,EAAE,MAAM,KAAK;AAAG;AAAA,UAAQ;AACnE,gBAAM,KAAK,KAAK,cAAc,UAAU,IAAI,IAAI;AAChD,cAAI,CAAC,GAAI;AACT,cAAI,GAAG,SAAS,YAAY;AAAE,eAAG,UAAU,CAAC,CAAC;AAAO;AAAA,UAAQ;AAC5D,gBAAM,IAAI,QAAQ,IAAI;AACtB,aAAG,QAAQ,SAAS,OAAO,KAAK,OAAO,KAAK;AAC5C,cAAI,GAAG,SAAS,UAAU;AACtB,kBAAM,UAAU,KAAK,cAAc,yBAAyB,IAAI,IAAI;AACpE,gBAAI,QAAS,SAAQ,QAAQ,aAAa,GAAG,GAAG,KAAK;AAAA,UACzD;AAAA,QACJ;AAAA,QACA,WAAW,MAAM,SAAS;AACtB,gBAAM,IAAI,SAAS,IAAI,IAAI;AAC3B,cAAI,CAAC,GAAG,WAAY;AACpB,oBAAU,IAAI,MAAM,OAAO;AAC3B,YAAE,WAAW,OAAO;AAAA,QACxB;AAAA,MACJ;AACA,YAAM,OAAO,CAAC,SAAS;AACnB,YAAI;AAAE,wBAAc,MAAM,QAAQ,OAAO,SAAY,IAAI,IAAI,IAAI,GAAG,GAAG;AAAA,QAAG,SACnE,KAAK;AAAE,kBAAQ,MAAM,+BAA+B,GAAG;AAAA,QAAG;AAAA,MACrE;AACA,iBAAW,KAAK,YAAY;AACxB,cAAM,KAAK,KAAK,cAAc,UAAU,EAAE,IAAI,IAAI;AAClD,YAAI,iBAAiB,UAAU,MAAM,KAAK,EAAE,IAAI,CAAC;AAAA,MACrD;AACA,iBAAW,CAAC,SAAS;AAAE,wBAAgB,IAAI;AAAG,aAAK,IAAI;AAAA,MAAG;AAG1D,WAAK,IAAI;AAAA,IACb;AAEA,SAAK,cAAc,MAAM,EAAE,iBAAiB,UAAU,OAAO,MAAM;AAC/D,QAAE,eAAe;AACjB,YAAM,YAAY,KAAK,cAAc,uBAAuB;AAC5D,gBAAU,EAAE;AACZ,YAAM,OAAO,CAAC;AACd,iBAAW,KAAK,YAAY;AACxB,cAAM,UAAU,SAAS,IAAI,EAAE,IAAI;AACnC,cAAM,KAAK,UAAU,OAAO,KAAK,cAAc,UAAU,EAAE,IAAI,IAAI;AACnE,YAAI,CAAC,WAAW,CAAC,GAAI;AACrB,YAAI;AACJ,YAAI,SAAS;AAET,cAAI,QAAQ,SAAS,QAAQ,OAAO,IAAI,QAAQ,KAAK;AAErD,cAAI,MAAM,OAAW,KAAI,EAAE,SAAS,WAAW,KAAK;AAAA,QACxD,WAAW,EAAE,SAAS,YAAY;AAC9B,cAAI,CAAC,CAAC,GAAG;AAAA,QACb,WAAW,EAAE,SAAS,UAAU;AAC5B,cAAK,GAAG,UAAU,KAAK,OAAO,OAAO,GAAG,KAAK;AAAA,QACjD,OAAO;AACH,cAAI,GAAG;AAAA,QACX;AACA,YAAI,EAAE,SAAS,YAAY,EAAE,QAAQ;AACjC,gBAAM,OAAO,YAAY,CAAC;AAG1B,gBAAM,QAAQ,YAAY,GAAG,CAAC;AAC9B,cAAI,MAAO,KAAI,MAAM;AAAA,mBACZ,GAAG;AACR,gBAAI,UAAW,WAAU,WAAW;AACpC,gBAAI;AACJ,gBAAI,UAAU;AACd,gBAAI;AAAE,wBAAU,MAAM,KAAK,SAAS,CAAC;AAAA,YAAG,SACjC,KAAK;AAAE,wBAAU;AAAM,wBAAU,KAAK,WAAW,OAAO,GAAG;AAAA,YAAG;AACrE,gBAAI,UAAW,WAAU,WAAW;AACpC,gBAAI,WAAW,MAAM;AACjB,oBAAM,OAAO,KAAK,QAAQ,EAAE,MAAM,YAAY;AAC9C,wBAAU,UACJ,mBAAmB,IAAI,KAAK,CAAC,MAAM,OAAO,KAC1C,mBAAmB,IAAI,KAAK,CAAC,+BAA+B;AAClE;AAAA,YACJ;AACA,gBAAI;AAAA,UACR;AAAA,QACJ;AACA,aAAK,EAAE,IAAI,IAAI;AAAA,MACnB;AAGA,UAAI,eAAe;AACnB,iBAAW,KAAK,YAAY;AACxB,wBAAgB,EAAE,IAAI;AACtB,YAAI,UAAU,EAAE,IAAI,GAAG;AAGnB,cAAI,YAAY,CAAC,KAAK,KAAM,MAAK,EAAE,IAAI,IAAI,EAAE,SAAS,UAAU,OAAO;AACvE;AAAA,QACJ;AACA,cAAM,IAAI,KAAK,EAAE,IAAI;AAIrB,YAAI,MAAM,EAAE,YAAY,SAAS,GAAG,CAAC,IAAI,cAAc;AACvD,YAAI,CAAC,OAAO,YAAY,GAAG,CAAC,EAAG,OAAM,cAAc,CAAC;AACpD,YAAI,CAAC,KAAK;AACN,gBAAM,SAAS,YAAY,CAAC;AAC5B,cAAI,UAAU,KAAM,OAAM,SAAS,kBAAkB,MAAM,KAAK;AAAA,QACpE;AACA,YAAI,CAAC,IAAK,OAAM,SAAS,IAAI,EAAE,IAAI,GAAG,QAAQ,KAAK;AACnD,YAAI,CAAC,OAAO,OAAO,EAAE,cAAc,YAAY;AAC3C,cAAI;AAAE,kBAAM,EAAE,UAAU,GAAG,IAAI;AAAA,UAAG,SAAS,KAAK;AAAE,kBAAM,KAAK,WAAW,OAAO,GAAG;AAAA,UAAG;AAAA,QACzF;AACA,YAAI,KAAK;AACL,wBAAc,EAAE,MAAM,GAAG;AACzB,cAAI,CAAC,aAAc,gBAAe,EAAE;AAAA,QACxC;AAAA,MACJ;AACA,UAAI,cAAc;AACd,iBAAS,IAAI,YAAY,GAAG,MAAM;AAClC,aAAK,cAAc,iBAAiB,YAAY,IAAI,GAAG,MAAM;AAC7D,aAAK,cAAc,UAAU,YAAY,yBAAyB,GAAG,MAAM;AAC3E;AAAA,MACJ;AACA,YAAM,IAAI;AAAA,IACd,CAAC;AAMD,0BAAsB,MAAM;AACxB,YAAM,QAAQ,CAAC,GAAG,KAAK,iBAAiB,8CAA8C,CAAC,EAClF,KAAK,CAAC,OAAO,CAAC,GAAG,QAAQ,kBAAkB,GAAG,MAAM;AACzD,aAAO,MAAM;AAAA,IACjB,CAAC;AAAA,EACL,CAAC;AACL;AAYO,SAAS,YAAY;AAAA,EACxB;AAAA,EAAO;AAAA,EAAS,eAAe;AAAA,EAC/B,cAAc;AAAA,EACd,SAAS;AAAA,EAAO,OAAO;AAC3B,IAAI,CAAC,GAAG;AACJ,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC5B,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AAEjB,UAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,cAAU,YAAY;AACtB,cAAU,cAAc,WAAW,OAAO,KAAK,OAAO,OAAO;AAE7D,UAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,cAAU,YAAY;AACtB,UAAM,SAAS,CAAC,QAAQ,WAAW,UAAU;AACzC,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,OAAO;AACX,UAAI,YAAY;AAChB,UAAI,QAAQ,SAAS;AACrB,UAAI,cAAc,SAAS,OAAO,KAAK,OAAO,KAAK;AACnD,gBAAU,YAAY,GAAG;AAAA,IAC7B;AACA,WAAO,UAAU,WAAW,WAAW;AACvC,WAAO,WAAW,SAAS,4BAA4B,4BAA4B,YAAY;AAE/F,SAAK,OAAO,WAAW,SAAS;AAEhC,QAAI,YAAY;AAChB,UAAM,MAAM,IAAI,cAAc;AAAA,MAC1B,WAAW,UAAU;AAAA,MACrB,IAAI,eAAe,WAAW;AAAA,MAC9B,OAAO,SAAS;AAAA,MAChB,MAAM,SAAS,SAAS,YAAY;AAAA,MACpC,SAAS;AAAA,MACT,OAAO;AAAA,MACP,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,MACX,SAAS;AAAA,MACT,cAAc;AAAA,MACd,eAAe;AAAA,MACf,SAAS,MAAM;AAAE,YAAI,CAAC,WAAW;AAAE,sBAAY;AAAM,kBAAQ,KAAK;AAAA,QAAG;AAAA,MAAE;AAAA,IAC3E,CAAC;AACD,QAAI,KAAK;AACT,UAAM,QAAQ,CAAC,MAAM;AACjB,UAAI,UAAW;AACf,kBAAY;AACZ,cAAQ,CAAC;AACT,UAAI;AAAE,YAAI,MAAM,EAAE,OAAO,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAC/C;AACA,SAAK,cAAc,wBAAwB,EAAE,iBAAiB,SAAS,MAAM,MAAM,KAAK,CAAC;AACzF,SAAK,cAAc,yBAAyB,EAAE,iBAAiB,SAAS,MAAM,MAAM,IAAI,CAAC;AACzF,0BAAsB,MAAM;AACxB,WAAK,cAAc,iBAAiB,SAAS,WAAW,SAAS,IAAI,GAAG,MAAM;AAAA,IAClF,CAAC;AAAA,EACL,CAAC;AACL;AA+EO,SAAS,UAAU;AAAA,EACtB,QAAW;AAAA,EACX,OAAW;AAAA,EACX,UAAW;AAAA,EACX,UAAW;AAAA,EACX,QAAW;AAAA,EACX,SAAW;AAAA,EACX,UAAW;AAAA,EACX,eAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,cAAmB;AAAA,EACnB,mBAAmB;AAAA,EACnB,cAAmB;AACvB,IAAI,CAAC,GAAG;AACJ,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC5B,UAAM,OAAO,SAAS,cAAc,KAAK;AACzC,SAAK,YAAY;AAEjB,UAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,cAAU,YAAY;AACtB,QAAI,mBAAmB,YAAa,WAAU,YAAY,OAAO;AACjE,SAAK,YAAY,SAAS;AAI1B,UAAM,OAAO,MAAM,QAAQ,OAAO,KAAK,QAAQ,SAAS,IAClD,UACA,CAAC,EAAE,OAAO,SAAS,OAAO,KAAK,CAAC;AACtC,UAAM,YAAY,SAAS,cAAc,KAAK;AAC9C,cAAU,YAAY;AACtB,SAAK,QAAQ,CAAC,GAAG,MAAM;AACnB,YAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,UAAI,OAAO;AACX,UAAI,MAAM;AACV,UAAI,EAAE,QAAS,QAAO;AACtB,UAAI,EAAE,OAAS,QAAO;AACtB,UAAI,YAAY;AAahB,UAAI,EAAE,MAAM;AACR,cAAM,QAAQ,SAAS,cAAc,MAAM;AAC3C,cAAM,YAAY;AAClB,cAAM,cAAc,OAAO,EAAE,IAAI;AACjC,cAAM,aAAa,eAAe,MAAM;AACxC,cAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,aAAK,YAAY;AACjB,aAAK,cAAc,OAAO,EAAE,SAAS,EAAE;AACvC,YAAI,OAAO,OAAO,IAAI;AAAA,MAC1B,OAAO;AACH,YAAI,cAAc,OAAO,EAAE,SAAS,EAAE;AAAA,MAC1C;AACA,UAAI,QAAQ,YAAY,OAAO,CAAC;AAchC,UAAI,EAAE,SAAU,KAAI,WAAW;AAC/B,UAAI,EAAE,UAAU,UAAa,EAAE,UAAU,MAAM;AAC3C,YAAI,QAAQ,cAAc,OAAO,EAAE,KAAK;AAAA,MAC5C;AACA,gBAAU,YAAY,GAAG;AAAA,IAC7B,CAAC;AACD,SAAK,YAAY,SAAS;AAE1B,QAAI,YAAY;AAOhB,QAAI,SAAS;AACb,UAAM,mBAAmB,MAAM;AAC3B,UAAI,CAAC,OAAQ;AACb,aAAO,oBAAoB,4BAA4B,MAAM;AAC7D,eAAS;AAAA,IACb;AACA,UAAM,MAAM,IAAI,cAAc;AAAA,MAC1B,WAAW,UAAU;AAAA,MACrB,IAAI,aAAa,WAAW;AAAA,MAC5B;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAQb,aAAa,CAAC,CAAC;AAAA,MACf,WAAW;AAAA,MACX,SAAS;AAAA,MACT,cAAe;AAAA,MACf,eAAe;AAAA,MACf;AAAA;AAAA;AAAA;AAAA;AAAA,MAKA,SAAS,MAAM;AACX,yBAAiB;AACjB,YAAI,CAAC,WAAW;AAAE,sBAAY;AAAM,kBAAQ,IAAI;AAAA,QAAG;AAAA,MACvD;AAAA,IACJ,CAAC;AACD,QAAI,KAAK;AAiBT,QAAI,eAAe,OAAO,qBAAqB,YAAY;AACvD,eAAS,CAAC,MAAM;AACZ,YAAI,EAAE,QAAQ,OAAO,IAAI,GAAI;AAC7B,YAAI;AAAE,2BAAiB,CAAC,CAAC,EAAE,OAAO,WAAW,SAAS;AAAA,QAAG,SAClD,KAAK;AAAE,kBAAQ,KAAK,kCAAkC,GAAG;AAAA,QAAG;AAAA,MACvE;AACA,aAAO,iBAAiB,4BAA4B,MAAM;AAAA,IAC9D;AAEA,UAAM,QAAQ,CAAC,UAAU;AACrB,UAAI,UAAW;AACf,kBAAY;AACZ,uBAAiB;AACjB,cAAQ,KAAK;AACb,UAAI;AAAE,YAAI,MAAM,EAAE,OAAO,KAAK,CAAC;AAAA,MAAG,QAAQ;AAAA,MAAC;AAAA,IAC/C;AACA,cAAU,iBAAiB,SAAS,CAAC,MAAM;AACvC,YAAM,MAAM,EAAE,OAAO,QAAQ,mBAAmB;AAChD,UAAI,CAAC,IAAK;AACV,YAAM,MAAM,OAAO,IAAI,QAAQ,SAAS;AACxC,YAAM,IAAI,KAAK,GAAG;AAClB,UAAI,CAAC,EAAG;AAKR,UAAI,EAAE,UAAU;AAMZ,YAAI;AAAE,YAAE,UAAU,KAAK;AAAA,QAAG,SAAS,KAAK;AAAE,kBAAQ,KAAK,GAAG;AAAA,QAAG;AAC7D;AAAA,MACJ;AACA,YAAM,EAAE,KAAK;AAAA,IACjB,CAAC;AAWD,UAAM,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOb,cAAc,CAAC,UAAU,UAAU;AAAA,QAC/B,uBAAuB,OAAO,KAAK,EAAE,QAAQ,UAAU,MAAM,CAAC;AAAA,MAAI;AAAA,MACtE,iBAAiB,OAAO,SAAS;AAC7B,cAAM,MAAM,SAAS,aAAa,KAAK;AACvC,YAAI,IAAK,KAAI,WAAW,CAAC;AACzB,eAAO,CAAC,CAAC;AAAA,MACb;AAAA,IACJ;AAIA,QAAI,OAAO,YAAY,YAAY;AAC/B,4BAAsB,MAAM;AACxB,YAAI;AAAE,kBAAQ,WAAW,QAAQ;AAAA,QAAG,SAAS,KAAK;AAAE,kBAAQ,KAAK,GAAG;AAAA,QAAG;AAAA,MAC3E,CAAC;AAAA,IACL;AAiBA,0BAAsB,MAAM;AACxB,YAAM,QAAQ,UAAU;AAAA,QACpB;AAAA,MAEyB;AAC7B,UAAI,OAAO;AACP,cAAM,MAAM;AAIZ,YAAI;AAAE,gBAAM,oBAAoB,MAAM,MAAM,QAAQ,MAAM,MAAM,MAAM;AAAA,QAAG,QACnE;AAAA,QAAuD;AAC7D;AAAA,MACJ;AACA,YAAM,MAAM,KAAK,UAAU,CAAC,MAAM,EAAE,OAAO;AAC3C,YAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,SAAS;AAC7C,gBAAU,cAAc,qBAAqB,KAAK,IAAI,GAAG,MAAM;AAAA,IACnE,CAAC;AAAA,EACL,CAAC;AACL;AAKA,SAAS,gBAAgB,QAAQ;AAK7B,QAAM,SAAS,CAAC,MAAM;AAClB,QAAI,EAAE,QAAS,QAAO;AACtB,UAAM,OAAO,EAAE,OAAO,KAAK;AAC3B,QAAI,EAAE,SAAS,WAAY,QAAO,MAAM,OAAO,EAAE,IAAI,KAAK,KAAK,KAAK;AACpE,QAAI,EAAE,SAAS,cAAc,EAAE,SAAS,SAAU,QAAO,KAAK;AAC9D,QAAI,EAAE,SAAS,aAAa;AACxB,YAAM,IAAI,MAAM,QAAQ,EAAE,OAAO,IAAI,EAAE,QAAQ,SAAS;AACxD,aAAO,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,KAAK;AAAA,IAC3C;AACA,QAAI,EAAE,SAAS,QAAS,QAAO,MAAM,MAAM,QAAQ,EAAE,OAAO,KAAK,EAAE,QAAQ,SAAS,KAAK,KAAK;AAC9F,QAAI,EAAE,SAAS,SAAS;AACpB,YAAM,OAAO,YAAY,EAAE,OAAO;AAClC,aAAO,KAAK,KAAK,OAAO,CAAC,GAAG,MAAM,IAAI,MAAM,EAAE,eAAe,EAAE,SAAS,KAAK,IAAI,CAAC,IAAI;AAAA,IAC1F;AACA,WAAO,KAAK;AAAA,EAChB;AACA,MAAI,OAAO;AACX,aAAW,KAAK,QAAQ;AACpB,YAAQ,MAAM,QAAQ,GAAG,GAAG,IAAI,KAAK,IAAI,GAAG,GAAG,YAAY,EAAE,GAAG,EAAE,IAAI,MAAM,CAAC,IAAI,OAAO,CAAC;AAAA,EAC7F;AACA,QAAM,OAAO,KAAK,KAAK,KAAK;AAC5B,QAAM,MAAM,KAAK,MAAM,OAAO,cAAc,GAAG;AAC/C,SAAO,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,CAAC;AAC5C;AAEA,SAAS,eAAe,QAAQ;AAO5B,QAAM,SAAS,KAAK,IAAI,GAAG,GAAG,OAAO,OAAO,CAAC,MAAM,MAAM,QAAQ,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,YAAY,EAAE,GAAG,EAAE,MAAM,CAAC;AAC/G,MAAI,UAAU,EAAG,QAAO,KAAK,IAAI,KAAK,KAAK,IAAI,MAAM,SAAS,KAAK,KAAK,MAAM,OAAO,aAAa,GAAG,CAAC,CAAC;AACvG,QAAM,OAAO,OAAO,KAAK,CAAC,MAAM,MAAM,EAAE,SAAS,cAAc,EAAE,SAAS,eAAe,EAAE,WAAW,MAAM,QAAQ,EAAE,GAAG,EAAE;AAC3H,SAAO,OAAO,MAAM;AACxB;AAGA,SAAS,YAAY,SAAS;AAC1B,SAAO,QAAQ,QAAQ,CAAC,MAAO,MAAM,QAAQ,GAAG,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAE,EAAE,OAAO,CAAC,MAAM,KAAK,EAAE,WAAW,IAAI;AAC7G;AAGA,SAAS,SAAS,GAAG;AACjB,SAAO,EAAE,OAAO,QAAQ,EAAE,OAAO;AACrC;AAGA,SAAS,YAAY,GAAG,GAAG;AACvB,MAAI,EAAE,SAAS,YAAY,CAAC,SAAS,CAAC,KAAK,KAAK,QAAQ,OAAO,MAAM,CAAC,EAAG,QAAO;AAChF,SAAQ,EAAE,OAAO,QAAQ,IAAI,OAAO,EAAE,GAAG,KAAO,EAAE,OAAO,QAAQ,IAAI,OAAO,EAAE,GAAG;AACrF;AAGA,SAAS,cAAc,GAAG;AACtB,MAAI,EAAE,OAAO,QAAQ,EAAE,OAAO,KAAM,QAAO,mBAAmB,EAAE,GAAG,QAAQ,EAAE,GAAG;AAChF,SAAO,EAAE,OAAO,OAAO,oBAAoB,EAAE,GAAG,MAAM,mBAAmB,EAAE,GAAG;AAClF;AAGA,SAAS,SAAS,SAAS;AACvB,SAAO,YAAY,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,QAAQ;AACzD;AAQA,SAAS,eAAe,MAAM,GAAG,OAAO;AACpC,MAAI,UAAU,EAAE;AAChB,QAAM,QAAQ,CAAC,SAAS,WAAW,YAAY,OAAO,GAAG,MAAM,IAAI;AACnE,QAAM,QAAQ,CAAC,MAAO,KAAK,QAAQ,MAAM,CAAC,GAAG,WAAW,KAAK,OAAO,CAAC;AAErE,QAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,OAAK,YAAY;AACjB,OAAK,SAAS;AAId,QAAM,OAAO,EAAE,WAAW,OAAO,OAAO,YAAY,CAAC,EAAE,QAAQ;AAC/D,QAAM,aAAa,MAAM;AACrB,UAAM,IAAI,EAAE,MAAM,KAAK;AACvB,UAAM,QAAQ,QAAQ,KAAK,CAAC,YAAY,OAAO,EAAE,KAAK,CAAC,MAAM,OAAO,EAAE,KAAK,MAAM,CAAC;AAClF,QAAI,MAAO,MAAK,cAAc,sBAAiB,IAAI,UAAK,CAAC;AACzD,SAAK,SAAS,CAAC;AAAA,EACnB;AAEA,QAAM,IAAI,eAAe;AAAA,IACrB,SAAS,SAAS,OAAO;AAAA,IACzB,OAAO,MAAM,KAAK;AAAA,IAClB,MAAM,EAAE;AAAA,IACR,aAAa,EAAE,eAAe;AAAA;AAAA,IAE9B,eAAe;AAAA,IACf,UAAU,MAAM,WAAW;AAAA,EAC/B,CAAC;AACD,MAAI,EAAE,SAAU,GAAE,MAAM,WAAW;AACnC,IAAE,GAAG,YAAY,IAAI;AACrB,OAAK,YAAY,EAAE,EAAE;AACrB,aAAW;AACX,SAAO;AAAA,IACH,OAAO;AACH,YAAM,IAAI,MAAM,EAAE,KAAK;AACvB,aAAO,IAAI,EAAE,QAAQ,EAAE;AAAA,IAC3B;AAAA,IACA,MAAM,GAAG;AAAE,QAAE,QAAQ,MAAM,CAAC;AAAG,iBAAW;AAAA,IAAG;AAAA,IAC7C,OAAO,EAAE;AAAA,IACT,cAAc;AACV,YAAM,IAAI,EAAE,UAAU,KAAK,SAAY,MAAM,EAAE,KAAK;AACpD,aAAO,GAAG,WAAY,EAAE,UAAU,KAAM;AAAA,IAC5C;AAAA,IACA,WAAW,MAAM;AACb,gBAAU;AACV,QAAE,WAAW,SAAS,IAAI,CAAC;AAC3B,iBAAW;AAAA,IACf;AAAA,IACA,SAAS,EAAE;AAAA,EACf;AACJ;AAgBA,SAAS,cAAc,MAAM,GAAG,OAAO,UAAU;AAC7C,QAAM,OAAO,KAAK,cAAc,uBAAuB,EAAE,IAAI,IAAI;AACjE,MAAI,CAAC,KAAM,QAAO;AAClB,MAAI,EAAE,SAAS,UAAU;AAGrB,UAAM,SAAS,IAAI,YAAY;AAAA,MAC3B,MAAM,EAAE;AAAA,MACR,SAAS,UAAU,QAAQ,UAAU;AAAA,MACrC,WAAW,EAAE,SAAS,EAAE;AAAA,MACxB,QAAQ,EAAE,UAAU;AAAA,MACpB,SAAS,EAAE,WAAW;AAAA,MACtB,UAAU,CAAC,CAAC,EAAE;AAAA,MACd,SAAS,CAAC,CAAC,EAAE;AAAA,IACjB,CAAC;AACD,SAAK,YAAY,OAAO,OAAO,CAAC;AAChC,WAAO;AAAA,MACH,MAAM,MAAM,OAAO,IAAI;AAAA,MACvB,OAAO,CAAC,MAAM,OAAO,IAAI,CAAC;AAAA,MAC1B,OAAO,MAAM,OAAO,OAAO,MAAM;AAAA,MACjC,aAAa,MAAM;AAAA,MACnB,SAAS,MAAM,OAAO,QAAQ;AAAA,IAClC;AAAA,EACJ;AACA,MAAI,EAAE,SAAS,WAAW,EAAE,SAAS,aAAa;AAG9C,UAAMC,KAAI,EAAE,SAAS,UACf,IAAI,WAAW,EAAE,MAAM,EAAE,MAAM,OAAO,SAAS,IAAI,SAAS,EAAE,SAAS,OAAO,EAAE,MAAM,CAAC,IACvF,IAAI,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,SAAS,CAAC,GAAG,SAAS,EAAE,QAAQ,CAAC;AACjF,SAAK,YAAYA,GAAE,OAAO,CAAC;AAC3B,UAAMC,QAAO,EAAE,SAAS;AACxB,WAAO;AAAA,MACH,MAAM,MAAOA,QAAOD,GAAE,SAAS,IAAIA,GAAE,QAAQ;AAAA,MAC7C,QAAQ,MAAMA,GAAE,SAAS;AAAA,MACzB,OAAO,CAAC,MAAMA,GAAE,SAAS,CAAC;AAAA,MAC1B,OAAO,MAAMA,GAAE,MAAM;AAAA,MACrB,aAAa,MAAM;AAAA,MACnB,OAAO,MAAM;AACT,YAAIA,GAAE,SAAS,MAAM,KAAM,QAAO;AAClC,YAAI,CAACC,MAAM,QAAO;AAClB,cAAM,MAAMD,GAAE,eAAe,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,KAAK,IAAI;AAC1D,eAAO,yBAAyB,GAAG;AAAA,MACvC;AAAA,MACA,SAAS,MAAMA,GAAE,QAAQ;AAAA,IAC7B;AAAA,EACJ;AACA,MAAI,EAAE,SAAS,YAAY,EAAE,OAAQ,QAAO,eAAe,MAAM,GAAG,KAAK;AACzE,QAAM,SAAS,EAAE,aAAa,OAAO,OAAO,KAAK;AACjD,QAAM,iBAAiB,CAAC,UAAW,OAAO,WAAY,MAAM,UAAU,KAAM;AAC5E,MAAI,EAAE,SAAS,UAAU;AACrB,UAAMA,KAAI,UAAU,EAAE,SAAS,OAAO,EAAE,GAAG,QAAQ,WAAW,SAAS,WAAW,GAAG,CAAC;AACtF,IAAAA,GAAE,IAAI,OAAO,EAAE;AACf,QAAI,EAAE,SAAU,CAAAA,GAAE,IAAI,WAAW;AACjC,SAAK,YAAYA,GAAE,GAAG;AACtB,WAAO;AAAA;AAAA;AAAA,MAGH,MAAM,MAAOA,GAAE,MAAM,IAAIA,GAAE,MAAM,EAAE,QAAQ;AAAA;AAAA;AAAA,MAG3C,OAAO,CAAC,MAAM;AAAE,YAAI,CAACA,GAAE,OAAO,CAAC,EAAG,CAAAA,GAAE,IAAI,gBAAgB;AAAA,MAAI;AAAA,MAC5D,OAAO,MAAMA,GAAE,IAAI,MAAM;AAAA,MACzB,aAAa,MAAM,eAAeA,GAAE,MAAM,CAAC;AAAA,MAC3C,YAAYA,GAAE;AAAA,IAClB;AAAA,EACJ;AACA,QAAM,OAAO,CAAC,MAAO,MAAM,QAAQ,CAAC,IAAI,IAAK,KAAK,QAAQ,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;AAC5E,MAAI,EAAE,SAAS,aAAa;AACxB,UAAMA,KAAI,YAAY;AAAA,MAAE,GAAG;AAAA,MAAQ,SAAS,EAAE;AAAA,MAAS,OAAO,KAAK,KAAK;AAAA,MAAG,OAAO,EAAE,SAAS,EAAE;AAAA,MACvE,UAAU,MAAM,SAAS,EAAE,IAAI;AAAA,IAAE,CAAC;AAC1D,SAAK,YAAYA,GAAE,EAAE;AACrB,WAAO;AAAA,MACH,MAAMA,GAAE;AAAA,MACR,OAAO,CAAC,MAAMA,GAAE,SAAS,KAAK,CAAC,CAAC;AAAA,MAChC,OAAO,MAAMA,GAAE,GAAG,cAAc,uBAAuB,GAAG,MAAM;AAAA,MAChE,aAAa,MAAM;AAAA;AAAA,MACnB,YAAYA,GAAE;AAAA,IAClB;AAAA,EACJ;AACA,QAAM,IAAI,WAAW;AAAA,IAAE,GAAG;AAAA,IAAQ,SAAS,EAAE;AAAA,IAAS;AAAA,IAAO,OAAO,EAAE,SAAS,EAAE;AAAA,IAC1D,MAAM,YAAY,SAAS,IAAI,EAAE,IAAI;AAAA,IAAI,UAAU,MAAM,SAAS,EAAE,IAAI;AAAA,EAAE,CAAC;AAClG,OAAK,YAAY,EAAE,EAAE;AACrB,SAAO;AAAA,IACH,MAAM,MAAM,EAAE,QAAQ,KAAK;AAAA,IAC3B,OAAO,CAAC,MAAM;AAAE,QAAE,OAAO,CAAC;AAAA,IAAG;AAAA,IAC7B,OAAO,EAAE;AAAA,IACT,aAAa,MAAM,eAAe,EAAE,MAAM,CAAC;AAAA,IAC3C,YAAY,EAAE;AAAA,EAClB;AACJ;AAGA,SAAS,SAAS,GAAG,GAAG;AACpB,MAAI,EAAE,SAAS,SAAU,QAAO,CAAC;AACjC,MAAI,EAAE,SAAS,YAAa,QAAO,CAAC,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW;AACrE,MAAI,EAAE,SAAS,QAAS,QAAO,KAAK;AAEpC,MAAI,EAAE,SAAS,QAAS,QAAO,MAAM;AACrC,MAAI,EAAE,SAAS,YAAa,QAAO,MAAM,QAAQ,CAAC,KAAK,EAAE,WAAW;AACpE,SAAO;AACX;AAGA,SAAS,YAAY,GAAG;AACpB,MAAI,CAAC,KAAK,CAAC,EAAE,OAAQ,QAAO;AAC5B,MAAI,EAAE,WAAW,KAAM,QAAO,EAAE,UAAU,OAAO,MAAM,GAAG,MAAM,KAAK;AACrE,SAAO;AAAA,IACH,UAAU,OAAO,EAAE,OAAO,aAAa,aAAa,EAAE,OAAO,WAAW,OAAO,MAAM;AAAA,IACrF,MAAM,EAAE,OAAO,QAAQ;AAAA,EAC3B;AACJ;AAGA,SAAS,aAAa,GAAG,OAAO;AAC5B,MAAI,OAAO,EAAE,eAAe,WAAY,QAAO,SAAS,OAAO,KAAK,OAAO,KAAK;AAChF,MAAI;AAAE,WAAO,OAAO,EAAE,WAAW,KAAK,KAAK,EAAE;AAAA,EAAG,SACzC,KAAK;AAAE,YAAQ,KAAK,4BAA4B,GAAG;AAAG,WAAO,OAAO,SAAS,EAAE;AAAA,EAAG;AAC7F;AAIA,SAAS,YAAY,MAAM,GAAG;AAC1B,QAAM,SAAS,KAAK,cAAc,8BAA8B,EAAE,IAAI,IAAI;AAC1E,QAAM,UAAU,KAAK,cAAc,yBAAyB,EAAE,IAAI,IAAI;AACtE,QAAM,MAAM,KAAK,cAAc,iBAAiB,EAAE,IAAI,IAAI;AAC1D,MAAI,CAAC,UAAU,CAAC,WAAW,CAAC,OAAO,OAAO,EAAE,SAAS,WAAY;AAEjE,MAAI,OAAO;AACX,QAAM,OAAO,YAAY;AACrB,QAAI,KAAM;AACV,WAAO;AACP,QAAI;AACJ,QAAI;AAAE,eAAS,MAAM,EAAE,KAAK,OAAO,KAAK;AAAA,IAAG,SACpC,KAAK;AAAE,cAAQ,KAAK,sBAAsB,GAAG;AAAG,eAAS;AAAA,IAAM,UACtE;AAAU,aAAO;AAAA,IAAO;AACxB,QAAI,UAAU,KAAM;AACpB,UAAM,SAAS,OAAO,WAAW;AACjC,WAAO,QAAQ,QAAQ,SAAS,OAAO,QAAQ,WAAW,EAAE;AAC5D,YAAQ,QAAQ,UAAU,OAAO,SAAS,OACpC,OAAO,OAAO,KAAK,IAAI,aAAa,GAAG,OAAO,KAAK;AAGzD,cAAU,QAAQ,UAAU,EAAE,SAAS,KAAK,CAAC;AAAA,EACjD;AACA,MAAI,iBAAiB,SAAS,IAAI;AAElC,UAAQ,iBAAiB,SAAS,IAAI;AAC1C;AAGA,SAAS,aAAa,GAAG,UAAU;AAC/B,MAAI,KAAK,EAAE,WAAW,MAAM;AAGxB,UAAM,OAAO,EAAE,OAAO,oBAAoB,EAAE,IAAI,MAAM;AACtD,WAAO,kCAAkC,IAAI,IAAI,KAAK,EAAE,OAAO,CAAC;AAAA,EACpE;AAGA,MAAI,MAAM,QAAQ,GAAG,GAAG,GAAG;AACvB,UAAM,QAAQ,YAAY,EAAE,GAAG,EAAE,IAAI,CAAC,MAAM,aAAa,GAAG,SAAS,EAAE,IAAI,KAAK,EAAE,OAAO,CAAC;AAC1F,WAAO,uCAAuC,MAAM,KAAK,EAAE,CAAC;AAAA,EAChE;AACA,SAAO,aAAa,GAAG,SAAS,EAAE,IAAI,KAAK,EAAE,OAAO;AACxD;AAEA,SAAS,aAAa,GAAG,OAAO;AAC5B,QAAM,WAAW,EAAE,WAAW,aAAa;AAC3C,QAAM,SAAU,EAAE,SAAS,cAAc,EAAE,SAAS,eAAe,EAAE,SAAS,UACxE,+BAA+B;AACrC,QAAM,WAAW,EAAE,OACb,uCAAuC,KAAK,EAAE,IAAI,CAAC,WAAW;AACpE,QAAM,UAAU,yDAAyD,EAAE,IAAI;AAC/E,QAAM,OAAO,CAAC,OAAO,MAAM,YAAY;AAAA,WAChC,GAAG,yBAAyB,MAAM,qBAAqB,EAAE,IAAI;AAAA,oBACpD,KAAK,EAAE,SAAS,EAAE,CAAC;AAAA,cACzB,KAAK;AAAA,cACL,QAAQ;AAAA,cACR,OAAO;AAAA,YACT,GAAG;AAAA;AAGX,QAAM,OAAO,4BAA4B,EAAE,IAAI;AAE/C,MAAI,EAAE,SAAS,YAAY;AACvB,UAAM,UAAW,UAAU,QAAQ,UAAU,SAAU,YAAY;AACnE,WAAO;AAAA,4DAC6C,EAAE,IAAI;AAAA;AAAA;AAAA,mCAG/B,EAAE,IAAI,qBAAqB,OAAO;AAAA,4BACzC,KAAK,EAAE,SAAS,EAAE,CAAC;AAAA;AAAA,kBAE7B,QAAQ;AAAA,kBACR,OAAO;AAAA;AAAA;AAAA,EAGrB;AAIA,MAAI,EAAE,SAAS,eAAe,EAAE,SAAS,QAAS,QAAO,KAAK,MAAM,KAAK;AAIzE,MAAI,EAAE,SAAS,UAAU;AACrB,WAAO,KAAK,sDAAsD,EAAE,IAAI,aAAa,KAAK;AAAA,EAC9F;AAEA,MAAI,EAAE,SAAS,YAAY;AACvB,UAAME,KAAI,SAAS,OAAO,KAAK,OAAO,KAAK;AAC3C,UAAM,OAAO,EAAE,QAAQ,OAAO,SAAS,OAAO,EAAE,IAAI,KAAK,CAAC,MAAM;AAChE,UAAMC,eAAc,EAAE,cAAc,gBAAgB,KAAK,EAAE,WAAW,CAAC,MAAM;AAC7E,WAAO,KAAK,mBAAmB,EAAE,IAAI,KAAK,IAAI,IAAIA,YAAW,IAAI,QAAQ,IAAI,KAAKD,EAAC,CAAC,aAAa;AAAA,EACrG;AAEA,MAAI,EAAE,SAAS,WAAW,EAAE,SAAS,aAAa;AAI9C,QAAI,EAAE,SAAS,QAAS,QAAO,KAAK,IAAI;AACxC,WAAO;AAAA,oFACqE,EAAE,IAAI,8BAA8B,KAAK,EAAE,SAAS,EAAE,CAAC;AAAA,wBACnH,KAAK,EAAE,SAAS,EAAE,CAAC;AAAA,kBACzB,IAAI;AAAA,kBACJ,QAAQ;AAAA,kBACR,OAAO;AAAA;AAAA;AAAA,EAGrB;AACA,QAAM,IAAI,SAAS,OAAO,KAAK,OAAO,KAAK;AAC3C,MAAI,EAAE,SAAS,UAAU;AAKrB,UAAMC,eAAc,EAAE,cAAc,gBAAgB,KAAK,EAAE,WAAW,CAAC,MAAM;AAC7E,WAAO,KAAK;AAAA;AAAA,6CAEyB,EAAE,IAAI,YAAY,KAAK,CAAC,CAAC;AAAA,0EACI,EAAE,IAAI;AAAA,gCAChD,KAAK,aAAa,GAAG,CAAC,CAAC,CAAC,KAAKA,YAAW;AAAA,qFACa,EAAE,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA,SAKlF;AAAA,EACL;AACA,MAAI,EAAE,SAAS,SAAU,QAAO,KAAK,IAAI;AACzC,QAAM,OAAO,EAAE,QAAQ,OAAO,SAAS,EAAE,IAAI,MAAM;AACnD,QAAM,cAAc,EAAE,cAAc,gBAAgB,KAAK,EAAE,WAAW,CAAC,MAAM;AAC7E,QAAM,OAAQ,EAAE,SAAS,YAAY,EAAE,SAAS,aAAc,EAAE,OAAO;AAEvE,MAAI,SAAS;AACb,MAAI,EAAE,SAAS,YAAY,EAAE,OAAO,KAAM,WAAU,SAAS,KAAK,EAAE,GAAG,CAAC;AACxE,MAAI,EAAE,SAAS,YAAY,EAAE,OAAO,KAAM,WAAU,SAAS,KAAK,EAAE,GAAG,CAAC;AACxE,SAAO,KAAK,gBAAgB,EAAE,IAAI,WAAW,IAAI,YAAY,KAAK,CAAC,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,WAAW,IAAI,QAAQ,GAAG;AACxH;AAEA,SAAS,KAAK,GAAG;AACb,SAAO,OAAO,KAAK,OAAO,KAAK,CAAC,EAC3B,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM,EACjE,QAAQ,MAAM,QAAQ;AAC/B;;;AC9rCA,IAAI,cAAc;AAClB,IAAI,iBAAiB;AAEd,SAAS,gBAAgB,GAAG,GAAG,OAAO,UAAU;AACnD,kBAAgB;AAKhB,mBAAiB,SAAS;AAE1B,QAAM,OAAO,SAAS,cAAc,KAAK;AACzC,OAAK,YAAY;AACjB,OAAK,aAAa,QAAQ,MAAM;AAEhC,aAAW,MAAM,OAAO;AACpB,QAAI,GAAG,WAAW;AACd,YAAM,MAAM,SAAS,cAAc,KAAK;AACxC,UAAI,YAAY;AAChB,UAAI,aAAa,QAAQ,WAAW;AACpC,WAAK,YAAY,GAAG;AACpB;AAAA,IACJ;AACA,UAAM,MAAM,SAAS,cAAc,QAAQ;AAC3C,QAAI,OAAO;AACX,QAAI,aAAa,QAAQ,UAAU;AACnC,QAAI,MAAM;AACV,QAAI,GAAG,OAAQ,QAAO;AACtB,QAAI,GAAG,SAAU,QAAO;AACxB,QAAI,YAAY;AAChB,QAAI,GAAG,UAAU;AACb,UAAI,WAAW;AACf,UAAI,aAAa,iBAAiB,MAAM;AAAA,IAC5C;AAOA,QAAI,GAAG,MAAO,KAAI,QAAQ,GAAG;AAC7B,QAAI,YAAY;AAAA,sDAC8B,GAAG,QAAQ,EAAE;AAAA,oBAC/C,WAAW,GAAG,KAAK,CAAC;AAAA;AAEhC,QAAI,CAAC,GAAG,UAAU;AACd,UAAI,iBAAiB,SAAS,CAAC,MAAM;AACjC,UAAE,gBAAgB;AAClB,wBAAgB;AAChB,mBAAW,GAAG,MAAM;AAAA,MACxB,CAAC;AAAA,IACL;AACA,SAAK,YAAY,GAAG;AAAA,EACxB;AAOA,GAAC,UAAU,KAAK,SAAS,MAAM,YAAY,IAAI;AAC/C,OAAK,MAAM,UAAU;AACrB,gBAAc;AAGd,sBAAoB,MAAM,GAAG,CAAC;AAI9B,aAAW,MAAM;AACb,aAAS,iBAAiB,aAAa,iBAAiB,EAAE,MAAM,MAAM,SAAS,KAAK,CAAC;AAAA,EACzF,GAAG,CAAC;AACJ,WAAS,iBAAiB,WAAW,WAAW;AAChD,SAAO,iBAAiB,UAAU,gBAAgB,EAAE,SAAS,KAAK,CAAC;AAInE,gBAAc,cAAc,IAAI,EAAE,CAAC,CAAC;AACxC;AAEO,SAAS,kBAAkB;AAC9B,MAAI,CAAC,YAAa;AAClB,QAAM,WAAW;AACjB,QAAM,OAAO,YAAY,SAAS,SAAS,aAAa;AACxD,cAAY,OAAO;AACnB,gBAAc;AACd,mBAAiB;AACjB,WAAS,oBAAoB,WAAW,WAAW;AACnD,SAAO,oBAAoB,UAAU,gBAAgB,EAAE,SAAS,KAAK,CAAC;AAGtE,MAAI,QAAQ,UAAU,YAAa,UAAS,QAAQ,EAAE,eAAe,KAAK,CAAC;AAC/E;AAEA,SAAS,cAAc,MAAM;AACzB,SAAO,CAAC,GAAG,KAAK,iBAAiB,uCAAuC,CAAC;AAC7E;AAKA,SAAS,YAAY,GAAG;AACpB,MAAI,CAAC,YAAa;AAClB,MAAI,EAAE,QAAQ,UAAU;AAAE,MAAE,eAAe;AAAG,oBAAgB;AAAG;AAAA,EAAQ;AACzE,gBAAc,GAAG,cAAc,WAAW,CAAC;AAC/C;AAEA,SAAS,eAAe,GAAG;AACvB,MAAI,eAAe,EAAE,QAAQ,YAAY,YAAY,SAAS,EAAE,MAAM,EAAG;AACzE,kBAAgB;AACpB;AAEA,SAAS,gBAAgB,GAAG;AACxB,MAAI,eAAe,CAAC,YAAY,SAAS,EAAE,MAAM,EAAG,iBAAgB;AACxE;AAEA,SAAS,WAAW,GAAG;AACnB,SAAO,OAAO,CAAC,EAAE,QAAQ,YAAY,CAAC,OAAO;AAAA,IACzC,KAAK;AAAA,IAAS,KAAK;AAAA,IAAQ,KAAK;AAAA,IAAQ,KAAK;AAAA,IAAU,KAAK;AAAA,EAChE,GAAE,CAAC,CAAE;AACT;",
|
|
6
|
-
"names": ["row", "SEQ", "errEl", "c", "list", "v", "placeholder"]
|
|
7
|
-
}
|