@dawcore/components 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/dist/index.d.mts +541 -0
- package/dist/index.d.ts +541 -0
- package/dist/index.js +3111 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3062 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/elements/daw-clip.ts","../src/elements/daw-track.ts","../src/elements/daw-waveform.ts","../src/utils/peak-rendering.ts","../src/utils/viewport.ts","../src/elements/daw-playhead.ts","../src/controllers/animation-controller.ts","../src/elements/daw-transport.ts","../src/elements/daw-play-button.ts","../src/elements/daw-transport-button.ts","../src/elements/daw-pause-button.ts","../src/elements/daw-stop-button.ts","../src/elements/daw-editor.ts","../src/workers/peaksWorker.ts","../src/workers/waveformDataUtils.ts","../src/workers/peakPipeline.ts","../src/elements/daw-track-controls.ts","../src/styles/theme.ts","../src/controllers/viewport-controller.ts","../src/controllers/audio-resume-controller.ts","../src/controllers/recording-controller.ts","../src/interactions/pointer-handler.ts","../src/interactions/file-loader.ts","../src/interactions/recording-clip.ts","../src/elements/daw-ruler.ts","../src/utils/time-format.ts","../src/utils/smart-scale.ts","../src/elements/daw-selection.ts","../src/elements/daw-record-button.ts"],"sourcesContent":["import { LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n@customElement('daw-clip')\nexport class DawClipElement extends LitElement {\n @property() src = '';\n @property({ attribute: 'peaks-src' }) peaksSrc = '';\n @property({ type: Number }) start = 0;\n @property({ type: Number }) duration = 0;\n @property({ type: Number }) offset = 0;\n @property({ type: Number }) gain = 1;\n @property() name = '';\n @property() color = '';\n @property({ type: Number, attribute: 'fade-in' }) fadeIn = 0;\n @property({ type: Number, attribute: 'fade-out' }) fadeOut = 0;\n @property({ attribute: 'fade-type' }) fadeType = 'linear';\n\n readonly clipId = crypto.randomUUID();\n\n // Light DOM — no visual rendering, just a data container\n createRenderRoot() {\n return this;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-clip': DawClipElement;\n }\n}\n","import { LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { PropertyValues } from 'lit';\n\n@customElement('daw-track')\nexport class DawTrackElement extends LitElement {\n @property() src = '';\n @property() name = '';\n @property({ type: Number }) volume = 1;\n @property({ type: Number }) pan = 0;\n @property({ type: Boolean }) muted = false;\n @property({ type: Boolean }) soloed = false;\n\n readonly trackId = crypto.randomUUID();\n\n // Light DOM so <daw-clip> children are queryable.\n createRenderRoot() {\n return this;\n }\n\n connectedCallback() {\n super.connectedCallback();\n // Defer so the editor's connectedCallback (which registers the\n // daw-track-connected listener) has time to run. Without this,\n // tracks parsed before the editor would fire events with no listener.\n setTimeout(() => {\n this.dispatchEvent(\n new CustomEvent('daw-track-connected', {\n bubbles: true,\n composed: true,\n detail: { trackId: this.trackId, element: this },\n })\n );\n }, 0);\n }\n\n // Track removal is detected by the editor's MutationObserver,\n // not by dispatching from disconnectedCallback (detached elements\n // cannot bubble events to ancestors).\n\n private _hasRendered = false;\n\n updated(changed: PropertyValues) {\n // Skip the initial render — all properties appear in `changed` on first\n // update, but the editor handles initial state via daw-track-connected.\n if (!this._hasRendered) {\n this._hasRendered = true;\n return;\n }\n\n const trackProps = ['volume', 'pan', 'muted', 'soloed', 'src', 'name'];\n const hasTrackChange = trackProps.some((p) => changed.has(p as keyof this));\n\n if (hasTrackChange) {\n this.dispatchEvent(\n new CustomEvent('daw-track-update', {\n bubbles: true,\n composed: true,\n detail: { trackId: this.trackId },\n })\n );\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-track': DawTrackElement;\n }\n}\n","import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport type { Peaks, Bits } from '@waveform-playlist/core';\nimport { aggregatePeaks, calculateBarRects } from '../utils/peak-rendering';\nimport { getVisibleChunkIndices } from '../utils/viewport';\n\nconst MAX_CANVAS_WIDTH = 1000;\n\n/** Layout/data properties that require a full redraw when changed. */\nconst LAYOUT_PROPS = new Set(['length', 'waveHeight', 'barWidth', 'barGap']);\n\n/**\n * Group dirty peak indices by canvas chunk. Returns bar-pixel-aligned\n * min/max positions per chunk for correct clearRect coordinates,\n * including when barWidth > 1 or barGap > 0.\n */\nfunction groupDirtyByChunk(\n dirtyPixels: Set<number>,\n step: number\n): Map<number, { min: number; max: number }> {\n const dirtyByChunk = new Map<number, { min: number; max: number }>();\n for (const peakIdx of dirtyPixels) {\n // Map peak index to its bar's global pixel position\n const barPixel = Math.floor(peakIdx / step) * step;\n const chunkIdx = Math.floor(barPixel / MAX_CANVAS_WIDTH);\n const existing = dirtyByChunk.get(chunkIdx);\n if (existing) {\n dirtyByChunk.set(chunkIdx, {\n min: Math.min(existing.min, barPixel),\n max: Math.max(existing.max, barPixel),\n });\n } else {\n dirtyByChunk.set(chunkIdx, { min: barPixel, max: barPixel });\n }\n }\n return dirtyByChunk;\n}\n\n@customElement('daw-waveform')\nexport class DawWaveformElement extends LitElement {\n private _peaks: Peaks = new Int16Array(0);\n private _dirtyPixels: Set<number> = new Set();\n private _drawScheduled = false;\n private _rafId = 0;\n /** Chunk indices visible in the last draw pass — used to detect new chunks on scroll. */\n private _drawnChunks: Set<number> = new Set();\n\n set peaks(value: Peaks) {\n this._peaks = value;\n this._markAllDirty();\n this.requestUpdate();\n }\n\n get peaks(): Peaks {\n return this._peaks;\n }\n\n /**\n * Replace the internal peaks reference without marking all dirty.\n * Use with updatePeaks() for incremental recording updates where\n * appendPeaks() returns a new array but only the tail changed.\n */\n setPeaksQuiet(value: Peaks) {\n this._peaks = value;\n }\n\n get bits(): Bits {\n return this._peaks instanceof Int8Array ? 8 : 16;\n }\n\n @property({ type: Number, attribute: false }) length = 0;\n @property({ type: Number, attribute: false }) waveHeight = 128;\n @property({ type: Number, attribute: false }) barWidth = 1;\n @property({ type: Number, attribute: false }) barGap = 0;\n /** Visible viewport start in pixels (relative to timeline origin). */\n @property({ type: Number, attribute: false }) visibleStart = -Infinity;\n /** Visible viewport end in pixels (relative to timeline origin). */\n @property({ type: Number, attribute: false }) visibleEnd = Infinity;\n /** This element's left offset on the timeline (for viewport intersection). */\n @property({ type: Number, attribute: false }) originX = 0;\n\n static styles = css`\n :host {\n display: block;\n position: relative;\n }\n .container {\n position: relative;\n }\n canvas {\n position: absolute;\n top: 0;\n }\n `;\n\n private _getVisibleChunkIndices(): number[] {\n return getVisibleChunkIndices(\n this.length,\n MAX_CANVAS_WIDTH,\n this.visibleStart,\n this.visibleEnd,\n this.originX\n );\n }\n\n /**\n * Mark a range of peak indices as dirty for incremental redraw.\n * The caller must have already updated the underlying peaks array.\n * Does NOT trigger a Lit re-render — bypasses Lit entirely.\n */\n updatePeaks(startIndex: number, endIndex: number) {\n const peakCount = Math.floor(this._peaks.length / 2);\n const clampedStart = Math.max(0, startIndex);\n const clampedEnd = Math.min(peakCount, endIndex);\n for (let i = clampedStart; i < clampedEnd; i++) {\n this._dirtyPixels.add(i);\n }\n this._scheduleDraw();\n }\n\n private _markAllDirty() {\n const peakCount = Math.floor(this._peaks.length / 2);\n for (let i = 0; i < peakCount; i++) {\n this._dirtyPixels.add(i);\n }\n this._scheduleDraw();\n }\n\n private _scheduleDraw() {\n if (!this._drawScheduled) {\n this._drawScheduled = true;\n this._rafId = requestAnimationFrame(() => {\n this._drawScheduled = false;\n this._drawDirty();\n });\n }\n }\n\n private _drawDirty() {\n if (this._dirtyPixels.size === 0 || this.length === 0 || this._peaks.length === 0) {\n this._dirtyPixels.clear();\n return;\n }\n\n const canvases = this.shadowRoot?.querySelectorAll('canvas');\n if (!canvases || canvases.length === 0) {\n // Don't clear _dirtyPixels — canvases may appear after Lit renders.\n // connectedCallback or updated() will reschedule the draw.\n return;\n }\n\n const step = this.barWidth + this.barGap;\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n const halfHeight = this.waveHeight / 2;\n const bits = this.bits;\n const waveColor =\n getComputedStyle(this).getPropertyValue('--daw-wave-color').trim() || '#c49a6c';\n\n const dirtyByChunk = groupDirtyByChunk(this._dirtyPixels, step);\n\n this._drawnChunks.clear();\n for (const canvas of canvases) {\n const chunkIdx = Number(canvas.dataset.index);\n this._drawnChunks.add(chunkIdx);\n const range = dirtyByChunk.get(chunkIdx);\n if (!range) continue;\n this._drawChunk(canvas, chunkIdx, range, step, dpr, halfHeight, bits, waveColor);\n }\n\n this._dirtyPixels.clear();\n }\n\n private _drawChunk(\n canvas: HTMLCanvasElement,\n chunkIdx: number,\n range: { min: number; max: number },\n step: number,\n dpr: number,\n halfHeight: number,\n bits: Bits,\n waveColor: string\n ) {\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const globalOffset = chunkIdx * MAX_CANVAS_WIDTH;\n // range.min/max are bar-pixel-aligned global positions from groupDirtyByChunk\n const clearStart = Math.max(0, range.min - globalOffset);\n const clearEnd = range.max - globalOffset + this.barWidth;\n const clearWidth = clearEnd - clearStart;\n const firstBar = range.min;\n\n ctx.resetTransform();\n ctx.clearRect(clearStart * dpr, 0, clearWidth * dpr, canvas.height);\n ctx.scale(dpr, dpr);\n ctx.fillStyle = waveColor;\n\n const canvasWidth = Math.min(MAX_CANVAS_WIDTH, this.length - globalOffset);\n const regionEnd = Math.min(globalOffset + clearEnd, globalOffset + canvasWidth);\n\n for (let bar = Math.max(0, firstBar); bar < regionEnd; bar += step) {\n const peak = aggregatePeaks(this._peaks, bits, bar, bar + step);\n if (!peak) continue;\n const rects = calculateBarRects(\n bar - globalOffset,\n this.barWidth,\n halfHeight,\n peak.min,\n peak.max,\n 'normal'\n );\n for (const r of rects) {\n ctx.fillRect(r.x, r.y, r.width, r.height);\n }\n }\n }\n\n connectedCallback() {\n super.connectedCallback();\n // Reschedule draw if dirty pixels survived a disconnect/reconnect cycle\n if (this._dirtyPixels.size > 0) {\n this._scheduleDraw();\n }\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n if (this._drawScheduled) {\n cancelAnimationFrame(this._rafId);\n this._drawScheduled = false;\n }\n // Keep _dirtyPixels — connectedCallback will reschedule if reconnected\n }\n\n render() {\n const indices = this._getVisibleChunkIndices();\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n\n return html`\n <div class=\"container\" style=\"width: ${this.length}px; height: ${this.waveHeight}px;\">\n ${indices.map((i) => {\n const width = Math.min(MAX_CANVAS_WIDTH, this.length - i * MAX_CANVAS_WIDTH);\n return html`\n <canvas\n data-index=${i}\n width=${width * dpr}\n height=${this.waveHeight * dpr}\n style=\"left: ${i * MAX_CANVAS_WIDTH}px; width: ${width}px; height: ${this\n .waveHeight}px;\"\n ></canvas>\n `;\n })}\n </div>\n `;\n }\n\n /** Mark peaks dirty only for chunks that weren't drawn in the previous frame. */\n private _markNewChunksDirty() {\n const currentIndices = this._getVisibleChunkIndices();\n const peakCount = Math.floor(this._peaks.length / 2);\n for (const chunkIdx of currentIndices) {\n if (!this._drawnChunks.has(chunkIdx)) {\n const start = chunkIdx * MAX_CANVAS_WIDTH;\n const end = Math.min(start + MAX_CANVAS_WIDTH, peakCount);\n for (let i = start; i < end; i++) {\n this._dirtyPixels.add(i);\n }\n }\n }\n if (this._dirtyPixels.size > 0) {\n this._scheduleDraw();\n }\n }\n\n updated(changedProperties: Map<string, unknown>) {\n // Layout/data changes require full redraw of all peaks\n const needsFullDirty = [...changedProperties.keys()].some((key) => LAYOUT_PROPS.has(key));\n if (needsFullDirty) {\n this._markAllDirty();\n return;\n }\n // Viewport-only changes: only draw newly visible chunks, skip already-drawn ones\n if (\n changedProperties.has('visibleStart') ||\n changedProperties.has('visibleEnd') ||\n changedProperties.has('originX')\n ) {\n this._markNewChunksDirty();\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-waveform': DawWaveformElement;\n }\n}\n","import type { Peaks, Bits } from '@waveform-playlist/core';\n\nexport type WaveformDrawMode = 'normal' | 'inverted';\n\n/**\n * Result of aggregating peaks over a range.\n *\n * Invariants (assumed from valid waveform input):\n * - min and max are normalized to [-1, 1] by dividing by 2^(bits-1)\n * - min <= max (min-of-mins, max-of-maxes — guaranteed by the interleaved min/max peak format)\n * - Values are finite (derived from integer typed arrays)\n *\n * Construct via aggregatePeaks() — do not create directly.\n */\nexport interface AggregatedPeak {\n min: number;\n max: number;\n}\n\n/**\n * Canvas fillRect parameters for a single waveform bar.\n * width >= 0 and height >= 0 when peak values are in [-1, 1] (guaranteed by\n * the interleaved min/max peak format normalization).\n */\nexport interface BarRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * Aggregates peaks over a range of interleaved min/max pairs.\n * Finds min-of-mins and max-of-maxes, normalized by bit depth.\n *\n * @param data - Interleaved peak data [min0, max0, min1, max1, ...]\n * @param bits - Bit depth (8 or 16)\n * @param startIndex - First peak index (not array index — peak i is at data[i*2], data[i*2+1])\n * @param endIndex - One past the last peak index to include\n * @returns Normalized { min, max } or null if startIndex is out of bounds\n */\nexport function aggregatePeaks(\n data: Peaks,\n bits: Bits,\n startIndex: number,\n endIndex: number\n): AggregatedPeak | null {\n if (startIndex * 2 + 1 >= data.length) {\n return null;\n }\n\n const maxValue = 2 ** (bits - 1);\n let minPeak = data[startIndex * 2] / maxValue;\n let maxPeak = data[startIndex * 2 + 1] / maxValue;\n\n for (let p = startIndex + 1; p < endIndex; p++) {\n if (p * 2 + 1 >= data.length) break;\n const pMin = data[p * 2] / maxValue;\n const pMax = data[p * 2 + 1] / maxValue;\n if (pMin < minPeak) minPeak = pMin;\n if (pMax > maxPeak) maxPeak = pMax;\n }\n\n return { min: minPeak, max: maxPeak };\n}\n\n/**\n * Computes canvas fillRect parameters for a single waveform bar.\n *\n * @param x - Bar x position in canvas coordinates\n * @param barWidth - Width of the bar in pixels\n * @param halfHeight - Half the waveform height (center line y)\n * @param minPeak - Normalized min peak value (negative for below center)\n * @param maxPeak - Normalized max peak value (positive for above center)\n * @param drawMode - 'normal' draws the peak region, 'inverted' draws the non-peak regions\n * @returns Array of BarRect — 1 rect for 'normal', 2 rects for 'inverted'\n */\nexport function calculateBarRects(\n x: number,\n barWidth: number,\n halfHeight: number,\n minPeak: number,\n maxPeak: number,\n drawMode: WaveformDrawMode\n): BarRect[] {\n const min = Math.abs(minPeak * halfHeight);\n const max = Math.abs(maxPeak * halfHeight);\n\n if (drawMode === 'normal') {\n return [{ x, y: halfHeight - max, width: barWidth, height: max + min }];\n }\n\n // Inverted: draw areas WITHOUT audio (top gap + bottom gap)\n return [\n { x, y: 0, width: barWidth, height: halfHeight - max },\n { x, y: halfHeight + min, width: barWidth, height: halfHeight - min },\n ];\n}\n\n/**\n * Computes the first bar position (in global pixel coordinates) that could\n * affect a given canvas chunk.\n *\n * A bar at position X extends from X to X+barWidth-1, so we need bars where\n * barStart + barWidth > canvasStartGlobal.\n *\n * @param canvasStartGlobal - Global pixel offset of the canvas chunk\n * @param barWidth - Width of each bar in pixels\n * @param step - Bar stride (barWidth + barGap)\n * @returns The first bar's global position (always >= 0 when step >= barWidth; caller clamps to 0)\n */\nexport function calculateFirstBarPosition(\n canvasStartGlobal: number,\n barWidth: number,\n step: number\n): number {\n return Math.floor((canvasStartGlobal - barWidth + step) / step) * step;\n}\n","/**\n * Compute which canvas chunk indices are visible within a viewport range.\n *\n * @param totalWidth - Total pixel width of the content\n * @param chunkWidth - Width of each canvas chunk (e.g. 1000px)\n * @param visibleStart - Viewport start in pixels (relative to timeline origin)\n * @param visibleEnd - Viewport end in pixels (relative to timeline origin)\n * @param originX - Content's left offset on the timeline\n */\nexport function getVisibleChunkIndices(\n totalWidth: number,\n chunkWidth: number,\n visibleStart: number,\n visibleEnd: number,\n originX = 0\n): number[] {\n const totalChunks = Math.ceil(totalWidth / chunkWidth);\n const indices: number[] = [];\n for (let i = 0; i < totalChunks; i++) {\n const chunkStart = originX + i * chunkWidth;\n const chunkEnd = chunkStart + chunkWidth;\n if (chunkEnd > visibleStart && chunkStart < visibleEnd) {\n indices.push(i);\n }\n }\n return indices;\n}\n","import { LitElement, html, css } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { AnimationController } from '../controllers/animation-controller';\n\n@customElement('daw-playhead')\nexport class DawPlayheadElement extends LitElement {\n private _animation = new AnimationController(this);\n private _line: HTMLElement | null = null;\n\n static styles = css`\n :host {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n z-index: 10;\n }\n div {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 1px;\n background: var(--daw-playhead-color, #d08070);\n will-change: transform;\n }\n `;\n\n render() {\n return html`<div></div>`;\n }\n\n firstUpdated() {\n this._line = this.shadowRoot!.querySelector('div');\n }\n\n startAnimation(getTime: () => number, sampleRate: number, samplesPerPixel: number) {\n this._animation.start(() => {\n const time = getTime();\n const px = (time * sampleRate) / samplesPerPixel;\n if (this._line) {\n this._line.style.transform = `translate3d(${px}px, 0, 0)`;\n }\n });\n }\n\n stopAnimation(time: number, sampleRate: number, samplesPerPixel: number) {\n this._animation.stop();\n const px = (time * sampleRate) / samplesPerPixel;\n if (this._line) {\n this._line.style.transform = `translate3d(${px}px, 0, 0)`;\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-playhead': DawPlayheadElement;\n }\n}\n","import type { ReactiveController, ReactiveControllerHost } from 'lit';\n\nexport class AnimationController implements ReactiveController {\n private _rafId: number | null = null;\n private _callback: (() => void) | null = null;\n\n constructor(host: ReactiveControllerHost) {\n host.addController(this);\n }\n\n start(callback: () => void) {\n this.stop();\n this._callback = callback;\n const loop = () => {\n this._callback?.();\n this._rafId = requestAnimationFrame(loop);\n };\n this._rafId = requestAnimationFrame(loop);\n }\n\n stop() {\n if (this._rafId !== null) {\n cancelAnimationFrame(this._rafId);\n this._rafId = null;\n }\n this._callback = null;\n }\n\n hostConnected() {}\n\n hostDisconnected() {\n this.stop();\n }\n}\n","import { LitElement } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n@customElement('daw-transport')\nexport class DawTransportElement extends LitElement {\n @property() for = '';\n\n get target(): HTMLElement | null {\n return this.for ? document.getElementById(this.for) : null;\n }\n\n // Light DOM — button children stay in consumer's DOM.\n // No render() needed; light DOM elements don't use <slot>.\n createRenderRoot() {\n return this;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-transport': DawTransportElement;\n }\n}\n","import { html } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { DawTransportButton } from './daw-transport-button';\n\n@customElement('daw-play-button')\nexport class DawPlayButtonElement extends DawTransportButton {\n render() {\n return html`\n <button part=\"button\" @click=${this._onClick}>\n <slot>Play</slot>\n </button>\n `;\n }\n\n private _onClick() {\n const target = this.target;\n if (!target) {\n console.warn(\n '[dawcore] <daw-play-button> has no target. Check <daw-transport for=\"...\"> references a valid <daw-editor> id.'\n );\n return;\n }\n target.play();\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-play-button': DawPlayButtonElement;\n }\n}\n","import { LitElement, css } from 'lit';\nimport type { DawTransportElement } from './daw-transport';\n\n/**\n * Base class for transport button elements.\n * Finds target daw-editor via closest <daw-transport>.\n */\nexport class DawTransportButton extends LitElement {\n protected get target(): any {\n const transport = this.closest('daw-transport') as DawTransportElement | null;\n return transport?.target ?? null;\n }\n\n static styles: import('lit').CSSResultGroup = css`\n button {\n cursor: pointer;\n background: var(--daw-controls-background, #1a1a2e);\n color: var(--daw-controls-text, #e0d4c8);\n border: 1px solid currentColor;\n padding: 4px 8px;\n font: inherit;\n }\n button:hover {\n opacity: 0.8;\n }\n button:disabled {\n opacity: 0.4;\n cursor: default;\n }\n `;\n}\n","import { html } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { DawTransportButton } from './daw-transport-button';\n\n@customElement('daw-pause-button')\nexport class DawPauseButtonElement extends DawTransportButton {\n render() {\n return html`\n <button part=\"button\" @click=${this._onClick}>\n <slot>Pause</slot>\n </button>\n `;\n }\n\n private _onClick() {\n const target = this.target;\n if (!target) {\n console.warn(\n '[dawcore] <daw-pause-button> has no target. Check <daw-transport for=\"...\"> references a valid <daw-editor> id.'\n );\n return;\n }\n target.pause();\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-pause-button': DawPauseButtonElement;\n }\n}\n","import { html } from 'lit';\nimport { customElement } from 'lit/decorators.js';\nimport { DawTransportButton } from './daw-transport-button';\n\n@customElement('daw-stop-button')\nexport class DawStopButtonElement extends DawTransportButton {\n render() {\n return html`\n <button part=\"button\" @click=${this._onClick}>\n <slot>Stop</slot>\n </button>\n `;\n }\n\n private _onClick() {\n const target = this.target;\n if (!target) {\n console.warn(\n '[dawcore] <daw-stop-button> has no target. Check <daw-transport for=\"...\"> references a valid <daw-editor> id.'\n );\n return;\n }\n target.stop();\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-stop-button': DawStopButtonElement;\n }\n}\n","import { LitElement, html, css } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport type { ClipTrack, FadeType, Peaks, PeakData } from '@waveform-playlist/core';\nimport type { TrackDescriptor, ClipDescriptor } from '../types';\nimport { createClipFromSeconds, createTrack, clipPixelWidth } from '@waveform-playlist/core';\nimport { PeakPipeline } from '../workers/peakPipeline';\nimport type { DawTrackElement } from './daw-track';\nimport type { DawClipElement } from './daw-clip';\nimport type { DawPlayheadElement } from './daw-playhead';\nimport type { PlaylistEngine } from '@waveform-playlist/engine';\nimport '../elements/daw-track-controls';\nimport { hostStyles } from '../styles/theme';\nimport { ViewportController } from '../controllers/viewport-controller';\nimport { AudioResumeController } from '../controllers/audio-resume-controller';\nimport { RecordingController } from '../controllers/recording-controller';\nimport type { RecordingOptions } from '../controllers/recording-controller';\nimport { PointerHandler } from '../interactions/pointer-handler';\nimport type {\n DawSelectionDetail,\n DawTrackIdDetail,\n DawTrackErrorDetail,\n DawErrorDetail,\n LoadFilesResult,\n} from '../events';\nimport { loadFiles as loadFilesImpl } from '../interactions/file-loader';\nimport { addRecordedClip } from '../interactions/recording-clip';\n\n@customElement('daw-editor')\nexport class DawEditorElement extends LitElement {\n @property({ type: Number, attribute: 'samples-per-pixel' }) samplesPerPixel = 1024;\n @property({ type: Number, attribute: 'wave-height' }) waveHeight = 128;\n @property({ type: Boolean }) timescale = false;\n @property({ type: Boolean }) mono = false;\n @property({ type: Number, attribute: 'bar-width' }) barWidth = 1;\n @property({ type: Number, attribute: 'bar-gap' }) barGap = 0;\n @property({ type: Boolean, attribute: 'file-drop' }) fileDrop = false;\n /** Initial sample rate hint. Overridden by decoded audio buffer's actual rate. */\n @property({ type: Number, attribute: 'sample-rate' }) sampleRate = 48000;\n /** Resolved sample rate — falls back to sampleRate property until first audio decode. */\n _resolvedSampleRate: number | null = null;\n @state() _tracks: Map<string, TrackDescriptor> = new Map();\n @state() _engineTracks: Map<string, ClipTrack> = new Map();\n @state() _peaksData: Map<string, PeakData> = new Map();\n @state() _isPlaying = false;\n @state() private _duration = 0;\n @state() _selectedTrackId: string | null = null;\n @state() _dragOver = false;\n // Not @state — updated directly to avoid 60fps Lit re-renders\n _selectionStartTime = 0;\n _selectionEndTime = 0;\n _currentTime = 0;\n _engine: PlaylistEngine | null = null;\n private _enginePromise: Promise<PlaylistEngine> | null = null;\n private _audioInitialized = false;\n _audioCache = new Map<string, Promise<AudioBuffer>>();\n _clipBuffers = new Map<string, AudioBuffer>();\n _peakPipeline = new PeakPipeline();\n private _trackElements = new Map<string, DawTrackElement>();\n private _childObserver: MutationObserver | null = null;\n private _audioResume = new AudioResumeController(this);\n @property({ attribute: 'eager-resume' })\n eagerResume?: string;\n private _recordingController = new RecordingController(this);\n private _pointer = new PointerHandler(this);\n private _viewport = (() => {\n const v = new ViewportController(this);\n v.scrollSelector = '.scroll-area';\n return v;\n })();\n\n static styles = [\n hostStyles,\n css`\n :host {\n display: flex;\n position: relative;\n background: var(--daw-background, #1a1a2e);\n overflow: hidden;\n }\n .controls-column {\n flex-shrink: 0;\n width: var(--daw-controls-width, 180px);\n }\n .scroll-area {\n flex: 1;\n overflow-x: auto;\n overflow-y: hidden;\n min-height: var(--daw-min-height, 200px);\n }\n .timeline {\n position: relative;\n min-height: 100%;\n cursor: text;\n }\n .track-row {\n position: relative;\n background: var(--daw-track-background, #16213e);\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n }\n .track-row.selected {\n background: rgba(99, 199, 95, 0.08);\n }\n .timeline.drag-over {\n outline: 2px dashed var(--daw-selection-color, rgba(99, 199, 95, 0.3));\n outline-offset: -2px;\n }\n `,\n ];\n\n get effectiveSampleRate(): number {\n return this._resolvedSampleRate ?? this.sampleRate;\n }\n resolveAudioContextSampleRate(rate: number) {\n if (!this._resolvedSampleRate) this._resolvedSampleRate = rate;\n }\n private get _totalWidth(): number {\n return Math.ceil((this._duration * this.effectiveSampleRate) / this.samplesPerPixel);\n }\n _setSelectedTrackId(trackId: string | null) {\n this._selectedTrackId = trackId;\n }\n get tracks(): TrackDescriptor[] {\n return [...this._tracks.values()];\n }\n get selectedTrackId(): string | null {\n return this._selectedTrackId;\n }\n get selection(): { start: number; end: number } | null {\n if (this._selectionStartTime === 0 && this._selectionEndTime === 0) return null;\n return { start: this._selectionStartTime, end: this._selectionEndTime };\n }\n setSelection(start: number, end: number) {\n this._selectionStartTime = Math.min(start, end);\n this._selectionEndTime = Math.max(start, end);\n if (this._engine) {\n this._engine.setSelection(this._selectionStartTime, this._selectionEndTime);\n }\n this.requestUpdate();\n this.dispatchEvent(\n new CustomEvent<DawSelectionDetail>('daw-selection', {\n bubbles: true,\n composed: true,\n detail: { start: this._selectionStartTime, end: this._selectionEndTime },\n })\n );\n }\n // --- Lifecycle ---\n connectedCallback() {\n super.connectedCallback();\n this.addEventListener('daw-track-connected', this._onTrackConnected as EventListener);\n this.addEventListener('daw-track-update', this._onTrackUpdate as EventListener);\n this.addEventListener('daw-track-control', this._onTrackControl as EventListener);\n this.addEventListener('daw-track-remove', this._onTrackRemoveRequest as EventListener);\n // Detect track removal via MutationObserver (detached elements can't bubble events).\n this._childObserver = new MutationObserver((mutations) => {\n for (const mutation of mutations) {\n for (const node of mutation.removedNodes) {\n if (node instanceof HTMLElement) {\n if (node.tagName === 'DAW-TRACK') {\n this._onTrackRemoved((node as DawTrackElement).trackId);\n }\n const nested = node.querySelectorAll?.('daw-track');\n if (nested) {\n for (const track of nested) {\n this._onTrackRemoved((track as DawTrackElement).trackId);\n }\n }\n }\n }\n }\n });\n this._childObserver.observe(this, { childList: true, subtree: true });\n }\n disconnectedCallback() {\n super.disconnectedCallback();\n this.removeEventListener('daw-track-connected', this._onTrackConnected as EventListener);\n this.removeEventListener('daw-track-update', this._onTrackUpdate as EventListener);\n this.removeEventListener('daw-track-control', this._onTrackControl as EventListener);\n this.removeEventListener('daw-track-remove', this._onTrackRemoveRequest as EventListener);\n this._childObserver?.disconnect();\n this._childObserver = null;\n this._trackElements.clear();\n this._audioCache.clear();\n this._clipBuffers.clear();\n this._peakPipeline.terminate();\n try {\n this._disposeEngine();\n } catch (err) {\n console.warn('[dawcore] Error disposing engine: ' + String(err));\n }\n }\n willUpdate(changedProperties: Map<string, unknown>) {\n if (changedProperties.has('eagerResume')) {\n this._audioResume.target = this.eagerResume;\n }\n // Re-extract peaks at new zoom level from cached WaveformData (near-instant)\n if (changedProperties.has('samplesPerPixel') && this._clipBuffers.size > 0) {\n const reextracted = this._peakPipeline.reextractPeaks(\n this._clipBuffers,\n this.samplesPerPixel,\n this.mono\n );\n if (reextracted.size > 0) {\n const next = new Map(this._peaksData);\n for (const [clipId, peakData] of reextracted) {\n next.set(clipId, peakData);\n }\n this._peaksData = next;\n }\n }\n }\n // --- Track Events ---\n private _onTrackConnected = (e: CustomEvent) => {\n const trackId = e.detail?.trackId;\n const trackEl = e.detail?.element;\n if (!trackId || !(trackEl instanceof HTMLElement)) {\n console.warn('[dawcore] Invalid daw-track-connected event detail: ' + String(e.detail));\n return;\n }\n const descriptor = this._readTrackDescriptor(trackEl as DawTrackElement);\n this._tracks = new Map(this._tracks).set(trackId, descriptor);\n this._trackElements.set(trackId, trackEl as DawTrackElement);\n this._loadTrack(trackId, descriptor);\n };\n private _onTrackRemoved(trackId: string) {\n this._trackElements.delete(trackId);\n // Clean up per-clip data before removing the track (need clip IDs from engine tracks)\n const removedTrack = this._engineTracks.get(trackId);\n if (removedTrack) {\n const nextPeaks = new Map(this._peaksData);\n for (const clip of removedTrack.clips) {\n this._clipBuffers.delete(clip.id);\n nextPeaks.delete(clip.id);\n }\n this._peaksData = nextPeaks;\n }\n const nextTracks = new Map(this._tracks);\n nextTracks.delete(trackId);\n this._tracks = nextTracks;\n const nextEngine = new Map(this._engineTracks);\n nextEngine.delete(trackId);\n this._engineTracks = nextEngine;\n this._recomputeDuration();\n if (this._engine) {\n // Incremental removal preserves playback (no playout rebuild)\n this._engine.removeTrack(trackId);\n }\n if (nextEngine.size === 0) {\n this._currentTime = 0;\n this._stopPlayhead();\n }\n }\n private _onTrackUpdate = (e: CustomEvent) => {\n const trackId = e.detail?.trackId as string;\n if (!trackId) return;\n const trackEl = (e.target as HTMLElement).closest('daw-track') as DawTrackElement | null;\n if (!trackEl) return;\n const oldDescriptor = this._tracks.get(trackId);\n const descriptor = this._readTrackDescriptor(trackEl);\n this._tracks = new Map(this._tracks).set(trackId, descriptor);\n if (this._engine) {\n if (oldDescriptor?.volume !== descriptor.volume)\n this._engine.setTrackVolume(trackId, descriptor.volume);\n if (oldDescriptor?.pan !== descriptor.pan) this._engine.setTrackPan(trackId, descriptor.pan);\n if (oldDescriptor?.muted !== descriptor.muted)\n this._engine.setTrackMute(trackId, descriptor.muted);\n if (oldDescriptor?.soloed !== descriptor.soloed)\n this._engine.setTrackSolo(trackId, descriptor.soloed);\n }\n if (oldDescriptor?.src !== descriptor.src) {\n this._loadTrack(trackId, descriptor);\n }\n };\n private static _CONTROL_PROPS = new Set(['volume', 'pan', 'muted', 'soloed']);\n private _onTrackControl = (e: CustomEvent) => {\n const { trackId, prop, value } = e.detail ?? {};\n if (!trackId || !prop || !DawEditorElement._CONTROL_PROPS.has(prop)) return;\n const oldDescriptor = this._tracks.get(trackId);\n if (oldDescriptor) {\n const descriptor = { ...oldDescriptor, [prop]: value };\n this._tracks = new Map(this._tracks).set(trackId, descriptor);\n // Forward to engine with validated values\n if (this._engine) {\n if (prop === 'volume')\n this._engine.setTrackVolume(trackId, Math.max(0, Math.min(1, Number(value))));\n if (prop === 'pan')\n this._engine.setTrackPan(trackId, Math.max(-1, Math.min(1, Number(value))));\n if (prop === 'muted') this._engine.setTrackMute(trackId, Boolean(value));\n if (prop === 'soloed') this._engine.setTrackSolo(trackId, Boolean(value));\n }\n }\n // Don't sync back to <daw-track> DOM element — avoids daw-track-update loop.\n // _tracks descriptor map is the source of truth for control values.\n };\n private _onTrackRemoveRequest = (e: CustomEvent) => {\n const { trackId } = e.detail ?? {};\n if (!trackId) return;\n const trackEl = this._trackElements.get(trackId);\n if (trackEl) {\n trackEl.remove(); // MutationObserver will trigger _onTrackRemoved\n } else {\n this._onTrackRemoved(trackId); // File-dropped tracks: no DOM element\n }\n };\n private _readTrackDescriptor(trackEl: DawTrackElement): TrackDescriptor {\n const clipEls = trackEl.querySelectorAll('daw-clip') as NodeListOf<DawClipElement>;\n const clips: ClipDescriptor[] = [];\n\n if (clipEls.length === 0 && trackEl.src) {\n clips.push({\n src: trackEl.src,\n start: 0,\n duration: 0,\n offset: 0,\n gain: 1,\n name: trackEl.name || '',\n fadeIn: 0,\n fadeOut: 0,\n fadeType: 'linear',\n });\n } else {\n for (const clipEl of clipEls) {\n clips.push({\n src: clipEl.src,\n start: clipEl.start,\n duration: clipEl.duration,\n offset: clipEl.offset,\n gain: clipEl.gain,\n name: clipEl.name,\n fadeIn: clipEl.fadeIn,\n fadeOut: clipEl.fadeOut,\n fadeType: clipEl.fadeType as FadeType,\n });\n }\n }\n return {\n name: trackEl.name || 'Untitled',\n src: trackEl.src,\n volume: trackEl.volume,\n pan: trackEl.pan,\n muted: trackEl.muted,\n soloed: trackEl.soloed,\n clips,\n };\n }\n // --- Audio Loading ---\n private async _loadTrack(trackId: string, descriptor: TrackDescriptor) {\n try {\n const clips = [];\n for (const clipDesc of descriptor.clips) {\n if (!clipDesc.src) continue;\n const audioBuffer = await this._fetchAndDecode(clipDesc.src);\n // Use the buffer's actual sample rate (hardware rate may differ from initial hint)\n this._resolvedSampleRate = audioBuffer.sampleRate;\n const clip = createClipFromSeconds({\n audioBuffer,\n startTime: clipDesc.start,\n duration: clipDesc.duration || audioBuffer.duration,\n offset: clipDesc.offset,\n gain: clipDesc.gain,\n name: clipDesc.name,\n sampleRate: audioBuffer.sampleRate,\n sourceDuration: audioBuffer.duration,\n });\n\n this._clipBuffers = new Map(this._clipBuffers).set(clip.id, audioBuffer);\n const peakData = await this._peakPipeline.generatePeaks(\n audioBuffer,\n this.samplesPerPixel,\n this.mono\n );\n this._peaksData = new Map(this._peaksData).set(clip.id, peakData);\n clips.push(clip);\n }\n const track = createTrack({\n name: descriptor.name,\n clips,\n volume: descriptor.volume,\n pan: descriptor.pan,\n muted: descriptor.muted,\n soloed: descriptor.soloed,\n });\n // Align track.id with the editor's trackId so engine.setTrackSolo/Mute/etc. find it\n track.id = trackId;\n this._engineTracks = new Map(this._engineTracks).set(trackId, track);\n this._recomputeDuration();\n const engine = await this._ensureEngine();\n engine.setTracks([...this._engineTracks.values()]);\n this.dispatchEvent(\n new CustomEvent<DawTrackIdDetail>('daw-track-ready', {\n bubbles: true,\n composed: true,\n detail: { trackId },\n })\n );\n } catch (err) {\n // Guard against dispatching on a disconnected element (CLAUDE.md pattern #36)\n if (!this.isConnected) return;\n console.warn('[dawcore] Failed to load track \"' + trackId + '\": ' + String(err));\n this.dispatchEvent(\n new CustomEvent<DawTrackErrorDetail>('daw-track-error', {\n bubbles: true,\n composed: true,\n detail: { trackId, error: err },\n })\n );\n }\n }\n async _fetchAndDecode(src: string): Promise<AudioBuffer> {\n if (this._audioCache.has(src)) {\n return this._audioCache.get(src)!;\n }\n const promise = (async () => {\n const response = await fetch(src);\n if (!response.ok) {\n throw new Error(\n 'Failed to fetch audio \"' + src + '\": ' + response.status + ' ' + response.statusText\n );\n }\n const arrayBuffer = await response.arrayBuffer();\n // decodeAudioData works while context is suspended (pre-gesture)\n const { getGlobalAudioContext } = await import('@waveform-playlist/playout');\n return getGlobalAudioContext().decodeAudioData(arrayBuffer);\n })();\n this._audioCache.set(src, promise);\n try {\n return await promise;\n } catch (err) {\n this._audioCache.delete(src);\n throw err;\n }\n }\n _recomputeDuration() {\n let maxSample = 0;\n for (const track of this._engineTracks.values()) {\n for (const clip of track.clips) {\n const endSample = clip.startSample + clip.durationSamples;\n if (endSample > maxSample) maxSample = endSample;\n }\n }\n this._duration = maxSample / this.effectiveSampleRate;\n }\n // --- Engine ---\n _ensureEngine(): Promise<PlaylistEngine> {\n if (this._engine) return Promise.resolve(this._engine);\n if (this._enginePromise) return this._enginePromise;\n this._enginePromise = this._buildEngine().catch((err) => {\n this._enginePromise = null;\n throw err;\n });\n return this._enginePromise;\n }\n private async _buildEngine() {\n const [{ PlaylistEngine }, { createToneAdapter }] = await Promise.all([\n import('@waveform-playlist/engine'),\n import('@waveform-playlist/playout'),\n ]);\n\n const adapter = createToneAdapter();\n const engine = new PlaylistEngine({\n adapter,\n sampleRate: this.effectiveSampleRate,\n samplesPerPixel: this.samplesPerPixel,\n zoomLevels: [256, 512, 1024, 2048, 4096, 8192, this.samplesPerPixel]\n .filter((v, i, a) => a.indexOf(v) === i)\n .sort((a, b) => a - b),\n });\n engine.on('statechange', (engineState) => {\n this._isPlaying = engineState.isPlaying;\n this._duration = engineState.duration;\n this._selectedTrackId = engineState.selectedTrackId;\n });\n engine.on('timeupdate', (time: number) => {\n this._currentTime = time;\n });\n engine.on('stop', () => {\n this._currentTime = engine.getCurrentTime();\n this._stopPlayhead();\n });\n\n this._engine = engine;\n return engine;\n }\n private _disposeEngine() {\n if (this._engine) {\n this._engine.dispose();\n this._engine = null;\n }\n this._enginePromise = null;\n }\n // --- File Drop ---\n private _onDragOver = (e: DragEvent) => {\n if (!this.fileDrop) return;\n e.preventDefault();\n if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';\n this._dragOver = true;\n };\n private _onDragLeave = (e: DragEvent) => {\n if (!this.fileDrop) return;\n // relatedTarget is null when cursor leaves the browser window — that's fine,\n // we still want to clear _dragOver in that case.\n const timeline = this.shadowRoot?.querySelector('.timeline');\n if (timeline && !timeline.contains(e.relatedTarget as Node)) {\n this._dragOver = false;\n }\n };\n private _onDrop = async (e: DragEvent) => {\n if (!this.fileDrop) return;\n e.preventDefault();\n this._dragOver = false;\n const files = e.dataTransfer?.files;\n if (!files || files.length === 0) return;\n try {\n await this.loadFiles(files);\n } catch (err) {\n console.warn('[dawcore] File drop failed: ' + String(err));\n this.dispatchEvent(\n new CustomEvent<DawErrorDetail>('daw-error', {\n bubbles: true,\n composed: true,\n detail: { operation: 'file-drop', error: err },\n })\n );\n }\n };\n async loadFiles(files: FileList | File[]): Promise<LoadFilesResult> {\n return loadFilesImpl(this, files);\n }\n // --- Playback ---\n async play() {\n try {\n const engine = await this._ensureEngine();\n if (!this._audioInitialized) {\n await engine.init();\n this._audioInitialized = true;\n }\n engine.play();\n this._startPlayhead();\n this.dispatchEvent(new CustomEvent('daw-play', { bubbles: true, composed: true }));\n } catch (err) {\n console.warn('[dawcore] Playback failed: ' + String(err));\n this.dispatchEvent(\n new CustomEvent<DawErrorDetail>('daw-error', {\n bubbles: true,\n composed: true,\n detail: { operation: 'play', error: err },\n })\n );\n }\n }\n pause() {\n if (!this._engine) return;\n this._engine.pause();\n this._stopPlayhead();\n this.dispatchEvent(new CustomEvent('daw-pause', { bubbles: true, composed: true }));\n }\n stop() {\n if (!this._engine) return;\n this._engine.stop();\n this._stopPlayhead();\n this.dispatchEvent(new CustomEvent('daw-stop', { bubbles: true, composed: true }));\n }\n seekTo(time: number) {\n if (!this._engine) return;\n this._engine.seek(time);\n this._currentTime = time;\n }\n\n // --- Recording ---\n recordingStream: MediaStream | null = null;\n get isRecording(): boolean {\n return this._recordingController.isRecording;\n }\n stopRecording(): void {\n this._recordingController.stopRecording();\n }\n _addRecordedClip(trackId: string, buf: AudioBuffer, startSample: number, durSamples: number) {\n addRecordedClip(this, trackId, buf, startSample, durSamples);\n }\n async startRecording(stream?: MediaStream, options?: RecordingOptions): Promise<void> {\n const s = stream ?? this.recordingStream;\n if (!s) {\n console.warn('[dawcore] startRecording: no stream provided and recordingStream is null');\n return;\n }\n await this._recordingController.startRecording(s, options);\n }\n\n private _renderRecordingPreview(trackId: string, chH: number) {\n const rs = this._recordingController.getSession(trackId);\n if (!rs) return '';\n const left = Math.floor(rs.startSample / this.samplesPerPixel);\n const w = Math.floor(rs.totalSamples / this.samplesPerPixel);\n return rs.peaks.map(\n (chPeaks, ch) => html`\n <daw-waveform\n data-recording-track=${trackId}\n data-recording-channel=${ch}\n style=\"position:absolute;left:${left}px;top:${ch * chH}px;\"\n .peaks=${chPeaks}\n .length=${w}\n .waveHeight=${chH}\n .barWidth=${this.barWidth}\n .barGap=${this.barGap}\n .visibleStart=${this._viewport.visibleStart}\n .visibleEnd=${this._viewport.visibleEnd}\n .originX=${left}\n ></daw-waveform>\n `\n );\n }\n\n // --- Playhead ---\n _startPlayhead() {\n const playhead = this._getPlayhead();\n if (!playhead || !this._engine) return;\n const engine = this._engine;\n playhead.startAnimation(\n () => engine.getCurrentTime(),\n this.effectiveSampleRate,\n this.samplesPerPixel\n );\n }\n _stopPlayhead() {\n const playhead = this._getPlayhead();\n if (!playhead) return;\n playhead.stopAnimation(this._currentTime, this.effectiveSampleRate, this.samplesPerPixel);\n }\n private _getPlayhead(): DawPlayheadElement | null {\n return this.shadowRoot?.querySelector('daw-playhead') as DawPlayheadElement | null;\n }\n private _getOrderedTracks(): Array<[string, ClipTrack]> {\n const domOrder: string[] = [...this.querySelectorAll('daw-track')].map(\n (el) => (el as DawTrackElement).trackId\n );\n return [...this._engineTracks.entries()].sort((a, b) => {\n const ai = domOrder.indexOf(a[0]);\n const bi = domOrder.indexOf(b[0]);\n // Both not in DOM (e.g. file drops): preserve Map insertion order\n if (ai === -1 && bi === -1) return 0;\n // Only one not in DOM: sort it after DOM tracks\n if (ai === -1) return 1;\n if (bi === -1) return -1;\n return ai - bi;\n });\n }\n\n // --- Render ---\n render() {\n const sr = this.effectiveSampleRate;\n const selStartPx = (this._selectionStartTime * sr) / this.samplesPerPixel;\n const selEndPx = (this._selectionEndTime * sr) / this.samplesPerPixel;\n\n // Precompute track info once for both controls column and timeline\n const orderedTracks = this._getOrderedTracks().map(([trackId, track]) => {\n const descriptor = this._tracks.get(trackId);\n const firstPeaks = track.clips\n .map((c) => this._peaksData.get(c.id))\n .find((p) => p && p.data.length > 0);\n const numChannels = firstPeaks ? firstPeaks.data.length : 1;\n return {\n trackId,\n track,\n descriptor,\n numChannels,\n trackHeight: this.waveHeight * numChannels,\n };\n });\n\n return html`\n ${orderedTracks.length > 0\n ? html`<div class=\"controls-column\">\n ${this.timescale ? html`<div style=\"height: 30px;\"></div>` : ''}\n ${orderedTracks.map(\n (t) => html`\n <daw-track-controls\n style=\"height: ${t.trackHeight}px;\"\n .trackId=${t.trackId}\n .trackName=${t.descriptor?.name ?? 'Untitled'}\n .volume=${t.descriptor?.volume ?? 1}\n .pan=${t.descriptor?.pan ?? 0}\n .muted=${t.descriptor?.muted ?? false}\n .soloed=${t.descriptor?.soloed ?? false}\n ></daw-track-controls>\n `\n )}\n </div>`\n : ''}\n <div class=\"scroll-area\">\n <div\n class=\"timeline ${this._dragOver ? 'drag-over' : ''}\"\n style=\"width: ${this._totalWidth > 0 ? this._totalWidth + 'px' : '100%'};\"\n data-playing=${this._isPlaying}\n @pointerdown=${this._pointer.onPointerDown}\n @dragover=${this._onDragOver}\n @dragleave=${this._onDragLeave}\n @drop=${this._onDrop}\n >\n ${orderedTracks.length > 0 && this.timescale\n ? html`<daw-ruler\n .samplesPerPixel=${this.samplesPerPixel}\n .sampleRate=${this.effectiveSampleRate}\n .duration=${this._duration}\n ></daw-ruler>`\n : ''}\n ${orderedTracks.length > 0\n ? html`<daw-selection .startPx=${selStartPx} .endPx=${selEndPx}></daw-selection>\n <daw-playhead></daw-playhead>`\n : ''}\n ${orderedTracks.map((t) => {\n const channelHeight = this.waveHeight;\n return html`\n <div\n class=\"track-row ${t.trackId === this._selectedTrackId ? 'selected' : ''}\"\n style=\"height: ${t.trackHeight}px;\"\n data-track-id=${t.trackId}\n >\n ${t.track.clips.map((clip) => {\n const peakData = this._peaksData.get(clip.id);\n const width = clipPixelWidth(\n clip.startSample,\n clip.durationSamples,\n this.samplesPerPixel\n );\n const clipLeft = Math.floor(clip.startSample / this.samplesPerPixel);\n const channels: Peaks[] = peakData?.data ?? [new Int16Array(0)];\n return channels.map(\n (channelPeaks, chIdx) => html`\n <daw-waveform\n style=\"position: absolute; left: ${clipLeft}px; top: ${chIdx *\n channelHeight}px;\"\n .peaks=${channelPeaks}\n .length=${peakData?.length ?? width}\n .waveHeight=${channelHeight}\n .barWidth=${this.barWidth}\n .barGap=${this.barGap}\n .visibleStart=${this._viewport.visibleStart}\n .visibleEnd=${this._viewport.visibleEnd}\n .originX=${clipLeft}\n ></daw-waveform>\n `\n );\n })}\n ${this._renderRecordingPreview(t.trackId, channelHeight)}\n </div>\n `;\n })}\n </div>\n </div>\n <slot></slot>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-editor': DawEditorElement;\n }\n}\n","/**\n * Inline Web Worker for generating WaveformData binary format from AudioBuffer channels.\n *\n * Uses a Blob URL approach (portable across all bundlers) with the generateWaveformData\n * algorithm adapted from BBC's waveform-data.js (MIT licensed, adapted from Audacity).\n *\n * The worker generates peaks at a base scale (finest zoom level). The main thread\n * then uses WaveformData.resample() for near-instant zoom changes.\n */\n\nimport WaveformData from 'waveform-data';\n\n// ────────────────────────────────────────────────────────────────────────────\n// Worker code (runs inside the Blob URL worker)\n// ────────────────────────────────────────────────────────────────────────────\n\n/**\n * Self-contained worker source.\n * Contains the generateWaveformData function from waveform-data.js/src/waveform-generator.js\n * (MIT License, BBC). Pure JS, zero dependencies.\n */\nconst workerSource = `\n\"use strict\";\n\nvar INT8_MAX = 127;\nvar INT8_MIN = -128;\nvar INT16_MAX = 32767;\nvar INT16_MIN = -32768;\n\nfunction calculateWaveformDataLength(audio_sample_count, scale) {\n var data_length = Math.floor(audio_sample_count / scale);\n var samples_remaining = audio_sample_count - (data_length * scale);\n if (samples_remaining > 0) {\n data_length++;\n }\n return data_length;\n}\n\nfunction generateWaveformData(options) {\n var scale = options.scale;\n var amplitude_scale = options.amplitude_scale;\n var split_channels = options.split_channels;\n var length = options.length;\n var sample_rate = options.sample_rate;\n var channels = options.channels.map(function(channel) {\n return new Float32Array(channel);\n });\n var output_channels = split_channels ? channels.length : 1;\n var header_size = 24;\n var data_length = calculateWaveformDataLength(length, scale);\n var bytes_per_sample = options.bits === 8 ? 1 : 2;\n var total_size = header_size + data_length * 2 * bytes_per_sample * output_channels;\n var buffer = new ArrayBuffer(total_size);\n var data_view = new DataView(buffer);\n\n var scale_counter = 0;\n var offset = header_size;\n\n var min_value = new Array(output_channels);\n var max_value = new Array(output_channels);\n\n for (var channel = 0; channel < output_channels; channel++) {\n min_value[channel] = Infinity;\n max_value[channel] = -Infinity;\n }\n\n var range_min = options.bits === 8 ? INT8_MIN : INT16_MIN;\n var range_max = options.bits === 8 ? INT8_MAX : INT16_MAX;\n\n data_view.setInt32(0, 2, true);\n data_view.setUint32(4, options.bits === 8, true);\n data_view.setInt32(8, sample_rate, true);\n data_view.setInt32(12, scale, true);\n data_view.setInt32(16, data_length, true);\n data_view.setInt32(20, output_channels, true);\n\n for (var i = 0; i < length; i++) {\n var sample = 0;\n\n if (output_channels === 1) {\n for (var ch = 0; ch < channels.length; ++ch) {\n sample += channels[ch][i];\n }\n sample = Math.floor(range_max * sample * amplitude_scale / channels.length);\n\n if (sample < min_value[0]) {\n min_value[0] = sample;\n if (min_value[0] < range_min) {\n min_value[0] = range_min;\n }\n }\n if (sample > max_value[0]) {\n max_value[0] = sample;\n if (max_value[0] > range_max) {\n max_value[0] = range_max;\n }\n }\n }\n else {\n for (var ch2 = 0; ch2 < output_channels; ++ch2) {\n sample = Math.floor(range_max * channels[ch2][i] * amplitude_scale);\n\n if (sample < min_value[ch2]) {\n min_value[ch2] = sample;\n if (min_value[ch2] < range_min) {\n min_value[ch2] = range_min;\n }\n }\n if (sample > max_value[ch2]) {\n max_value[ch2] = sample;\n if (max_value[ch2] > range_max) {\n max_value[ch2] = range_max;\n }\n }\n }\n }\n\n if (++scale_counter === scale) {\n for (var ch3 = 0; ch3 < output_channels; ch3++) {\n if (options.bits === 8) {\n data_view.setInt8(offset++, min_value[ch3]);\n data_view.setInt8(offset++, max_value[ch3]);\n }\n else {\n data_view.setInt16(offset, min_value[ch3], true);\n data_view.setInt16(offset + 2, max_value[ch3], true);\n offset += 4;\n }\n min_value[ch3] = Infinity;\n max_value[ch3] = -Infinity;\n }\n scale_counter = 0;\n }\n }\n\n if (scale_counter > 0) {\n for (var ch4 = 0; ch4 < output_channels; ch4++) {\n if (options.bits === 8) {\n data_view.setInt8(offset++, min_value[ch4]);\n data_view.setInt8(offset++, max_value[ch4]);\n }\n else {\n data_view.setInt16(offset, min_value[ch4], true);\n data_view.setInt16(offset + 2, max_value[ch4], true);\n offset += 4;\n }\n }\n }\n\n return buffer;\n}\n\nself.onmessage = function(e) {\n var msg = e.data;\n try {\n var result = generateWaveformData({\n scale: msg.scale,\n bits: msg.bits,\n amplitude_scale: msg.amplitude_scale,\n split_channels: msg.split_channels,\n length: msg.length,\n sample_rate: msg.sample_rate,\n channels: msg.channels\n });\n self.postMessage({ id: msg.id, buffer: result }, [result]);\n } catch (err) {\n self.postMessage({ id: msg.id, error: err.message || String(err) });\n }\n};\n`;\n\n// ────────────────────────────────────────────────────────────────────────────\n// Promise-based worker API (runs on the main thread)\n// ────────────────────────────────────────────────────────────────────────────\n\nexport interface PeaksWorkerApi {\n generate(params: {\n channels: ArrayBuffer[];\n length: number;\n sampleRate: number;\n scale: number;\n bits: 8 | 16;\n splitChannels: boolean;\n }): Promise<WaveformData>;\n terminate(): void;\n}\n\ninterface PendingEntry {\n resolve: (value: WaveformData) => void;\n reject: (reason: unknown) => void;\n}\n\nexport function createPeaksWorker(): PeaksWorkerApi {\n let worker: Worker;\n try {\n const blob = new Blob([workerSource], { type: 'application/javascript' });\n const url = URL.createObjectURL(blob);\n worker = new Worker(url);\n URL.revokeObjectURL(url);\n } catch (err) {\n // Worker creation can fail in CSP-restricted environments that block blob: URLs.\n console.warn('[dawcore] Failed to create peaks worker (CSP restriction?): ' + String(err));\n return {\n generate() {\n return Promise.reject(\n new Error(\n 'Peaks worker unavailable (CSP may block blob: URLs). Add blob: to worker-src directive.'\n )\n );\n },\n terminate() {\n /* no-op */\n },\n };\n }\n\n const pending = new Map<string, PendingEntry>();\n let terminated = false;\n let idCounter = 0;\n\n worker.onmessage = (e: MessageEvent) => {\n const msg = e.data;\n const entry = pending.get(msg.id);\n if (!entry) {\n console.warn('[dawcore] Received worker message for unknown id: ' + String(msg.id));\n return;\n }\n pending.delete(msg.id);\n\n if (msg.error) {\n entry.reject(new Error(msg.error));\n } else {\n try {\n const waveformData = WaveformData.create(msg.buffer);\n entry.resolve(waveformData);\n } catch (err) {\n entry.reject(err);\n }\n }\n };\n\n worker.onerror = (e: ErrorEvent) => {\n const reason = e.error ?? new Error(e.message);\n console.warn('[dawcore] Peaks worker crashed: ' + String(reason));\n terminated = true;\n worker.terminate();\n for (const [, entry] of pending) {\n entry.reject(reason);\n }\n pending.clear();\n };\n\n return {\n generate(params) {\n if (terminated) return Promise.reject(new Error('Worker terminated'));\n const messageId = String(++idCounter);\n\n return new Promise<WaveformData>((resolve, reject) => {\n pending.set(messageId, { resolve, reject });\n\n worker.postMessage(\n {\n id: messageId,\n scale: params.scale,\n bits: params.bits,\n amplitude_scale: 1.0,\n split_channels: params.splitChannels,\n length: params.length,\n sample_rate: params.sampleRate,\n channels: params.channels,\n },\n params.channels // Transfer ownership\n );\n });\n },\n\n terminate() {\n terminated = true;\n worker.terminate();\n for (const [, entry] of pending) {\n entry.reject(new Error('Worker terminated'));\n }\n pending.clear();\n },\n };\n}\n","/**\n * Utilities for converting WaveformData to PeakData format.\n * Adapted from @waveform-playlist/browser waveformDataLoader.ts.\n */\n\nimport WaveformData from 'waveform-data';\nimport type { PeakData, Peaks } from '@waveform-playlist/core';\n\n/**\n * Slice and resample WaveformData with aligned source indices.\n */\nfunction sliceAndResample(\n waveformData: WaveformData,\n samplesPerPixel: number,\n offsetSamples?: number,\n durationSamples?: number\n): WaveformData | null {\n let processedData = waveformData;\n\n if (offsetSamples !== undefined && durationSamples !== undefined) {\n if (processedData.scale !== samplesPerPixel) {\n const sourceScale = waveformData.scale;\n const ratio = samplesPerPixel / sourceScale;\n\n const targetStart = Math.floor(offsetSamples / samplesPerPixel);\n const targetEnd = Math.ceil((offsetSamples + durationSamples) / samplesPerPixel);\n\n const sourceStart = Math.max(0, Math.floor(targetStart * ratio));\n const sourceEnd = Math.min(waveformData.length, Math.ceil(targetEnd * ratio));\n\n if (sourceStart >= sourceEnd) {\n return null;\n }\n\n processedData = processedData.slice({\n startIndex: sourceStart,\n endIndex: sourceEnd,\n });\n processedData = processedData.resample({ scale: samplesPerPixel });\n } else {\n const startIndex = Math.floor(offsetSamples / samplesPerPixel);\n const endIndex = Math.ceil((offsetSamples + durationSamples) / samplesPerPixel);\n processedData = processedData.slice({ startIndex, endIndex });\n }\n } else if (processedData.scale !== samplesPerPixel) {\n processedData = processedData.resample({ scale: samplesPerPixel });\n }\n\n return processedData;\n}\n\n/**\n * Extract peaks from a WaveformData object, handling all channels, mono merging,\n * slicing, and resampling.\n */\nexport function extractPeaks(\n waveformData: WaveformData,\n samplesPerPixel: number,\n isMono: boolean,\n offsetSamples?: number,\n durationSamples?: number\n): PeakData {\n const processedData = sliceAndResample(\n waveformData,\n samplesPerPixel,\n offsetSamples,\n durationSamples\n );\n\n if (processedData === null) {\n const bits = waveformData.bits as 8 | 16;\n const numChannels = isMono ? 1 : waveformData.channels;\n const emptyData: Peaks[] = Array.from({ length: numChannels }, () =>\n bits === 8 ? new Int8Array(0) : new Int16Array(0)\n );\n return { length: 0, data: emptyData, bits };\n }\n\n const numChannels = processedData.channels;\n const bits = processedData.bits as 8 | 16;\n\n const channelPeaks: Peaks[] = [];\n for (let c = 0; c < numChannels; c++) {\n const channel = processedData.channel(c);\n const minArray = channel.min_array();\n const maxArray = channel.max_array();\n const len = minArray.length;\n\n const peaks: Peaks = bits === 8 ? new Int8Array(len * 2) : new Int16Array(len * 2);\n\n for (let i = 0; i < len; i++) {\n peaks[i * 2] = minArray[i];\n peaks[i * 2 + 1] = maxArray[i];\n }\n channelPeaks.push(peaks);\n }\n\n if (isMono && channelPeaks.length > 1) {\n const weight = 1 / channelPeaks.length;\n const numPeaks = channelPeaks[0].length / 2;\n const monoPeaks: Peaks =\n bits === 8 ? new Int8Array(numPeaks * 2) : new Int16Array(numPeaks * 2);\n\n for (let i = 0; i < numPeaks; i++) {\n let min = 0;\n let max = 0;\n for (let c = 0; c < channelPeaks.length; c++) {\n min += weight * channelPeaks[c][i * 2];\n max += weight * channelPeaks[c][i * 2 + 1];\n }\n monoPeaks[i * 2] = min;\n monoPeaks[i * 2 + 1] = max;\n }\n\n return { length: numPeaks, data: [monoPeaks], bits };\n }\n\n const peakLength = channelPeaks.length > 0 ? channelPeaks[0].length / 2 : 0;\n return { length: peakLength, data: channelPeaks, bits };\n}\n","/**\n * Peak generation pipeline: AudioBuffer → web worker → WaveformData → PeakData.\n *\n * Manages worker lifecycle, WaveformData caching per AudioBuffer (WeakMap),\n * inflight dedup, and peak extraction via resample() for any zoom level\n * coarser than the base scale.\n *\n * The base scale determines the finest zoom level that can be rendered without\n * regenerating. Resampling only works to coarser (larger) scales. Set baseScale\n * to the finest zoom level the user might need.\n */\n\nimport type WaveformData from 'waveform-data';\nimport type { PeakData } from '@waveform-playlist/core';\nimport { createPeaksWorker, type PeaksWorkerApi } from './peaksWorker';\nimport { extractPeaks } from './waveformDataUtils';\n\nexport class PeakPipeline {\n private _worker: PeaksWorkerApi | null = null;\n private _cache = new WeakMap<AudioBuffer, WaveformData>();\n private _inflight = new WeakMap<AudioBuffer, Promise<WaveformData>>();\n\n /**\n * Generate PeakData for a clip from its AudioBuffer.\n * Uses cached WaveformData when available; otherwise generates via worker.\n * The worker generates at `scale` (= samplesPerPixel) for exact rendering.\n */\n async generatePeaks(\n audioBuffer: AudioBuffer,\n samplesPerPixel: number,\n isMono: boolean\n ): Promise<PeakData> {\n const waveformData = await this._getWaveformData(audioBuffer, samplesPerPixel);\n try {\n return extractPeaks(waveformData, samplesPerPixel, isMono);\n } catch (err) {\n console.warn('[dawcore] extractPeaks failed: ' + String(err));\n throw err;\n }\n }\n\n /**\n * Re-extract peaks for all clips at a new zoom level using cached WaveformData.\n * Only works for zoom levels coarser than (or equal to) the cached base scale.\n * Returns a new Map of clipId → PeakData. Clips without cached data or where\n * the target scale is finer than the cached base are skipped.\n */\n reextractPeaks(\n clipBuffers: ReadonlyMap<string, AudioBuffer>,\n samplesPerPixel: number,\n isMono: boolean\n ): Map<string, PeakData> {\n const result = new Map<string, PeakData>();\n for (const [clipId, audioBuffer] of clipBuffers) {\n const cached = this._cache.get(audioBuffer);\n if (cached) {\n // Skip if target scale is finer than cached — resample can't downsample\n if (samplesPerPixel < cached.scale) continue;\n try {\n result.set(clipId, extractPeaks(cached, samplesPerPixel, isMono));\n } catch (err) {\n console.warn('[dawcore] reextractPeaks failed for clip ' + clipId + ': ' + String(err));\n }\n }\n }\n return result;\n }\n\n terminate() {\n this._worker?.terminate();\n this._worker = null;\n }\n\n private async _getWaveformData(\n audioBuffer: AudioBuffer,\n samplesPerPixel: number\n ): Promise<WaveformData> {\n const cached = this._cache.get(audioBuffer);\n // Use cache if it's at a scale fine enough for the requested zoom\n if (cached && cached.scale <= samplesPerPixel) return cached;\n\n const inflight = this._inflight.get(audioBuffer);\n if (inflight) return inflight;\n\n if (!this._worker) {\n this._worker = createPeaksWorker();\n }\n\n // Generate at the requested scale — this is the finest zoom we can resample from\n // .slice() channel buffers to avoid detaching the original AudioBuffer views\n const channels: ArrayBuffer[] = [];\n for (let c = 0; c < audioBuffer.numberOfChannels; c++) {\n channels.push(audioBuffer.getChannelData(c).slice().buffer as ArrayBuffer);\n }\n\n const promise = this._worker\n .generate({\n channels,\n length: audioBuffer.length,\n sampleRate: audioBuffer.sampleRate,\n scale: samplesPerPixel,\n bits: 16,\n splitChannels: true,\n })\n .then((waveformData) => {\n this._cache.set(audioBuffer, waveformData);\n this._inflight.delete(audioBuffer);\n return waveformData;\n })\n .catch((err) => {\n this._inflight.delete(audioBuffer);\n console.warn('[dawcore] Peak generation via worker failed: ' + String(err));\n throw err;\n });\n\n this._inflight.set(audioBuffer, promise);\n return promise;\n }\n}\n","import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n@customElement('daw-track-controls')\nexport class DawTrackControlsElement extends LitElement {\n /** Track ID — set by the editor to link controls to a track row. */\n @property({ attribute: false }) trackId: string | null = null;\n @property({ attribute: false }) trackName = '';\n @property({ type: Number, attribute: false }) volume = 1;\n @property({ type: Number, attribute: false }) pan = 0;\n @property({ type: Boolean, attribute: false }) muted = false;\n @property({ type: Boolean, attribute: false }) soloed = false;\n\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n justify-content: center;\n box-sizing: border-box;\n padding: 6px 8px;\n background: var(--daw-controls-background, #0f0f1a);\n color: var(--daw-controls-text, #c49a6c);\n border-bottom: 1px solid rgba(255, 255, 255, 0.05);\n font-family: system-ui, sans-serif;\n font-size: 11px;\n }\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 4px;\n margin-bottom: 6px;\n }\n .name {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-weight: 600;\n font-size: 11px;\n }\n .remove-btn {\n background: none;\n border: none;\n color: var(--daw-controls-text, #c49a6c);\n cursor: pointer;\n padding: 0 2px;\n font-size: 14px;\n line-height: 1;\n opacity: 0.4;\n }\n .remove-btn:hover {\n opacity: 1;\n color: #d08070;\n }\n .buttons {\n display: flex;\n gap: 3px;\n margin-bottom: 6px;\n }\n .btn {\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 3px;\n color: var(--daw-controls-text, #c49a6c);\n cursor: pointer;\n font-size: 10px;\n font-weight: 600;\n padding: 2px 8px;\n text-align: center;\n }\n .btn:hover {\n background: rgba(255, 255, 255, 0.12);\n }\n .btn.active {\n background: rgba(99, 199, 95, 0.25);\n border-color: rgba(99, 199, 95, 0.5);\n color: #63c75f;\n }\n .btn.muted-active {\n background: rgba(208, 128, 112, 0.25);\n border-color: rgba(208, 128, 112, 0.5);\n color: #d08070;\n }\n .slider-row {\n display: flex;\n align-items: center;\n gap: 4px;\n height: 20px;\n }\n .slider-label {\n width: 50px;\n font-size: 9px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n opacity: 0.6;\n flex-shrink: 0;\n display: flex;\n justify-content: space-between;\n }\n .slider-label-name {\n opacity: 0.5;\n }\n .slider-label-value {\n font-family: 'Courier New', monospace;\n }\n input[type='range'] {\n flex: 1;\n min-width: 0;\n height: 20px;\n margin: 0;\n -webkit-appearance: none;\n appearance: none;\n background: transparent;\n cursor: pointer;\n }\n input[type='range']::-webkit-slider-runnable-track {\n height: 3px;\n background: rgba(255, 255, 255, 0.12);\n border-radius: 2px;\n }\n input[type='range']::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: var(--daw-controls-text, #c49a6c);\n margin-top: -4.5px;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);\n }\n input[type='range']::-moz-range-track {\n height: 3px;\n background: rgba(255, 255, 255, 0.12);\n border-radius: 2px;\n border: none;\n }\n input[type='range']::-moz-range-thumb {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: var(--daw-controls-text, #c49a6c);\n border: none;\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4);\n }\n `;\n\n private _onVolumeInput = (e: Event) => {\n const value = Number((e.target as HTMLInputElement).value);\n if (Number.isFinite(value)) this._dispatchControl('volume', value);\n };\n\n private _onPanInput = (e: Event) => {\n const value = Number((e.target as HTMLInputElement).value);\n if (Number.isFinite(value)) this._dispatchControl('pan', value);\n };\n\n private _onMuteClick = () => {\n this._dispatchControl('muted', !this.muted);\n };\n\n private _onSoloClick = () => {\n this._dispatchControl('soloed', !this.soloed);\n };\n\n private _onRemoveClick = () => {\n if (!this.trackId) return;\n this.dispatchEvent(\n new CustomEvent('daw-track-remove', {\n bubbles: true,\n composed: true,\n detail: { trackId: this.trackId },\n })\n );\n };\n\n private _dispatchControl(prop: string, value: number | boolean) {\n if (!this.trackId) return;\n this.dispatchEvent(\n new CustomEvent('daw-track-control', {\n bubbles: true,\n composed: true,\n detail: { trackId: this.trackId, prop, value },\n })\n );\n }\n\n render() {\n const volPercent = Math.round(this.volume * 100);\n const panPercent = Math.round(Math.abs(this.pan) * 100);\n const panDisplay = this.pan === 0 ? 'C' : (this.pan > 0 ? 'R' : 'L') + panPercent;\n\n return html`\n <div class=\"header\">\n <span class=\"name\" title=${this.trackName}>${this.trackName || 'Untitled'}</span>\n <button class=\"remove-btn\" @click=${this._onRemoveClick} title=\"Remove track\">\n ×\n </button>\n </div>\n <div class=\"buttons\">\n <button\n class=\"btn ${this.muted ? 'muted-active' : ''}\"\n @click=${this._onMuteClick}\n title=\"Mute\"\n >\n M\n </button>\n <button class=\"btn ${this.soloed ? 'active' : ''}\" @click=${this._onSoloClick} title=\"Solo\">\n S\n </button>\n </div>\n <div class=\"slider-row\">\n <span class=\"slider-label\">\n <span class=\"slider-label-name\">Vol</span>\n <span class=\"slider-label-value\">${volPercent}%</span>\n </span>\n <input\n type=\"range\"\n min=\"0\"\n max=\"1\"\n step=\"0.01\"\n .value=${String(this.volume)}\n @input=${this._onVolumeInput}\n />\n </div>\n <div class=\"slider-row\">\n <span class=\"slider-label\">\n <span class=\"slider-label-name\">Pan</span>\n <span class=\"slider-label-value\">${panDisplay}</span>\n </span>\n <input\n type=\"range\"\n min=\"-1\"\n max=\"1\"\n step=\"0.01\"\n .value=${String(this.pan)}\n @input=${this._onPanInput}\n />\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-track-controls': DawTrackControlsElement;\n }\n}\n","import { css } from 'lit';\n\n/**\n * Default CSS custom properties for dawcore elements.\n * Consumers override these on <daw-editor> or any ancestor.\n * Values inherit through Shadow DOM boundaries automatically.\n */\nexport const hostStyles = css`\n :host {\n --daw-wave-color: #c49a6c;\n --daw-progress-color: #63c75f;\n --daw-playhead-color: #d08070;\n --daw-background: #1a1a2e;\n --daw-track-background: #16213e;\n --daw-ruler-color: #c49a6c;\n --daw-ruler-background: #0f0f1a;\n --daw-controls-background: #1a1a2e;\n --daw-controls-text: #e0d4c8;\n --daw-selection-color: rgba(99, 199, 95, 0.3);\n --daw-clip-header-background: rgba(0, 0, 0, 0.4);\n --daw-clip-header-text: #e0d4c8;\n }\n`;\n","import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport { getVisibleChunkIndices } from '../utils/viewport';\n\nexport { getVisibleChunkIndices };\n\nconst OVERSCAN_MULTIPLIER = 1.5;\nconst SCROLL_THRESHOLD = 100;\n\nexport class ViewportController implements ReactiveController {\n private _host: ReactiveControllerHost & HTMLElement;\n private _scrollContainer: HTMLElement | null = null;\n private _lastScrollLeft = 0;\n\n // Permissive defaults: render everything until scroll container is attached\n visibleStart = -Infinity;\n visibleEnd = Infinity;\n containerWidth = 0;\n\n constructor(host: ReactiveControllerHost & HTMLElement) {\n this._host = host;\n host.addController(this);\n }\n\n /** CSS selector for the scroll container inside the host's Shadow DOM. */\n scrollSelector = '';\n\n hostConnected() {\n // Defer to allow Shadow DOM to render before querying\n requestAnimationFrame(() => {\n if (!this._host.isConnected) return;\n const container = this.scrollSelector\n ? (this._host.shadowRoot?.querySelector(this.scrollSelector) as HTMLElement)\n : this._host;\n if (container) {\n this._attachScrollContainer(container);\n } else if (this.scrollSelector) {\n console.warn(\n '[dawcore] ViewportController: scroll container not found for \"' +\n this.scrollSelector +\n '\"'\n );\n }\n });\n }\n\n hostDisconnected() {\n this._scrollContainer?.removeEventListener('scroll', this._onScroll);\n this._scrollContainer = null;\n }\n\n private _attachScrollContainer(container: HTMLElement) {\n this._scrollContainer?.removeEventListener('scroll', this._onScroll);\n this._scrollContainer = container;\n container.addEventListener('scroll', this._onScroll, { passive: true });\n this._update(container.scrollLeft, container.clientWidth);\n this._host.requestUpdate();\n }\n\n private _onScroll = () => {\n if (!this._scrollContainer) return;\n const { scrollLeft, clientWidth } = this._scrollContainer;\n if (Math.abs(scrollLeft - this._lastScrollLeft) >= SCROLL_THRESHOLD) {\n this._update(scrollLeft, clientWidth);\n this._host.requestUpdate();\n }\n };\n\n private _update(scrollLeft: number, containerWidth: number) {\n this._lastScrollLeft = scrollLeft;\n this.containerWidth = containerWidth;\n const buffer = containerWidth * OVERSCAN_MULTIPLIER;\n this.visibleStart = scrollLeft - buffer;\n this.visibleEnd = scrollLeft + containerWidth + buffer;\n }\n}\n","import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport { resumeGlobalAudioContext } from '@waveform-playlist/playout';\n\nexport class AudioResumeController implements ReactiveController {\n private _host: ReactiveControllerHost & HTMLElement;\n private _target: EventTarget | null = null;\n private _attached = false;\n private _generation = 0;\n\n /** CSS selector, or 'document'. When undefined, controller is inert. */\n target?: string;\n\n constructor(host: ReactiveControllerHost & HTMLElement) {\n this._host = host;\n host.addController(this);\n }\n\n hostConnected() {\n // Defer to next frame so Lit's willUpdate() can set `target` from\n // the host's attribute before we read it. Same pattern as ViewportController.\n const gen = ++this._generation;\n requestAnimationFrame(() => {\n if (gen !== this._generation) return; // stale callback from previous connect\n if (!this._host.isConnected || this._attached || this.target === undefined) return;\n\n let resolvedTarget: EventTarget | null;\n try {\n resolvedTarget = this._resolveTarget();\n } catch (err) {\n console.warn(\n '[dawcore] AudioResumeController: failed to resolve target \"' +\n this.target +\n '\": ' +\n String(err)\n );\n return;\n }\n if (!resolvedTarget) return;\n\n this._target = resolvedTarget;\n this._attached = true;\n resolvedTarget.addEventListener('pointerdown', this._onGesture, {\n once: true,\n capture: true,\n });\n resolvedTarget.addEventListener('keydown', this._onGesture, {\n once: true,\n capture: true,\n });\n });\n }\n\n hostDisconnected() {\n this._removeListeners();\n this._attached = false;\n }\n\n private _onGesture = (e: Event) => {\n resumeGlobalAudioContext().catch((err) => {\n console.warn(\n '[dawcore] AudioResumeController: eager resume failed, will retry on play: ' + String(err)\n );\n });\n // Remove the other listener (the fired one was auto-removed by { once: true })\n const otherType = e.type === 'pointerdown' ? 'keydown' : 'pointerdown';\n this._target?.removeEventListener(otherType, this._onGesture, {\n capture: true,\n });\n this._target = null;\n };\n\n private _resolveTarget(): EventTarget | null {\n const t = this.target;\n if (t === undefined) return null;\n if (t === '') return this._host;\n if (t === 'document') return document;\n\n const el = document.querySelector(t);\n if (!el) {\n console.warn(\n '[dawcore] AudioResumeController: target \"' +\n t +\n '\" not found in DOM at attach time, falling back to host element. ' +\n 'Ensure the target exists before <daw-editor> connects.'\n );\n return this._host;\n }\n return el;\n }\n\n private _removeListeners() {\n if (!this._target) return;\n this._target.removeEventListener('pointerdown', this._onGesture, {\n capture: true,\n });\n this._target.removeEventListener('keydown', this._onGesture, {\n capture: true,\n });\n this._target = null;\n }\n}\n","import type { ReactiveController, ReactiveControllerHost } from 'lit';\nimport type { Bits } from '@waveform-playlist/core';\nimport { getGlobalContext } from '@waveform-playlist/playout';\nimport { recordingProcessorUrl } from '@waveform-playlist/worklets';\nimport { appendPeaks, concatenateAudioData, createAudioBuffer } from '@waveform-playlist/recording';\nimport type {\n DawRecordingStartDetail,\n DawRecordingCompleteDetail,\n DawRecordingErrorDetail,\n} from '../events';\n\nexport interface RecordingOptions {\n trackId?: string;\n bits?: 8 | 16;\n startSample?: number;\n}\n\nexport interface RecordingSession {\n readonly trackId: string;\n readonly stream: MediaStream;\n readonly source: { disconnect(): void; connect(dest: unknown): void };\n readonly workletNode: { port: MessagePort; disconnect(): void };\n readonly chunks: Float32Array[][];\n totalSamples: number;\n readonly peaks: (Int8Array | Int16Array)[];\n readonly startSample: number;\n readonly channelCount: number;\n readonly bits: Bits;\n isFirstMessage: boolean;\n /** Stored so it can be removed on stop/cleanup — not just when stream ends. */\n readonly _onTrackEnded: (() => void) | null;\n readonly _audioTrack: MediaStreamTrack | null;\n}\n\n/** Readonly view of a recording session for external consumers. */\nexport type ReadonlyRecordingSession = Readonly<\n Omit<RecordingSession, 'chunks' | 'peaks' | '_onTrackEnded' | '_audioTrack'>\n> & {\n readonly chunks: ReadonlyArray<ReadonlyArray<Float32Array>>;\n readonly peaks: ReadonlyArray<Int8Array | Int16Array>;\n};\n\n/** Narrow interface for the host editor. */\nexport interface RecordingHost extends ReactiveControllerHost {\n readonly samplesPerPixel: number;\n readonly effectiveSampleRate: number;\n readonly _selectedTrackId: string | null;\n readonly _currentTime: number;\n readonly shadowRoot: ShadowRoot | null;\n resolveAudioContextSampleRate(rate: number): void;\n _addRecordedClip?(\n trackId: string,\n buf: AudioBuffer,\n startSample: number,\n durSamples: number\n ): void;\n dispatchEvent(event: Event): boolean;\n}\n\nexport class RecordingController implements ReactiveController {\n private _host: RecordingHost & HTMLElement;\n private _sessions = new Map<string, RecordingSession>();\n private _workletLoaded = false;\n\n constructor(host: RecordingHost & HTMLElement) {\n this._host = host;\n host.addController(this);\n }\n\n hostConnected() {}\n\n hostDisconnected() {\n for (const trackId of [...this._sessions.keys()]) {\n this._cleanupSession(trackId);\n }\n }\n\n get isRecording(): boolean {\n return this._sessions.size > 0;\n }\n\n getSession(trackId: string): ReadonlyRecordingSession | undefined {\n return this._sessions.get(trackId);\n }\n\n async startRecording(stream: MediaStream, options: RecordingOptions = {}): Promise<void> {\n const trackId = options.trackId ?? this._host._selectedTrackId;\n if (!trackId) {\n console.warn('[dawcore] RecordingController: No track selected for recording');\n return;\n }\n if (this._sessions.has(trackId)) {\n console.warn('[dawcore] RecordingController: Already recording on track \"' + trackId + '\"');\n return;\n }\n\n const bits: Bits = options.bits ?? 16;\n const context = getGlobalContext();\n const rawCtx = context.rawContext as AudioContext;\n\n // Resolve editor sample rate from AudioContext before computing startSample\n this._host.resolveAudioContextSampleRate(rawCtx.sampleRate);\n\n try {\n // Load worklet via native API (not Tone.js addAudioWorkletModule — caches single URL)\n if (!this._workletLoaded) {\n await rawCtx.audioWorklet.addModule(recordingProcessorUrl);\n this._workletLoaded = true;\n }\n\n // Detect channel count from stream (not source.channelCount — defaults to 2)\n const channelCount = stream.getAudioTracks()[0]?.getSettings()?.channelCount ?? 1;\n\n const startSample =\n options.startSample ?? Math.floor(this._host._currentTime * this._host.effectiveSampleRate);\n\n // Use Tone.js Context methods — avoids standardized-audio-context identity issues\n const source = context.createMediaStreamSource(stream);\n const workletNode = context.createAudioWorkletNode('recording-processor', {\n channelCount,\n channelCountMode: 'explicit' as globalThis.ChannelCountMode,\n });\n\n // Listen on MediaStreamTrack (not MediaStream — MediaStream has no 'ended' event)\n const audioTrack = stream.getAudioTracks()[0] ?? null;\n const onTrackEnded = audioTrack\n ? () => {\n if (this._sessions.has(trackId)) {\n this.stopRecording(trackId);\n }\n }\n : null;\n\n const session: RecordingSession = {\n trackId,\n stream,\n source,\n workletNode,\n chunks: Array.from({ length: channelCount }, () => []),\n totalSamples: 0,\n peaks: Array.from({ length: channelCount }, () =>\n bits === 8 ? new Int8Array(0) : new Int16Array(0)\n ),\n startSample,\n channelCount,\n bits,\n isFirstMessage: true,\n _onTrackEnded: onTrackEnded,\n _audioTrack: audioTrack,\n };\n this._sessions.set(trackId, session);\n\n // dawcore CLAUDE.md: wire onmessage BEFORE source.connect() and postMessage start\n workletNode.port.onmessage = (e: MessageEvent) => {\n this._onWorkletMessage(trackId, e.data);\n };\n source.connect(workletNode);\n workletNode.port.postMessage({ command: 'start', channelCount });\n\n // Attach mic-unplug listener (stored in session for cleanup)\n if (audioTrack && onTrackEnded) {\n audioTrack.addEventListener('ended', onTrackEnded);\n }\n\n this._host.dispatchEvent(\n new CustomEvent<DawRecordingStartDetail>('daw-recording-start', {\n bubbles: true,\n composed: true,\n detail: { trackId, stream },\n })\n );\n\n this._host.requestUpdate();\n } catch (err) {\n // Clean up partially-created session to prevent stuck isRecording state\n this._cleanupSession(trackId);\n console.warn('[dawcore] RecordingController: Failed to start recording: ' + String(err));\n this._host.dispatchEvent(\n new CustomEvent<DawRecordingErrorDetail>('daw-recording-error', {\n bubbles: true,\n composed: true,\n detail: { trackId, error: err },\n })\n );\n }\n }\n\n stopRecording(trackId?: string): void {\n const id = trackId ?? [...this._sessions.keys()][0];\n if (!id) return;\n\n const session = this._sessions.get(id);\n if (!session) return;\n\n // Send stop BEFORE disconnect so worklet can flush remaining buffered samples\n session.workletNode.port.postMessage({ command: 'stop' });\n session.source.disconnect();\n session.workletNode.disconnect();\n\n // Remove mic-unplug listener (fix #4: prevent leak on normal stop path)\n this._removeTrackEndedListener(session);\n\n // Build AudioBuffer from accumulated chunks\n if (session.totalSamples === 0) {\n console.warn('[dawcore] RecordingController: No audio data captured');\n this._sessions.delete(id);\n this._host.requestUpdate();\n // Dispatch error so record button can reset its state (fix #3)\n this._host.dispatchEvent(\n new CustomEvent<DawRecordingErrorDetail>('daw-recording-error', {\n bubbles: true,\n composed: true,\n detail: { trackId: id, error: new Error('No audio data captured') },\n })\n );\n return;\n }\n const stopCtx = getGlobalContext().rawContext as AudioContext;\n const channelData = session.chunks.map((chunkArr) => concatenateAudioData(chunkArr));\n const audioBuffer = createAudioBuffer(\n stopCtx,\n channelData,\n this._host.effectiveSampleRate,\n session.channelCount\n );\n const durationSamples = audioBuffer.length;\n\n // Dispatch cancelable event\n const event = new CustomEvent<DawRecordingCompleteDetail>('daw-recording-complete', {\n bubbles: true,\n composed: true,\n cancelable: true,\n detail: {\n trackId: id,\n audioBuffer,\n startSample: session.startSample,\n durationSamples,\n },\n });\n const notPrevented = this._host.dispatchEvent(event);\n\n // Clean up session\n this._sessions.delete(id);\n this._host.requestUpdate();\n\n if (notPrevented) {\n this._createClipFromRecording(id, audioBuffer, session.startSample, durationSamples);\n }\n }\n\n // Session fields are mutated in place on the hot path (~60fps worklet messages).\n // This is intentional — creating new session objects + Map entries per message\n // would cause significant GC pressure. Mutations are confined to the controller's\n // private map and do not affect Lit's reactive rendering.\n private _onWorkletMessage(trackId: string, data: unknown) {\n const session = this._sessions.get(trackId);\n if (!session) return;\n\n const { channels } = data as { channels: Float32Array[] };\n if (!channels || channels.length === 0 || !channels[0]) return;\n\n // Capture pre-increment value for appendPeaks\n const samplesProcessedBefore = session.totalSamples;\n\n // Accumulate chunks per channel\n for (let ch = 0; ch < session.channelCount; ch++) {\n if (channels[ch]) {\n session.chunks[ch].push(channels[ch]);\n }\n }\n session.totalSamples += channels[0].length;\n\n // Generate peaks per channel and update live preview waveforms\n for (let ch = 0; ch < session.channelCount; ch++) {\n if (!channels[ch]) continue;\n const oldPeakCount = Math.floor(session.peaks[ch].length / 2);\n (session.peaks as (Int8Array | Int16Array)[])[ch] = appendPeaks(\n session.peaks[ch],\n channels[ch],\n this._host.samplesPerPixel,\n samplesProcessedBefore,\n session.bits\n );\n const newPeakCount = Math.floor(session.peaks[ch].length / 2);\n\n // Update live preview waveform — host is already & HTMLElement so shadowRoot is typed\n const waveformSelector = `daw-waveform[data-recording-track=\"${trackId}\"][data-recording-channel=\"${ch}\"]`;\n const waveformEl = this._host.shadowRoot?.querySelector(waveformSelector) as any;\n if (waveformEl) {\n if (session.isFirstMessage) {\n waveformEl.peaks = session.peaks[ch];\n } else {\n waveformEl.setPeaksQuiet(session.peaks[ch]);\n waveformEl.updatePeaks(Math.max(0, oldPeakCount - 1), newPeakCount);\n }\n }\n }\n\n session.isFirstMessage = false;\n\n // Throttle requestUpdate — only when container width needs to grow\n const newPixelWidth = Math.floor(session.totalSamples / this._host.samplesPerPixel);\n const oldPixelWidth = Math.floor(\n (session.totalSamples - channels[0].length) / this._host.samplesPerPixel\n );\n if (newPixelWidth > oldPixelWidth) {\n this._host.requestUpdate();\n }\n }\n\n private _createClipFromRecording(\n trackId: string,\n audioBuffer: AudioBuffer,\n startSample: number,\n durationSamples: number\n ) {\n if (typeof this._host._addRecordedClip === 'function') {\n this._host._addRecordedClip(trackId, audioBuffer, startSample, durationSamples);\n } else {\n console.warn(\n '[dawcore] RecordingController: host does not implement _addRecordedClip — clip not created for track \"' +\n trackId +\n '\"'\n );\n }\n }\n\n private _removeTrackEndedListener(session: RecordingSession) {\n if (session._audioTrack && session._onTrackEnded) {\n session._audioTrack.removeEventListener('ended', session._onTrackEnded);\n }\n }\n\n private _cleanupSession(trackId: string) {\n const session = this._sessions.get(trackId);\n if (!session) return;\n try {\n this._removeTrackEndedListener(session);\n session.workletNode.port.postMessage({ command: 'stop' });\n session.source.disconnect();\n session.workletNode.disconnect();\n } catch (err) {\n console.warn(\n '[dawcore] RecordingController: disconnect error during cleanup for track \"' +\n trackId +\n '\": ' +\n String(err)\n );\n }\n this._sessions.delete(trackId);\n }\n}\n","import { pixelsToSeconds } from '@waveform-playlist/core';\n\n/** Narrow engine contract for pointer interactions. */\nexport interface PointerEngineContract {\n setSelection(start: number, end: number): void;\n stop(): void;\n play(time: number): void;\n seek(time: number): void;\n selectTrack(trackId: string | null): void;\n}\n\n/** Manages pointer interactions on the timeline: click-to-seek and drag-to-select. */\nexport interface PointerHandlerHost {\n readonly samplesPerPixel: number;\n readonly _engine: PointerEngineContract | null;\n readonly _isPlaying: boolean;\n readonly effectiveSampleRate: number;\n _currentTime: number;\n _selectionStartTime: number;\n _selectionEndTime: number;\n _dragOver: boolean;\n _setSelectedTrackId(trackId: string | null): void;\n _startPlayhead(): void;\n _stopPlayhead(): void;\n dispatchEvent(event: Event): boolean;\n shadowRoot: ShadowRoot | null;\n requestUpdate(): void;\n}\n\nexport class PointerHandler {\n private _host: PointerHandlerHost;\n private _isDragging = false;\n private _dragStartPx = 0;\n private _timeline: HTMLElement | null = null;\n // Cached from onPointerDown to avoid forced layout reflows at 60fps during drag\n private _timelineRect: DOMRect | null = null;\n\n constructor(host: PointerHandlerHost) {\n this._host = host;\n }\n\n private _pxFromPointer(e: PointerEvent): number {\n if (!this._timelineRect) {\n console.warn('[dawcore] _pxFromPointer called without timeline reference');\n return 0;\n }\n // .timeline is wider than :host (which has overflow-x: auto).\n // getBoundingClientRect().left already reflects scroll position\n // (goes negative when scrolled), so no scrollLeft adjustment needed.\n return e.clientX - this._timelineRect.left;\n }\n\n onPointerDown = (e: PointerEvent) => {\n this._timeline = this._host.shadowRoot?.querySelector('.timeline') as HTMLElement | null;\n if (!this._timeline) return;\n\n this._timelineRect = this._timeline.getBoundingClientRect();\n this._dragStartPx = this._pxFromPointer(e);\n this._isDragging = false;\n\n this._timeline.setPointerCapture(e.pointerId);\n this._timeline.addEventListener('pointermove', this._onPointerMove);\n this._timeline.addEventListener('pointerup', this._onPointerUp);\n };\n\n private _onPointerMove = (e: PointerEvent) => {\n if (!this._timeline) return;\n\n const currentPx = this._pxFromPointer(e);\n\n if (!this._isDragging && Math.abs(currentPx - this._dragStartPx) > 3) {\n this._isDragging = true;\n }\n\n if (this._isDragging) {\n const h = this._host;\n const startTime = pixelsToSeconds(\n this._dragStartPx,\n h.samplesPerPixel,\n h.effectiveSampleRate\n );\n const endTime = pixelsToSeconds(currentPx, h.samplesPerPixel, h.effectiveSampleRate);\n // Mutate host fields directly (not @state) and update <daw-selection>\n // imperatively to avoid triggering Lit re-renders at 60fps during drag\n h._selectionStartTime = Math.min(startTime, endTime);\n h._selectionEndTime = Math.max(startTime, endTime);\n const sel = h.shadowRoot?.querySelector('daw-selection') as\n | { startPx: number; endPx: number }\n | undefined;\n if (sel) {\n sel.startPx = (h._selectionStartTime * h.effectiveSampleRate) / h.samplesPerPixel;\n sel.endPx = (h._selectionEndTime * h.effectiveSampleRate) / h.samplesPerPixel;\n }\n }\n };\n\n private _onPointerUp = (e: PointerEvent) => {\n if (!this._timeline) return;\n\n try {\n this._timeline.releasePointerCapture(e.pointerId);\n } catch (err) {\n console.warn(\n '[dawcore] releasePointerCapture failed (may already be released): ' + String(err)\n );\n }\n this._timeline.removeEventListener('pointermove', this._onPointerMove);\n this._timeline.removeEventListener('pointerup', this._onPointerUp);\n\n try {\n if (this._isDragging) {\n this._finalizeSelection();\n } else {\n this._handleSeekClick(e);\n }\n } catch (err) {\n console.warn('[dawcore] Pointer interaction failed: ' + String(err));\n } finally {\n this._isDragging = false;\n this._timeline = null;\n this._timelineRect = null;\n }\n };\n\n private _finalizeSelection() {\n const h = this._host;\n if (h._engine) {\n h._engine.setSelection(h._selectionStartTime, h._selectionEndTime);\n }\n h.dispatchEvent(\n new CustomEvent('daw-selection', {\n bubbles: true,\n composed: true,\n detail: { start: h._selectionStartTime, end: h._selectionEndTime },\n })\n );\n h.requestUpdate();\n }\n\n private _handleSeekClick(e: PointerEvent) {\n const h = this._host;\n const px = this._pxFromPointer(e);\n const time = pixelsToSeconds(px, h.samplesPerPixel, h.effectiveSampleRate);\n\n // Clear selection\n h._selectionStartTime = 0;\n h._selectionEndTime = 0;\n\n // Detect which track was clicked by Y position\n if (this._timeline) {\n const trackRows = this._timeline.querySelectorAll('.track-row');\n for (const row of trackRows) {\n const rowRect = row.getBoundingClientRect();\n if (e.clientY >= rowRect.top && e.clientY < rowRect.bottom) {\n const trackId = (row as HTMLElement).dataset.trackId;\n if (trackId) {\n this._selectTrack(trackId);\n }\n break;\n }\n }\n }\n\n // Capture playing state before engine calls (stop emits statechange\n // which synchronously flips _isPlaying — use wasPlaying for all guards)\n const wasPlaying = h._isPlaying;\n\n if (h._engine) {\n h._engine.setSelection(0, 0);\n if (wasPlaying) {\n // Tone.js needs stop + play to reschedule audio sources\n h._engine.stop();\n h._engine.play(time);\n h._startPlayhead();\n } else {\n h._engine.seek(time);\n }\n }\n\n h._currentTime = time;\n if (!wasPlaying) {\n h._stopPlayhead();\n }\n\n h.dispatchEvent(\n new CustomEvent('daw-seek', {\n bubbles: true,\n composed: true,\n detail: { time },\n })\n );\n h.requestUpdate();\n }\n\n private _selectTrack(trackId: string) {\n const h = this._host;\n if (h._engine) {\n try {\n h._engine.selectTrack(trackId);\n // Engine sets _selectedTrackId via statechange — don't set locally\n } catch (err) {\n console.warn(\n '[dawcore] selectTrack via engine failed, falling back to local: ' + String(err)\n );\n // Fall through to local selection below\n h._setSelectedTrackId(trackId);\n }\n } else {\n // No engine — set locally (will be lost when engine builds, acceptable for Phase 2)\n h._setSelectedTrackId(trackId);\n }\n h.dispatchEvent(\n new CustomEvent('daw-track-select', {\n bubbles: true,\n composed: true,\n detail: { trackId },\n })\n );\n }\n}\n","/**\n * File loading logic extracted from daw-editor to keep the editor under 800 lines.\n * Operates on the editor instance via a narrow interface.\n */\n\nimport type { ClipTrack, PeakData } from '@waveform-playlist/core';\nimport { createClipFromSeconds, createTrack } from '@waveform-playlist/core';\nimport type { PeakPipeline } from '../workers/peakPipeline';\nimport type { DawTrackIdDetail, DawFilesLoadErrorDetail, LoadFilesResult } from '../events';\nimport type { TrackDescriptor } from '../types';\n\nexport interface FileLoaderHost {\n readonly samplesPerPixel: number;\n readonly mono: boolean;\n readonly isConnected: boolean;\n _resolvedSampleRate: number | null;\n _tracks: Map<string, TrackDescriptor>;\n _engineTracks: Map<string, ClipTrack>;\n _peaksData: Map<string, PeakData>;\n _clipBuffers: Map<string, AudioBuffer>;\n _audioCache: Map<string, Promise<AudioBuffer>>;\n _peakPipeline: PeakPipeline;\n _fetchAndDecode(src: string): Promise<AudioBuffer>;\n _recomputeDuration(): void;\n _ensureEngine(): Promise<{ setTracks(tracks: ClipTrack[]): void }>;\n dispatchEvent(event: Event): boolean;\n}\n\nexport async function loadFiles(\n host: FileLoaderHost,\n files: FileList | File[]\n): Promise<LoadFilesResult> {\n if (!files) {\n console.warn('[dawcore] loadFiles called with null/undefined');\n return { loaded: [], failed: [] };\n }\n\n const fileArray = Array.from(files);\n const loaded: string[] = [];\n const failed: Array<{ file: File; error: unknown }> = [];\n\n for (const file of fileArray) {\n if (file.type && !file.type.startsWith('audio/')) {\n failed.push({ file, error: new Error('Non-audio MIME type: ' + file.type) });\n console.warn('[dawcore] Skipping non-audio file: ' + file.name + ' (' + file.type + ')');\n continue;\n }\n\n const blobUrl = URL.createObjectURL(file);\n try {\n const audioBuffer = await host._fetchAndDecode(blobUrl);\n URL.revokeObjectURL(blobUrl);\n host._audioCache.delete(blobUrl);\n\n host._resolvedSampleRate = audioBuffer.sampleRate;\n\n const name = file.name.replace(/\\.\\w+$/, '');\n const clip = createClipFromSeconds({\n audioBuffer,\n startTime: 0,\n duration: audioBuffer.duration,\n offset: 0,\n gain: 1,\n name,\n sampleRate: audioBuffer.sampleRate,\n sourceDuration: audioBuffer.duration,\n });\n\n host._clipBuffers = new Map(host._clipBuffers).set(clip.id, audioBuffer);\n const peakData = await host._peakPipeline.generatePeaks(\n audioBuffer,\n host.samplesPerPixel,\n host.mono\n );\n host._peaksData = new Map(host._peaksData).set(clip.id, peakData);\n\n const trackId = crypto.randomUUID();\n const track = createTrack({ name, clips: [clip] });\n track.id = trackId;\n\n host._tracks = new Map(host._tracks).set(trackId, {\n name,\n src: '',\n volume: 1,\n pan: 0,\n muted: false,\n soloed: false,\n clips: [\n {\n src: '',\n start: 0,\n duration: audioBuffer.duration,\n offset: 0,\n gain: 1,\n name,\n fadeIn: 0,\n fadeOut: 0,\n fadeType: 'linear',\n },\n ],\n });\n host._engineTracks = new Map(host._engineTracks).set(trackId, track);\n host._recomputeDuration();\n\n const engine = await host._ensureEngine();\n engine.setTracks([...host._engineTracks.values()]);\n\n loaded.push(trackId);\n host.dispatchEvent(\n new CustomEvent<DawTrackIdDetail>('daw-track-ready', {\n bubbles: true,\n composed: true,\n detail: { trackId },\n })\n );\n } catch (err) {\n URL.revokeObjectURL(blobUrl);\n console.warn('[dawcore] Failed to load file: ' + file.name + ' — ' + String(err));\n failed.push({ file, error: err });\n if (host.isConnected) {\n host.dispatchEvent(\n new CustomEvent<DawFilesLoadErrorDetail>('daw-files-load-error', {\n bubbles: true,\n composed: true,\n detail: { file, error: err },\n })\n );\n }\n }\n }\n\n return { loaded, failed };\n}\n","/**\n * Recording clip creation extracted from daw-editor to keep the editor under 800 lines.\n * Operates on the editor instance via a narrow interface.\n */\n\nimport type { ClipTrack, PeakData } from '@waveform-playlist/core';\nimport { createClip } from '@waveform-playlist/core';\nimport type { PeakPipeline } from '../workers/peakPipeline';\nimport type { DawErrorDetail } from '../events';\nimport type { TrackDescriptor, ClipDescriptor } from '../types';\n\nexport interface RecordingClipHost {\n readonly samplesPerPixel: number;\n readonly mono: boolean;\n readonly isConnected: boolean;\n readonly effectiveSampleRate: number;\n _tracks: Map<string, TrackDescriptor>;\n _engineTracks: Map<string, ClipTrack>;\n _peaksData: Map<string, PeakData>;\n _clipBuffers: Map<string, AudioBuffer>;\n _peakPipeline: PeakPipeline;\n _engine: { setTracks(tracks: ClipTrack[]): void } | null;\n _recomputeDuration(): void;\n dispatchEvent(event: Event): boolean;\n}\n\nexport function addRecordedClip(\n host: RecordingClipHost,\n trackId: string,\n buf: AudioBuffer,\n startSample: number,\n durSamples: number\n) {\n const clip = createClip({\n audioBuffer: buf,\n startSample,\n durationSamples: durSamples,\n offsetSamples: 0,\n gain: 1,\n name: 'Recording',\n });\n host._clipBuffers = new Map(host._clipBuffers).set(clip.id, buf);\n host._peakPipeline\n .generatePeaks(buf, host.samplesPerPixel, host.mono)\n .then((pd) => {\n host._peaksData = new Map(host._peaksData).set(clip.id, pd);\n const t = host._engineTracks.get(trackId);\n if (!t) {\n // Track was removed during peak generation — clean up orphaned buffer\n const next = new Map(host._clipBuffers);\n next.delete(clip.id);\n host._clipBuffers = next;\n return;\n }\n host._engineTracks = new Map(host._engineTracks).set(trackId, {\n ...t,\n clips: [...t.clips, clip],\n });\n // Keep _tracks in sync so public API and track controls reflect the clip\n const desc = host._tracks.get(trackId);\n if (desc) {\n const sr = host.effectiveSampleRate;\n const clipDesc: ClipDescriptor = {\n src: '',\n start: startSample / sr,\n duration: durSamples / sr,\n offset: 0,\n gain: 1,\n name: 'Recording',\n fadeIn: 0,\n fadeOut: 0,\n fadeType: 'linear',\n };\n host._tracks = new Map(host._tracks).set(trackId, {\n ...desc,\n clips: [...desc.clips, clipDesc],\n });\n }\n host._recomputeDuration();\n host._engine?.setTracks([...host._engineTracks.values()]);\n })\n .catch((err) => {\n console.warn('[dawcore] Failed to generate peaks for recorded clip: ' + String(err));\n const next = new Map(host._clipBuffers);\n next.delete(clip.id);\n host._clipBuffers = next;\n if (host.isConnected) {\n host.dispatchEvent(\n new CustomEvent<DawErrorDetail>('daw-error', {\n bubbles: true,\n composed: true,\n detail: { operation: 'recording-peaks', error: err },\n })\n );\n }\n });\n}\n","import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { computeTemporalTicks, type TickData } from '../utils/smart-scale';\n\nconst MAX_CANVAS_WIDTH = 1000;\n\n@customElement('daw-ruler')\nexport class DawRulerElement extends LitElement {\n @property({ type: Number, attribute: false }) samplesPerPixel = 1024;\n @property({ type: Number, attribute: false }) sampleRate = 48000;\n @property({ type: Number, attribute: false }) duration = 0;\n @property({ type: Number, attribute: false }) rulerHeight = 30;\n\n private _tickData: TickData | null = null;\n\n static styles = css`\n :host {\n display: block;\n position: relative;\n background: var(--daw-ruler-background, #0f0f1a);\n }\n .container {\n position: relative;\n }\n canvas {\n position: absolute;\n top: 0;\n }\n .label {\n position: absolute;\n font-size: 0.7rem;\n white-space: nowrap;\n color: var(--daw-ruler-color, #c49a6c);\n top: 2px;\n }\n `;\n\n willUpdate() {\n // Compute ticks once per update — used by both render() and updated()\n if (this.duration > 0) {\n this._tickData = computeTemporalTicks(\n this.samplesPerPixel,\n this.sampleRate,\n this.duration,\n this.rulerHeight\n );\n } else {\n this._tickData = null;\n }\n }\n\n render() {\n if (!this._tickData) return html``;\n\n const { widthX, labels } = this._tickData;\n const totalChunks = Math.ceil(widthX / MAX_CANVAS_WIDTH);\n const indices = Array.from({ length: totalChunks }, (_, i) => i);\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n\n return html`\n <div class=\"container\" style=\"width: ${widthX}px; height: ${this.rulerHeight}px;\">\n ${indices.map((i) => {\n const width = Math.min(MAX_CANVAS_WIDTH, widthX - i * MAX_CANVAS_WIDTH);\n return html`\n <canvas\n data-index=${i}\n width=${width * dpr}\n height=${this.rulerHeight * dpr}\n style=\"left: ${i * MAX_CANVAS_WIDTH}px; width: ${width}px; height: ${this\n .rulerHeight}px;\"\n ></canvas>\n `;\n })}\n ${labels.map(\n ({ pix, text }) => html`<span class=\"label\" style=\"left: ${pix + 4}px;\">${text}</span>`\n )}\n </div>\n `;\n }\n\n updated() {\n this._drawTicks();\n }\n\n private _drawTicks() {\n if (!this._tickData) return;\n\n const canvases = this.shadowRoot?.querySelectorAll('canvas');\n if (!canvases) return;\n\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n const rulerColor =\n getComputedStyle(this).getPropertyValue('--daw-ruler-color').trim() || '#c49a6c';\n\n for (const canvas of canvases) {\n const idx = Number(canvas.dataset.index);\n const ctx = canvas.getContext('2d');\n if (!ctx) continue;\n\n const canvasWidth = Math.min(\n MAX_CANVAS_WIDTH,\n this._tickData.widthX - idx * MAX_CANVAS_WIDTH\n );\n const globalOffset = idx * MAX_CANVAS_WIDTH;\n\n ctx.resetTransform();\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.scale(dpr, dpr);\n ctx.strokeStyle = rulerColor;\n ctx.lineWidth = 1;\n\n for (const [pix, height] of this._tickData.canvasInfo) {\n const localX = pix - globalOffset;\n if (localX < 0 || localX >= canvasWidth) continue;\n\n ctx.beginPath();\n ctx.moveTo(localX + 0.5, this.rulerHeight);\n ctx.lineTo(localX + 0.5, this.rulerHeight - height);\n ctx.stroke();\n }\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-ruler': DawRulerElement;\n }\n}\n","/**\n * Format milliseconds into a m:ss display string.\n */\nexport function formatTime(milliseconds: number): string {\n const seconds = Math.floor(milliseconds / 1000);\n const s = seconds % 60;\n const m = (seconds - s) / 60;\n\n return `${m}:${String(s).padStart(2, '0')}`;\n}\n","import { formatTime } from './time-format';\n\nconst timeinfo = new Map([\n [700, { marker: 1000, bigStep: 500, smallStep: 100 }],\n [1500, { marker: 2000, bigStep: 1000, smallStep: 200 }],\n [2500, { marker: 2000, bigStep: 1000, smallStep: 500 }],\n [5000, { marker: 5000, bigStep: 1000, smallStep: 500 }],\n [10000, { marker: 10000, bigStep: 5000, smallStep: 1000 }],\n [12000, { marker: 15000, bigStep: 5000, smallStep: 1000 }],\n [Infinity, { marker: 30000, bigStep: 10000, smallStep: 5000 }],\n]);\n\nexport function getScaleInfo(samplesPerPixel: number) {\n for (const [resolution, config] of timeinfo) {\n if (samplesPerPixel < resolution) {\n return config;\n }\n }\n return { marker: 30000, bigStep: 10000, smallStep: 5000 };\n}\n\nexport interface TickData {\n /** Map of pixel position → tick height */\n canvasInfo: Map<number, number>;\n /** Labeled ticks with pixel positions */\n labels: Array<{ pix: number; text: string }>;\n /** Total width in pixels */\n widthX: number;\n}\n\n/**\n * Compute temporal tick data for a ruler.\n *\n * Pure function — no DOM dependencies.\n */\nexport function computeTemporalTicks(\n samplesPerPixel: number,\n sampleRate: number,\n duration: number,\n rulerHeight: number\n): TickData {\n const widthX = Math.ceil((duration * sampleRate) / samplesPerPixel);\n const config = getScaleInfo(samplesPerPixel);\n const { marker, bigStep, smallStep } = config;\n const canvasInfo = new Map<number, number>();\n const labels: Array<{ pix: number; text: string }> = [];\n const pixPerSec = sampleRate / samplesPerPixel;\n\n // Iterate with integer counter (milliseconds) to avoid float precision drift.\n // Compute pixel position from counter each iteration instead of accumulating.\n for (let counter = 0; ; counter += smallStep) {\n const pix = Math.floor((counter / 1000) * pixPerSec);\n if (pix >= widthX) break;\n\n if (counter % marker === 0) {\n canvasInfo.set(pix, rulerHeight);\n labels.push({ pix, text: formatTime(counter) });\n } else if (counter % bigStep === 0) {\n canvasInfo.set(pix, Math.floor(rulerHeight / 2));\n } else if (counter % smallStep === 0) {\n canvasInfo.set(pix, Math.floor(rulerHeight / 5));\n }\n }\n\n return { widthX, canvasInfo, labels };\n}\n","import { LitElement, html, css } from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\n\n@customElement('daw-selection')\nexport class DawSelectionElement extends LitElement {\n @property({ type: Number, attribute: false }) startPx = 0;\n @property({ type: Number, attribute: false }) endPx = 0;\n\n static styles = css`\n :host {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n pointer-events: none;\n z-index: 5;\n }\n div {\n position: absolute;\n top: 0;\n bottom: 0;\n background: var(--daw-selection-color, rgba(99, 199, 95, 0.3));\n }\n `;\n\n render() {\n const left = Math.min(this.startPx, this.endPx);\n const width = Math.abs(this.endPx - this.startPx);\n if (width === 0) return html``;\n return html`<div style=\"left: ${left}px; width: ${width}px;\"></div>`;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-selection': DawSelectionElement;\n }\n}\n","import { html, css } from 'lit';\nimport { customElement, state } from 'lit/decorators.js';\nimport { DawTransportButton } from './daw-transport-button';\n\n@customElement('daw-record-button')\nexport class DawRecordButtonElement extends DawTransportButton {\n @state() private _isRecording = false;\n private _targetRef: HTMLElement | null = null;\n private _onStart = () => {\n this._isRecording = true;\n };\n private _onComplete = () => {\n this._isRecording = false;\n };\n private _onError = () => {\n this._isRecording = false;\n };\n\n static override styles = [\n DawTransportButton.styles,\n css`\n button[data-recording] {\n color: #d08070;\n border-color: #d08070;\n }\n `,\n ];\n\n connectedCallback() {\n super.connectedCallback();\n this._listenToTarget();\n }\n\n disconnectedCallback() {\n super.disconnectedCallback();\n this._cleanupListeners();\n }\n\n private _listenToTarget() {\n const target = this.target;\n if (!target) return;\n this._targetRef = target;\n target.addEventListener('daw-recording-start', this._onStart);\n target.addEventListener('daw-recording-complete', this._onComplete);\n target.addEventListener('daw-recording-error', this._onError);\n }\n\n private _cleanupListeners() {\n if (this._targetRef) {\n this._targetRef.removeEventListener('daw-recording-start', this._onStart);\n this._targetRef.removeEventListener('daw-recording-complete', this._onComplete);\n this._targetRef.removeEventListener('daw-recording-error', this._onError);\n this._targetRef = null;\n }\n }\n\n render() {\n return html`\n <button part=\"button\" ?data-recording=${this._isRecording} @click=${this._onClick}>\n <slot>${this._isRecording ? 'Stop Rec' : 'Record'}</slot>\n </button>\n `;\n }\n\n private _onClick() {\n const target = this.target;\n if (!target) {\n console.warn(\n '[dawcore] <daw-record-button> has no target. Check <daw-transport for=\"...\"> references a valid <daw-editor> id.'\n );\n return;\n }\n if (this._isRecording) {\n target.stopRecording();\n } else {\n target.startRecording(target.recordingStream);\n }\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'daw-record-button': DawRecordButtonElement;\n }\n}\n"],"mappings":";;;;;;;;;;;;AAAA,SAAS,kBAAkB;AAC3B,SAAS,eAAe,gBAAgB;AAGjC,IAAM,iBAAN,cAA6B,WAAW;AAAA,EAAxC;AAAA;AACO,eAAM;AACoB,oBAAW;AACrB,iBAAQ;AACR,oBAAW;AACX,kBAAS;AACT,gBAAO;AACvB,gBAAO;AACP,iBAAQ;AAC8B,kBAAS;AACR,mBAAU;AACvB,oBAAW;AAEjD,SAAS,SAAS,OAAO,WAAW;AAAA;AAAA;AAAA,EAGpC,mBAAmB;AACjB,WAAO;AAAA,EACT;AACF;AAlBc;AAAA,EAAX,SAAS;AAAA,GADC,eACC;AAC0B;AAAA,EAArC,SAAS,EAAE,WAAW,YAAY,CAAC;AAAA,GAFzB,eAE2B;AACV;AAAA,EAA3B,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GAHf,eAGiB;AACA;AAAA,EAA3B,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GAJf,eAIiB;AACA;AAAA,EAA3B,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GALf,eAKiB;AACA;AAAA,EAA3B,SAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GANf,eAMiB;AAChB;AAAA,EAAX,SAAS;AAAA,GAPC,eAOC;AACA;AAAA,EAAX,SAAS;AAAA,GARC,eAQC;AACsC;AAAA,EAAjD,SAAS,EAAE,MAAM,QAAQ,WAAW,UAAU,CAAC;AAAA,GATrC,eASuC;AACC;AAAA,EAAlD,SAAS,EAAE,MAAM,QAAQ,WAAW,WAAW,CAAC;AAAA,GAVtC,eAUwC;AACb;AAAA,EAArC,SAAS,EAAE,WAAW,YAAY,CAAC;AAAA,GAXzB,eAW2B;AAX3B,iBAAN;AAAA,EADN,cAAc,UAAU;AAAA,GACZ;;;ACJb,SAAS,cAAAA,mBAAkB;AAC3B,SAAS,iBAAAC,gBAAe,YAAAC,iBAAgB;AAIjC,IAAM,kBAAN,cAA8BC,YAAW;AAAA,EAAzC;AAAA;AACO,eAAM;AACN,gBAAO;AACS,kBAAS;AACT,eAAM;AACL,iBAAQ;AACR,kBAAS;AAEtC,SAAS,UAAU,OAAO,WAAW;AA2BrC;AAAA;AAAA;AAAA,SAAQ,eAAe;AAAA;AAAA;AAAA,EAxBvB,mBAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EAEA,oBAAoB;AAClB,UAAM,kBAAkB;AAIxB,eAAW,MAAM;AACf,WAAK;AAAA,QACH,IAAI,YAAY,uBAAuB;AAAA,UACrC,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,KAAK,SAAS,SAAS,KAAK;AAAA,QACjD,CAAC;AAAA,MACH;AAAA,IACF,GAAG,CAAC;AAAA,EACN;AAAA,EAQA,QAAQ,SAAyB;AAG/B,QAAI,CAAC,KAAK,cAAc;AACtB,WAAK,eAAe;AACpB;AAAA,IACF;AAEA,UAAM,aAAa,CAAC,UAAU,OAAO,SAAS,UAAU,OAAO,MAAM;AACrE,UAAM,iBAAiB,WAAW,KAAK,CAAC,MAAM,QAAQ,IAAI,CAAe,CAAC;AAE1E,QAAI,gBAAgB;AAClB,WAAK;AAAA,QACH,IAAI,YAAY,oBAAoB;AAAA,UAClC,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,KAAK,QAAQ;AAAA,QAClC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAzDc;AAAA,EAAXC,UAAS;AAAA,GADC,gBACC;AACA;AAAA,EAAXA,UAAS;AAAA,GAFC,gBAEC;AACgB;AAAA,EAA3BA,UAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GAHf,gBAGiB;AACA;AAAA,EAA3BA,UAAS,EAAE,MAAM,OAAO,CAAC;AAAA,GAJf,gBAIiB;AACC;AAAA,EAA5BA,UAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,GALhB,gBAKkB;AACA;AAAA,EAA5BA,UAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,GANhB,gBAMkB;AANlB,kBAAN;AAAA,EADNC,eAAc,WAAW;AAAA,GACb;;;ACLb,SAAS,cAAAC,aAAY,MAAM,WAAW;AACtC,SAAS,iBAAAC,gBAAe,YAAAC,iBAAgB;;;ACwCjC,SAAS,eACd,MACA,MACA,YACA,UACuB;AACvB,MAAI,aAAa,IAAI,KAAK,KAAK,QAAQ;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,WAAW,MAAM,OAAO;AAC9B,MAAI,UAAU,KAAK,aAAa,CAAC,IAAI;AACrC,MAAI,UAAU,KAAK,aAAa,IAAI,CAAC,IAAI;AAEzC,WAAS,IAAI,aAAa,GAAG,IAAI,UAAU,KAAK;AAC9C,QAAI,IAAI,IAAI,KAAK,KAAK,OAAQ;AAC9B,UAAM,OAAO,KAAK,IAAI,CAAC,IAAI;AAC3B,UAAM,OAAO,KAAK,IAAI,IAAI,CAAC,IAAI;AAC/B,QAAI,OAAO,QAAS,WAAU;AAC9B,QAAI,OAAO,QAAS,WAAU;AAAA,EAChC;AAEA,SAAO,EAAE,KAAK,SAAS,KAAK,QAAQ;AACtC;AAaO,SAAS,kBACd,GACA,UACA,YACA,SACA,SACA,UACW;AACX,QAAM,MAAM,KAAK,IAAI,UAAU,UAAU;AACzC,QAAM,MAAM,KAAK,IAAI,UAAU,UAAU;AAEzC,MAAI,aAAa,UAAU;AACzB,WAAO,CAAC,EAAE,GAAG,GAAG,aAAa,KAAK,OAAO,UAAU,QAAQ,MAAM,IAAI,CAAC;AAAA,EACxE;AAGA,SAAO;AAAA,IACL,EAAE,GAAG,GAAG,GAAG,OAAO,UAAU,QAAQ,aAAa,IAAI;AAAA,IACrD,EAAE,GAAG,GAAG,aAAa,KAAK,OAAO,UAAU,QAAQ,aAAa,IAAI;AAAA,EACtE;AACF;;;ACxFO,SAAS,uBACd,YACA,YACA,cACA,YACA,UAAU,GACA;AACV,QAAM,cAAc,KAAK,KAAK,aAAa,UAAU;AACrD,QAAM,UAAoB,CAAC;AAC3B,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,UAAM,aAAa,UAAU,IAAI;AACjC,UAAM,WAAW,aAAa;AAC9B,QAAI,WAAW,gBAAgB,aAAa,YAAY;AACtD,cAAQ,KAAK,CAAC;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;;;AFpBA,IAAM,mBAAmB;AAGzB,IAAM,eAAe,oBAAI,IAAI,CAAC,UAAU,cAAc,YAAY,QAAQ,CAAC;AAO3E,SAAS,kBACP,aACA,MAC2C;AAC3C,QAAM,eAAe,oBAAI,IAA0C;AACnE,aAAW,WAAW,aAAa;AAEjC,UAAM,WAAW,KAAK,MAAM,UAAU,IAAI,IAAI;AAC9C,UAAM,WAAW,KAAK,MAAM,WAAW,gBAAgB;AACvD,UAAM,WAAW,aAAa,IAAI,QAAQ;AAC1C,QAAI,UAAU;AACZ,mBAAa,IAAI,UAAU;AAAA,QACzB,KAAK,KAAK,IAAI,SAAS,KAAK,QAAQ;AAAA,QACpC,KAAK,KAAK,IAAI,SAAS,KAAK,QAAQ;AAAA,MACtC,CAAC;AAAA,IACH,OAAO;AACL,mBAAa,IAAI,UAAU,EAAE,KAAK,UAAU,KAAK,SAAS,CAAC;AAAA,IAC7D;AAAA,EACF;AACA,SAAO;AACT;AAGO,IAAM,qBAAN,cAAiCC,YAAW;AAAA,EAA5C;AAAA;AACL,SAAQ,SAAgB,IAAI,WAAW,CAAC;AACxC,SAAQ,eAA4B,oBAAI,IAAI;AAC5C,SAAQ,iBAAiB;AACzB,SAAQ,SAAS;AAEjB;AAAA,SAAQ,eAA4B,oBAAI,IAAI;AAyBE,kBAAS;AACT,sBAAa;AACb,oBAAW;AACX,kBAAS;AAET,wBAAe;AAEf,sBAAa;AAEb,mBAAU;AAAA;AAAA,EAhCxD,IAAI,MAAM,OAAc;AACtB,SAAK,SAAS;AACd,SAAK,cAAc;AACnB,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,IAAI,QAAe;AACjB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAc,OAAc;AAC1B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,IAAI,OAAa;AACf,WAAO,KAAK,kBAAkB,YAAY,IAAI;AAAA,EAChD;AAAA,EA2BQ,0BAAoC;AAC1C,WAAO;AAAA,MACL,KAAK;AAAA,MACL;AAAA,MACA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,YAAoB,UAAkB;AAChD,UAAM,YAAY,KAAK,MAAM,KAAK,OAAO,SAAS,CAAC;AACnD,UAAM,eAAe,KAAK,IAAI,GAAG,UAAU;AAC3C,UAAM,aAAa,KAAK,IAAI,WAAW,QAAQ;AAC/C,aAAS,IAAI,cAAc,IAAI,YAAY,KAAK;AAC9C,WAAK,aAAa,IAAI,CAAC;AAAA,IACzB;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,gBAAgB;AACtB,UAAM,YAAY,KAAK,MAAM,KAAK,OAAO,SAAS,CAAC;AACnD,aAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,WAAK,aAAa,IAAI,CAAC;AAAA,IACzB;AACA,SAAK,cAAc;AAAA,EACrB;AAAA,EAEQ,gBAAgB;AACtB,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAiB;AACtB,WAAK,SAAS,sBAAsB,MAAM;AACxC,aAAK,iBAAiB;AACtB,aAAK,WAAW;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,aAAa;AACnB,QAAI,KAAK,aAAa,SAAS,KAAK,KAAK,WAAW,KAAK,KAAK,OAAO,WAAW,GAAG;AACjF,WAAK,aAAa,MAAM;AACxB;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,YAAY,iBAAiB,QAAQ;AAC3D,QAAI,CAAC,YAAY,SAAS,WAAW,GAAG;AAGtC;AAAA,IACF;AAEA,UAAM,OAAO,KAAK,WAAW,KAAK;AAClC,UAAM,MAAM,OAAO,qBAAqB,cAAc,mBAAmB;AACzE,UAAM,aAAa,KAAK,aAAa;AACrC,UAAM,OAAO,KAAK;AAClB,UAAM,YACJ,iBAAiB,IAAI,EAAE,iBAAiB,kBAAkB,EAAE,KAAK,KAAK;AAExE,UAAM,eAAe,kBAAkB,KAAK,cAAc,IAAI;AAE9D,SAAK,aAAa,MAAM;AACxB,eAAW,UAAU,UAAU;AAC7B,YAAM,WAAW,OAAO,OAAO,QAAQ,KAAK;AAC5C,WAAK,aAAa,IAAI,QAAQ;AAC9B,YAAM,QAAQ,aAAa,IAAI,QAAQ;AACvC,UAAI,CAAC,MAAO;AACZ,WAAK,WAAW,QAAQ,UAAU,OAAO,MAAM,KAAK,YAAY,MAAM,SAAS;AAAA,IACjF;AAEA,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA,EAEQ,WACN,QACA,UACA,OACA,MACA,KACA,YACA,MACA,WACA;AACA,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK;AAEV,UAAM,eAAe,WAAW;AAEhC,UAAM,aAAa,KAAK,IAAI,GAAG,MAAM,MAAM,YAAY;AACvD,UAAM,WAAW,MAAM,MAAM,eAAe,KAAK;AACjD,UAAM,aAAa,WAAW;AAC9B,UAAM,WAAW,MAAM;AAEvB,QAAI,eAAe;AACnB,QAAI,UAAU,aAAa,KAAK,GAAG,aAAa,KAAK,OAAO,MAAM;AAClE,QAAI,MAAM,KAAK,GAAG;AAClB,QAAI,YAAY;AAEhB,UAAM,cAAc,KAAK,IAAI,kBAAkB,KAAK,SAAS,YAAY;AACzE,UAAM,YAAY,KAAK,IAAI,eAAe,UAAU,eAAe,WAAW;AAE9E,aAAS,MAAM,KAAK,IAAI,GAAG,QAAQ,GAAG,MAAM,WAAW,OAAO,MAAM;AAClE,YAAM,OAAO,eAAe,KAAK,QAAQ,MAAM,KAAK,MAAM,IAAI;AAC9D,UAAI,CAAC,KAAM;AACX,YAAM,QAAQ;AAAA,QACZ,MAAM;AAAA,QACN,KAAK;AAAA,QACL;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,QACL;AAAA,MACF;AACA,iBAAW,KAAK,OAAO;AACrB,YAAI,SAAS,EAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,oBAAoB;AAClB,UAAM,kBAAkB;AAExB,QAAI,KAAK,aAAa,OAAO,GAAG;AAC9B,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,uBAAuB;AACrB,UAAM,qBAAqB;AAC3B,QAAI,KAAK,gBAAgB;AACvB,2BAAqB,KAAK,MAAM;AAChC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EAEF;AAAA,EAEA,SAAS;AACP,UAAM,UAAU,KAAK,wBAAwB;AAC7C,UAAM,MAAM,OAAO,qBAAqB,cAAc,mBAAmB;AAEzE,WAAO;AAAA,6CACkC,KAAK,MAAM,eAAe,KAAK,UAAU;AAAA,UAC5E,QAAQ,IAAI,CAAC,MAAM;AACnB,YAAM,QAAQ,KAAK,IAAI,kBAAkB,KAAK,SAAS,IAAI,gBAAgB;AAC3E,aAAO;AAAA;AAAA,2BAEU,CAAC;AAAA,sBACN,QAAQ,GAAG;AAAA,uBACV,KAAK,aAAa,GAAG;AAAA,6BACf,IAAI,gBAAgB,cAAc,KAAK,eAAe,KAClE,UAAU;AAAA;AAAA;AAAA,IAGnB,CAAC,CAAC;AAAA;AAAA;AAAA,EAGR;AAAA;AAAA,EAGQ,sBAAsB;AAC5B,UAAM,iBAAiB,KAAK,wBAAwB;AACpD,UAAM,YAAY,KAAK,MAAM,KAAK,OAAO,SAAS,CAAC;AACnD,eAAW,YAAY,gBAAgB;AACrC,UAAI,CAAC,KAAK,aAAa,IAAI,QAAQ,GAAG;AACpC,cAAM,QAAQ,WAAW;AACzB,cAAM,MAAM,KAAK,IAAI,QAAQ,kBAAkB,SAAS;AACxD,iBAAS,IAAI,OAAO,IAAI,KAAK,KAAK;AAChC,eAAK,aAAa,IAAI,CAAC;AAAA,QACzB;AAAA,MACF;AAAA,IACF;AACA,QAAI,KAAK,aAAa,OAAO,GAAG;AAC9B,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,QAAQ,mBAAyC;AAE/C,UAAM,iBAAiB,CAAC,GAAG,kBAAkB,KAAK,CAAC,EAAE,KAAK,CAAC,QAAQ,aAAa,IAAI,GAAG,CAAC;AACxF,QAAI,gBAAgB;AAClB,WAAK,cAAc;AACnB;AAAA,IACF;AAEA,QACE,kBAAkB,IAAI,cAAc,KACpC,kBAAkB,IAAI,YAAY,KAClC,kBAAkB,IAAI,SAAS,GAC/B;AACA,WAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AACF;AA3Pa,mBA0CJ,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAX8B;AAAA,EAA7CC,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GA/BjC,mBA+BmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAhCjC,mBAgCmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAjCjC,mBAiCmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAlCjC,mBAkCmC;AAEA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GApCjC,mBAoCmC;AAEA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAtCjC,mBAsCmC;AAEA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAxCjC,mBAwCmC;AAxCnC,qBAAN;AAAA,EADNC,eAAc,cAAc;AAAA,GAChB;;;AGvCb,SAAS,cAAAC,aAAY,QAAAC,OAAM,OAAAC,YAAW;AACtC,SAAS,iBAAAC,sBAAqB;;;ACCvB,IAAM,sBAAN,MAAwD;AAAA,EAI7D,YAAY,MAA8B;AAH1C,SAAQ,SAAwB;AAChC,SAAQ,YAAiC;AAGvC,SAAK,cAAc,IAAI;AAAA,EACzB;AAAA,EAEA,MAAM,UAAsB;AAC1B,SAAK,KAAK;AACV,SAAK,YAAY;AACjB,UAAM,OAAO,MAAM;AACjB,WAAK,YAAY;AACjB,WAAK,SAAS,sBAAsB,IAAI;AAAA,IAC1C;AACA,SAAK,SAAS,sBAAsB,IAAI;AAAA,EAC1C;AAAA,EAEA,OAAO;AACL,QAAI,KAAK,WAAW,MAAM;AACxB,2BAAqB,KAAK,MAAM;AAChC,WAAK,SAAS;AAAA,IAChB;AACA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,gBAAgB;AAAA,EAAC;AAAA,EAEjB,mBAAmB;AACjB,SAAK,KAAK;AAAA,EACZ;AACF;;;AD5BO,IAAM,qBAAN,cAAiCC,YAAW;AAAA,EAA5C;AAAA;AACL,SAAQ,aAAa,IAAI,oBAAoB,IAAI;AACjD,SAAQ,QAA4B;AAAA;AAAA,EAqBpC,SAAS;AACP,WAAOC;AAAA,EACT;AAAA,EAEA,eAAe;AACb,SAAK,QAAQ,KAAK,WAAY,cAAc,KAAK;AAAA,EACnD;AAAA,EAEA,eAAe,SAAuB,YAAoB,iBAAyB;AACjF,SAAK,WAAW,MAAM,MAAM;AAC1B,YAAM,OAAO,QAAQ;AACrB,YAAM,KAAM,OAAO,aAAc;AACjC,UAAI,KAAK,OAAO;AACd,aAAK,MAAM,MAAM,YAAY,eAAe,EAAE;AAAA,MAChD;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,cAAc,MAAc,YAAoB,iBAAyB;AACvE,SAAK,WAAW,KAAK;AACrB,UAAM,KAAM,OAAO,aAAc;AACjC,QAAI,KAAK,OAAO;AACd,WAAK,MAAM,MAAM,YAAY,eAAe,EAAE;AAAA,IAChD;AAAA,EACF;AACF;AAhDa,mBAIJ,SAASC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAJL,qBAAN;AAAA,EADNC,eAAc,cAAc;AAAA,GAChB;;;AELb,SAAS,cAAAC,mBAAkB;AAC3B,SAAS,iBAAAC,gBAAe,YAAAC,iBAAgB;AAGjC,IAAM,sBAAN,cAAkCC,YAAW;AAAA,EAA7C;AAAA;AACO,eAAM;AAAA;AAAA,EAElB,IAAI,SAA6B;AAC/B,WAAO,KAAK,MAAM,SAAS,eAAe,KAAK,GAAG,IAAI;AAAA,EACxD;AAAA;AAAA;AAAA,EAIA,mBAAmB;AACjB,WAAO;AAAA,EACT;AACF;AAXc;AAAA,EAAXC,UAAS;AAAA,GADC,oBACC;AADD,sBAAN;AAAA,EADNC,eAAc,eAAe;AAAA,GACjB;;;ACJb,SAAS,QAAAC,aAAY;AACrB,SAAS,iBAAAC,sBAAqB;;;ACD9B,SAAS,cAAAC,aAAY,OAAAC,YAAW;AAOzB,IAAM,qBAAN,cAAiCD,YAAW;AAAA,EACjD,IAAc,SAAc;AAC1B,UAAM,YAAY,KAAK,QAAQ,eAAe;AAC9C,WAAO,WAAW,UAAU;AAAA,EAC9B;AAmBF;AAvBa,mBAMJ,SAAuCC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ADRzC,IAAM,uBAAN,cAAmC,mBAAmB;AAAA,EAC3D,SAAS;AACP,WAAOC;AAAA,qCAC0B,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIhD;AAAA,EAEQ,WAAW;AACjB,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AACF;AAnBa,uBAAN;AAAA,EADNC,eAAc,iBAAiB;AAAA,GACnB;;;AELb,SAAS,QAAAC,aAAY;AACrB,SAAS,iBAAAC,sBAAqB;AAIvB,IAAM,wBAAN,cAAoC,mBAAmB;AAAA,EAC5D,SAAS;AACP,WAAOC;AAAA,qCAC0B,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIhD;AAAA,EAEQ,WAAW;AACjB,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AACA,WAAO,MAAM;AAAA,EACf;AACF;AAnBa,wBAAN;AAAA,EADNC,eAAc,kBAAkB;AAAA,GACpB;;;ACLb,SAAS,QAAAC,aAAY;AACrB,SAAS,iBAAAC,sBAAqB;AAIvB,IAAM,uBAAN,cAAmC,mBAAmB;AAAA,EAC3D,SAAS;AACP,WAAOC;AAAA,qCAC0B,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,EAIhD;AAAA,EAEQ,WAAW;AACjB,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AACF;AAnBa,uBAAN;AAAA,EADNC,eAAc,iBAAiB;AAAA,GACnB;;;ACLb,SAAS,cAAAC,aAAY,QAAAC,OAAM,OAAAC,YAAW;AACtC,SAAS,iBAAAC,iBAAe,YAAAC,WAAU,aAAa;AAG/C,SAAS,yBAAAC,wBAAuB,eAAAC,cAAa,sBAAsB;;;ACMnE,OAAO,kBAAkB;AAWzB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2Kd,SAAS,oBAAoC;AAClD,MAAI;AACJ,MAAI;AACF,UAAM,OAAO,IAAI,KAAK,CAAC,YAAY,GAAG,EAAE,MAAM,yBAAyB,CAAC;AACxE,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,aAAS,IAAI,OAAO,GAAG;AACvB,QAAI,gBAAgB,GAAG;AAAA,EACzB,SAAS,KAAK;AAEZ,YAAQ,KAAK,iEAAiE,OAAO,GAAG,CAAC;AACzF,WAAO;AAAA,MACL,WAAW;AACT,eAAO,QAAQ;AAAA,UACb,IAAI;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MACA,YAAY;AAAA,MAEZ;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAU,oBAAI,IAA0B;AAC9C,MAAI,aAAa;AACjB,MAAI,YAAY;AAEhB,SAAO,YAAY,CAAC,MAAoB;AACtC,UAAM,MAAM,EAAE;AACd,UAAM,QAAQ,QAAQ,IAAI,IAAI,EAAE;AAChC,QAAI,CAAC,OAAO;AACV,cAAQ,KAAK,uDAAuD,OAAO,IAAI,EAAE,CAAC;AAClF;AAAA,IACF;AACA,YAAQ,OAAO,IAAI,EAAE;AAErB,QAAI,IAAI,OAAO;AACb,YAAM,OAAO,IAAI,MAAM,IAAI,KAAK,CAAC;AAAA,IACnC,OAAO;AACL,UAAI;AACF,cAAM,eAAe,aAAa,OAAO,IAAI,MAAM;AACnD,cAAM,QAAQ,YAAY;AAAA,MAC5B,SAAS,KAAK;AACZ,cAAM,OAAO,GAAG;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,UAAU,CAAC,MAAkB;AAClC,UAAM,SAAS,EAAE,SAAS,IAAI,MAAM,EAAE,OAAO;AAC7C,YAAQ,KAAK,qCAAqC,OAAO,MAAM,CAAC;AAChE,iBAAa;AACb,WAAO,UAAU;AACjB,eAAW,CAAC,EAAE,KAAK,KAAK,SAAS;AAC/B,YAAM,OAAO,MAAM;AAAA,IACrB;AACA,YAAQ,MAAM;AAAA,EAChB;AAEA,SAAO;AAAA,IACL,SAAS,QAAQ;AACf,UAAI,WAAY,QAAO,QAAQ,OAAO,IAAI,MAAM,mBAAmB,CAAC;AACpE,YAAM,YAAY,OAAO,EAAE,SAAS;AAEpC,aAAO,IAAI,QAAsB,CAAC,SAAS,WAAW;AACpD,gBAAQ,IAAI,WAAW,EAAE,SAAS,OAAO,CAAC;AAE1C,eAAO;AAAA,UACL;AAAA,YACE,IAAI;AAAA,YACJ,OAAO,OAAO;AAAA,YACd,MAAM,OAAO;AAAA,YACb,iBAAiB;AAAA,YACjB,gBAAgB,OAAO;AAAA,YACvB,QAAQ,OAAO;AAAA,YACf,aAAa,OAAO;AAAA,YACpB,UAAU,OAAO;AAAA,UACnB;AAAA,UACA,OAAO;AAAA;AAAA,QACT;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,YAAY;AACV,mBAAa;AACb,aAAO,UAAU;AACjB,iBAAW,CAAC,EAAE,KAAK,KAAK,SAAS;AAC/B,cAAM,OAAO,IAAI,MAAM,mBAAmB,CAAC;AAAA,MAC7C;AACA,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AACF;;;AClRA,SAAS,iBACP,cACA,iBACA,eACA,iBACqB;AACrB,MAAI,gBAAgB;AAEpB,MAAI,kBAAkB,UAAa,oBAAoB,QAAW;AAChE,QAAI,cAAc,UAAU,iBAAiB;AAC3C,YAAM,cAAc,aAAa;AACjC,YAAM,QAAQ,kBAAkB;AAEhC,YAAM,cAAc,KAAK,MAAM,gBAAgB,eAAe;AAC9D,YAAM,YAAY,KAAK,MAAM,gBAAgB,mBAAmB,eAAe;AAE/E,YAAM,cAAc,KAAK,IAAI,GAAG,KAAK,MAAM,cAAc,KAAK,CAAC;AAC/D,YAAM,YAAY,KAAK,IAAI,aAAa,QAAQ,KAAK,KAAK,YAAY,KAAK,CAAC;AAE5E,UAAI,eAAe,WAAW;AAC5B,eAAO;AAAA,MACT;AAEA,sBAAgB,cAAc,MAAM;AAAA,QAClC,YAAY;AAAA,QACZ,UAAU;AAAA,MACZ,CAAC;AACD,sBAAgB,cAAc,SAAS,EAAE,OAAO,gBAAgB,CAAC;AAAA,IACnE,OAAO;AACL,YAAM,aAAa,KAAK,MAAM,gBAAgB,eAAe;AAC7D,YAAM,WAAW,KAAK,MAAM,gBAAgB,mBAAmB,eAAe;AAC9E,sBAAgB,cAAc,MAAM,EAAE,YAAY,SAAS,CAAC;AAAA,IAC9D;AAAA,EACF,WAAW,cAAc,UAAU,iBAAiB;AAClD,oBAAgB,cAAc,SAAS,EAAE,OAAO,gBAAgB,CAAC;AAAA,EACnE;AAEA,SAAO;AACT;AAMO,SAAS,aACd,cACA,iBACA,QACA,eACA,iBACU;AACV,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,kBAAkB,MAAM;AAC1B,UAAMC,QAAO,aAAa;AAC1B,UAAMC,eAAc,SAAS,IAAI,aAAa;AAC9C,UAAM,YAAqB,MAAM;AAAA,MAAK,EAAE,QAAQA,aAAY;AAAA,MAAG,MAC7DD,UAAS,IAAI,IAAI,UAAU,CAAC,IAAI,IAAI,WAAW,CAAC;AAAA,IAClD;AACA,WAAO,EAAE,QAAQ,GAAG,MAAM,WAAW,MAAAA,MAAK;AAAA,EAC5C;AAEA,QAAM,cAAc,cAAc;AAClC,QAAM,OAAO,cAAc;AAE3B,QAAM,eAAwB,CAAC;AAC/B,WAAS,IAAI,GAAG,IAAI,aAAa,KAAK;AACpC,UAAM,UAAU,cAAc,QAAQ,CAAC;AACvC,UAAM,WAAW,QAAQ,UAAU;AACnC,UAAM,WAAW,QAAQ,UAAU;AACnC,UAAM,MAAM,SAAS;AAErB,UAAM,QAAe,SAAS,IAAI,IAAI,UAAU,MAAM,CAAC,IAAI,IAAI,WAAW,MAAM,CAAC;AAEjF,aAAS,IAAI,GAAG,IAAI,KAAK,KAAK;AAC5B,YAAM,IAAI,CAAC,IAAI,SAAS,CAAC;AACzB,YAAM,IAAI,IAAI,CAAC,IAAI,SAAS,CAAC;AAAA,IAC/B;AACA,iBAAa,KAAK,KAAK;AAAA,EACzB;AAEA,MAAI,UAAU,aAAa,SAAS,GAAG;AACrC,UAAM,SAAS,IAAI,aAAa;AAChC,UAAM,WAAW,aAAa,CAAC,EAAE,SAAS;AAC1C,UAAM,YACJ,SAAS,IAAI,IAAI,UAAU,WAAW,CAAC,IAAI,IAAI,WAAW,WAAW,CAAC;AAExE,aAAS,IAAI,GAAG,IAAI,UAAU,KAAK;AACjC,UAAI,MAAM;AACV,UAAI,MAAM;AACV,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,eAAO,SAAS,aAAa,CAAC,EAAE,IAAI,CAAC;AACrC,eAAO,SAAS,aAAa,CAAC,EAAE,IAAI,IAAI,CAAC;AAAA,MAC3C;AACA,gBAAU,IAAI,CAAC,IAAI;AACnB,gBAAU,IAAI,IAAI,CAAC,IAAI;AAAA,IACzB;AAEA,WAAO,EAAE,QAAQ,UAAU,MAAM,CAAC,SAAS,GAAG,KAAK;AAAA,EACrD;AAEA,QAAM,aAAa,aAAa,SAAS,IAAI,aAAa,CAAC,EAAE,SAAS,IAAI;AAC1E,SAAO,EAAE,QAAQ,YAAY,MAAM,cAAc,KAAK;AACxD;;;ACtGO,IAAM,eAAN,MAAmB;AAAA,EAAnB;AACL,SAAQ,UAAiC;AACzC,SAAQ,SAAS,oBAAI,QAAmC;AACxD,SAAQ,YAAY,oBAAI,QAA4C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOpE,MAAM,cACJ,aACA,iBACA,QACmB;AACnB,UAAM,eAAe,MAAM,KAAK,iBAAiB,aAAa,eAAe;AAC7E,QAAI;AACF,aAAO,aAAa,cAAc,iBAAiB,MAAM;AAAA,IAC3D,SAAS,KAAK;AACZ,cAAQ,KAAK,oCAAoC,OAAO,GAAG,CAAC;AAC5D,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,eACE,aACA,iBACA,QACuB;AACvB,UAAM,SAAS,oBAAI,IAAsB;AACzC,eAAW,CAAC,QAAQ,WAAW,KAAK,aAAa;AAC/C,YAAM,SAAS,KAAK,OAAO,IAAI,WAAW;AAC1C,UAAI,QAAQ;AAEV,YAAI,kBAAkB,OAAO,MAAO;AACpC,YAAI;AACF,iBAAO,IAAI,QAAQ,aAAa,QAAQ,iBAAiB,MAAM,CAAC;AAAA,QAClE,SAAS,KAAK;AACZ,kBAAQ,KAAK,8CAA8C,SAAS,OAAO,OAAO,GAAG,CAAC;AAAA,QACxF;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,YAAY;AACV,SAAK,SAAS,UAAU;AACxB,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAc,iBACZ,aACA,iBACuB;AACvB,UAAM,SAAS,KAAK,OAAO,IAAI,WAAW;AAE1C,QAAI,UAAU,OAAO,SAAS,gBAAiB,QAAO;AAEtD,UAAM,WAAW,KAAK,UAAU,IAAI,WAAW;AAC/C,QAAI,SAAU,QAAO;AAErB,QAAI,CAAC,KAAK,SAAS;AACjB,WAAK,UAAU,kBAAkB;AAAA,IACnC;AAIA,UAAM,WAA0B,CAAC;AACjC,aAAS,IAAI,GAAG,IAAI,YAAY,kBAAkB,KAAK;AACrD,eAAS,KAAK,YAAY,eAAe,CAAC,EAAE,MAAM,EAAE,MAAqB;AAAA,IAC3E;AAEA,UAAM,UAAU,KAAK,QAClB,SAAS;AAAA,MACR;AAAA,MACA,QAAQ,YAAY;AAAA,MACpB,YAAY,YAAY;AAAA,MACxB,OAAO;AAAA,MACP,MAAM;AAAA,MACN,eAAe;AAAA,IACjB,CAAC,EACA,KAAK,CAAC,iBAAiB;AACtB,WAAK,OAAO,IAAI,aAAa,YAAY;AACzC,WAAK,UAAU,OAAO,WAAW;AACjC,aAAO;AAAA,IACT,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,WAAK,UAAU,OAAO,WAAW;AACjC,cAAQ,KAAK,kDAAkD,OAAO,GAAG,CAAC;AAC1E,YAAM;AAAA,IACR,CAAC;AAEH,SAAK,UAAU,IAAI,aAAa,OAAO;AACvC,WAAO;AAAA,EACT;AACF;;;ACtHA,SAAS,cAAAE,aAAY,QAAAC,OAAM,OAAAC,YAAW;AACtC,SAAS,iBAAAC,gBAAe,YAAAC,iBAAgB;AAGjC,IAAM,0BAAN,cAAsCC,YAAW;AAAA,EAAjD;AAAA;AAE2B,mBAAyB;AACzB,qBAAY;AACE,kBAAS;AACT,eAAM;AACL,iBAAQ;AACR,kBAAS;AAuIxD,SAAQ,iBAAiB,CAAC,MAAa;AACrC,YAAM,QAAQ,OAAQ,EAAE,OAA4B,KAAK;AACzD,UAAI,OAAO,SAAS,KAAK,EAAG,MAAK,iBAAiB,UAAU,KAAK;AAAA,IACnE;AAEA,SAAQ,cAAc,CAAC,MAAa;AAClC,YAAM,QAAQ,OAAQ,EAAE,OAA4B,KAAK;AACzD,UAAI,OAAO,SAAS,KAAK,EAAG,MAAK,iBAAiB,OAAO,KAAK;AAAA,IAChE;AAEA,SAAQ,eAAe,MAAM;AAC3B,WAAK,iBAAiB,SAAS,CAAC,KAAK,KAAK;AAAA,IAC5C;AAEA,SAAQ,eAAe,MAAM;AAC3B,WAAK,iBAAiB,UAAU,CAAC,KAAK,MAAM;AAAA,IAC9C;AAEA,SAAQ,iBAAiB,MAAM;AAC7B,UAAI,CAAC,KAAK,QAAS;AACnB,WAAK;AAAA,QACH,IAAI,YAAY,oBAAoB;AAAA,UAClC,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,KAAK,QAAQ;AAAA,QAClC,CAAC;AAAA,MACH;AAAA,IACF;AAAA;AAAA,EAEQ,iBAAiB,MAAc,OAAyB;AAC9D,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK;AAAA,MACH,IAAI,YAAY,qBAAqB;AAAA,QACnC,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,SAAS,KAAK,SAAS,MAAM,MAAM;AAAA,MAC/C,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,SAAS;AACP,UAAM,aAAa,KAAK,MAAM,KAAK,SAAS,GAAG;AAC/C,UAAM,aAAa,KAAK,MAAM,KAAK,IAAI,KAAK,GAAG,IAAI,GAAG;AACtD,UAAM,aAAa,KAAK,QAAQ,IAAI,OAAO,KAAK,MAAM,IAAI,MAAM,OAAO;AAEvE,WAAOC;AAAA;AAAA,mCAEwB,KAAK,SAAS,IAAI,KAAK,aAAa,UAAU;AAAA,4CACrC,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAMxC,KAAK,QAAQ,iBAAiB,EAAE;AAAA,mBACpC,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,6BAKP,KAAK,SAAS,WAAW,EAAE,YAAY,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6CAOxC,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOpC,OAAO,KAAK,MAAM,CAAC;AAAA,mBACnB,KAAK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6CAMO,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAOpC,OAAO,KAAK,GAAG,CAAC;AAAA,mBAChB,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA,EAIjC;AACF;AA5Oa,wBASJ,SAASC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAPgB;AAAA,EAA/BC,UAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAFnB,wBAEqB;AACA;AAAA,EAA/BA,UAAS,EAAE,WAAW,MAAM,CAAC;AAAA,GAHnB,wBAGqB;AACc;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAJjC,wBAImC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GALjC,wBAKmC;AACC;AAAA,EAA9CA,UAAS,EAAE,MAAM,SAAS,WAAW,MAAM,CAAC;AAAA,GANlC,wBAMoC;AACA;AAAA,EAA9CA,UAAS,EAAE,MAAM,SAAS,WAAW,MAAM,CAAC;AAAA,GAPlC,wBAOoC;AAPpC,0BAAN;AAAA,EADNC,eAAc,oBAAoB;AAAA,GACtB;;;ACJb,SAAS,OAAAC,YAAW;AAOb,IAAM,aAAaA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACF1B,IAAM,sBAAsB;AAC5B,IAAM,mBAAmB;AAElB,IAAM,qBAAN,MAAuD;AAAA,EAU5D,YAAY,MAA4C;AARxD,SAAQ,mBAAuC;AAC/C,SAAQ,kBAAkB;AAG1B;AAAA,wBAAe;AACf,sBAAa;AACb,0BAAiB;AAQjB;AAAA,0BAAiB;AAkCjB,SAAQ,YAAY,MAAM;AACxB,UAAI,CAAC,KAAK,iBAAkB;AAC5B,YAAM,EAAE,YAAY,YAAY,IAAI,KAAK;AACzC,UAAI,KAAK,IAAI,aAAa,KAAK,eAAe,KAAK,kBAAkB;AACnE,aAAK,QAAQ,YAAY,WAAW;AACpC,aAAK,MAAM,cAAc;AAAA,MAC3B;AAAA,IACF;AA9CE,SAAK,QAAQ;AACb,SAAK,cAAc,IAAI;AAAA,EACzB;AAAA,EAKA,gBAAgB;AAEd,0BAAsB,MAAM;AAC1B,UAAI,CAAC,KAAK,MAAM,YAAa;AAC7B,YAAM,YAAY,KAAK,iBAClB,KAAK,MAAM,YAAY,cAAc,KAAK,cAAc,IACzD,KAAK;AACT,UAAI,WAAW;AACb,aAAK,uBAAuB,SAAS;AAAA,MACvC,WAAW,KAAK,gBAAgB;AAC9B,gBAAQ;AAAA,UACN,mEACE,KAAK,iBACL;AAAA,QACJ;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,mBAAmB;AACjB,SAAK,kBAAkB,oBAAoB,UAAU,KAAK,SAAS;AACnE,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEQ,uBAAuB,WAAwB;AACrD,SAAK,kBAAkB,oBAAoB,UAAU,KAAK,SAAS;AACnE,SAAK,mBAAmB;AACxB,cAAU,iBAAiB,UAAU,KAAK,WAAW,EAAE,SAAS,KAAK,CAAC;AACtE,SAAK,QAAQ,UAAU,YAAY,UAAU,WAAW;AACxD,SAAK,MAAM,cAAc;AAAA,EAC3B;AAAA,EAWQ,QAAQ,YAAoB,gBAAwB;AAC1D,SAAK,kBAAkB;AACvB,SAAK,iBAAiB;AACtB,UAAM,SAAS,iBAAiB;AAChC,SAAK,eAAe,aAAa;AACjC,SAAK,aAAa,aAAa,iBAAiB;AAAA,EAClD;AACF;;;ACzEA,SAAS,gCAAgC;AAElC,IAAM,wBAAN,MAA0D;AAAA,EAS/D,YAAY,MAA4C;AAPxD,SAAQ,UAA8B;AACtC,SAAQ,YAAY;AACpB,SAAQ,cAAc;AAkDtB,SAAQ,aAAa,CAAC,MAAa;AACjC,+BAAyB,EAAE,MAAM,CAAC,QAAQ;AACxC,gBAAQ;AAAA,UACN,+EAA+E,OAAO,GAAG;AAAA,QAC3F;AAAA,MACF,CAAC;AAED,YAAM,YAAY,EAAE,SAAS,gBAAgB,YAAY;AACzD,WAAK,SAAS,oBAAoB,WAAW,KAAK,YAAY;AAAA,QAC5D,SAAS;AAAA,MACX,CAAC;AACD,WAAK,UAAU;AAAA,IACjB;AAxDE,SAAK,QAAQ;AACb,SAAK,cAAc,IAAI;AAAA,EACzB;AAAA,EAEA,gBAAgB;AAGd,UAAM,MAAM,EAAE,KAAK;AACnB,0BAAsB,MAAM;AAC1B,UAAI,QAAQ,KAAK,YAAa;AAC9B,UAAI,CAAC,KAAK,MAAM,eAAe,KAAK,aAAa,KAAK,WAAW,OAAW;AAE5E,UAAI;AACJ,UAAI;AACF,yBAAiB,KAAK,eAAe;AAAA,MACvC,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,gEACE,KAAK,SACL,QACA,OAAO,GAAG;AAAA,QACd;AACA;AAAA,MACF;AACA,UAAI,CAAC,eAAgB;AAErB,WAAK,UAAU;AACf,WAAK,YAAY;AACjB,qBAAe,iBAAiB,eAAe,KAAK,YAAY;AAAA,QAC9D,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AACD,qBAAe,iBAAiB,WAAW,KAAK,YAAY;AAAA,QAC1D,MAAM;AAAA,QACN,SAAS;AAAA,MACX,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,mBAAmB;AACjB,SAAK,iBAAiB;AACtB,SAAK,YAAY;AAAA,EACnB;AAAA,EAgBQ,iBAAqC;AAC3C,UAAM,IAAI,KAAK;AACf,QAAI,MAAM,OAAW,QAAO;AAC5B,QAAI,MAAM,GAAI,QAAO,KAAK;AAC1B,QAAI,MAAM,WAAY,QAAO;AAE7B,UAAM,KAAK,SAAS,cAAc,CAAC;AACnC,QAAI,CAAC,IAAI;AACP,cAAQ;AAAA,QACN,8CACE,IACA;AAAA,MAEJ;AACA,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB;AACzB,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,QAAQ,oBAAoB,eAAe,KAAK,YAAY;AAAA,MAC/D,SAAS;AAAA,IACX,CAAC;AACD,SAAK,QAAQ,oBAAoB,WAAW,KAAK,YAAY;AAAA,MAC3D,SAAS;AAAA,IACX,CAAC;AACD,SAAK,UAAU;AAAA,EACjB;AACF;;;AClGA,SAAS,wBAAwB;AACjC,SAAS,6BAA6B;AACtC,SAAS,aAAa,sBAAsB,yBAAyB;AAuD9D,IAAM,sBAAN,MAAwD;AAAA,EAK7D,YAAY,MAAmC;AAH/C,SAAQ,YAAY,oBAAI,IAA8B;AACtD,SAAQ,iBAAiB;AAGvB,SAAK,QAAQ;AACb,SAAK,cAAc,IAAI;AAAA,EACzB;AAAA,EAEA,gBAAgB;AAAA,EAAC;AAAA,EAEjB,mBAAmB;AACjB,eAAW,WAAW,CAAC,GAAG,KAAK,UAAU,KAAK,CAAC,GAAG;AAChD,WAAK,gBAAgB,OAAO;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,IAAI,cAAuB;AACzB,WAAO,KAAK,UAAU,OAAO;AAAA,EAC/B;AAAA,EAEA,WAAW,SAAuD;AAChE,WAAO,KAAK,UAAU,IAAI,OAAO;AAAA,EACnC;AAAA,EAEA,MAAM,eAAe,QAAqB,UAA4B,CAAC,GAAkB;AACvF,UAAM,UAAU,QAAQ,WAAW,KAAK,MAAM;AAC9C,QAAI,CAAC,SAAS;AACZ,cAAQ,KAAK,gEAAgE;AAC7E;AAAA,IACF;AACA,QAAI,KAAK,UAAU,IAAI,OAAO,GAAG;AAC/B,cAAQ,KAAK,gEAAgE,UAAU,GAAG;AAC1F;AAAA,IACF;AAEA,UAAM,OAAa,QAAQ,QAAQ;AACnC,UAAM,UAAU,iBAAiB;AACjC,UAAM,SAAS,QAAQ;AAGvB,SAAK,MAAM,8BAA8B,OAAO,UAAU;AAE1D,QAAI;AAEF,UAAI,CAAC,KAAK,gBAAgB;AACxB,cAAM,OAAO,aAAa,UAAU,qBAAqB;AACzD,aAAK,iBAAiB;AAAA,MACxB;AAGA,YAAM,eAAe,OAAO,eAAe,EAAE,CAAC,GAAG,YAAY,GAAG,gBAAgB;AAEhF,YAAM,cACJ,QAAQ,eAAe,KAAK,MAAM,KAAK,MAAM,eAAe,KAAK,MAAM,mBAAmB;AAG5F,YAAM,SAAS,QAAQ,wBAAwB,MAAM;AACrD,YAAM,cAAc,QAAQ,uBAAuB,uBAAuB;AAAA,QACxE;AAAA,QACA,kBAAkB;AAAA,MACpB,CAAC;AAGD,YAAM,aAAa,OAAO,eAAe,EAAE,CAAC,KAAK;AACjD,YAAM,eAAe,aACjB,MAAM;AACJ,YAAI,KAAK,UAAU,IAAI,OAAO,GAAG;AAC/B,eAAK,cAAc,OAAO;AAAA,QAC5B;AAAA,MACF,IACA;AAEJ,YAAM,UAA4B;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,MAAM,KAAK,EAAE,QAAQ,aAAa,GAAG,MAAM,CAAC,CAAC;AAAA,QACrD,cAAc;AAAA,QACd,OAAO,MAAM;AAAA,UAAK,EAAE,QAAQ,aAAa;AAAA,UAAG,MAC1C,SAAS,IAAI,IAAI,UAAU,CAAC,IAAI,IAAI,WAAW,CAAC;AAAA,QAClD;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,gBAAgB;AAAA,QAChB,eAAe;AAAA,QACf,aAAa;AAAA,MACf;AACA,WAAK,UAAU,IAAI,SAAS,OAAO;AAGnC,kBAAY,KAAK,YAAY,CAAC,MAAoB;AAChD,aAAK,kBAAkB,SAAS,EAAE,IAAI;AAAA,MACxC;AACA,aAAO,QAAQ,WAAW;AAC1B,kBAAY,KAAK,YAAY,EAAE,SAAS,SAAS,aAAa,CAAC;AAG/D,UAAI,cAAc,cAAc;AAC9B,mBAAW,iBAAiB,SAAS,YAAY;AAAA,MACnD;AAEA,WAAK,MAAM;AAAA,QACT,IAAI,YAAqC,uBAAuB;AAAA,UAC9D,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,OAAO;AAAA,QAC5B,CAAC;AAAA,MACH;AAEA,WAAK,MAAM,cAAc;AAAA,IAC3B,SAAS,KAAK;AAEZ,WAAK,gBAAgB,OAAO;AAC5B,cAAQ,KAAK,+DAA+D,OAAO,GAAG,CAAC;AACvF,WAAK,MAAM;AAAA,QACT,IAAI,YAAqC,uBAAuB;AAAA,UAC9D,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,OAAO,IAAI;AAAA,QAChC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEA,cAAc,SAAwB;AACpC,UAAM,KAAK,WAAW,CAAC,GAAG,KAAK,UAAU,KAAK,CAAC,EAAE,CAAC;AAClD,QAAI,CAAC,GAAI;AAET,UAAM,UAAU,KAAK,UAAU,IAAI,EAAE;AACrC,QAAI,CAAC,QAAS;AAGd,YAAQ,YAAY,KAAK,YAAY,EAAE,SAAS,OAAO,CAAC;AACxD,YAAQ,OAAO,WAAW;AAC1B,YAAQ,YAAY,WAAW;AAG/B,SAAK,0BAA0B,OAAO;AAGtC,QAAI,QAAQ,iBAAiB,GAAG;AAC9B,cAAQ,KAAK,uDAAuD;AACpE,WAAK,UAAU,OAAO,EAAE;AACxB,WAAK,MAAM,cAAc;AAEzB,WAAK,MAAM;AAAA,QACT,IAAI,YAAqC,uBAAuB;AAAA,UAC9D,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,IAAI,OAAO,IAAI,MAAM,wBAAwB,EAAE;AAAA,QACpE,CAAC;AAAA,MACH;AACA;AAAA,IACF;AACA,UAAM,UAAU,iBAAiB,EAAE;AACnC,UAAM,cAAc,QAAQ,OAAO,IAAI,CAAC,aAAa,qBAAqB,QAAQ,CAAC;AACnF,UAAM,cAAc;AAAA,MAClB;AAAA,MACA;AAAA,MACA,KAAK,MAAM;AAAA,MACX,QAAQ;AAAA,IACV;AACA,UAAM,kBAAkB,YAAY;AAGpC,UAAM,QAAQ,IAAI,YAAwC,0BAA0B;AAAA,MAClF,SAAS;AAAA,MACT,UAAU;AAAA,MACV,YAAY;AAAA,MACZ,QAAQ;AAAA,QACN,SAAS;AAAA,QACT;AAAA,QACA,aAAa,QAAQ;AAAA,QACrB;AAAA,MACF;AAAA,IACF,CAAC;AACD,UAAM,eAAe,KAAK,MAAM,cAAc,KAAK;AAGnD,SAAK,UAAU,OAAO,EAAE;AACxB,SAAK,MAAM,cAAc;AAEzB,QAAI,cAAc;AAChB,WAAK,yBAAyB,IAAI,aAAa,QAAQ,aAAa,eAAe;AAAA,IACrF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,SAAiB,MAAe;AACxD,UAAM,UAAU,KAAK,UAAU,IAAI,OAAO;AAC1C,QAAI,CAAC,QAAS;AAEd,UAAM,EAAE,SAAS,IAAI;AACrB,QAAI,CAAC,YAAY,SAAS,WAAW,KAAK,CAAC,SAAS,CAAC,EAAG;AAGxD,UAAM,yBAAyB,QAAQ;AAGvC,aAAS,KAAK,GAAG,KAAK,QAAQ,cAAc,MAAM;AAChD,UAAI,SAAS,EAAE,GAAG;AAChB,gBAAQ,OAAO,EAAE,EAAE,KAAK,SAAS,EAAE,CAAC;AAAA,MACtC;AAAA,IACF;AACA,YAAQ,gBAAgB,SAAS,CAAC,EAAE;AAGpC,aAAS,KAAK,GAAG,KAAK,QAAQ,cAAc,MAAM;AAChD,UAAI,CAAC,SAAS,EAAE,EAAG;AACnB,YAAM,eAAe,KAAK,MAAM,QAAQ,MAAM,EAAE,EAAE,SAAS,CAAC;AAC5D,MAAC,QAAQ,MAAqC,EAAE,IAAI;AAAA,QAClD,QAAQ,MAAM,EAAE;AAAA,QAChB,SAAS,EAAE;AAAA,QACX,KAAK,MAAM;AAAA,QACX;AAAA,QACA,QAAQ;AAAA,MACV;AACA,YAAM,eAAe,KAAK,MAAM,QAAQ,MAAM,EAAE,EAAE,SAAS,CAAC;AAG5D,YAAM,mBAAmB,sCAAsC,OAAO,8BAA8B,EAAE;AACtG,YAAM,aAAa,KAAK,MAAM,YAAY,cAAc,gBAAgB;AACxE,UAAI,YAAY;AACd,YAAI,QAAQ,gBAAgB;AAC1B,qBAAW,QAAQ,QAAQ,MAAM,EAAE;AAAA,QACrC,OAAO;AACL,qBAAW,cAAc,QAAQ,MAAM,EAAE,CAAC;AAC1C,qBAAW,YAAY,KAAK,IAAI,GAAG,eAAe,CAAC,GAAG,YAAY;AAAA,QACpE;AAAA,MACF;AAAA,IACF;AAEA,YAAQ,iBAAiB;AAGzB,UAAM,gBAAgB,KAAK,MAAM,QAAQ,eAAe,KAAK,MAAM,eAAe;AAClF,UAAM,gBAAgB,KAAK;AAAA,OACxB,QAAQ,eAAe,SAAS,CAAC,EAAE,UAAU,KAAK,MAAM;AAAA,IAC3D;AACA,QAAI,gBAAgB,eAAe;AACjC,WAAK,MAAM,cAAc;AAAA,IAC3B;AAAA,EACF;AAAA,EAEQ,yBACN,SACA,aACA,aACA,iBACA;AACA,QAAI,OAAO,KAAK,MAAM,qBAAqB,YAAY;AACrD,WAAK,MAAM,iBAAiB,SAAS,aAAa,aAAa,eAAe;AAAA,IAChF,OAAO;AACL,cAAQ;AAAA,QACN,gHACE,UACA;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,0BAA0B,SAA2B;AAC3D,QAAI,QAAQ,eAAe,QAAQ,eAAe;AAChD,cAAQ,YAAY,oBAAoB,SAAS,QAAQ,aAAa;AAAA,IACxE;AAAA,EACF;AAAA,EAEQ,gBAAgB,SAAiB;AACvC,UAAM,UAAU,KAAK,UAAU,IAAI,OAAO;AAC1C,QAAI,CAAC,QAAS;AACd,QAAI;AACF,WAAK,0BAA0B,OAAO;AACtC,cAAQ,YAAY,KAAK,YAAY,EAAE,SAAS,OAAO,CAAC;AACxD,cAAQ,OAAO,WAAW;AAC1B,cAAQ,YAAY,WAAW;AAAA,IACjC,SAAS,KAAK;AACZ,cAAQ;AAAA,QACN,+EACE,UACA,QACA,OAAO,GAAG;AAAA,MACd;AAAA,IACF;AACA,SAAK,UAAU,OAAO,OAAO;AAAA,EAC/B;AACF;;;AC/VA,SAAS,uBAAuB;AA6BzB,IAAM,iBAAN,MAAqB;AAAA,EAQ1B,YAAY,MAA0B;AANtC,SAAQ,cAAc;AACtB,SAAQ,eAAe;AACvB,SAAQ,YAAgC;AAExC;AAAA,SAAQ,gBAAgC;AAiBxC,yBAAgB,CAAC,MAAoB;AACnC,WAAK,YAAY,KAAK,MAAM,YAAY,cAAc,WAAW;AACjE,UAAI,CAAC,KAAK,UAAW;AAErB,WAAK,gBAAgB,KAAK,UAAU,sBAAsB;AAC1D,WAAK,eAAe,KAAK,eAAe,CAAC;AACzC,WAAK,cAAc;AAEnB,WAAK,UAAU,kBAAkB,EAAE,SAAS;AAC5C,WAAK,UAAU,iBAAiB,eAAe,KAAK,cAAc;AAClE,WAAK,UAAU,iBAAiB,aAAa,KAAK,YAAY;AAAA,IAChE;AAEA,SAAQ,iBAAiB,CAAC,MAAoB;AAC5C,UAAI,CAAC,KAAK,UAAW;AAErB,YAAM,YAAY,KAAK,eAAe,CAAC;AAEvC,UAAI,CAAC,KAAK,eAAe,KAAK,IAAI,YAAY,KAAK,YAAY,IAAI,GAAG;AACpE,aAAK,cAAc;AAAA,MACrB;AAEA,UAAI,KAAK,aAAa;AACpB,cAAM,IAAI,KAAK;AACf,cAAM,YAAY;AAAA,UAChB,KAAK;AAAA,UACL,EAAE;AAAA,UACF,EAAE;AAAA,QACJ;AACA,cAAM,UAAU,gBAAgB,WAAW,EAAE,iBAAiB,EAAE,mBAAmB;AAGnF,UAAE,sBAAsB,KAAK,IAAI,WAAW,OAAO;AACnD,UAAE,oBAAoB,KAAK,IAAI,WAAW,OAAO;AACjD,cAAM,MAAM,EAAE,YAAY,cAAc,eAAe;AAGvD,YAAI,KAAK;AACP,cAAI,UAAW,EAAE,sBAAsB,EAAE,sBAAuB,EAAE;AAClE,cAAI,QAAS,EAAE,oBAAoB,EAAE,sBAAuB,EAAE;AAAA,QAChE;AAAA,MACF;AAAA,IACF;AAEA,SAAQ,eAAe,CAAC,MAAoB;AAC1C,UAAI,CAAC,KAAK,UAAW;AAErB,UAAI;AACF,aAAK,UAAU,sBAAsB,EAAE,SAAS;AAAA,MAClD,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,uEAAuE,OAAO,GAAG;AAAA,QACnF;AAAA,MACF;AACA,WAAK,UAAU,oBAAoB,eAAe,KAAK,cAAc;AACrE,WAAK,UAAU,oBAAoB,aAAa,KAAK,YAAY;AAEjE,UAAI;AACF,YAAI,KAAK,aAAa;AACpB,eAAK,mBAAmB;AAAA,QAC1B,OAAO;AACL,eAAK,iBAAiB,CAAC;AAAA,QACzB;AAAA,MACF,SAAS,KAAK;AACZ,gBAAQ,KAAK,2CAA2C,OAAO,GAAG,CAAC;AAAA,MACrE,UAAE;AACA,aAAK,cAAc;AACnB,aAAK,YAAY;AACjB,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF;AApFE,SAAK,QAAQ;AAAA,EACf;AAAA,EAEQ,eAAe,GAAyB;AAC9C,QAAI,CAAC,KAAK,eAAe;AACvB,cAAQ,KAAK,4DAA4D;AACzE,aAAO;AAAA,IACT;AAIA,WAAO,EAAE,UAAU,KAAK,cAAc;AAAA,EACxC;AAAA,EA0EQ,qBAAqB;AAC3B,UAAM,IAAI,KAAK;AACf,QAAI,EAAE,SAAS;AACb,QAAE,QAAQ,aAAa,EAAE,qBAAqB,EAAE,iBAAiB;AAAA,IACnE;AACA,MAAE;AAAA,MACA,IAAI,YAAY,iBAAiB;AAAA,QAC/B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,EAAE,kBAAkB;AAAA,MACnE,CAAC;AAAA,IACH;AACA,MAAE,cAAc;AAAA,EAClB;AAAA,EAEQ,iBAAiB,GAAiB;AACxC,UAAM,IAAI,KAAK;AACf,UAAM,KAAK,KAAK,eAAe,CAAC;AAChC,UAAM,OAAO,gBAAgB,IAAI,EAAE,iBAAiB,EAAE,mBAAmB;AAGzE,MAAE,sBAAsB;AACxB,MAAE,oBAAoB;AAGtB,QAAI,KAAK,WAAW;AAClB,YAAM,YAAY,KAAK,UAAU,iBAAiB,YAAY;AAC9D,iBAAW,OAAO,WAAW;AAC3B,cAAM,UAAU,IAAI,sBAAsB;AAC1C,YAAI,EAAE,WAAW,QAAQ,OAAO,EAAE,UAAU,QAAQ,QAAQ;AAC1D,gBAAM,UAAW,IAAoB,QAAQ;AAC7C,cAAI,SAAS;AACX,iBAAK,aAAa,OAAO;AAAA,UAC3B;AACA;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAIA,UAAM,aAAa,EAAE;AAErB,QAAI,EAAE,SAAS;AACb,QAAE,QAAQ,aAAa,GAAG,CAAC;AAC3B,UAAI,YAAY;AAEd,UAAE,QAAQ,KAAK;AACf,UAAE,QAAQ,KAAK,IAAI;AACnB,UAAE,eAAe;AAAA,MACnB,OAAO;AACL,UAAE,QAAQ,KAAK,IAAI;AAAA,MACrB;AAAA,IACF;AAEA,MAAE,eAAe;AACjB,QAAI,CAAC,YAAY;AACf,QAAE,cAAc;AAAA,IAClB;AAEA,MAAE;AAAA,MACA,IAAI,YAAY,YAAY;AAAA,QAC1B,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,KAAK;AAAA,MACjB,CAAC;AAAA,IACH;AACA,MAAE,cAAc;AAAA,EAClB;AAAA,EAEQ,aAAa,SAAiB;AACpC,UAAM,IAAI,KAAK;AACf,QAAI,EAAE,SAAS;AACb,UAAI;AACF,UAAE,QAAQ,YAAY,OAAO;AAAA,MAE/B,SAAS,KAAK;AACZ,gBAAQ;AAAA,UACN,qEAAqE,OAAO,GAAG;AAAA,QACjF;AAEA,UAAE,oBAAoB,OAAO;AAAA,MAC/B;AAAA,IACF,OAAO;AAEL,QAAE,oBAAoB,OAAO;AAAA,IAC/B;AACA,MAAE;AAAA,MACA,IAAI,YAAY,oBAAoB;AAAA,QAClC,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,QAAQ;AAAA,MACpB,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ACrNA,SAAS,uBAAuB,mBAAmB;AAsBnD,eAAsB,UACpB,MACA,OAC0B;AAC1B,MAAI,CAAC,OAAO;AACV,YAAQ,KAAK,gDAAgD;AAC7D,WAAO,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE;AAAA,EAClC;AAEA,QAAM,YAAY,MAAM,KAAK,KAAK;AAClC,QAAM,SAAmB,CAAC;AAC1B,QAAM,SAAgD,CAAC;AAEvD,aAAW,QAAQ,WAAW;AAC5B,QAAI,KAAK,QAAQ,CAAC,KAAK,KAAK,WAAW,QAAQ,GAAG;AAChD,aAAO,KAAK,EAAE,MAAM,OAAO,IAAI,MAAM,0BAA0B,KAAK,IAAI,EAAE,CAAC;AAC3E,cAAQ,KAAK,wCAAwC,KAAK,OAAO,OAAO,KAAK,OAAO,GAAG;AACvF;AAAA,IACF;AAEA,UAAM,UAAU,IAAI,gBAAgB,IAAI;AACxC,QAAI;AACF,YAAM,cAAc,MAAM,KAAK,gBAAgB,OAAO;AACtD,UAAI,gBAAgB,OAAO;AAC3B,WAAK,YAAY,OAAO,OAAO;AAE/B,WAAK,sBAAsB,YAAY;AAEvC,YAAM,OAAO,KAAK,KAAK,QAAQ,UAAU,EAAE;AAC3C,YAAM,OAAO,sBAAsB;AAAA,QACjC;AAAA,QACA,WAAW;AAAA,QACX,UAAU,YAAY;AAAA,QACtB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN;AAAA,QACA,YAAY,YAAY;AAAA,QACxB,gBAAgB,YAAY;AAAA,MAC9B,CAAC;AAED,WAAK,eAAe,IAAI,IAAI,KAAK,YAAY,EAAE,IAAI,KAAK,IAAI,WAAW;AACvE,YAAM,WAAW,MAAM,KAAK,cAAc;AAAA,QACxC;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AACA,WAAK,aAAa,IAAI,IAAI,KAAK,UAAU,EAAE,IAAI,KAAK,IAAI,QAAQ;AAEhE,YAAM,UAAU,OAAO,WAAW;AAClC,YAAM,QAAQ,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;AACjD,YAAM,KAAK;AAEX,WAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE,IAAI,SAAS;AAAA,QAChD;AAAA,QACA,KAAK;AAAA,QACL,QAAQ;AAAA,QACR,KAAK;AAAA,QACL,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,OAAO;AAAA,UACL;AAAA,YACE,KAAK;AAAA,YACL,OAAO;AAAA,YACP,UAAU,YAAY;AAAA,YACtB,QAAQ;AAAA,YACR,MAAM;AAAA,YACN;AAAA,YACA,QAAQ;AAAA,YACR,SAAS;AAAA,YACT,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF,CAAC;AACD,WAAK,gBAAgB,IAAI,IAAI,KAAK,aAAa,EAAE,IAAI,SAAS,KAAK;AACnE,WAAK,mBAAmB;AAExB,YAAM,SAAS,MAAM,KAAK,cAAc;AACxC,aAAO,UAAU,CAAC,GAAG,KAAK,cAAc,OAAO,CAAC,CAAC;AAEjD,aAAO,KAAK,OAAO;AACnB,WAAK;AAAA,QACH,IAAI,YAA8B,mBAAmB;AAAA,UACnD,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,QAAQ;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AACZ,UAAI,gBAAgB,OAAO;AAC3B,cAAQ,KAAK,oCAAoC,KAAK,OAAO,aAAQ,OAAO,GAAG,CAAC;AAChF,aAAO,KAAK,EAAE,MAAM,OAAO,IAAI,CAAC;AAChC,UAAI,KAAK,aAAa;AACpB,aAAK;AAAA,UACH,IAAI,YAAqC,wBAAwB;AAAA,YAC/D,SAAS;AAAA,YACT,UAAU;AAAA,YACV,QAAQ,EAAE,MAAM,OAAO,IAAI;AAAA,UAC7B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,OAAO;AAC1B;;;AC9HA,SAAS,kBAAkB;AAoBpB,SAAS,gBACd,MACA,SACA,KACA,aACA,YACA;AACA,QAAM,OAAO,WAAW;AAAA,IACtB,aAAa;AAAA,IACb;AAAA,IACA,iBAAiB;AAAA,IACjB,eAAe;AAAA,IACf,MAAM;AAAA,IACN,MAAM;AAAA,EACR,CAAC;AACD,OAAK,eAAe,IAAI,IAAI,KAAK,YAAY,EAAE,IAAI,KAAK,IAAI,GAAG;AAC/D,OAAK,cACF,cAAc,KAAK,KAAK,iBAAiB,KAAK,IAAI,EAClD,KAAK,CAAC,OAAO;AACZ,SAAK,aAAa,IAAI,IAAI,KAAK,UAAU,EAAE,IAAI,KAAK,IAAI,EAAE;AAC1D,UAAM,IAAI,KAAK,cAAc,IAAI,OAAO;AACxC,QAAI,CAAC,GAAG;AAEN,YAAM,OAAO,IAAI,IAAI,KAAK,YAAY;AACtC,WAAK,OAAO,KAAK,EAAE;AACnB,WAAK,eAAe;AACpB;AAAA,IACF;AACA,SAAK,gBAAgB,IAAI,IAAI,KAAK,aAAa,EAAE,IAAI,SAAS;AAAA,MAC5D,GAAG;AAAA,MACH,OAAO,CAAC,GAAG,EAAE,OAAO,IAAI;AAAA,IAC1B,CAAC;AAED,UAAM,OAAO,KAAK,QAAQ,IAAI,OAAO;AACrC,QAAI,MAAM;AACR,YAAM,KAAK,KAAK;AAChB,YAAM,WAA2B;AAAA,QAC/B,KAAK;AAAA,QACL,OAAO,cAAc;AAAA,QACrB,UAAU,aAAa;AAAA,QACvB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM;AAAA,QACN,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,MACZ;AACA,WAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE,IAAI,SAAS;AAAA,QAChD,GAAG;AAAA,QACH,OAAO,CAAC,GAAG,KAAK,OAAO,QAAQ;AAAA,MACjC,CAAC;AAAA,IACH;AACA,SAAK,mBAAmB;AACxB,SAAK,SAAS,UAAU,CAAC,GAAG,KAAK,cAAc,OAAO,CAAC,CAAC;AAAA,EAC1D,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,YAAQ,KAAK,2DAA2D,OAAO,GAAG,CAAC;AACnF,UAAM,OAAO,IAAI,IAAI,KAAK,YAAY;AACtC,SAAK,OAAO,KAAK,EAAE;AACnB,SAAK,eAAe;AACpB,QAAI,KAAK,aAAa;AACpB,WAAK;AAAA,QACH,IAAI,YAA4B,aAAa;AAAA,UAC3C,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,WAAW,mBAAmB,OAAO,IAAI;AAAA,QACrD,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,CAAC;AACL;;;AXpEO,IAAM,mBAAN,cAA+BC,YAAW;AAAA,EAA1C;AAAA;AACuD,2BAAkB;AACxB,sBAAa;AACtC,qBAAY;AACZ,gBAAO;AACgB,oBAAW;AACb,kBAAS;AACN,oBAAW;AAEV,sBAAa;AAEnE;AAAA,+BAAqC;AAC5B,mBAAwC,oBAAI,IAAI;AAChD,yBAAwC,oBAAI,IAAI;AAChD,sBAAoC,oBAAI,IAAI;AAC5C,sBAAa;AACb,SAAQ,YAAY;AACpB,4BAAkC;AAClC,qBAAY;AAErB;AAAA,+BAAsB;AACtB,6BAAoB;AACpB,wBAAe;AACf,mBAAiC;AACjC,SAAQ,iBAAiD;AACzD,SAAQ,oBAAoB;AAC5B,uBAAc,oBAAI,IAAkC;AACpD,wBAAe,oBAAI,IAAyB;AAC5C,yBAAgB,IAAI,aAAa;AACjC,SAAQ,iBAAiB,oBAAI,IAA6B;AAC1D,SAAQ,iBAA0C;AAClD,SAAQ,eAAe,IAAI,sBAAsB,IAAI;AAGrD,SAAQ,uBAAuB,IAAI,oBAAoB,IAAI;AAC3D,SAAQ,WAAW,IAAI,eAAe,IAAI;AAC1C,SAAQ,aAAa,MAAM;AACzB,YAAM,IAAI,IAAI,mBAAmB,IAAI;AACrC,QAAE,iBAAiB;AACnB,aAAO;AAAA,IACT,GAAG;AAgJH;AAAA,SAAQ,oBAAoB,CAAC,MAAmB;AAC9C,YAAM,UAAU,EAAE,QAAQ;AAC1B,YAAM,UAAU,EAAE,QAAQ;AAC1B,UAAI,CAAC,WAAW,EAAE,mBAAmB,cAAc;AACjD,gBAAQ,KAAK,yDAAyD,OAAO,EAAE,MAAM,CAAC;AACtF;AAAA,MACF;AACA,YAAM,aAAa,KAAK,qBAAqB,OAA0B;AACvE,WAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE,IAAI,SAAS,UAAU;AAC5D,WAAK,eAAe,IAAI,SAAS,OAA0B;AAC3D,WAAK,WAAW,SAAS,UAAU;AAAA,IACrC;AA6BA,SAAQ,iBAAiB,CAAC,MAAmB;AAC3C,YAAM,UAAU,EAAE,QAAQ;AAC1B,UAAI,CAAC,QAAS;AACd,YAAM,UAAW,EAAE,OAAuB,QAAQ,WAAW;AAC7D,UAAI,CAAC,QAAS;AACd,YAAM,gBAAgB,KAAK,QAAQ,IAAI,OAAO;AAC9C,YAAM,aAAa,KAAK,qBAAqB,OAAO;AACpD,WAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE,IAAI,SAAS,UAAU;AAC5D,UAAI,KAAK,SAAS;AAChB,YAAI,eAAe,WAAW,WAAW;AACvC,eAAK,QAAQ,eAAe,SAAS,WAAW,MAAM;AACxD,YAAI,eAAe,QAAQ,WAAW,IAAK,MAAK,QAAQ,YAAY,SAAS,WAAW,GAAG;AAC3F,YAAI,eAAe,UAAU,WAAW;AACtC,eAAK,QAAQ,aAAa,SAAS,WAAW,KAAK;AACrD,YAAI,eAAe,WAAW,WAAW;AACvC,eAAK,QAAQ,aAAa,SAAS,WAAW,MAAM;AAAA,MACxD;AACA,UAAI,eAAe,QAAQ,WAAW,KAAK;AACzC,aAAK,WAAW,SAAS,UAAU;AAAA,MACrC;AAAA,IACF;AAEA,SAAQ,kBAAkB,CAAC,MAAmB;AAC5C,YAAM,EAAE,SAAS,MAAM,MAAM,IAAI,EAAE,UAAU,CAAC;AAC9C,UAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,iBAAiB,eAAe,IAAI,IAAI,EAAG;AACrE,YAAM,gBAAgB,KAAK,QAAQ,IAAI,OAAO;AAC9C,UAAI,eAAe;AACjB,cAAM,aAAa,EAAE,GAAG,eAAe,CAAC,IAAI,GAAG,MAAM;AACrD,aAAK,UAAU,IAAI,IAAI,KAAK,OAAO,EAAE,IAAI,SAAS,UAAU;AAE5D,YAAI,KAAK,SAAS;AAChB,cAAI,SAAS;AACX,iBAAK,QAAQ,eAAe,SAAS,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC;AAC9E,cAAI,SAAS;AACX,iBAAK,QAAQ,YAAY,SAAS,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC;AAC5E,cAAI,SAAS,QAAS,MAAK,QAAQ,aAAa,SAAS,QAAQ,KAAK,CAAC;AACvE,cAAI,SAAS,SAAU,MAAK,QAAQ,aAAa,SAAS,QAAQ,KAAK,CAAC;AAAA,QAC1E;AAAA,MACF;AAAA,IAGF;AACA,SAAQ,wBAAwB,CAAC,MAAmB;AAClD,YAAM,EAAE,QAAQ,IAAI,EAAE,UAAU,CAAC;AACjC,UAAI,CAAC,QAAS;AACd,YAAM,UAAU,KAAK,eAAe,IAAI,OAAO;AAC/C,UAAI,SAAS;AACX,gBAAQ,OAAO;AAAA,MACjB,OAAO;AACL,aAAK,gBAAgB,OAAO;AAAA,MAC9B;AAAA,IACF;AA4LA;AAAA,SAAQ,cAAc,CAAC,MAAiB;AACtC,UAAI,CAAC,KAAK,SAAU;AACpB,QAAE,eAAe;AACjB,UAAI,EAAE,aAAc,GAAE,aAAa,aAAa;AAChD,WAAK,YAAY;AAAA,IACnB;AACA,SAAQ,eAAe,CAAC,MAAiB;AACvC,UAAI,CAAC,KAAK,SAAU;AAGpB,YAAM,WAAW,KAAK,YAAY,cAAc,WAAW;AAC3D,UAAI,YAAY,CAAC,SAAS,SAAS,EAAE,aAAqB,GAAG;AAC3D,aAAK,YAAY;AAAA,MACnB;AAAA,IACF;AACA,SAAQ,UAAU,OAAO,MAAiB;AACxC,UAAI,CAAC,KAAK,SAAU;AACpB,QAAE,eAAe;AACjB,WAAK,YAAY;AACjB,YAAM,QAAQ,EAAE,cAAc;AAC9B,UAAI,CAAC,SAAS,MAAM,WAAW,EAAG;AAClC,UAAI;AACF,cAAM,KAAK,UAAU,KAAK;AAAA,MAC5B,SAAS,KAAK;AACZ,gBAAQ,KAAK,iCAAiC,OAAO,GAAG,CAAC;AACzD,aAAK;AAAA,UACH,IAAI,YAA4B,aAAa;AAAA,YAC3C,SAAS;AAAA,YACT,UAAU;AAAA,YACV,QAAQ,EAAE,WAAW,aAAa,OAAO,IAAI;AAAA,UAC/C,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AA6CA;AAAA,2BAAsC;AAAA;AAAA,EA5ctC,IAAI,sBAA8B;AAChC,WAAO,KAAK,uBAAuB,KAAK;AAAA,EAC1C;AAAA,EACA,8BAA8B,MAAc;AAC1C,QAAI,CAAC,KAAK,oBAAqB,MAAK,sBAAsB;AAAA,EAC5D;AAAA,EACA,IAAY,cAAsB;AAChC,WAAO,KAAK,KAAM,KAAK,YAAY,KAAK,sBAAuB,KAAK,eAAe;AAAA,EACrF;AAAA,EACA,oBAAoB,SAAwB;AAC1C,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EACA,IAAI,SAA4B;AAC9B,WAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC;AAAA,EAClC;AAAA,EACA,IAAI,kBAAiC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA,EACA,IAAI,YAAmD;AACrD,QAAI,KAAK,wBAAwB,KAAK,KAAK,sBAAsB,EAAG,QAAO;AAC3E,WAAO,EAAE,OAAO,KAAK,qBAAqB,KAAK,KAAK,kBAAkB;AAAA,EACxE;AAAA,EACA,aAAa,OAAe,KAAa;AACvC,SAAK,sBAAsB,KAAK,IAAI,OAAO,GAAG;AAC9C,SAAK,oBAAoB,KAAK,IAAI,OAAO,GAAG;AAC5C,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,aAAa,KAAK,qBAAqB,KAAK,iBAAiB;AAAA,IAC5E;AACA,SAAK,cAAc;AACnB,SAAK;AAAA,MACH,IAAI,YAAgC,iBAAiB;AAAA,QACnD,SAAS;AAAA,QACT,UAAU;AAAA,QACV,QAAQ,EAAE,OAAO,KAAK,qBAAqB,KAAK,KAAK,kBAAkB;AAAA,MACzE,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAEA,oBAAoB;AAClB,UAAM,kBAAkB;AACxB,SAAK,iBAAiB,uBAAuB,KAAK,iBAAkC;AACpF,SAAK,iBAAiB,oBAAoB,KAAK,cAA+B;AAC9E,SAAK,iBAAiB,qBAAqB,KAAK,eAAgC;AAChF,SAAK,iBAAiB,oBAAoB,KAAK,qBAAsC;AAErF,SAAK,iBAAiB,IAAI,iBAAiB,CAAC,cAAc;AACxD,iBAAW,YAAY,WAAW;AAChC,mBAAW,QAAQ,SAAS,cAAc;AACxC,cAAI,gBAAgB,aAAa;AAC/B,gBAAI,KAAK,YAAY,aAAa;AAChC,mBAAK,gBAAiB,KAAyB,OAAO;AAAA,YACxD;AACA,kBAAM,SAAS,KAAK,mBAAmB,WAAW;AAClD,gBAAI,QAAQ;AACV,yBAAW,SAAS,QAAQ;AAC1B,qBAAK,gBAAiB,MAA0B,OAAO;AAAA,cACzD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AACD,SAAK,eAAe,QAAQ,MAAM,EAAE,WAAW,MAAM,SAAS,KAAK,CAAC;AAAA,EACtE;AAAA,EACA,uBAAuB;AACrB,UAAM,qBAAqB;AAC3B,SAAK,oBAAoB,uBAAuB,KAAK,iBAAkC;AACvF,SAAK,oBAAoB,oBAAoB,KAAK,cAA+B;AACjF,SAAK,oBAAoB,qBAAqB,KAAK,eAAgC;AACnF,SAAK,oBAAoB,oBAAoB,KAAK,qBAAsC;AACxF,SAAK,gBAAgB,WAAW;AAChC,SAAK,iBAAiB;AACtB,SAAK,eAAe,MAAM;AAC1B,SAAK,YAAY,MAAM;AACvB,SAAK,aAAa,MAAM;AACxB,SAAK,cAAc,UAAU;AAC7B,QAAI;AACF,WAAK,eAAe;AAAA,IACtB,SAAS,KAAK;AACZ,cAAQ,KAAK,uCAAuC,OAAO,GAAG,CAAC;AAAA,IACjE;AAAA,EACF;AAAA,EACA,WAAW,mBAAyC;AAClD,QAAI,kBAAkB,IAAI,aAAa,GAAG;AACxC,WAAK,aAAa,SAAS,KAAK;AAAA,IAClC;AAEA,QAAI,kBAAkB,IAAI,iBAAiB,KAAK,KAAK,aAAa,OAAO,GAAG;AAC1E,YAAM,cAAc,KAAK,cAAc;AAAA,QACrC,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AACA,UAAI,YAAY,OAAO,GAAG;AACxB,cAAM,OAAO,IAAI,IAAI,KAAK,UAAU;AACpC,mBAAW,CAAC,QAAQ,QAAQ,KAAK,aAAa;AAC5C,eAAK,IAAI,QAAQ,QAAQ;AAAA,QAC3B;AACA,aAAK,aAAa;AAAA,MACpB;AAAA,IACF;AAAA,EACF;AAAA,EAcQ,gBAAgB,SAAiB;AACvC,SAAK,eAAe,OAAO,OAAO;AAElC,UAAM,eAAe,KAAK,cAAc,IAAI,OAAO;AACnD,QAAI,cAAc;AAChB,YAAM,YAAY,IAAI,IAAI,KAAK,UAAU;AACzC,iBAAW,QAAQ,aAAa,OAAO;AACrC,aAAK,aAAa,OAAO,KAAK,EAAE;AAChC,kBAAU,OAAO,KAAK,EAAE;AAAA,MAC1B;AACA,WAAK,aAAa;AAAA,IACpB;AACA,UAAM,aAAa,IAAI,IAAI,KAAK,OAAO;AACvC,eAAW,OAAO,OAAO;AACzB,SAAK,UAAU;AACf,UAAM,aAAa,IAAI,IAAI,KAAK,aAAa;AAC7C,eAAW,OAAO,OAAO;AACzB,SAAK,gBAAgB;AACrB,SAAK,mBAAmB;AACxB,QAAI,KAAK,SAAS;AAEhB,WAAK,QAAQ,YAAY,OAAO;AAAA,IAClC;AACA,QAAI,WAAW,SAAS,GAAG;AACzB,WAAK,eAAe;AACpB,WAAK,cAAc;AAAA,IACrB;AAAA,EACF;AAAA,EAqDQ,qBAAqB,SAA2C;AACtE,UAAM,UAAU,QAAQ,iBAAiB,UAAU;AACnD,UAAM,QAA0B,CAAC;AAEjC,QAAI,QAAQ,WAAW,KAAK,QAAQ,KAAK;AACvC,YAAM,KAAK;AAAA,QACT,KAAK,QAAQ;AAAA,QACb,OAAO;AAAA,QACP,UAAU;AAAA,QACV,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,QAAQ,QAAQ;AAAA,QACtB,QAAQ;AAAA,QACR,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH,OAAO;AACL,iBAAW,UAAU,SAAS;AAC5B,cAAM,KAAK;AAAA,UACT,KAAK,OAAO;AAAA,UACZ,OAAO,OAAO;AAAA,UACd,UAAU,OAAO;AAAA,UACjB,QAAQ,OAAO;AAAA,UACf,MAAM,OAAO;AAAA,UACb,MAAM,OAAO;AAAA,UACb,QAAQ,OAAO;AAAA,UACf,SAAS,OAAO;AAAA,UAChB,UAAU,OAAO;AAAA,QACnB,CAAC;AAAA,MACH;AAAA,IACF;AACA,WAAO;AAAA,MACL,MAAM,QAAQ,QAAQ;AAAA,MACtB,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ;AAAA,MAChB,KAAK,QAAQ;AAAA,MACb,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAEA,MAAc,WAAW,SAAiB,YAA6B;AACrE,QAAI;AACF,YAAM,QAAQ,CAAC;AACf,iBAAW,YAAY,WAAW,OAAO;AACvC,YAAI,CAAC,SAAS,IAAK;AACnB,cAAM,cAAc,MAAM,KAAK,gBAAgB,SAAS,GAAG;AAE3D,aAAK,sBAAsB,YAAY;AACvC,cAAM,OAAOC,uBAAsB;AAAA,UACjC;AAAA,UACA,WAAW,SAAS;AAAA,UACpB,UAAU,SAAS,YAAY,YAAY;AAAA,UAC3C,QAAQ,SAAS;AAAA,UACjB,MAAM,SAAS;AAAA,UACf,MAAM,SAAS;AAAA,UACf,YAAY,YAAY;AAAA,UACxB,gBAAgB,YAAY;AAAA,QAC9B,CAAC;AAED,aAAK,eAAe,IAAI,IAAI,KAAK,YAAY,EAAE,IAAI,KAAK,IAAI,WAAW;AACvE,cAAM,WAAW,MAAM,KAAK,cAAc;AAAA,UACxC;AAAA,UACA,KAAK;AAAA,UACL,KAAK;AAAA,QACP;AACA,aAAK,aAAa,IAAI,IAAI,KAAK,UAAU,EAAE,IAAI,KAAK,IAAI,QAAQ;AAChE,cAAM,KAAK,IAAI;AAAA,MACjB;AACA,YAAM,QAAQC,aAAY;AAAA,QACxB,MAAM,WAAW;AAAA,QACjB;AAAA,QACA,QAAQ,WAAW;AAAA,QACnB,KAAK,WAAW;AAAA,QAChB,OAAO,WAAW;AAAA,QAClB,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,YAAM,KAAK;AACX,WAAK,gBAAgB,IAAI,IAAI,KAAK,aAAa,EAAE,IAAI,SAAS,KAAK;AACnE,WAAK,mBAAmB;AACxB,YAAM,SAAS,MAAM,KAAK,cAAc;AACxC,aAAO,UAAU,CAAC,GAAG,KAAK,cAAc,OAAO,CAAC,CAAC;AACjD,WAAK;AAAA,QACH,IAAI,YAA8B,mBAAmB;AAAA,UACnD,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,QAAQ;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF,SAAS,KAAK;AAEZ,UAAI,CAAC,KAAK,YAAa;AACvB,cAAQ,KAAK,qCAAqC,UAAU,QAAQ,OAAO,GAAG,CAAC;AAC/E,WAAK;AAAA,QACH,IAAI,YAAiC,mBAAmB;AAAA,UACtD,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,SAAS,OAAO,IAAI;AAAA,QAChC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM,gBAAgB,KAAmC;AACvD,QAAI,KAAK,YAAY,IAAI,GAAG,GAAG;AAC7B,aAAO,KAAK,YAAY,IAAI,GAAG;AAAA,IACjC;AACA,UAAM,WAAW,YAAY;AAC3B,YAAM,WAAW,MAAM,MAAM,GAAG;AAChC,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI;AAAA,UACR,4BAA4B,MAAM,QAAQ,SAAS,SAAS,MAAM,SAAS;AAAA,QAC7E;AAAA,MACF;AACA,YAAM,cAAc,MAAM,SAAS,YAAY;AAE/C,YAAM,EAAE,sBAAsB,IAAI,MAAM,OAAO,4BAA4B;AAC3E,aAAO,sBAAsB,EAAE,gBAAgB,WAAW;AAAA,IAC5D,GAAG;AACH,SAAK,YAAY,IAAI,KAAK,OAAO;AACjC,QAAI;AACF,aAAO,MAAM;AAAA,IACf,SAAS,KAAK;AACZ,WAAK,YAAY,OAAO,GAAG;AAC3B,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EACA,qBAAqB;AACnB,QAAI,YAAY;AAChB,eAAW,SAAS,KAAK,cAAc,OAAO,GAAG;AAC/C,iBAAW,QAAQ,MAAM,OAAO;AAC9B,cAAM,YAAY,KAAK,cAAc,KAAK;AAC1C,YAAI,YAAY,UAAW,aAAY;AAAA,MACzC;AAAA,IACF;AACA,SAAK,YAAY,YAAY,KAAK;AAAA,EACpC;AAAA;AAAA,EAEA,gBAAyC;AACvC,QAAI,KAAK,QAAS,QAAO,QAAQ,QAAQ,KAAK,OAAO;AACrD,QAAI,KAAK,eAAgB,QAAO,KAAK;AACrC,SAAK,iBAAiB,KAAK,aAAa,EAAE,MAAM,CAAC,QAAQ;AACvD,WAAK,iBAAiB;AACtB,YAAM;AAAA,IACR,CAAC;AACD,WAAO,KAAK;AAAA,EACd;AAAA,EACA,MAAc,eAAe;AAC3B,UAAM,CAAC,EAAE,eAAe,GAAG,EAAE,kBAAkB,CAAC,IAAI,MAAM,QAAQ,IAAI;AAAA,MACpE,OAAO,2BAA2B;AAAA,MAClC,OAAO,4BAA4B;AAAA,IACrC,CAAC;AAED,UAAM,UAAU,kBAAkB;AAClC,UAAM,SAAS,IAAI,eAAe;AAAA,MAChC;AAAA,MACA,YAAY,KAAK;AAAA,MACjB,iBAAiB,KAAK;AAAA,MACtB,YAAY,CAAC,KAAK,KAAK,MAAM,MAAM,MAAM,MAAM,KAAK,eAAe,EAChE,OAAO,CAAC,GAAG,GAAG,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EACtC,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAAA,IACzB,CAAC;AACD,WAAO,GAAG,eAAe,CAAC,gBAAgB;AACxC,WAAK,aAAa,YAAY;AAC9B,WAAK,YAAY,YAAY;AAC7B,WAAK,mBAAmB,YAAY;AAAA,IACtC,CAAC;AACD,WAAO,GAAG,cAAc,CAAC,SAAiB;AACxC,WAAK,eAAe;AAAA,IACtB,CAAC;AACD,WAAO,GAAG,QAAQ,MAAM;AACtB,WAAK,eAAe,OAAO,eAAe;AAC1C,WAAK,cAAc;AAAA,IACrB,CAAC;AAED,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA,EACQ,iBAAiB;AACvB,QAAI,KAAK,SAAS;AAChB,WAAK,QAAQ,QAAQ;AACrB,WAAK,UAAU;AAAA,IACjB;AACA,SAAK,iBAAiB;AAAA,EACxB;AAAA,EAoCA,MAAM,UAAU,OAAoD;AAClE,WAAO,UAAc,MAAM,KAAK;AAAA,EAClC;AAAA;AAAA,EAEA,MAAM,OAAO;AACX,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,cAAc;AACxC,UAAI,CAAC,KAAK,mBAAmB;AAC3B,cAAM,OAAO,KAAK;AAClB,aAAK,oBAAoB;AAAA,MAC3B;AACA,aAAO,KAAK;AACZ,WAAK,eAAe;AACpB,WAAK,cAAc,IAAI,YAAY,YAAY,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,IACnF,SAAS,KAAK;AACZ,cAAQ,KAAK,gCAAgC,OAAO,GAAG,CAAC;AACxD,WAAK;AAAA,QACH,IAAI,YAA4B,aAAa;AAAA,UAC3C,SAAS;AAAA,UACT,UAAU;AAAA,UACV,QAAQ,EAAE,WAAW,QAAQ,OAAO,IAAI;AAAA,QAC1C,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EACA,QAAQ;AACN,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,QAAQ,MAAM;AACnB,SAAK,cAAc;AACnB,SAAK,cAAc,IAAI,YAAY,aAAa,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EACpF;AAAA,EACA,OAAO;AACL,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,QAAQ,KAAK;AAClB,SAAK,cAAc;AACnB,SAAK,cAAc,IAAI,YAAY,YAAY,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,EACnF;AAAA,EACA,OAAO,MAAc;AACnB,QAAI,CAAC,KAAK,QAAS;AACnB,SAAK,QAAQ,KAAK,IAAI;AACtB,SAAK,eAAe;AAAA,EACtB;AAAA,EAIA,IAAI,cAAuB;AACzB,WAAO,KAAK,qBAAqB;AAAA,EACnC;AAAA,EACA,gBAAsB;AACpB,SAAK,qBAAqB,cAAc;AAAA,EAC1C;AAAA,EACA,iBAAiB,SAAiB,KAAkB,aAAqB,YAAoB;AAC3F,oBAAgB,MAAM,SAAS,KAAK,aAAa,UAAU;AAAA,EAC7D;AAAA,EACA,MAAM,eAAe,QAAsB,SAA2C;AACpF,UAAM,IAAI,UAAU,KAAK;AACzB,QAAI,CAAC,GAAG;AACN,cAAQ,KAAK,0EAA0E;AACvF;AAAA,IACF;AACA,UAAM,KAAK,qBAAqB,eAAe,GAAG,OAAO;AAAA,EAC3D;AAAA,EAEQ,wBAAwB,SAAiB,KAAa;AAC5D,UAAM,KAAK,KAAK,qBAAqB,WAAW,OAAO;AACvD,QAAI,CAAC,GAAI,QAAO;AAChB,UAAM,OAAO,KAAK,MAAM,GAAG,cAAc,KAAK,eAAe;AAC7D,UAAM,IAAI,KAAK,MAAM,GAAG,eAAe,KAAK,eAAe;AAC3D,WAAO,GAAG,MAAM;AAAA,MACd,CAAC,SAAS,OAAOC;AAAA;AAAA,iCAEU,OAAO;AAAA,mCACL,EAAE;AAAA,0CACK,IAAI,UAAU,KAAK,GAAG;AAAA,mBAC7C,OAAO;AAAA,oBACN,CAAC;AAAA,wBACG,GAAG;AAAA,sBACL,KAAK,QAAQ;AAAA,oBACf,KAAK,MAAM;AAAA,0BACL,KAAK,UAAU,YAAY;AAAA,wBAC7B,KAAK,UAAU,UAAU;AAAA,qBAC5B,IAAI;AAAA;AAAA;AAAA,IAGrB;AAAA,EACF;AAAA;AAAA,EAGA,iBAAiB;AACf,UAAM,WAAW,KAAK,aAAa;AACnC,QAAI,CAAC,YAAY,CAAC,KAAK,QAAS;AAChC,UAAM,SAAS,KAAK;AACpB,aAAS;AAAA,MACP,MAAM,OAAO,eAAe;AAAA,MAC5B,KAAK;AAAA,MACL,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,gBAAgB;AACd,UAAM,WAAW,KAAK,aAAa;AACnC,QAAI,CAAC,SAAU;AACf,aAAS,cAAc,KAAK,cAAc,KAAK,qBAAqB,KAAK,eAAe;AAAA,EAC1F;AAAA,EACQ,eAA0C;AAChD,WAAO,KAAK,YAAY,cAAc,cAAc;AAAA,EACtD;AAAA,EACQ,oBAAgD;AACtD,UAAM,WAAqB,CAAC,GAAG,KAAK,iBAAiB,WAAW,CAAC,EAAE;AAAA,MACjE,CAAC,OAAQ,GAAuB;AAAA,IAClC;AACA,WAAO,CAAC,GAAG,KAAK,cAAc,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM;AACtD,YAAM,KAAK,SAAS,QAAQ,EAAE,CAAC,CAAC;AAChC,YAAM,KAAK,SAAS,QAAQ,EAAE,CAAC,CAAC;AAEhC,UAAI,OAAO,MAAM,OAAO,GAAI,QAAO;AAEnC,UAAI,OAAO,GAAI,QAAO;AACtB,UAAI,OAAO,GAAI,QAAO;AACtB,aAAO,KAAK;AAAA,IACd,CAAC;AAAA,EACH;AAAA;AAAA,EAGA,SAAS;AACP,UAAM,KAAK,KAAK;AAChB,UAAM,aAAc,KAAK,sBAAsB,KAAM,KAAK;AAC1D,UAAM,WAAY,KAAK,oBAAoB,KAAM,KAAK;AAGtD,UAAM,gBAAgB,KAAK,kBAAkB,EAAE,IAAI,CAAC,CAAC,SAAS,KAAK,MAAM;AACvE,YAAM,aAAa,KAAK,QAAQ,IAAI,OAAO;AAC3C,YAAM,aAAa,MAAM,MACtB,IAAI,CAAC,MAAM,KAAK,WAAW,IAAI,EAAE,EAAE,CAAC,EACpC,KAAK,CAAC,MAAM,KAAK,EAAE,KAAK,SAAS,CAAC;AACrC,YAAM,cAAc,aAAa,WAAW,KAAK,SAAS;AAC1D,aAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,KAAK,aAAa;AAAA,MACjC;AAAA,IACF,CAAC;AAED,WAAOA;AAAA,QACH,cAAc,SAAS,IACrBA;AAAA,cACI,KAAK,YAAYA,2CAA0C,EAAE;AAAA,cAC7D,cAAc;AAAA,MACd,CAAC,MAAMA;AAAA;AAAA,mCAEc,EAAE,WAAW;AAAA,6BACnB,EAAE,OAAO;AAAA,+BACP,EAAE,YAAY,QAAQ,UAAU;AAAA,4BACnC,EAAE,YAAY,UAAU,CAAC;AAAA,yBAC5B,EAAE,YAAY,OAAO,CAAC;AAAA,2BACpB,EAAE,YAAY,SAAS,KAAK;AAAA,4BAC3B,EAAE,YAAY,UAAU,KAAK;AAAA;AAAA;AAAA,IAG7C,CAAC;AAAA,oBAEH,EAAE;AAAA;AAAA;AAAA,4BAGgB,KAAK,YAAY,cAAc,EAAE;AAAA,0BACnC,KAAK,cAAc,IAAI,KAAK,cAAc,OAAO,MAAM;AAAA,yBACxD,KAAK,UAAU;AAAA,yBACf,KAAK,SAAS,aAAa;AAAA,sBAC9B,KAAK,WAAW;AAAA,uBACf,KAAK,YAAY;AAAA,kBACtB,KAAK,OAAO;AAAA;AAAA,YAElB,cAAc,SAAS,KAAK,KAAK,YAC/BA;AAAA,mCACqB,KAAK,eAAe;AAAA,8BACzB,KAAK,mBAAmB;AAAA,4BAC1B,KAAK,SAAS;AAAA,+BAE5B,EAAE;AAAA,YACJ,cAAc,SAAS,IACrBA,gCAA+B,UAAU,WAAW,QAAQ;AAAA,iDAE5D,EAAE;AAAA,YACJ,cAAc,IAAI,CAAC,MAAM;AACzB,YAAM,gBAAgB,KAAK;AAC3B,aAAOA;AAAA;AAAA,mCAEgB,EAAE,YAAY,KAAK,mBAAmB,aAAa,EAAE;AAAA,iCACvD,EAAE,WAAW;AAAA,gCACd,EAAE,OAAO;AAAA;AAAA,kBAEvB,EAAE,MAAM,MAAM,IAAI,CAAC,SAAS;AAC5B,cAAM,WAAW,KAAK,WAAW,IAAI,KAAK,EAAE;AAC5C,cAAM,QAAQ;AAAA,UACZ,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK;AAAA,QACP;AACA,cAAM,WAAW,KAAK,MAAM,KAAK,cAAc,KAAK,eAAe;AACnE,cAAM,WAAoB,UAAU,QAAQ,CAAC,IAAI,WAAW,CAAC,CAAC;AAC9D,eAAO,SAAS;AAAA,UACd,CAAC,cAAc,UAAUA;AAAA;AAAA,2DAEc,QAAQ,YAAY,QACvD,aAAa;AAAA,iCACJ,YAAY;AAAA,kCACX,UAAU,UAAU,KAAK;AAAA,sCACrB,aAAa;AAAA,oCACf,KAAK,QAAQ;AAAA,kCACf,KAAK,MAAM;AAAA,wCACL,KAAK,UAAU,YAAY;AAAA,sCAC7B,KAAK,UAAU,UAAU;AAAA,mCAC5B,QAAQ;AAAA;AAAA;AAAA,QAGzB;AAAA,MACF,CAAC,CAAC;AAAA,kBACA,KAAK,wBAAwB,EAAE,SAAS,aAAa,CAAC;AAAA;AAAA;AAAA,IAG9D,CAAC,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKV;AACF;AAptBa,iBA0CJ,SAAS;AAAA,EACd;AAAA,EACAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCF;AA/EW,iBAqPI,iBAAiB,oBAAI,IAAI,CAAC,UAAU,OAAO,SAAS,QAAQ,CAAC;AApPhB;AAAA,EAA3DC,UAAS,EAAE,MAAM,QAAQ,WAAW,oBAAoB,CAAC;AAAA,GAD/C,iBACiD;AACN;AAAA,EAArDA,UAAS,EAAE,MAAM,QAAQ,WAAW,cAAc,CAAC;AAAA,GAFzC,iBAE2C;AACzB;AAAA,EAA5BA,UAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,GAHhB,iBAGkB;AACA;AAAA,EAA5BA,UAAS,EAAE,MAAM,QAAQ,CAAC;AAAA,GAJhB,iBAIkB;AACuB;AAAA,EAAnDA,UAAS,EAAE,MAAM,QAAQ,WAAW,YAAY,CAAC;AAAA,GALvC,iBAKyC;AACF;AAAA,EAAjDA,UAAS,EAAE,MAAM,QAAQ,WAAW,UAAU,CAAC;AAAA,GANrC,iBAMuC;AACG;AAAA,EAApDA,UAAS,EAAE,MAAM,SAAS,WAAW,YAAY,CAAC;AAAA,GAPxC,iBAO0C;AAEC;AAAA,EAArDA,UAAS,EAAE,MAAM,QAAQ,WAAW,cAAc,CAAC;AAAA,GATzC,iBAS2C;AAG7C;AAAA,EAAR,MAAM;AAAA,GAZI,iBAYF;AACA;AAAA,EAAR,MAAM;AAAA,GAbI,iBAaF;AACA;AAAA,EAAR,MAAM;AAAA,GAdI,iBAcF;AACA;AAAA,EAAR,MAAM;AAAA,GAfI,iBAeF;AACQ;AAAA,EAAhB,MAAM;AAAA,GAhBI,iBAgBM;AACR;AAAA,EAAR,MAAM;AAAA,GAjBI,iBAiBF;AACA;AAAA,EAAR,MAAM;AAAA,GAlBI,iBAkBF;AAeT;AAAA,EADCA,UAAS,EAAE,WAAW,eAAe,CAAC;AAAA,GAhC5B,iBAiCX;AAjCW,mBAAN;AAAA,EADNC,gBAAc,YAAY;AAAA,GACd;;;AY5Bb,SAAS,cAAAC,aAAY,QAAAC,OAAM,OAAAC,YAAW;AACtC,SAAS,iBAAAC,iBAAe,YAAAC,iBAAgB;;;ACEjC,SAAS,WAAW,cAA8B;AACvD,QAAM,UAAU,KAAK,MAAM,eAAe,GAAI;AAC9C,QAAM,IAAI,UAAU;AACpB,QAAM,KAAK,UAAU,KAAK;AAE1B,SAAO,GAAG,CAAC,IAAI,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC;AAC3C;;;ACPA,IAAM,WAAW,oBAAI,IAAI;AAAA,EACvB,CAAC,KAAK,EAAE,QAAQ,KAAM,SAAS,KAAK,WAAW,IAAI,CAAC;AAAA,EACpD,CAAC,MAAM,EAAE,QAAQ,KAAM,SAAS,KAAM,WAAW,IAAI,CAAC;AAAA,EACtD,CAAC,MAAM,EAAE,QAAQ,KAAM,SAAS,KAAM,WAAW,IAAI,CAAC;AAAA,EACtD,CAAC,KAAM,EAAE,QAAQ,KAAM,SAAS,KAAM,WAAW,IAAI,CAAC;AAAA,EACtD,CAAC,KAAO,EAAE,QAAQ,KAAO,SAAS,KAAM,WAAW,IAAK,CAAC;AAAA,EACzD,CAAC,MAAO,EAAE,QAAQ,MAAO,SAAS,KAAM,WAAW,IAAK,CAAC;AAAA,EACzD,CAAC,UAAU,EAAE,QAAQ,KAAO,SAAS,KAAO,WAAW,IAAK,CAAC;AAC/D,CAAC;AAEM,SAAS,aAAa,iBAAyB;AACpD,aAAW,CAAC,YAAY,MAAM,KAAK,UAAU;AAC3C,QAAI,kBAAkB,YAAY;AAChC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO,EAAE,QAAQ,KAAO,SAAS,KAAO,WAAW,IAAK;AAC1D;AAgBO,SAAS,qBACd,iBACA,YACA,UACA,aACU;AACV,QAAM,SAAS,KAAK,KAAM,WAAW,aAAc,eAAe;AAClE,QAAM,SAAS,aAAa,eAAe;AAC3C,QAAM,EAAE,QAAQ,SAAS,UAAU,IAAI;AACvC,QAAM,aAAa,oBAAI,IAAoB;AAC3C,QAAM,SAA+C,CAAC;AACtD,QAAM,YAAY,aAAa;AAI/B,WAAS,UAAU,KAAK,WAAW,WAAW;AAC5C,UAAM,MAAM,KAAK,MAAO,UAAU,MAAQ,SAAS;AACnD,QAAI,OAAO,OAAQ;AAEnB,QAAI,UAAU,WAAW,GAAG;AAC1B,iBAAW,IAAI,KAAK,WAAW;AAC/B,aAAO,KAAK,EAAE,KAAK,MAAM,WAAW,OAAO,EAAE,CAAC;AAAA,IAChD,WAAW,UAAU,YAAY,GAAG;AAClC,iBAAW,IAAI,KAAK,KAAK,MAAM,cAAc,CAAC,CAAC;AAAA,IACjD,WAAW,UAAU,cAAc,GAAG;AACpC,iBAAW,IAAI,KAAK,KAAK,MAAM,cAAc,CAAC,CAAC;AAAA,IACjD;AAAA,EACF;AAEA,SAAO,EAAE,QAAQ,YAAY,OAAO;AACtC;;;AF7DA,IAAMC,oBAAmB;AAGlB,IAAM,kBAAN,cAA8BC,YAAW;AAAA,EAAzC;AAAA;AACyC,2BAAkB;AAClB,sBAAa;AACb,oBAAW;AACX,uBAAc;AAE5D,SAAQ,YAA6B;AAAA;AAAA,EAwBrC,aAAa;AAEX,QAAI,KAAK,WAAW,GAAG;AACrB,WAAK,YAAY;AAAA,QACf,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,MACP;AAAA,IACF,OAAO;AACL,WAAK,YAAY;AAAA,IACnB;AAAA,EACF;AAAA,EAEA,SAAS;AACP,QAAI,CAAC,KAAK,UAAW,QAAOC;AAE5B,UAAM,EAAE,QAAQ,OAAO,IAAI,KAAK;AAChC,UAAM,cAAc,KAAK,KAAK,SAASF,iBAAgB;AACvD,UAAM,UAAU,MAAM,KAAK,EAAE,QAAQ,YAAY,GAAG,CAAC,GAAG,MAAM,CAAC;AAC/D,UAAM,MAAM,OAAO,qBAAqB,cAAc,mBAAmB;AAEzE,WAAOE;AAAA,6CACkC,MAAM,eAAe,KAAK,WAAW;AAAA,UACxE,QAAQ,IAAI,CAAC,MAAM;AACnB,YAAM,QAAQ,KAAK,IAAIF,mBAAkB,SAAS,IAAIA,iBAAgB;AACtE,aAAOE;AAAA;AAAA,2BAEU,CAAC;AAAA,sBACN,QAAQ,GAAG;AAAA,uBACV,KAAK,cAAc,GAAG;AAAA,6BAChB,IAAIF,iBAAgB,cAAc,KAAK,eAAe,KAClE,WAAW;AAAA;AAAA;AAAA,IAGpB,CAAC,CAAC;AAAA,UACA,OAAO;AAAA,MACP,CAAC,EAAE,KAAK,KAAK,MAAME,yCAAwC,MAAM,CAAC,QAAQ,IAAI;AAAA,IAChF,CAAC;AAAA;AAAA;AAAA,EAGP;AAAA,EAEA,UAAU;AACR,SAAK,WAAW;AAAA,EAClB;AAAA,EAEQ,aAAa;AACnB,QAAI,CAAC,KAAK,UAAW;AAErB,UAAM,WAAW,KAAK,YAAY,iBAAiB,QAAQ;AAC3D,QAAI,CAAC,SAAU;AAEf,UAAM,MAAM,OAAO,qBAAqB,cAAc,mBAAmB;AACzE,UAAM,aACJ,iBAAiB,IAAI,EAAE,iBAAiB,mBAAmB,EAAE,KAAK,KAAK;AAEzE,eAAW,UAAU,UAAU;AAC7B,YAAM,MAAM,OAAO,OAAO,QAAQ,KAAK;AACvC,YAAM,MAAM,OAAO,WAAW,IAAI;AAClC,UAAI,CAAC,IAAK;AAEV,YAAM,cAAc,KAAK;AAAA,QACvBF;AAAA,QACA,KAAK,UAAU,SAAS,MAAMA;AAAA,MAChC;AACA,YAAM,eAAe,MAAMA;AAE3B,UAAI,eAAe;AACnB,UAAI,UAAU,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAC/C,UAAI,MAAM,KAAK,GAAG;AAClB,UAAI,cAAc;AAClB,UAAI,YAAY;AAEhB,iBAAW,CAAC,KAAK,MAAM,KAAK,KAAK,UAAU,YAAY;AACrD,cAAM,SAAS,MAAM;AACrB,YAAI,SAAS,KAAK,UAAU,YAAa;AAEzC,YAAI,UAAU;AACd,YAAI,OAAO,SAAS,KAAK,KAAK,WAAW;AACzC,YAAI,OAAO,SAAS,KAAK,KAAK,cAAc,MAAM;AAClD,YAAI,OAAO;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;AAnHa,gBAQJ,SAASG;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAP8B;AAAA,EAA7CC,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GADjC,gBACmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAFjC,gBAEmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAHjC,gBAGmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAJjC,gBAImC;AAJnC,kBAAN;AAAA,EADNC,gBAAc,WAAW;AAAA,GACb;;;AGPb,SAAS,cAAAC,cAAY,QAAAC,OAAM,OAAAC,YAAW;AACtC,SAAS,iBAAAC,iBAAe,YAAAC,iBAAgB;AAGjC,IAAM,sBAAN,cAAkCC,aAAW;AAAA,EAA7C;AAAA;AACyC,mBAAU;AACV,iBAAQ;AAAA;AAAA,EAmBtD,SAAS;AACP,UAAM,OAAO,KAAK,IAAI,KAAK,SAAS,KAAK,KAAK;AAC9C,UAAM,QAAQ,KAAK,IAAI,KAAK,QAAQ,KAAK,OAAO;AAChD,QAAI,UAAU,EAAG,QAAOC;AACxB,WAAOA,0BAAyB,IAAI,cAAc,KAAK;AAAA,EACzD;AACF;AA3Ba,oBAIJ,SAASC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAH8B;AAAA,EAA7CC,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GADjC,oBACmC;AACA;AAAA,EAA7CA,UAAS,EAAE,MAAM,QAAQ,WAAW,MAAM,CAAC;AAAA,GAFjC,oBAEmC;AAFnC,sBAAN;AAAA,EADNC,gBAAc,eAAe;AAAA,GACjB;;;ACJb,SAAS,QAAAC,QAAM,OAAAC,YAAW;AAC1B,SAAS,iBAAAC,iBAAe,SAAAC,cAAa;AAI9B,IAAM,yBAAN,cAAqC,mBAAmB;AAAA,EAAxD;AAAA;AACI,SAAQ,eAAe;AAChC,SAAQ,aAAiC;AACzC,SAAQ,WAAW,MAAM;AACvB,WAAK,eAAe;AAAA,IACtB;AACA,SAAQ,cAAc,MAAM;AAC1B,WAAK,eAAe;AAAA,IACtB;AACA,SAAQ,WAAW,MAAM;AACvB,WAAK,eAAe;AAAA,IACtB;AAAA;AAAA,EAYA,oBAAoB;AAClB,UAAM,kBAAkB;AACxB,SAAK,gBAAgB;AAAA,EACvB;AAAA,EAEA,uBAAuB;AACrB,UAAM,qBAAqB;AAC3B,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,kBAAkB;AACxB,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,OAAQ;AACb,SAAK,aAAa;AAClB,WAAO,iBAAiB,uBAAuB,KAAK,QAAQ;AAC5D,WAAO,iBAAiB,0BAA0B,KAAK,WAAW;AAClE,WAAO,iBAAiB,uBAAuB,KAAK,QAAQ;AAAA,EAC9D;AAAA,EAEQ,oBAAoB;AAC1B,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,oBAAoB,uBAAuB,KAAK,QAAQ;AACxE,WAAK,WAAW,oBAAoB,0BAA0B,KAAK,WAAW;AAC9E,WAAK,WAAW,oBAAoB,uBAAuB,KAAK,QAAQ;AACxE,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,SAAS;AACP,WAAOC;AAAA,8CACmC,KAAK,YAAY,WAAW,KAAK,QAAQ;AAAA,gBACvE,KAAK,eAAe,aAAa,QAAQ;AAAA;AAAA;AAAA,EAGvD;AAAA,EAEQ,WAAW;AACjB,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC,QAAQ;AACX,cAAQ;AAAA,QACN;AAAA,MACF;AACA;AAAA,IACF;AACA,QAAI,KAAK,cAAc;AACrB,aAAO,cAAc;AAAA,IACvB,OAAO;AACL,aAAO,eAAe,OAAO,eAAe;AAAA,IAC9C;AAAA,EACF;AACF;AAzEa,uBAaK,SAAS;AAAA,EACvB,mBAAmB;AAAA,EACnBC;AAAA;AAAA;AAAA;AAAA;AAAA;AAMF;AApBiB;AAAA,EAAhBC,OAAM;AAAA,GADI,uBACM;AADN,yBAAN;AAAA,EADNC,gBAAc,mBAAmB;AAAA,GACrB;","names":["LitElement","customElement","property","LitElement","property","customElement","LitElement","customElement","property","LitElement","property","customElement","LitElement","html","css","customElement","LitElement","html","css","customElement","LitElement","customElement","property","LitElement","property","customElement","html","customElement","LitElement","css","html","customElement","html","customElement","html","customElement","html","customElement","html","customElement","LitElement","html","css","customElement","property","createClipFromSeconds","createTrack","bits","numChannels","LitElement","html","css","customElement","property","LitElement","html","css","property","customElement","css","LitElement","createClipFromSeconds","createTrack","html","css","property","customElement","LitElement","html","css","customElement","property","MAX_CANVAS_WIDTH","LitElement","html","css","property","customElement","LitElement","html","css","customElement","property","LitElement","html","css","property","customElement","html","css","customElement","state","html","css","state","customElement"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dawcore/components",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Web Components for multi-track audio editing — framework-agnostic",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": true,
|
|
16
|
+
"author": "Naomi Aro",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"lit": "^3.0.0",
|
|
23
|
+
"waveform-data": "^4.5.2"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@waveform-playlist/engine": ">=7.0.0",
|
|
27
|
+
"@waveform-playlist/core": ">=7.0.0",
|
|
28
|
+
"@waveform-playlist/playout": ">=7.0.0",
|
|
29
|
+
"@waveform-playlist/worklets": ">=7.0.0",
|
|
30
|
+
"@waveform-playlist/recording": ">=7.0.0"
|
|
31
|
+
},
|
|
32
|
+
"peerDependenciesMeta": {
|
|
33
|
+
"@waveform-playlist/recording": {
|
|
34
|
+
"optional": true
|
|
35
|
+
},
|
|
36
|
+
"@waveform-playlist/worklets": {
|
|
37
|
+
"optional": true
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"happy-dom": "^17.0.0",
|
|
42
|
+
"tsup": "^8.0.1",
|
|
43
|
+
"typescript": "^5.3.3",
|
|
44
|
+
"vite": "^6.0.0",
|
|
45
|
+
"vitest": "^3.0.0",
|
|
46
|
+
"@waveform-playlist/core": "10.3.0",
|
|
47
|
+
"@waveform-playlist/playout": "10.3.0",
|
|
48
|
+
"@waveform-playlist/engine": "10.3.0",
|
|
49
|
+
"@waveform-playlist/recording": "10.3.0",
|
|
50
|
+
"@waveform-playlist/worklets": "10.3.0"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "pnpm typecheck && tsup",
|
|
54
|
+
"dev": "tsup --watch",
|
|
55
|
+
"typecheck": "tsc --noEmit",
|
|
56
|
+
"test": "vitest run",
|
|
57
|
+
"test:watch": "vitest",
|
|
58
|
+
"dev:page": "vite --config dev/vite.config.ts"
|
|
59
|
+
}
|
|
60
|
+
}
|