velo-plot 2.20.0 → 3.0.0
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/README.md +15 -8
- package/dist/{ChartCore-ivzLqxVb.js → ChartCore-BpzRvN4Y.js} +978 -861
- package/dist/ChartCore-BpzRvN4Y.js.map +1 -0
- package/dist/a11y-Bw6urYpr.js +105 -0
- package/dist/a11y-Bw6urYpr.js.map +1 -0
- package/dist/angular/hooks-entry.d.ts +1 -0
- package/dist/angular/hooks.d.ts +26 -0
- package/dist/angular/index.d.ts +8 -0
- package/dist/angular/velo-plot.component.d.ts +46 -0
- package/dist/angular-hooks.d.ts +1 -0
- package/dist/angular-hooks.js +9 -0
- package/dist/angular-hooks.js.map +1 -0
- package/dist/angular.d.ts +1 -0
- package/dist/angular.js +166 -0
- package/dist/angular.js.map +1 -0
- package/dist/assets/indicator.worker-bv0zC4EX.js.map +1 -1
- package/dist/astro/StackedPlot.astro +19 -0
- package/dist/astro/VeloPlot.astro +23 -0
- package/dist/bindings/shared/a11y.d.ts +26 -0
- package/dist/bindings/shared/chartLifecycle.d.ts +16 -0
- package/dist/bindings/shared/chartSyncBridge.d.ts +8 -0
- package/dist/bindings/shared/dimensions.d.ts +1 -0
- package/dist/bindings/shared/index.d.ts +9 -0
- package/dist/bindings/shared/indicatorBridge.d.ts +11 -0
- package/dist/bindings/shared/optionsSync.d.ts +7 -0
- package/dist/bindings/shared/seriesDiff.d.ts +8 -0
- package/dist/bindings/shared/stackedSync.d.ts +9 -0
- package/dist/bindings/shared/types.d.ts +46 -0
- package/dist/bindings/test-utils/index.d.ts +35 -0
- package/dist/bindings/test-utils/mockLifecycle.d.ts +120 -0
- package/dist/bindings/test-utils/vitestSveltePlugin.d.ts +3 -0
- package/dist/chartSyncBridge-DbWrwtyP.js +57 -0
- package/dist/chartSyncBridge-DbWrwtyP.js.map +1 -0
- package/dist/core/Chart.d.ts +1 -1
- package/dist/core/InteractionManager.d.ts +7 -1
- package/dist/core/OverlayRenderer.d.ts +5 -0
- package/dist/core/annotations/types.d.ts +1 -1
- package/dist/core/chart/ChartCore.d.ts +2 -2
- package/dist/core/chart/types.d.ts +1 -1
- package/dist/core/clipboard/index.d.ts +1 -1
- package/dist/core/debug/index.d.ts +1 -1
- package/dist/core/keybindings/index.d.ts +1 -1
- package/dist/core/loading/index.d.ts +1 -1
- package/dist/core/locale/index.d.ts +1 -1
- package/dist/core/stacked/paneResize.d.ts +3 -0
- package/dist/core/stacked/types.d.ts +10 -0
- package/dist/core/theme-editor/index.d.ts +1 -1
- package/dist/createStackedChart-Dm-YqUT7.js +756 -0
- package/dist/createStackedChart-Dm-YqUT7.js.map +1 -0
- package/dist/examples/PluginDemonstration.d.ts +1 -1
- package/dist/gpuRenderer-BpaMYz-k.js.map +1 -1
- package/dist/hooks-CYPCxoZx.js +69 -0
- package/dist/hooks-CYPCxoZx.js.map +1 -0
- package/dist/{index-BBpJwOct.js → index-0InEyj0q.js} +119 -121
- package/dist/index-0InEyj0q.js.map +1 -0
- package/dist/index-BMiZoKmm.js.map +1 -1
- package/dist/{index-DoYxf1cV.js → index-CWxIHdwX.js} +38 -98
- package/dist/index-CWxIHdwX.js.map +1 -0
- package/dist/index-CaXWSOTk.js.map +1 -1
- package/dist/index-Dag88bW4.js.map +1 -1
- package/dist/index-qhscKTDy.js.map +1 -1
- package/dist/index-qunX30Xu.js.map +1 -1
- package/dist/index-x4stH3jD.js.map +1 -1
- package/dist/{index.core-COREBDNq.js → index.core-BmZe2jRQ.js} +9 -9
- package/dist/index.core-BmZe2jRQ.js.map +1 -0
- package/dist/index.core.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/indicators--eJGmVox.js.map +1 -1
- package/dist/{mockDatafeed-927foCM4.js → mockDatafeed-DHIDPcpX.js} +150 -146
- package/dist/mockDatafeed-DHIDPcpX.js.map +1 -0
- package/dist/optionsSync-QUiN4Inw.js +119 -0
- package/dist/optionsSync-QUiN4Inw.js.map +1 -0
- package/dist/plugins/3d/index.d.ts +2 -2
- package/dist/plugins/3d.d.ts +2 -2
- package/dist/plugins/3d.js.map +1 -1
- package/dist/plugins/analysis/index.d.ts +1 -1
- package/dist/plugins/analysis/indicators.d.ts +1 -1
- package/dist/plugins/analysis.d.ts +2 -2
- package/dist/plugins/analysis.js +2 -2
- package/dist/plugins/analysis.js.map +1 -1
- package/dist/plugins/annotations/index.d.ts +1 -1
- package/dist/plugins/annotations.d.ts +2 -2
- package/dist/plugins/annotations.js.map +1 -1
- package/dist/plugins/anomaly-detection.js +1 -1
- package/dist/plugins/anomaly-detection.js.map +1 -1
- package/dist/plugins/broken-axis.d.ts +2 -2
- package/dist/plugins/builtins/crosshair/CrosshairPlugin.d.ts +1 -1
- package/dist/plugins/builtins/index.d.ts +1 -1
- package/dist/plugins/caching.d.ts +2 -2
- package/dist/plugins/clipboard/index.d.ts +2 -2
- package/dist/plugins/clipboard.d.ts +2 -2
- package/dist/plugins/clipboard.js.map +1 -1
- package/dist/plugins/context-menu/index.d.ts +1 -1
- package/dist/plugins/context-menu.d.ts +2 -2
- package/dist/plugins/context-menu.js +1 -1
- package/dist/plugins/context-menu.js.map +1 -1
- package/dist/plugins/data-export/index.d.ts +1 -1
- package/dist/plugins/data-export.d.ts +2 -2
- package/dist/plugins/data-export.js +2 -2
- package/dist/plugins/data-export.js.map +1 -1
- package/dist/plugins/data-transform.d.ts +2 -2
- package/dist/plugins/data-transform.js +19 -19
- package/dist/plugins/data-transform.js.map +1 -1
- package/dist/plugins/debug/index.d.ts +2 -2
- package/dist/plugins/debug.d.ts +2 -2
- package/dist/plugins/debug.js +2 -2
- package/dist/plugins/debug.js.map +1 -1
- package/dist/plugins/forecasting/index.d.ts +1 -1
- package/dist/plugins/forecasting.js.map +1 -1
- package/dist/plugins/gpu/index.d.ts +2 -2
- package/dist/plugins/gpu.d.ts +2 -2
- package/dist/plugins/gpu.js.map +1 -1
- package/dist/plugins/i18n/index.d.ts +2 -2
- package/dist/plugins/i18n.d.ts +2 -2
- package/dist/plugins/i18n.js.map +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/keyboard.d.ts +2 -2
- package/dist/plugins/keyboard.js +65 -5
- package/dist/plugins/keyboard.js.map +1 -1
- package/dist/plugins/latex.js.map +1 -1
- package/dist/plugins/lazy-load.d.ts +2 -2
- package/dist/plugins/loading/index.d.ts +1 -1
- package/dist/plugins/loading.d.ts +2 -2
- package/dist/plugins/ml-integration.d.ts +2 -2
- package/dist/plugins/ml-integration.js +5 -5
- package/dist/plugins/ml-integration.js.map +1 -1
- package/dist/plugins/offscreen.d.ts +2 -2
- package/dist/plugins/pattern-recognition.d.ts +2 -2
- package/dist/plugins/pattern-recognition.js +1 -1
- package/dist/plugins/pattern-recognition.js.map +1 -1
- package/dist/plugins/radar.d.ts +2 -2
- package/dist/plugins/regression.d.ts +2 -2
- package/dist/plugins/regression.js +1 -1
- package/dist/plugins/regression.js.map +1 -1
- package/dist/plugins/roi.js +9 -9
- package/dist/plugins/roi.js.map +1 -1
- package/dist/plugins/snapshot/index.d.ts +1 -1
- package/dist/plugins/snapshot/types.d.ts +1 -1
- package/dist/plugins/snapshot.d.ts +2 -2
- package/dist/plugins/snapshot.js.map +1 -1
- package/dist/plugins/streaming/index.d.ts +2 -2
- package/dist/plugins/streaming.d.ts +2 -2
- package/dist/plugins/sync/index.d.ts +3 -2
- package/dist/plugins/sync.d.ts +2 -2
- package/dist/plugins/sync.js.map +1 -1
- package/dist/plugins/theme-editor/index.d.ts +1 -1
- package/dist/plugins/theme-editor.d.ts +2 -2
- package/dist/plugins/tools/index.d.ts +1 -1
- package/dist/plugins/tools/tooltip/index.d.ts +1 -1
- package/dist/plugins/tools.d.ts +2 -2
- package/dist/plugins/types.d.ts +1 -1
- package/dist/plugins/video-recorder.d.ts +2 -2
- package/dist/plugins/virtualization.d.ts +2 -2
- package/dist/plugins/virtualization.js +1 -1
- package/dist/pool-DZ8shSqv.js +109 -0
- package/dist/pool-DZ8shSqv.js.map +1 -0
- package/dist/react/StackedPlot.d.ts +31 -0
- package/dist/react/VeloPlot.d.ts +29 -0
- package/dist/react/index.d.ts +25 -3
- package/dist/react/useChartSync.d.ts +8 -0
- package/dist/react/useIndicator.d.ts +12 -0
- package/dist/react/useVeloPlot.d.ts +19 -0
- package/dist/react.js +328 -24
- package/dist/react.js.map +1 -1
- package/dist/scientific/index.d.ts +48 -0
- package/dist/scientific.d.ts +1 -0
- package/dist/scientific.js +91 -0
- package/dist/scientific.js.map +1 -0
- package/dist/solid/VeloPlot.d.ts +16 -0
- package/dist/solid/index.d.ts +13 -0
- package/dist/solid/useChartSync.d.ts +6 -0
- package/dist/solid/useIndicator.d.ts +11 -0
- package/dist/solid/useStackedPlot.d.ts +14 -0
- package/dist/solid/useVeloPlot.d.ts +18 -0
- package/dist/solid.d.ts +1 -0
- package/dist/solid.js +172 -0
- package/dist/solid.js.map +1 -0
- package/dist/stackedSync-tnrunZMt.js +100 -0
- package/dist/stackedSync-tnrunZMt.js.map +1 -0
- package/dist/svelte/StackedPlot.svelte +29 -0
- package/dist/svelte/StackedPlot.test.ts +114 -0
- package/dist/svelte/VeloPlot.svelte +44 -0
- package/dist/svelte/VeloPlot.test.ts +105 -0
- package/dist/svelte/index.d.ts +11 -0
- package/dist/svelte/index.test.ts +20 -0
- package/dist/svelte/index.ts +15 -0
- package/dist/svelte/useChartSync.d.ts +8 -0
- package/dist/svelte/useChartSync.test.ts +49 -0
- package/dist/svelte/useChartSync.ts +29 -0
- package/dist/svelte/useIndicator.d.ts +13 -0
- package/dist/svelte/useIndicator.test.ts +67 -0
- package/dist/svelte/useIndicator.ts +43 -0
- package/dist/svelte/useStackedPlot.d.ts +16 -0
- package/dist/svelte/useStackedPlot.test.ts +76 -0
- package/dist/svelte/useStackedPlot.ts +54 -0
- package/dist/svelte/useVeloPlot.d.ts +21 -0
- package/dist/svelte/useVeloPlot.test.ts +100 -0
- package/dist/svelte/useVeloPlot.ts +81 -0
- package/dist/svelte.d.ts +1 -0
- package/dist/svelte.js +143 -0
- package/dist/svelte.js.map +1 -0
- package/dist/testing/index.d.ts +1 -1
- package/dist/theme/index.d.ts +2 -1
- package/dist/trading.js +6 -6
- package/dist/types.d.ts +1 -1
- package/dist/{utils-BK5UUXxj.js → utils-Dx0h0bgQ.js} +9 -9
- package/dist/{utils-BK5UUXxj.js.map → utils-Dx0h0bgQ.js.map} +1 -1
- package/dist/velo-plot.full.js +452 -443
- package/dist/velo-plot.full.js.map +1 -1
- package/dist/velo-plot.js +15 -15
- package/dist/vue/StackedPlot.vue.d.ts +48 -0
- package/dist/vue/VeloPlot.vue.d.ts +64 -0
- package/dist/vue/index.d.ts +250 -0
- package/dist/vue/useChartSync.d.ts +52 -0
- package/dist/vue/useIndicator.d.ts +23 -0
- package/dist/vue/useStackedPlot.d.ts +15 -0
- package/dist/vue/useVeloPlot.d.ts +20 -0
- package/dist/vue.d.ts +1 -0
- package/dist/vue.js +312 -0
- package/dist/vue.js.map +1 -0
- package/dist/workers/indicatorsAsync.d.ts +2 -0
- package/dist/workers/pool.d.ts +9 -0
- package/package.json +88 -10
- package/dist/ChartCore-ivzLqxVb.js.map +0 -1
- package/dist/SciPlot-CEU4ApgD.js +0 -463
- package/dist/SciPlot-CEU4ApgD.js.map +0 -1
- package/dist/createStackedChart-DxNW0VkF.js +0 -705
- package/dist/createStackedChart-DxNW0VkF.js.map +0 -1
- package/dist/index-BBpJwOct.js.map +0 -1
- package/dist/index-DoYxf1cV.js.map +0 -1
- package/dist/index.core-COREBDNq.js.map +0 -1
- package/dist/mockDatafeed-927foCM4.js.map +0 -1
- package/dist/pool-15HMCNv8.js +0 -88
- package/dist/pool-15HMCNv8.js.map +0 -1
- package/dist/react/SciPlot.d.ts +0 -60
- package/dist/react/useSciPlot.d.ts +0 -56
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"velo-plot.full.js","sources":["../src/renderer/WebGPURenderer.ts","../src/plugins/builtins/crosshair/CrosshairPlugin.ts","../src/plugins/builtins/stats/StatsPlugin.ts","../src/plugins/builtins/watermark/WatermarkPlugin.ts","../src/plugins/builtins/grid-highlight/GridHighlightPlugin.ts","../src/plugins/builtins/data-logger/DataLoggerPlugin.ts","../src/plugins/builtins/direction-indicator/DirectionIndicatorPlugin.ts","../src/plugins/builtins/index.ts","../src/plugins/drag-edit/index.ts","../src/renderer/spike/WebGLGridSpike.ts","../src/testing/gridSpikeBenchmark.ts","../src/testing/stage1BrowserBench.ts","../src/testing/rendererBenchmark.ts","../src/testing/index.ts"],"sourcesContent":["export interface WebGPURendererOptions {\n powerPreference?: \"low-power\" | \"high-performance\";\n preferredFormat?: string;\n antialias?: boolean;\n}\n\nexport class WebGPURenderer {\n public readonly available: boolean;\n\n private canvas: HTMLCanvasElement;\n private adapter: any;\n private device: any;\n private context: any;\n\n constructor(canvas: HTMLCanvasElement, opts: WebGPURendererOptions = {}) {\n this.canvas = canvas;\n this.available = WebGPURenderer.isSupported();\n void opts;\n }\n\n static isSupported(): boolean {\n return (\n typeof (globalThis as any).navigator !== \"undefined\" &&\n typeof (globalThis as any).navigator.gpu !== \"undefined\"\n );\n }\n\n async init(opts: WebGPURendererOptions = {}): Promise<void> {\n if (!this.available) {\n throw new Error(\"[SciPlot] WebGPU is not supported in this environment\");\n }\n\n const gpu = (globalThis as any).navigator.gpu;\n this.adapter = await gpu.requestAdapter({\n powerPreference: opts.powerPreference ?? \"high-performance\",\n });\n\n if (!this.adapter) {\n throw new Error(\"[SciPlot] Failed to request WebGPU adapter\");\n }\n\n this.device = await this.adapter.requestDevice();\n\n const ctx = (this.canvas as any).getContext(\"webgpu\");\n if (!ctx) {\n throw new Error(\"[SciPlot] Failed to get WebGPU context\");\n }\n\n this.context = ctx;\n\n const format =\n opts.preferredFormat ??\n (gpu.getPreferredCanvasFormat\n ? gpu.getPreferredCanvasFormat()\n : \"bgra8unorm\");\n\n this.context.configure({\n device: this.device,\n format,\n alphaMode: \"premultiplied\",\n });\n }\n\n destroy(): void {\n this.device = undefined;\n this.adapter = undefined;\n this.context = undefined;\n }\n}\n","import type {\n PluginContext,\n PluginManifest,\n InteractionEvent,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\nimport type {\n CrosshairValueMode,\n CornerPosition\n} from \"../../../core/layout\";\n\nexport interface CrosshairPluginConfig {\n /** Show vertical line (default: true) */\n showVertical?: boolean;\n /** Show horizontal line (default: true) */\n showHorizontal?: boolean;\n /** Line color (default: from theme) */\n color?: string;\n /** Line style (default: 'dashed') */\n lineStyle?: \"solid\" | \"dashed\" | \"dotted\";\n /** Line width (default: 1) */\n lineWidth?: number;\n /** \n * @deprecated Use valueDisplayMode instead\n * Show axis labels (will be converted to valueDisplayMode)\n */\n showAxisLabels?: boolean;\n /**\n * Display mode for X,Y coordinate values (default: 'disabled')\n * - 'disabled': Never show coordinate values\n * - 'corner': Show values in a fixed corner position\n * - 'floating': Show values next to the cursor (axis labels)\n */\n valueDisplayMode?: CrosshairValueMode;\n /**\n * Corner position when valueDisplayMode is 'corner' (default: 'top-left')\n */\n cornerPosition?: CornerPosition;\n /** Snap to nearest data point (default: false) */\n snapToData?: boolean;\n /** Value format options */\n valueFormat?: {\n /** X value precision (default: 4) */\n xPrecision?: number;\n /** Y value precision (default: 4) */\n yPrecision?: number;\n };\n}\n\nconst crosshairManifest: PluginManifest = {\n name: \"crosshair\",\n version: \"1.0.0\",\n description: \"Interactive crosshair that follows mouse cursor\",\n provides: [\"interaction\", \"visualization\"],\n tags: [\"cursor\", \"crosshair\", \"tooltip\"],\n};\n\nexport const CrosshairPlugin = definePlugin<CrosshairPluginConfig>(\n crosshairManifest,\n (config = {}) => {\n const {\n showVertical = true,\n showHorizontal = true,\n color,\n lineStyle = \"dashed\",\n lineWidth = 1,\n snapToData = false,\n valueFormat = { xPrecision: 4, yPrecision: 4 },\n } = config;\n\n // Handle deprecated showAxisLabels -> convert to valueDisplayMode\n let valueDisplayMode: CrosshairValueMode = config.valueDisplayMode ?? 'disabled';\n if (config.showAxisLabels !== undefined && config.valueDisplayMode === undefined) {\n valueDisplayMode = config.showAxisLabels ? 'floating' : 'disabled';\n }\n const cornerPosition: CornerPosition = config.cornerPosition ?? 'top-left';\n\n let cursorX = -1;\n let cursorY = -1;\n let overlayId: string;\n let canvas: HTMLCanvasElement | null = null;\n let ctx: CanvasRenderingContext2D | null = null;\n\n return {\n onInit(pluginCtx: PluginContext) {\n overlayId = \"crosshair-overlay\";\n const overlay = pluginCtx.ui.createOverlay(overlayId, {\n zIndex: 500,\n position: { top: \"0\", left: \"0\", right: \"0\", bottom: \"0\" },\n });\n\n canvas = document.createElement(\"canvas\");\n canvas.style.cssText = \"width: 100%; height: 100%;\";\n overlay.appendChild(canvas);\n\n ctx = canvas.getContext(\"2d\");\n resizeCanvas(pluginCtx);\n },\n\n onDestroy(pluginCtx: PluginContext) {\n pluginCtx.ui.removeOverlay(overlayId);\n canvas = null;\n ctx = null;\n },\n\n onResize(pluginCtx: PluginContext) {\n resizeCanvas(pluginCtx);\n },\n\n onInteraction(pluginCtx: PluginContext, event: InteractionEvent) {\n if (event.type === \"mousemove\") {\n cursorX = event.pixelX;\n cursorY = event.pixelY;\n\n if (snapToData && event.inPlotArea) {\n const nearest = pluginCtx.coords.pickPoint(cursorX, cursorY);\n if (nearest) {\n cursorX = nearest.pixelX;\n cursorY = nearest.pixelY;\n }\n }\n\n render(pluginCtx);\n }\n },\n\n onViewChange() {\n // Re-render on zoom/pan\n if (cursorX >= 0 && cursorY >= 0) {\n // Will be re-rendered on next frame\n }\n },\n };\n\n function resizeCanvas(pluginCtx: PluginContext) {\n if (!canvas || !ctx) return;\n const size = pluginCtx.render.canvasSize;\n const dpr = pluginCtx.render.pixelRatio;\n canvas.width = size.width * dpr;\n canvas.height = size.height * dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.scale(dpr, dpr);\n }\n\n function render(pluginCtx: PluginContext) {\n if (!ctx || !canvas) return;\n\n const { width, height } = pluginCtx.render.canvasSize;\n ctx.clearRect(0, 0, width, height);\n\n if (cursorX < 0 || cursorY < 0) return;\n\n const plotArea = pluginCtx.render.plotArea;\n if (\n cursorX < plotArea.x ||\n cursorX > plotArea.x + plotArea.width ||\n cursorY < plotArea.y ||\n cursorY > plotArea.y + plotArea.height\n ) {\n return;\n }\n\n const lineColor = color || (pluginCtx.ui.theme.cursor as unknown as Record<string, unknown>)?.color as string || \"#888888\";\n\n ctx.save();\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = lineWidth;\n\n if (lineStyle === \"dashed\") {\n ctx.setLineDash([6, 4]);\n } else if (lineStyle === \"dotted\") {\n ctx.setLineDash([2, 2]);\n }\n\n // Vertical line\n if (showVertical) {\n ctx.beginPath();\n ctx.moveTo(cursorX, plotArea.y);\n ctx.lineTo(cursorX, plotArea.y + plotArea.height);\n ctx.stroke();\n }\n\n // Horizontal line\n if (showHorizontal) {\n ctx.beginPath();\n ctx.moveTo(plotArea.x, cursorY);\n ctx.lineTo(plotArea.x + plotArea.width, cursorY);\n ctx.stroke();\n }\n\n ctx.restore();\n\n // Value display based on mode\n if (valueDisplayMode === 'floating') {\n drawFloatingLabels(pluginCtx, ctx, cursorX, cursorY, lineColor);\n } else if (valueDisplayMode === 'corner') {\n drawCornerLabels(pluginCtx, ctx, cursorX, cursorY, lineColor);\n }\n // 'disabled' mode: don't draw any labels\n }\n\n function drawFloatingLabels(\n pluginCtx: PluginContext,\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n bgColor: string\n ) {\n const dataX = pluginCtx.coords.pixelToDataX(x);\n const dataY = pluginCtx.coords.pixelToDataY(y);\n const plotArea = pluginCtx.render.plotArea;\n\n ctx.save();\n ctx.font = \"11px system-ui, sans-serif\";\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"top\";\n\n // X axis label\n const xText = dataX.toPrecision(valueFormat.xPrecision);\n const xMetrics = ctx.measureText(xText);\n const xLabelWidth = xMetrics.width + 8;\n const xLabelHeight = 18;\n const xLabelX = x - xLabelWidth / 2;\n const xLabelY = plotArea.y + plotArea.height + 2;\n\n ctx.fillStyle = bgColor;\n ctx.fillRect(xLabelX, xLabelY, xLabelWidth, xLabelHeight);\n ctx.fillStyle = \"#ffffff\";\n ctx.fillText(xText, x, xLabelY + 3);\n\n // Y axis label\n ctx.textAlign = \"right\";\n ctx.textBaseline = \"middle\";\n const yText = dataY.toPrecision(valueFormat.yPrecision);\n const yMetrics = ctx.measureText(yText);\n const yLabelWidth = yMetrics.width + 8;\n const yLabelHeight = 18;\n const yLabelX = plotArea.x - yLabelWidth - 2;\n const yLabelY = y - yLabelHeight / 2;\n\n ctx.fillStyle = bgColor;\n ctx.fillRect(yLabelX, yLabelY, yLabelWidth, yLabelHeight);\n ctx.fillStyle = \"#ffffff\";\n ctx.fillText(yText, plotArea.x - 6, y);\n\n ctx.restore();\n }\n\n function drawCornerLabels(\n pluginCtx: PluginContext,\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n bgColor: string\n ) {\n const dataX = pluginCtx.coords.pixelToDataX(x);\n const dataY = pluginCtx.coords.pixelToDataY(y);\n const plotArea = pluginCtx.render.plotArea;\n\n ctx.save();\n ctx.font = \"11px system-ui, sans-serif\";\n\n const xText = `X: ${dataX.toPrecision(valueFormat.xPrecision)}`;\n const yText = `Y: ${dataY.toPrecision(valueFormat.yPrecision)}`;\n\n const xMetrics = ctx.measureText(xText);\n const yMetrics = ctx.measureText(yText);\n const maxWidth = Math.max(xMetrics.width, yMetrics.width);\n const padding = 6;\n const lineHeight = 16;\n const boxWidth = maxWidth + padding * 2;\n const boxHeight = lineHeight * 2 + padding * 2;\n\n // Determine corner position\n let boxX: number;\n let boxY: number;\n\n switch (cornerPosition) {\n case 'top-left':\n boxX = plotArea.x + 8;\n boxY = plotArea.y + 8;\n break;\n case 'top-right':\n boxX = plotArea.x + plotArea.width - boxWidth - 8;\n boxY = plotArea.y + 8;\n break;\n case 'bottom-left':\n boxX = plotArea.x + 8;\n boxY = plotArea.y + plotArea.height - boxHeight - 8;\n break;\n case 'bottom-right':\n boxX = plotArea.x + plotArea.width - boxWidth - 8;\n boxY = plotArea.y + plotArea.height - boxHeight - 8;\n break;\n default:\n boxX = plotArea.x + 8;\n boxY = plotArea.y + 8;\n }\n\n // Draw background\n ctx.fillStyle = bgColor;\n ctx.globalAlpha = 0.85;\n ctx.fillRect(boxX, boxY, boxWidth, boxHeight);\n ctx.globalAlpha = 1.0;\n\n // Draw border\n ctx.strokeStyle = \"rgba(255,255,255,0.3)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(boxX, boxY, boxWidth, boxHeight);\n\n // Draw text\n ctx.fillStyle = \"#ffffff\";\n ctx.textAlign = \"left\";\n ctx.textBaseline = \"top\";\n ctx.fillText(xText, boxX + padding, boxY + padding);\n ctx.fillText(yText, boxX + padding, boxY + padding + lineHeight);\n\n ctx.restore();\n }\n }\n);\n\n","import type {\n PluginContext,\n PluginManifest,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface StatsPluginConfig {\n /** Position of the stats overlay */\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n /** Which stats to show */\n show?: Array<\"count\" | \"mean\" | \"min\" | \"max\" | \"std\" | \"range\">;\n /** Series ID to compute stats for (default: all) */\n seriesId?: string;\n /** Update on every data change (default: true) */\n autoUpdate?: boolean;\n}\n\nconst statsManifest: PluginManifest = {\n name: \"statistics-overlay\",\n version: \"1.0.0\",\n description: \"Displays real-time statistics for chart data\",\n provides: [\"visualization\", \"analysis\"],\n tags: [\"statistics\", \"overlay\", \"analytics\"],\n};\n\nexport const StatsPlugin = definePlugin<StatsPluginConfig>(\n statsManifest,\n (config = {}) => {\n const {\n position = \"top-right\",\n show = [\"count\", \"mean\", \"min\", \"max\"],\n seriesId,\n autoUpdate = true,\n } = config;\n\n let overlayId: string;\n let container: HTMLDivElement | null = null;\n\n return {\n onInit(ctx: PluginContext) {\n overlayId = \"stats-overlay\";\n const posStyle: Record<string, string> = {};\n\n if (position.includes(\"top\")) posStyle.top = \"10px\";\n if (position.includes(\"bottom\")) posStyle.bottom = \"10px\";\n if (position.includes(\"left\")) posStyle.left = \"10px\";\n if (position.includes(\"right\")) posStyle.right = \"10px\";\n\n container = ctx.ui.createOverlay(overlayId, {\n zIndex: 800,\n position: posStyle,\n pointerEvents: false,\n });\n\n container.innerHTML = `\n <div style=\"\n background: rgba(0, 0, 0, 0.85);\n color: #fff;\n padding: 10px 14px;\n border-radius: 6px;\n font-family: ui-monospace, monospace;\n font-size: 12px;\n line-height: 1.6;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n \">\n <div style=\"font-weight: bold; margin-bottom: 4px; color: #4ade80;\">📊 Statistics</div>\n <div class=\"stats-content\"></div>\n </div>\n `;\n\n updateStats(ctx);\n },\n\n onDestroy(ctx: PluginContext) {\n ctx.ui.removeOverlay(overlayId);\n container = null;\n },\n\n onDataUpdate(ctx: PluginContext) {\n if (autoUpdate) {\n updateStats(ctx);\n }\n },\n\n onSeriesAdd(ctx: PluginContext) {\n updateStats(ctx);\n },\n\n onSeriesRemove(ctx: PluginContext) {\n updateStats(ctx);\n },\n\n api: {\n refresh(ctx: PluginContext) {\n updateStats(ctx);\n },\n },\n };\n\n function updateStats(ctx: PluginContext) {\n if (!container) return;\n\n const content = container.querySelector(\".stats-content\");\n if (!content) return;\n\n const allSeries = ctx.data.getAllSeries();\n const targetSeries = seriesId\n ? allSeries.filter((s) => s.getId() === seriesId)\n : allSeries;\n\n if (targetSeries.length === 0) {\n content.innerHTML = \"<div style='color: #888'>No data</div>\";\n return;\n }\n\n // Aggregate all Y data\n let allY: number[] = [];\n targetSeries.forEach((series) => {\n const data = series.getData();\n if (data?.y) {\n allY = allY.concat(Array.from(data.y));\n }\n });\n\n if (allY.length === 0) {\n content.innerHTML = \"<div style='color: #888'>No data</div>\";\n return;\n }\n\n const stats = computeStats(allY);\n const lines: string[] = [];\n\n if (show.includes(\"count\")) {\n lines.push(`<div>N: <span style=\"color: #60a5fa\">${stats.count.toLocaleString()}</span></div>`);\n }\n if (show.includes(\"mean\")) {\n lines.push(`<div>μ: <span style=\"color: #60a5fa\">${stats.mean.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"min\")) {\n lines.push(`<div>Min: <span style=\"color: #60a5fa\">${stats.min.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"max\")) {\n lines.push(`<div>Max: <span style=\"color: #60a5fa\">${stats.max.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"std\")) {\n lines.push(`<div>σ: <span style=\"color: #60a5fa\">${stats.std.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"range\")) {\n lines.push(`<div>Range: <span style=\"color: #60a5fa\">${stats.range.toPrecision(4)}</span></div>`);\n }\n\n content.innerHTML = lines.join(\"\");\n }\n\n function computeStats(values: number[]) {\n const n = values.length;\n let sum = 0;\n let min = Infinity;\n let max = -Infinity;\n\n for (const v of values) {\n sum += v;\n if (v < min) min = v;\n if (v > max) max = v;\n }\n\n const mean = sum / n;\n\n let sumSq = 0;\n for (const v of values) {\n sumSq += (v - mean) ** 2;\n }\n const std = Math.sqrt(sumSq / n);\n\n return {\n count: n,\n mean,\n min,\n max,\n std,\n range: max - min,\n };\n }\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface WatermarkPluginConfig {\n /** Watermark text */\n text: string;\n /** Font size (default: 48) */\n fontSize?: number;\n /** Font family (default: system-ui) */\n fontFamily?: string;\n /** Text color with opacity (default: rgba(128,128,128,0.15)) */\n color?: string;\n /** Position (default: center) */\n position?: \"center\" | \"bottom-right\" | \"bottom-left\";\n /** Rotation in degrees (default: -30 for center, 0 for corners) */\n rotation?: number;\n}\n\nconst watermarkManifest: PluginManifest = {\n name: \"watermark\",\n version: \"1.0.0\",\n description: \"Adds a customizable watermark to the chart\",\n provides: [\"visualization\"],\n tags: [\"watermark\", \"branding\", \"overlay\"],\n};\n\nexport const WatermarkPlugin = definePlugin<WatermarkPluginConfig>(\n watermarkManifest,\n (config) => {\n if (!config?.text) {\n throw new Error(\"WatermarkPlugin requires 'text' configuration\");\n }\n\n const {\n text,\n fontSize = 48,\n fontFamily = \"system-ui, sans-serif\",\n color = \"rgba(128, 128, 128, 0.15)\",\n position = \"center\",\n rotation = position === \"center\" ? -30 : 0,\n } = config;\n\n return {\n onRenderOverlay(ctx: PluginContext) {\n const ctx2d = ctx.render.ctx2d;\n if (!ctx2d) return;\n\n // width/height available for future use\n void ctx.render.canvasSize;\n const plotArea = ctx.render.plotArea;\n\n ctx2d.save();\n ctx2d.font = `${fontSize}px ${fontFamily}`;\n ctx2d.fillStyle = color;\n ctx2d.textAlign = \"center\";\n ctx2d.textBaseline = \"middle\";\n\n let x: number, y: number;\n\n if (position === \"center\") {\n x = plotArea.x + plotArea.width / 2;\n y = plotArea.y + plotArea.height / 2;\n } else if (position === \"bottom-right\") {\n x = plotArea.x + plotArea.width - fontSize;\n y = plotArea.y + plotArea.height - fontSize / 2;\n } else {\n x = plotArea.x + fontSize;\n y = plotArea.y + plotArea.height - fontSize / 2;\n }\n\n ctx2d.translate(x, y);\n ctx2d.rotate((rotation * Math.PI) / 180);\n ctx2d.fillText(text, 0, 0);\n ctx2d.restore();\n },\n };\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n AfterRenderEvent,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface GridHighlightConfig {\n /** Highlight intervals on X axis */\n xIntervals?: Array<{ start: number; end: number; color: string }>;\n /** Highlight intervals on Y axis */\n yIntervals?: Array<{ start: number; end: number; color: string }>;\n /** Opacity for highlight regions (default: 0.1) */\n opacity?: number;\n}\n\nconst gridHighlightManifest: PluginManifest = {\n name: \"grid-highlight\",\n version: \"1.0.0\",\n description: \"Highlights specific regions of the chart grid\",\n provides: [\"visualization\"],\n tags: [\"grid\", \"highlight\", \"regions\"],\n};\n\nexport const GridHighlightPlugin = definePlugin<GridHighlightConfig>(\n gridHighlightManifest,\n (config = {}) => {\n const { xIntervals = [], yIntervals = [], opacity = 0.1 } = config;\n\n return {\n onRenderOverlay(ctx: PluginContext, _event: AfterRenderEvent) {\n const ctx2d = ctx.render.ctx2d;\n if (!ctx2d) return;\n\n const plotArea = ctx.render.plotArea;\n // bounds available if needed for future features\n void ctx.data.getViewBounds();\n\n ctx2d.save();\n\n // Clip to plot area\n ctx2d.beginPath();\n ctx2d.rect(plotArea.x, plotArea.y, plotArea.width, plotArea.height);\n ctx2d.clip();\n\n ctx2d.globalAlpha = opacity;\n\n // Draw X intervals (vertical bands)\n for (const interval of xIntervals) {\n const x1 = ctx.coords.dataToPixelX(interval.start);\n const x2 = ctx.coords.dataToPixelX(interval.end);\n\n ctx2d.fillStyle = interval.color;\n ctx2d.fillRect(\n Math.min(x1, x2),\n plotArea.y,\n Math.abs(x2 - x1),\n plotArea.height\n );\n }\n\n // Draw Y intervals (horizontal bands)\n for (const interval of yIntervals) {\n const y1 = ctx.coords.dataToPixelY(interval.start);\n const y2 = ctx.coords.dataToPixelY(interval.end);\n\n ctx2d.fillStyle = interval.color;\n ctx2d.fillRect(\n plotArea.x,\n Math.min(y1, y2),\n plotArea.width,\n Math.abs(y2 - y1)\n );\n }\n\n ctx2d.restore();\n },\n };\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n DataUpdateEvent,\n ViewChangeEvent,\n InteractionEvent,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface DataLoggerConfig {\n /** Log data updates (default: true) */\n logDataUpdates?: boolean;\n /** Log view changes (default: true) */\n logViewChanges?: boolean;\n /** Log interactions (default: false) */\n logInteractions?: boolean;\n /** Maximum log entries to keep (default: 100) */\n maxEntries?: number;\n}\n\nconst dataLoggerManifest: PluginManifest = {\n name: \"data-logger\",\n version: \"1.0.0\",\n description: \"Logs chart events for debugging and analysis\",\n provides: [\"analysis\"],\n tags: [\"debug\", \"logging\", \"events\"],\n};\n\nexport const DataLoggerPlugin = definePlugin<DataLoggerConfig>(\n dataLoggerManifest,\n (config = {}) => {\n const {\n logDataUpdates = true,\n logViewChanges = true,\n logInteractions = false,\n maxEntries = 100,\n } = config;\n\n interface LogEntry {\n timestamp: number;\n type: string;\n data: unknown;\n }\n\n const entries: LogEntry[] = [];\n\n function addEntry(type: string, data: unknown) {\n entries.push({\n timestamp: Date.now(),\n type,\n data,\n });\n\n if (entries.length > maxEntries) {\n entries.shift();\n }\n }\n\n return {\n onInit(ctx: PluginContext) {\n ctx.log.info(\"Data logger initialized\");\n },\n\n onDataUpdate(ctx: PluginContext, event: DataUpdateEvent) {\n if (logDataUpdates) {\n addEntry(\"dataUpdate\", {\n seriesId: event.seriesId,\n mode: event.mode,\n pointCount: event.pointCount,\n });\n ctx.log.debug(`Data update: ${event.seriesId} (${event.mode}, ${event.pointCount} points)`);\n }\n },\n\n onViewChange(ctx: PluginContext, event: ViewChangeEvent) {\n if (logViewChanges) {\n addEntry(\"viewChange\", {\n trigger: event.trigger,\n bounds: event.current,\n });\n ctx.log.debug(`View change: ${event.trigger}`);\n }\n },\n\n onInteraction(_ctx: PluginContext, event: InteractionEvent) {\n if (logInteractions) {\n addEntry(\"interaction\", {\n type: event.type,\n pixelX: event.pixelX,\n pixelY: event.pixelY,\n inPlotArea: event.inPlotArea,\n });\n }\n },\n\n onSerialize(_ctx: PluginContext) {\n return { entries };\n },\n\n onDeserialize(_ctx: PluginContext, data: unknown) {\n const saved = data as { entries?: LogEntry[] };\n if (saved?.entries) {\n entries.length = 0;\n entries.push(...saved.entries);\n }\n },\n\n api: {\n getEntries() {\n return [...entries];\n },\n clear() {\n entries.length = 0;\n },\n export() {\n return JSON.stringify(entries, null, 2);\n },\n },\n };\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface DirectionIndicatorConfig {\n /** Series ID to track (if not specified, tracks the first series) */\n seriesId?: string;\n /** Number of recent points to analyze for direction (default: 20) */\n sampleSize?: number;\n /** Arrow color (default: from theme) */\n color?: string;\n /** Arrow size in pixels (default: 40) */\n size?: number;\n /** Minimum velocity to show arrow (default: 0.01) */\n minVelocity?: number;\n /** Number of points for smoothing the position/angle (default: 20) */\n historySize?: number;\n /** Hide arrow if no new points are received for this duration in ms (default: undefined/disabled) */\n idleTimeout?: number;\n}\n\ninterface DirectionData {\n angle: number; // Continuous angle in radians\n magnitude: number; // Normalized magnitude 0-1\n lastX: number; // Last data point X coordinate (data space)\n lastY: number; // Last data point Y coordinate (data space)\n smoothX: number; // Smoothed X position (pixel space)\n smoothY: number; // Smoothed Y position (pixel space)\n}\n\nconst directionIndicatorManifest: PluginManifest = {\n name: \"direction-indicator\",\n version: \"1.0.0\",\n description: \"Shows an arrow indicating the direction and trend of streaming data\",\n provides: [\"visualization\", \"analysis\"],\n tags: [\"streaming\", \"direction\", \"trend\", \"arrow\"],\n};\n\nexport const DirectionIndicatorPlugin = definePlugin<DirectionIndicatorConfig>(\n directionIndicatorManifest,\n (config = {}) => {\n const {\n seriesId,\n sampleSize = 20,\n color,\n size = 40,\n minVelocity = 0.01,\n historySize = 20,\n idleTimeout,\n } = config;\n\n let overlayId: string;\n let canvas: HTMLCanvasElement | null = null;\n let ctx: CanvasRenderingContext2D | null = null;\n let currentDirection: DirectionData | null = null;\n let targetSeriesId: string | null = null;\n \n // Smoothing buffers (moving average to reduce jitter)\n const positionHistoryX: number[] = [];\n const positionHistoryY: number[] = [];\n const angleHistory: number[] = [];\n\n let maxHistorySize = historySize;\n let timeoutTimer: any = null;\n let lastPointTimestamp = Date.now();\n let lastSeenX = -Infinity;\n let lastSeenY = -Infinity;\n let currentIdleTimeout = idleTimeout;\n\n return {\n onInit(pluginCtx: PluginContext) {\n overlayId = \"direction-indicator-overlay\";\n const overlay = pluginCtx.ui.createOverlay(overlayId, {\n zIndex: 600,\n position: { top: \"0\", left: \"0\", right: \"0\", bottom: \"0\" },\n pointerEvents: false,\n });\n\n canvas = document.createElement(\"canvas\");\n canvas.style.cssText = \"width: 100%; height: 100%; pointer-events: none;\";\n overlay.appendChild(canvas);\n\n ctx = canvas.getContext(\"2d\");\n resizeCanvas(pluginCtx);\n\n // Determine which series to track\n if (seriesId) {\n targetSeriesId = seriesId;\n } else {\n const allSeries = pluginCtx.data.getAllSeries();\n if (allSeries.length > 0) {\n targetSeriesId = allSeries[0].getId();\n }\n }\n },\n\n onDestroy(pluginCtx: PluginContext) {\n pluginCtx.ui.removeOverlay(overlayId);\n if (timeoutTimer) clearTimeout(timeoutTimer);\n canvas = null;\n ctx = null;\n currentDirection = null;\n },\n\n onResize(pluginCtx: PluginContext) {\n resizeCanvas(pluginCtx);\n },\n\n onAfterRender(pluginCtx: PluginContext) {\n // Update direction every frame for smooth rendering\n updateDirection(pluginCtx);\n render(pluginCtx);\n\n // Ensure we render again when the idle timeout expires to hide the arrow\n if (currentIdleTimeout) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n const age = Date.now() - lastPointTimestamp;\n if (age < currentIdleTimeout) {\n timeoutTimer = setTimeout(() => {\n pluginCtx.requestRender();\n }, currentIdleTimeout - age + 10);\n }\n }\n },\n\n onConfigChange(_pluginCtx: PluginContext, newConfig: DirectionIndicatorConfig) {\n if (newConfig.historySize !== undefined) {\n maxHistorySize = newConfig.historySize;\n // Reset history buffers if size changes significantly or just trim/expand? \n // Simpler to just let them adjust over time or trim if needed.\n // If we want immediate effect, we might want to trim if smaller.\n while (positionHistoryX.length > maxHistorySize) positionHistoryX.shift();\n while (positionHistoryY.length > maxHistorySize) positionHistoryY.shift();\n while (angleHistory.length > maxHistorySize) angleHistory.shift();\n }\n\n if (newConfig.idleTimeout !== undefined) {\n currentIdleTimeout = newConfig.idleTimeout;\n }\n }\n };\n\n function resizeCanvas(pluginCtx: PluginContext) {\n if (!canvas || !ctx) return;\n const canvasSize = pluginCtx.render.canvasSize;\n const dpr = pluginCtx.render.pixelRatio;\n canvas.width = canvasSize.width * dpr;\n canvas.height = canvasSize.height * dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.scale(dpr, dpr);\n }\n\n function updateDirection(pluginCtx: PluginContext) {\n if (!targetSeriesId) return;\n\n const series = pluginCtx.data.getSeries(targetSeriesId);\n if (!series) return;\n\n const data = pluginCtx.data.getSeriesData(targetSeriesId);\n if (!data || !data.x || !data.y) return;\n\n const totalPoints = data.x.length;\n if (totalPoints < 2) return;\n\n // Get last point coordinates in data space\n const lastX = data.x[totalPoints - 1];\n const lastY = data.y[totalPoints - 1];\n\n // Detect if this is a new point\n if (lastX !== lastSeenX || lastY !== lastSeenY) {\n lastSeenX = lastX;\n lastSeenY = lastY;\n lastPointTimestamp = Date.now();\n }\n\n // Get last N points for direction calculation\n const n = Math.min(sampleSize, totalPoints);\n const startIdx = totalPoints - n;\n\n // Calculate direction using linear regression on recent points IN PIXEL SPACE\n let sumT = 0, sumPX = 0, sumPY = 0, sumTPX = 0, sumTPY = 0, sumTT = 0;\n\n for (let i = startIdx; i < totalPoints; i++) {\n const t = i - startIdx; // Time index\n const dataX = data.x[i];\n const dataY = data.y[i];\n \n // Convert to pixel coordinates\n const pixelX = pluginCtx.coords.dataToPixelX(dataX);\n const pixelY = pluginCtx.coords.dataToPixelY(dataY);\n\n sumT += t;\n sumPX += pixelX;\n sumPY += pixelY;\n sumTPX += t * pixelX;\n sumTPY += t * pixelY;\n sumTT += t * t;\n }\n\n const meanT = sumT / n;\n const meanPX = sumPX / n;\n const meanPY = sumPY / n;\n\n // Calculate slopes in pixel space (dpx/dt and dpy/dt)\n const denominator = sumTT - n * meanT * meanT;\n if (Math.abs(denominator) < 1e-10) return; // Avoid division by zero\n \n const slopePX = (sumTPX - n * meanT * meanPX) / denominator;\n const slopePY = (sumTPY - n * meanT * meanPY) / denominator;\n\n // Calculate continuous angle in pixel space (canvas coordinates)\n const rawAngle = Math.atan2(slopePY, slopePX);\n \n // Convert last point to pixel coordinates\n const lastPixelX = pluginCtx.coords.dataToPixelX(lastX);\n const lastPixelY = pluginCtx.coords.dataToPixelY(lastY);\n \n // Add to position history for smoothing\n positionHistoryX.push(lastPixelX);\n positionHistoryY.push(lastPixelY);\n if (positionHistoryX.length > maxHistorySize) {\n positionHistoryX.shift();\n positionHistoryY.shift();\n }\n \n // Add to angle history for smoothing\n angleHistory.push(rawAngle);\n if (angleHistory.length > maxHistorySize) {\n angleHistory.shift();\n }\n \n // Apply moving average to smooth position and angle\n const smoothX = average(positionHistoryX);\n const smoothY = average(positionHistoryY);\n const smoothedAngle = smoothAngle(angleHistory);\n \n // Calculate magnitude in pixel space\n const magnitude = Math.sqrt(slopePX * slopePX + slopePY * slopePY);\n\n currentDirection = { angle: smoothedAngle, magnitude, lastX, lastY, smoothX, smoothY };\n }\n \n function average(values: number[]): number {\n if (values.length === 0) return 0;\n return values.reduce((sum, val) => sum + val, 0) / values.length;\n }\n \n function smoothAngle(angles: number[]): number {\n if (angles.length === 0) return 0;\n \n // Convert angles to unit vectors to handle wraparound correctly\n let sumX = 0;\n let sumY = 0;\n \n for (const angle of angles) {\n sumX += Math.cos(angle);\n sumY += Math.sin(angle);\n }\n \n // Average the vectors and convert back to angle\n return Math.atan2(sumY / angles.length, sumX / angles.length);\n }\n\n function render(pluginCtx: PluginContext) {\n if (!ctx || !canvas || !currentDirection) return;\n\n const { width, height } = pluginCtx.render.canvasSize;\n ctx.clearRect(0, 0, width, height);\n\n // Check for idle timeout\n if (currentIdleTimeout !== undefined) {\n const age = Date.now() - lastPointTimestamp;\n if (age > currentIdleTimeout) return;\n }\n\n if (currentDirection.magnitude < minVelocity) return;\n\n // Use smoothed position for fluid movement\n const smoothX = currentDirection.smoothX;\n const smoothY = currentDirection.smoothY;\n\n const arrowColor = color || \"#FF9800\";\n \n ctx.save();\n\n // Draw arrow at smoothed position with smoothed angle\n drawArrow(ctx, smoothX, smoothY, currentDirection.angle, size, arrowColor);\n\n ctx.restore();\n }\n\n function drawArrow(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n angle: number,\n length: number,\n color: string\n ) {\n // Triangle dimensions (only the arrow head)\n const triangleHeight = length * 0.6;\n const triangleWidth = length * 0.4;\n\n ctx.save();\n ctx.translate(x, y);\n ctx.rotate(angle);\n\n // Draw filled triangle pointing in the direction of movement\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.moveTo(triangleHeight / 2, 0); // Tip of the triangle\n ctx.lineTo(-triangleHeight / 2, -triangleWidth / 2); // Bottom left\n ctx.lineTo(-triangleHeight / 2, triangleWidth / 2); // Bottom right\n ctx.closePath();\n ctx.fill();\n\n ctx.restore();\n }\n }\n);\n","/**\n * Sci Plot - Built-in Plugins\n * \n * Collection of official plugins that demonstrate the plugin system\n * capabilities and provide common functionality.\n * \n * @module plugins/builtins\n */\n\nexport * from \"./crosshair\";\nexport * from \"./stats\";\nexport * from \"./watermark\";\nexport * from \"./grid-highlight\";\nexport * from \"./data-logger\";\nexport * from \"./direction-indicator\";\n\nimport { CrosshairPlugin } from \"./crosshair\";\nimport { StatsPlugin } from \"./stats\";\nimport { WatermarkPlugin } from \"./watermark\";\nimport { GridHighlightPlugin } from \"./grid-highlight\";\nimport { DataLoggerPlugin } from \"./data-logger\";\nimport { DirectionIndicatorPlugin } from \"./direction-indicator\";\n\n/**\n * Plugin collection for easy registration\n */\nexport const BuiltinPlugins = {\n Crosshair: CrosshairPlugin,\n Statistics: StatsPlugin,\n Watermark: WatermarkPlugin,\n GridHighlight: GridHighlightPlugin,\n DataLogger: DataLoggerPlugin,\n DirectionIndicator: DirectionIndicatorPlugin,\n};\n","/**\n * @fileoverview Drag & Drop editing plugin for interactive point manipulation\n * @module plugins/drag-edit\n */\n\nimport type {\n PluginDragEditConfig,\n DragEditAPI,\n DraggedPoint,\n DragEditEvent,\n DragConstraint,\n} from './types';\nimport type {\n ChartPlugin,\n PluginContext,\n PluginManifest,\n} from '../types';\n\nconst manifest: PluginManifest = {\n name: 'velo-plot-drag-edit',\n version: '1.0.0',\n description: 'Interactive drag & drop editing of data points',\n provides: ['drag-edit', 'point-editing'],\n tags: ['interaction', 'editing', 'ux'],\n};\n\nconst DEFAULT_CONFIG: Required<PluginDragEditConfig> = {\n enabled: true,\n constraint: 'both',\n snapToGrid: false,\n snapIntervalX: 1,\n snapIntervalY: 1,\n dragThreshold: 5,\n hitRadius: 10,\n editableSeries: [],\n validator: () => ({ valid: true }),\n onDragStart: () => {},\n onDrag: () => {},\n onDragEnd: () => {},\n highlightColor: '#ffff00',\n showPreview: true,\n previewStyle: {\n color: '#ffffff',\n width: 2,\n dash: [5, 5],\n opacity: 0.5,\n },\n};\n\nexport function PluginDragEdit(\n userConfig: Partial<PluginDragEditConfig> = {}\n): ChartPlugin<PluginDragEditConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n \n // Drag state\n let isDragging = false;\n let draggedPoint: DraggedPoint | null = null;\n let dragStartX = 0;\n let dragStartY = 0;\n let hasMoved = false;\n\n /**\n * Find nearest point to mouse position\n */\n function findNearestPoint(mouseX: number, mouseY: number): DraggedPoint | null {\n if (!ctx) return null;\n\n // Use built-in pick functionality\n const picked = ctx.coords.pickPoint(mouseX, mouseY, config.hitRadius);\n \n if (!picked) return null;\n\n // Check if series is editable\n if (config.editableSeries.length > 0 && !config.editableSeries.includes(picked.seriesId)) {\n return null;\n }\n\n return {\n seriesId: picked.seriesId,\n index: picked.index,\n originalX: picked.x,\n originalY: picked.y,\n currentX: picked.x,\n currentY: picked.y,\n };\n }\n\n /**\n * Convert pixel coordinates to data coordinates\n */\n function pixelToData(pixelX: number, pixelY: number): { x: number; y: number } {\n if (!ctx) return { x: 0, y: 0 };\n\n return {\n x: ctx.coords.pixelToDataX(pixelX),\n y: ctx.coords.pixelToDataY(pixelY),\n };\n }\n\n /**\n * Snap value to grid\n */\n function snapToGrid(value: number, interval: number): number {\n return Math.round(value / interval) * interval;\n }\n\n /**\n * Apply drag constraints\n */\n function applyConstraints(\n newX: number,\n newY: number,\n constraint: DragConstraint\n ): { x: number; y: number } {\n if (!draggedPoint) return { x: newX, y: newY };\n\n switch (constraint) {\n case 'x':\n return { x: newX, y: draggedPoint.originalY };\n case 'y':\n return { x: draggedPoint.originalX, y: newY };\n case 'none':\n return { x: draggedPoint.originalX, y: draggedPoint.originalY };\n default:\n return { x: newX, y: newY };\n }\n }\n\n /**\n * Validate and apply snapping\n */\n function validateAndSnap(x: number, y: number): { x: number; y: number; valid: boolean } {\n let finalX = x;\n let finalY = y;\n\n // Apply snapping\n if (config.snapToGrid) {\n finalX = snapToGrid(x, config.snapIntervalX);\n finalY = snapToGrid(y, config.snapIntervalY);\n }\n\n // Run custom validation\n if (draggedPoint && config.validator) {\n const tempPoint: DraggedPoint = { ...draggedPoint, currentX: finalX, currentY: finalY };\n const validation = config.validator(tempPoint);\n\n if (typeof validation === 'boolean') {\n return { x: finalX, y: finalY, valid: validation };\n }\n\n if (!validation.valid) {\n return { x: finalX, y: finalY, valid: false };\n }\n\n // Apply snap suggestions from validator\n if (validation.snapX !== undefined) finalX = validation.snapX;\n if (validation.snapY !== undefined) finalY = validation.snapY;\n }\n\n return { x: finalX, y: finalY, valid: true };\n }\n\n /**\n * Update point data\n */\n function updatePointData(seriesId: string, index: number, newX: number, newY: number): void {\n if (!ctx) return;\n\n const series = (ctx.chart as any).getSeries?.(seriesId);\n if (!series) return;\n\n const data = series.getData();\n if (!data || !data.x || !data.y) return;\n\n // Update the data arrays\n data.x[index] = newX;\n data.y[index] = newY;\n\n // Invalidate buffers to trigger GPU upload\n series.invalidateBuffers?.();\n\n // Trigger chart re-render\n ctx.requestRender();\n }\n\n /**\n * Create drag event\n */\n function createDragEvent(): DragEditEvent | null {\n if (!draggedPoint) return null;\n\n return {\n seriesId: draggedPoint.seriesId,\n index: draggedPoint.index,\n oldX: draggedPoint.originalX,\n oldY: draggedPoint.originalY,\n newX: draggedPoint.currentX,\n newY: draggedPoint.currentY,\n deltaX: draggedPoint.currentX - draggedPoint.originalX,\n deltaY: draggedPoint.currentY - draggedPoint.originalY,\n };\n }\n\n /**\n * Draw preview overlay\n */\n function drawPreview(pCtx: PluginContext): void {\n if (!isDragging || !draggedPoint || !config.showPreview) return;\n\n const { render, coords } = pCtx;\n const { ctx2d } = render;\n if (!ctx2d) return;\n\n ctx2d.save();\n\n // Convert data coordinates to pixel coordinates\n const origPixelX = coords.dataToPixelX(draggedPoint.originalX);\n const origPixelY = coords.dataToPixelY(draggedPoint.originalY);\n \n const currPixelX = coords.dataToPixelX(draggedPoint.currentX);\n const currPixelY = coords.dataToPixelY(draggedPoint.currentY);\n\n // Draw preview line from original to current position\n ctx2d.strokeStyle = config.previewStyle.color || '#ffffff';\n ctx2d.lineWidth = config.previewStyle.width || 2;\n ctx2d.globalAlpha = config.previewStyle.opacity || 0.5;\n ctx2d.setLineDash(config.previewStyle.dash || [5, 5]);\n\n ctx2d.beginPath();\n ctx2d.moveTo(origPixelX, origPixelY);\n ctx2d.lineTo(currPixelX, currPixelY);\n ctx2d.stroke();\n\n // Draw highlight circle at current position\n ctx2d.globalAlpha = 1;\n ctx2d.fillStyle = config.highlightColor;\n ctx2d.setLineDash([]);\n ctx2d.beginPath();\n ctx2d.arc(currPixelX, currPixelY, 6, 0, Math.PI * 2);\n ctx2d.fill();\n\n // Draw outline\n ctx2d.strokeStyle = '#000000';\n ctx2d.lineWidth = 1;\n ctx2d.stroke();\n\n ctx2d.restore();\n }\n\n // API implementation\n const api: DragEditAPI & Record<string, unknown> = {\n enable() {\n config.enabled = true;\n },\n disable() {\n config.enabled = false;\n if (isDragging) {\n draggedPoint = null;\n isDragging = false;\n hasMoved = false;\n ctx?.requestRender();\n }\n },\n isEnabled() {\n return config.enabled;\n },\n setEditableSeries(seriesIds: string[]) {\n config.editableSeries = seriesIds;\n },\n getDraggedPoint() {\n return draggedPoint;\n },\n cancelDrag() {\n if (isDragging && draggedPoint) {\n draggedPoint = null;\n isDragging = false;\n hasMoved = false;\n ctx?.requestRender();\n }\n },\n updateConfig(newConfig: Partial<PluginDragEditConfig>) {\n Object.assign(config, newConfig);\n },\n };\n\n return {\n manifest,\n\n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n\n // Attach to chart API\n (ctx.chart as any).dragEdit = api;\n },\n\n onDestroy(_pluginCtx: PluginContext) {\n // Remove from chart API\n delete (_pluginCtx.chart as any).dragEdit;\n\n ctx = null;\n },\n\n onInteraction(_pluginCtx: PluginContext, event: import('../types').InteractionEvent) {\n if (!config.enabled) return;\n\n if (event.type === 'mousedown') {\n const point = findNearestPoint(event.pixelX, event.pixelY);\n if (point) {\n draggedPoint = point;\n dragStartX = event.pixelX;\n dragStartY = event.pixelY;\n hasMoved = false;\n isDragging = false;\n // Prevent default to stop panning when clicking on a point\n event.preventDefault();\n }\n } else if (event.type === 'mousemove') {\n if (!draggedPoint) return;\n\n // Check if we've moved beyond threshold\n if (!isDragging) {\n const dx = event.pixelX - dragStartX;\n const dy = event.pixelY - dragStartY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance > config.dragThreshold) {\n isDragging = true;\n hasMoved = true;\n\n // Fire drag start event\n const dragEvent = createDragEvent();\n if (dragEvent) config.onDragStart(dragEvent);\n } else {\n return;\n }\n }\n\n // Prevent default during dragging\n if (isDragging) {\n event.preventDefault();\n }\n\n // Convert to data coordinates\n let { x, y } = pixelToData(event.pixelX, event.pixelY);\n\n // Apply constraints\n ({ x, y } = applyConstraints(x, y, config.constraint));\n\n // Validate and snap\n const { x: finalX, y: finalY, valid } = validateAndSnap(x, y);\n\n if (valid) {\n draggedPoint.currentX = finalX;\n draggedPoint.currentY = finalY;\n\n // Fire drag event (for callbacks)\n const dragEvent = createDragEvent();\n if (dragEvent) config.onDrag(dragEvent);\n\n // Request render to show preview line\n ctx?.requestRender();\n }\n } else if (event.type === 'mouseup') {\n if (!draggedPoint) return;\n\n if (isDragging && hasMoved) {\n // Apply the changes\n updatePointData(\n draggedPoint.seriesId,\n draggedPoint.index,\n draggedPoint.currentX,\n draggedPoint.currentY\n );\n\n // Fire drag end event\n const dragEvent = createDragEvent();\n if (dragEvent) config.onDragEnd(dragEvent);\n\n // Prevent default on mouseup to avoid triggering click events\n event.preventDefault();\n }\n\n // Reset state\n draggedPoint = null;\n isDragging = false;\n hasMoved = false;\n ctx?.requestRender();\n }\n },\n\n onRenderOverlay(pluginCtx: PluginContext) {\n drawPreview(pluginCtx);\n },\n\n api,\n };\n}\n\nexport default PluginDragEdit;\n\n// Type exports\nexport type {\n PluginDragEditConfig,\n DragEditAPI,\n DraggedPoint,\n DragEditEvent,\n DragConstraint,\n} from './types';\n","/**\n * WebGL grid spike — batched GL_LINES renderer for axis grid lines.\n * Labels remain on Canvas 2D; this spike covers grid lines only.\n * @module renderer/spike/WebGLGridSpike\n */\n\nexport interface GridLineSpec {\n /** Plot area in CSS pixels */\n plotArea: { x: number; y: number; width: number; height: number };\n /** Pixel X positions for vertical grid lines */\n xLines: number[];\n /** Pixel Y positions for horizontal grid lines */\n yLines: number[];\n /** Canvas width (physical pixels) */\n width: number;\n /** Canvas height (physical pixels) */\n height: number;\n /** Line color RGBA 0–1 */\n color?: [number, number, number, number];\n /** Line width in pixels */\n lineWidth?: number;\n}\n\nconst VERT_SRC = `\n attribute vec2 aPosition;\n uniform vec2 uResolution;\n void main() {\n vec2 clip = (aPosition / uResolution) * 2.0 - 1.0;\n gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);\n }\n`;\n\nconst FRAG_SRC = `\n precision mediump float;\n uniform vec4 uColor;\n void main() {\n gl_FragColor = uColor;\n }\n`;\n\nfunction compileShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error(\"createShader failed\");\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(gl.getShaderInfoLog(shader) ?? \"shader compile failed\");\n }\n return shader;\n}\n\nfunction createProgram(gl: WebGLRenderingContext): WebGLProgram {\n const vs = compileShader(gl, gl.VERTEX_SHADER, VERT_SRC);\n const fs = compileShader(gl, gl.FRAGMENT_SHADER, FRAG_SRC);\n const program = gl.createProgram();\n if (!program) throw new Error(\"createProgram failed\");\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(gl.getProgramInfoLog(program) ?? \"program link failed\");\n }\n gl.deleteShader(vs);\n gl.deleteShader(fs);\n return program;\n}\n\n/** Build interleaved [x,y] vertex pairs for GL_LINES from tick pixel positions */\nexport function buildGridLineVertices(spec: GridLineSpec): Float32Array {\n const { plotArea, xLines, yLines } = spec;\n const y0 = plotArea.y;\n const y1 = plotArea.y + plotArea.height;\n const x0 = plotArea.x;\n const x1 = plotArea.x + plotArea.width;\n\n const vertCount = (xLines.length + yLines.length) * 2;\n const out = new Float32Array(vertCount * 2);\n let o = 0;\n\n for (const x of xLines) {\n out[o++] = x;\n out[o++] = y0;\n out[o++] = x;\n out[o++] = y1;\n }\n\n for (const y of yLines) {\n out[o++] = x0;\n out[o++] = y;\n out[o++] = x1;\n out[o++] = y;\n }\n\n return out;\n}\n\nexport class WebGLGridSpike {\n private gl: WebGLRenderingContext;\n private program: WebGLProgram;\n private buffer: WebGLBuffer;\n private aPosition: number;\n private uResolution: WebGLUniformLocation;\n private uColor: WebGLUniformLocation;\n\n constructor(canvas: HTMLCanvasElement) {\n const gl = canvas.getContext(\"webgl\", {\n alpha: true,\n antialias: false,\n preserveDrawingBuffer: true,\n });\n if (!gl) throw new Error(\"WebGL not available for grid spike\");\n\n this.gl = gl;\n this.program = createProgram(gl);\n this.aPosition = gl.getAttribLocation(this.program, \"aPosition\");\n this.uResolution = gl.getUniformLocation(this.program, \"uResolution\")!;\n this.uColor = gl.getUniformLocation(this.program, \"uColor\")!;\n\n const buf = gl.createBuffer();\n if (!buf) throw new Error(\"createBuffer failed\");\n this.buffer = buf;\n }\n\n /** Upload vertices and draw grid lines */\n draw(spec: GridLineSpec): number {\n const gl = this.gl;\n const vertices = buildGridLineVertices(spec);\n const lineSegments = vertices.length / 4;\n\n gl.viewport(0, 0, spec.width, spec.height);\n gl.clearColor(0.04, 0.05, 0.08, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n gl.useProgram(this.program);\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);\n gl.enableVertexAttribArray(this.aPosition);\n gl.vertexAttribPointer(this.aPosition, 2, gl.FLOAT, false, 0, 0);\n\n gl.uniform2f(this.uResolution, spec.width, spec.height);\n const c = spec.color ?? [0.2, 0.22, 0.3, 0.6];\n gl.uniform4f(this.uColor, c[0], c[1], c[2], c[3]);\n gl.lineWidth(spec.lineWidth ?? 1);\n\n gl.drawArrays(gl.LINES, 0, vertices.length / 2);\n return lineSegments;\n }\n\n destroy(): void {\n const gl = this.gl;\n gl.deleteBuffer(this.buffer);\n gl.deleteProgram(this.program);\n }\n}\n","/**\n * Grid rendering benchmark — Canvas 2D vs WebGL spike comparison.\n * @module testing/gridSpikeBenchmark\n */\n\nimport { OverlayRenderer } from \"../core/OverlayRenderer\";\nimport { LinearScale } from \"../scales\";\nimport { DARK_THEME } from \"../theme\";\nimport { WebGLGridSpike, buildGridLineVertices, type GridLineSpec } from \"../renderer/spike/WebGLGridSpike\";\nimport { snapLineCoord } from \"../core/render/pixelSnap\";\nimport type { PlotArea } from \"../types\";\n\nexport interface GridBenchmarkResult {\n backend: \"canvas2d\" | \"webgl\";\n dpr: number;\n width: number;\n height: number;\n xTicks: number;\n yTicks: number;\n lineSegments: number;\n avgFrameUs: number;\n p95FrameUs: number;\n frames: number;\n}\n\nexport interface GridCompareResult {\n canvas2d: GridBenchmarkResult;\n webgl: GridBenchmarkResult | null;\n /** Positive = WebGL faster */\n gainPercent: number;\n recommendation: \"implement\" | \"defer\";\n}\n\nfunction createMinimalMock2D(canvas: HTMLCanvasElement): CanvasRenderingContext2D {\n const noop = () => {};\n return {\n canvas,\n strokeStyle: \"\",\n fillStyle: \"\",\n lineWidth: 1,\n font: \"\",\n textAlign: \"left\",\n textBaseline: \"alphabetic\",\n beginPath: noop,\n moveTo: noop,\n lineTo: noop,\n stroke: noop,\n fill: noop,\n clearRect: noop,\n setTransform: noop,\n setLineDash: noop,\n save: noop,\n restore: noop,\n translate: noop,\n rotate: noop,\n fillText: noop,\n measureText: (text: string) => ({ width: text.length * 7 } as TextMetrics),\n } as unknown as CanvasRenderingContext2D;\n}\n\nfunction getCanvas2DContext(width: number, height: number): CanvasRenderingContext2D {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas.getContext(\"2d\") ?? createMinimalMock2D(canvas);\n}\n\nfunction makePlotArea(width: number, height: number): PlotArea {\n const margin = { top: 40, right: 40, bottom: 50, left: 60 };\n return {\n x: margin.left,\n y: margin.top,\n width: width - margin.left - margin.right,\n height: height - margin.top - margin.bottom,\n };\n}\n\nfunction tickPixelLines(\n _plotArea: PlotArea,\n xScale: LinearScale,\n yScale: LinearScale,\n xTickCount: number,\n yTickCount: number,\n): { xLines: number[]; yLines: number[] } {\n const xLines = xScale.ticks(xTickCount).map((t) => snapLineCoord(xScale.transform(t)));\n const yLines = yScale.ticks(yTickCount).map((t) => snapLineCoord(yScale.transform(t)));\n return { xLines, yLines };\n}\n\nfunction measureFrames(runFrame: () => void, frames: number): { avg: number; p95: number } {\n const samples: number[] = [];\n for (let i = 0; i < frames; i++) {\n const t0 = performance.now();\n runFrame();\n samples.push((performance.now() - t0) * 1000);\n }\n samples.sort((a, b) => a - b);\n const avg = samples.reduce((s, v) => s + v, 0) / samples.length;\n const p95 = samples[Math.floor(samples.length * 0.95)] ?? avg;\n return { avg, p95 };\n}\n\n/** Benchmark Canvas 2D grid via OverlayRenderer.drawGrid */\nexport function benchmarkCanvasGrid(options: {\n width?: number;\n height?: number;\n dpr?: number;\n xTickCount?: number;\n yTickCount?: number;\n frames?: number;\n showMinor?: boolean;\n} = {}): GridBenchmarkResult {\n const width = Math.round((options.width ?? 1920) * (options.dpr ?? 1));\n const height = Math.round((options.height ?? 1080) * (options.dpr ?? 1));\n const xTickCount = options.xTickCount ?? 24;\n const yTickCount = options.yTickCount ?? 16;\n const frames = options.frames ?? 120;\n\n const ctx = getCanvas2DContext(width, height);\n\n const theme = {\n ...DARK_THEME,\n grid: {\n ...DARK_THEME.grid,\n visible: true,\n showMinor: options.showMinor ?? true,\n },\n };\n\n const plotArea = makePlotArea(width, height);\n const xScale = new LinearScale();\n const yScale = new LinearScale();\n xScale.setDomain(0, 1_000_000);\n yScale.setDomain(-1, 1);\n xScale.setRange(plotArea.x, plotArea.x + plotArea.width);\n yScale.setRange(plotArea.y + plotArea.height, plotArea.y);\n\n const renderer = new OverlayRenderer(ctx, theme);\n\n const { avg, p95 } = measureFrames(() => {\n ctx.clearRect(0, 0, width, height);\n renderer.drawGrid(plotArea, xScale, yScale, { tickCount: xTickCount }, { tickCount: yTickCount });\n }, frames);\n\n const { xLines, yLines } = tickPixelLines(plotArea, xScale, yScale, xTickCount, yTickCount);\n\n return {\n backend: \"canvas2d\",\n dpr: options.dpr ?? 1,\n width,\n height,\n xTicks: xTickCount,\n yTicks: yTickCount,\n lineSegments: xLines.length + yLines.length,\n avgFrameUs: Math.round(avg),\n p95FrameUs: Math.round(p95),\n frames,\n };\n}\n\n/** Benchmark WebGL grid spike (returns null if WebGL unavailable) */\nexport function benchmarkWebGLGrid(options: {\n width?: number;\n height?: number;\n dpr?: number;\n xTickCount?: number;\n yTickCount?: number;\n frames?: number;\n} = {}): GridBenchmarkResult | null {\n const width = Math.round((options.width ?? 1920) * (options.dpr ?? 1));\n const height = Math.round((options.height ?? 1080) * (options.dpr ?? 1));\n const xTickCount = options.xTickCount ?? 24;\n const yTickCount = options.yTickCount ?? 16;\n const frames = options.frames ?? 120;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n\n let spike: WebGLGridSpike;\n try {\n spike = new WebGLGridSpike(canvas);\n } catch {\n return null;\n }\n\n const plotArea = makePlotArea(width, height);\n const xScale = new LinearScale();\n const yScale = new LinearScale();\n xScale.setDomain(0, 1_000_000);\n yScale.setDomain(-1, 1);\n xScale.setRange(plotArea.x, plotArea.x + plotArea.width);\n yScale.setRange(plotArea.y + plotArea.height, plotArea.y);\n\n const { xLines, yLines } = tickPixelLines(plotArea, xScale, yScale, xTickCount, yTickCount);\n const spec: GridLineSpec = { plotArea, xLines, yLines, width, height };\n\n let lineSegments = 0;\n const { avg, p95 } = measureFrames(() => {\n lineSegments = spike.draw(spec);\n }, frames);\n\n spike.destroy();\n\n return {\n backend: \"webgl\",\n dpr: options.dpr ?? 1,\n width,\n height,\n xTicks: xTickCount,\n yTicks: yTickCount,\n lineSegments,\n avgFrameUs: Math.round(avg),\n p95FrameUs: Math.round(p95),\n frames,\n };\n}\n\n/** Compare backends; recommends implement if WebGL ≥20% faster */\nexport function compareGridBackends(options?: {\n dpr?: number;\n frames?: number;\n}): GridCompareResult {\n const dpr = options?.dpr ?? 2;\n const frames = options?.frames ?? 120;\n\n const canvas2d = benchmarkCanvasGrid({ dpr, frames, showMinor: true });\n const webgl = benchmarkWebGLGrid({ dpr, frames });\n\n if (!webgl) {\n return {\n canvas2d,\n webgl: null,\n gainPercent: 0,\n recommendation: \"defer\",\n };\n }\n\n const gainPercent = ((canvas2d.avgFrameUs - webgl.avgFrameUs) / canvas2d.avgFrameUs) * 100;\n\n return {\n canvas2d,\n webgl,\n gainPercent: Math.round(gainPercent * 10) / 10,\n recommendation: gainPercent >= 20 ? \"implement\" : \"defer\",\n };\n}\n\n/** Vertex builder smoke test (no GL required) */\nexport function countGridVertices(xTickCount: number, yTickCount: number): number {\n const spec: GridLineSpec = {\n plotArea: { x: 60, y: 40, width: 800, height: 400 },\n xLines: Array.from({ length: xTickCount }, (_, i) => 60 + i * 30),\n yLines: Array.from({ length: yTickCount }, (_, i) => 40 + i * 25),\n width: 960,\n height: 540,\n };\n return buildGridLineVertices(spec).length / 2;\n}\n","/**\n * Stage 1 browser benchmark harness — scenarios + baseline comparison.\n * @module testing/stage1BrowserBench\n */\n\nimport type { BenchmarkResult } from \"./index\";\nimport baseline from \"./baselines/v1.15.0.json\";\n\nexport interface Stage1ScenarioResult {\n id: string;\n benchmark: BenchmarkResult;\n passed: boolean;\n failures: string[];\n baselineMinFps?: number;\n}\n\nexport interface Stage1BrowserReport {\n timestamp: number;\n version: string;\n scenarios: Stage1ScenarioResult[];\n allPassed: boolean;\n regressionThreshold: number;\n}\n\nexport interface BaselineScenario {\n minAvgFps?: number;\n maxAvgFrameTimeMs?: number;\n maxAvgFrameUs?: number;\n dpr?: number;\n points?: number;\n description?: string;\n}\n\n/** When wall-clock frame count is below this, headless rAF is unreliable — use renderFps. */\nexport const HEADLESS_LOW_FRAME_THRESHOLD = 30;\n\n/** Headless smoke floors (renderFps or effective FPS). Desktop uses baseline minAvgFps. */\nexport const SMOKE_FLOORS: Record<string, number> = {\n \"line-1m-pan\": 5,\n \"candlestick-500k\": 25,\n \"stack-5pane-resize\": 20,\n \"line-200k-webgl\": 3,\n \"line-200k-webgpu\": 2,\n \"boxplot-5k-webgpu\": 2,\n};\n\n/** Pick wall or render FPS depending on headless throttling artifacts. */\nexport function effectiveBenchmarkFps(\n result: Pick<BenchmarkResult, \"avgFps\" | \"renderFps\" | \"frameCount\">,\n isHeadless: boolean,\n): number {\n const wall = result.avgFps ?? 0;\n const render = result.renderFps ?? 0;\n const frames = result.frameCount ?? 0;\n\n if (!isHeadless) return wall;\n\n if (render > 0 && (frames < HEADLESS_LOW_FRAME_THRESHOLD || wall < 10)) {\n return render;\n }\n return wall;\n}\n\nexport function getBaseline(): typeof baseline {\n return baseline;\n}\n\n/** Compare a benchmark result against v1.15 baseline for a scenario */\nexport function compareScenarioToBaseline(\n scenarioId: string,\n result: BenchmarkResult | { avgFrameUs: number; backend?: string },\n): { passed: boolean; failures: string[] } {\n const spec = (baseline.scenarios as Record<string, BaselineScenario>)[scenarioId];\n if (!spec) {\n return { passed: true, failures: [] };\n }\n\n const failures: string[] = [];\n const threshold = baseline.regressionThreshold ?? 0.1;\n\n if (\"avgFps\" in result && spec.minAvgFps !== undefined) {\n const minAllowed = spec.minAvgFps * (1 - threshold);\n if (result.avgFps < minAllowed) {\n failures.push(\n `FPS ${result.avgFps} < baseline min ${spec.minAvgFps} (allowed ${minAllowed.toFixed(1)} with ${threshold * 100}% slack)`,\n );\n }\n }\n\n if (\"avgFrameTime\" in result && spec.maxAvgFrameTimeMs !== undefined) {\n const maxAllowed = spec.maxAvgFrameTimeMs * (1 + threshold);\n if (result.avgFrameTime > maxAllowed) {\n failures.push(\n `Frame time ${result.avgFrameTime}ms > baseline max ${spec.maxAvgFrameTimeMs}ms`,\n );\n }\n }\n\n if (\"avgFrameUs\" in result && spec.maxAvgFrameUs !== undefined) {\n const maxAllowed = spec.maxAvgFrameUs * (1 + threshold);\n if (result.avgFrameUs > maxAllowed) {\n failures.push(\n `Grid frame ${result.avgFrameUs}µs > baseline max ${spec.maxAvgFrameUs}µs`,\n );\n }\n }\n\n return { passed: failures.length === 0, failures };\n}\n\n/** Build a full Stage 1 report from scenario results */\nexport function buildStage1Report(\n scenarios: Stage1ScenarioResult[],\n): Stage1BrowserReport {\n return {\n timestamp: Date.now(),\n version: baseline.version,\n scenarios,\n allPassed: scenarios.every((s) => s.passed),\n regressionThreshold: baseline.regressionThreshold,\n };\n}\n","/**\n * WebGL vs WebGPU chart renderer comparison helpers.\n * @module testing/rendererBenchmark\n */\n\nimport type { BenchmarkResult } from \"./index\";\n\nexport interface RendererCompareResult {\n webgl: BenchmarkResult;\n webgpu: BenchmarkResult | null;\n webgpuActive: boolean;\n /** webgpuFps / webglFps — ≥1 means WebGPU is faster or equal */\n fpsRatio: number;\n /** Meets ADR target: WebGPU ≥ 95% of WebGL FPS */\n meetsTarget: boolean;\n recommendation: \"webgpu-ready\" | \"webgl-faster\" | \"webgpu-unavailable\";\n}\n\nexport function evaluateRendererCompare(\n webgl: BenchmarkResult,\n webgpu: BenchmarkResult | null,\n webgpuActive: boolean,\n minRatio = 0.95,\n): RendererCompareResult {\n if (!webgpuActive || !webgpu) {\n return {\n webgl,\n webgpu,\n webgpuActive: false,\n fpsRatio: 0,\n meetsTarget: false,\n recommendation: \"webgpu-unavailable\",\n };\n }\n\n const ratio = webgl.avgFps > 0 ? webgpu.avgFps / webgl.avgFps : 0;\n const meetsTarget = ratio >= minRatio;\n\n return {\n webgl,\n webgpu,\n webgpuActive: true,\n fpsRatio: ratio,\n meetsTarget,\n recommendation: meetsTarget ? \"webgpu-ready\" : \"webgl-faster\",\n };\n}\n","/**\n * Sci Plot - Testing Utilities\n * \n * Provides utilities for testing chart applications:\n * - Mock data generators\n * - Chart test harness\n * - Snapshot helpers\n * - Performance benchmarks\n * \n * @module testing\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport interface MockChartOptions {\n /** Canvas width (default: 800) */\n width?: number;\n /** Canvas height (default: 600) */\n height?: number;\n /** Device pixel ratio (default: 1) */\n devicePixelRatio?: number;\n /** Theme (default: 'dark') */\n theme?: string;\n /** Enable WebGL mock (default: true) */\n mockWebGL?: boolean;\n}\n\nexport interface WaveformOptions {\n /** Number of points (default: 1000) */\n pointCount?: number;\n /** Amplitude (default: 1) */\n amplitude?: number;\n /** Frequency in Hz (default: 1) */\n frequency?: number;\n /** Phase offset in radians (default: 0) */\n phase?: number;\n /** Noise level (0-1, default: 0) */\n noise?: number;\n /** X start value (default: 0) */\n xStart?: number;\n /** X end value (default: 10) */\n xEnd?: number;\n /** DC offset (default: 0) */\n offset?: number;\n}\n\nexport interface RandomDataOptions {\n /** Number of points (default: 1000) */\n pointCount?: number;\n /** X range [min, max] (default: [0, 100]) */\n xRange?: [number, number];\n /** Y range [min, max] (default: [-1, 1]) */\n yRange?: [number, number];\n /** Sort by X value (default: true) */\n sorted?: boolean;\n /** Seed for reproducible random (optional) */\n seed?: number;\n}\n\nexport interface BenchmarkResult {\n /** Average frames per second */\n avgFps: number;\n /** Minimum FPS recorded */\n minFps: number;\n /** Maximum FPS recorded */\n maxFps: number;\n /** Average frame time in ms */\n avgFrameTime: number;\n /** Total frames rendered */\n frameCount: number;\n /** Test duration in ms */\n duration: number;\n /** Points per frame */\n pointsRendered: number;\n /** Points per second throughput */\n throughput: number;\n /** Render-only throughput (1000 / avgFrameTime); can exceed wall FPS */\n renderFps?: number;\n}\n\nexport interface BenchmarkOptions {\n /** Duration of benchmark in ms (default: 5000) */\n duration?: number;\n /** Warmup duration in ms (default: 1000) */\n warmup?: number;\n /** Target FPS for assertions (default: 55) */\n targetFps?: number;\n /** Enable console output (default: false) */\n verbose?: boolean;\n}\n\nexport interface SnapshotOptions {\n /** Output format: 'json' | 'png' | 'canvas' (default: 'json') */\n format?: 'json' | 'png' | 'canvas';\n /** Include data in snapshot (default: false for performance) */\n includeData?: boolean;\n /** Include styles in snapshot (default: true) */\n includeStyles?: boolean;\n}\n\nexport interface ChartSnapshot {\n /** Snapshot timestamp */\n timestamp: number;\n /** Chart configuration */\n config: Record<string, unknown>;\n /** Series metadata (without data by default) */\n series: {\n id: string;\n type: string;\n pointCount: number;\n style?: Record<string, unknown>;\n }[];\n /** View bounds */\n bounds: {\n xMin: number;\n xMax: number;\n yMin: number;\n yMax: number;\n };\n /** Canvas data URL (if format is 'png') */\n image?: string;\n}\n\n// ============================================\n// Seeded Random Number Generator\n// ============================================\n\nclass SeededRandom {\n private seed: number;\n\n constructor(seed: number) {\n this.seed = seed;\n }\n\n next(): number {\n // Mulberry32 PRNG\n let t = (this.seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n\n nextRange(min: number, max: number): number {\n return min + this.next() * (max - min);\n }\n}\n\n// ============================================\n// Data Generators\n// ============================================\n\n/**\n * Generate a sine wave\n */\nexport function generateSineWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const baseValue =\n opts.amplitude * Math.sin(2 * Math.PI * opts.frequency * x[i] + opts.phase);\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate a square wave\n */\nexport function generateSquareWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const t = x[i] * opts.frequency + opts.phase / (2 * Math.PI);\n const baseValue = Math.sign(Math.sin(2 * Math.PI * t)) * opts.amplitude;\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate a sawtooth wave\n */\nexport function generateSawtoothWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const t = x[i] * opts.frequency + opts.phase / (2 * Math.PI);\n const baseValue = opts.amplitude * 2 * (t - Math.floor(t + 0.5));\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate a triangle wave\n */\nexport function generateTriangleWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const t = x[i] * opts.frequency + opts.phase / (2 * Math.PI);\n const baseValue = opts.amplitude * 2 * Math.abs(2 * (t - Math.floor(t + 0.5))) - opts.amplitude;\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate random data points\n */\nexport function generateRandomData(options?: RandomDataOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<RandomDataOptions> = {\n pointCount: 1000,\n xRange: [0, 100],\n yRange: [-1, 1],\n sorted: true,\n seed: Date.now(),\n ...options,\n };\n\n const rng = new SeededRandom(opts.seed);\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = rng.nextRange(opts.xRange[0], opts.xRange[1]);\n y[i] = rng.nextRange(opts.yRange[0], opts.yRange[1]);\n }\n\n // Sort by X if requested\n if (opts.sorted) {\n const indices = Array.from({ length: opts.pointCount }, (_, i) => i);\n indices.sort((a, b) => x[a] - x[b]);\n \n const sortedX = new Float32Array(opts.pointCount);\n const sortedY = new Float32Array(opts.pointCount);\n \n for (let i = 0; i < opts.pointCount; i++) {\n sortedX[i] = x[indices[i]];\n sortedY[i] = y[indices[i]];\n }\n \n return { x: sortedX, y: sortedY };\n }\n\n return { x, y };\n}\n\n/**\n * Generate a cyclic voltammogram (CV) mock data\n */\nexport function generateCVData(options?: {\n pointCount?: number;\n vMin?: number;\n vMax?: number;\n cycles?: number;\n peakCurrent?: number;\n noise?: number;\n}): { x: Float32Array; y: Float32Array } {\n const opts = {\n pointCount: 2000,\n vMin: -0.5,\n vMax: 0.5,\n cycles: 1,\n peakCurrent: 10e-6, // 10 µA\n noise: 0.02,\n ...options,\n };\n\n const totalPoints = opts.pointCount * opts.cycles;\n const x = new Float32Array(totalPoints);\n const y = new Float32Array(totalPoints);\n \n const pointsPerCycle = opts.pointCount;\n const halfCycle = pointsPerCycle / 2;\n\n for (let c = 0; c < opts.cycles; c++) {\n for (let i = 0; i < pointsPerCycle; i++) {\n const idx = c * pointsPerCycle + i;\n \n // Potential sweep\n if (i < halfCycle) {\n x[idx] = opts.vMin + (opts.vMax - opts.vMin) * (i / halfCycle);\n } else {\n x[idx] = opts.vMax - (opts.vMax - opts.vMin) * ((i - halfCycle) / halfCycle);\n }\n \n // Current response (simplified Randles-Sevcik)\n const E = x[idx];\n const E0 = 0; // Formal potential\n const scanDirection = i < halfCycle ? 1 : -1;\n \n // Gaussian-like peak\n const peakWidth = 0.1;\n const exponent = -Math.pow(E - E0, 2) / (2 * peakWidth * peakWidth);\n const peakCurrent = opts.peakCurrent * Math.exp(exponent);\n \n // Add capacitive current and noise\n const capacitive = scanDirection * opts.peakCurrent * 0.1;\n const noiseValue = (Math.random() - 0.5) * 2 * opts.noise * opts.peakCurrent;\n \n y[idx] = scanDirection * peakCurrent + capacitive + noiseValue;\n }\n }\n\n return { x, y };\n}\n\n/**\n * Generate electrochemical impedance spectroscopy (EIS) Nyquist data\n */\nexport function generateNyquistData(options?: {\n pointCount?: number;\n rSolution?: number;\n rCharge?: number;\n frequency?: [number, number];\n}): { x: Float32Array; y: Float32Array } {\n const opts = {\n pointCount: 50,\n rSolution: 100, // Ohms\n rCharge: 1000, // Ohms\n frequency: [1e5, 0.01] as [number, number],\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n \n // Logarithmic frequency spacing\n const logFMin = Math.log10(opts.frequency[1]);\n const logFMax = Math.log10(opts.frequency[0]);\n \n for (let i = 0; i < opts.pointCount; i++) {\n const logF = logFMax - (logFMax - logFMin) * (i / (opts.pointCount - 1));\n const omega = 2 * Math.PI * Math.pow(10, logF);\n \n // Simple Randles circuit: Rs + (Rct || CPE)\n const tau = opts.rCharge * 1e-5; // Time constant\n const realPart = opts.rSolution + opts.rCharge / (1 + Math.pow(omega * tau, 2));\n const imagPart = omega * tau * opts.rCharge / (1 + Math.pow(omega * tau, 2));\n \n x[i] = realPart;\n y[i] = -imagPart; // Negative for Nyquist convention\n }\n\n return { x, y };\n}\n\n// ============================================\n// Performance Benchmarking\n// ============================================\n\n/**\n * Benchmark chart rendering performance\n */\nexport async function benchmarkRender(\n chart: { render: () => void; getAllSeries: () => { getPointCount: () => number }[] },\n options?: BenchmarkOptions\n): Promise<BenchmarkResult> {\n const opts: Required<BenchmarkOptions> = {\n duration: 5000,\n warmup: 1000,\n targetFps: 55,\n verbose: false,\n ...options,\n };\n\n const fpsHistory: number[] = [];\n const frameTimes: number[] = [];\n let frameCount = 0;\n\n // Calculate total points\n const totalPoints = chart\n .getAllSeries()\n .reduce((sum, s) => sum + s.getPointCount(), 0);\n\n return new Promise((resolve) => {\n const endTime = performance.now() + opts.warmup + opts.duration;\n const warmupEndTime = performance.now() + opts.warmup;\n let recording = false;\n let recordingStartTime = 0;\n\n function frame() {\n const now = performance.now();\n\n if (now >= endTime) {\n const avgRenderMs =\n frameTimes.length > 0\n ? frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length\n : 0;\n const recordElapsedMs =\n recordingStartTime > 0 ? now - recordingStartTime : opts.duration;\n // Wall-clock FPS (includes rAF pacing + work outside timed render)\n const wallFps =\n frameCount > 0 && recordElapsedMs > 0\n ? (frameCount / recordElapsedMs) * 1000\n : 0;\n // Instantaneous render throughput (can exceed monitor refresh; useful for micro-bench)\n const renderFps =\n fpsHistory.length > 0\n ? fpsHistory.reduce((a, b) => a + b, 0) / fpsHistory.length\n : avgRenderMs > 0\n ? 1000 / avgRenderMs\n : 0;\n\n const result: BenchmarkResult = {\n avgFps: Math.round(wallFps * 100) / 100,\n minFps: Math.round((fpsHistory.length > 0 ? Math.min(...fpsHistory) : wallFps) * 100) / 100,\n maxFps: Math.round((fpsHistory.length > 0 ? Math.max(...fpsHistory) : wallFps) * 100) / 100,\n avgFrameTime: Math.round(avgRenderMs * 1000) / 1000,\n frameCount,\n duration: opts.duration,\n pointsRendered: totalPoints,\n throughput: Math.round((totalPoints * wallFps) / 1000) * 1000,\n /** @internal render-only FPS (not wall clock) */\n ...(renderFps > 0 ? { renderFps: Math.round(renderFps * 100) / 100 } : {}),\n } as BenchmarkResult;\n\n resolve(result);\n return;\n }\n\n // Start recording after warmup\n if (now >= warmupEndTime && !recording) {\n recording = true;\n recordingStartTime = now;\n frameCount = 0;\n frameTimes.length = 0;\n fpsHistory.length = 0;\n }\n\n const renderStart = performance.now();\n chart.render();\n const renderEnd = performance.now();\n\n if (recording) {\n const frameTime = renderEnd - renderStart;\n frameTimes.push(frameTime);\n frameCount++;\n\n const recentTimes = frameTimes.slice(-30);\n if (recentTimes.length > 0) {\n const avgRecentTime = recentTimes.reduce((a, b) => a + b, 0) / recentTimes.length;\n if (avgRecentTime > 0) {\n fpsHistory.push(1000 / avgRecentTime);\n }\n }\n }\n\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n });\n}\n\n// ============================================\n// Snapshot Utilities\n// ============================================\n\n/**\n * Create a snapshot of chart state for testing\n */\nexport function createSnapshot(\n chart: {\n getViewBounds: () => { xMin: number; xMax: number; yMin: number; yMax: number };\n getAllSeries: () => { getId: () => string; getType: () => string; getPointCount: () => number; getStyle: () => Record<string, unknown> }[];\n exportImage?: () => string;\n },\n options?: SnapshotOptions\n): ChartSnapshot {\n const opts: Required<SnapshotOptions> = {\n format: 'json',\n includeData: false,\n includeStyles: true,\n ...options,\n };\n\n const series = chart.getAllSeries().map((s) => ({\n id: s.getId(),\n type: s.getType(),\n pointCount: s.getPointCount(),\n ...(opts.includeStyles ? { style: s.getStyle() } : {}),\n }));\n\n const snapshot: ChartSnapshot = {\n timestamp: Date.now(),\n config: {},\n series,\n bounds: chart.getViewBounds(),\n };\n\n if (opts.format === 'png' && chart.exportImage) {\n snapshot.image = chart.exportImage();\n }\n\n return snapshot;\n}\n\n/**\n * Compare two snapshots for equality\n */\nexport function compareSnapshots(\n a: ChartSnapshot,\n b: ChartSnapshot,\n tolerance: number = 1e-6\n): {\n equal: boolean;\n differences: string[];\n} {\n const differences: string[] = [];\n\n // Compare series count\n if (a.series.length !== b.series.length) {\n differences.push(`Series count: ${a.series.length} vs ${b.series.length}`);\n }\n\n // Compare series metadata\n for (let i = 0; i < Math.min(a.series.length, b.series.length); i++) {\n const sa = a.series[i];\n const sb = b.series[i];\n\n if (sa.id !== sb.id) {\n differences.push(`Series[${i}] id: \"${sa.id}\" vs \"${sb.id}\"`);\n }\n if (sa.type !== sb.type) {\n differences.push(`Series[${i}] type: \"${sa.type}\" vs \"${sb.type}\"`);\n }\n if (sa.pointCount !== sb.pointCount) {\n differences.push(`Series[${i}] pointCount: ${sa.pointCount} vs ${sb.pointCount}`);\n }\n }\n\n // Compare bounds with tolerance\n const boundsKeys: (keyof ChartSnapshot['bounds'])[] = ['xMin', 'xMax', 'yMin', 'yMax'];\n for (const key of boundsKeys) {\n if (Math.abs(a.bounds[key] - b.bounds[key]) > tolerance) {\n differences.push(`Bounds.${key}: ${a.bounds[key]} vs ${b.bounds[key]}`);\n }\n }\n\n return {\n equal: differences.length === 0,\n differences,\n };\n}\n\n// ============================================\n// Test Assertions\n// ============================================\n\n/**\n * Assert that a benchmark meets performance requirements\n */\nexport function assertPerformance(\n result: BenchmarkResult,\n requirements: {\n minFps?: number;\n maxFrameTime?: number;\n minThroughput?: number;\n }\n): { passed: boolean; failures: string[] } {\n const failures: string[] = [];\n\n if (requirements.minFps && result.avgFps < requirements.minFps) {\n failures.push(`FPS ${result.avgFps} < required ${requirements.minFps}`);\n }\n\n if (requirements.maxFrameTime && result.avgFrameTime > requirements.maxFrameTime) {\n failures.push(`Frame time ${result.avgFrameTime}ms > required ${requirements.maxFrameTime}ms`);\n }\n\n if (requirements.minThroughput && result.throughput < requirements.minThroughput) {\n failures.push(`Throughput ${result.throughput} < required ${requirements.minThroughput}`);\n }\n\n return {\n passed: failures.length === 0,\n failures,\n };\n}\n\n/**\n * Wait for a number of animation frames\n */\nexport function waitForFrames(count: number = 1): Promise<void> {\n return new Promise((resolve) => {\n let remaining = count;\n function tick() {\n remaining--;\n if (remaining <= 0) {\n resolve();\n } else {\n requestAnimationFrame(tick);\n }\n }\n requestAnimationFrame(tick);\n });\n}\n\n/**\n * Wait for a specified duration\n */\nexport function waitFor(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// Stage 1 grid spike + browser benchmarks\nexport {\n benchmarkCanvasGrid,\n benchmarkWebGLGrid,\n compareGridBackends,\n countGridVertices,\n type GridBenchmarkResult,\n type GridCompareResult,\n} from \"./gridSpikeBenchmark\";\n\nexport {\n getBaseline,\n compareScenarioToBaseline,\n buildStage1Report,\n effectiveBenchmarkFps,\n HEADLESS_LOW_FRAME_THRESHOLD,\n SMOKE_FLOORS,\n type Stage1ScenarioResult,\n type Stage1BrowserReport,\n} from \"./stage1BrowserBench\";\n\nexport {\n evaluateRendererCompare,\n type RendererCompareResult,\n} from \"./rendererBenchmark\";\n"],"names":["WebGPURenderer","canvas","opts","__publicField","gpu","ctx","format","crosshairManifest","CrosshairPlugin","definePlugin","config","showVertical","showHorizontal","color","lineStyle","lineWidth","snapToData","valueFormat","valueDisplayMode","cornerPosition","cursorX","cursorY","overlayId","pluginCtx","overlay","resizeCanvas","event","nearest","render","size","dpr","width","height","plotArea","lineColor","_a","drawFloatingLabels","drawCornerLabels","x","y","bgColor","dataX","dataY","xText","xLabelWidth","xLabelHeight","xLabelX","xLabelY","yText","yLabelWidth","yLabelHeight","yLabelX","yLabelY","xMetrics","yMetrics","maxWidth","padding","lineHeight","boxWidth","boxHeight","boxX","boxY","statsManifest","StatsPlugin","position","show","seriesId","autoUpdate","container","posStyle","updateStats","content","allSeries","targetSeries","s","allY","series","data","stats","computeStats","lines","values","n","sum","min","max","v","mean","sumSq","std","watermarkManifest","WatermarkPlugin","text","fontSize","fontFamily","rotation","ctx2d","gridHighlightManifest","GridHighlightPlugin","xIntervals","yIntervals","opacity","_event","interval","x1","x2","y1","y2","dataLoggerManifest","DataLoggerPlugin","logDataUpdates","logViewChanges","logInteractions","maxEntries","entries","addEntry","type","_ctx","saved","directionIndicatorManifest","DirectionIndicatorPlugin","sampleSize","minVelocity","historySize","idleTimeout","currentDirection","targetSeriesId","positionHistoryX","positionHistoryY","angleHistory","maxHistorySize","timeoutTimer","lastPointTimestamp","lastSeenX","lastSeenY","currentIdleTimeout","updateDirection","age","_pluginCtx","newConfig","canvasSize","totalPoints","lastX","lastY","startIdx","sumT","sumPX","sumPY","sumTPX","sumTPY","sumTT","i","t","pixelX","pixelY","meanT","meanPX","meanPY","denominator","slopePX","slopePY","rawAngle","lastPixelX","lastPixelY","smoothX","average","smoothY","smoothedAngle","smoothAngle","magnitude","val","angles","sumX","sumY","angle","arrowColor","drawArrow","length","triangleHeight","triangleWidth","BuiltinPlugins","manifest","DEFAULT_CONFIG","PluginDragEdit","userConfig","isDragging","draggedPoint","dragStartX","dragStartY","hasMoved","findNearestPoint","mouseX","mouseY","picked","pixelToData","snapToGrid","value","applyConstraints","newX","newY","constraint","validateAndSnap","finalX","finalY","tempPoint","validation","updatePointData","index","_b","_c","createDragEvent","drawPreview","pCtx","coords","origPixelX","origPixelY","currPixelX","currPixelY","api","seriesIds","point","dx","dy","dragEvent","valid","VERT_SRC","FRAG_SRC","compileShader","gl","source","shader","createProgram","vs","fs","program","buildGridLineVertices","spec","xLines","yLines","y0","x0","vertCount","out","o","WebGLGridSpike","buf","vertices","lineSegments","c","createMinimalMock2D","noop","getCanvas2DContext","makePlotArea","margin","tickPixelLines","_plotArea","xScale","yScale","xTickCount","yTickCount","snapLineCoord","measureFrames","runFrame","frames","samples","t0","b","avg","p95","benchmarkCanvasGrid","options","theme","DARK_THEME","LinearScale","renderer","OverlayRenderer","benchmarkWebGLGrid","spike","compareGridBackends","canvas2d","webgl","gainPercent","getBaseline","baseline","compareScenarioToBaseline","scenarioId","result","failures","threshold","minAllowed","maxAllowed","evaluateRendererCompare","webgpu","webgpuActive","minRatio","ratio","meetsTarget","SeededRandom","seed","generateSineWave","baseValue","noiseValue","generateSquareWave","generateSawtoothWave","generateTriangleWave","generateRandomData","rng","indices","_","a","sortedX","sortedY","generateCVData","pointsPerCycle","halfCycle","idx","E","E0","scanDirection","peakWidth","exponent","peakCurrent","capacitive","generateNyquistData","logFMin","logFMax","logF","omega","tau","realPart","imagPart","benchmarkRender","chart","fpsHistory","frameTimes","frameCount","resolve","endTime","warmupEndTime","recording","recordingStartTime","frame","now","avgRenderMs","recordElapsedMs","wallFps","renderFps","renderStart","renderEnd","frameTime","recentTimes","avgRecentTime","createSnapshot","snapshot","compareSnapshots","tolerance","differences","sa","sb","boundsKeys","key","assertPerformance","requirements","waitForFrames","count","remaining","tick","waitFor","ms"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"velo-plot.full.js","sources":["../src/renderer/WebGPURenderer.ts","../src/plugins/builtins/crosshair/CrosshairPlugin.ts","../src/plugins/builtins/stats/StatsPlugin.ts","../src/plugins/builtins/watermark/WatermarkPlugin.ts","../src/plugins/builtins/grid-highlight/GridHighlightPlugin.ts","../src/plugins/builtins/data-logger/DataLoggerPlugin.ts","../src/plugins/builtins/direction-indicator/DirectionIndicatorPlugin.ts","../src/plugins/builtins/index.ts","../src/plugins/drag-edit/index.ts","../src/renderer/spike/WebGLGridSpike.ts","../src/testing/gridSpikeBenchmark.ts","../src/testing/stage1BrowserBench.ts","../src/testing/rendererBenchmark.ts","../src/testing/index.ts"],"sourcesContent":["export interface WebGPURendererOptions {\n powerPreference?: \"low-power\" | \"high-performance\";\n preferredFormat?: string;\n antialias?: boolean;\n}\n\nexport class WebGPURenderer {\n public readonly available: boolean;\n\n private canvas: HTMLCanvasElement;\n private adapter: any;\n private device: any;\n private context: any;\n\n constructor(canvas: HTMLCanvasElement, opts: WebGPURendererOptions = {}) {\n this.canvas = canvas;\n this.available = WebGPURenderer.isSupported();\n void opts;\n }\n\n static isSupported(): boolean {\n return (\n typeof (globalThis as any).navigator !== \"undefined\" &&\n typeof (globalThis as any).navigator.gpu !== \"undefined\"\n );\n }\n\n async init(opts: WebGPURendererOptions = {}): Promise<void> {\n if (!this.available) {\n throw new Error(\"[VeloPlot] WebGPU is not supported in this environment\");\n }\n\n const gpu = (globalThis as any).navigator.gpu;\n this.adapter = await gpu.requestAdapter({\n powerPreference: opts.powerPreference ?? \"high-performance\",\n });\n\n if (!this.adapter) {\n throw new Error(\"[VeloPlot] Failed to request WebGPU adapter\");\n }\n\n this.device = await this.adapter.requestDevice();\n\n const ctx = (this.canvas as any).getContext(\"webgpu\");\n if (!ctx) {\n throw new Error(\"[VeloPlot] Failed to get WebGPU context\");\n }\n\n this.context = ctx;\n\n const format =\n opts.preferredFormat ??\n (gpu.getPreferredCanvasFormat\n ? gpu.getPreferredCanvasFormat()\n : \"bgra8unorm\");\n\n this.context.configure({\n device: this.device,\n format,\n alphaMode: \"premultiplied\",\n });\n }\n\n destroy(): void {\n this.device = undefined;\n this.adapter = undefined;\n this.context = undefined;\n }\n}\n","import type {\n PluginContext,\n PluginManifest,\n InteractionEvent,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\nimport type {\n CrosshairValueMode,\n CornerPosition\n} from \"../../../core/layout\";\n\nexport interface CrosshairPluginConfig {\n /** Show vertical line (default: true) */\n showVertical?: boolean;\n /** Show horizontal line (default: true) */\n showHorizontal?: boolean;\n /** Line color (default: from theme) */\n color?: string;\n /** Line style (default: 'dashed') */\n lineStyle?: \"solid\" | \"dashed\" | \"dotted\";\n /** Line width (default: 1) */\n lineWidth?: number;\n /** \n * @deprecated Use valueDisplayMode instead. **Removed in v4.0.**\n * Show axis labels (will be converted to valueDisplayMode)\n */\n showAxisLabels?: boolean;\n /**\n * Display mode for X,Y coordinate values (default: 'disabled')\n * - 'disabled': Never show coordinate values\n * - 'corner': Show values in a fixed corner position\n * - 'floating': Show values next to the cursor (axis labels)\n */\n valueDisplayMode?: CrosshairValueMode;\n /**\n * Corner position when valueDisplayMode is 'corner' (default: 'top-left')\n */\n cornerPosition?: CornerPosition;\n /** Snap to nearest data point (default: false) */\n snapToData?: boolean;\n /** Value format options */\n valueFormat?: {\n /** X value precision (default: 4) */\n xPrecision?: number;\n /** Y value precision (default: 4) */\n yPrecision?: number;\n };\n}\n\nconst crosshairManifest: PluginManifest = {\n name: \"crosshair\",\n version: \"1.0.0\",\n description: \"Interactive crosshair that follows mouse cursor\",\n provides: [\"interaction\", \"visualization\"],\n tags: [\"cursor\", \"crosshair\", \"tooltip\"],\n};\n\nexport const CrosshairPlugin = definePlugin<CrosshairPluginConfig>(\n crosshairManifest,\n (config = {}) => {\n const {\n showVertical = true,\n showHorizontal = true,\n color,\n lineStyle = \"dashed\",\n lineWidth = 1,\n snapToData = false,\n valueFormat = { xPrecision: 4, yPrecision: 4 },\n } = config;\n\n // Handle deprecated showAxisLabels -> convert to valueDisplayMode\n let valueDisplayMode: CrosshairValueMode = config.valueDisplayMode ?? 'disabled';\n if (config.showAxisLabels !== undefined && config.valueDisplayMode === undefined) {\n valueDisplayMode = config.showAxisLabels ? 'floating' : 'disabled';\n }\n const cornerPosition: CornerPosition = config.cornerPosition ?? 'top-left';\n\n let cursorX = -1;\n let cursorY = -1;\n let overlayId: string;\n let canvas: HTMLCanvasElement | null = null;\n let ctx: CanvasRenderingContext2D | null = null;\n\n return {\n onInit(pluginCtx: PluginContext) {\n overlayId = \"crosshair-overlay\";\n const overlay = pluginCtx.ui.createOverlay(overlayId, {\n zIndex: 500,\n position: { top: \"0\", left: \"0\", right: \"0\", bottom: \"0\" },\n });\n\n canvas = document.createElement(\"canvas\");\n canvas.style.cssText = \"width: 100%; height: 100%;\";\n overlay.appendChild(canvas);\n\n ctx = canvas.getContext(\"2d\");\n resizeCanvas(pluginCtx);\n },\n\n onDestroy(pluginCtx: PluginContext) {\n pluginCtx.ui.removeOverlay(overlayId);\n canvas = null;\n ctx = null;\n },\n\n onResize(pluginCtx: PluginContext) {\n resizeCanvas(pluginCtx);\n },\n\n onInteraction(pluginCtx: PluginContext, event: InteractionEvent) {\n if (event.type === \"mousemove\") {\n cursorX = event.pixelX;\n cursorY = event.pixelY;\n\n if (snapToData && event.inPlotArea) {\n const nearest = pluginCtx.coords.pickPoint(cursorX, cursorY);\n if (nearest) {\n cursorX = nearest.pixelX;\n cursorY = nearest.pixelY;\n }\n }\n\n render(pluginCtx);\n }\n },\n\n onViewChange() {\n // Re-render on zoom/pan\n if (cursorX >= 0 && cursorY >= 0) {\n // Will be re-rendered on next frame\n }\n },\n };\n\n function resizeCanvas(pluginCtx: PluginContext) {\n if (!canvas || !ctx) return;\n const size = pluginCtx.render.canvasSize;\n const dpr = pluginCtx.render.pixelRatio;\n canvas.width = size.width * dpr;\n canvas.height = size.height * dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.scale(dpr, dpr);\n }\n\n function render(pluginCtx: PluginContext) {\n if (!ctx || !canvas) return;\n\n const { width, height } = pluginCtx.render.canvasSize;\n ctx.clearRect(0, 0, width, height);\n\n if (cursorX < 0 || cursorY < 0) return;\n\n const plotArea = pluginCtx.render.plotArea;\n if (\n cursorX < plotArea.x ||\n cursorX > plotArea.x + plotArea.width ||\n cursorY < plotArea.y ||\n cursorY > plotArea.y + plotArea.height\n ) {\n return;\n }\n\n const lineColor = color || (pluginCtx.ui.theme.cursor as unknown as Record<string, unknown>)?.color as string || \"#888888\";\n\n ctx.save();\n ctx.strokeStyle = lineColor;\n ctx.lineWidth = lineWidth;\n\n if (lineStyle === \"dashed\") {\n ctx.setLineDash([6, 4]);\n } else if (lineStyle === \"dotted\") {\n ctx.setLineDash([2, 2]);\n }\n\n // Vertical line\n if (showVertical) {\n ctx.beginPath();\n ctx.moveTo(cursorX, plotArea.y);\n ctx.lineTo(cursorX, plotArea.y + plotArea.height);\n ctx.stroke();\n }\n\n // Horizontal line\n if (showHorizontal) {\n ctx.beginPath();\n ctx.moveTo(plotArea.x, cursorY);\n ctx.lineTo(plotArea.x + plotArea.width, cursorY);\n ctx.stroke();\n }\n\n ctx.restore();\n\n // Value display based on mode\n if (valueDisplayMode === 'floating') {\n drawFloatingLabels(pluginCtx, ctx, cursorX, cursorY, lineColor);\n } else if (valueDisplayMode === 'corner') {\n drawCornerLabels(pluginCtx, ctx, cursorX, cursorY, lineColor);\n }\n // 'disabled' mode: don't draw any labels\n }\n\n function drawFloatingLabels(\n pluginCtx: PluginContext,\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n bgColor: string\n ) {\n const dataX = pluginCtx.coords.pixelToDataX(x);\n const dataY = pluginCtx.coords.pixelToDataY(y);\n const plotArea = pluginCtx.render.plotArea;\n\n ctx.save();\n ctx.font = \"11px system-ui, sans-serif\";\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"top\";\n\n // X axis label\n const xText = dataX.toPrecision(valueFormat.xPrecision);\n const xMetrics = ctx.measureText(xText);\n const xLabelWidth = xMetrics.width + 8;\n const xLabelHeight = 18;\n const xLabelX = x - xLabelWidth / 2;\n const xLabelY = plotArea.y + plotArea.height + 2;\n\n ctx.fillStyle = bgColor;\n ctx.fillRect(xLabelX, xLabelY, xLabelWidth, xLabelHeight);\n ctx.fillStyle = \"#ffffff\";\n ctx.fillText(xText, x, xLabelY + 3);\n\n // Y axis label\n ctx.textAlign = \"right\";\n ctx.textBaseline = \"middle\";\n const yText = dataY.toPrecision(valueFormat.yPrecision);\n const yMetrics = ctx.measureText(yText);\n const yLabelWidth = yMetrics.width + 8;\n const yLabelHeight = 18;\n const yLabelX = plotArea.x - yLabelWidth - 2;\n const yLabelY = y - yLabelHeight / 2;\n\n ctx.fillStyle = bgColor;\n ctx.fillRect(yLabelX, yLabelY, yLabelWidth, yLabelHeight);\n ctx.fillStyle = \"#ffffff\";\n ctx.fillText(yText, plotArea.x - 6, y);\n\n ctx.restore();\n }\n\n function drawCornerLabels(\n pluginCtx: PluginContext,\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n bgColor: string\n ) {\n const dataX = pluginCtx.coords.pixelToDataX(x);\n const dataY = pluginCtx.coords.pixelToDataY(y);\n const plotArea = pluginCtx.render.plotArea;\n\n ctx.save();\n ctx.font = \"11px system-ui, sans-serif\";\n\n const xText = `X: ${dataX.toPrecision(valueFormat.xPrecision)}`;\n const yText = `Y: ${dataY.toPrecision(valueFormat.yPrecision)}`;\n\n const xMetrics = ctx.measureText(xText);\n const yMetrics = ctx.measureText(yText);\n const maxWidth = Math.max(xMetrics.width, yMetrics.width);\n const padding = 6;\n const lineHeight = 16;\n const boxWidth = maxWidth + padding * 2;\n const boxHeight = lineHeight * 2 + padding * 2;\n\n // Determine corner position\n let boxX: number;\n let boxY: number;\n\n switch (cornerPosition) {\n case 'top-left':\n boxX = plotArea.x + 8;\n boxY = plotArea.y + 8;\n break;\n case 'top-right':\n boxX = plotArea.x + plotArea.width - boxWidth - 8;\n boxY = plotArea.y + 8;\n break;\n case 'bottom-left':\n boxX = plotArea.x + 8;\n boxY = plotArea.y + plotArea.height - boxHeight - 8;\n break;\n case 'bottom-right':\n boxX = plotArea.x + plotArea.width - boxWidth - 8;\n boxY = plotArea.y + plotArea.height - boxHeight - 8;\n break;\n default:\n boxX = plotArea.x + 8;\n boxY = plotArea.y + 8;\n }\n\n // Draw background\n ctx.fillStyle = bgColor;\n ctx.globalAlpha = 0.85;\n ctx.fillRect(boxX, boxY, boxWidth, boxHeight);\n ctx.globalAlpha = 1.0;\n\n // Draw border\n ctx.strokeStyle = \"rgba(255,255,255,0.3)\";\n ctx.lineWidth = 1;\n ctx.strokeRect(boxX, boxY, boxWidth, boxHeight);\n\n // Draw text\n ctx.fillStyle = \"#ffffff\";\n ctx.textAlign = \"left\";\n ctx.textBaseline = \"top\";\n ctx.fillText(xText, boxX + padding, boxY + padding);\n ctx.fillText(yText, boxX + padding, boxY + padding + lineHeight);\n\n ctx.restore();\n }\n }\n);\n\n","import type {\n PluginContext,\n PluginManifest,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface StatsPluginConfig {\n /** Position of the stats overlay */\n position?: \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n /** Which stats to show */\n show?: Array<\"count\" | \"mean\" | \"min\" | \"max\" | \"std\" | \"range\">;\n /** Series ID to compute stats for (default: all) */\n seriesId?: string;\n /** Update on every data change (default: true) */\n autoUpdate?: boolean;\n}\n\nconst statsManifest: PluginManifest = {\n name: \"statistics-overlay\",\n version: \"1.0.0\",\n description: \"Displays real-time statistics for chart data\",\n provides: [\"visualization\", \"analysis\"],\n tags: [\"statistics\", \"overlay\", \"analytics\"],\n};\n\nexport const StatsPlugin = definePlugin<StatsPluginConfig>(\n statsManifest,\n (config = {}) => {\n const {\n position = \"top-right\",\n show = [\"count\", \"mean\", \"min\", \"max\"],\n seriesId,\n autoUpdate = true,\n } = config;\n\n let overlayId: string;\n let container: HTMLDivElement | null = null;\n\n return {\n onInit(ctx: PluginContext) {\n overlayId = \"stats-overlay\";\n const posStyle: Record<string, string> = {};\n\n if (position.includes(\"top\")) posStyle.top = \"10px\";\n if (position.includes(\"bottom\")) posStyle.bottom = \"10px\";\n if (position.includes(\"left\")) posStyle.left = \"10px\";\n if (position.includes(\"right\")) posStyle.right = \"10px\";\n\n container = ctx.ui.createOverlay(overlayId, {\n zIndex: 800,\n position: posStyle,\n pointerEvents: false,\n });\n\n container.innerHTML = `\n <div style=\"\n background: rgba(0, 0, 0, 0.85);\n color: #fff;\n padding: 10px 14px;\n border-radius: 6px;\n font-family: ui-monospace, monospace;\n font-size: 12px;\n line-height: 1.6;\n box-shadow: 0 4px 12px rgba(0,0,0,0.3);\n \">\n <div style=\"font-weight: bold; margin-bottom: 4px; color: #4ade80;\">📊 Statistics</div>\n <div class=\"stats-content\"></div>\n </div>\n `;\n\n updateStats(ctx);\n },\n\n onDestroy(ctx: PluginContext) {\n ctx.ui.removeOverlay(overlayId);\n container = null;\n },\n\n onDataUpdate(ctx: PluginContext) {\n if (autoUpdate) {\n updateStats(ctx);\n }\n },\n\n onSeriesAdd(ctx: PluginContext) {\n updateStats(ctx);\n },\n\n onSeriesRemove(ctx: PluginContext) {\n updateStats(ctx);\n },\n\n api: {\n refresh(ctx: PluginContext) {\n updateStats(ctx);\n },\n },\n };\n\n function updateStats(ctx: PluginContext) {\n if (!container) return;\n\n const content = container.querySelector(\".stats-content\");\n if (!content) return;\n\n const allSeries = ctx.data.getAllSeries();\n const targetSeries = seriesId\n ? allSeries.filter((s) => s.getId() === seriesId)\n : allSeries;\n\n if (targetSeries.length === 0) {\n content.innerHTML = \"<div style='color: #888'>No data</div>\";\n return;\n }\n\n // Aggregate all Y data\n let allY: number[] = [];\n targetSeries.forEach((series) => {\n const data = series.getData();\n if (data?.y) {\n allY = allY.concat(Array.from(data.y));\n }\n });\n\n if (allY.length === 0) {\n content.innerHTML = \"<div style='color: #888'>No data</div>\";\n return;\n }\n\n const stats = computeStats(allY);\n const lines: string[] = [];\n\n if (show.includes(\"count\")) {\n lines.push(`<div>N: <span style=\"color: #60a5fa\">${stats.count.toLocaleString()}</span></div>`);\n }\n if (show.includes(\"mean\")) {\n lines.push(`<div>μ: <span style=\"color: #60a5fa\">${stats.mean.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"min\")) {\n lines.push(`<div>Min: <span style=\"color: #60a5fa\">${stats.min.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"max\")) {\n lines.push(`<div>Max: <span style=\"color: #60a5fa\">${stats.max.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"std\")) {\n lines.push(`<div>σ: <span style=\"color: #60a5fa\">${stats.std.toPrecision(4)}</span></div>`);\n }\n if (show.includes(\"range\")) {\n lines.push(`<div>Range: <span style=\"color: #60a5fa\">${stats.range.toPrecision(4)}</span></div>`);\n }\n\n content.innerHTML = lines.join(\"\");\n }\n\n function computeStats(values: number[]) {\n const n = values.length;\n let sum = 0;\n let min = Infinity;\n let max = -Infinity;\n\n for (const v of values) {\n sum += v;\n if (v < min) min = v;\n if (v > max) max = v;\n }\n\n const mean = sum / n;\n\n let sumSq = 0;\n for (const v of values) {\n sumSq += (v - mean) ** 2;\n }\n const std = Math.sqrt(sumSq / n);\n\n return {\n count: n,\n mean,\n min,\n max,\n std,\n range: max - min,\n };\n }\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface WatermarkPluginConfig {\n /** Watermark text */\n text: string;\n /** Font size (default: 48) */\n fontSize?: number;\n /** Font family (default: system-ui) */\n fontFamily?: string;\n /** Text color with opacity (default: rgba(128,128,128,0.15)) */\n color?: string;\n /** Position (default: center) */\n position?: \"center\" | \"bottom-right\" | \"bottom-left\";\n /** Rotation in degrees (default: -30 for center, 0 for corners) */\n rotation?: number;\n}\n\nconst watermarkManifest: PluginManifest = {\n name: \"watermark\",\n version: \"1.0.0\",\n description: \"Adds a customizable watermark to the chart\",\n provides: [\"visualization\"],\n tags: [\"watermark\", \"branding\", \"overlay\"],\n};\n\nexport const WatermarkPlugin = definePlugin<WatermarkPluginConfig>(\n watermarkManifest,\n (config) => {\n if (!config?.text) {\n throw new Error(\"WatermarkPlugin requires 'text' configuration\");\n }\n\n const {\n text,\n fontSize = 48,\n fontFamily = \"system-ui, sans-serif\",\n color = \"rgba(128, 128, 128, 0.15)\",\n position = \"center\",\n rotation = position === \"center\" ? -30 : 0,\n } = config;\n\n return {\n onRenderOverlay(ctx: PluginContext) {\n const ctx2d = ctx.render.ctx2d;\n if (!ctx2d) return;\n\n // width/height available for future use\n void ctx.render.canvasSize;\n const plotArea = ctx.render.plotArea;\n\n ctx2d.save();\n ctx2d.font = `${fontSize}px ${fontFamily}`;\n ctx2d.fillStyle = color;\n ctx2d.textAlign = \"center\";\n ctx2d.textBaseline = \"middle\";\n\n let x: number, y: number;\n\n if (position === \"center\") {\n x = plotArea.x + plotArea.width / 2;\n y = plotArea.y + plotArea.height / 2;\n } else if (position === \"bottom-right\") {\n x = plotArea.x + plotArea.width - fontSize;\n y = plotArea.y + plotArea.height - fontSize / 2;\n } else {\n x = plotArea.x + fontSize;\n y = plotArea.y + plotArea.height - fontSize / 2;\n }\n\n ctx2d.translate(x, y);\n ctx2d.rotate((rotation * Math.PI) / 180);\n ctx2d.fillText(text, 0, 0);\n ctx2d.restore();\n },\n };\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n AfterRenderEvent,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface GridHighlightConfig {\n /** Highlight intervals on X axis */\n xIntervals?: Array<{ start: number; end: number; color: string }>;\n /** Highlight intervals on Y axis */\n yIntervals?: Array<{ start: number; end: number; color: string }>;\n /** Opacity for highlight regions (default: 0.1) */\n opacity?: number;\n}\n\nconst gridHighlightManifest: PluginManifest = {\n name: \"grid-highlight\",\n version: \"1.0.0\",\n description: \"Highlights specific regions of the chart grid\",\n provides: [\"visualization\"],\n tags: [\"grid\", \"highlight\", \"regions\"],\n};\n\nexport const GridHighlightPlugin = definePlugin<GridHighlightConfig>(\n gridHighlightManifest,\n (config = {}) => {\n const { xIntervals = [], yIntervals = [], opacity = 0.1 } = config;\n\n return {\n onRenderOverlay(ctx: PluginContext, _event: AfterRenderEvent) {\n const ctx2d = ctx.render.ctx2d;\n if (!ctx2d) return;\n\n const plotArea = ctx.render.plotArea;\n // bounds available if needed for future features\n void ctx.data.getViewBounds();\n\n ctx2d.save();\n\n // Clip to plot area\n ctx2d.beginPath();\n ctx2d.rect(plotArea.x, plotArea.y, plotArea.width, plotArea.height);\n ctx2d.clip();\n\n ctx2d.globalAlpha = opacity;\n\n // Draw X intervals (vertical bands)\n for (const interval of xIntervals) {\n const x1 = ctx.coords.dataToPixelX(interval.start);\n const x2 = ctx.coords.dataToPixelX(interval.end);\n\n ctx2d.fillStyle = interval.color;\n ctx2d.fillRect(\n Math.min(x1, x2),\n plotArea.y,\n Math.abs(x2 - x1),\n plotArea.height\n );\n }\n\n // Draw Y intervals (horizontal bands)\n for (const interval of yIntervals) {\n const y1 = ctx.coords.dataToPixelY(interval.start);\n const y2 = ctx.coords.dataToPixelY(interval.end);\n\n ctx2d.fillStyle = interval.color;\n ctx2d.fillRect(\n plotArea.x,\n Math.min(y1, y2),\n plotArea.width,\n Math.abs(y2 - y1)\n );\n }\n\n ctx2d.restore();\n },\n };\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n DataUpdateEvent,\n ViewChangeEvent,\n InteractionEvent,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface DataLoggerConfig {\n /** Log data updates (default: true) */\n logDataUpdates?: boolean;\n /** Log view changes (default: true) */\n logViewChanges?: boolean;\n /** Log interactions (default: false) */\n logInteractions?: boolean;\n /** Maximum log entries to keep (default: 100) */\n maxEntries?: number;\n}\n\nconst dataLoggerManifest: PluginManifest = {\n name: \"data-logger\",\n version: \"1.0.0\",\n description: \"Logs chart events for debugging and analysis\",\n provides: [\"analysis\"],\n tags: [\"debug\", \"logging\", \"events\"],\n};\n\nexport const DataLoggerPlugin = definePlugin<DataLoggerConfig>(\n dataLoggerManifest,\n (config = {}) => {\n const {\n logDataUpdates = true,\n logViewChanges = true,\n logInteractions = false,\n maxEntries = 100,\n } = config;\n\n interface LogEntry {\n timestamp: number;\n type: string;\n data: unknown;\n }\n\n const entries: LogEntry[] = [];\n\n function addEntry(type: string, data: unknown) {\n entries.push({\n timestamp: Date.now(),\n type,\n data,\n });\n\n if (entries.length > maxEntries) {\n entries.shift();\n }\n }\n\n return {\n onInit(ctx: PluginContext) {\n ctx.log.info(\"Data logger initialized\");\n },\n\n onDataUpdate(ctx: PluginContext, event: DataUpdateEvent) {\n if (logDataUpdates) {\n addEntry(\"dataUpdate\", {\n seriesId: event.seriesId,\n mode: event.mode,\n pointCount: event.pointCount,\n });\n ctx.log.debug(`Data update: ${event.seriesId} (${event.mode}, ${event.pointCount} points)`);\n }\n },\n\n onViewChange(ctx: PluginContext, event: ViewChangeEvent) {\n if (logViewChanges) {\n addEntry(\"viewChange\", {\n trigger: event.trigger,\n bounds: event.current,\n });\n ctx.log.debug(`View change: ${event.trigger}`);\n }\n },\n\n onInteraction(_ctx: PluginContext, event: InteractionEvent) {\n if (logInteractions) {\n addEntry(\"interaction\", {\n type: event.type,\n pixelX: event.pixelX,\n pixelY: event.pixelY,\n inPlotArea: event.inPlotArea,\n });\n }\n },\n\n onSerialize(_ctx: PluginContext) {\n return { entries };\n },\n\n onDeserialize(_ctx: PluginContext, data: unknown) {\n const saved = data as { entries?: LogEntry[] };\n if (saved?.entries) {\n entries.length = 0;\n entries.push(...saved.entries);\n }\n },\n\n api: {\n getEntries() {\n return [...entries];\n },\n clear() {\n entries.length = 0;\n },\n export() {\n return JSON.stringify(entries, null, 2);\n },\n },\n };\n }\n);\n","import type {\n PluginContext,\n PluginManifest,\n} from \"../../types\";\nimport { definePlugin } from \"../../PluginRegistry\";\n\nexport interface DirectionIndicatorConfig {\n /** Series ID to track (if not specified, tracks the first series) */\n seriesId?: string;\n /** Number of recent points to analyze for direction (default: 20) */\n sampleSize?: number;\n /** Arrow color (default: from theme) */\n color?: string;\n /** Arrow size in pixels (default: 40) */\n size?: number;\n /** Minimum velocity to show arrow (default: 0.01) */\n minVelocity?: number;\n /** Number of points for smoothing the position/angle (default: 20) */\n historySize?: number;\n /** Hide arrow if no new points are received for this duration in ms (default: undefined/disabled) */\n idleTimeout?: number;\n}\n\ninterface DirectionData {\n angle: number; // Continuous angle in radians\n magnitude: number; // Normalized magnitude 0-1\n lastX: number; // Last data point X coordinate (data space)\n lastY: number; // Last data point Y coordinate (data space)\n smoothX: number; // Smoothed X position (pixel space)\n smoothY: number; // Smoothed Y position (pixel space)\n}\n\nconst directionIndicatorManifest: PluginManifest = {\n name: \"direction-indicator\",\n version: \"1.0.0\",\n description: \"Shows an arrow indicating the direction and trend of streaming data\",\n provides: [\"visualization\", \"analysis\"],\n tags: [\"streaming\", \"direction\", \"trend\", \"arrow\"],\n};\n\nexport const DirectionIndicatorPlugin = definePlugin<DirectionIndicatorConfig>(\n directionIndicatorManifest,\n (config = {}) => {\n const {\n seriesId,\n sampleSize = 20,\n color,\n size = 40,\n minVelocity = 0.01,\n historySize = 20,\n idleTimeout,\n } = config;\n\n let overlayId: string;\n let canvas: HTMLCanvasElement | null = null;\n let ctx: CanvasRenderingContext2D | null = null;\n let currentDirection: DirectionData | null = null;\n let targetSeriesId: string | null = null;\n \n // Smoothing buffers (moving average to reduce jitter)\n const positionHistoryX: number[] = [];\n const positionHistoryY: number[] = [];\n const angleHistory: number[] = [];\n\n let maxHistorySize = historySize;\n let timeoutTimer: any = null;\n let lastPointTimestamp = Date.now();\n let lastSeenX = -Infinity;\n let lastSeenY = -Infinity;\n let currentIdleTimeout = idleTimeout;\n\n return {\n onInit(pluginCtx: PluginContext) {\n overlayId = \"direction-indicator-overlay\";\n const overlay = pluginCtx.ui.createOverlay(overlayId, {\n zIndex: 600,\n position: { top: \"0\", left: \"0\", right: \"0\", bottom: \"0\" },\n pointerEvents: false,\n });\n\n canvas = document.createElement(\"canvas\");\n canvas.style.cssText = \"width: 100%; height: 100%; pointer-events: none;\";\n overlay.appendChild(canvas);\n\n ctx = canvas.getContext(\"2d\");\n resizeCanvas(pluginCtx);\n\n // Determine which series to track\n if (seriesId) {\n targetSeriesId = seriesId;\n } else {\n const allSeries = pluginCtx.data.getAllSeries();\n if (allSeries.length > 0) {\n targetSeriesId = allSeries[0].getId();\n }\n }\n },\n\n onDestroy(pluginCtx: PluginContext) {\n pluginCtx.ui.removeOverlay(overlayId);\n if (timeoutTimer) clearTimeout(timeoutTimer);\n canvas = null;\n ctx = null;\n currentDirection = null;\n },\n\n onResize(pluginCtx: PluginContext) {\n resizeCanvas(pluginCtx);\n },\n\n onAfterRender(pluginCtx: PluginContext) {\n // Update direction every frame for smooth rendering\n updateDirection(pluginCtx);\n render(pluginCtx);\n\n // Ensure we render again when the idle timeout expires to hide the arrow\n if (currentIdleTimeout) {\n if (timeoutTimer) clearTimeout(timeoutTimer);\n const age = Date.now() - lastPointTimestamp;\n if (age < currentIdleTimeout) {\n timeoutTimer = setTimeout(() => {\n pluginCtx.requestRender();\n }, currentIdleTimeout - age + 10);\n }\n }\n },\n\n onConfigChange(_pluginCtx: PluginContext, newConfig: DirectionIndicatorConfig) {\n if (newConfig.historySize !== undefined) {\n maxHistorySize = newConfig.historySize;\n // Reset history buffers if size changes significantly or just trim/expand? \n // Simpler to just let them adjust over time or trim if needed.\n // If we want immediate effect, we might want to trim if smaller.\n while (positionHistoryX.length > maxHistorySize) positionHistoryX.shift();\n while (positionHistoryY.length > maxHistorySize) positionHistoryY.shift();\n while (angleHistory.length > maxHistorySize) angleHistory.shift();\n }\n\n if (newConfig.idleTimeout !== undefined) {\n currentIdleTimeout = newConfig.idleTimeout;\n }\n }\n };\n\n function resizeCanvas(pluginCtx: PluginContext) {\n if (!canvas || !ctx) return;\n const canvasSize = pluginCtx.render.canvasSize;\n const dpr = pluginCtx.render.pixelRatio;\n canvas.width = canvasSize.width * dpr;\n canvas.height = canvasSize.height * dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.scale(dpr, dpr);\n }\n\n function updateDirection(pluginCtx: PluginContext) {\n if (!targetSeriesId) return;\n\n const series = pluginCtx.data.getSeries(targetSeriesId);\n if (!series) return;\n\n const data = pluginCtx.data.getSeriesData(targetSeriesId);\n if (!data || !data.x || !data.y) return;\n\n const totalPoints = data.x.length;\n if (totalPoints < 2) return;\n\n // Get last point coordinates in data space\n const lastX = data.x[totalPoints - 1];\n const lastY = data.y[totalPoints - 1];\n\n // Detect if this is a new point\n if (lastX !== lastSeenX || lastY !== lastSeenY) {\n lastSeenX = lastX;\n lastSeenY = lastY;\n lastPointTimestamp = Date.now();\n }\n\n // Get last N points for direction calculation\n const n = Math.min(sampleSize, totalPoints);\n const startIdx = totalPoints - n;\n\n // Calculate direction using linear regression on recent points IN PIXEL SPACE\n let sumT = 0, sumPX = 0, sumPY = 0, sumTPX = 0, sumTPY = 0, sumTT = 0;\n\n for (let i = startIdx; i < totalPoints; i++) {\n const t = i - startIdx; // Time index\n const dataX = data.x[i];\n const dataY = data.y[i];\n \n // Convert to pixel coordinates\n const pixelX = pluginCtx.coords.dataToPixelX(dataX);\n const pixelY = pluginCtx.coords.dataToPixelY(dataY);\n\n sumT += t;\n sumPX += pixelX;\n sumPY += pixelY;\n sumTPX += t * pixelX;\n sumTPY += t * pixelY;\n sumTT += t * t;\n }\n\n const meanT = sumT / n;\n const meanPX = sumPX / n;\n const meanPY = sumPY / n;\n\n // Calculate slopes in pixel space (dpx/dt and dpy/dt)\n const denominator = sumTT - n * meanT * meanT;\n if (Math.abs(denominator) < 1e-10) return; // Avoid division by zero\n \n const slopePX = (sumTPX - n * meanT * meanPX) / denominator;\n const slopePY = (sumTPY - n * meanT * meanPY) / denominator;\n\n // Calculate continuous angle in pixel space (canvas coordinates)\n const rawAngle = Math.atan2(slopePY, slopePX);\n \n // Convert last point to pixel coordinates\n const lastPixelX = pluginCtx.coords.dataToPixelX(lastX);\n const lastPixelY = pluginCtx.coords.dataToPixelY(lastY);\n \n // Add to position history for smoothing\n positionHistoryX.push(lastPixelX);\n positionHistoryY.push(lastPixelY);\n if (positionHistoryX.length > maxHistorySize) {\n positionHistoryX.shift();\n positionHistoryY.shift();\n }\n \n // Add to angle history for smoothing\n angleHistory.push(rawAngle);\n if (angleHistory.length > maxHistorySize) {\n angleHistory.shift();\n }\n \n // Apply moving average to smooth position and angle\n const smoothX = average(positionHistoryX);\n const smoothY = average(positionHistoryY);\n const smoothedAngle = smoothAngle(angleHistory);\n \n // Calculate magnitude in pixel space\n const magnitude = Math.sqrt(slopePX * slopePX + slopePY * slopePY);\n\n currentDirection = { angle: smoothedAngle, magnitude, lastX, lastY, smoothX, smoothY };\n }\n \n function average(values: number[]): number {\n if (values.length === 0) return 0;\n return values.reduce((sum, val) => sum + val, 0) / values.length;\n }\n \n function smoothAngle(angles: number[]): number {\n if (angles.length === 0) return 0;\n \n // Convert angles to unit vectors to handle wraparound correctly\n let sumX = 0;\n let sumY = 0;\n \n for (const angle of angles) {\n sumX += Math.cos(angle);\n sumY += Math.sin(angle);\n }\n \n // Average the vectors and convert back to angle\n return Math.atan2(sumY / angles.length, sumX / angles.length);\n }\n\n function render(pluginCtx: PluginContext) {\n if (!ctx || !canvas || !currentDirection) return;\n\n const { width, height } = pluginCtx.render.canvasSize;\n ctx.clearRect(0, 0, width, height);\n\n // Check for idle timeout\n if (currentIdleTimeout !== undefined) {\n const age = Date.now() - lastPointTimestamp;\n if (age > currentIdleTimeout) return;\n }\n\n if (currentDirection.magnitude < minVelocity) return;\n\n // Use smoothed position for fluid movement\n const smoothX = currentDirection.smoothX;\n const smoothY = currentDirection.smoothY;\n\n const arrowColor = color || \"#FF9800\";\n \n ctx.save();\n\n // Draw arrow at smoothed position with smoothed angle\n drawArrow(ctx, smoothX, smoothY, currentDirection.angle, size, arrowColor);\n\n ctx.restore();\n }\n\n function drawArrow(\n ctx: CanvasRenderingContext2D,\n x: number,\n y: number,\n angle: number,\n length: number,\n color: string\n ) {\n // Triangle dimensions (only the arrow head)\n const triangleHeight = length * 0.6;\n const triangleWidth = length * 0.4;\n\n ctx.save();\n ctx.translate(x, y);\n ctx.rotate(angle);\n\n // Draw filled triangle pointing in the direction of movement\n ctx.fillStyle = color;\n ctx.beginPath();\n ctx.moveTo(triangleHeight / 2, 0); // Tip of the triangle\n ctx.lineTo(-triangleHeight / 2, -triangleWidth / 2); // Bottom left\n ctx.lineTo(-triangleHeight / 2, triangleWidth / 2); // Bottom right\n ctx.closePath();\n ctx.fill();\n\n ctx.restore();\n }\n }\n);\n","/**\n * Velo Plot - Built-in Plugins\n * \n * Collection of official plugins that demonstrate the plugin system\n * capabilities and provide common functionality.\n * \n * @module plugins/builtins\n */\n\nexport * from \"./crosshair\";\nexport * from \"./stats\";\nexport * from \"./watermark\";\nexport * from \"./grid-highlight\";\nexport * from \"./data-logger\";\nexport * from \"./direction-indicator\";\n\nimport { CrosshairPlugin } from \"./crosshair\";\nimport { StatsPlugin } from \"./stats\";\nimport { WatermarkPlugin } from \"./watermark\";\nimport { GridHighlightPlugin } from \"./grid-highlight\";\nimport { DataLoggerPlugin } from \"./data-logger\";\nimport { DirectionIndicatorPlugin } from \"./direction-indicator\";\n\n/**\n * Plugin collection for easy registration\n */\nexport const BuiltinPlugins = {\n Crosshair: CrosshairPlugin,\n Statistics: StatsPlugin,\n Watermark: WatermarkPlugin,\n GridHighlight: GridHighlightPlugin,\n DataLogger: DataLoggerPlugin,\n DirectionIndicator: DirectionIndicatorPlugin,\n};\n","/**\n * @fileoverview Drag & Drop editing plugin for interactive point manipulation\n * @module plugins/drag-edit\n */\n\nimport type {\n PluginDragEditConfig,\n DragEditAPI,\n DraggedPoint,\n DragEditEvent,\n DragConstraint,\n} from './types';\nimport type {\n ChartPlugin,\n PluginContext,\n PluginManifest,\n} from '../types';\n\nconst manifest: PluginManifest = {\n name: 'velo-plot-drag-edit',\n version: '1.0.0',\n description: 'Interactive drag & drop editing of data points',\n provides: ['drag-edit', 'point-editing'],\n tags: ['interaction', 'editing', 'ux'],\n};\n\nconst DEFAULT_CONFIG: Required<PluginDragEditConfig> = {\n enabled: true,\n constraint: 'both',\n snapToGrid: false,\n snapIntervalX: 1,\n snapIntervalY: 1,\n dragThreshold: 5,\n hitRadius: 10,\n editableSeries: [],\n validator: () => ({ valid: true }),\n onDragStart: () => {},\n onDrag: () => {},\n onDragEnd: () => {},\n highlightColor: '#ffff00',\n showPreview: true,\n previewStyle: {\n color: '#ffffff',\n width: 2,\n dash: [5, 5],\n opacity: 0.5,\n },\n};\n\nexport function PluginDragEdit(\n userConfig: Partial<PluginDragEditConfig> = {}\n): ChartPlugin<PluginDragEditConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n \n // Drag state\n let isDragging = false;\n let draggedPoint: DraggedPoint | null = null;\n let dragStartX = 0;\n let dragStartY = 0;\n let hasMoved = false;\n\n /**\n * Find nearest point to mouse position\n */\n function findNearestPoint(mouseX: number, mouseY: number): DraggedPoint | null {\n if (!ctx) return null;\n\n // Use built-in pick functionality\n const picked = ctx.coords.pickPoint(mouseX, mouseY, config.hitRadius);\n \n if (!picked) return null;\n\n // Check if series is editable\n if (config.editableSeries.length > 0 && !config.editableSeries.includes(picked.seriesId)) {\n return null;\n }\n\n return {\n seriesId: picked.seriesId,\n index: picked.index,\n originalX: picked.x,\n originalY: picked.y,\n currentX: picked.x,\n currentY: picked.y,\n };\n }\n\n /**\n * Convert pixel coordinates to data coordinates\n */\n function pixelToData(pixelX: number, pixelY: number): { x: number; y: number } {\n if (!ctx) return { x: 0, y: 0 };\n\n return {\n x: ctx.coords.pixelToDataX(pixelX),\n y: ctx.coords.pixelToDataY(pixelY),\n };\n }\n\n /**\n * Snap value to grid\n */\n function snapToGrid(value: number, interval: number): number {\n return Math.round(value / interval) * interval;\n }\n\n /**\n * Apply drag constraints\n */\n function applyConstraints(\n newX: number,\n newY: number,\n constraint: DragConstraint\n ): { x: number; y: number } {\n if (!draggedPoint) return { x: newX, y: newY };\n\n switch (constraint) {\n case 'x':\n return { x: newX, y: draggedPoint.originalY };\n case 'y':\n return { x: draggedPoint.originalX, y: newY };\n case 'none':\n return { x: draggedPoint.originalX, y: draggedPoint.originalY };\n default:\n return { x: newX, y: newY };\n }\n }\n\n /**\n * Validate and apply snapping\n */\n function validateAndSnap(x: number, y: number): { x: number; y: number; valid: boolean } {\n let finalX = x;\n let finalY = y;\n\n // Apply snapping\n if (config.snapToGrid) {\n finalX = snapToGrid(x, config.snapIntervalX);\n finalY = snapToGrid(y, config.snapIntervalY);\n }\n\n // Run custom validation\n if (draggedPoint && config.validator) {\n const tempPoint: DraggedPoint = { ...draggedPoint, currentX: finalX, currentY: finalY };\n const validation = config.validator(tempPoint);\n\n if (typeof validation === 'boolean') {\n return { x: finalX, y: finalY, valid: validation };\n }\n\n if (!validation.valid) {\n return { x: finalX, y: finalY, valid: false };\n }\n\n // Apply snap suggestions from validator\n if (validation.snapX !== undefined) finalX = validation.snapX;\n if (validation.snapY !== undefined) finalY = validation.snapY;\n }\n\n return { x: finalX, y: finalY, valid: true };\n }\n\n /**\n * Update point data\n */\n function updatePointData(seriesId: string, index: number, newX: number, newY: number): void {\n if (!ctx) return;\n\n const series = (ctx.chart as any).getSeries?.(seriesId);\n if (!series) return;\n\n const data = series.getData();\n if (!data || !data.x || !data.y) return;\n\n // Update the data arrays\n data.x[index] = newX;\n data.y[index] = newY;\n\n // Invalidate buffers to trigger GPU upload\n series.invalidateBuffers?.();\n\n // Trigger chart re-render\n ctx.requestRender();\n }\n\n /**\n * Create drag event\n */\n function createDragEvent(): DragEditEvent | null {\n if (!draggedPoint) return null;\n\n return {\n seriesId: draggedPoint.seriesId,\n index: draggedPoint.index,\n oldX: draggedPoint.originalX,\n oldY: draggedPoint.originalY,\n newX: draggedPoint.currentX,\n newY: draggedPoint.currentY,\n deltaX: draggedPoint.currentX - draggedPoint.originalX,\n deltaY: draggedPoint.currentY - draggedPoint.originalY,\n };\n }\n\n /**\n * Draw preview overlay\n */\n function drawPreview(pCtx: PluginContext): void {\n if (!isDragging || !draggedPoint || !config.showPreview) return;\n\n const { render, coords } = pCtx;\n const { ctx2d } = render;\n if (!ctx2d) return;\n\n ctx2d.save();\n\n // Convert data coordinates to pixel coordinates\n const origPixelX = coords.dataToPixelX(draggedPoint.originalX);\n const origPixelY = coords.dataToPixelY(draggedPoint.originalY);\n \n const currPixelX = coords.dataToPixelX(draggedPoint.currentX);\n const currPixelY = coords.dataToPixelY(draggedPoint.currentY);\n\n // Draw preview line from original to current position\n ctx2d.strokeStyle = config.previewStyle.color || '#ffffff';\n ctx2d.lineWidth = config.previewStyle.width || 2;\n ctx2d.globalAlpha = config.previewStyle.opacity || 0.5;\n ctx2d.setLineDash(config.previewStyle.dash || [5, 5]);\n\n ctx2d.beginPath();\n ctx2d.moveTo(origPixelX, origPixelY);\n ctx2d.lineTo(currPixelX, currPixelY);\n ctx2d.stroke();\n\n // Draw highlight circle at current position\n ctx2d.globalAlpha = 1;\n ctx2d.fillStyle = config.highlightColor;\n ctx2d.setLineDash([]);\n ctx2d.beginPath();\n ctx2d.arc(currPixelX, currPixelY, 6, 0, Math.PI * 2);\n ctx2d.fill();\n\n // Draw outline\n ctx2d.strokeStyle = '#000000';\n ctx2d.lineWidth = 1;\n ctx2d.stroke();\n\n ctx2d.restore();\n }\n\n // API implementation\n const api: DragEditAPI & Record<string, unknown> = {\n enable() {\n config.enabled = true;\n },\n disable() {\n config.enabled = false;\n if (isDragging) {\n draggedPoint = null;\n isDragging = false;\n hasMoved = false;\n ctx?.requestRender();\n }\n },\n isEnabled() {\n return config.enabled;\n },\n setEditableSeries(seriesIds: string[]) {\n config.editableSeries = seriesIds;\n },\n getDraggedPoint() {\n return draggedPoint;\n },\n cancelDrag() {\n if (isDragging && draggedPoint) {\n draggedPoint = null;\n isDragging = false;\n hasMoved = false;\n ctx?.requestRender();\n }\n },\n updateConfig(newConfig: Partial<PluginDragEditConfig>) {\n Object.assign(config, newConfig);\n },\n };\n\n return {\n manifest,\n\n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n\n // Attach to chart API\n (ctx.chart as any).dragEdit = api;\n },\n\n onDestroy(_pluginCtx: PluginContext) {\n // Remove from chart API\n delete (_pluginCtx.chart as any).dragEdit;\n\n ctx = null;\n },\n\n onInteraction(_pluginCtx: PluginContext, event: import('../types').InteractionEvent) {\n if (!config.enabled) return;\n\n if (event.type === 'mousedown') {\n const point = findNearestPoint(event.pixelX, event.pixelY);\n if (point) {\n draggedPoint = point;\n dragStartX = event.pixelX;\n dragStartY = event.pixelY;\n hasMoved = false;\n isDragging = false;\n // Prevent default to stop panning when clicking on a point\n event.preventDefault();\n }\n } else if (event.type === 'mousemove') {\n if (!draggedPoint) return;\n\n // Check if we've moved beyond threshold\n if (!isDragging) {\n const dx = event.pixelX - dragStartX;\n const dy = event.pixelY - dragStartY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance > config.dragThreshold) {\n isDragging = true;\n hasMoved = true;\n\n // Fire drag start event\n const dragEvent = createDragEvent();\n if (dragEvent) config.onDragStart(dragEvent);\n } else {\n return;\n }\n }\n\n // Prevent default during dragging\n if (isDragging) {\n event.preventDefault();\n }\n\n // Convert to data coordinates\n let { x, y } = pixelToData(event.pixelX, event.pixelY);\n\n // Apply constraints\n ({ x, y } = applyConstraints(x, y, config.constraint));\n\n // Validate and snap\n const { x: finalX, y: finalY, valid } = validateAndSnap(x, y);\n\n if (valid) {\n draggedPoint.currentX = finalX;\n draggedPoint.currentY = finalY;\n\n // Fire drag event (for callbacks)\n const dragEvent = createDragEvent();\n if (dragEvent) config.onDrag(dragEvent);\n\n // Request render to show preview line\n ctx?.requestRender();\n }\n } else if (event.type === 'mouseup') {\n if (!draggedPoint) return;\n\n if (isDragging && hasMoved) {\n // Apply the changes\n updatePointData(\n draggedPoint.seriesId,\n draggedPoint.index,\n draggedPoint.currentX,\n draggedPoint.currentY\n );\n\n // Fire drag end event\n const dragEvent = createDragEvent();\n if (dragEvent) config.onDragEnd(dragEvent);\n\n // Prevent default on mouseup to avoid triggering click events\n event.preventDefault();\n }\n\n // Reset state\n draggedPoint = null;\n isDragging = false;\n hasMoved = false;\n ctx?.requestRender();\n }\n },\n\n onRenderOverlay(pluginCtx: PluginContext) {\n drawPreview(pluginCtx);\n },\n\n api,\n };\n}\n\nexport default PluginDragEdit;\n\n// Type exports\nexport type {\n PluginDragEditConfig,\n DragEditAPI,\n DraggedPoint,\n DragEditEvent,\n DragConstraint,\n} from './types';\n","/**\n * WebGL grid spike — batched GL_LINES renderer for axis grid lines.\n * Labels remain on Canvas 2D; this spike covers grid lines only.\n * @module renderer/spike/WebGLGridSpike\n */\n\nexport interface GridLineSpec {\n /** Plot area in CSS pixels */\n plotArea: { x: number; y: number; width: number; height: number };\n /** Pixel X positions for vertical grid lines */\n xLines: number[];\n /** Pixel Y positions for horizontal grid lines */\n yLines: number[];\n /** Canvas width (physical pixels) */\n width: number;\n /** Canvas height (physical pixels) */\n height: number;\n /** Line color RGBA 0–1 */\n color?: [number, number, number, number];\n /** Line width in pixels */\n lineWidth?: number;\n}\n\nconst VERT_SRC = `\n attribute vec2 aPosition;\n uniform vec2 uResolution;\n void main() {\n vec2 clip = (aPosition / uResolution) * 2.0 - 1.0;\n gl_Position = vec4(clip.x, -clip.y, 0.0, 1.0);\n }\n`;\n\nconst FRAG_SRC = `\n precision mediump float;\n uniform vec4 uColor;\n void main() {\n gl_FragColor = uColor;\n }\n`;\n\nfunction compileShader(gl: WebGLRenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) throw new Error(\"createShader failed\");\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n throw new Error(gl.getShaderInfoLog(shader) ?? \"shader compile failed\");\n }\n return shader;\n}\n\nfunction createProgram(gl: WebGLRenderingContext): WebGLProgram {\n const vs = compileShader(gl, gl.VERTEX_SHADER, VERT_SRC);\n const fs = compileShader(gl, gl.FRAGMENT_SHADER, FRAG_SRC);\n const program = gl.createProgram();\n if (!program) throw new Error(\"createProgram failed\");\n gl.attachShader(program, vs);\n gl.attachShader(program, fs);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(gl.getProgramInfoLog(program) ?? \"program link failed\");\n }\n gl.deleteShader(vs);\n gl.deleteShader(fs);\n return program;\n}\n\n/** Build interleaved [x,y] vertex pairs for GL_LINES from tick pixel positions */\nexport function buildGridLineVertices(spec: GridLineSpec): Float32Array {\n const { plotArea, xLines, yLines } = spec;\n const y0 = plotArea.y;\n const y1 = plotArea.y + plotArea.height;\n const x0 = plotArea.x;\n const x1 = plotArea.x + plotArea.width;\n\n const vertCount = (xLines.length + yLines.length) * 2;\n const out = new Float32Array(vertCount * 2);\n let o = 0;\n\n for (const x of xLines) {\n out[o++] = x;\n out[o++] = y0;\n out[o++] = x;\n out[o++] = y1;\n }\n\n for (const y of yLines) {\n out[o++] = x0;\n out[o++] = y;\n out[o++] = x1;\n out[o++] = y;\n }\n\n return out;\n}\n\nexport class WebGLGridSpike {\n private gl: WebGLRenderingContext;\n private program: WebGLProgram;\n private buffer: WebGLBuffer;\n private aPosition: number;\n private uResolution: WebGLUniformLocation;\n private uColor: WebGLUniformLocation;\n\n constructor(canvas: HTMLCanvasElement) {\n const gl = canvas.getContext(\"webgl\", {\n alpha: true,\n antialias: false,\n preserveDrawingBuffer: true,\n });\n if (!gl) throw new Error(\"WebGL not available for grid spike\");\n\n this.gl = gl;\n this.program = createProgram(gl);\n this.aPosition = gl.getAttribLocation(this.program, \"aPosition\");\n this.uResolution = gl.getUniformLocation(this.program, \"uResolution\")!;\n this.uColor = gl.getUniformLocation(this.program, \"uColor\")!;\n\n const buf = gl.createBuffer();\n if (!buf) throw new Error(\"createBuffer failed\");\n this.buffer = buf;\n }\n\n /** Upload vertices and draw grid lines */\n draw(spec: GridLineSpec): number {\n const gl = this.gl;\n const vertices = buildGridLineVertices(spec);\n const lineSegments = vertices.length / 4;\n\n gl.viewport(0, 0, spec.width, spec.height);\n gl.clearColor(0.04, 0.05, 0.08, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n gl.useProgram(this.program);\n gl.bindBuffer(gl.ARRAY_BUFFER, this.buffer);\n gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.DYNAMIC_DRAW);\n gl.enableVertexAttribArray(this.aPosition);\n gl.vertexAttribPointer(this.aPosition, 2, gl.FLOAT, false, 0, 0);\n\n gl.uniform2f(this.uResolution, spec.width, spec.height);\n const c = spec.color ?? [0.2, 0.22, 0.3, 0.6];\n gl.uniform4f(this.uColor, c[0], c[1], c[2], c[3]);\n gl.lineWidth(spec.lineWidth ?? 1);\n\n gl.drawArrays(gl.LINES, 0, vertices.length / 2);\n return lineSegments;\n }\n\n destroy(): void {\n const gl = this.gl;\n gl.deleteBuffer(this.buffer);\n gl.deleteProgram(this.program);\n }\n}\n","/**\n * Grid rendering benchmark — Canvas 2D vs WebGL spike comparison.\n * @module testing/gridSpikeBenchmark\n */\n\nimport { OverlayRenderer } from \"../core/OverlayRenderer\";\nimport { LinearScale } from \"../scales\";\nimport { DARK_THEME } from \"../theme\";\nimport { WebGLGridSpike, buildGridLineVertices, type GridLineSpec } from \"../renderer/spike/WebGLGridSpike\";\nimport { snapLineCoord } from \"../core/render/pixelSnap\";\nimport type { PlotArea } from \"../types\";\n\nexport interface GridBenchmarkResult {\n backend: \"canvas2d\" | \"webgl\";\n dpr: number;\n width: number;\n height: number;\n xTicks: number;\n yTicks: number;\n lineSegments: number;\n avgFrameUs: number;\n p95FrameUs: number;\n frames: number;\n}\n\nexport interface GridCompareResult {\n canvas2d: GridBenchmarkResult;\n webgl: GridBenchmarkResult | null;\n /** Positive = WebGL faster */\n gainPercent: number;\n recommendation: \"implement\" | \"defer\";\n}\n\nfunction createMinimalMock2D(canvas: HTMLCanvasElement): CanvasRenderingContext2D {\n const noop = () => {};\n return {\n canvas,\n strokeStyle: \"\",\n fillStyle: \"\",\n lineWidth: 1,\n font: \"\",\n textAlign: \"left\",\n textBaseline: \"alphabetic\",\n beginPath: noop,\n moveTo: noop,\n lineTo: noop,\n stroke: noop,\n fill: noop,\n clearRect: noop,\n setTransform: noop,\n setLineDash: noop,\n save: noop,\n restore: noop,\n translate: noop,\n rotate: noop,\n fillText: noop,\n measureText: (text: string) => ({ width: text.length * 7 } as TextMetrics),\n } as unknown as CanvasRenderingContext2D;\n}\n\nfunction getCanvas2DContext(width: number, height: number): CanvasRenderingContext2D {\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n return canvas.getContext(\"2d\") ?? createMinimalMock2D(canvas);\n}\n\nfunction makePlotArea(width: number, height: number): PlotArea {\n const margin = { top: 40, right: 40, bottom: 50, left: 60 };\n return {\n x: margin.left,\n y: margin.top,\n width: width - margin.left - margin.right,\n height: height - margin.top - margin.bottom,\n };\n}\n\nfunction tickPixelLines(\n _plotArea: PlotArea,\n xScale: LinearScale,\n yScale: LinearScale,\n xTickCount: number,\n yTickCount: number,\n): { xLines: number[]; yLines: number[] } {\n const xLines = xScale.ticks(xTickCount).map((t) => snapLineCoord(xScale.transform(t)));\n const yLines = yScale.ticks(yTickCount).map((t) => snapLineCoord(yScale.transform(t)));\n return { xLines, yLines };\n}\n\nfunction measureFrames(runFrame: () => void, frames: number): { avg: number; p95: number } {\n const samples: number[] = [];\n for (let i = 0; i < frames; i++) {\n const t0 = performance.now();\n runFrame();\n samples.push((performance.now() - t0) * 1000);\n }\n samples.sort((a, b) => a - b);\n const avg = samples.reduce((s, v) => s + v, 0) / samples.length;\n const p95 = samples[Math.floor(samples.length * 0.95)] ?? avg;\n return { avg, p95 };\n}\n\n/** Benchmark Canvas 2D grid via OverlayRenderer.drawGrid */\nexport function benchmarkCanvasGrid(options: {\n width?: number;\n height?: number;\n dpr?: number;\n xTickCount?: number;\n yTickCount?: number;\n frames?: number;\n showMinor?: boolean;\n} = {}): GridBenchmarkResult {\n const width = Math.round((options.width ?? 1920) * (options.dpr ?? 1));\n const height = Math.round((options.height ?? 1080) * (options.dpr ?? 1));\n const xTickCount = options.xTickCount ?? 24;\n const yTickCount = options.yTickCount ?? 16;\n const frames = options.frames ?? 120;\n\n const ctx = getCanvas2DContext(width, height);\n\n const theme = {\n ...DARK_THEME,\n grid: {\n ...DARK_THEME.grid,\n visible: true,\n showMinor: options.showMinor ?? true,\n },\n };\n\n const plotArea = makePlotArea(width, height);\n const xScale = new LinearScale();\n const yScale = new LinearScale();\n xScale.setDomain(0, 1_000_000);\n yScale.setDomain(-1, 1);\n xScale.setRange(plotArea.x, plotArea.x + plotArea.width);\n yScale.setRange(plotArea.y + plotArea.height, plotArea.y);\n\n const renderer = new OverlayRenderer(ctx, theme);\n\n const { avg, p95 } = measureFrames(() => {\n ctx.clearRect(0, 0, width, height);\n renderer.drawGrid(plotArea, xScale, yScale, { tickCount: xTickCount }, { tickCount: yTickCount });\n }, frames);\n\n const { xLines, yLines } = tickPixelLines(plotArea, xScale, yScale, xTickCount, yTickCount);\n\n return {\n backend: \"canvas2d\",\n dpr: options.dpr ?? 1,\n width,\n height,\n xTicks: xTickCount,\n yTicks: yTickCount,\n lineSegments: xLines.length + yLines.length,\n avgFrameUs: Math.round(avg),\n p95FrameUs: Math.round(p95),\n frames,\n };\n}\n\n/** Benchmark WebGL grid spike (returns null if WebGL unavailable) */\nexport function benchmarkWebGLGrid(options: {\n width?: number;\n height?: number;\n dpr?: number;\n xTickCount?: number;\n yTickCount?: number;\n frames?: number;\n} = {}): GridBenchmarkResult | null {\n const width = Math.round((options.width ?? 1920) * (options.dpr ?? 1));\n const height = Math.round((options.height ?? 1080) * (options.dpr ?? 1));\n const xTickCount = options.xTickCount ?? 24;\n const yTickCount = options.yTickCount ?? 16;\n const frames = options.frames ?? 120;\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = width;\n canvas.height = height;\n\n let spike: WebGLGridSpike;\n try {\n spike = new WebGLGridSpike(canvas);\n } catch {\n return null;\n }\n\n const plotArea = makePlotArea(width, height);\n const xScale = new LinearScale();\n const yScale = new LinearScale();\n xScale.setDomain(0, 1_000_000);\n yScale.setDomain(-1, 1);\n xScale.setRange(plotArea.x, plotArea.x + plotArea.width);\n yScale.setRange(plotArea.y + plotArea.height, plotArea.y);\n\n const { xLines, yLines } = tickPixelLines(plotArea, xScale, yScale, xTickCount, yTickCount);\n const spec: GridLineSpec = { plotArea, xLines, yLines, width, height };\n\n let lineSegments = 0;\n const { avg, p95 } = measureFrames(() => {\n lineSegments = spike.draw(spec);\n }, frames);\n\n spike.destroy();\n\n return {\n backend: \"webgl\",\n dpr: options.dpr ?? 1,\n width,\n height,\n xTicks: xTickCount,\n yTicks: yTickCount,\n lineSegments,\n avgFrameUs: Math.round(avg),\n p95FrameUs: Math.round(p95),\n frames,\n };\n}\n\n/** Compare backends; recommends implement if WebGL ≥20% faster */\nexport function compareGridBackends(options?: {\n dpr?: number;\n frames?: number;\n}): GridCompareResult {\n const dpr = options?.dpr ?? 2;\n const frames = options?.frames ?? 120;\n\n const canvas2d = benchmarkCanvasGrid({ dpr, frames, showMinor: true });\n const webgl = benchmarkWebGLGrid({ dpr, frames });\n\n if (!webgl) {\n return {\n canvas2d,\n webgl: null,\n gainPercent: 0,\n recommendation: \"defer\",\n };\n }\n\n const gainPercent = ((canvas2d.avgFrameUs - webgl.avgFrameUs) / canvas2d.avgFrameUs) * 100;\n\n return {\n canvas2d,\n webgl,\n gainPercent: Math.round(gainPercent * 10) / 10,\n recommendation: gainPercent >= 20 ? \"implement\" : \"defer\",\n };\n}\n\n/** Vertex builder smoke test (no GL required) */\nexport function countGridVertices(xTickCount: number, yTickCount: number): number {\n const spec: GridLineSpec = {\n plotArea: { x: 60, y: 40, width: 800, height: 400 },\n xLines: Array.from({ length: xTickCount }, (_, i) => 60 + i * 30),\n yLines: Array.from({ length: yTickCount }, (_, i) => 40 + i * 25),\n width: 960,\n height: 540,\n };\n return buildGridLineVertices(spec).length / 2;\n}\n","/**\n * Stage 1 browser benchmark harness — scenarios + baseline comparison.\n * @module testing/stage1BrowserBench\n */\n\nimport type { BenchmarkResult } from \"./index\";\nimport baseline from \"./baselines/v1.15.0.json\";\n\nexport interface Stage1ScenarioResult {\n id: string;\n benchmark: BenchmarkResult;\n passed: boolean;\n failures: string[];\n baselineMinFps?: number;\n}\n\nexport interface Stage1BrowserReport {\n timestamp: number;\n version: string;\n scenarios: Stage1ScenarioResult[];\n allPassed: boolean;\n regressionThreshold: number;\n}\n\nexport interface BaselineScenario {\n minAvgFps?: number;\n maxAvgFrameTimeMs?: number;\n maxAvgFrameUs?: number;\n dpr?: number;\n points?: number;\n description?: string;\n}\n\n/** When wall-clock frame count is below this, headless rAF is unreliable — use renderFps. */\nexport const HEADLESS_LOW_FRAME_THRESHOLD = 30;\n\n/** Headless smoke floors (renderFps or effective FPS). Desktop uses baseline minAvgFps. */\nexport const SMOKE_FLOORS: Record<string, number> = {\n \"line-1m-pan\": 5,\n \"candlestick-500k\": 25,\n \"stack-5pane-resize\": 20,\n \"line-200k-webgl\": 3,\n \"line-200k-webgpu\": 2,\n \"boxplot-5k-webgpu\": 2,\n};\n\n/** Pick wall or render FPS depending on headless throttling artifacts. */\nexport function effectiveBenchmarkFps(\n result: Pick<BenchmarkResult, \"avgFps\" | \"renderFps\" | \"frameCount\">,\n isHeadless: boolean,\n): number {\n const wall = result.avgFps ?? 0;\n const render = result.renderFps ?? 0;\n const frames = result.frameCount ?? 0;\n\n if (!isHeadless) return wall;\n\n if (render > 0 && (frames < HEADLESS_LOW_FRAME_THRESHOLD || wall < 10)) {\n return render;\n }\n return wall;\n}\n\nexport function getBaseline(): typeof baseline {\n return baseline;\n}\n\n/** Compare a benchmark result against v1.15 baseline for a scenario */\nexport function compareScenarioToBaseline(\n scenarioId: string,\n result: BenchmarkResult | { avgFrameUs: number; backend?: string },\n): { passed: boolean; failures: string[] } {\n const spec = (baseline.scenarios as Record<string, BaselineScenario>)[scenarioId];\n if (!spec) {\n return { passed: true, failures: [] };\n }\n\n const failures: string[] = [];\n const threshold = baseline.regressionThreshold ?? 0.1;\n\n if (\"avgFps\" in result && spec.minAvgFps !== undefined) {\n const minAllowed = spec.minAvgFps * (1 - threshold);\n if (result.avgFps < minAllowed) {\n failures.push(\n `FPS ${result.avgFps} < baseline min ${spec.minAvgFps} (allowed ${minAllowed.toFixed(1)} with ${threshold * 100}% slack)`,\n );\n }\n }\n\n if (\"avgFrameTime\" in result && spec.maxAvgFrameTimeMs !== undefined) {\n const maxAllowed = spec.maxAvgFrameTimeMs * (1 + threshold);\n if (result.avgFrameTime > maxAllowed) {\n failures.push(\n `Frame time ${result.avgFrameTime}ms > baseline max ${spec.maxAvgFrameTimeMs}ms`,\n );\n }\n }\n\n if (\"avgFrameUs\" in result && spec.maxAvgFrameUs !== undefined) {\n const maxAllowed = spec.maxAvgFrameUs * (1 + threshold);\n if (result.avgFrameUs > maxAllowed) {\n failures.push(\n `Grid frame ${result.avgFrameUs}µs > baseline max ${spec.maxAvgFrameUs}µs`,\n );\n }\n }\n\n return { passed: failures.length === 0, failures };\n}\n\n/** Build a full Stage 1 report from scenario results */\nexport function buildStage1Report(\n scenarios: Stage1ScenarioResult[],\n): Stage1BrowserReport {\n return {\n timestamp: Date.now(),\n version: baseline.version,\n scenarios,\n allPassed: scenarios.every((s) => s.passed),\n regressionThreshold: baseline.regressionThreshold,\n };\n}\n","/**\n * WebGL vs WebGPU chart renderer comparison helpers.\n * @module testing/rendererBenchmark\n */\n\nimport type { BenchmarkResult } from \"./index\";\n\nexport interface RendererCompareResult {\n webgl: BenchmarkResult;\n webgpu: BenchmarkResult | null;\n webgpuActive: boolean;\n /** webgpuFps / webglFps — ≥1 means WebGPU is faster or equal */\n fpsRatio: number;\n /** Meets ADR target: WebGPU ≥ 95% of WebGL FPS */\n meetsTarget: boolean;\n recommendation: \"webgpu-ready\" | \"webgl-faster\" | \"webgpu-unavailable\";\n}\n\nexport function evaluateRendererCompare(\n webgl: BenchmarkResult,\n webgpu: BenchmarkResult | null,\n webgpuActive: boolean,\n minRatio = 0.95,\n): RendererCompareResult {\n if (!webgpuActive || !webgpu) {\n return {\n webgl,\n webgpu,\n webgpuActive: false,\n fpsRatio: 0,\n meetsTarget: false,\n recommendation: \"webgpu-unavailable\",\n };\n }\n\n const ratio = webgl.avgFps > 0 ? webgpu.avgFps / webgl.avgFps : 0;\n const meetsTarget = ratio >= minRatio;\n\n return {\n webgl,\n webgpu,\n webgpuActive: true,\n fpsRatio: ratio,\n meetsTarget,\n recommendation: meetsTarget ? \"webgpu-ready\" : \"webgl-faster\",\n };\n}\n","/**\n * Velo Plot - Testing Utilities\n * \n * Provides utilities for testing chart applications:\n * - Mock data generators\n * - Chart test harness\n * - Snapshot helpers\n * - Performance benchmarks\n * \n * @module testing\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport interface MockChartOptions {\n /** Canvas width (default: 800) */\n width?: number;\n /** Canvas height (default: 600) */\n height?: number;\n /** Device pixel ratio (default: 1) */\n devicePixelRatio?: number;\n /** Theme (default: 'dark') */\n theme?: string;\n /** Enable WebGL mock (default: true) */\n mockWebGL?: boolean;\n}\n\nexport interface WaveformOptions {\n /** Number of points (default: 1000) */\n pointCount?: number;\n /** Amplitude (default: 1) */\n amplitude?: number;\n /** Frequency in Hz (default: 1) */\n frequency?: number;\n /** Phase offset in radians (default: 0) */\n phase?: number;\n /** Noise level (0-1, default: 0) */\n noise?: number;\n /** X start value (default: 0) */\n xStart?: number;\n /** X end value (default: 10) */\n xEnd?: number;\n /** DC offset (default: 0) */\n offset?: number;\n}\n\nexport interface RandomDataOptions {\n /** Number of points (default: 1000) */\n pointCount?: number;\n /** X range [min, max] (default: [0, 100]) */\n xRange?: [number, number];\n /** Y range [min, max] (default: [-1, 1]) */\n yRange?: [number, number];\n /** Sort by X value (default: true) */\n sorted?: boolean;\n /** Seed for reproducible random (optional) */\n seed?: number;\n}\n\nexport interface BenchmarkResult {\n /** Average frames per second */\n avgFps: number;\n /** Minimum FPS recorded */\n minFps: number;\n /** Maximum FPS recorded */\n maxFps: number;\n /** Average frame time in ms */\n avgFrameTime: number;\n /** Total frames rendered */\n frameCount: number;\n /** Test duration in ms */\n duration: number;\n /** Points per frame */\n pointsRendered: number;\n /** Points per second throughput */\n throughput: number;\n /** Render-only throughput (1000 / avgFrameTime); can exceed wall FPS */\n renderFps?: number;\n}\n\nexport interface BenchmarkOptions {\n /** Duration of benchmark in ms (default: 5000) */\n duration?: number;\n /** Warmup duration in ms (default: 1000) */\n warmup?: number;\n /** Target FPS for assertions (default: 55) */\n targetFps?: number;\n /** Enable console output (default: false) */\n verbose?: boolean;\n}\n\nexport interface SnapshotOptions {\n /** Output format: 'json' | 'png' | 'canvas' (default: 'json') */\n format?: 'json' | 'png' | 'canvas';\n /** Include data in snapshot (default: false for performance) */\n includeData?: boolean;\n /** Include styles in snapshot (default: true) */\n includeStyles?: boolean;\n}\n\nexport interface ChartSnapshot {\n /** Snapshot timestamp */\n timestamp: number;\n /** Chart configuration */\n config: Record<string, unknown>;\n /** Series metadata (without data by default) */\n series: {\n id: string;\n type: string;\n pointCount: number;\n style?: Record<string, unknown>;\n }[];\n /** View bounds */\n bounds: {\n xMin: number;\n xMax: number;\n yMin: number;\n yMax: number;\n };\n /** Canvas data URL (if format is 'png') */\n image?: string;\n}\n\n// ============================================\n// Seeded Random Number Generator\n// ============================================\n\nclass SeededRandom {\n private seed: number;\n\n constructor(seed: number) {\n this.seed = seed;\n }\n\n next(): number {\n // Mulberry32 PRNG\n let t = (this.seed += 0x6d2b79f5);\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n\n nextRange(min: number, max: number): number {\n return min + this.next() * (max - min);\n }\n}\n\n// ============================================\n// Data Generators\n// ============================================\n\n/**\n * Generate a sine wave\n */\nexport function generateSineWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const baseValue =\n opts.amplitude * Math.sin(2 * Math.PI * opts.frequency * x[i] + opts.phase);\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate a square wave\n */\nexport function generateSquareWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const t = x[i] * opts.frequency + opts.phase / (2 * Math.PI);\n const baseValue = Math.sign(Math.sin(2 * Math.PI * t)) * opts.amplitude;\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate a sawtooth wave\n */\nexport function generateSawtoothWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const t = x[i] * opts.frequency + opts.phase / (2 * Math.PI);\n const baseValue = opts.amplitude * 2 * (t - Math.floor(t + 0.5));\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate a triangle wave\n */\nexport function generateTriangleWave(options?: WaveformOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<WaveformOptions> = {\n pointCount: 1000,\n amplitude: 1,\n frequency: 1,\n phase: 0,\n noise: 0,\n xStart: 0,\n xEnd: 10,\n offset: 0,\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n const dx = (opts.xEnd - opts.xStart) / (opts.pointCount - 1);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = opts.xStart + i * dx;\n const t = x[i] * opts.frequency + opts.phase / (2 * Math.PI);\n const baseValue = opts.amplitude * 2 * Math.abs(2 * (t - Math.floor(t + 0.5))) - opts.amplitude;\n const noiseValue = opts.noise > 0 ? (Math.random() - 0.5) * 2 * opts.noise : 0;\n y[i] = baseValue + noiseValue + opts.offset;\n }\n\n return { x, y };\n}\n\n/**\n * Generate random data points\n */\nexport function generateRandomData(options?: RandomDataOptions): {\n x: Float32Array;\n y: Float32Array;\n} {\n const opts: Required<RandomDataOptions> = {\n pointCount: 1000,\n xRange: [0, 100],\n yRange: [-1, 1],\n sorted: true,\n seed: Date.now(),\n ...options,\n };\n\n const rng = new SeededRandom(opts.seed);\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n\n for (let i = 0; i < opts.pointCount; i++) {\n x[i] = rng.nextRange(opts.xRange[0], opts.xRange[1]);\n y[i] = rng.nextRange(opts.yRange[0], opts.yRange[1]);\n }\n\n // Sort by X if requested\n if (opts.sorted) {\n const indices = Array.from({ length: opts.pointCount }, (_, i) => i);\n indices.sort((a, b) => x[a] - x[b]);\n \n const sortedX = new Float32Array(opts.pointCount);\n const sortedY = new Float32Array(opts.pointCount);\n \n for (let i = 0; i < opts.pointCount; i++) {\n sortedX[i] = x[indices[i]];\n sortedY[i] = y[indices[i]];\n }\n \n return { x: sortedX, y: sortedY };\n }\n\n return { x, y };\n}\n\n/**\n * Generate a cyclic voltammogram (CV) mock data\n */\nexport function generateCVData(options?: {\n pointCount?: number;\n vMin?: number;\n vMax?: number;\n cycles?: number;\n peakCurrent?: number;\n noise?: number;\n}): { x: Float32Array; y: Float32Array } {\n const opts = {\n pointCount: 2000,\n vMin: -0.5,\n vMax: 0.5,\n cycles: 1,\n peakCurrent: 10e-6, // 10 µA\n noise: 0.02,\n ...options,\n };\n\n const totalPoints = opts.pointCount * opts.cycles;\n const x = new Float32Array(totalPoints);\n const y = new Float32Array(totalPoints);\n \n const pointsPerCycle = opts.pointCount;\n const halfCycle = pointsPerCycle / 2;\n\n for (let c = 0; c < opts.cycles; c++) {\n for (let i = 0; i < pointsPerCycle; i++) {\n const idx = c * pointsPerCycle + i;\n \n // Potential sweep\n if (i < halfCycle) {\n x[idx] = opts.vMin + (opts.vMax - opts.vMin) * (i / halfCycle);\n } else {\n x[idx] = opts.vMax - (opts.vMax - opts.vMin) * ((i - halfCycle) / halfCycle);\n }\n \n // Current response (simplified Randles-Sevcik)\n const E = x[idx];\n const E0 = 0; // Formal potential\n const scanDirection = i < halfCycle ? 1 : -1;\n \n // Gaussian-like peak\n const peakWidth = 0.1;\n const exponent = -Math.pow(E - E0, 2) / (2 * peakWidth * peakWidth);\n const peakCurrent = opts.peakCurrent * Math.exp(exponent);\n \n // Add capacitive current and noise\n const capacitive = scanDirection * opts.peakCurrent * 0.1;\n const noiseValue = (Math.random() - 0.5) * 2 * opts.noise * opts.peakCurrent;\n \n y[idx] = scanDirection * peakCurrent + capacitive + noiseValue;\n }\n }\n\n return { x, y };\n}\n\n/**\n * Generate electrochemical impedance spectroscopy (EIS) Nyquist data\n */\nexport function generateNyquistData(options?: {\n pointCount?: number;\n rSolution?: number;\n rCharge?: number;\n frequency?: [number, number];\n}): { x: Float32Array; y: Float32Array } {\n const opts = {\n pointCount: 50,\n rSolution: 100, // Ohms\n rCharge: 1000, // Ohms\n frequency: [1e5, 0.01] as [number, number],\n ...options,\n };\n\n const x = new Float32Array(opts.pointCount);\n const y = new Float32Array(opts.pointCount);\n \n // Logarithmic frequency spacing\n const logFMin = Math.log10(opts.frequency[1]);\n const logFMax = Math.log10(opts.frequency[0]);\n \n for (let i = 0; i < opts.pointCount; i++) {\n const logF = logFMax - (logFMax - logFMin) * (i / (opts.pointCount - 1));\n const omega = 2 * Math.PI * Math.pow(10, logF);\n \n // Simple Randles circuit: Rs + (Rct || CPE)\n const tau = opts.rCharge * 1e-5; // Time constant\n const realPart = opts.rSolution + opts.rCharge / (1 + Math.pow(omega * tau, 2));\n const imagPart = omega * tau * opts.rCharge / (1 + Math.pow(omega * tau, 2));\n \n x[i] = realPart;\n y[i] = -imagPart; // Negative for Nyquist convention\n }\n\n return { x, y };\n}\n\n// ============================================\n// Performance Benchmarking\n// ============================================\n\n/**\n * Benchmark chart rendering performance\n */\nexport async function benchmarkRender(\n chart: { render: () => void; getAllSeries: () => { getPointCount: () => number }[] },\n options?: BenchmarkOptions\n): Promise<BenchmarkResult> {\n const opts: Required<BenchmarkOptions> = {\n duration: 5000,\n warmup: 1000,\n targetFps: 55,\n verbose: false,\n ...options,\n };\n\n const fpsHistory: number[] = [];\n const frameTimes: number[] = [];\n let frameCount = 0;\n\n // Calculate total points\n const totalPoints = chart\n .getAllSeries()\n .reduce((sum, s) => sum + s.getPointCount(), 0);\n\n return new Promise((resolve) => {\n const endTime = performance.now() + opts.warmup + opts.duration;\n const warmupEndTime = performance.now() + opts.warmup;\n let recording = false;\n let recordingStartTime = 0;\n\n function frame() {\n const now = performance.now();\n\n if (now >= endTime) {\n const avgRenderMs =\n frameTimes.length > 0\n ? frameTimes.reduce((a, b) => a + b, 0) / frameTimes.length\n : 0;\n const recordElapsedMs =\n recordingStartTime > 0 ? now - recordingStartTime : opts.duration;\n // Wall-clock FPS (includes rAF pacing + work outside timed render)\n const wallFps =\n frameCount > 0 && recordElapsedMs > 0\n ? (frameCount / recordElapsedMs) * 1000\n : 0;\n // Instantaneous render throughput (can exceed monitor refresh; useful for micro-bench)\n const renderFps =\n fpsHistory.length > 0\n ? fpsHistory.reduce((a, b) => a + b, 0) / fpsHistory.length\n : avgRenderMs > 0\n ? 1000 / avgRenderMs\n : 0;\n\n const result: BenchmarkResult = {\n avgFps: Math.round(wallFps * 100) / 100,\n minFps: Math.round((fpsHistory.length > 0 ? Math.min(...fpsHistory) : wallFps) * 100) / 100,\n maxFps: Math.round((fpsHistory.length > 0 ? Math.max(...fpsHistory) : wallFps) * 100) / 100,\n avgFrameTime: Math.round(avgRenderMs * 1000) / 1000,\n frameCount,\n duration: opts.duration,\n pointsRendered: totalPoints,\n throughput: Math.round((totalPoints * wallFps) / 1000) * 1000,\n /** @internal render-only FPS (not wall clock) */\n ...(renderFps > 0 ? { renderFps: Math.round(renderFps * 100) / 100 } : {}),\n } as BenchmarkResult;\n\n resolve(result);\n return;\n }\n\n // Start recording after warmup\n if (now >= warmupEndTime && !recording) {\n recording = true;\n recordingStartTime = now;\n frameCount = 0;\n frameTimes.length = 0;\n fpsHistory.length = 0;\n }\n\n const renderStart = performance.now();\n chart.render();\n const renderEnd = performance.now();\n\n if (recording) {\n const frameTime = renderEnd - renderStart;\n frameTimes.push(frameTime);\n frameCount++;\n\n const recentTimes = frameTimes.slice(-30);\n if (recentTimes.length > 0) {\n const avgRecentTime = recentTimes.reduce((a, b) => a + b, 0) / recentTimes.length;\n if (avgRecentTime > 0) {\n fpsHistory.push(1000 / avgRecentTime);\n }\n }\n }\n\n requestAnimationFrame(frame);\n }\n\n requestAnimationFrame(frame);\n });\n}\n\n// ============================================\n// Snapshot Utilities\n// ============================================\n\n/**\n * Create a snapshot of chart state for testing\n */\nexport function createSnapshot(\n chart: {\n getViewBounds: () => { xMin: number; xMax: number; yMin: number; yMax: number };\n getAllSeries: () => { getId: () => string; getType: () => string; getPointCount: () => number; getStyle: () => Record<string, unknown> }[];\n exportImage?: () => string;\n },\n options?: SnapshotOptions\n): ChartSnapshot {\n const opts: Required<SnapshotOptions> = {\n format: 'json',\n includeData: false,\n includeStyles: true,\n ...options,\n };\n\n const series = chart.getAllSeries().map((s) => ({\n id: s.getId(),\n type: s.getType(),\n pointCount: s.getPointCount(),\n ...(opts.includeStyles ? { style: s.getStyle() } : {}),\n }));\n\n const snapshot: ChartSnapshot = {\n timestamp: Date.now(),\n config: {},\n series,\n bounds: chart.getViewBounds(),\n };\n\n if (opts.format === 'png' && chart.exportImage) {\n snapshot.image = chart.exportImage();\n }\n\n return snapshot;\n}\n\n/**\n * Compare two snapshots for equality\n */\nexport function compareSnapshots(\n a: ChartSnapshot,\n b: ChartSnapshot,\n tolerance: number = 1e-6\n): {\n equal: boolean;\n differences: string[];\n} {\n const differences: string[] = [];\n\n // Compare series count\n if (a.series.length !== b.series.length) {\n differences.push(`Series count: ${a.series.length} vs ${b.series.length}`);\n }\n\n // Compare series metadata\n for (let i = 0; i < Math.min(a.series.length, b.series.length); i++) {\n const sa = a.series[i];\n const sb = b.series[i];\n\n if (sa.id !== sb.id) {\n differences.push(`Series[${i}] id: \"${sa.id}\" vs \"${sb.id}\"`);\n }\n if (sa.type !== sb.type) {\n differences.push(`Series[${i}] type: \"${sa.type}\" vs \"${sb.type}\"`);\n }\n if (sa.pointCount !== sb.pointCount) {\n differences.push(`Series[${i}] pointCount: ${sa.pointCount} vs ${sb.pointCount}`);\n }\n }\n\n // Compare bounds with tolerance\n const boundsKeys: (keyof ChartSnapshot['bounds'])[] = ['xMin', 'xMax', 'yMin', 'yMax'];\n for (const key of boundsKeys) {\n if (Math.abs(a.bounds[key] - b.bounds[key]) > tolerance) {\n differences.push(`Bounds.${key}: ${a.bounds[key]} vs ${b.bounds[key]}`);\n }\n }\n\n return {\n equal: differences.length === 0,\n differences,\n };\n}\n\n// ============================================\n// Test Assertions\n// ============================================\n\n/**\n * Assert that a benchmark meets performance requirements\n */\nexport function assertPerformance(\n result: BenchmarkResult,\n requirements: {\n minFps?: number;\n maxFrameTime?: number;\n minThroughput?: number;\n }\n): { passed: boolean; failures: string[] } {\n const failures: string[] = [];\n\n if (requirements.minFps && result.avgFps < requirements.minFps) {\n failures.push(`FPS ${result.avgFps} < required ${requirements.minFps}`);\n }\n\n if (requirements.maxFrameTime && result.avgFrameTime > requirements.maxFrameTime) {\n failures.push(`Frame time ${result.avgFrameTime}ms > required ${requirements.maxFrameTime}ms`);\n }\n\n if (requirements.minThroughput && result.throughput < requirements.minThroughput) {\n failures.push(`Throughput ${result.throughput} < required ${requirements.minThroughput}`);\n }\n\n return {\n passed: failures.length === 0,\n failures,\n };\n}\n\n/**\n * Wait for a number of animation frames\n */\nexport function waitForFrames(count: number = 1): Promise<void> {\n return new Promise((resolve) => {\n let remaining = count;\n function tick() {\n remaining--;\n if (remaining <= 0) {\n resolve();\n } else {\n requestAnimationFrame(tick);\n }\n }\n requestAnimationFrame(tick);\n });\n}\n\n/**\n * Wait for a specified duration\n */\nexport function waitFor(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n// Stage 1 grid spike + browser benchmarks\nexport {\n benchmarkCanvasGrid,\n benchmarkWebGLGrid,\n compareGridBackends,\n countGridVertices,\n type GridBenchmarkResult,\n type GridCompareResult,\n} from \"./gridSpikeBenchmark\";\n\nexport {\n getBaseline,\n compareScenarioToBaseline,\n buildStage1Report,\n effectiveBenchmarkFps,\n HEADLESS_LOW_FRAME_THRESHOLD,\n SMOKE_FLOORS,\n type Stage1ScenarioResult,\n type Stage1BrowserReport,\n} from \"./stage1BrowserBench\";\n\nexport {\n evaluateRendererCompare,\n type RendererCompareResult,\n} from \"./rendererBenchmark\";\n"],"names":["WebGPURenderer","canvas","opts","__publicField","gpu","ctx","format","crosshairManifest","CrosshairPlugin","definePlugin","config","showVertical","showHorizontal","color","lineStyle","lineWidth","snapToData","valueFormat","valueDisplayMode","cornerPosition","cursorX","cursorY","overlayId","pluginCtx","overlay","resizeCanvas","event","nearest","render","size","dpr","width","height","plotArea","lineColor","_a","drawFloatingLabels","drawCornerLabels","x","y","bgColor","dataX","dataY","xText","xLabelWidth","xLabelHeight","xLabelX","xLabelY","yText","yLabelWidth","yLabelHeight","yLabelX","yLabelY","xMetrics","yMetrics","maxWidth","padding","lineHeight","boxWidth","boxHeight","boxX","boxY","statsManifest","StatsPlugin","position","show","seriesId","autoUpdate","container","posStyle","updateStats","content","allSeries","targetSeries","s","allY","series","data","stats","computeStats","lines","values","n","sum","min","max","v","mean","sumSq","std","watermarkManifest","WatermarkPlugin","text","fontSize","fontFamily","rotation","ctx2d","gridHighlightManifest","GridHighlightPlugin","xIntervals","yIntervals","opacity","_event","interval","x1","x2","y1","y2","dataLoggerManifest","DataLoggerPlugin","logDataUpdates","logViewChanges","logInteractions","maxEntries","entries","addEntry","type","_ctx","saved","directionIndicatorManifest","DirectionIndicatorPlugin","sampleSize","minVelocity","historySize","idleTimeout","currentDirection","targetSeriesId","positionHistoryX","positionHistoryY","angleHistory","maxHistorySize","timeoutTimer","lastPointTimestamp","lastSeenX","lastSeenY","currentIdleTimeout","updateDirection","age","_pluginCtx","newConfig","canvasSize","totalPoints","lastX","lastY","startIdx","sumT","sumPX","sumPY","sumTPX","sumTPY","sumTT","i","t","pixelX","pixelY","meanT","meanPX","meanPY","denominator","slopePX","slopePY","rawAngle","lastPixelX","lastPixelY","smoothX","average","smoothY","smoothedAngle","smoothAngle","magnitude","val","angles","sumX","sumY","angle","arrowColor","drawArrow","length","triangleHeight","triangleWidth","BuiltinPlugins","manifest","DEFAULT_CONFIG","PluginDragEdit","userConfig","isDragging","draggedPoint","dragStartX","dragStartY","hasMoved","findNearestPoint","mouseX","mouseY","picked","pixelToData","snapToGrid","value","applyConstraints","newX","newY","constraint","validateAndSnap","finalX","finalY","tempPoint","validation","updatePointData","index","_b","_c","createDragEvent","drawPreview","pCtx","coords","origPixelX","origPixelY","currPixelX","currPixelY","api","seriesIds","point","dx","dy","dragEvent","valid","VERT_SRC","FRAG_SRC","compileShader","gl","source","shader","createProgram","vs","fs","program","buildGridLineVertices","spec","xLines","yLines","y0","x0","vertCount","out","o","WebGLGridSpike","buf","vertices","lineSegments","c","createMinimalMock2D","noop","getCanvas2DContext","makePlotArea","margin","tickPixelLines","_plotArea","xScale","yScale","xTickCount","yTickCount","snapLineCoord","measureFrames","runFrame","frames","samples","t0","b","avg","p95","benchmarkCanvasGrid","options","theme","DARK_THEME","LinearScale","renderer","OverlayRenderer","benchmarkWebGLGrid","spike","compareGridBackends","canvas2d","webgl","gainPercent","getBaseline","baseline","compareScenarioToBaseline","scenarioId","result","failures","threshold","minAllowed","maxAllowed","evaluateRendererCompare","webgpu","webgpuActive","minRatio","ratio","meetsTarget","SeededRandom","seed","generateSineWave","baseValue","noiseValue","generateSquareWave","generateSawtoothWave","generateTriangleWave","generateRandomData","rng","indices","_","a","sortedX","sortedY","generateCVData","pointsPerCycle","halfCycle","idx","E","E0","scanDirection","peakWidth","exponent","peakCurrent","capacitive","generateNyquistData","logFMin","logFMax","logF","omega","tau","realPart","imagPart","benchmarkRender","chart","fpsHistory","frameTimes","frameCount","resolve","endTime","warmupEndTime","recording","recordingStartTime","frame","now","avgRenderMs","recordElapsedMs","wallFps","renderFps","renderStart","renderEnd","frameTime","recentTimes","avgRecentTime","createSnapshot","snapshot","compareSnapshots","tolerance","differences","sa","sb","boundsKeys","key","assertPerformance","requirements","waitForFrames","count","remaining","tick","waitFor","ms"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMO,MAAMA,GAAe;AAAA,EAQ1B,YAAYC,GAA2BC,IAA8B,IAAI;AAPzD,IAAAC,EAAA;AAER,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAGN,SAAK,SAASF,GACd,KAAK,YAAYD,GAAe,YAAA;AAAA,EAElC;AAAA,EAEA,OAAO,cAAuB;AAC5B,WACE,OAAQ,WAAmB,YAAc,OACzC,OAAQ,WAAmB,UAAU,MAAQ;AAAA,EAEjD;AAAA,EAEA,MAAM,KAAKE,IAA8B,IAAmB;AAC1D,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,wDAAwD;AAG1E,UAAME,IAAO,WAAmB,UAAU;AAK1C,QAJA,KAAK,UAAU,MAAMA,EAAI,eAAe;AAAA,MACtC,iBAAiBF,EAAK,mBAAmB;AAAA,IAAA,CAC1C,GAEG,CAAC,KAAK;AACR,YAAM,IAAI,MAAM,6CAA6C;AAG/D,SAAK,SAAS,MAAM,KAAK,QAAQ,cAAA;AAEjC,UAAMG,IAAO,KAAK,OAAe,WAAW,QAAQ;AACpD,QAAI,CAACA;AACH,YAAM,IAAI,MAAM,yCAAyC;AAG3D,SAAK,UAAUA;AAEf,UAAMC,IACJJ,EAAK,oBACJE,EAAI,2BACDA,EAAI,6BACJ;AAEN,SAAK,QAAQ,UAAU;AAAA,MACrB,QAAQ,KAAK;AAAA,MACb,QAAAE;AAAA,MACA,WAAW;AAAA,IAAA,CACZ;AAAA,EACH;AAAA,EAEA,UAAgB;AACd,SAAK,SAAS,QACd,KAAK,UAAU,QACf,KAAK,UAAU;AAAA,EACjB;AACF;ACnBA,MAAMC,KAAoC;AAAA,EACtC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,eAAe,eAAe;AAAA,EACzC,MAAM,CAAC,UAAU,aAAa,SAAS;AAC3C,GAEaC,KAAkBC;AAAA,EAC3BF;AAAA,EACA,CAACG,IAAS,CAAA,MAAO;AACb,UAAM;AAAA,MACF,cAAAC,IAAe;AAAA,MACf,gBAAAC,IAAiB;AAAA,MACjB,OAAAC;AAAA,MACA,WAAAC,IAAY;AAAA,MACZ,WAAAC,IAAY;AAAA,MACZ,YAAAC,IAAa;AAAA,MACb,aAAAC,IAAc,EAAE,YAAY,GAAG,YAAY,EAAA;AAAA,IAAE,IAC7CP;AAGJ,QAAIQ,IAAuCR,EAAO,oBAAoB;AACtE,IAAIA,EAAO,mBAAmB,UAAaA,EAAO,qBAAqB,WACnEQ,IAAmBR,EAAO,iBAAiB,aAAa;AAE5D,UAAMS,IAAiCT,EAAO,kBAAkB;AAEhE,QAAIU,IAAU,IACVC,IAAU,IACVC,GACArB,IAAmC,MACnCI,IAAuC;AAE3C,WAAO;AAAA,MACH,OAAOkB,GAA0B;AAC7B,QAAAD,IAAY;AACZ,cAAME,IAAUD,EAAU,GAAG,cAAcD,GAAW;AAAA,UAClD,QAAQ;AAAA,UACR,UAAU,EAAE,KAAK,KAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,IAAA;AAAA,QAAI,CAC5D;AAED,QAAArB,IAAS,SAAS,cAAc,QAAQ,GACxCA,EAAO,MAAM,UAAU,8BACvBuB,EAAQ,YAAYvB,CAAM,GAE1BI,IAAMJ,EAAO,WAAW,IAAI,GAC5BwB,EAAaF,CAAS;AAAA,MAC1B;AAAA,MAEA,UAAUA,GAA0B;AAChC,QAAAA,EAAU,GAAG,cAAcD,CAAS,GACpCrB,IAAS,MACTI,IAAM;AAAA,MACV;AAAA,MAEA,SAASkB,GAA0B;AAC/B,QAAAE,EAAaF,CAAS;AAAA,MAC1B;AAAA,MAEA,cAAcA,GAA0BG,GAAyB;AAC7D,YAAIA,EAAM,SAAS,aAAa;AAI5B,cAHAN,IAAUM,EAAM,QAChBL,IAAUK,EAAM,QAEZV,KAAcU,EAAM,YAAY;AAChC,kBAAMC,IAAUJ,EAAU,OAAO,UAAUH,GAASC,CAAO;AAC3D,YAAIM,MACAP,IAAUO,EAAQ,QAClBN,IAAUM,EAAQ;AAAA,UAE1B;AAEA,UAAAC,EAAOL,CAAS;AAAA,QACpB;AAAA,MACJ;AAAA,MAEA,eAAe;AAAA,MAKf;AAAA,IAAA;AAGJ,aAASE,EAAaF,GAA0B;AAC5C,UAAI,CAACtB,KAAU,CAACI,EAAK;AACrB,YAAMwB,IAAON,EAAU,OAAO,YACxBO,IAAMP,EAAU,OAAO;AAC7B,MAAAtB,EAAO,QAAQ4B,EAAK,QAAQC,GAC5B7B,EAAO,SAAS4B,EAAK,SAASC,GAC9BzB,EAAI,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GACjCA,EAAI,MAAMyB,GAAKA,CAAG;AAAA,IACtB;AAEA,aAASF,EAAOL,GAA0B;;AACtC,UAAI,CAAClB,KAAO,CAACJ,EAAQ;AAErB,YAAM,EAAE,OAAA8B,GAAO,QAAAC,EAAA,IAAWT,EAAU,OAAO;AAG3C,UAFAlB,EAAI,UAAU,GAAG,GAAG0B,GAAOC,CAAM,GAE7BZ,IAAU,KAAKC,IAAU,EAAG;AAEhC,YAAMY,IAAWV,EAAU,OAAO;AAClC,UACIH,IAAUa,EAAS,KACnBb,IAAUa,EAAS,IAAIA,EAAS,SAChCZ,IAAUY,EAAS,KACnBZ,IAAUY,EAAS,IAAIA,EAAS;AAEhC;AAGJ,YAAMC,IAAYrB,OAAUsB,IAAAZ,EAAU,GAAG,MAAM,WAAnB,gBAAAY,EAAkE,UAAmB;AAEjH,MAAA9B,EAAI,KAAA,GACJA,EAAI,cAAc6B,GAClB7B,EAAI,YAAYU,GAEZD,MAAc,WACdT,EAAI,YAAY,CAAC,GAAG,CAAC,CAAC,IACfS,MAAc,YACrBT,EAAI,YAAY,CAAC,GAAG,CAAC,CAAC,GAItBM,MACAN,EAAI,UAAA,GACJA,EAAI,OAAOe,GAASa,EAAS,CAAC,GAC9B5B,EAAI,OAAOe,GAASa,EAAS,IAAIA,EAAS,MAAM,GAChD5B,EAAI,OAAA,IAIJO,MACAP,EAAI,UAAA,GACJA,EAAI,OAAO4B,EAAS,GAAGZ,CAAO,GAC9BhB,EAAI,OAAO4B,EAAS,IAAIA,EAAS,OAAOZ,CAAO,GAC/ChB,EAAI,OAAA,IAGRA,EAAI,QAAA,GAGAa,MAAqB,aACrBkB,EAAmBb,GAAWlB,GAAKe,GAASC,GAASa,CAAS,IACvDhB,MAAqB,YAC5BmB,EAAiBd,GAAWlB,GAAKe,GAASC,GAASa,CAAS;AAAA,IAGpE;AAEA,aAASE,EACLb,GACAlB,GACAiC,GACAC,GACAC,GACF;AACE,YAAMC,IAAQlB,EAAU,OAAO,aAAae,CAAC,GACvCI,IAAQnB,EAAU,OAAO,aAAagB,CAAC,GACvCN,IAAWV,EAAU,OAAO;AAElClB,MAAAA,EAAI,KAAA,GACJA,EAAI,OAAO,8BACXA,EAAI,YAAY,UAChBA,EAAI,eAAe;AAGnB,YAAMsC,IAAQF,EAAM,YAAYxB,EAAY,UAAU,GAEhD2B,IADWvC,EAAI,YAAYsC,CAAK,EACT,QAAQ,GAC/BE,IAAe,IACfC,IAAUR,IAAIM,IAAc,GAC5BG,IAAUd,EAAS,IAAIA,EAAS,SAAS;AAE/C5B,MAAAA,EAAI,YAAYmC,GAChBnC,EAAI,SAASyC,GAASC,GAASH,GAAaC,CAAY,GACxDxC,EAAI,YAAY,WAChBA,EAAI,SAASsC,GAAOL,GAAGS,IAAU,CAAC,GAGlC1C,EAAI,YAAY,SAChBA,EAAI,eAAe;AACnB,YAAM2C,IAAQN,EAAM,YAAYzB,EAAY,UAAU,GAEhDgC,IADW5C,EAAI,YAAY2C,CAAK,EACT,QAAQ,GAC/BE,IAAe,IACfC,IAAUlB,EAAS,IAAIgB,IAAc,GACrCG,IAAUb,IAAIW,IAAe;AAEnC7C,MAAAA,EAAI,YAAYmC,GAChBnC,EAAI,SAAS8C,GAASC,GAASH,GAAaC,CAAY,GACxD7C,EAAI,YAAY,WAChBA,EAAI,SAAS2C,GAAOf,EAAS,IAAI,GAAGM,CAAC,GAErClC,EAAI,QAAA;AAAA,IACR;AAEA,aAASgC,EACLd,GACAlB,GACAiC,GACAC,GACAC,GACF;AACE,YAAMC,IAAQlB,EAAU,OAAO,aAAae,CAAC,GACvCI,IAAQnB,EAAU,OAAO,aAAagB,CAAC,GACvCN,IAAWV,EAAU,OAAO;AAElClB,MAAAA,EAAI,KAAA,GACJA,EAAI,OAAO;AAEX,YAAMsC,IAAQ,MAAMF,EAAM,YAAYxB,EAAY,UAAU,CAAC,IACvD+B,IAAQ,MAAMN,EAAM,YAAYzB,EAAY,UAAU,CAAC,IAEvDoC,IAAWhD,EAAI,YAAYsC,CAAK,GAChCW,IAAWjD,EAAI,YAAY2C,CAAK,GAChCO,IAAW,KAAK,IAAIF,EAAS,OAAOC,EAAS,KAAK,GAClDE,IAAU,GACVC,IAAa,IACbC,IAAWH,IAAWC,IAAU,GAChCG,IAAYF,IAAa,IAAID,IAAU;AAG7C,UAAII,GACAC;AAEJ,cAAQ1C,GAAA;AAAA,QACJ,KAAK;AACD,UAAAyC,IAAO3B,EAAS,IAAI,GACpB4B,IAAO5B,EAAS,IAAI;AACpB;AAAA,QACJ,KAAK;AACD,UAAA2B,IAAO3B,EAAS,IAAIA,EAAS,QAAQyB,IAAW,GAChDG,IAAO5B,EAAS,IAAI;AACpB;AAAA,QACJ,KAAK;AACD,UAAA2B,IAAO3B,EAAS,IAAI,GACpB4B,IAAO5B,EAAS,IAAIA,EAAS,SAAS0B,IAAY;AAClD;AAAA,QACJ,KAAK;AACD,UAAAC,IAAO3B,EAAS,IAAIA,EAAS,QAAQyB,IAAW,GAChDG,IAAO5B,EAAS,IAAIA,EAAS,SAAS0B,IAAY;AAClD;AAAA,QACJ;AACI,UAAAC,IAAO3B,EAAS,IAAI,GACpB4B,IAAO5B,EAAS,IAAI;AAAA,MAAA;AAI5B5B,MAAAA,EAAI,YAAYmC,GAChBnC,EAAI,cAAc,MAClBA,EAAI,SAASuD,GAAMC,GAAMH,GAAUC,CAAS,GAC5CtD,EAAI,cAAc,GAGlBA,EAAI,cAAc,yBAClBA,EAAI,YAAY,GAChBA,EAAI,WAAWuD,GAAMC,GAAMH,GAAUC,CAAS,GAG9CtD,EAAI,YAAY,WAChBA,EAAI,YAAY,QAChBA,EAAI,eAAe,OACnBA,EAAI,SAASsC,GAAOiB,IAAOJ,GAASK,IAAOL,CAAO,GAClDnD,EAAI,SAAS2C,GAAOY,IAAOJ,GAASK,IAAOL,IAAUC,CAAU,GAE/DpD,EAAI,QAAA;AAAA,IACR;AAAA,EACJ;AACJ,GC/SMyD,KAAgC;AAAA,EAClC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,iBAAiB,UAAU;AAAA,EACtC,MAAM,CAAC,cAAc,WAAW,WAAW;AAC/C,GAEaC,KAActD;AAAA,EACvBqD;AAAA,EACA,CAACpD,IAAS,CAAA,MAAO;AACb,UAAM;AAAA,MACF,UAAAsD,IAAW;AAAA,MACX,MAAAC,IAAO,CAAC,SAAS,QAAQ,OAAO,KAAK;AAAA,MACrC,UAAAC;AAAA,MACA,YAAAC,IAAa;AAAA,IAAA,IACbzD;AAEJ,QAAIY,GACA8C,IAAmC;AAEvC,WAAO;AAAA,MACH,OAAO/D,GAAoB;AACvB,QAAAiB,IAAY;AACZ,cAAM+C,IAAmC,CAAA;AAEzC,QAAIL,EAAS,SAAS,KAAK,QAAY,MAAM,SACzCA,EAAS,SAAS,QAAQ,QAAY,SAAS,SAC/CA,EAAS,SAAS,MAAM,QAAY,OAAO,SAC3CA,EAAS,SAAS,OAAO,QAAY,QAAQ,SAEjDI,IAAY/D,EAAI,GAAG,cAAciB,GAAW;AAAA,UACxC,QAAQ;AAAA,UACR,UAAU+C;AAAA,UACV,eAAe;AAAA,QAAA,CAClB,GAEDD,EAAU,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAgBtBE,EAAYjE,CAAG;AAAA,MACnB;AAAA,MAEA,UAAUA,GAAoB;AAC1B,QAAAA,EAAI,GAAG,cAAciB,CAAS,GAC9B8C,IAAY;AAAA,MAChB;AAAA,MAEA,aAAa/D,GAAoB;AAC7B,QAAI8D,KACAG,EAAYjE,CAAG;AAAA,MAEvB;AAAA,MAEA,YAAYA,GAAoB;AAC5B,QAAAiE,EAAYjE,CAAG;AAAA,MACnB;AAAA,MAEA,eAAeA,GAAoB;AAC/B,QAAAiE,EAAYjE,CAAG;AAAA,MACnB;AAAA,MAEA,KAAK;AAAA,QACD,QAAQA,GAAoB;AACxB,UAAAiE,EAAYjE,CAAG;AAAA,QACnB;AAAA,MAAA;AAAA,IACJ;AAGJ,aAASiE,EAAYjE,GAAoB;AACrC,UAAI,CAAC+D,EAAW;AAEhB,YAAMG,IAAUH,EAAU,cAAc,gBAAgB;AACxD,UAAI,CAACG,EAAS;AAEd,YAAMC,IAAYnE,EAAI,KAAK,aAAA,GACrBoE,IAAeP,IACfM,EAAU,OAAO,CAACE,MAAMA,EAAE,MAAA,MAAYR,CAAQ,IAC9CM;AAEN,UAAIC,EAAa,WAAW,GAAG;AAC3B,QAAAF,EAAQ,YAAY;AACpB;AAAA,MACJ;AAGA,UAAII,IAAiB,CAAA;AAQrB,UAPAF,EAAa,QAAQ,CAACG,MAAW;AAC7B,cAAMC,IAAOD,EAAO,QAAA;AACpB,QAAIC,KAAA,QAAAA,EAAM,MACNF,IAAOA,EAAK,OAAO,MAAM,KAAKE,EAAK,CAAC,CAAC;AAAA,MAE7C,CAAC,GAEGF,EAAK,WAAW,GAAG;AACnB,QAAAJ,EAAQ,YAAY;AACpB;AAAA,MACJ;AAEA,YAAMO,IAAQC,EAAaJ,CAAI,GACzBK,IAAkB,CAAA;AAExB,MAAIf,EAAK,SAAS,OAAO,KACrBe,EAAM,KAAK,wCAAwCF,EAAM,MAAM,eAAA,CAAgB,eAAe,GAE9Fb,EAAK,SAAS,MAAM,KACpBe,EAAM,KAAK,wCAAwCF,EAAM,KAAK,YAAY,CAAC,CAAC,eAAe,GAE3Fb,EAAK,SAAS,KAAK,KACnBe,EAAM,KAAK,0CAA0CF,EAAM,IAAI,YAAY,CAAC,CAAC,eAAe,GAE5Fb,EAAK,SAAS,KAAK,KACnBe,EAAM,KAAK,0CAA0CF,EAAM,IAAI,YAAY,CAAC,CAAC,eAAe,GAE5Fb,EAAK,SAAS,KAAK,KACnBe,EAAM,KAAK,wCAAwCF,EAAM,IAAI,YAAY,CAAC,CAAC,eAAe,GAE1Fb,EAAK,SAAS,OAAO,KACrBe,EAAM,KAAK,4CAA4CF,EAAM,MAAM,YAAY,CAAC,CAAC,eAAe,GAGpGP,EAAQ,YAAYS,EAAM,KAAK,EAAE;AAAA,IACrC;AAEA,aAASD,EAAaE,GAAkB;AACpC,YAAMC,IAAID,EAAO;AACjB,UAAIE,IAAM,GACNC,IAAM,OACNC,IAAM;AAEV,iBAAWC,KAAKL;AACZ,QAAAE,KAAOG,GACHA,IAAIF,MAAKA,IAAME,IACfA,IAAID,MAAKA,IAAMC;AAGvB,YAAMC,IAAOJ,IAAMD;AAEnB,UAAIM,IAAQ;AACZ,iBAAWF,KAAKL;AACZ,QAAAO,MAAUF,IAAIC,MAAS;AAE3B,YAAME,IAAM,KAAK,KAAKD,IAAQN,CAAC;AAE/B,aAAO;AAAA,QACH,OAAOA;AAAA,QACP,MAAAK;AAAA,QACA,KAAAH;AAAA,QACA,KAAAC;AAAA,QACA,KAAAI;AAAA,QACA,OAAOJ,IAAMD;AAAA,MAAA;AAAA,IAErB;AAAA,EACJ;AACJ,GCnKMM,KAAoC;AAAA,EACtC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,eAAe;AAAA,EAC1B,MAAM,CAAC,aAAa,YAAY,SAAS;AAC7C,GAEaC,KAAkBlF;AAAA,EAC3BiF;AAAA,EACA,CAAChF,MAAW;AACR,QAAI,EAACA,KAAA,QAAAA,EAAQ;AACT,YAAM,IAAI,MAAM,+CAA+C;AAGnE,UAAM;AAAA,MACF,MAAAkF;AAAA,MACA,UAAAC,IAAW;AAAA,MACX,YAAAC,IAAa;AAAA,MACb,OAAAjF,IAAQ;AAAA,MACR,UAAAmD,IAAW;AAAA,MACX,UAAA+B,IAAW/B,MAAa,WAAW,MAAM;AAAA,IAAA,IACzCtD;AAEJ,WAAO;AAAA,MACH,gBAAgBL,GAAoB;AAChC,cAAM2F,IAAQ3F,EAAI,OAAO;AACzB,YAAI,CAAC2F,EAAO;AAGZ,QAAK3F,EAAI,OAAO;AAChB,cAAM4B,IAAW5B,EAAI,OAAO;AAE5B,QAAA2F,EAAM,KAAA,GACNA,EAAM,OAAO,GAAGH,CAAQ,MAAMC,CAAU,IACxCE,EAAM,YAAYnF,GAClBmF,EAAM,YAAY,UAClBA,EAAM,eAAe;AAErB,YAAI1D,GAAWC;AAEf,QAAIyB,MAAa,YACb1B,IAAIL,EAAS,IAAIA,EAAS,QAAQ,GAClCM,IAAIN,EAAS,IAAIA,EAAS,SAAS,KAC5B+B,MAAa,kBACpB1B,IAAIL,EAAS,IAAIA,EAAS,QAAQ4D,GAClCtD,IAAIN,EAAS,IAAIA,EAAS,SAAS4D,IAAW,MAE9CvD,IAAIL,EAAS,IAAI4D,GACjBtD,IAAIN,EAAS,IAAIA,EAAS,SAAS4D,IAAW,IAGlDG,EAAM,UAAU1D,GAAGC,CAAC,GACpByD,EAAM,OAAQD,IAAW,KAAK,KAAM,GAAG,GACvCC,EAAM,SAASJ,GAAM,GAAG,CAAC,GACzBI,EAAM,QAAA;AAAA,MACV;AAAA,IAAA;AAAA,EAER;AACJ,GChEMC,KAAwC;AAAA,EAC1C,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,eAAe;AAAA,EAC1B,MAAM,CAAC,QAAQ,aAAa,SAAS;AACzC,GAEaC,KAAsBzF;AAAA,EAC/BwF;AAAA,EACA,CAACvF,IAAS,CAAA,MAAO;AACb,UAAM,EAAE,YAAAyF,IAAa,IAAI,YAAAC,IAAa,CAAA,GAAI,SAAAC,IAAU,IAAA,IAAQ3F;AAE5D,WAAO;AAAA,MACH,gBAAgBL,GAAoBiG,GAA0B;AAC1D,cAAMN,IAAQ3F,EAAI,OAAO;AACzB,YAAI,CAAC2F,EAAO;AAEZ,cAAM/D,IAAW5B,EAAI,OAAO;AAE5B,QAAKA,EAAI,KAAK,cAAA,GAEd2F,EAAM,KAAA,GAGNA,EAAM,UAAA,GACNA,EAAM,KAAK/D,EAAS,GAAGA,EAAS,GAAGA,EAAS,OAAOA,EAAS,MAAM,GAClE+D,EAAM,KAAA,GAENA,EAAM,cAAcK;AAGpB,mBAAWE,KAAYJ,GAAY;AAC/B,gBAAMK,IAAKnG,EAAI,OAAO,aAAakG,EAAS,KAAK,GAC3CE,IAAKpG,EAAI,OAAO,aAAakG,EAAS,GAAG;AAE/C,UAAAP,EAAM,YAAYO,EAAS,OAC3BP,EAAM;AAAA,YACF,KAAK,IAAIQ,GAAIC,CAAE;AAAA,YACfxE,EAAS;AAAA,YACT,KAAK,IAAIwE,IAAKD,CAAE;AAAA,YAChBvE,EAAS;AAAA,UAAA;AAAA,QAEjB;AAGA,mBAAWsE,KAAYH,GAAY;AAC/B,gBAAMM,IAAKrG,EAAI,OAAO,aAAakG,EAAS,KAAK,GAC3CI,IAAKtG,EAAI,OAAO,aAAakG,EAAS,GAAG;AAE/C,UAAAP,EAAM,YAAYO,EAAS,OAC3BP,EAAM;AAAA,YACF/D,EAAS;AAAA,YACT,KAAK,IAAIyE,GAAIC,CAAE;AAAA,YACf1E,EAAS;AAAA,YACT,KAAK,IAAI0E,IAAKD,CAAE;AAAA,UAAA;AAAA,QAExB;AAEA,QAAAV,EAAM,QAAA;AAAA,MACV;AAAA,IAAA;AAAA,EAER;AACJ,GC3DMY,KAAqC;AAAA,EACvC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,UAAU;AAAA,EACrB,MAAM,CAAC,SAAS,WAAW,QAAQ;AACvC,GAEaC,KAAmBpG;AAAA,EAC5BmG;AAAA,EACA,CAAClG,IAAS,CAAA,MAAO;AACb,UAAM;AAAA,MACF,gBAAAoG,IAAiB;AAAA,MACjB,gBAAAC,IAAiB;AAAA,MACjB,iBAAAC,IAAkB;AAAA,MAClB,YAAAC,IAAa;AAAA,IAAA,IACbvG,GAQEwG,IAAsB,CAAA;AAE5B,aAASC,EAASC,GAAcvC,GAAe;AAC3C,MAAAqC,EAAQ,KAAK;AAAA,QACT,WAAW,KAAK,IAAA;AAAA,QAChB,MAAAE;AAAA,QACA,MAAAvC;AAAA,MAAA,CACH,GAEGqC,EAAQ,SAASD,KACjBC,EAAQ,MAAA;AAAA,IAEhB;AAEA,WAAO;AAAA,MACH,OAAO7G,GAAoB;AACvB,QAAAA,EAAI,IAAI,KAAK,yBAAyB;AAAA,MAC1C;AAAA,MAEA,aAAaA,GAAoBqB,GAAwB;AACrD,QAAIoF,MACAK,EAAS,cAAc;AAAA,UACnB,UAAUzF,EAAM;AAAA,UAChB,MAAMA,EAAM;AAAA,UACZ,YAAYA,EAAM;AAAA,QAAA,CACrB,GACDrB,EAAI,IAAI,MAAM,gBAAgBqB,EAAM,QAAQ,KAAKA,EAAM,IAAI,KAAKA,EAAM,UAAU,UAAU;AAAA,MAElG;AAAA,MAEA,aAAarB,GAAoBqB,GAAwB;AACrD,QAAIqF,MACAI,EAAS,cAAc;AAAA,UACnB,SAASzF,EAAM;AAAA,UACf,QAAQA,EAAM;AAAA,QAAA,CACjB,GACDrB,EAAI,IAAI,MAAM,gBAAgBqB,EAAM,OAAO,EAAE;AAAA,MAErD;AAAA,MAEA,cAAc2F,GAAqB3F,GAAyB;AACxD,QAAIsF,KACAG,EAAS,eAAe;AAAA,UACpB,MAAMzF,EAAM;AAAA,UACZ,QAAQA,EAAM;AAAA,UACd,QAAQA,EAAM;AAAA,UACd,YAAYA,EAAM;AAAA,QAAA,CACrB;AAAA,MAET;AAAA,MAEA,YAAY2F,GAAqB;AAC7B,eAAO,EAAE,SAAAH,EAAA;AAAA,MACb;AAAA,MAEA,cAAcG,GAAqBxC,GAAe;AAC9C,cAAMyC,IAAQzC;AACd,QAAIyC,KAAA,QAAAA,EAAO,YACPJ,EAAQ,SAAS,GACjBA,EAAQ,KAAK,GAAGI,EAAM,OAAO;AAAA,MAErC;AAAA,MAEA,KAAK;AAAA,QACD,aAAa;AACT,iBAAO,CAAC,GAAGJ,CAAO;AAAA,QACtB;AAAA,QACA,QAAQ;AACJ,UAAAA,EAAQ,SAAS;AAAA,QACrB;AAAA,QACA,SAAS;AACL,iBAAO,KAAK,UAAUA,GAAS,MAAM,CAAC;AAAA,QAC1C;AAAA,MAAA;AAAA,IACJ;AAAA,EAER;AACJ,GCxFMK,KAA6C;AAAA,EAC/C,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,iBAAiB,UAAU;AAAA,EACtC,MAAM,CAAC,aAAa,aAAa,SAAS,OAAO;AACrD,GAEaC,KAA2B/G;AAAA,EACpC8G;AAAA,EACA,CAAC7G,IAAS,CAAA,MAAO;AACb,UAAM;AAAA,MACF,UAAAwD;AAAA,MACA,YAAAuD,IAAa;AAAA,MACb,OAAA5G;AAAA,MACA,MAAAgB,IAAO;AAAA,MACP,aAAA6F,IAAc;AAAA,MACd,aAAAC,IAAc;AAAA,MACd,aAAAC;AAAA,IAAA,IACAlH;AAEJ,QAAIY,GACArB,IAAmC,MACnCI,IAAuC,MACvCwH,IAAyC,MACzCC,IAAgC;AAGpC,UAAMC,IAA6B,CAAA,GAC7BC,IAA6B,CAAA,GAC7BC,IAAyB,CAAA;AAE/B,QAAIC,IAAiBP,GACjBQ,IAAoB,MACpBC,IAAqB,KAAK,IAAA,GAC1BC,IAAY,QACZC,IAAY,QACZC,IAAqBX;AAEzB,WAAO;AAAA,MACH,OAAOrG,GAA0B;AAC7B,QAAAD,IAAY;AACZ,cAAME,IAAUD,EAAU,GAAG,cAAcD,GAAW;AAAA,UAClD,QAAQ;AAAA,UACR,UAAU,EAAE,KAAK,KAAK,MAAM,KAAK,OAAO,KAAK,QAAQ,IAAA;AAAA,UACrD,eAAe;AAAA,QAAA,CAClB;AAUD,YARArB,IAAS,SAAS,cAAc,QAAQ,GACxCA,EAAO,MAAM,UAAU,oDACvBuB,EAAQ,YAAYvB,CAAM,GAE1BI,IAAMJ,EAAO,WAAW,IAAI,GAC5BwB,EAAaF,CAAS,GAGlB2C;AACA,UAAA4D,IAAiB5D;AAAA,aACd;AACH,gBAAMM,IAAYjD,EAAU,KAAK,aAAA;AACjC,UAAIiD,EAAU,SAAS,MACnBsD,IAAiBtD,EAAU,CAAC,EAAE,MAAA;AAAA,QAEtC;AAAA,MACJ;AAAA,MAEA,UAAUjD,GAA0B;AAChC,QAAAA,EAAU,GAAG,cAAcD,CAAS,GAChC6G,kBAA2BA,CAAY,GAC3ClI,IAAS,MACTI,IAAM,MACNwH,IAAmB;AAAA,MACvB;AAAA,MAEA,SAAStG,GAA0B;AAC/B,QAAAE,EAAaF,CAAS;AAAA,MAC1B;AAAA,MAEA,cAAcA,GAA0B;AAMpC,YAJAiH,EAAgBjH,CAAS,GACzBK,EAAOL,CAAS,GAGZgH,GAAoB;AACpB,UAAIJ,kBAA2BA,CAAY;AAC3C,gBAAMM,IAAM,KAAK,IAAA,IAAQL;AACzB,UAAIK,IAAMF,MACNJ,IAAe,WAAW,MAAM;AAC5B,YAAA5G,EAAU,cAAA;AAAA,UACd,GAAGgH,IAAqBE,IAAM,EAAE;AAAA,QAExC;AAAA,MACJ;AAAA,MAEA,eAAeC,GAA2BC,GAAqC;AAC3E,YAAIA,EAAU,gBAAgB,QAAW;AAKrC,eAJAT,IAAiBS,EAAU,aAIpBZ,EAAiB,SAASG,IAAgB,CAAAH,EAAiB,MAAA;AAClE,iBAAOC,EAAiB,SAASE,IAAgB,CAAAF,EAAiB,MAAA;AAClE,iBAAOC,EAAa,SAASC,IAAgB,CAAAD,EAAa,MAAA;AAAA,QAC9D;AAEA,QAAIU,EAAU,gBAAgB,WAC1BJ,IAAqBI,EAAU;AAAA,MAEvC;AAAA,IAAA;AAGJ,aAASlH,EAAaF,GAA0B;AAC5C,UAAI,CAACtB,KAAU,CAACI,EAAK;AACrB,YAAMuI,IAAarH,EAAU,OAAO,YAC9BO,IAAMP,EAAU,OAAO;AAC7B,MAAAtB,EAAO,QAAQ2I,EAAW,QAAQ9G,GAClC7B,EAAO,SAAS2I,EAAW,SAAS9G,GACpCzB,EAAI,aAAa,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GACjCA,EAAI,MAAMyB,GAAKA,CAAG;AAAA,IACtB;AAEA,aAAS0G,EAAgBjH,GAA0B;AAI/C,UAHI,CAACuG,KAGD,CADWvG,EAAU,KAAK,UAAUuG,CAAc,EACzC;AAEb,YAAMjD,IAAOtD,EAAU,KAAK,cAAcuG,CAAc;AACxD,UAAI,CAACjD,KAAQ,CAACA,EAAK,KAAK,CAACA,EAAK,EAAG;AAEjC,YAAMgE,IAAchE,EAAK,EAAE;AAC3B,UAAIgE,IAAc,EAAG;AAGrB,YAAMC,IAAQjE,EAAK,EAAEgE,IAAc,CAAC,GAC9BE,IAAQlE,EAAK,EAAEgE,IAAc,CAAC;AAGpC,OAAIC,MAAUT,KAAaU,MAAUT,OACjCD,IAAYS,GACZR,IAAYS,GACZX,IAAqB,KAAK,IAAA;AAI9B,YAAMlD,IAAI,KAAK,IAAIuC,GAAYoB,CAAW,GACpCG,IAAWH,IAAc3D;AAG/B,UAAI+D,IAAO,GAAGC,IAAQ,GAAGC,IAAQ,GAAGC,IAAS,GAAGC,IAAS,GAAGC,IAAQ;AAEpE,eAASC,IAAIP,GAAUO,IAAIV,GAAaU,KAAK;AACzC,cAAMC,IAAID,IAAIP,GACRvG,KAAQoC,EAAK,EAAE0E,CAAC,GAChB7G,KAAQmC,EAAK,EAAE0E,CAAC,GAGhBE,IAASlI,EAAU,OAAO,aAAakB,EAAK,GAC5CiH,IAASnI,EAAU,OAAO,aAAamB,EAAK;AAElD,QAAAuG,KAAQO,GACRN,KAASO,GACTN,KAASO,GACTN,KAAUI,IAAIC,GACdJ,KAAUG,IAAIE,GACdJ,KAASE,IAAIA;AAAA,MACjB;AAEA,YAAMG,IAAQV,IAAO/D,GACf0E,KAASV,IAAQhE,GACjB2E,KAASV,IAAQjE,GAGjB4E,IAAcR,IAAQpE,IAAIyE,IAAQA;AACxC,UAAI,KAAK,IAAIG,CAAW,IAAI,MAAO;AAEnC,YAAMC,KAAWX,IAASlE,IAAIyE,IAAQC,MAAUE,GAC1CE,KAAWX,IAASnE,IAAIyE,IAAQE,MAAUC,GAG1CG,KAAW,KAAK,MAAMD,GAASD,CAAO,GAGtCG,KAAa3I,EAAU,OAAO,aAAauH,CAAK,GAChDqB,KAAa5I,EAAU,OAAO,aAAawH,CAAK;AAGtD,MAAAhB,EAAiB,KAAKmC,EAAU,GAChClC,EAAiB,KAAKmC,EAAU,GAC5BpC,EAAiB,SAASG,MAC1BH,EAAiB,MAAA,GACjBC,EAAiB,MAAA,IAIrBC,EAAa,KAAKgC,EAAQ,GACtBhC,EAAa,SAASC,KACtBD,EAAa,MAAA;AAIjB,YAAMmC,KAAUC,EAAQtC,CAAgB,GAClCuC,KAAUD,EAAQrC,CAAgB,GAClCuC,KAAgBC,EAAYvC,CAAY,GAGxCwC,KAAY,KAAK,KAAKV,IAAUA,IAAUC,IAAUA,CAAO;AAEjE,MAAAnC,IAAmB,EAAE,OAAO0C,IAAe,WAAAE,IAAW,OAAA3B,GAAO,OAAAC,GAAO,SAAAqB,IAAS,SAAAE,GAAA;AAAA,IACjF;AAEA,aAASD,EAAQpF,GAA0B;AACvC,aAAIA,EAAO,WAAW,IAAU,IACzBA,EAAO,OAAO,CAACE,GAAKuF,MAAQvF,IAAMuF,GAAK,CAAC,IAAIzF,EAAO;AAAA,IAC9D;AAEA,aAASuF,EAAYG,GAA0B;AAC3C,UAAIA,EAAO,WAAW,EAAG,QAAO;AAGhC,UAAIC,IAAO,GACPC,IAAO;AAEX,iBAAWC,KAASH;AAChB,QAAAC,KAAQ,KAAK,IAAIE,CAAK,GACtBD,KAAQ,KAAK,IAAIC,CAAK;AAI1B,aAAO,KAAK,MAAMD,IAAOF,EAAO,QAAQC,IAAOD,EAAO,MAAM;AAAA,IAChE;AAEA,aAAS/I,EAAOL,GAA0B;AACtC,UAAI,CAAClB,KAAO,CAACJ,KAAU,CAAC4H,EAAkB;AAE1C,YAAM,EAAE,OAAA9F,GAAO,QAAAC,EAAA,IAAWT,EAAU,OAAO;AAS3C,UARAlB,EAAI,UAAU,GAAG,GAAG0B,GAAOC,CAAM,GAG7BuG,MAAuB,UACX,KAAK,IAAA,IAAQH,IACfG,KAGVV,EAAiB,YAAYH,EAAa;AAG9C,YAAM0C,IAAUvC,EAAiB,SAC3ByC,IAAUzC,EAAiB,SAE3BkD,IAAalK,KAAS;AAE5B,MAAAR,EAAI,KAAA,GAGJ2K,EAAU3K,GAAK+J,GAASE,GAASzC,EAAiB,OAAOhG,GAAMkJ,CAAU,GAEzE1K,EAAI,QAAA;AAAA,IACR;AAEA,aAAS2K,EACL3K,GACAiC,GACAC,GACAuI,GACAG,GACApK,GACF;AAEE,YAAMqK,IAAiBD,IAAS,KAC1BE,IAAgBF,IAAS;AAE/B5K,MAAAA,EAAI,KAAA,GACJA,EAAI,UAAUiC,GAAGC,CAAC,GAClBlC,EAAI,OAAOyK,CAAK,GAGhBzK,EAAI,YAAYQ,GAChBR,EAAI,UAAA,GACJA,EAAI,OAAO6K,IAAiB,GAAG,CAAC,GAChC7K,EAAI,OAAO,CAAC6K,IAAiB,GAAG,CAACC,IAAgB,CAAC,GAClD9K,EAAI,OAAO,CAAC6K,IAAiB,GAAGC,IAAgB,CAAC,GACjD9K,EAAI,UAAA,GACJA,EAAI,KAAA,GAEJA,EAAI,QAAA;AAAA,IACR;AAAA,EACJ;AACJ,GCvSa+K,KAAiB;AAAA,EAC1B,WAAW5K;AAAA,EACX,YAAYuD;AAAA,EACZ,WAAW4B;AAAA,EACX,eAAeO;AAAA,EACf,YAAYW;AAAA,EACZ,oBAAoBW;AACxB,GCfM6D,KAA2B;AAAA,EAC/B,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,aAAa,eAAe;AAAA,EACvC,MAAM,CAAC,eAAe,WAAW,IAAI;AACvC,GAEMC,KAAiD;AAAA,EACrD,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,eAAe;AAAA,EACf,eAAe;AAAA,EACf,eAAe;AAAA,EACf,WAAW;AAAA,EACX,gBAAgB,CAAA;AAAA,EAChB,WAAW,OAAO,EAAE,OAAO;EAC3B,aAAa,MAAM;AAAA,EAAC;AAAA,EACpB,QAAQ,MAAM;AAAA,EAAC;AAAA,EACf,WAAW,MAAM;AAAA,EAAC;AAAA,EAClB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,cAAc;AAAA,IACZ,OAAO;AAAA,IACP,OAAO;AAAA,IACP,MAAM,CAAC,GAAG,CAAC;AAAA,IACX,SAAS;AAAA,EAAA;AAEb;AAEO,SAASC,GACdC,IAA4C,IACT;AACnC,QAAM9K,IAAS,EAAE,GAAG4K,IAAgB,GAAGE,EAAA;AACvC,MAAInL,IAA4B,MAG5BoL,IAAa,IACbC,IAAoC,MACpCC,IAAa,GACbC,IAAa,GACbC,IAAW;AAKf,WAASC,EAAiBC,GAAgBC,GAAqC;AAC7E,QAAI,CAAC3L,EAAK,QAAO;AAGjB,UAAM4L,IAAS5L,EAAI,OAAO,UAAU0L,GAAQC,GAAQtL,EAAO,SAAS;AAKpE,WAHI,CAACuL,KAGDvL,EAAO,eAAe,SAAS,KAAK,CAACA,EAAO,eAAe,SAASuL,EAAO,QAAQ,IAC9E,OAGF;AAAA,MACL,UAAUA,EAAO;AAAA,MACjB,OAAOA,EAAO;AAAA,MACd,WAAWA,EAAO;AAAA,MAClB,WAAWA,EAAO;AAAA,MAClB,UAAUA,EAAO;AAAA,MACjB,UAAUA,EAAO;AAAA,IAAA;AAAA,EAErB;AAKA,WAASC,EAAYzC,GAAgBC,GAA0C;AAC7E,WAAKrJ,IAEE;AAAA,MACL,GAAGA,EAAI,OAAO,aAAaoJ,CAAM;AAAA,MACjC,GAAGpJ,EAAI,OAAO,aAAaqJ,CAAM;AAAA,IAAA,IAJlB,EAAE,GAAG,GAAG,GAAG,EAAA;AAAA,EAM9B;AAKA,WAASyC,EAAWC,GAAe7F,GAA0B;AAC3D,WAAO,KAAK,MAAM6F,IAAQ7F,CAAQ,IAAIA;AAAA,EACxC;AAKA,WAAS8F,EACPC,GACAC,GACAC,GAC0B;AAC1B,QAAI,CAACd,EAAc,QAAO,EAAE,GAAGY,GAAMC,EAAG;AAExC,YAAQC,GAAA;AAAA,MACN,KAAK;AACH,eAAO,EAAE,GAAGF,GAAM,GAAGZ,EAAa,UAAA;AAAA,MACpC,KAAK;AACH,eAAO,EAAE,GAAGA,EAAa,WAAWa,EAAG;AAAA,MACzC,KAAK;AACH,eAAO,EAAE,GAAGb,EAAa,WAAW,GAAGA,EAAa,UAAA;AAAA,MACtD;AACE,eAAO,EAAE,GAAGY,GAAMC,EAAG;AAAA,IAAK;AAAA,EAEhC;AAKA,WAASE,EAAgBnK,GAAW,GAAqD;AACvF,QAAIoK,IAASpK,GACTqK,IAAS;AASb,QANIjM,EAAO,eACTgM,IAASP,EAAW7J,GAAG5B,EAAO,aAAa,GAC3CiM,IAASR,EAAW,GAAGzL,EAAO,aAAa,IAIzCgL,KAAgBhL,EAAO,WAAW;AACpC,YAAMkM,IAA0B,EAAE,GAAGlB,GAAc,UAAUgB,GAAQ,UAAUC,EAAA,GACzEE,IAAanM,EAAO,UAAUkM,CAAS;AAE7C,UAAI,OAAOC,KAAe;AACxB,eAAO,EAAE,GAAGH,GAAQ,GAAGC,GAAQ,OAAOE,EAAA;AAGxC,UAAI,CAACA,EAAW;AACd,eAAO,EAAE,GAAGH,GAAQ,GAAGC,GAAQ,OAAO,GAAA;AAIxC,MAAIE,EAAW,UAAU,WAAWH,IAASG,EAAW,QACpDA,EAAW,UAAU,WAAWF,IAASE,EAAW;AAAA,IAC1D;AAEA,WAAO,EAAE,GAAGH,GAAQ,GAAGC,GAAQ,OAAO,GAAA;AAAA,EACxC;AAKA,WAASG,EAAgB5I,GAAkB6I,GAAeT,GAAcC,GAAoB;;AAC1F,QAAI,CAAClM,EAAK;AAEV,UAAMuE,KAAUoI,KAAA7K,IAAA9B,EAAI,OAAc,cAAlB,gBAAA2M,EAAA,KAAA7K,GAA8B+B;AAC9C,QAAI,CAACU,EAAQ;AAEb,UAAMC,IAAOD,EAAO,QAAA;AACpB,IAAI,CAACC,KAAQ,CAACA,EAAK,KAAK,CAACA,EAAK,MAG9BA,EAAK,EAAEkI,CAAK,IAAIT,GAChBzH,EAAK,EAAEkI,CAAK,IAAIR,IAGhBU,IAAArI,EAAO,sBAAP,QAAAqI,EAAA,KAAArI,IAGAvE,EAAI,cAAA;AAAA,EACN;AAKA,WAAS6M,IAAwC;AAC/C,WAAKxB,IAEE;AAAA,MACL,UAAUA,EAAa;AAAA,MACvB,OAAOA,EAAa;AAAA,MACpB,MAAMA,EAAa;AAAA,MACnB,MAAMA,EAAa;AAAA,MACnB,MAAMA,EAAa;AAAA,MACnB,MAAMA,EAAa;AAAA,MACnB,QAAQA,EAAa,WAAWA,EAAa;AAAA,MAC7C,QAAQA,EAAa,WAAWA,EAAa;AAAA,IAAA,IAVrB;AAAA,EAY5B;AAKA,WAASyB,EAAYC,GAA2B;AAC9C,QAAI,CAAC3B,KAAc,CAACC,KAAgB,CAAChL,EAAO,YAAa;AAEzD,UAAM,EAAE,QAAAkB,GAAQ,QAAAyL,EAAA,IAAWD,GACrB,EAAE,OAAApH,MAAUpE;AAClB,QAAI,CAACoE,EAAO;AAEZ,IAAAA,EAAM,KAAA;AAGN,UAAMsH,IAAaD,EAAO,aAAa3B,EAAa,SAAS,GACvD6B,IAAaF,EAAO,aAAa3B,EAAa,SAAS,GAEvD8B,IAAaH,EAAO,aAAa3B,EAAa,QAAQ,GACtD+B,IAAaJ,EAAO,aAAa3B,EAAa,QAAQ;AAG5D,IAAA1F,EAAM,cAActF,EAAO,aAAa,SAAS,WACjDsF,EAAM,YAAYtF,EAAO,aAAa,SAAS,GAC/CsF,EAAM,cAActF,EAAO,aAAa,WAAW,KACnDsF,EAAM,YAAYtF,EAAO,aAAa,QAAQ,CAAC,GAAG,CAAC,CAAC,GAEpDsF,EAAM,UAAA,GACNA,EAAM,OAAOsH,GAAYC,CAAU,GACnCvH,EAAM,OAAOwH,GAAYC,CAAU,GACnCzH,EAAM,OAAA,GAGNA,EAAM,cAAc,GACpBA,EAAM,YAAYtF,EAAO,gBACzBsF,EAAM,YAAY,EAAE,GACpBA,EAAM,UAAA,GACNA,EAAM,IAAIwH,GAAYC,GAAY,GAAG,GAAG,KAAK,KAAK,CAAC,GACnDzH,EAAM,KAAA,GAGNA,EAAM,cAAc,WACpBA,EAAM,YAAY,GAClBA,EAAM,OAAA,GAENA,EAAM,QAAA;AAAA,EACR;AAGA,QAAM0H,IAA6C;AAAA,IACjD,SAAS;AACP,MAAAhN,EAAO,UAAU;AAAA,IACnB;AAAA,IACA,UAAU;AACR,MAAAA,EAAO,UAAU,IACb+K,MACFC,IAAe,MACfD,IAAa,IACbI,IAAW,IACXxL,KAAA,QAAAA,EAAK;AAAA,IAET;AAAA,IACA,YAAY;AACV,aAAOK,EAAO;AAAA,IAChB;AAAA,IACA,kBAAkBiN,GAAqB;AACrC,MAAAjN,EAAO,iBAAiBiN;AAAA,IAC1B;AAAA,IACA,kBAAkB;AAChB,aAAOjC;AAAA,IACT;AAAA,IACA,aAAa;AACX,MAAID,KAAcC,MAChBA,IAAe,MACfD,IAAa,IACbI,IAAW,IACXxL,KAAA,QAAAA,EAAK;AAAA,IAET;AAAA,IACA,aAAasI,GAA0C;AACrD,aAAO,OAAOjI,GAAQiI,CAAS;AAAA,IACjC;AAAA,EAAA;AAGF,SAAO;AAAA,IACL,UAAA0C;AAAA,IAEA,OAAO9J,GAA0B;AAC/B,MAAAlB,IAAMkB,GAGLlB,EAAI,MAAc,WAAWqN;AAAA,IAChC;AAAA,IAEA,UAAUhF,GAA2B;AAEnC,aAAQA,EAAW,MAAc,UAEjCrI,IAAM;AAAA,IACR;AAAA,IAEA,cAAcqI,GAA2BhH,GAA4C;AACnF,UAAKhB,EAAO;AAEZ,YAAIgB,EAAM,SAAS,aAAa;AAC9B,gBAAMkM,IAAQ9B,EAAiBpK,EAAM,QAAQA,EAAM,MAAM;AACzD,UAAIkM,MACFlC,IAAekC,GACfjC,IAAajK,EAAM,QACnBkK,IAAalK,EAAM,QACnBmK,IAAW,IACXJ,IAAa,IAEb/J,EAAM,eAAA;AAAA,QAEV,WAAWA,EAAM,SAAS,aAAa;AACrC,cAAI,CAACgK,EAAc;AAGnB,cAAI,CAACD,GAAY;AACf,kBAAMoC,IAAKnM,EAAM,SAASiK,GACpBmC,IAAKpM,EAAM,SAASkK;AAG1B,gBAFiB,KAAK,KAAKiC,IAAKA,IAAKC,IAAKA,CAAE,IAE7BpN,EAAO,eAAe;AACnC,cAAA+K,IAAa,IACbI,IAAW;AAGX,oBAAMkC,IAAYb,EAAA;AAClB,cAAIa,KAAWrN,EAAO,YAAYqN,CAAS;AAAA,YAC7C;AACE;AAAA,UAEJ;AAGA,UAAItC,KACF/J,EAAM,eAAA;AAIR,cAAI,EAAE,GAAAY,GAAG,GAAAC,MAAM2J,EAAYxK,EAAM,QAAQA,EAAM,MAAM;AAGrD,WAAC,EAAE,GAAAY,GAAG,GAAAC,MAAM8J,EAAiB/J,GAAGC,GAAG7B,EAAO,UAAU;AAGpD,gBAAM,EAAE,GAAGgM,GAAQ,GAAGC,GAAQ,OAAAqB,MAAUvB,EAAgBnK,GAAGC,CAAC;AAE5D,cAAIyL,GAAO;AACT,YAAAtC,EAAa,WAAWgB,GACxBhB,EAAa,WAAWiB;AAGxB,kBAAMoB,IAAYb,EAAA;AAClB,YAAIa,KAAWrN,EAAO,OAAOqN,CAAS,GAGtC1N,KAAA,QAAAA,EAAK;AAAA,UACP;AAAA,QACF,WAAWqB,EAAM,SAAS,WAAW;AACnC,cAAI,CAACgK,EAAc;AAEnB,cAAID,KAAcI,GAAU;AAE1B,YAAAiB;AAAA,cACEpB,EAAa;AAAA,cACbA,EAAa;AAAA,cACbA,EAAa;AAAA,cACbA,EAAa;AAAA,YAAA;AAIf,kBAAMqC,IAAYb,EAAA;AAClB,YAAIa,KAAWrN,EAAO,UAAUqN,CAAS,GAGzCrM,EAAM,eAAA;AAAA,UACR;AAGA,UAAAgK,IAAe,MACfD,IAAa,IACbI,IAAW,IACXxL,KAAA,QAAAA,EAAK;AAAA,QACP;AAAA;AAAA,IACF;AAAA,IAEA,gBAAgBkB,GAA0B;AACxC,MAAA4L,EAAY5L,CAAS;AAAA,IACvB;AAAA,IAEA,KAAAmM;AAAA,EAAA;AAEJ;ACtXA,MAAMO,KAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASXC,KAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQjB,SAASC,GAAcC,GAA2BhH,GAAciH,GAA6B;AAC3F,QAAMC,IAASF,EAAG,aAAahH,CAAI;AACnC,MAAI,CAACkH,EAAQ,OAAM,IAAI,MAAM,qBAAqB;AAGlD,MAFAF,EAAG,aAAaE,GAAQD,CAAM,GAC9BD,EAAG,cAAcE,CAAM,GACnB,CAACF,EAAG,mBAAmBE,GAAQF,EAAG,cAAc;AAClD,UAAM,IAAI,MAAMA,EAAG,iBAAiBE,CAAM,KAAK,uBAAuB;AAExE,SAAOA;AACT;AAEA,SAASC,GAAcH,GAAyC;AAC9D,QAAMI,IAAKL,GAAcC,GAAIA,EAAG,eAAeH,EAAQ,GACjDQ,IAAKN,GAAcC,GAAIA,EAAG,iBAAiBF,EAAQ,GACnDQ,IAAUN,EAAG,cAAA;AACnB,MAAI,CAACM,EAAS,OAAM,IAAI,MAAM,sBAAsB;AAIpD,MAHAN,EAAG,aAAaM,GAASF,CAAE,GAC3BJ,EAAG,aAAaM,GAASD,CAAE,GAC3BL,EAAG,YAAYM,CAAO,GAClB,CAACN,EAAG,oBAAoBM,GAASN,EAAG,WAAW;AACjD,UAAM,IAAI,MAAMA,EAAG,kBAAkBM,CAAO,KAAK,qBAAqB;AAExE,SAAAN,EAAG,aAAaI,CAAE,GAClBJ,EAAG,aAAaK,CAAE,GACXC;AACT;AAGO,SAASC,GAAsBC,GAAkC;AACtE,QAAM,EAAE,UAAA3M,GAAU,QAAA4M,GAAQ,QAAAC,EAAA,IAAWF,GAC/BG,IAAK9M,EAAS,GACdyE,IAAKzE,EAAS,IAAIA,EAAS,QAC3B+M,IAAK/M,EAAS,GACduE,IAAKvE,EAAS,IAAIA,EAAS,OAE3BgN,KAAaJ,EAAO,SAASC,EAAO,UAAU,GAC9CI,IAAM,IAAI,aAAaD,IAAY,CAAC;AAC1C,MAAIE,IAAI;AAER,aAAW7M,KAAKuM;AACd,IAAAK,EAAIC,GAAG,IAAI7M,GACX4M,EAAIC,GAAG,IAAIJ,GACXG,EAAIC,GAAG,IAAI7M,GACX4M,EAAIC,GAAG,IAAIzI;AAGb,aAAWnE,KAAKuM;AACd,IAAAI,EAAIC,GAAG,IAAIH,GACXE,EAAIC,GAAG,IAAI5M,GACX2M,EAAIC,GAAG,IAAI3I,GACX0I,EAAIC,GAAG,IAAI5M;AAGb,SAAO2M;AACT;AAEO,MAAME,GAAe;AAAA,EAQ1B,YAAYnP,GAA2B;AAP/B,IAAAE,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AACA,IAAAA,EAAA;AAGN,UAAMiO,IAAKnO,EAAO,WAAW,SAAS;AAAA,MACpC,OAAO;AAAA,MACP,WAAW;AAAA,MACX,uBAAuB;AAAA,IAAA,CACxB;AACD,QAAI,CAACmO,EAAI,OAAM,IAAI,MAAM,oCAAoC;AAE7D,SAAK,KAAKA,GACV,KAAK,UAAUG,GAAcH,CAAE,GAC/B,KAAK,YAAYA,EAAG,kBAAkB,KAAK,SAAS,WAAW,GAC/D,KAAK,cAAcA,EAAG,mBAAmB,KAAK,SAAS,aAAa,GACpE,KAAK,SAASA,EAAG,mBAAmB,KAAK,SAAS,QAAQ;AAE1D,UAAMiB,IAAMjB,EAAG,aAAA;AACf,QAAI,CAACiB,EAAK,OAAM,IAAI,MAAM,qBAAqB;AAC/C,SAAK,SAASA;AAAA,EAChB;AAAA;AAAA,EAGA,KAAKT,GAA4B;AAC/B,UAAMR,IAAK,KAAK,IACVkB,IAAWX,GAAsBC,CAAI,GACrCW,IAAeD,EAAS,SAAS;AAEvC,IAAAlB,EAAG,SAAS,GAAG,GAAGQ,EAAK,OAAOA,EAAK,MAAM,GACzCR,EAAG,WAAW,MAAM,MAAM,MAAM,CAAC,GACjCA,EAAG,MAAMA,EAAG,gBAAgB,GAE5BA,EAAG,WAAW,KAAK,OAAO,GAC1BA,EAAG,WAAWA,EAAG,cAAc,KAAK,MAAM,GAC1CA,EAAG,WAAWA,EAAG,cAAckB,GAAUlB,EAAG,YAAY,GACxDA,EAAG,wBAAwB,KAAK,SAAS,GACzCA,EAAG,oBAAoB,KAAK,WAAW,GAAGA,EAAG,OAAO,IAAO,GAAG,CAAC,GAE/DA,EAAG,UAAU,KAAK,aAAaQ,EAAK,OAAOA,EAAK,MAAM;AACtD,UAAMY,IAAIZ,EAAK,SAAS,CAAC,KAAK,MAAM,KAAK,GAAG;AAC5C,WAAAR,EAAG,UAAU,KAAK,QAAQoB,EAAE,CAAC,GAAGA,EAAE,CAAC,GAAGA,EAAE,CAAC,GAAGA,EAAE,CAAC,CAAC,GAChDpB,EAAG,UAAUQ,EAAK,aAAa,CAAC,GAEhCR,EAAG,WAAWA,EAAG,OAAO,GAAGkB,EAAS,SAAS,CAAC,GACvCC;AAAA,EACT;AAAA,EAEA,UAAgB;AACd,UAAMnB,IAAK,KAAK;AAChB,IAAAA,EAAG,aAAa,KAAK,MAAM,GAC3BA,EAAG,cAAc,KAAK,OAAO;AAAA,EAC/B;AACF;ACxHA,SAASqB,GAAoBxP,GAAqD;AAChF,QAAMyP,IAAO,MAAM;AAAA,EAAC;AACpB,SAAO;AAAA,IACL,QAAAzP;AAAA,IACA,aAAa;AAAA,IACb,WAAW;AAAA,IACX,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,cAAc;AAAA,IACd,WAAWyP;AAAA,IACX,QAAQA;AAAA,IACR,QAAQA;AAAA,IACR,QAAQA;AAAA,IACR,MAAMA;AAAA,IACN,WAAWA;AAAA,IACX,cAAcA;AAAA,IACd,aAAaA;AAAA,IACb,MAAMA;AAAA,IACN,SAASA;AAAA,IACT,WAAWA;AAAA,IACX,QAAQA;AAAA,IACR,UAAUA;AAAA,IACV,aAAa,CAAC9J,OAAkB,EAAE,OAAOA,EAAK,SAAS,EAAA;AAAA,EAAE;AAE7D;AAEA,SAAS+J,GAAmB5N,GAAeC,GAA0C;AACnF,QAAM/B,IAAS,SAAS,cAAc,QAAQ;AAC9C,SAAAA,EAAO,QAAQ8B,GACf9B,EAAO,SAAS+B,GACT/B,EAAO,WAAW,IAAI,KAAKwP,GAAoBxP,CAAM;AAC9D;AAEA,SAAS2P,GAAa7N,GAAeC,GAA0B;AAC7D,QAAM6N,IAAS,EAAE,KAAK,IAAI,OAAO,IAAI,QAAQ,IAAI,MAAM,GAAA;AACvD,SAAO;AAAA,IACL,GAAGA,EAAO;AAAA,IACV,GAAGA,EAAO;AAAA,IACV,OAAO9N,IAAQ8N,EAAO,OAAOA,EAAO;AAAA,IACpC,QAAQ7N,IAAS6N,EAAO,MAAMA,EAAO;AAAA,EAAA;AAEzC;AAEA,SAASC,GACPC,GACAC,GACAC,GACAC,GACAC,GACwC;AACxC,QAAMtB,IAASmB,EAAO,MAAME,CAAU,EAAE,IAAI,CAAC1G,MAAM4G,GAAcJ,EAAO,UAAUxG,CAAC,CAAC,CAAC,GAC/EsF,IAASmB,EAAO,MAAME,CAAU,EAAE,IAAI,CAAC3G,MAAM4G,GAAcH,EAAO,UAAUzG,CAAC,CAAC,CAAC;AACrF,SAAO,EAAE,QAAAqF,GAAQ,QAAAC,EAAA;AACnB;AAEA,SAASuB,GAAcC,GAAsBC,GAA8C;AACzF,QAAMC,IAAoB,CAAA;AAC1B,WAASjH,IAAI,GAAGA,IAAIgH,GAAQhH,KAAK;AAC/B,UAAMkH,IAAK,YAAY,IAAA;AACvB,IAAAH,EAAA,GACAE,EAAQ,MAAM,YAAY,IAAA,IAAQC,KAAM,GAAI;AAAA,EAC9C;AACA,EAAAD,EAAQ,KAAK,CAAC,GAAGE,MAAM,IAAIA,CAAC;AAC5B,QAAMC,IAAMH,EAAQ,OAAO,CAAC9L,GAAGY,MAAMZ,IAAIY,GAAG,CAAC,IAAIkL,EAAQ,QACnDI,IAAMJ,EAAQ,KAAK,MAAMA,EAAQ,SAAS,IAAI,CAAC,KAAKG;AAC1D,SAAO,EAAE,KAAAA,GAAK,KAAAC,EAAA;AAChB;AAGO,SAASC,GAAoBC,IAQhC,IAAyB;AAC3B,QAAM/O,IAAQ,KAAK,OAAO+O,EAAQ,SAAS,SAASA,EAAQ,OAAO,EAAE,GAC/D9O,IAAS,KAAK,OAAO8O,EAAQ,UAAU,SAASA,EAAQ,OAAO,EAAE,GACjEZ,IAAaY,EAAQ,cAAc,IACnCX,IAAaW,EAAQ,cAAc,IACnCP,IAASO,EAAQ,UAAU,KAE3BzQ,IAAMsP,GAAmB5N,GAAOC,CAAM,GAEtC+O,IAAQ;AAAA,IACZ,GAAGC;AAAA,IACH,MAAM;AAAA,MACJ,GAAGA,GAAW;AAAA,MACd,SAAS;AAAA,MACT,WAAWF,EAAQ,aAAa;AAAA,IAAA;AAAA,EAClC,GAGI7O,IAAW2N,GAAa7N,GAAOC,CAAM,GACrCgO,IAAS,IAAIiB,EAAA,GACbhB,IAAS,IAAIgB,EAAA;AACnB,EAAAjB,EAAO,UAAU,GAAG,GAAS,GAC7BC,EAAO,UAAU,IAAI,CAAC,GACtBD,EAAO,SAAS/N,EAAS,GAAGA,EAAS,IAAIA,EAAS,KAAK,GACvDgO,EAAO,SAAShO,EAAS,IAAIA,EAAS,QAAQA,EAAS,CAAC;AAExD,QAAMiP,IAAW,IAAIC,GAAgB9Q,GAAK0Q,CAAK,GAEzC,EAAE,KAAAJ,GAAK,KAAAC,EAAA,IAAQP,GAAc,MAAM;AACvC,IAAAhQ,EAAI,UAAU,GAAG,GAAG0B,GAAOC,CAAM,GACjCkP,EAAS,SAASjP,GAAU+N,GAAQC,GAAQ,EAAE,WAAWC,EAAA,GAAc,EAAE,WAAWC,EAAA,CAAY;AAAA,EAClG,GAAGI,CAAM,GAEH,EAAE,QAAA1B,GAAQ,QAAAC,EAAA,IAAWgB,GAAe7N,GAAU+N,GAAQC,GAAQC,GAAYC,CAAU;AAE1F,SAAO;AAAA,IACL,SAAS;AAAA,IACT,KAAKW,EAAQ,OAAO;AAAA,IACpB,OAAA/O;AAAA,IACA,QAAAC;AAAA,IACA,QAAQkO;AAAA,IACR,QAAQC;AAAA,IACR,cAActB,EAAO,SAASC,EAAO;AAAA,IACrC,YAAY,KAAK,MAAM6B,CAAG;AAAA,IAC1B,YAAY,KAAK,MAAMC,CAAG;AAAA,IAC1B,QAAAL;AAAA,EAAA;AAEJ;AAGO,SAASa,GAAmBN,IAO/B,IAAgC;AAClC,QAAM/O,IAAQ,KAAK,OAAO+O,EAAQ,SAAS,SAASA,EAAQ,OAAO,EAAE,GAC/D9O,IAAS,KAAK,OAAO8O,EAAQ,UAAU,SAASA,EAAQ,OAAO,EAAE,GACjEZ,IAAaY,EAAQ,cAAc,IACnCX,IAAaW,EAAQ,cAAc,IACnCP,IAASO,EAAQ,UAAU,KAE3B7Q,IAAS,SAAS,cAAc,QAAQ;AAC9C,EAAAA,EAAO,QAAQ8B,GACf9B,EAAO,SAAS+B;AAEhB,MAAIqP;AACJ,MAAI;AACF,IAAAA,IAAQ,IAAIjC,GAAenP,CAAM;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AAEA,QAAMgC,IAAW2N,GAAa7N,GAAOC,CAAM,GACrCgO,IAAS,IAAIiB,EAAA,GACbhB,IAAS,IAAIgB,EAAA;AACnB,EAAAjB,EAAO,UAAU,GAAG,GAAS,GAC7BC,EAAO,UAAU,IAAI,CAAC,GACtBD,EAAO,SAAS/N,EAAS,GAAGA,EAAS,IAAIA,EAAS,KAAK,GACvDgO,EAAO,SAAShO,EAAS,IAAIA,EAAS,QAAQA,EAAS,CAAC;AAExD,QAAM,EAAE,QAAA4M,GAAQ,QAAAC,EAAA,IAAWgB,GAAe7N,GAAU+N,GAAQC,GAAQC,GAAYC,CAAU,GACpFvB,IAAqB,EAAE,UAAA3M,GAAU,QAAA4M,GAAQ,QAAAC,GAAQ,OAAA/M,GAAO,QAAAC,EAAA;AAE9D,MAAIuN,IAAe;AACnB,QAAM,EAAE,KAAAoB,GAAK,KAAAC,EAAA,IAAQP,GAAc,MAAM;AACvC,IAAAd,IAAe8B,EAAM,KAAKzC,CAAI;AAAA,EAChC,GAAG2B,CAAM;AAET,SAAAc,EAAM,QAAA,GAEC;AAAA,IACL,SAAS;AAAA,IACT,KAAKP,EAAQ,OAAO;AAAA,IACpB,OAAA/O;AAAA,IACA,QAAAC;AAAA,IACA,QAAQkO;AAAA,IACR,QAAQC;AAAA,IACR,cAAAZ;AAAA,IACA,YAAY,KAAK,MAAMoB,CAAG;AAAA,IAC1B,YAAY,KAAK,MAAMC,CAAG;AAAA,IAC1B,QAAAL;AAAA,EAAA;AAEJ;AAGO,SAASe,GAAoBR,GAGd;AACpB,QAAMhP,KAAMgP,KAAA,gBAAAA,EAAS,QAAO,GACtBP,KAASO,KAAA,gBAAAA,EAAS,WAAU,KAE5BS,IAAWV,GAAoB,EAAE,KAAA/O,GAAK,QAAAyO,GAAQ,WAAW,IAAM,GAC/DiB,IAAQJ,GAAmB,EAAE,KAAAtP,GAAK,QAAAyO,GAAQ;AAEhD,MAAI,CAACiB;AACH,WAAO;AAAA,MACL,UAAAD;AAAA,MACA,OAAO;AAAA,MACP,aAAa;AAAA,MACb,gBAAgB;AAAA,IAAA;AAIpB,QAAME,KAAgBF,EAAS,aAAaC,EAAM,cAAcD,EAAS,aAAc;AAEvF,SAAO;AAAA,IACL,UAAAA;AAAA,IACA,OAAAC;AAAA,IACA,aAAa,KAAK,MAAMC,IAAc,EAAE,IAAI;AAAA,IAC5C,gBAAgBA,KAAe,KAAK,cAAc;AAAA,EAAA;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACvLO,SAASC,KAA+B;AAC7C,SAAOC;AACT;AAGO,SAASC,GACdC,GACAC,GACyC;AACzC,QAAMlD,IAAQ+C,EAAS,UAA+CE,CAAU;AAChF,MAAI,CAACjD;AACH,WAAO,EAAE,QAAQ,IAAM,UAAU,CAAA,EAAC;AAGpC,QAAMmD,IAAqB,CAAA,GACrBC,IAAYL,EAAS,uBAAuB;AAElD,MAAI,YAAYG,KAAUlD,EAAK,cAAc,QAAW;AACtD,UAAMqD,IAAarD,EAAK,aAAa,IAAIoD;AACzC,IAAIF,EAAO,SAASG,KAClBF,EAAS;AAAA,MACP,OAAOD,EAAO,MAAM,mBAAmBlD,EAAK,SAAS,aAAaqD,EAAW,QAAQ,CAAC,CAAC,SAASD,IAAY,GAAG;AAAA,IAAA;AAAA,EAGrH;AAEA,MAAI,kBAAkBF,KAAUlD,EAAK,sBAAsB,QAAW;AACpE,UAAMsD,IAAatD,EAAK,qBAAqB,IAAIoD;AACjD,IAAIF,EAAO,eAAeI,KACxBH,EAAS;AAAA,MACP,cAAcD,EAAO,YAAY,qBAAqBlD,EAAK,iBAAiB;AAAA,IAAA;AAAA,EAGlF;AAEA,MAAI,gBAAgBkD,KAAUlD,EAAK,kBAAkB,QAAW;AAC9D,UAAMsD,IAAatD,EAAK,iBAAiB,IAAIoD;AAC7C,IAAIF,EAAO,aAAaI,KACtBH,EAAS;AAAA,MACP,cAAcD,EAAO,UAAU,qBAAqBlD,EAAK,aAAa;AAAA,IAAA;AAAA,EAG5E;AAEA,SAAO,EAAE,QAAQmD,EAAS,WAAW,GAAG,UAAAA,EAAA;AAC1C;AC1FO,SAASI,GACdX,GACAY,GACAC,GACAC,IAAW,MACY;AACvB,MAAI,CAACD,KAAgB,CAACD;AACpB,WAAO;AAAA,MACL,OAAAZ;AAAA,MACA,QAAAY;AAAA,MACA,cAAc;AAAA,MACd,UAAU;AAAA,MACV,aAAa;AAAA,MACb,gBAAgB;AAAA,IAAA;AAIpB,QAAMG,IAAQf,EAAM,SAAS,IAAIY,EAAO,SAASZ,EAAM,SAAS,GAC1DgB,IAAcD,KAASD;AAE7B,SAAO;AAAA,IACL,OAAAd;AAAA,IACA,QAAAY;AAAA,IACA,cAAc;AAAA,IACd,UAAUG;AAAA,IACV,aAAAC;AAAA,IACA,gBAAgBA,IAAc,iBAAiB;AAAA,EAAA;AAEnD;ACmFA,MAAMC,GAAa;AAAA,EAGjB,YAAYC,GAAc;AAFlB,IAAAvS,EAAA;AAGN,SAAK,OAAOuS;AAAA,EACd;AAAA,EAEA,OAAe;AAEb,QAAIlJ,IAAK,KAAK,QAAQ;AACtB,WAAAA,IAAI,KAAK,KAAKA,IAAKA,MAAM,IAAKA,IAAI,CAAC,GACnCA,KAAKA,IAAI,KAAK,KAAKA,IAAKA,MAAM,GAAIA,IAAI,EAAE,KAC/BA,IAAKA,MAAM,QAAS,KAAK;AAAA,EACpC;AAAA,EAEA,UAAUpE,GAAaC,GAAqB;AAC1C,WAAOD,IAAM,KAAK,KAAA,KAAUC,IAAMD;AAAA,EACpC;AACF;AASO,SAASuN,GAAiB7B,GAG/B;AACA,QAAM5Q,IAAkC;AAAA,IACtC,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAG4Q;AAAA,EAAA,GAGCxO,IAAI,IAAI,aAAapC,EAAK,UAAU,GACpCqC,IAAI,IAAI,aAAarC,EAAK,UAAU,GACpC2N,KAAM3N,EAAK,OAAOA,EAAK,WAAWA,EAAK,aAAa;AAE1D,WAASqJ,IAAI,GAAGA,IAAIrJ,EAAK,YAAYqJ,KAAK;AACxC,IAAAjH,EAAEiH,CAAC,IAAIrJ,EAAK,SAASqJ,IAAIsE;AACzB,UAAM+E,IACJ1S,EAAK,YAAY,KAAK,IAAI,IAAI,KAAK,KAAKA,EAAK,YAAYoC,EAAEiH,CAAC,IAAIrJ,EAAK,KAAK,GACtE2S,IAAa3S,EAAK,QAAQ,KAAK,KAAK,WAAW,OAAO,IAAIA,EAAK,QAAQ;AAC7E,IAAAqC,EAAEgH,CAAC,IAAIqJ,IAAYC,IAAa3S,EAAK;AAAA,EACvC;AAEA,SAAO,EAAE,GAAAoC,GAAG,GAAAC,EAAA;AACd;AAKO,SAASuQ,GAAmBhC,GAGjC;AACA,QAAM5Q,IAAkC;AAAA,IACtC,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAG4Q;AAAA,EAAA,GAGCxO,IAAI,IAAI,aAAapC,EAAK,UAAU,GACpCqC,IAAI,IAAI,aAAarC,EAAK,UAAU,GACpC2N,KAAM3N,EAAK,OAAOA,EAAK,WAAWA,EAAK,aAAa;AAE1D,WAASqJ,IAAI,GAAGA,IAAIrJ,EAAK,YAAYqJ,KAAK;AACxC,IAAAjH,EAAEiH,CAAC,IAAIrJ,EAAK,SAASqJ,IAAIsE;AACzB,UAAMrE,IAAIlH,EAAEiH,CAAC,IAAIrJ,EAAK,YAAYA,EAAK,SAAS,IAAI,KAAK,KACnD0S,IAAY,KAAK,KAAK,KAAK,IAAI,IAAI,KAAK,KAAKpJ,CAAC,CAAC,IAAItJ,EAAK,WACxD2S,IAAa3S,EAAK,QAAQ,KAAK,KAAK,WAAW,OAAO,IAAIA,EAAK,QAAQ;AAC7E,IAAAqC,EAAEgH,CAAC,IAAIqJ,IAAYC,IAAa3S,EAAK;AAAA,EACvC;AAEA,SAAO,EAAE,GAAAoC,GAAG,GAAAC,EAAA;AACd;AAKO,SAASwQ,GAAqBjC,GAGnC;AACA,QAAM5Q,IAAkC;AAAA,IACtC,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAG4Q;AAAA,EAAA,GAGCxO,IAAI,IAAI,aAAapC,EAAK,UAAU,GACpCqC,IAAI,IAAI,aAAarC,EAAK,UAAU,GACpC2N,KAAM3N,EAAK,OAAOA,EAAK,WAAWA,EAAK,aAAa;AAE1D,WAASqJ,IAAI,GAAGA,IAAIrJ,EAAK,YAAYqJ,KAAK;AACxC,IAAAjH,EAAEiH,CAAC,IAAIrJ,EAAK,SAASqJ,IAAIsE;AACzB,UAAMrE,IAAIlH,EAAEiH,CAAC,IAAIrJ,EAAK,YAAYA,EAAK,SAAS,IAAI,KAAK,KACnD0S,IAAY1S,EAAK,YAAY,KAAKsJ,IAAI,KAAK,MAAMA,IAAI,GAAG,IACxDqJ,IAAa3S,EAAK,QAAQ,KAAK,KAAK,WAAW,OAAO,IAAIA,EAAK,QAAQ;AAC7E,IAAAqC,EAAEgH,CAAC,IAAIqJ,IAAYC,IAAa3S,EAAK;AAAA,EACvC;AAEA,SAAO,EAAE,GAAAoC,GAAG,GAAAC,EAAA;AACd;AAKO,SAASyQ,GAAqBlC,GAGnC;AACA,QAAM5Q,IAAkC;AAAA,IACtC,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAO;AAAA,IACP,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,GAAG4Q;AAAA,EAAA,GAGCxO,IAAI,IAAI,aAAapC,EAAK,UAAU,GACpCqC,IAAI,IAAI,aAAarC,EAAK,UAAU,GACpC2N,KAAM3N,EAAK,OAAOA,EAAK,WAAWA,EAAK,aAAa;AAE1D,WAASqJ,IAAI,GAAGA,IAAIrJ,EAAK,YAAYqJ,KAAK;AACxC,IAAAjH,EAAEiH,CAAC,IAAIrJ,EAAK,SAASqJ,IAAIsE;AACzB,UAAMrE,IAAIlH,EAAEiH,CAAC,IAAIrJ,EAAK,YAAYA,EAAK,SAAS,IAAI,KAAK,KACnD0S,IAAY1S,EAAK,YAAY,IAAI,KAAK,IAAI,KAAKsJ,IAAI,KAAK,MAAMA,IAAI,GAAG,EAAE,IAAItJ,EAAK,WAChF2S,IAAa3S,EAAK,QAAQ,KAAK,KAAK,WAAW,OAAO,IAAIA,EAAK,QAAQ;AAC7E,IAAAqC,EAAEgH,CAAC,IAAIqJ,IAAYC,IAAa3S,EAAK;AAAA,EACvC;AAEA,SAAO,EAAE,GAAAoC,GAAG,GAAAC,EAAA;AACd;AAKO,SAAS0Q,GAAmBnC,GAGjC;AACA,QAAM5Q,IAAoC;AAAA,IACxC,YAAY;AAAA,IACZ,QAAQ,CAAC,GAAG,GAAG;AAAA,IACf,QAAQ,CAAC,IAAI,CAAC;AAAA,IACd,QAAQ;AAAA,IACR,MAAM,KAAK,IAAA;AAAA,IACX,GAAG4Q;AAAA,EAAA,GAGCoC,IAAM,IAAIT,GAAavS,EAAK,IAAI,GAChCoC,IAAI,IAAI,aAAapC,EAAK,UAAU,GACpCqC,IAAI,IAAI,aAAarC,EAAK,UAAU;AAE1C,WAASqJ,IAAI,GAAGA,IAAIrJ,EAAK,YAAYqJ;AACnC,IAAAjH,EAAEiH,CAAC,IAAI2J,EAAI,UAAUhT,EAAK,OAAO,CAAC,GAAGA,EAAK,OAAO,CAAC,CAAC,GACnDqC,EAAEgH,CAAC,IAAI2J,EAAI,UAAUhT,EAAK,OAAO,CAAC,GAAGA,EAAK,OAAO,CAAC,CAAC;AAIrD,MAAIA,EAAK,QAAQ;AACf,UAAMiT,IAAU,MAAM,KAAK,EAAE,QAAQjT,EAAK,cAAc,CAACkT,GAAG7J,MAAMA,CAAC;AACnE,IAAA4J,EAAQ,KAAK,CAACE,GAAG3C,MAAMpO,EAAE+Q,CAAC,IAAI/Q,EAAEoO,CAAC,CAAC;AAElC,UAAM4C,IAAU,IAAI,aAAapT,EAAK,UAAU,GAC1CqT,IAAU,IAAI,aAAarT,EAAK,UAAU;AAEhD,aAAS,IAAI,GAAG,IAAIA,EAAK,YAAY;AACnC,MAAAoT,EAAQ,CAAC,IAAIhR,EAAE6Q,EAAQ,CAAC,CAAC,GACzBI,EAAQ,CAAC,IAAIhR,EAAE4Q,EAAQ,CAAC,CAAC;AAG3B,WAAO,EAAE,GAAGG,GAAS,GAAGC,EAAA;AAAA,EAC1B;AAEA,SAAO,EAAE,GAAAjR,GAAG,GAAAC,EAAA;AACd;AAKO,SAASiR,GAAe1C,GAOU;AACvC,QAAM5Q,IAAO;AAAA,IACX,YAAY;AAAA,IACZ,MAAM;AAAA,IACN,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,aAAa;AAAA;AAAA,IACb,OAAO;AAAA,IACP,GAAG4Q;AAAA,EAAA,GAGCjI,IAAc3I,EAAK,aAAaA,EAAK,QACrCoC,IAAI,IAAI,aAAauG,CAAW,GAChCtG,IAAI,IAAI,aAAasG,CAAW,GAEhC4K,IAAiBvT,EAAK,YACtBwT,IAAYD,IAAiB;AAEnC,WAAS,IAAI,GAAG,IAAIvT,EAAK,QAAQ;AAC/B,aAAS,IAAI,GAAG,IAAIuT,GAAgB,KAAK;AACvC,YAAME,IAAM,IAAIF,IAAiB;AAGjC,MAAI,IAAIC,IACNpR,EAAEqR,CAAG,IAAIzT,EAAK,QAAQA,EAAK,OAAOA,EAAK,SAAS,IAAIwT,KAEpDpR,EAAEqR,CAAG,IAAIzT,EAAK,QAAQA,EAAK,OAAOA,EAAK,UAAU,IAAIwT,KAAaA;AAIpE,YAAME,IAAItR,EAAEqR,CAAG,GACTE,IAAK,GACLC,IAAgB,IAAIJ,IAAY,IAAI,IAGpCK,IAAY,KACZC,IAAW,CAAC,KAAK,IAAIJ,IAAIC,GAAI,CAAC,KAAK,IAAIE,IAAYA,IACnDE,IAAc/T,EAAK,cAAc,KAAK,IAAI8T,CAAQ,GAGlDE,IAAaJ,IAAgB5T,EAAK,cAAc,KAChD2S,KAAc,KAAK,OAAA,IAAW,OAAO,IAAI3S,EAAK,QAAQA,EAAK;AAEjE,MAAAqC,EAAEoR,CAAG,IAAIG,IAAgBG,IAAcC,IAAarB;AAAA,IACtD;AAGF,SAAO,EAAE,GAAAvQ,GAAG,GAAAC,EAAA;AACd;AAKO,SAAS4R,GAAoBrD,GAKK;AACvC,QAAM5Q,IAAO;AAAA,IACX,YAAY;AAAA,IACZ,WAAW;AAAA;AAAA,IACX,SAAS;AAAA;AAAA,IACT,WAAW,CAAC,KAAK,IAAI;AAAA,IACrB,GAAG4Q;AAAA,EAAA,GAGCxO,IAAI,IAAI,aAAapC,EAAK,UAAU,GACpCqC,IAAI,IAAI,aAAarC,EAAK,UAAU,GAGpCkU,IAAU,KAAK,MAAMlU,EAAK,UAAU,CAAC,CAAC,GACtCmU,IAAU,KAAK,MAAMnU,EAAK,UAAU,CAAC,CAAC;AAE5C,WAASqJ,IAAI,GAAGA,IAAIrJ,EAAK,YAAYqJ,KAAK;AACxC,UAAM+K,IAAOD,KAAWA,IAAUD,MAAY7K,KAAKrJ,EAAK,aAAa,KAC/DqU,IAAQ,IAAI,KAAK,KAAK,KAAK,IAAI,IAAID,CAAI,GAGvCE,IAAMtU,EAAK,UAAU,MACrBuU,IAAWvU,EAAK,YAAYA,EAAK,WAAW,IAAI,KAAK,IAAIqU,IAAQC,GAAK,CAAC,IACvEE,IAAWH,IAAQC,IAAMtU,EAAK,WAAW,IAAI,KAAK,IAAIqU,IAAQC,GAAK,CAAC;AAE1E,IAAAlS,EAAEiH,CAAC,IAAIkL,GACPlS,EAAEgH,CAAC,IAAI,CAACmL;AAAA,EACV;AAEA,SAAO,EAAE,GAAApS,GAAG,GAAAC,EAAA;AACd;AASA,eAAsBoS,GACpBC,GACA9D,GAC0B;AAC1B,QAAM5Q,IAAmC;AAAA,IACvC,UAAU;AAAA,IACV,QAAQ;AAAA,IAGR,GAAG4Q;AAAA,EAAA,GAGC+D,IAAuB,CAAA,GACvBC,IAAuB,CAAA;AAC7B,MAAIC,IAAa;AAGjB,QAAMlM,IAAc+L,EACjB,aAAA,EACA,OAAO,CAACzP,GAAKT,MAAMS,IAAMT,EAAE,cAAA,GAAiB,CAAC;AAEhD,SAAO,IAAI,QAAQ,CAACsQ,MAAY;AAC9B,UAAMC,IAAU,YAAY,IAAA,IAAQ/U,EAAK,SAASA,EAAK,UACjDgV,IAAgB,YAAY,IAAA,IAAQhV,EAAK;AAC/C,QAAIiV,IAAY,IACZC,IAAqB;AAEzB,aAASC,IAAQ;AACf,YAAMC,IAAM,YAAY,IAAA;AAExB,UAAIA,KAAOL,GAAS;AAClB,cAAMM,IACJT,EAAW,SAAS,IAChBA,EAAW,OAAO,CAACzB,GAAG3C,MAAM2C,IAAI3C,GAAG,CAAC,IAAIoE,EAAW,SACnD,GACAU,IACJJ,IAAqB,IAAIE,IAAMF,IAAqBlV,EAAK,UAErDuV,IACJV,IAAa,KAAKS,IAAkB,IAC/BT,IAAaS,IAAmB,MACjC,GAEAE,IACJb,EAAW,SAAS,IAChBA,EAAW,OAAO,CAACxB,GAAG3C,MAAM2C,IAAI3C,GAAG,CAAC,IAAImE,EAAW,SACnDU,IAAc,IACZ,MAAOA,IACP,GAEFzD,IAA0B;AAAA,UAC9B,QAAQ,KAAK,MAAM2D,IAAU,GAAG,IAAI;AAAA,UACpC,QAAQ,KAAK,OAAOZ,EAAW,SAAS,IAAI,KAAK,IAAI,GAAGA,CAAU,IAAIY,KAAW,GAAG,IAAI;AAAA,UACxF,QAAQ,KAAK,OAAOZ,EAAW,SAAS,IAAI,KAAK,IAAI,GAAGA,CAAU,IAAIY,KAAW,GAAG,IAAI;AAAA,UACxF,cAAc,KAAK,MAAMF,IAAc,GAAI,IAAI;AAAA,UAC/C,YAAAR;AAAA,UACA,UAAU7U,EAAK;AAAA,UACf,gBAAgB2I;AAAA,UAChB,YAAY,KAAK,MAAOA,IAAc4M,IAAW,GAAI,IAAI;AAAA;AAAA,UAEzD,GAAIC,IAAY,IAAI,EAAE,WAAW,KAAK,MAAMA,IAAY,GAAG,IAAI,QAAQ,CAAA;AAAA,QAAC;AAG1E,QAAAV,EAAQlD,CAAM;AACd;AAAA,MACF;AAGA,MAAIwD,KAAOJ,KAAiB,CAACC,MAC3BA,IAAY,IACZC,IAAqBE,GACrBP,IAAa,GACbD,EAAW,SAAS,GACpBD,EAAW,SAAS;AAGtB,YAAMc,IAAc,YAAY,IAAA;AAChC,MAAAf,EAAM,OAAA;AACN,YAAMgB,IAAY,YAAY,IAAA;AAE9B,UAAIT,GAAW;AACb,cAAMU,IAAYD,IAAYD;AAC9B,QAAAb,EAAW,KAAKe,CAAS,GACzBd;AAEA,cAAMe,IAAchB,EAAW,MAAM,GAAG;AACxC,YAAIgB,EAAY,SAAS,GAAG;AAC1B,gBAAMC,IAAgBD,EAAY,OAAO,CAACzC,GAAG3C,MAAM2C,IAAI3C,GAAG,CAAC,IAAIoF,EAAY;AAC3E,UAAIC,IAAgB,KAClBlB,EAAW,KAAK,MAAOkB,CAAa;AAAA,QAExC;AAAA,MACF;AAEA,4BAAsBV,CAAK;AAAA,IAC7B;AAEA,0BAAsBA,CAAK;AAAA,EAC7B,CAAC;AACH;AASO,SAASW,GACdpB,GAKA9D,GACe;AACf,QAAM5Q,IAAkC;AAAA,IACtC,QAAQ;AAAA,IAER,eAAe;AAAA,IACf,GAAG4Q;AAAA,EAAA,GAGClM,IAASgQ,EAAM,aAAA,EAAe,IAAI,CAAClQ,OAAO;AAAA,IAC9C,IAAIA,EAAE,MAAA;AAAA,IACN,MAAMA,EAAE,QAAA;AAAA,IACR,YAAYA,EAAE,cAAA;AAAA,IACd,GAAIxE,EAAK,gBAAgB,EAAE,OAAOwE,EAAE,SAAA,MAAe,CAAA;AAAA,EAAC,EACpD,GAEIuR,IAA0B;AAAA,IAC9B,WAAW,KAAK,IAAA;AAAA,IAChB,QAAQ,CAAA;AAAA,IACR,QAAArR;AAAA,IACA,QAAQgQ,EAAM,cAAA;AAAA,EAAc;AAG9B,SAAI1U,EAAK,WAAW,SAAS0U,EAAM,gBACjCqB,EAAS,QAAQrB,EAAM,YAAA,IAGlBqB;AACT;AAKO,SAASC,GACd7C,GACA3C,GACAyF,IAAoB,MAIpB;AACA,QAAMC,IAAwB,CAAA;AAG9B,EAAI/C,EAAE,OAAO,WAAW3C,EAAE,OAAO,UAC/B0F,EAAY,KAAK,iBAAiB/C,EAAE,OAAO,MAAM,OAAO3C,EAAE,OAAO,MAAM,EAAE;AAI3E,WAASnH,IAAI,GAAGA,IAAI,KAAK,IAAI8J,EAAE,OAAO,QAAQ3C,EAAE,OAAO,MAAM,GAAGnH,KAAK;AACnE,UAAM8M,IAAKhD,EAAE,OAAO9J,CAAC,GACf+M,IAAK5F,EAAE,OAAOnH,CAAC;AAErB,IAAI8M,EAAG,OAAOC,EAAG,MACfF,EAAY,KAAK,UAAU7M,CAAC,UAAU8M,EAAG,EAAE,SAASC,EAAG,EAAE,GAAG,GAE1DD,EAAG,SAASC,EAAG,QACjBF,EAAY,KAAK,UAAU7M,CAAC,YAAY8M,EAAG,IAAI,SAASC,EAAG,IAAI,GAAG,GAEhED,EAAG,eAAeC,EAAG,cACvBF,EAAY,KAAK,UAAU7M,CAAC,iBAAiB8M,EAAG,UAAU,OAAOC,EAAG,UAAU,EAAE;AAAA,EAEpF;AAGA,QAAMC,IAAgD,CAAC,QAAQ,QAAQ,QAAQ,MAAM;AACrF,aAAWC,KAAOD;AAChB,IAAI,KAAK,IAAIlD,EAAE,OAAOmD,CAAG,IAAI9F,EAAE,OAAO8F,CAAG,CAAC,IAAIL,KAC5CC,EAAY,KAAK,UAAUI,CAAG,KAAKnD,EAAE,OAAOmD,CAAG,CAAC,OAAO9F,EAAE,OAAO8F,CAAG,CAAC,EAAE;AAI1E,SAAO;AAAA,IACL,OAAOJ,EAAY,WAAW;AAAA,IAC9B,aAAAA;AAAA,EAAA;AAEJ;AASO,SAASK,GACd3E,GACA4E,GAKyC;AACzC,QAAM3E,IAAqB,CAAA;AAE3B,SAAI2E,EAAa,UAAU5E,EAAO,SAAS4E,EAAa,UACtD3E,EAAS,KAAK,OAAOD,EAAO,MAAM,eAAe4E,EAAa,MAAM,EAAE,GAGpEA,EAAa,gBAAgB5E,EAAO,eAAe4E,EAAa,gBAClE3E,EAAS,KAAK,cAAcD,EAAO,YAAY,iBAAiB4E,EAAa,YAAY,IAAI,GAG3FA,EAAa,iBAAiB5E,EAAO,aAAa4E,EAAa,iBACjE3E,EAAS,KAAK,cAAcD,EAAO,UAAU,eAAe4E,EAAa,aAAa,EAAE,GAGnF;AAAA,IACL,QAAQ3E,EAAS,WAAW;AAAA,IAC5B,UAAAA;AAAA,EAAA;AAEJ;AAKO,SAAS4E,GAAcC,IAAgB,GAAkB;AAC9D,SAAO,IAAI,QAAQ,CAAC5B,MAAY;AAC9B,QAAI6B,IAAYD;AAChB,aAASE,IAAO;AACd,MAAAD,KACIA,KAAa,IACf7B,EAAA,IAEA,sBAAsB8B,CAAI;AAAA,IAE9B;AACA,0BAAsBA,CAAI;AAAA,EAC5B,CAAC;AACH;AAKO,SAASC,GAAQC,GAA2B;AACjD,SAAO,IAAI,QAAQ,CAAChC,MAAY,WAAWA,GAASgC,CAAE,CAAC;AACzD;"}
|