open-plant 1.3.2 → 1.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +7 -7
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1715 -1696
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/react/draw-layer-label.d.ts +4 -4
- package/dist/types/react/draw-layer-label.d.ts.map +1 -1
- package/dist/types/react/draw-layer-types.d.ts +3 -0
- package/dist/types/react/draw-layer-types.d.ts.map +1 -1
- package/dist/types/react/draw-layer.d.ts +2 -2
- package/dist/types/react/draw-layer.d.ts.map +1 -1
- package/dist/types/react/wsi-region-hit-utils.d.ts +4 -4
- package/dist/types/react/wsi-region-hit-utils.d.ts.map +1 -1
- package/dist/types/react/wsi-viewer-canvas.d.ts +4 -2
- package/dist/types/react/wsi-viewer-canvas.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../src/core/gl-utils.ts","../src/core/ortho-camera.ts","../src/core/m1-tile-renderer.ts","../src/wsi/roi-geometry.ts","../src/wsi/constants.ts","../src/wsi/utils.ts","../src/wsi/brush-stroke.ts","../src/react/draw-layer-types.ts","../src/react/draw-layer-utils.ts","../src/react/draw-layer-brush.ts","../src/react/draw-layer-label.ts","../src/react/draw-layer-overlay.ts","../src/react/draw-layer-stamp.ts","../src/react/draw-layer.tsx","../src/wsi/image-info.ts","../src/react/overview-map.tsx","../src/react/tile-viewer-canvas.tsx","../src/wsi/point-clip.ts","../src/wsi/webgpu.ts","../src/wsi/point-clip-hybrid.ts","../src/wsi/worker-client.ts","../src/wsi/point-clip-worker-client.ts","../src/wsi/point-hit-index-shared.ts","../src/wsi/point-hit-index-worker-client.ts","../src/wsi/roi-term-stats.ts","../src/wsi/tile-scheduler.ts","../src/wsi/wsi-canvas-lifecycle.ts","../src/wsi/wsi-normalize.ts","../src/wsi/wsi-interaction.ts","../src/wsi/wsi-tile-visibility.ts","../src/wsi/wsi-input-handlers.ts","../src/wsi/wsi-tile-cache.ts","../src/wsi/wsi-lifecycle-ops.ts","../src/wsi/wsi-point-data.ts","../src/wsi/wsi-render-pass.ts","../src/wsi/wsi-shaders.ts","../src/wsi/wsi-view-animation.ts","../src/wsi/wsi-view-ops.ts","../src/wsi/wsi-tile-renderer.ts","../src/react/wsi-region-hit-utils.ts","../src/react/wsi-viewer-canvas.tsx"],"sourcesContent":["function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) {\n throw new Error(\"Failed to create shader.\");\n }\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n if (!ok) {\n const log = gl.getShaderInfoLog(shader) ?? \"unknown shader error\";\n gl.deleteShader(shader);\n throw new Error(log);\n }\n\n return shader;\n}\n\nexport function createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n\n const program = gl.createProgram();\n if (!program) {\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n throw new Error(\"Failed to create program.\");\n }\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n const ok = gl.getProgramParameter(program, gl.LINK_STATUS);\n if (!ok) {\n const log = gl.getProgramInfoLog(program) ?? \"unknown link error\";\n gl.deleteProgram(program);\n throw new Error(log);\n }\n\n return program;\n}\n\nexport function requireUniformLocation(\n gl: WebGL2RenderingContext,\n program: WebGLProgram,\n uniformName: string,\n): WebGLUniformLocation {\n const location = gl.getUniformLocation(program, uniformName);\n if (!location) {\n throw new Error(`Failed to get uniform location: ${uniformName}`);\n }\n return location;\n}\n\nexport function requireWebGL2(canvas: HTMLCanvasElement): WebGL2RenderingContext {\n const context = canvas.getContext(\"webgl2\", {\n alpha: false,\n antialias: false,\n depth: false,\n stencil: false,\n preserveDrawingBuffer: false,\n powerPreference: \"high-performance\",\n });\n\n if (!context) {\n throw new Error(\"WebGL2 is not available.\");\n }\n\n return context;\n}\n","export interface ViewState {\n offsetX: number;\n offsetY: number;\n zoom: number;\n rotationDeg: number;\n}\n\nexport type WorldPoint = [number, number];\n\nfunction toRadians(deg: number): number {\n return (deg * Math.PI) / 180;\n}\n\nexport class OrthoCamera {\n private viewportWidth = 1;\n private viewportHeight = 1;\n\n private viewState: ViewState = {\n offsetX: 0,\n offsetY: 0,\n zoom: 1,\n rotationDeg: 0,\n };\n\n setViewport(width: number, height: number): void {\n this.viewportWidth = Math.max(1, width);\n this.viewportHeight = Math.max(1, height);\n }\n\n getViewportSize(): { width: number; height: number } {\n return {\n width: this.viewportWidth,\n height: this.viewportHeight,\n };\n }\n\n setViewState(next: Partial<ViewState>): void {\n if (next.offsetX !== undefined) {\n this.viewState.offsetX = next.offsetX;\n }\n\n if (next.offsetY !== undefined) {\n this.viewState.offsetY = next.offsetY;\n }\n\n if (next.zoom !== undefined) {\n this.viewState.zoom = Math.max(0.0001, next.zoom);\n }\n\n if (typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)) {\n this.viewState.rotationDeg = next.rotationDeg;\n }\n }\n\n getViewState(): ViewState {\n return { ...this.viewState };\n }\n\n getCenter(): WorldPoint {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n return [\n this.viewState.offsetX + this.viewportWidth / (2 * zoom),\n this.viewState.offsetY + this.viewportHeight / (2 * zoom),\n ];\n }\n\n setCenter(centerX: number, centerY: number): void {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n this.viewState.offsetX = centerX - this.viewportWidth / (2 * zoom);\n this.viewState.offsetY = centerY - this.viewportHeight / (2 * zoom);\n }\n\n screenToWorld(screenX: number, screenY: number): WorldPoint {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n const [centerX, centerY] = this.getCenter();\n const rotationDeg = this.viewState.rotationDeg ?? 0;\n const dx = (screenX - this.viewportWidth * 0.5) / zoom;\n const dy = (screenY - this.viewportHeight * 0.5) / zoom;\n const rad = toRadians(rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n return [centerX + dx * cos - dy * sin, centerY + dx * sin + dy * cos];\n }\n\n worldToScreen(worldX: number, worldY: number): WorldPoint {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n const [centerX, centerY] = this.getCenter();\n const rotationDeg = this.viewState.rotationDeg ?? 0;\n const dx = worldX - centerX;\n const dy = worldY - centerY;\n const rad = toRadians(rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const rx = dx * cos + dy * sin;\n const ry = -dx * sin + dy * cos;\n return [\n this.viewportWidth * 0.5 + rx * zoom,\n this.viewportHeight * 0.5 + ry * zoom,\n ];\n }\n\n getViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n const w = this.viewportWidth;\n const h = this.viewportHeight;\n return [\n this.screenToWorld(0, 0),\n this.screenToWorld(w, 0),\n this.screenToWorld(w, h),\n this.screenToWorld(0, h),\n ];\n }\n\n getMatrix(): Float32Array {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n const rotationDeg = this.viewState.rotationDeg ?? 0;\n\n if (rotationDeg === 0) {\n const viewWidth = this.viewportWidth / zoom;\n const viewHeight = this.viewportHeight / zoom;\n const sx = 2 / viewWidth;\n const sy = -2 / viewHeight;\n const tx = -1 - this.viewState.offsetX * sx;\n const ty = 1 - this.viewState.offsetY * sy;\n return new Float32Array([sx, 0, 0, 0, sy, 0, tx, ty, 1]);\n }\n\n const [centerX, centerY] = this.getCenter();\n const rad = toRadians(rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const ax = (2 * zoom * cos) / this.viewportWidth;\n const bx = (2 * zoom * sin) / this.viewportWidth;\n const ay = (2 * zoom * sin) / this.viewportHeight;\n const by = (-2 * zoom * cos) / this.viewportHeight;\n const tx = -(ax * centerX + bx * centerY);\n const ty = -(ay * centerX + by * centerY);\n return new Float32Array([ax, ay, 0, bx, by, 0, tx, ty, 1]);\n }\n}\n","import {\n\tcreateProgram,\n\trequireUniformLocation,\n\trequireWebGL2,\n} from \"./gl-utils\";\nimport { OrthoCamera, type ViewState } from \"./ortho-camera\";\nimport type { Bounds, TileDefinition } from \"./types\";\n\ninterface LoadedTile {\n\tid: string;\n\tbounds: Bounds;\n\ttexture: WebGLTexture;\n}\n\nexport interface M1TileRendererOptions {\n\tcanvas: HTMLCanvasElement;\n\timageWidth: number;\n\timageHeight: number;\n\tclearColor?: [number, number, number, number];\n\tinitialViewState?: Partial<ViewState>;\n}\n\nconst VERTEX_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 aUnit;\nin vec2 aUv;\n\nuniform mat3 uCamera;\nuniform vec4 uBounds;\n\nout vec2 vUv;\n\nvoid main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nuniform sampler2D uTexture;\n\nout vec4 outColor;\n\nvoid main() {\n outColor = texture(uTexture, vUv);\n}\n`;\n\nexport class M1TileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly imageWidth: number;\n\tprivate readonly imageHeight: number;\n\tprivate readonly clearColor: [number, number, number, number];\n\tprivate readonly program: WebGLProgram;\n\tprivate readonly vao: WebGLVertexArrayObject;\n\tprivate readonly quadBuffer: WebGLBuffer;\n\tprivate readonly uCameraLocation: WebGLUniformLocation;\n\tprivate readonly uBoundsLocation: WebGLUniformLocation;\n\tprivate readonly uTextureLocation: WebGLUniformLocation;\n\tprivate readonly resizeObserver: ResizeObserver;\n\n\tprivate tiles: LoadedTile[] = [];\n\tprivate frameId: number | null = null;\n\tprivate loadVersion = 0;\n\tprivate destroyed = false;\n\tprivate fitted = false;\n\tprivate controlledViewState = false;\n\n\tconstructor(options: M1TileRendererOptions) {\n\t\tthis.canvas = options.canvas;\n\t\tthis.imageWidth = Math.max(1, options.imageWidth);\n\t\tthis.imageHeight = Math.max(1, options.imageHeight);\n\t\tthis.clearColor = options.clearColor ?? [0.03, 0.05, 0.08, 1];\n\n\t\tthis.gl = requireWebGL2(this.canvas);\n\t\tthis.program = createProgram(this.gl, VERTEX_SHADER, FRAGMENT_SHADER);\n\n\t\tconst vao = this.gl.createVertexArray();\n\t\tconst quadBuffer = this.gl.createBuffer();\n\t\tif (!vao || !quadBuffer) {\n\t\t\tthrow new Error(\"Failed to create WebGL buffers.\");\n\t\t}\n\n\t\tthis.vao = vao;\n\t\tthis.quadBuffer = quadBuffer;\n\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadBuffer);\n\n\t\tconst quadVertices = new Float32Array([\n\t\t\t0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,\n\t\t]);\n\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\n\t\tconst unitLocation = this.gl.getAttribLocation(this.program, \"aUnit\");\n\t\tconst uvLocation = this.gl.getAttribLocation(this.program, \"aUv\");\n\t\tif (unitLocation < 0 || uvLocation < 0) {\n\t\t\tthrow new Error(\"Failed to get attribute locations.\");\n\t\t}\n\n\t\tconst stride = 4 * Float32Array.BYTES_PER_ELEMENT;\n\t\tthis.gl.enableVertexAttribArray(unitLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tunitLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t0,\n\t\t);\n\t\tthis.gl.enableVertexAttribArray(uvLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tuvLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t2 * Float32Array.BYTES_PER_ELEMENT,\n\t\t);\n\n\t\tthis.gl.bindVertexArray(null);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n\n\t\tthis.uCameraLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uCamera\",\n\t\t);\n\t\tthis.uBoundsLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uBounds\",\n\t\t);\n\t\tthis.uTextureLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uTexture\",\n\t\t);\n\n\t\tif (options.initialViewState) {\n\t\t\tthis.controlledViewState = true;\n\t\t\tthis.camera.setViewState(options.initialViewState);\n\t\t}\n\n\t\tthis.resizeObserver = new ResizeObserver(() => {\n\t\t\tthis.resize();\n\t\t});\n\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.resize();\n\t}\n\n\tasync setTiles(tiles: TileDefinition[]): Promise<void> {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst version = ++this.loadVersion;\n\n\t\tconst loaded = await Promise.all(\n\t\t\ttiles.map(async (tile) => {\n\t\t\t\tconst loadedTile = await this.loadTile(tile, version);\n\t\t\t\treturn loadedTile;\n\t\t\t}),\n\t\t);\n\n\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\tfor (const tile of loaded) {\n\t\t\t\tif (tile) {\n\t\t\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = loaded.filter((tile): tile is LoadedTile => tile !== null);\n\t\tthis.requestRender();\n\t}\n\n\tsetViewState(viewState: Partial<ViewState>): void {\n\t\tthis.controlledViewState = true;\n\t\tthis.camera.setViewState(viewState);\n\t\tthis.requestRender();\n\t}\n\n\tgetViewState(): ViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.destroyed = true;\n\t\tthis.loadVersion += 1;\n\n\t\tif (this.frameId !== null) {\n\t\t\tcancelAnimationFrame(this.frameId);\n\t\t\tthis.frameId = null;\n\t\t}\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = [];\n\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tthis.gl.deleteVertexArray(this.vao);\n\t\tthis.gl.deleteProgram(this.program);\n\t}\n\n\tprivate async loadTile(\n\t\ttile: TileDefinition,\n\t\tversion: number,\n\t): Promise<LoadedTile | null> {\n\t\ttry {\n\t\t\tconst response = await fetch(tile.url);\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Tile fetch failed: ${response.status} ${response.statusText}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst blob = await response.blob();\n\t\t\tconst bitmap = await createImageBitmap(blob);\n\n\t\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\t\tbitmap.close();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst texture = this.gl.createTexture();\n\t\t\tif (!texture) {\n\t\t\t\tbitmap.close();\n\t\t\t\tthrow new Error(\"Failed to create tile texture.\");\n\t\t\t}\n\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_S,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_T,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MIN_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MAG_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\tbitmap,\n\t\t\t);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\t\tbitmap.close();\n\n\t\t\treturn {\n\t\t\t\tid: tile.id,\n\t\t\t\tbounds: tile.bounds,\n\t\t\t\ttexture,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`[M1TileRenderer] tile load failed: ${tile.id}`, error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate resize(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssWidth = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssHeight = Math.max(1, rect.height || this.canvas.clientHeight || 1);\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst targetWidth = Math.max(1, Math.round(cssWidth * dpr));\n\t\tconst targetHeight = Math.max(1, Math.round(cssHeight * dpr));\n\n\t\tif (\n\t\t\tthis.canvas.width !== targetWidth ||\n\t\t\tthis.canvas.height !== targetHeight\n\t\t) {\n\t\t\tthis.canvas.width = targetWidth;\n\t\t\tthis.canvas.height = targetHeight;\n\t\t}\n\n\t\tthis.camera.setViewport(cssWidth, cssHeight);\n\t\tthis.gl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\n\t\tif (!this.fitted && !this.controlledViewState) {\n\t\t\tthis.fitToImage();\n\t\t\tthis.fitted = true;\n\t\t}\n\n\t\tthis.requestRender();\n\t}\n\n\tprivate fitToImage(): void {\n\t\tconst viewport = this.camera.getViewportSize();\n\n\t\tconst zoom = Math.min(\n\t\t\tviewport.width / this.imageWidth,\n\t\t\tviewport.height / this.imageHeight,\n\t\t);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tconst visibleWorldWidth = viewport.width / safeZoom;\n\t\tconst visibleWorldHeight = viewport.height / safeZoom;\n\n\t\tconst offsetX = (this.imageWidth - visibleWorldWidth) * 0.5;\n\t\tconst offsetY = (this.imageHeight - visibleWorldHeight) * 0.5;\n\n\t\tthis.camera.setViewState({\n\t\t\tzoom: safeZoom,\n\t\t\toffsetX,\n\t\t\toffsetY,\n\t\t});\n\t}\n\n\tprivate requestRender(): void {\n\t\tif (this.frameId !== null || this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.frameId = requestAnimationFrame(() => {\n\t\t\tthis.frameId = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tprivate render(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gl.clearColor(\n\t\t\tthis.clearColor[0],\n\t\t\tthis.clearColor[1],\n\t\t\tthis.clearColor[2],\n\t\t\tthis.clearColor[3],\n\t\t);\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\tthis.gl.useProgram(this.program);\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.uniformMatrix3fv(\n\t\t\tthis.uCameraLocation,\n\t\t\tfalse,\n\t\t\tthis.camera.getMatrix(),\n\t\t);\n\t\tthis.gl.uniform1i(this.uTextureLocation, 0);\n\n\t\tfor (const tile of this.tiles) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, tile.texture);\n\t\t\tthis.gl.uniform4f(\n\t\t\t\tthis.uBoundsLocation,\n\t\t\t\ttile.bounds[0],\n\t\t\t\ttile.bounds[1],\n\t\t\t\ttile.bounds[2],\n\t\t\t\ttile.bounds[3],\n\t\t\t);\n\t\t\tthis.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\tthis.gl.bindVertexArray(null);\n\t}\n\n\tprivate disposeTiles(tiles: LoadedTile[]): void {\n\t\tfor (const tile of tiles) {\n\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t}\n\t}\n}\n","import type { WsiRegionCoordinates } from \"./types\";\n\nexport type RoiCoordinate = [number, number];\nexport type RoiLinearRing = RoiCoordinate[];\nexport type RoiPolygonRings = RoiLinearRing[];\nexport type RoiMultiPolygon = RoiPolygonRings[];\nexport type RoiGeometry = RoiLinearRing | RoiPolygonRings | RoiMultiPolygon;\n\nexport function toRoiGeometry(coords: WsiRegionCoordinates | null | undefined): RoiGeometry | null | undefined;\nexport function toRoiGeometry(coords: unknown): RoiGeometry | null | undefined;\nexport function toRoiGeometry(coords: unknown): RoiGeometry | null | undefined {\n\tif (coords == null) return null;\n\treturn coords as RoiGeometry;\n}\n\nexport interface PreparedRoiPolygon {\n\touter: RoiLinearRing;\n\tholes: RoiLinearRing[];\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n\tarea: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is RoiCoordinate {\n\treturn (\n\t\tArray.isArray(value) &&\n\t\tvalue.length >= 2 &&\n\t\tisFiniteNumber(value[0]) &&\n\t\tisFiniteNumber(value[1])\n\t);\n}\n\nfunction isLinearRing(value: unknown): value is RoiLinearRing {\n\treturn Array.isArray(value) && value.length > 0 && value.every(point => isCoordinatePair(point));\n}\n\nfunction isPolygonRings(value: unknown): value is RoiPolygonRings {\n\treturn Array.isArray(value) && value.length > 0 && value.every(ring => isLinearRing(ring));\n}\n\nfunction isMultiPolygon(value: unknown): value is RoiMultiPolygon {\n\treturn Array.isArray(value) && value.length > 0 && value.every(polygon => isPolygonRings(polygon));\n}\n\nexport function closeRoiRing(coordinates: readonly RoiCoordinate[]): RoiLinearRing {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out: RoiLinearRing = [];\n\tfor (const point of coordinates) {\n\t\tif (!Array.isArray(point) || point.length < 2) continue;\n\t\tconst x = Number(point[0]);\n\t\tconst y = Number(point[1]);\n\t\tif (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && prev[0] === x && prev[1] === y) continue;\n\t\tout.push([x, y]);\n\t}\n\tif (out.length < 3) return [];\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out.length >= 4 ? out : [];\n}\n\nexport function polygonSignedArea(ring: RoiLinearRing): number {\n\tif (!Array.isArray(ring) || ring.length < 4) return 0;\n\tlet sum = 0;\n\tfor (let i = 0; i < ring.length - 1; i += 1) {\n\t\tconst a = ring[i];\n\t\tconst b = ring[i + 1];\n\t\tsum += a[0] * b[1] - b[0] * a[1];\n\t}\n\treturn sum * 0.5;\n}\n\nfunction normalizePolygonRings(rings: RoiPolygonRings): RoiPolygonRings {\n\tif (!Array.isArray(rings) || rings.length === 0) return [];\n\tconst normalized: RoiLinearRing[] = [];\n\tfor (const ring of rings) {\n\t\tconst closed = closeRoiRing(ring);\n\t\tif (closed.length >= 4) normalized.push(closed);\n\t}\n\tif (normalized.length === 0) return [];\n\tif (normalized.length === 1) return [normalized[0]];\n\n\tlet outerIndex = 0;\n\tlet outerArea = 0;\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tconst area = Math.abs(polygonSignedArea(normalized[i]));\n\t\tif (area <= outerArea) continue;\n\t\touterArea = area;\n\t\touterIndex = i;\n\t}\n\n\tconst out: RoiPolygonRings = [normalized[outerIndex]];\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tif (i === outerIndex) continue;\n\t\tout.push(normalized[i]);\n\t}\n\treturn out;\n}\n\nexport function normalizeRoiGeometry(geometry: RoiGeometry | null | undefined): RoiMultiPolygon {\n\tif (!geometry) return [];\n\n\tif (isLinearRing(geometry)) {\n\t\tconst polygon = normalizePolygonRings([geometry]);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isPolygonRings(geometry)) {\n\t\tconst polygon = normalizePolygonRings(geometry);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isMultiPolygon(geometry)) {\n\t\tconst out: RoiMultiPolygon = [];\n\t\tfor (const polygon of geometry) {\n\t\t\tconst normalized = normalizePolygonRings(polygon);\n\t\t\tif (normalized.length > 0) out.push(normalized);\n\t\t}\n\t\treturn out;\n\t}\n\n\treturn [];\n}\n\nexport function pointInRing(x: number, y: number, ring: RoiLinearRing): boolean {\n\tlet inside = false;\n\tfor (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n\t\tconst xi = ring[i][0];\n\t\tconst yi = ring[i][1];\n\t\tconst xj = ring[j][0];\n\t\tconst yj = ring[j][1];\n\t\tconst intersect =\n\t\t\tyi > y !== yj > y &&\n\t\t\tx < ((xj - xi) * (y - yi)) / ((yj - yi) || Number.EPSILON) + xi;\n\t\tif (intersect) inside = !inside;\n\t}\n\treturn inside;\n}\n\nexport function pointInPolygonWithHoles(\n\tx: number,\n\ty: number,\n\tpolygon: RoiPolygonRings,\n): boolean {\n\tif (!Array.isArray(polygon) || polygon.length === 0) return false;\n\tconst outer = polygon[0];\n\tif (!outer || outer.length < 4) return false;\n\tif (!pointInRing(x, y, outer)) return false;\n\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\tconst hole = polygon[i];\n\t\tif (!hole || hole.length < 4) continue;\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function prepareRoiPolygons(\n\tgeometries: readonly (RoiGeometry | null | undefined)[] | null | undefined,\n): PreparedRoiPolygon[] {\n\tconst prepared: PreparedRoiPolygon[] = [];\n\tfor (const geometry of geometries ?? []) {\n\t\tconst multipolygon = normalizeRoiGeometry(geometry);\n\t\tfor (const polygon of multipolygon) {\n\t\t\tconst outer = polygon[0];\n\t\t\tif (!outer || outer.length < 4) continue;\n\t\t\tlet minX = Infinity;\n\t\t\tlet minY = Infinity;\n\t\t\tlet maxX = -Infinity;\n\t\t\tlet maxY = -Infinity;\n\t\t\tfor (const [x, y] of outer) {\n\t\t\t\tif (x < minX) minX = x;\n\t\t\t\tif (x > maxX) maxX = x;\n\t\t\t\tif (y < minY) minY = y;\n\t\t\t\tif (y > maxY) maxY = y;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!Number.isFinite(minX) ||\n\t\t\t\t!Number.isFinite(minY) ||\n\t\t\t\t!Number.isFinite(maxX) ||\n\t\t\t\t!Number.isFinite(maxY)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet area = Math.abs(polygonSignedArea(outer));\n\t\t\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\t\t\tarea -= Math.abs(polygonSignedArea(polygon[i]));\n\t\t\t}\n\t\t\tprepared.push({\n\t\t\t\touter,\n\t\t\t\tholes: polygon.slice(1),\n\t\t\t\tminX,\n\t\t\t\tminY,\n\t\t\t\tmaxX,\n\t\t\t\tmaxY,\n\t\t\t\tarea: Math.max(1e-6, area),\n\t\t\t});\n\t\t}\n\t}\n\treturn prepared;\n}\n\nexport function pointInPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygon: PreparedRoiPolygon,\n): boolean {\n\tif (x < polygon.minX || x > polygon.maxX || y < polygon.minY || y > polygon.maxY) {\n\t\treturn false;\n\t}\n\tif (!pointInRing(x, y, polygon.outer)) return false;\n\tfor (const hole of polygon.holes) {\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function pointInAnyPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygons: readonly PreparedRoiPolygon[],\n): boolean {\n\tfor (const polygon of polygons) {\n\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\treturn true;\n\t}\n\treturn false;\n}\n","export const DEFAULT_POINT_COLOR: [number, number, number, number] = [\n\t160, 160, 160, 255,\n];\n","import { DEFAULT_POINT_COLOR } from \"./constants\";\nimport type { TermPalette, WsiPointData, WsiViewState } from \"./types\";\n\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nexport function calcScaleResolution(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): number {\n\tconst mpp = Number(imageMpp);\n\tconst z0 = Number(imageZoom);\n\tconst z1 = Number(currentZoom);\n\tif (!Number.isFinite(mpp) || mpp <= 0) return 1;\n\tif (!Number.isFinite(z0) || !Number.isFinite(z1)) return mpp;\n\treturn Math.pow(2, z0 - z1) * mpp;\n}\n\nexport function calcScaleLength(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): string {\n\tconst resolution = calcScaleResolution(imageMpp, imageZoom, currentZoom);\n\tlet length = 100 * resolution;\n\tif (Number(imageMpp)) {\n\t\tlet unit = \"μm\";\n\t\tif (length > 1000) {\n\t\t\tlength /= 1000;\n\t\t\tunit = \"mm\";\n\t\t}\n\t\treturn `${length.toPrecision(3)} ${unit}`;\n\t}\n\treturn `${Math.round(length * 1000) / 1000} pixels`;\n}\n\nexport function nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nexport function sanitizePointCount(pointData: WsiPointData): number {\n\tconst fillModesLength =\n\t\tpointData.fillModes instanceof Uint8Array\n\t\t\t? pointData.fillModes.length\n\t\t\t: Number.MAX_SAFE_INTEGER;\n\treturn Math.max(\n\t\t0,\n\t\tMath.min(\n\t\t\tMath.floor(pointData.count ?? 0),\n\t\t\tMath.floor((pointData.positions?.length ?? 0) / 2),\n\t\t\tpointData.paletteIndices?.length ?? 0,\n\t\t\tfillModesLength,\n\t\t),\n\t);\n}\n\nexport function isSameViewState(\n\ta: Partial<WsiViewState> | null | undefined,\n\tb: Partial<WsiViewState> | null | undefined,\n): boolean {\n\tif (!a && !b) return true;\n\tif (!a || !b) return false;\n\treturn (\n\t\tMath.abs((a.zoom ?? 0) - (b.zoom ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetX ?? 0) - (b.offsetX ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetY ?? 0) - (b.offsetY ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.rotationDeg ?? 0) - (b.rotationDeg ?? 0)) < 1e-6\n\t);\n}\n\nexport function toBearerToken(value: string | null | undefined): string {\n\tconst trimmed = String(value ?? \"\").trim();\n\tif (!trimmed) return \"\";\n\tif (/^bearer\\s+/i.test(trimmed)) {\n\t\tconst token = trimmed.replace(/^bearer\\s+/i, \"\").trim();\n\t\treturn token ? `Bearer ${token}` : \"\";\n\t}\n\treturn `Bearer ${trimmed}`;\n}\n\nexport function hexToRgba(\n\thex: string | null | undefined,\n): [number, number, number, number] {\n\tconst value = String(hex ?? \"\").trim();\n\tconst match = value.match(/^#?([0-9a-fA-F]{6})$/);\n\tif (!match) return [...DEFAULT_POINT_COLOR];\n\n\tconst n = Number.parseInt(match[1], 16);\n\treturn [(n >> 16) & 255, (n >> 8) & 255, n & 255, 255];\n}\n\nexport function buildTermPalette(\n\tterms:\n\t\t| Array<{ termId?: string | null; termColor?: string | null }>\n\t\t| null\n\t\t| undefined,\n): TermPalette {\n\tconst palette: Array<[number, number, number, number]> = [\n\t\t[...DEFAULT_POINT_COLOR],\n\t];\n\tconst termToPaletteIndex = new Map<string, number>();\n\n\tfor (const term of terms ?? []) {\n\t\tconst termId = String(term?.termId ?? \"\");\n\t\tif (!termId || termToPaletteIndex.has(termId)) continue;\n\n\t\ttermToPaletteIndex.set(termId, palette.length);\n\t\tpalette.push(hexToRgba(term?.termColor));\n\t}\n\n\tconst colors = new Uint8Array(palette.length * 4);\n\tfor (let i = 0; i < palette.length; i += 1) {\n\t\tcolors[i * 4] = palette[i][0];\n\t\tcolors[i * 4 + 1] = palette[i][1];\n\t\tcolors[i * 4 + 2] = palette[i][2];\n\t\tcolors[i * 4 + 3] = palette[i][3];\n\t}\n\n\treturn { colors, termToPaletteIndex };\n}\n","import { closeRoiRing as closeRing, polygonSignedArea } from \"./roi-geometry\";\nimport { clamp } from \"./utils\";\n\nexport type BrushStrokeCoordinate = [number, number];\nexport type BrushStrokeBounds = [number, number, number, number];\n\nexport interface BrushStrokePolygonOptions {\n\tradius: number;\n\tclipBounds?: BrushStrokeBounds;\n\tminRasterStep?: number;\n\tmaxRasterPixels?: number;\n\tmaxRasterSize?: number;\n\tsimplifyTolerance?: number;\n\tcircleSides?: number;\n\tsmoothingPasses?: number;\n}\n\ninterface RasterConfig {\n\tminX: number;\n\tminY: number;\n\tstep: number;\n\tpadding: number;\n\twidth: number;\n\theight: number;\n}\n\ninterface BoundaryEdge {\n\tstart: number;\n\tend: number;\n\tdir: 0 | 1 | 2 | 3;\n}\n\nconst DEFAULT_MIN_RASTER_STEP = 0.1;\nconst DEFAULT_MAX_RASTER_PIXELS = 4_000_000;\nconst DEFAULT_MAX_RASTER_SIZE = 4096;\nconst DEFAULT_CIRCLE_SIDES = 64;\nconst DEFAULT_SMOOTHING_PASSES = 1;\nconst MAX_SMOOTHING_PASSES = 4;\nconst MIN_RADIUS = 1e-6;\nconst ALPHA_THRESHOLD = 24;\n\nfunction sanitizePath(\n\tpoints: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(points) || points.length === 0) return [];\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (const point of points) {\n\t\tif (!Array.isArray(point) || point.length < 2) continue;\n\t\tconst x = Number(point[0]);\n\t\tconst y = Number(point[1]);\n\t\tif (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && Math.abs(prev[0] - x) < 1e-9 && Math.abs(prev[1] - y) < 1e-9) {\n\t\t\tcontinue;\n\t\t}\n\t\tout.push([x, y]);\n\t}\n\treturn out;\n}\n\nfunction createCirclePolygon(\n\tcenter: BrushStrokeCoordinate,\n\tradius: number,\n\tsides: number,\n): BrushStrokeCoordinate[] {\n\tif (radius <= MIN_RADIUS || sides < 8) return [];\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i <= sides; i += 1) {\n\t\tconst t = (i / sides) * Math.PI * 2;\n\t\tring.push([\n\t\t\tcenter[0] + Math.cos(t) * radius,\n\t\t\tcenter[1] + Math.sin(t) * radius,\n\t\t]);\n\t}\n\treturn closeRing(ring);\n}\n\nfunction createBoundsFallback(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeCoordinate[] {\n\tif (!points.length) return [];\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\n\t\tif (x < minX) minX = x;\n\t\tif (x > maxX) maxX = x;\n\t\tif (y < minY) minY = y;\n\t\tif (y > maxY) maxY = y;\n\t}\n\tif (!Number.isFinite(minX) || !Number.isFinite(minY)) return [];\n\tconst pad = Math.max(radius, 1);\n\treturn closeRing([\n\t\t[minX - pad, minY - pad],\n\t\t[maxX + pad, minY - pad],\n\t\t[maxX + pad, maxY + pad],\n\t\t[minX - pad, maxY + pad],\n\t]);\n}\n\nfunction computeExpandedBounds(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeBounds {\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\n\t\tif (x < minX) minX = x;\n\t\tif (x > maxX) maxX = x;\n\t\tif (y < minY) minY = y;\n\t\tif (y > maxY) maxY = y;\n\t}\n\tconst pad = Math.max(radius, 1);\n\treturn [minX - pad, minY - pad, maxX + pad, maxY + pad];\n}\n\nfunction resolveRasterConfig(\n\tbounds: BrushStrokeBounds,\n\tradius: number,\n\toptions: BrushStrokePolygonOptions,\n): RasterConfig {\n\tconst minRasterStep = Math.max(\n\t\tDEFAULT_MIN_RASTER_STEP,\n\t\tNumber(options.minRasterStep) || 0,\n\t);\n\tconst maxRasterPixels = Math.max(\n\t\t32_768,\n\t\tMath.floor(options.maxRasterPixels || DEFAULT_MAX_RASTER_PIXELS),\n\t);\n\tconst maxRasterSize = Math.max(\n\t\t256,\n\t\tMath.floor(options.maxRasterSize || DEFAULT_MAX_RASTER_SIZE),\n\t);\n\n\tconst widthWorld = Math.max(1e-3, bounds[2] - bounds[0]);\n\tconst heightWorld = Math.max(1e-3, bounds[3] - bounds[1]);\n\tlet step = Math.max(minRasterStep, Number.EPSILON);\n\tlet padding = 3;\n\tlet width = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\tlet height = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\n\twhile (\n\t\twidth > maxRasterSize ||\n\t\theight > maxRasterSize ||\n\t\twidth * height > maxRasterPixels\n\t) {\n\t\tstep *= 1.15;\n\t\twidth = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\t\theight = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\t\tif (step > Math.max(widthWorld, heightWorld)) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\twidth = Math.max(8, width);\n\theight = Math.max(8, height);\n\n\treturn {\n\t\tminX: bounds[0],\n\t\tminY: bounds[1],\n\t\tstep,\n\t\tpadding,\n\t\twidth,\n\t\theight,\n\t};\n}\n\ntype AnyCanvas2DContext =\n\t| CanvasRenderingContext2D\n\t| OffscreenCanvasRenderingContext2D;\n\nfunction createRasterContext(\n\twidth: number,\n\theight: number,\n): AnyCanvas2DContext | null {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\tconst canvas = new OffscreenCanvas(width, height);\n\t\tconst context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\t\tif (context) return context;\n\t}\n\tif (typeof document !== \"undefined\") {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tcanvas.width = width;\n\t\tcanvas.height = height;\n\t\treturn canvas.getContext(\"2d\", { willReadFrequently: true });\n\t}\n\treturn null;\n}\n\nfunction worldToRaster(\n\tpoint: BrushStrokeCoordinate,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate {\n\treturn [\n\t\t(point[0] - config.minX) / config.step + config.padding,\n\t\t(point[1] - config.minY) / config.step + config.padding,\n\t];\n}\n\nfunction rasterizeStrokeMask(\n\tpath: BrushStrokeCoordinate[],\n\tradius: number,\n\tconfig: RasterConfig,\n): Uint8Array {\n\tconst context = createRasterContext(config.width, config.height);\n\tif (!context) return new Uint8Array(0);\n\n\tcontext.clearRect(0, 0, config.width, config.height);\n\tcontext.fillStyle = \"#ffffff\";\n\tcontext.strokeStyle = \"#ffffff\";\n\tcontext.lineCap = \"round\";\n\tcontext.lineJoin = \"round\";\n\tcontext.lineWidth = (radius * 2) / config.step;\n\n\tconst points = path.map(point => worldToRaster(point, config));\n\tif (points.length <= 1) {\n\t\tconst p = points[0];\n\t\tif (!p) return new Uint8Array(0);\n\t\tcontext.beginPath();\n\t\tcontext.arc(p[0], p[1], radius / config.step, 0, Math.PI * 2);\n\t\tcontext.fill();\n\t} else {\n\t\tcontext.beginPath();\n\t\tcontext.moveTo(points[0][0], points[0][1]);\n\t\tfor (let i = 1; i < points.length; i += 1) {\n\t\t\tcontext.lineTo(points[i][0], points[i][1]);\n\t\t}\n\t\tcontext.stroke();\n\t}\n\n\tconst image = context.getImageData(0, 0, config.width, config.height);\n\tconst out = new Uint8Array(config.width * config.height);\n\tfor (let i = 0; i < out.length; i += 1) {\n\t\tout[i] = image.data[i * 4 + 3] >= ALPHA_THRESHOLD ? 1 : 0;\n\t}\n\treturn out;\n}\n\nfunction buildBoundaryEdges(mask: Uint8Array, width: number, height: number): BoundaryEdge[] {\n\tconst edges: BoundaryEdge[] = [];\n\tconst stride = width + 1;\n\tconst vertex = (x: number, y: number): number => y * stride + x;\n\tconst at = (x: number, y: number): boolean =>\n\t\tx >= 0 && y >= 0 && x < width && y < height && mask[y * width + x] > 0;\n\n\tfor (let y = 0; y < height; y += 1) {\n\t\tfor (let x = 0; x < width; x += 1) {\n\t\t\tif (!at(x, y)) continue;\n\t\t\tif (!at(x, y - 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y),\n\t\t\t\t\tend: vertex(x + 1, y),\n\t\t\t\t\tdir: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x + 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y),\n\t\t\t\t\tend: vertex(x + 1, y + 1),\n\t\t\t\t\tdir: 1,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x, y + 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y + 1),\n\t\t\t\t\tend: vertex(x, y + 1),\n\t\t\t\t\tdir: 2,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x - 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y + 1),\n\t\t\t\t\tend: vertex(x, y),\n\t\t\t\t\tdir: 3,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn edges;\n}\n\nfunction turnPriority(fromDir: number, toDir: number): number {\n\tconst delta = (toDir - fromDir + 4) % 4;\n\tif (delta === 1) return 0; // right\n\tif (delta === 0) return 1; // straight\n\tif (delta === 3) return 2; // left\n\treturn 3; // reverse\n}\n\nfunction traceLoops(edges: BoundaryEdge[]): number[][] {\n\tif (!edges.length) return [];\n\n\tconst outgoing = new Map<number, number[]>();\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tconst entry = outgoing.get(edges[i].start);\n\t\tif (entry) {\n\t\t\tentry.push(i);\n\t\t} else {\n\t\t\toutgoing.set(edges[i].start, [i]);\n\t\t}\n\t}\n\n\tconst used = new Uint8Array(edges.length);\n\tconst loops: number[][] = [];\n\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tif (used[i]) continue;\n\n\t\tconst first = edges[i];\n\t\tconst startVertex = first.start;\n\t\tlet currentVertex = first.end;\n\t\tlet currentDir = first.dir;\n\t\tconst loop: number[] = [first.start, first.end];\n\t\tused[i] = 1;\n\n\t\tlet guard = 0;\n\t\tconst guardLimit = edges.length * 3;\n\t\twhile (currentVertex !== startVertex && guard < guardLimit) {\n\t\t\tconst candidates = outgoing.get(currentVertex);\n\t\t\tif (!candidates || candidates.length === 0) break;\n\n\t\t\tlet bestIndex = -1;\n\t\t\tlet bestPriority = Infinity;\n\t\t\tfor (const edgeIndex of candidates) {\n\t\t\t\tif (used[edgeIndex]) continue;\n\t\t\t\tconst candidate = edges[edgeIndex];\n\t\t\t\tconst priority = turnPriority(currentDir, candidate.dir);\n\t\t\t\tif (priority < bestPriority) {\n\t\t\t\t\tbestPriority = priority;\n\t\t\t\t\tbestIndex = edgeIndex;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bestIndex < 0) break;\n\t\t\tused[bestIndex] = 1;\n\t\t\tconst next = edges[bestIndex];\n\t\t\tcurrentVertex = next.end;\n\t\t\tcurrentDir = next.dir;\n\t\t\tloop.push(currentVertex);\n\t\t\tguard += 1;\n\t\t}\n\n\t\tif (\n\t\t\tloop.length >= 4 &&\n\t\t\tloop[0] === loop[loop.length - 1]\n\t\t) {\n\t\t\tloops.push(loop);\n\t\t}\n\t}\n\n\treturn loops;\n}\n\nfunction toWorldRing(\n\tvertexLoop: number[],\n\twidth: number,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate[] {\n\tconst stride = width + 1;\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (const id of vertexLoop) {\n\t\tconst x = id % stride;\n\t\tconst y = Math.floor(id / stride);\n\t\tring.push([\n\t\t\tconfig.minX + (x - config.padding) * config.step,\n\t\t\tconfig.minY + (y - config.padding) * config.step,\n\t\t]);\n\t}\n\treturn closeRing(ring);\n}\n\nfunction removeCollinearVertices(\n\tring: BrushStrokeCoordinate[],\n\tepsilon = 1e-9,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5) return closed;\n\tconst out: BrushStrokeCoordinate[] = [closed[0]];\n\tfor (let i = 1; i < closed.length - 1; i += 1) {\n\t\tconst prev = out[out.length - 1];\n\t\tconst curr = closed[i];\n\t\tconst next = closed[i + 1];\n\t\tconst cross =\n\t\t\t(curr[0] - prev[0]) * (next[1] - curr[1]) -\n\t\t\t(curr[1] - prev[1]) * (next[0] - curr[0]);\n\t\tif (Math.abs(cross) <= epsilon) continue;\n\t\tout.push(curr);\n\t}\n\tout.push(out[0]);\n\treturn closeRing(out);\n}\n\nfunction pointLineDistanceSquared(\n\tp: BrushStrokeCoordinate,\n\ta: BrushStrokeCoordinate,\n\tb: BrushStrokeCoordinate,\n): number {\n\tconst abx = b[0] - a[0];\n\tconst aby = b[1] - a[1];\n\tconst len2 = abx * abx + aby * aby;\n\tif (len2 <= 1e-12) {\n\t\tconst dx = p[0] - a[0];\n\t\tconst dy = p[1] - a[1];\n\t\treturn dx * dx + dy * dy;\n\t}\n\tconst t = clamp(\n\t\t((p[0] - a[0]) * abx + (p[1] - a[1]) * aby) / len2,\n\t\t0,\n\t\t1,\n\t);\n\tconst x = a[0] + abx * t;\n\tconst y = a[1] + aby * t;\n\tconst dx = p[0] - x;\n\tconst dy = p[1] - y;\n\treturn dx * dx + dy * dy;\n}\n\nfunction simplifyRdp(\n\tpoints: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tif (points.length <= 2 || tolerance <= 0) return points.slice();\n\n\tconst keep = new Uint8Array(points.length);\n\tkeep[0] = 1;\n\tkeep[points.length - 1] = 1;\n\tconst tolerance2 = tolerance * tolerance;\n\tconst stack: Array<[number, number]> = [[0, points.length - 1]];\n\n\twhile (stack.length > 0) {\n\t\tconst next = stack.pop();\n\t\tif (!next) break;\n\t\tconst [start, end] = next;\n\t\tif (end - start <= 1) continue;\n\n\t\tlet maxDist2 = 0;\n\t\tlet split = -1;\n\t\tfor (let i = start + 1; i < end; i += 1) {\n\t\t\tconst dist2 = pointLineDistanceSquared(points[i], points[start], points[end]);\n\t\t\tif (dist2 > maxDist2) {\n\t\t\t\tmaxDist2 = dist2;\n\t\t\t\tsplit = i;\n\t\t\t}\n\t\t}\n\n\t\tif (split >= 0 && maxDist2 > tolerance2) {\n\t\t\tkeep[split] = 1;\n\t\t\tstack.push([start, split], [split, end]);\n\t\t}\n\t}\n\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i < points.length; i += 1) {\n\t\tif (keep[i]) out.push(points[i]);\n\t}\n\treturn out;\n}\n\nfunction simplifyClosedRing(\n\tring: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5 || tolerance <= 0) return closed;\n\tconst open = closed.slice(0, -1);\n\tconst simplified = simplifyRdp(open, tolerance);\n\tif (simplified.length < 3) return closed;\n\treturn closeRing(simplified);\n}\n\nfunction smoothClosedRingChaikin(\n\tring: BrushStrokeCoordinate[],\n\titerations: number,\n): BrushStrokeCoordinate[] {\n\tlet out = closeRing(ring);\n\tif (iterations <= 0 || out.length < 5) return out;\n\n\tfor (let pass = 0; pass < iterations; pass += 1) {\n\t\tconst open = out.slice(0, -1);\n\t\tif (open.length < 3) break;\n\t\tconst next: BrushStrokeCoordinate[] = [];\n\t\tfor (let i = 0; i < open.length; i += 1) {\n\t\t\tconst a = open[i];\n\t\t\tconst b = open[(i + 1) % open.length];\n\t\t\tnext.push(\n\t\t\t\t[a[0] * 0.75 + b[0] * 0.25, a[1] * 0.75 + b[1] * 0.25],\n\t\t\t\t[a[0] * 0.25 + b[0] * 0.75, a[1] * 0.25 + b[1] * 0.75],\n\t\t\t);\n\t\t}\n\t\tout = closeRing(next);\n\t}\n\treturn out;\n}\n\nfunction clampRingToBounds(\n\tring: BrushStrokeCoordinate[],\n\tbounds: BrushStrokeBounds | undefined,\n): BrushStrokeCoordinate[] {\n\tif (!bounds) return ring;\n\treturn closeRing(\n\t\tring.map(([x, y]) => [\n\t\t\tclamp(x, bounds[0], bounds[2]),\n\t\t\tclamp(y, bounds[1], bounds[3]),\n\t\t] as BrushStrokeCoordinate),\n\t);\n}\n\nexport function buildBrushStrokePolygon(\n\tpath: BrushStrokeCoordinate[],\n\toptions: BrushStrokePolygonOptions,\n): BrushStrokeCoordinate[] {\n\tconst points = sanitizePath(path);\n\tconst radius = Math.max(MIN_RADIUS, Number(options.radius) || 0);\n\tif (points.length === 0 || !Number.isFinite(radius)) return [];\n\n\tconst circleSides = Math.max(12, Math.floor(options.circleSides || DEFAULT_CIRCLE_SIDES));\n\tif (points.length === 1) {\n\t\treturn clampRingToBounds(\n\t\t\tcreateCirclePolygon(points[0], radius, circleSides),\n\t\t\toptions.clipBounds,\n\t\t);\n\t}\n\n\tconst bounds = computeExpandedBounds(points, radius);\n\tconst raster = resolveRasterConfig(bounds, radius, options);\n\tconst mask = rasterizeStrokeMask(points, radius, raster);\n\tif (!mask.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst edges = buildBoundaryEdges(mask, raster.width, raster.height);\n\tconst loops = traceLoops(edges);\n\tif (!loops.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tlet bestRing: BrushStrokeCoordinate[] = [];\n\tlet bestArea = 0;\n\tfor (const loop of loops) {\n\t\tconst ring = toWorldRing(loop, raster.width, raster);\n\t\tconst area = Math.abs(polygonSignedArea(ring));\n\t\tif (area <= bestArea) continue;\n\t\tbestArea = area;\n\t\tbestRing = ring;\n\t}\n\n\tif (!bestRing.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst tolerance =\n\t\ttypeof options.simplifyTolerance === \"number\" && Number.isFinite(options.simplifyTolerance)\n\t\t\t? Math.max(0, options.simplifyTolerance)\n\t\t\t: raster.step * 0.2;\n\tconst smoothingPasses =\n\t\ttypeof options.smoothingPasses === \"number\" && Number.isFinite(options.smoothingPasses)\n\t\t\t? Math.round(clamp(options.smoothingPasses, 0, MAX_SMOOTHING_PASSES))\n\t\t\t: DEFAULT_SMOOTHING_PASSES;\n\tconst simplified = simplifyClosedRing(\n\t\tsmoothClosedRingChaikin(\n\t\t\tremoveCollinearVertices(bestRing, raster.step * 1e-3),\n\t\t\tsmoothingPasses,\n\t\t),\n\t\ttolerance,\n\t);\n\treturn clampRingToBounds(simplified, options.clipBounds);\n}\n","import type { CSSProperties, MutableRefObject, RefObject } from \"react\";\n\nexport type StampDrawTool =\n | \"stamp-rectangle\"\n | \"stamp-circle\"\n | \"stamp-rectangle-4096px\"\n | \"stamp-rectangle-2mm2\"\n | \"stamp-circle-2mm2\"\n | \"stamp-circle-hpf-0.2mm2\";\n\nexport type DrawTool = \"cursor\" | \"freehand\" | \"rectangle\" | \"circular\" | \"brush\" | StampDrawTool;\n\nexport type DrawCoordinate = [number, number];\n\nexport type DrawBounds = [number, number, number, number];\nexport type DrawRegionCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\n\nexport type DrawIntent = \"roi\" | \"patch\" | \"brush\";\n\nexport interface DrawResult {\n tool: Exclude<DrawTool, \"cursor\">;\n intent: DrawIntent;\n coordinates: DrawCoordinate[];\n bbox: DrawBounds;\n areaPx: number;\n}\n\nexport type PatchDrawResult = DrawResult & {\n tool: \"stamp-rectangle-4096px\";\n intent: \"patch\";\n};\n\nexport interface DrawRegion {\n id?: string | number;\n coordinates: DrawRegionCoordinates;\n label?: string;\n}\n\nexport interface RegionStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n state: \"default\" | \"hover\" | \"active\";\n}\n\nexport type RegionStrokeStyleResolver = (context: RegionStyleContext) => Partial<RegionStrokeStyle> | null | undefined;\n\nexport interface RegionLabelStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n zoom: number;\n}\n\nexport type RegionLabelStyleResolver = (context: RegionLabelStyleContext) => Partial<RegionLabelStyle> | null | undefined;\n\nexport type DrawOverlayCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\n\nexport interface DrawOverlayShape {\n id?: string | number;\n coordinates: DrawOverlayCoordinates;\n closed?: boolean;\n fill?: boolean;\n stroke?: Partial<RegionStrokeStyle>;\n strokeStyle?: Partial<RegionStrokeStyle>;\n invertedFill?: DrawOverlayInvertedFillStyle;\n visible?: boolean;\n}\n\nexport interface DrawOverlayInvertedFillStyle {\n fillColor: string;\n}\n\nexport interface RegionStrokeStyle {\n color: string;\n width: number;\n lineDash: number[];\n lineJoin: CanvasLineJoin;\n lineCap: CanvasLineCap;\n shadowColor: string;\n shadowBlur: number;\n shadowOffsetX: number;\n shadowOffsetY: number;\n}\n\nexport interface RegionLabelStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderColor: string;\n borderWidth: number;\n paddingX: number;\n paddingY: number;\n offsetY: number;\n borderRadius: number;\n}\n\nexport interface DrawAreaTooltipStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderRadius: number;\n paddingX: number;\n paddingY: number;\n}\n\nexport interface DrawAreaTooltipOptions {\n enabled?: boolean;\n format?: (areaMm2: number) => string;\n style?: Partial<DrawAreaTooltipStyle>;\n cursorOffset?: {\n x: number;\n y: number;\n };\n}\n\nexport interface DrawProjector {\n screenToWorld(clientX: number, clientY: number): DrawCoordinate | number[];\n worldToScreen(worldX: number, worldY: number): DrawCoordinate | number[];\n getViewState?: () => { zoom: number; rotationDeg?: number };\n getZoomRange?: () => { minZoom: number; maxZoom: number };\n zoomBy?: (factor: number, screenX: number, screenY: number) => void;\n}\n\nexport interface StampOptions {\n rectangleAreaMm2?: number;\n circleAreaMm2?: number;\n rectanglePixelSize?: number;\n}\n\nexport interface BrushOptions {\n radius: number;\n edgeDetail?: number;\n edgeSmoothing?: number;\n clickSelectRoi?: boolean;\n fillColor?: string;\n fillOpacity?: number;\n cursorColor?: string;\n cursorActiveColor?: string;\n cursorLineWidth?: number;\n cursorLineDash?: number[];\n}\n\nexport interface DrawLayerProps {\n tool: DrawTool;\n imageWidth: number;\n imageHeight: number;\n imageMpp?: number;\n imageZoom?: number;\n stampOptions?: StampOptions;\n brushOptions?: BrushOptions;\n projectorRef: RefObject<DrawProjector | null>;\n onBrushTap?: (coordinate: DrawCoordinate) => boolean;\n onDrawComplete?: (result: DrawResult) => void;\n onPatchComplete?: (result: PatchDrawResult) => void;\n enabled?: boolean;\n viewStateSignal?: unknown;\n persistedRegions?: DrawRegion[];\n patchRegions?: DrawRegion[];\n persistedPolygons?: DrawRegionCoordinates[];\n drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n hoveredRegionId?: string | number | null;\n activeRegionId?: string | number | null;\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\n regionLabelAutoLiftOffsetPx?: number;\n invalidateRef?: MutableRefObject<(() => void) | null>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport interface DrawSession {\n isDrawing: boolean;\n pointerId: number | null;\n start: DrawCoordinate | null;\n current: DrawCoordinate | null;\n cursor: DrawCoordinate | null;\n cursorScreen: DrawCoordinate | null;\n points: DrawCoordinate[];\n screenPoints: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\nexport interface NormalizedDrawRegionPolygon {\n outer: DrawCoordinate[];\n holes: DrawCoordinate[][];\n}\n\nexport interface PreparedRenderedRegion {\n region: DrawRegion;\n regionIndex: number;\n regionKey: string | number;\n polygons: NormalizedDrawRegionPolygon[];\n}\n\nexport interface ResolvedBrushOptions {\n radius: number;\n edgeDetail: number;\n edgeSmoothing: number;\n clickSelectRoi: boolean;\n fillColor: string;\n fillOpacity: number;\n cursorColor: string;\n cursorActiveColor: string;\n cursorLineWidth: number;\n cursorLineDash: number[];\n}\n\nexport interface ResolvedDrawAreaTooltipOptions {\n enabled: boolean;\n format: (areaMm2: number) => string;\n style: DrawAreaTooltipStyle;\n cursorOffsetX: number;\n cursorOffsetY: number;\n}\n\nexport const EMPTY_DASH: number[] = [];\nexport const EMPTY_REGIONS: DrawRegion[] = [];\n\nexport const DEFAULT_REGION_STROKE_STYLE: RegionStrokeStyle = {\n color: \"#ff4d4f\",\n width: 2,\n lineDash: EMPTY_DASH,\n lineJoin: \"round\",\n lineCap: \"round\",\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n};\n\nexport const DEFAULT_PATCH_STROKE_STYLE: RegionStrokeStyle = {\n color: \"#4cc9f0\",\n width: 2,\n lineDash: [10, 8],\n lineJoin: \"round\",\n lineCap: \"round\",\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n};\n\nexport const REGION_INTERACTION_SHADOW_COLOR = \"rgba(23, 23, 25, 0.1)\";\nexport const REGION_INTERACTION_SHADOW_WIDTH = 6;\n\nexport const DEFAULT_REGION_LABEL_STYLE: RegionLabelStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 11,\n fontWeight: 600,\n textColor: \"#171719\",\n backgroundColor: \"#FFCC00\",\n borderColor: \"rgba(0, 0, 0, 0)\",\n borderWidth: 0,\n paddingX: 8,\n paddingY: 4,\n offsetY: 10,\n borderRadius: 4,\n};\n\nexport const DEFAULT_DRAW_AREA_TOOLTIP_STYLE: DrawAreaTooltipStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 13,\n fontWeight: 500,\n textColor: \"#FFFFFF\",\n backgroundColor: \"rgba(23, 23, 25, 0.5)\",\n borderRadius: 4,\n paddingX: 6,\n paddingY: 3,\n};\n\nexport const DEFAULT_DRAW_AREA_TOOLTIP_OFFSET = {\n x: 16,\n y: -24,\n} as const;\n\nexport const REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\nexport const REGION_LABEL_AUTO_LIFT_MAX_EPSILON = 1e-6;\n\nexport const DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nexport const DEFAULT_DRAW_PREVIEW_FILL = \"transparent\";\nexport const FREEHAND_MIN_POINTS = 3;\nexport const FREEHAND_SCREEN_STEP = 2;\nexport const CIRCLE_SIDES = 96;\nexport const MIN_AREA_PX = 1;\nexport const MICRONS_PER_MM = 1000;\nexport const DEFAULT_STAMP_RECTANGLE_AREA_MM2 = 2;\nexport const DEFAULT_STAMP_CIRCLE_AREA_MM2 = 2;\nexport const DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE = 4096;\nexport const LEGACY_HPF_CIRCLE_AREA_MM2 = 0.2;\nexport const WHEEL_ZOOM_IN_FACTOR = 1.12;\nexport const WHEEL_ZOOM_OUT_FACTOR = 0.89;\nexport const DEFAULT_BRUSH_RADIUS = 32;\nexport const DEFAULT_BRUSH_FILL_COLOR = \"#000000\";\nexport const DEFAULT_BRUSH_FILL_OPACITY = 0.1;\nexport const DEFAULT_BRUSH_CURSOR_COLOR = \"#FFCF00\";\nexport const DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR = \"#FF0000\";\nexport const DEFAULT_BRUSH_CURSOR_LINE_WIDTH = 1.5;\nexport const DEFAULT_BRUSH_CURSOR_DASH = [2, 2];\nexport const DEFAULT_BRUSH_EDGE_DETAIL = 1;\nexport const MIN_BRUSH_EDGE_DETAIL = 0.25;\nexport const MAX_BRUSH_EDGE_DETAIL = 4;\nexport const DEFAULT_BRUSH_EDGE_SMOOTHING = 1;\nexport const MIN_BRUSH_EDGE_SMOOTHING = 0;\nexport const MAX_BRUSH_EDGE_SMOOTHING = 4;\nexport const MIN_BRUSH_RASTER_STEP = 0.05;\nexport const BRUSH_RASTER_DIAMETER_SAMPLES = 256;\nexport const BRUSH_SCREEN_STEP = 1.5;\n","import { closeRoiRing, normalizeRoiGeometry, polygonSignedArea, toRoiGeometry } from \"../wsi/roi-geometry\";\nimport { clamp } from \"../wsi/utils\";\nimport type { DrawCoordinate, DrawOverlayCoordinates, DrawRegionCoordinates, NormalizedDrawRegionPolygon, RegionStrokeStyle } from \"./draw-layer-types\";\nimport { CIRCLE_SIDES, DEFAULT_REGION_STROKE_STYLE, type DrawBounds, EMPTY_DASH } from \"./draw-layer-types\";\n\nexport { clamp };\n\nexport function clampWorld(coord: DrawCoordinate, imageWidth: number, imageHeight: number): DrawCoordinate {\n return [clamp(coord[0], 0, imageWidth), clamp(coord[1], 0, imageHeight)];\n}\n\nexport function toDrawCoordinate(value: unknown): DrawCoordinate | null {\n if (!Array.isArray(value) || value.length < 2) return null;\n const x = Number(value[0]);\n const y = Number(value[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n}\n\nexport const toCoord = toDrawCoordinate;\n\nexport function closeRing(coords: DrawCoordinate[]): DrawCoordinate[] {\n return closeRoiRing(coords) as DrawCoordinate[];\n}\n\nexport function polygonArea(coords: DrawCoordinate[]): number {\n return Math.abs(polygonSignedArea(closeRing(coords)));\n}\n\nexport function computeBounds(coords: DrawCoordinate[]): DrawBounds {\n if (!Array.isArray(coords) || coords.length === 0) return [0, 0, 0, 0];\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const [x, y] of coords) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n\n return [minX, minY, maxX, maxY];\n}\n\nexport function tracePath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], close = false): void {\n if (points.length === 0) return;\n\n ctx.moveTo(points[0][0], points[0][1]);\n for (let i = 1; i < points.length; i += 1) {\n ctx.lineTo(points[i][0], points[i][1]);\n }\n\n if (close) {\n ctx.closePath();\n }\n}\n\nexport function drawPath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], strokeStyle: RegionStrokeStyle, close = false, fill = false, fillColor = \"rgba(255, 77, 79, 0.16)\"): void {\n if (points.length === 0) return;\n\n ctx.beginPath();\n tracePath(ctx, points, close);\n if (fill && close) {\n ctx.fillStyle = fillColor;\n ctx.fill();\n }\n\n ctx.strokeStyle = strokeStyle.color;\n ctx.lineWidth = strokeStyle.width;\n ctx.lineJoin = strokeStyle.lineJoin;\n ctx.lineCap = strokeStyle.lineCap;\n ctx.shadowColor = strokeStyle.shadowColor;\n ctx.shadowBlur = strokeStyle.shadowBlur;\n ctx.shadowOffsetX = strokeStyle.shadowOffsetX;\n ctx.shadowOffsetY = strokeStyle.shadowOffsetY;\n ctx.setLineDash(strokeStyle.lineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.shadowColor = \"rgba(0, 0, 0, 0)\";\n ctx.shadowBlur = 0;\n ctx.shadowOffsetX = 0;\n ctx.shadowOffsetY = 0;\n}\n\nexport function resolveStrokeStyle(style: Partial<RegionStrokeStyle> | undefined): RegionStrokeStyle {\n const dash = Array.isArray(style?.lineDash) ? style.lineDash.filter(value => Number.isFinite(value) && value >= 0) : EMPTY_DASH;\n const width = typeof style?.width === \"number\" && Number.isFinite(style.width) ? Math.max(0, style.width) : DEFAULT_REGION_STROKE_STYLE.width;\n const shadowBlur = typeof style?.shadowBlur === \"number\" && Number.isFinite(style.shadowBlur) ? Math.max(0, style.shadowBlur) : DEFAULT_REGION_STROKE_STYLE.shadowBlur;\n const shadowOffsetX = typeof style?.shadowOffsetX === \"number\" && Number.isFinite(style.shadowOffsetX) ? style.shadowOffsetX : DEFAULT_REGION_STROKE_STYLE.shadowOffsetX;\n const shadowOffsetY = typeof style?.shadowOffsetY === \"number\" && Number.isFinite(style.shadowOffsetY) ? style.shadowOffsetY : DEFAULT_REGION_STROKE_STYLE.shadowOffsetY;\n return {\n color: style?.color || DEFAULT_REGION_STROKE_STYLE.color,\n width,\n lineDash: dash.length ? dash : EMPTY_DASH,\n lineJoin: style?.lineJoin || DEFAULT_REGION_STROKE_STYLE.lineJoin,\n lineCap: style?.lineCap || DEFAULT_REGION_STROKE_STYLE.lineCap,\n shadowColor: style?.shadowColor || DEFAULT_REGION_STROKE_STYLE.shadowColor,\n shadowBlur,\n shadowOffsetX,\n shadowOffsetY,\n };\n}\n\nexport function mergeStrokeStyle(base: RegionStrokeStyle, override: Partial<RegionStrokeStyle> | undefined): RegionStrokeStyle {\n if (!override) return base;\n return resolveStrokeStyle({\n color: override.color ?? base.color,\n width: override.width ?? base.width,\n lineDash: override.lineDash ?? base.lineDash,\n lineJoin: override.lineJoin ?? base.lineJoin,\n lineCap: override.lineCap ?? base.lineCap,\n shadowColor: override.shadowColor ?? base.shadowColor,\n shadowBlur: override.shadowBlur ?? base.shadowBlur,\n shadowOffsetX: override.shadowOffsetX ?? base.shadowOffsetX,\n shadowOffsetY: override.shadowOffsetY ?? base.shadowOffsetY,\n });\n}\n\nexport function isSameRegionId(a: string | number | null | undefined, b: string | number | null | undefined): boolean {\n if (a === null || a === undefined || b === null || b === undefined) {\n return false;\n }\n return String(a) === String(b);\n}\n\nexport function isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nexport function isCoordinatePair(value: unknown): value is [number, number] {\n return Array.isArray(value) && value.length >= 2 && isFiniteNumber(value[0]) && isFiniteNumber(value[1]);\n}\n\nexport function isCoordinateRing(value: unknown): value is DrawCoordinate[] {\n return Array.isArray(value) && value.length >= 2 && value.every(point => isCoordinatePair(point));\n}\n\nfunction collectOverlayRings(value: unknown, out: DrawCoordinate[][]): void {\n if (!Array.isArray(value) || value.length === 0) return;\n if (isCoordinateRing(value)) {\n out.push(value.map(([x, y]) => [x, y] as DrawCoordinate));\n return;\n }\n for (const item of value) {\n collectOverlayRings(item, out);\n }\n}\n\nexport function normalizeOverlayRings(coordinates: DrawOverlayCoordinates, close: boolean): DrawCoordinate[][] {\n const sourceRings: DrawCoordinate[][] = [];\n collectOverlayRings(coordinates, sourceRings);\n const out: DrawCoordinate[][] = [];\n for (const ring of sourceRings) {\n if (ring.length < 2) continue;\n const normalized = close ? closeRing(ring) : ring;\n if (normalized.length >= (close ? 4 : 2)) {\n out.push(normalized);\n }\n }\n return out;\n}\n\nexport function clampPositiveOrFallback(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n return fallback;\n }\n return value;\n}\n\nexport function clampUnitOpacity(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return clamp(value, 0, 1);\n}\n\nexport function drawRoundedRect(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number): void {\n const r = Math.max(0, Math.min(radius, width * 0.5, height * 0.5));\n ctx.beginPath();\n ctx.moveTo(x + r, y);\n ctx.lineTo(x + width - r, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + r);\n ctx.lineTo(x + width, y + height - r);\n ctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height);\n ctx.lineTo(x + r, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - r);\n ctx.lineTo(x, y + r);\n ctx.quadraticCurveTo(x, y, x + r, y);\n ctx.closePath();\n}\n\nexport function isNestedRingCoordinates(coordinates: DrawOverlayCoordinates): boolean {\n const first = coordinates[0];\n return Array.isArray(first) && Array.isArray(first[0]);\n}\n\nexport function createRectangle(\n start: DrawCoordinate | null,\n end: DrawCoordinate | null,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n }\n): DrawCoordinate[] {\n if (!start || !end) return [];\n\n if (projection) {\n const startScreen = projection.worldToScreen(start[0], start[1]);\n const endScreen = projection.worldToScreen(end[0], end[1]);\n\n if (startScreen && endScreen) {\n const screenCorners: DrawCoordinate[] = [\n [startScreen[0], startScreen[1]],\n [endScreen[0], startScreen[1]],\n [endScreen[0], endScreen[1]],\n [startScreen[0], endScreen[1]],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) return createRectangle(start, end);\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\n\n return closeRing([\n [start[0], start[1]],\n [end[0], start[1]],\n [end[0], end[1]],\n [start[0], end[1]],\n ]);\n}\n\nexport function createCircle(start: DrawCoordinate | null, end: DrawCoordinate | null, sides = CIRCLE_SIDES): DrawCoordinate[] {\n if (!start || !end) return [];\n\n const centerX = (start[0] + end[0]) * 0.5;\n const centerY = (start[1] + end[1]) * 0.5;\n const radius = Math.hypot(end[0] - start[0], end[1] - start[1]) * 0.5;\n if (radius < 1) return [];\n\n const coords: DrawCoordinate[] = [];\n for (let i = 0; i <= sides; i += 1) {\n const t = (i / sides) * Math.PI * 2;\n coords.push([centerX + Math.cos(t) * radius, centerY + Math.sin(t) * radius]);\n }\n\n return closeRing(coords);\n}\n\nexport function normalizeDrawRegionPolygons(coordinates: DrawRegionCoordinates): NormalizedDrawRegionPolygon[] {\n const multipolygon = normalizeRoiGeometry(toRoiGeometry(coordinates));\n if (multipolygon.length === 0) return [];\n\n const out: NormalizedDrawRegionPolygon[] = [];\n for (const polygon of multipolygon) {\n const outer = polygon[0];\n if (!outer || outer.length < 4) continue;\n const normalizedOuter = outer.map(([x, y]) => [x, y] as DrawCoordinate);\n const holes: DrawCoordinate[][] = [];\n for (let i = 1; i < polygon.length; i += 1) {\n const hole = polygon[i];\n if (!hole || hole.length < 4) continue;\n holes.push(hole.map(([x, y]) => [x, y] as DrawCoordinate));\n }\n out.push({\n outer: normalizedOuter,\n holes,\n });\n }\n return out;\n}\n","import type { BrushOptions, DrawCoordinate, DrawProjector, DrawSession, ResolvedBrushOptions } from \"./draw-layer-types\";\nimport {\n DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR,\n DEFAULT_BRUSH_CURSOR_COLOR,\n DEFAULT_BRUSH_CURSOR_DASH,\n DEFAULT_BRUSH_CURSOR_LINE_WIDTH,\n DEFAULT_BRUSH_EDGE_DETAIL,\n DEFAULT_BRUSH_EDGE_SMOOTHING,\n DEFAULT_BRUSH_FILL_COLOR,\n DEFAULT_BRUSH_FILL_OPACITY,\n DEFAULT_BRUSH_RADIUS,\n EMPTY_DASH,\n MAX_BRUSH_EDGE_DETAIL,\n MAX_BRUSH_EDGE_SMOOTHING,\n MIN_BRUSH_EDGE_DETAIL,\n MIN_BRUSH_EDGE_SMOOTHING,\n} from \"./draw-layer-types\";\nimport { clamp, clampPositiveOrFallback, clampUnitOpacity, toCoord } from \"./draw-layer-utils\";\n\nexport type { BrushOptions, ResolvedBrushOptions };\n\nexport function sanitizeBrushLineDash(value: number[] | undefined): number[] {\n if (!Array.isArray(value)) return DEFAULT_BRUSH_CURSOR_DASH;\n const out = value.filter(item => Number.isFinite(item) && item >= 0);\n return out.length > 0 ? out : DEFAULT_BRUSH_CURSOR_DASH;\n}\n\nexport function resolveBrushEdgeDetail(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_DETAIL;\n return clamp(value, MIN_BRUSH_EDGE_DETAIL, MAX_BRUSH_EDGE_DETAIL);\n}\n\nexport function resolveBrushEdgeSmoothing(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_SMOOTHING;\n return Math.round(clamp(value, MIN_BRUSH_EDGE_SMOOTHING, MAX_BRUSH_EDGE_SMOOTHING));\n}\n\nexport function resolveBrushOptions(options: BrushOptions | undefined): ResolvedBrushOptions {\n const radius = clampPositiveOrFallback(options?.radius, DEFAULT_BRUSH_RADIUS);\n const cursorLineWidth = clampPositiveOrFallback(options?.cursorLineWidth, DEFAULT_BRUSH_CURSOR_LINE_WIDTH);\n const edgeDetail = resolveBrushEdgeDetail(options?.edgeDetail);\n const edgeSmoothing = resolveBrushEdgeSmoothing(options?.edgeSmoothing);\n return {\n radius,\n edgeDetail,\n edgeSmoothing,\n clickSelectRoi: options?.clickSelectRoi === true,\n fillColor: options?.fillColor || DEFAULT_BRUSH_FILL_COLOR,\n fillOpacity: clampUnitOpacity(options?.fillOpacity, DEFAULT_BRUSH_FILL_OPACITY),\n cursorColor: options?.cursorColor || DEFAULT_BRUSH_CURSOR_COLOR,\n cursorActiveColor: options?.cursorActiveColor || DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR,\n cursorLineWidth,\n cursorLineDash: sanitizeBrushLineDash(options?.cursorLineDash),\n };\n}\n\nexport function drawBrushStrokePreview(ctx: CanvasRenderingContext2D, session: DrawSession, resolvedBrushOptions: ResolvedBrushOptions): void {\n if (!session.isDrawing || session.screenPoints.length === 0) return;\n const screenPoints = session.screenPoints;\n if (screenPoints.length === 0) return;\n const radiusPx = resolvedBrushOptions.radius;\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.globalAlpha = resolvedBrushOptions.fillOpacity;\n ctx.fillStyle = resolvedBrushOptions.fillColor;\n ctx.strokeStyle = resolvedBrushOptions.fillColor;\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n ctx.lineWidth = radiusPx * 2;\n if (screenPoints.length === 1) {\n ctx.beginPath();\n ctx.arc(screenPoints[0][0], screenPoints[0][1], radiusPx, 0, Math.PI * 2);\n ctx.fill();\n } else {\n ctx.beginPath();\n ctx.moveTo(screenPoints[0][0], screenPoints[0][1]);\n for (let i = 1; i < screenPoints.length; i += 1) {\n ctx.lineTo(screenPoints[i][0], screenPoints[i][1]);\n }\n ctx.stroke();\n }\n ctx.restore();\n}\n\nexport function drawBrushCursor(ctx: CanvasRenderingContext2D, session: DrawSession, projector: DrawProjector | null, resolvedBrushOptions: ResolvedBrushOptions): void {\n const cursor = session.cursor;\n if (!cursor) return;\n const screen = session.cursorScreen ?? toCoord(projector?.worldToScreen(cursor[0], cursor[1]) ?? []);\n if (!screen) return;\n const radiusPx = resolvedBrushOptions.radius;\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.beginPath();\n ctx.arc(screen[0], screen[1], radiusPx, 0, Math.PI * 2);\n ctx.strokeStyle = session.isDrawing ? resolvedBrushOptions.cursorActiveColor : resolvedBrushOptions.cursorColor;\n ctx.lineWidth = resolvedBrushOptions.cursorLineWidth;\n ctx.setLineDash(resolvedBrushOptions.cursorLineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.restore();\n}\n","import type { DrawAreaTooltipOptions, DrawAreaTooltipStyle, DrawCoordinate, RegionLabelStyle, ResolvedDrawAreaTooltipOptions } from \"./draw-layer-types\";\nimport {\n DEFAULT_DRAW_AREA_TOOLTIP_OFFSET,\n DEFAULT_DRAW_AREA_TOOLTIP_STYLE,\n DEFAULT_REGION_LABEL_STYLE,\n REGION_LABEL_AUTO_LIFT_MAX_EPSILON,\n REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX,\n} from \"./draw-layer-types\";\nimport { clamp, drawRoundedRect } from \"./draw-layer-utils\";\n\nconst LABEL_MEASURE_FALLBACK_EM = 0.58;\nconst LABEL_MEASURE_CACHE_LIMIT = 4096;\nconst TOP_ANCHOR_Y_TOLERANCE = 0.5;\n\nlet sharedLabelMeasureContext: CanvasRenderingContext2D | null = null;\nconst labelTextWidthCache = new Map<string, number>();\n\nfunction getLabelMeasureContext(): CanvasRenderingContext2D | null {\n if (sharedLabelMeasureContext) return sharedLabelMeasureContext;\n if (typeof document === \"undefined\") return null;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n sharedLabelMeasureContext = ctx;\n return sharedLabelMeasureContext;\n}\n\nexport function measureLabelTextWidth(label: string, labelStyle: { fontFamily: string; fontSize: number; fontWeight: string | number }): number {\n const key = `${labelStyle.fontWeight}|${labelStyle.fontSize}|${labelStyle.fontFamily}|${label}`;\n const cached = labelTextWidthCache.get(key);\n if (cached !== undefined) return cached;\n\n const fallback = label.length * labelStyle.fontSize * LABEL_MEASURE_FALLBACK_EM;\n const ctx = getLabelMeasureContext();\n let width = fallback;\n if (ctx) {\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n const measured = ctx.measureText(label).width;\n if (Number.isFinite(measured) && measured >= 0) {\n width = measured;\n }\n }\n\n if (labelTextWidthCache.size > LABEL_MEASURE_CACHE_LIMIT) {\n labelTextWidthCache.clear();\n }\n labelTextWidthCache.set(key, width);\n return width;\n}\n\nexport function getTopAnchor(coords: DrawCoordinate[]): DrawCoordinate | null {\n if (!coords.length) return null;\n\n let minY = Infinity;\n for (const point of coords) {\n if (point[1] < minY) minY = point[1];\n }\n if (!Number.isFinite(minY)) return null;\n\n let minX = Infinity;\n let maxX = -Infinity;\n for (const point of coords) {\n if (Math.abs(point[1] - minY) > TOP_ANCHOR_Y_TOLERANCE) continue;\n if (point[0] < minX) minX = point[0];\n if (point[0] > maxX) maxX = point[0];\n }\n\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n return [(minX + maxX) * 0.5, minY];\n}\n\nexport function getTopAnchorFromPolygons<T extends { outer: DrawCoordinate[] }>(polygons: T[]): DrawCoordinate | null {\n let best: DrawCoordinate | null = null;\n for (const polygon of polygons) {\n const anchor = getTopAnchor(polygon.outer);\n if (!anchor) continue;\n if (!best || anchor[1] < best[1] || (anchor[1] === best[1] && anchor[0] < best[0])) {\n best = anchor;\n }\n }\n return best;\n}\n\nexport function resolveRegionLabelStyle(style: Partial<RegionLabelStyle> | undefined): RegionLabelStyle {\n const px = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_REGION_LABEL_STYLE.paddingX;\n const py = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_REGION_LABEL_STYLE.paddingY;\n const fs = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_REGION_LABEL_STYLE.fontSize;\n const bw = typeof style?.borderWidth === \"number\" && Number.isFinite(style.borderWidth) ? Math.max(0, style.borderWidth) : DEFAULT_REGION_LABEL_STYLE.borderWidth;\n const oy = typeof style?.offsetY === \"number\" && Number.isFinite(style.offsetY) ? style.offsetY : DEFAULT_REGION_LABEL_STYLE.offsetY;\n const br = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_REGION_LABEL_STYLE.borderRadius;\n return {\n fontFamily: style?.fontFamily || DEFAULT_REGION_LABEL_STYLE.fontFamily,\n fontSize: fs,\n fontWeight: style?.fontWeight || DEFAULT_REGION_LABEL_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_REGION_LABEL_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_REGION_LABEL_STYLE.backgroundColor,\n borderColor: style?.borderColor || DEFAULT_REGION_LABEL_STYLE.borderColor,\n borderWidth: bw,\n paddingX: px,\n paddingY: py,\n offsetY: oy,\n borderRadius: br,\n };\n}\n\nexport function mergeRegionLabelStyle(base: RegionLabelStyle, override: Partial<RegionLabelStyle> | null | undefined): RegionLabelStyle {\n if (!override) return base;\n return resolveRegionLabelStyle({\n fontFamily: override.fontFamily ?? base.fontFamily,\n fontSize: override.fontSize ?? base.fontSize,\n fontWeight: override.fontWeight ?? base.fontWeight,\n textColor: override.textColor ?? base.textColor,\n backgroundColor: override.backgroundColor ?? base.backgroundColor,\n borderColor: override.borderColor ?? base.borderColor,\n borderWidth: override.borderWidth ?? base.borderWidth,\n paddingX: override.paddingX ?? base.paddingX,\n paddingY: override.paddingY ?? base.paddingY,\n offsetY: override.offsetY ?? base.offsetY,\n borderRadius: override.borderRadius ?? base.borderRadius,\n });\n}\n\nexport function resolveRegionLabelAutoLiftOffsetPx(enabled: boolean | undefined, zoom: number, zoomRange: { minZoom: number; maxZoom: number } | null | undefined): number {\n if (!enabled) return 0;\n if (!zoomRange) return 0;\n\n const minZoom = Number(zoomRange.minZoom);\n const maxZoom = Number(zoomRange.maxZoom);\n if (!Number.isFinite(minZoom) || !Number.isFinite(maxZoom)) return 0;\n\n if (maxZoom - minZoom <= REGION_LABEL_AUTO_LIFT_MAX_EPSILON) return 0;\n if (!Number.isFinite(zoom)) return 0;\n return zoom >= maxZoom - REGION_LABEL_AUTO_LIFT_MAX_EPSILON ? REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX : 0;\n}\n\nfunction resolveDrawAreaTooltipStyle(style: Partial<DrawAreaTooltipStyle> | undefined): DrawAreaTooltipStyle {\n const fontSize = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontSize;\n const borderRadius = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.borderRadius;\n const paddingX = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingX;\n const paddingY = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingY;\n return {\n fontFamily: style?.fontFamily || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontFamily,\n fontSize,\n fontWeight: style?.fontWeight || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.backgroundColor,\n borderRadius,\n paddingX,\n paddingY,\n };\n}\n\nfunction resolveTooltipCursorOffset(value: DrawAreaTooltipOptions[\"cursorOffset\"]): { x: number; y: number } {\n const x = typeof value?.x === \"number\" && Number.isFinite(value.x) ? value.x : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.x;\n const y = typeof value?.y === \"number\" && Number.isFinite(value.y) ? value.y : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.y;\n return { x, y };\n}\n\nexport function defaultDrawAreaTooltipFormatter(areaMm2: number): string {\n if (!Number.isFinite(areaMm2)) return \"0.000 mm²\";\n return `${Math.max(0, areaMm2).toFixed(3)} mm²`;\n}\n\nexport function resolveDrawAreaTooltipOptions(options: DrawAreaTooltipOptions | undefined): ResolvedDrawAreaTooltipOptions {\n const format = typeof options?.format === \"function\" ? options.format : defaultDrawAreaTooltipFormatter;\n const cursorOffset = resolveTooltipCursorOffset(options?.cursorOffset);\n return {\n enabled: options?.enabled === true,\n format,\n style: resolveDrawAreaTooltipStyle(options?.style),\n cursorOffsetX: cursorOffset.x,\n cursorOffsetY: cursorOffset.y,\n };\n}\n\nexport function drawRegionLabel(ctx: CanvasRenderingContext2D, text: string, anchor: DrawCoordinate, canvasWidth: number, canvasHeight: number, labelStyle: RegionLabelStyle): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = measureLabelTextWidth(label, labelStyle);\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const x = clamp(anchor[0], boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(anchor[1] - labelStyle.offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n\n ctx.fillStyle = labelStyle.backgroundColor;\n ctx.strokeStyle = labelStyle.borderColor;\n ctx.lineWidth = labelStyle.borderWidth;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, labelStyle.borderRadius);\n ctx.fill();\n if (labelStyle.borderWidth > 0) {\n ctx.stroke();\n }\n\n ctx.fillStyle = labelStyle.textColor;\n ctx.fillText(label, x, y + 0.5);\n ctx.restore();\n}\n\nexport function drawAreaTooltipBox(\n ctx: CanvasRenderingContext2D,\n text: string,\n cursorScreen: DrawCoordinate,\n canvasWidth: number,\n canvasHeight: number,\n style: DrawAreaTooltipStyle,\n offsetX: number,\n offsetY: number\n): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = measureLabelTextWidth(label, style);\n const boxWidth = textWidth + style.paddingX * 2;\n const boxHeight = style.fontSize + style.paddingY * 2;\n\n const x = clamp(cursorScreen[0] + offsetX, boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(cursorScreen[1] + offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n\n ctx.fillStyle = style.backgroundColor;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, style.borderRadius);\n ctx.fill();\n\n ctx.fillStyle = style.textColor;\n ctx.fillText(label, x, y + 0.5);\n ctx.restore();\n}\n","import type { DrawCoordinate, DrawOverlayShape, RegionStrokeStyle } from \"./draw-layer-types\";\nimport { drawPath, isNestedRingCoordinates, mergeStrokeStyle, normalizeOverlayRings, tracePath } from \"./draw-layer-utils\";\n\nexport function drawInvertedFillMask(ctx: CanvasRenderingContext2D, outerRing: DrawCoordinate[], holeRings: DrawCoordinate[][], fillColor: string): void {\n if (outerRing.length < 4 || holeRings.length === 0) return;\n ctx.save();\n ctx.beginPath();\n tracePath(ctx, outerRing, true);\n for (const ring of holeRings) {\n if (ring.length < 4) continue;\n tracePath(ctx, ring, true);\n }\n ctx.fillStyle = fillColor;\n ctx.fill(\"evenodd\");\n ctx.restore();\n}\n\nexport interface DrawOverlayShapesParams {\n ctx: CanvasRenderingContext2D;\n overlayShapes: DrawOverlayShape[];\n imageOuterRing: DrawCoordinate[];\n worldToScreenPoints: (points: DrawCoordinate[]) => DrawCoordinate[];\n baseStrokeStyle: RegionStrokeStyle;\n onInvertedFillDebug?: (info: { id: string | number; outerRingPoints: number; sourceRingCount: number; holeRingCount: number; fillColor: string }) => void;\n}\n\nexport function drawOverlayShapes(params: DrawOverlayShapesParams): void {\n const { ctx, overlayShapes, imageOuterRing, worldToScreenPoints, baseStrokeStyle, onInvertedFillDebug } = params;\n\n const debugOverlay = Boolean((globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__);\n\n for (let i = 0; i < overlayShapes.length; i += 1) {\n const shape = overlayShapes[i];\n if (!shape?.coordinates?.length || shape.visible === false) continue;\n\n const closed = shape.closed ?? isNestedRingCoordinates(shape.coordinates);\n const renderRings = normalizeOverlayRings(shape.coordinates, closed);\n\n if (shape.invertedFill?.fillColor) {\n const holeRings: DrawCoordinate[][] = [];\n const closedRings = normalizeOverlayRings(shape.coordinates, true);\n for (const ring of closedRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length >= 4) {\n holeRings.push(screen);\n }\n }\n if (debugOverlay && onInvertedFillDebug) {\n onInvertedFillDebug({\n id: shape.id ?? i,\n outerRingPoints: imageOuterRing.length,\n sourceRingCount: closedRings.length,\n holeRingCount: holeRings.length,\n fillColor: shape.invertedFill.fillColor,\n });\n }\n drawInvertedFillMask(ctx, imageOuterRing, holeRings, shape.invertedFill.fillColor);\n }\n\n if (renderRings.length === 0) continue;\n const strokeStyle = mergeStrokeStyle(baseStrokeStyle, shape.stroke ?? shape.strokeStyle);\n for (const ring of renderRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length < 2) continue;\n drawPath(ctx, screen, strokeStyle, closed, shape.fill ?? false);\n }\n }\n}\n","import type { DrawCoordinate, DrawTool, StampDrawTool, StampOptions } from \"./draw-layer-types\";\nimport { CIRCLE_SIDES, DEFAULT_STAMP_CIRCLE_AREA_MM2, DEFAULT_STAMP_RECTANGLE_AREA_MM2, DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE, LEGACY_HPF_CIRCLE_AREA_MM2 } from \"./draw-layer-types\";\nimport { clampPositiveOrFallback, clampWorld, closeRing } from \"./draw-layer-utils\";\n\nexport type { StampDrawTool, StampOptions };\n\nexport function isStampTool(tool: DrawTool): tool is StampDrawTool {\n return (\n tool === \"stamp-rectangle\" || tool === \"stamp-circle\" || tool === \"stamp-rectangle-4096px\" || tool === \"stamp-rectangle-2mm2\" || tool === \"stamp-circle-2mm2\" || tool === \"stamp-circle-hpf-0.2mm2\"\n );\n}\n\nexport function resolveStampOptions(options: StampOptions | undefined): Required<StampOptions> {\n return {\n rectangleAreaMm2: clampPositiveOrFallback(options?.rectangleAreaMm2, DEFAULT_STAMP_RECTANGLE_AREA_MM2),\n circleAreaMm2: clampPositiveOrFallback(options?.circleAreaMm2, DEFAULT_STAMP_CIRCLE_AREA_MM2),\n rectanglePixelSize: clampPositiveOrFallback(options?.rectanglePixelSize, DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE),\n };\n}\n\nconst MICRONS_PER_MM = 1000;\n\nexport function mm2ToUm2(areaMm2: number): number {\n return areaMm2 * MICRONS_PER_MM * MICRONS_PER_MM;\n}\n\nexport function createSquareFromCenter(\n center: DrawCoordinate | null,\n halfLength: number,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n }\n): DrawCoordinate[] {\n if (!center || !Number.isFinite(halfLength) || halfLength <= 0) return [];\n\n if (projection) {\n const screenCenter = projection.worldToScreen(center[0], center[1]);\n const screenEdge = projection.worldToScreen(center[0] + halfLength, center[1]);\n if (screenCenter && screenEdge) {\n const screenHL = Math.hypot(screenEdge[0] - screenCenter[0], screenEdge[1] - screenCenter[1]);\n const screenCorners: DrawCoordinate[] = [\n [screenCenter[0] - screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] + screenHL],\n [screenCenter[0] - screenHL, screenCenter[1] + screenHL],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) throw new Error(\"Failed to create rectangle\");\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\n\n return closeRing([\n [center[0] - halfLength, center[1] - halfLength],\n [center[0] + halfLength, center[1] - halfLength],\n [center[0] + halfLength, center[1] + halfLength],\n [center[0] - halfLength, center[1] + halfLength],\n ]);\n}\n\nexport function createCircleFromCenter(center: DrawCoordinate | null, radius: number, sides = CIRCLE_SIDES): DrawCoordinate[] {\n if (!center || !Number.isFinite(radius) || radius <= 0) return [];\n\n const coords: DrawCoordinate[] = [];\n for (let i = 0; i <= sides; i += 1) {\n const t = (i / sides) * Math.PI * 2;\n coords.push([center[0] + Math.cos(t) * radius, center[1] + Math.sin(t) * radius]);\n }\n\n return closeRing(coords);\n}\n\nexport interface BuildStampCoordsParams {\n stampTool: StampDrawTool;\n center: DrawCoordinate | null;\n resolvedStampOptions: Required<StampOptions>;\n imageWidth: number;\n imageHeight: number;\n micronsToWorldPixels: (lengthUm: number) => number;\n getRectangleProjection: () =>\n | {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n }\n | undefined;\n}\n\nexport function buildStampCoords(params: BuildStampCoordsParams): DrawCoordinate[] {\n const { stampTool, center, resolvedStampOptions, imageWidth, imageHeight, micronsToWorldPixels, getRectangleProjection } = params;\n\n if (!center) return [];\n\n if (stampTool === \"stamp-rectangle-4096px\") {\n const halfLength = resolvedStampOptions.rectanglePixelSize * 0.5;\n return createSquareFromCenter(center, halfLength, getRectangleProjection()).map(point => clampWorld(point, imageWidth, imageHeight));\n }\n\n let areaMm2 = 0;\n if (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n areaMm2 = stampTool === \"stamp-rectangle-2mm2\" ? DEFAULT_STAMP_RECTANGLE_AREA_MM2 : resolvedStampOptions.rectangleAreaMm2;\n } else if (stampTool === \"stamp-circle\" || stampTool === \"stamp-circle-2mm2\" || stampTool === \"stamp-circle-hpf-0.2mm2\") {\n areaMm2 = stampTool === \"stamp-circle-hpf-0.2mm2\" ? LEGACY_HPF_CIRCLE_AREA_MM2 : stampTool === \"stamp-circle-2mm2\" ? DEFAULT_STAMP_CIRCLE_AREA_MM2 : resolvedStampOptions.circleAreaMm2;\n }\n if (!Number.isFinite(areaMm2) || areaMm2 <= 0) return [];\n\n const areaUm2 = mm2ToUm2(areaMm2);\n let coords: DrawCoordinate[] = [];\n if (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n const halfLength = micronsToWorldPixels(Math.sqrt(areaUm2) * 0.5);\n coords = createSquareFromCenter(center, halfLength, getRectangleProjection());\n } else if (stampTool === \"stamp-circle\" || stampTool === \"stamp-circle-2mm2\" || stampTool === \"stamp-circle-hpf-0.2mm2\") {\n const radius = micronsToWorldPixels(Math.sqrt(areaUm2 / Math.PI));\n coords = createCircleFromCenter(center, radius);\n }\n\n if (!coords.length) return [];\n return coords.map(point => clampWorld(point, imageWidth, imageHeight));\n}\n","import { type CSSProperties, type PointerEvent as ReactPointerEvent, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { buildBrushStrokePolygon } from \"../wsi/brush-stroke\";\nimport { calcScaleResolution } from \"../wsi/utils\";\nimport { drawBrushCursor, drawBrushStrokePreview, resolveBrushOptions } from \"./draw-layer-brush\";\nimport {\n drawAreaTooltipBox,\n drawRegionLabel,\n getTopAnchorFromPolygons,\n mergeRegionLabelStyle,\n resolveDrawAreaTooltipOptions,\n resolveRegionLabelAutoLiftOffsetPx,\n resolveRegionLabelStyle,\n} from \"./draw-layer-label\";\nimport { drawOverlayShapes } from \"./draw-layer-overlay\";\nimport { buildStampCoords, isStampTool, resolveStampOptions } from \"./draw-layer-stamp\";\nimport {\n BRUSH_RASTER_DIAMETER_SAMPLES,\n BRUSH_SCREEN_STEP,\n DEFAULT_DRAW_PREVIEW_FILL,\n DEFAULT_PATCH_STROKE_STYLE,\n type DrawLayerProps,\n type DrawRegion,\n type DrawSession,\n type DrawTool,\n EMPTY_DASH,\n EMPTY_REGIONS,\n FREEHAND_MIN_POINTS,\n FREEHAND_SCREEN_STEP,\n MICRONS_PER_MM,\n MIN_AREA_PX,\n MIN_BRUSH_RASTER_STEP,\n type PreparedRenderedRegion,\n REGION_INTERACTION_SHADOW_COLOR,\n REGION_INTERACTION_SHADOW_WIDTH,\n type StampDrawTool,\n WHEEL_ZOOM_IN_FACTOR,\n WHEEL_ZOOM_OUT_FACTOR,\n} from \"./draw-layer-types\";\nimport {\n clamp,\n clampWorld,\n closeRing,\n computeBounds,\n createCircle,\n createRectangle,\n drawPath,\n isSameRegionId,\n mergeStrokeStyle,\n normalizeDrawRegionPolygons,\n polygonArea,\n resolveStrokeStyle,\n toCoord,\n} from \"./draw-layer-utils\";\n\nexport { mergeRegionLabelStyle, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer-label\";\nexport type {\n BrushOptions,\n DrawAreaTooltipOptions,\n DrawAreaTooltipStyle,\n DrawBounds,\n DrawCoordinate,\n DrawIntent,\n DrawOverlayCoordinates,\n DrawOverlayInvertedFillStyle,\n DrawOverlayShape,\n DrawProjector,\n DrawRegion,\n DrawRegionCoordinates,\n DrawResult,\n DrawTool,\n PatchDrawResult,\n RegionLabelStyle,\n RegionLabelStyleContext,\n RegionLabelStyleResolver,\n RegionStrokeStyle,\n RegionStrokeStyleResolver,\n RegionStyleContext,\n StampDrawTool,\n StampOptions,\n} from \"./draw-layer-types\";\nexport { closeRing, createCircle, createRectangle } from \"./draw-layer-utils\";\n\nfunction resolveRegionInteractionShadowStyle(strokeStyle: import(\"./draw-layer-types\").RegionStrokeStyle): import(\"./draw-layer-types\").RegionStrokeStyle {\n return {\n color: REGION_INTERACTION_SHADOW_COLOR,\n width: REGION_INTERACTION_SHADOW_WIDTH,\n lineDash: EMPTY_DASH,\n lineJoin: strokeStyle.lineJoin,\n lineCap: strokeStyle.lineCap,\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n };\n}\n\nfunction resolveDrawPreviewFillColor(value: string | undefined): string {\n if (typeof value !== \"string\") return DEFAULT_DRAW_PREVIEW_FILL;\n const next = value.trim();\n return next.length > 0 ? next : DEFAULT_DRAW_PREVIEW_FILL;\n}\n\nfunction isValidPolygon(coords: import(\"./draw-layer-types\").DrawCoordinate[]): boolean {\n return Array.isArray(coords) && coords.length >= 4 && polygonArea(coords) > MIN_AREA_PX;\n}\n\nexport function DrawLayer({\n tool,\n imageWidth,\n imageHeight,\n imageMpp,\n imageZoom,\n stampOptions,\n brushOptions,\n projectorRef,\n onBrushTap,\n onDrawComplete,\n onPatchComplete,\n enabled,\n viewStateSignal,\n persistedRegions,\n patchRegions,\n persistedPolygons,\n drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n hoveredRegionId = null,\n activeRegionId = null,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n regionLabelAutoLiftOffsetPx,\n invalidateRef,\n className,\n style,\n}: DrawLayerProps): React.ReactElement {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const drawPendingRef = useRef(false);\n const overlayDebugSnapshotRef = useRef<Map<string, string>>(new Map());\n const lastToolRef = useRef<DrawTool>(tool);\n const sessionRef = useRef<DrawSession>({\n isDrawing: false,\n pointerId: null,\n start: null,\n current: null,\n cursor: null,\n cursorScreen: null,\n points: [],\n screenPoints: [],\n stampCenter: null,\n });\n\n const active = enabled ?? tool !== \"cursor\";\n const mergedPersistedRegions = useMemo<DrawRegion[]>(() => {\n if (persistedRegions && persistedRegions.length > 0) {\n return persistedRegions;\n }\n if (!persistedPolygons || persistedPolygons.length === 0) {\n return EMPTY_REGIONS;\n }\n return persistedPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [persistedRegions, persistedPolygons]);\n const mergedPatchRegions = useMemo<DrawRegion[]>(() => patchRegions ?? EMPTY_REGIONS, [patchRegions]);\n const preparedPersistedRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPersistedRegions.length; i += 1) {\n const region = mergedPersistedRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPersistedRegions]);\n const preparedPatchRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPatchRegions.length; i += 1) {\n const region = mergedPatchRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPatchRegions]);\n\n const resolvedStrokeStyle = useMemo(() => resolveStrokeStyle(regionStrokeStyle), [regionStrokeStyle]);\n const resolvedHoverStrokeStyle = useMemo(() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeHoverStyle), [resolvedStrokeStyle, regionStrokeHoverStyle]);\n const resolvedActiveStrokeStyle = useMemo(() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeActiveStyle), [resolvedStrokeStyle, regionStrokeActiveStyle]);\n const resolvedPatchStrokeStyle = useMemo(() => mergeStrokeStyle(DEFAULT_PATCH_STROKE_STYLE, patchStrokeStyle), [patchStrokeStyle]);\n const resolvedDrawPreviewFillColor = useMemo(() => resolveDrawPreviewFillColor(drawFillColor), [drawFillColor]);\n\n const resolvedLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n const resolvedDrawAreaTooltipOptions = useMemo(() => resolveDrawAreaTooltipOptions(drawAreaTooltip), [drawAreaTooltip]);\n const resolvedStampOptions = useMemo(() => resolveStampOptions(stampOptions), [stampOptions]);\n const resolvedBrushOptions = useMemo(() => resolveBrushOptions(brushOptions), [brushOptions]);\n\n const mergedStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n inset: 0,\n zIndex: 2,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n pointerEvents: active ? \"auto\" : \"none\",\n cursor: active ? (tool === \"brush\" ? \"none\" : \"crosshair\") : \"default\",\n ...style,\n }),\n [active, tool, style]\n );\n\n const resizeCanvas = useCallback(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const w = Math.max(1, Math.round(rect.width * dpr));\n const h = Math.max(1, Math.round(rect.height * dpr));\n\n if (canvas.width !== w || canvas.height !== h) {\n canvas.width = w;\n canvas.height = h;\n }\n }, []);\n\n const worldToScreenPoints = useCallback(\n (points: import(\"./draw-layer-types\").DrawCoordinate[]): import(\"./draw-layer-types\").DrawCoordinate[] => {\n const projector = projectorRef.current;\n if (!projector || points.length === 0) return [];\n\n const out = new Array<import(\"./draw-layer-types\").DrawCoordinate>(points.length);\n for (let i = 0; i < points.length; i += 1) {\n const coord = toCoord(projector.worldToScreen(points[i][0], points[i][1]));\n if (!coord) return [];\n out[i] = coord;\n }\n return out;\n },\n [projectorRef]\n );\n\n const localScreenToWorld = useCallback(\n (screen: import(\"./draw-layer-types\").DrawCoordinate): import(\"./draw-layer-types\").DrawCoordinate | null => {\n const projector = projectorRef.current;\n const canvas = canvasRef.current;\n if (!projector || !canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const raw = toCoord(projector.screenToWorld(rect.left + screen[0], rect.top + screen[1]));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const getRectangleProjection = useCallback(() => {\n const projector = projectorRef.current;\n const rotationDeg = projector?.getViewState?.().rotationDeg ?? 0;\n if (Math.abs(rotationDeg % 360) < 0.01 || !projector) return undefined;\n\n return {\n worldToScreen: (x: number, y: number): import(\"./draw-layer-types\").DrawCoordinate | null => toCoord(projector.worldToScreen(x, y)),\n screenToWorld: localScreenToWorld,\n };\n }, [projectorRef, localScreenToWorld]);\n\n const micronsToWorldPixels = useCallback(\n (lengthUm: number): number => {\n if (!Number.isFinite(lengthUm) || lengthUm <= 0) return 0;\n\n const mppValue = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 1;\n const imageZoomValue = typeof imageZoom === \"number\" && Number.isFinite(imageZoom) ? imageZoom : 0;\n const viewZoomRaw = projectorRef.current?.getViewState?.().zoom;\n const viewZoom = typeof viewZoomRaw === \"number\" && Number.isFinite(viewZoomRaw) && viewZoomRaw > 0 ? viewZoomRaw : 1;\n const continuousZoom = imageZoomValue + Math.log2(viewZoom);\n const umPerScreenPixel = Math.max(1e-9, calcScaleResolution(mppValue, imageZoomValue, continuousZoom));\n const screenPixels = lengthUm / umPerScreenPixel;\n return screenPixels / viewZoom;\n },\n [imageMpp, imageZoom, projectorRef]\n );\n\n const buildStampCoordsCallback = useCallback(\n (stampTool: StampDrawTool, center: import(\"./draw-layer-types\").DrawCoordinate | null): import(\"./draw-layer-types\").DrawCoordinate[] => {\n return buildStampCoords({\n stampTool,\n center,\n resolvedStampOptions,\n imageWidth,\n imageHeight,\n micronsToWorldPixels,\n getRectangleProjection,\n });\n },\n [micronsToWorldPixels, imageWidth, imageHeight, resolvedStampOptions, getRectangleProjection]\n );\n\n const buildPreviewCoords = useCallback((): import(\"./draw-layer-types\").DrawCoordinate[] => {\n const session = sessionRef.current;\n if (isStampTool(tool)) {\n return buildStampCoordsCallback(tool, session.stampCenter);\n }\n if (tool === \"brush\") {\n return [];\n }\n if (!session.isDrawing) return [];\n\n if (tool === \"freehand\") {\n return session.points;\n }\n if (tool === \"rectangle\") {\n return createRectangle(session.start, session.current, getRectangleProjection());\n }\n if (tool === \"circular\") {\n return createCircle(session.start, session.current);\n }\n\n return [];\n }, [tool, buildStampCoordsCallback, getRectangleProjection]);\n\n const drawOverlay = useCallback(() => {\n resizeCanvas();\n\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const canvasWidth = canvas.width / dpr;\n const canvasHeight = canvas.height / dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (preparedPersistedRegions.length > 0) {\n for (const entry of preparedPersistedRegions) {\n const { region, polygons, regionIndex, regionKey } = entry;\n const state: \"default\" | \"hover\" | \"active\" = isSameRegionId(activeRegionId, regionKey) ? \"active\" : isSameRegionId(hoveredRegionId, regionKey) ? \"hover\" : \"default\";\n let strokeStyle = state === \"active\" ? resolvedActiveStrokeStyle : state === \"hover\" ? resolvedHoverStrokeStyle : resolvedStrokeStyle;\n\n if (resolveRegionStrokeStyle) {\n const resolved = resolveRegionStrokeStyle({\n region,\n regionId: regionKey,\n regionIndex,\n state,\n });\n strokeStyle = mergeStrokeStyle(strokeStyle, resolved || undefined);\n }\n const interactionShadowStyle = state === \"default\" ? null : resolveRegionInteractionShadowStyle(strokeStyle);\n\n for (const polygon of polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenOuter, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenOuter, strokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenHole, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenHole, strokeStyle, true, false);\n }\n }\n }\n }\n }\n\n if (preparedPatchRegions.length > 0) {\n for (const entry of preparedPatchRegions) {\n for (const polygon of entry.polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n drawPath(ctx, screenOuter, resolvedPatchStrokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n drawPath(ctx, screenHole, resolvedPatchStrokeStyle, true, false);\n }\n }\n }\n }\n }\n\n if (Array.isArray(overlayShapes) && overlayShapes.length > 0) {\n const imageOuterRing = worldToScreenPoints(\n closeRing([\n [0, 0],\n [imageWidth, 0],\n [imageWidth, imageHeight],\n [0, imageHeight],\n ])\n );\n drawOverlayShapes({\n ctx,\n overlayShapes,\n imageOuterRing,\n worldToScreenPoints,\n baseStrokeStyle: resolvedStrokeStyle,\n onInvertedFillDebug: (globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__\n ? info => {\n const debugKey = String(info.id);\n const debugSignature = `${info.outerRingPoints}|${info.sourceRingCount}|${info.holeRingCount}|${info.fillColor}`;\n if (overlayDebugSnapshotRef.current.get(debugKey) !== debugSignature) {\n overlayDebugSnapshotRef.current.set(debugKey, debugSignature);\n console.debug(\"[open-plant] invertedFill\", info);\n }\n }\n : undefined,\n });\n }\n\n const preview = buildPreviewCoords();\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx, sessionRef.current, resolvedBrushOptions);\n drawBrushCursor(ctx, sessionRef.current, projectorRef.current, resolvedBrushOptions);\n } else if (preview.length > 0) {\n if (tool === \"freehand\") {\n const line = worldToScreenPoints(preview);\n if (line.length >= 2) {\n drawPath(ctx, line, resolvedStrokeStyle, false, false);\n }\n if (line.length >= 3) {\n drawPath(ctx, worldToScreenPoints(closeRing(preview)), resolvedStrokeStyle, true, true, resolvedDrawPreviewFillColor);\n }\n } else {\n const polygon = worldToScreenPoints(preview);\n if (polygon.length >= 4) {\n drawPath(ctx, polygon, resolvedStrokeStyle, true, true, resolvedDrawPreviewFillColor);\n }\n }\n }\n }\n\n if (preparedPersistedRegions.length > 0) {\n const zoom = Math.max(1e-6, projectorRef.current?.getViewState?.().zoom ?? 1);\n const labelAutoLiftOffset =\n typeof regionLabelAutoLiftOffsetPx === \"number\" && Number.isFinite(regionLabelAutoLiftOffsetPx)\n ? Math.max(0, regionLabelAutoLiftOffsetPx)\n : resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, projectorRef.current?.getZoomRange?.());\n for (const entry of preparedPersistedRegions) {\n if (!entry.region.label) continue;\n const anchorWorld = getTopAnchorFromPolygons(entry.polygons);\n if (!anchorWorld) continue;\n const anchorScreen = toCoord(projectorRef.current?.worldToScreen(anchorWorld[0], anchorWorld[1]) ?? []);\n if (!anchorScreen) continue;\n let dynamicLabelStyle = mergeRegionLabelStyle(\n resolvedLabelStyle,\n resolveRegionLabelStyleProp?.({\n region: entry.region,\n regionId: entry.regionKey,\n regionIndex: entry.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n drawRegionLabel(ctx, entry.region.label, anchorScreen, canvasWidth, canvasHeight, dynamicLabelStyle);\n }\n }\n\n if (resolvedDrawAreaTooltipOptions.enabled && active && (tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\")) {\n const session = sessionRef.current;\n if (session.isDrawing) {\n const areaCoords = tool === \"freehand\" ? closeRing(preview) : preview;\n if (areaCoords.length >= 4) {\n const areaPx = polygonArea(areaCoords);\n const mpp = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 0;\n const areaMm2 = mpp > 0 ? (areaPx * mpp * mpp) / (MICRONS_PER_MM * MICRONS_PER_MM) : 0;\n const text = resolvedDrawAreaTooltipOptions.format(areaMm2);\n\n const cursor = session.cursorScreen ?? (session.current ? toCoord(projectorRef.current?.worldToScreen(session.current[0], session.current[1]) ?? []) : null);\n if (cursor) {\n drawAreaTooltipBox(\n ctx,\n text,\n cursor,\n canvasWidth,\n canvasHeight,\n resolvedDrawAreaTooltipOptions.style,\n resolvedDrawAreaTooltipOptions.cursorOffsetX,\n resolvedDrawAreaTooltipOptions.cursorOffsetY\n );\n }\n }\n }\n }\n }, [\n active,\n tool,\n buildPreviewCoords,\n resizeCanvas,\n worldToScreenPoints,\n imageWidth,\n imageHeight,\n projectorRef,\n preparedPersistedRegions,\n overlayShapes,\n hoveredRegionId,\n activeRegionId,\n resolvedStrokeStyle,\n resolvedHoverStrokeStyle,\n resolvedActiveStrokeStyle,\n resolvedDrawPreviewFillColor,\n preparedPatchRegions,\n resolvedPatchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyleProp,\n resolvedLabelStyle,\n resolvedDrawAreaTooltipOptions,\n autoLiftRegionLabelAtMaxZoom,\n regionLabelAutoLiftOffsetPx,\n imageMpp,\n resolvedBrushOptions,\n ]);\n\n const requestDraw = useCallback(() => {\n if (drawPendingRef.current) return;\n drawPendingRef.current = true;\n requestAnimationFrame(() => {\n drawPendingRef.current = false;\n drawOverlay();\n });\n }, [drawOverlay]);\n\n const resetSession = useCallback((preserveCursor = false) => {\n const session = sessionRef.current;\n const canvas = canvasRef.current;\n\n if (canvas && session.pointerId !== null && canvas.hasPointerCapture(session.pointerId)) {\n canvas.releasePointerCapture(session.pointerId);\n }\n\n session.isDrawing = false;\n session.pointerId = null;\n session.start = null;\n session.current = null;\n session.points = [];\n session.screenPoints = [];\n session.stampCenter = null;\n if (!preserveCursor) {\n session.cursor = null;\n session.cursorScreen = null;\n }\n }, []);\n\n const toWorld = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>): import(\"./draw-layer-types\").DrawCoordinate | null => {\n const projector = projectorRef.current;\n if (!projector || imageWidth <= 0 || imageHeight <= 0) return null;\n\n const raw = toCoord(projector.screenToWorld(event.clientX, event.clientY));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const toLocalScreen = useCallback((event: ReactPointerEvent<HTMLCanvasElement>): import(\"./draw-layer-types\").DrawCoordinate | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const x = clamp(event.clientX - rect.left, 0, rect.width);\n const y = clamp(event.clientY - rect.top, 0, rect.height);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const finishSession = useCallback(() => {\n const session = sessionRef.current;\n if (!session.isDrawing) {\n resetSession(true);\n requestDraw();\n return;\n }\n\n let coordinates: import(\"./draw-layer-types\").DrawCoordinate[] = [];\n if (tool === \"freehand\") {\n if (session.points.length >= FREEHAND_MIN_POINTS) {\n coordinates = closeRing(session.points);\n }\n } else if (tool === \"rectangle\") {\n coordinates = createRectangle(session.start, session.current, getRectangleProjection());\n } else if (tool === \"circular\") {\n coordinates = createCircle(session.start, session.current);\n } else if (tool === \"brush\") {\n const tapPoint = session.points[session.points.length - 1] ?? session.current ?? session.start;\n if (resolvedBrushOptions.clickSelectRoi && tapPoint && session.points.length <= 1 && onBrushTap?.(tapPoint)) {\n resetSession(true);\n requestDraw();\n return;\n }\n const edgeDetail = resolvedBrushOptions.edgeDetail;\n const minRasterStep = Math.max(MIN_BRUSH_RASTER_STEP, (resolvedBrushOptions.radius * 2) / (BRUSH_RASTER_DIAMETER_SAMPLES * edgeDetail));\n const screenPath = session.screenPoints.length > 0 ? session.screenPoints : worldToScreenPoints(session.points);\n const screenPolygon = buildBrushStrokePolygon(screenPath, {\n radius: resolvedBrushOptions.radius,\n minRasterStep,\n circleSides: Math.max(24, Math.round(64 * edgeDetail)),\n simplifyTolerance: minRasterStep * 0.25,\n smoothingPasses: resolvedBrushOptions.edgeSmoothing,\n }) as import(\"./draw-layer-types\").DrawCoordinate[];\n const worldPolygon: import(\"./draw-layer-types\").DrawCoordinate[] = [];\n for (const point of screenPolygon) {\n const world = localScreenToWorld(point);\n if (!world) continue;\n worldPolygon.push(world);\n }\n coordinates = closeRing(worldPolygon);\n }\n\n if ((tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\" || tool === \"brush\") && isValidPolygon(coordinates) && onDrawComplete) {\n const intent: import(\"./draw-layer-types\").DrawIntent = tool === \"brush\" ? \"brush\" : \"roi\";\n onDrawComplete({\n tool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n });\n }\n\n resetSession(true);\n requestDraw();\n }, [\n tool,\n onDrawComplete,\n resetSession,\n requestDraw,\n worldToScreenPoints,\n localScreenToWorld,\n getRectangleProjection,\n resolvedBrushOptions.radius,\n resolvedBrushOptions.edgeDetail,\n resolvedBrushOptions.edgeSmoothing,\n resolvedBrushOptions.clickSelectRoi,\n onBrushTap,\n ]);\n\n const handleStampAt = useCallback(\n (stampTool: StampDrawTool, center: import(\"./draw-layer-types\").DrawCoordinate): void => {\n const coordinates = buildStampCoordsCallback(stampTool, center);\n if (!isValidPolygon(coordinates)) return;\n const intent: import(\"./draw-layer-types\").DrawIntent = stampTool === \"stamp-rectangle-4096px\" ? \"patch\" : \"roi\";\n const result: import(\"./draw-layer-types\").DrawResult = {\n tool: stampTool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n };\n onDrawComplete?.(result);\n if (intent === \"patch\" && onPatchComplete) {\n onPatchComplete(result as import(\"./draw-layer-types\").PatchDrawResult);\n }\n },\n [buildStampCoordsCallback, onDrawComplete, onPatchComplete]\n );\n\n const appendBrushPoint = useCallback((session: DrawSession, world: import(\"./draw-layer-types\").DrawCoordinate, screen: import(\"./draw-layer-types\").DrawCoordinate): void => {\n const minScreenStep2 = BRUSH_SCREEN_STEP * BRUSH_SCREEN_STEP;\n const prevScreen = session.screenPoints[session.screenPoints.length - 1];\n if (!prevScreen) {\n session.points.push(world);\n session.screenPoints.push(screen);\n session.current = world;\n return;\n }\n const dx = screen[0] - prevScreen[0];\n const dy = screen[1] - prevScreen[1];\n if (dx * dx + dy * dy >= minScreenStep2) {\n session.points.push(world);\n session.screenPoints.push(screen);\n } else {\n session.points[session.points.length - 1] = world;\n session.screenPoints[session.screenPoints.length - 1] = screen;\n }\n session.current = world;\n }, []);\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n if (!active) return;\n if (tool === \"cursor\") return;\n if (event.button !== 0) return;\n\n const world = toWorld(event);\n if (!world) return;\n const screen = toLocalScreen(event);\n if (!screen) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n if (isStampTool(tool)) {\n const session = sessionRef.current;\n session.stampCenter = world;\n handleStampAt(tool, world);\n requestDraw();\n return;\n }\n\n const canvas = canvasRef.current;\n if (canvas) {\n canvas.setPointerCapture(event.pointerId);\n }\n\n const session = sessionRef.current;\n session.isDrawing = true;\n session.pointerId = event.pointerId;\n session.start = world;\n session.current = world;\n session.cursor = world;\n session.cursorScreen = screen;\n session.points = tool === \"freehand\" || tool === \"brush\" ? [world] : [];\n session.screenPoints = tool === \"brush\" ? [screen] : [];\n requestDraw();\n },\n [active, tool, toWorld, toLocalScreen, handleStampAt, requestDraw]\n );\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n if (!active) return;\n if (tool === \"cursor\") return;\n\n const world = toWorld(event);\n if (!world) return;\n const screen = toLocalScreen(event);\n if (!screen) return;\n\n const session = sessionRef.current;\n session.cursor = world;\n session.cursorScreen = screen;\n\n if (isStampTool(tool)) {\n session.stampCenter = world;\n event.preventDefault();\n event.stopPropagation();\n requestDraw();\n return;\n }\n\n if (tool === \"brush\") {\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n requestDraw();\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n appendBrushPoint(session, world, screen);\n requestDraw();\n return;\n }\n\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n\n if (tool === \"freehand\") {\n const projector = projectorRef.current;\n const zoom = Math.max(1e-6, projector?.getViewState?.().zoom ?? 1);\n const minWorldStep = FREEHAND_SCREEN_STEP / zoom;\n const minWorldStep2 = minWorldStep * minWorldStep;\n const prev = session.points[session.points.length - 1];\n\n if (!prev) {\n session.points.push(world);\n } else {\n const dx = world[0] - prev[0];\n const dy = world[1] - prev[1];\n if (dx * dx + dy * dy >= minWorldStep2) {\n session.points.push(world);\n }\n }\n } else {\n session.current = world;\n }\n\n requestDraw();\n },\n [active, tool, toWorld, toLocalScreen, requestDraw, projectorRef, appendBrushPoint]\n );\n\n const handlePointerUp = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.pointerId !== event.pointerId) return;\n\n event.preventDefault();\n event.stopPropagation();\n const world = toWorld(event);\n const screen = toLocalScreen(event);\n if (world) {\n session.cursor = world;\n if (screen) {\n session.cursorScreen = screen;\n }\n if (tool === \"brush\") {\n if (screen) {\n appendBrushPoint(session, world, screen);\n }\n } else {\n session.current = world;\n }\n }\n const canvas = canvasRef.current;\n if (canvas && canvas.hasPointerCapture(event.pointerId)) {\n canvas.releasePointerCapture(event.pointerId);\n }\n\n finishSession();\n },\n [finishSession, toWorld, toLocalScreen, tool, appendBrushPoint]\n );\n\n const handlePointerLeave = useCallback(() => {\n const session = sessionRef.current;\n let changed = false;\n if (tool === \"brush\" && !session.isDrawing && session.cursor) {\n session.cursor = null;\n session.cursorScreen = null;\n changed = true;\n }\n if (isStampTool(tool) && session.stampCenter) {\n session.stampCenter = null;\n changed = true;\n }\n if (changed) {\n requestDraw();\n }\n }, [tool, requestDraw]);\n\n useEffect(() => {\n resizeCanvas();\n requestDraw();\n\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n\n const observer = new ResizeObserver(() => {\n resizeCanvas();\n requestDraw();\n });\n observer.observe(canvas);\n\n return () => {\n observer.disconnect();\n };\n }, [resizeCanvas, requestDraw]);\n\n useEffect(() => {\n if (!active) {\n resetSession();\n }\n requestDraw();\n }, [active, requestDraw, resetSession]);\n\n useEffect(() => {\n if (lastToolRef.current === tool) {\n return;\n }\n lastToolRef.current = tool;\n resetSession();\n requestDraw();\n }, [tool, resetSession, requestDraw]);\n\n useEffect(() => {\n requestDraw();\n }, [viewStateSignal, mergedPersistedRegions, overlayShapes, requestDraw]);\n\n useEffect(() => {\n if (!invalidateRef) return undefined;\n invalidateRef.current = requestDraw;\n return () => {\n if (invalidateRef.current === requestDraw) {\n invalidateRef.current = null;\n }\n };\n }, [invalidateRef, requestDraw]);\n\n useEffect(() => {\n if (!active) return undefined;\n\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== \"Escape\") return;\n resetSession();\n requestDraw();\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [active, resetSession, requestDraw]);\n\n return (\n <canvas\n ref={canvasRef}\n className={className}\n style={mergedStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onPointerLeave={handlePointerLeave}\n onContextMenu={event => {\n if (active) event.preventDefault();\n }}\n onWheel={event => {\n if (!active) return;\n const canvas = canvasRef.current;\n const projector = projectorRef.current;\n if (!canvas || typeof projector?.zoomBy !== \"function\") return;\n event.preventDefault();\n event.stopPropagation();\n const rect = canvas.getBoundingClientRect();\n const screenX = event.clientX - rect.left;\n const screenY = event.clientY - rect.top;\n projector.zoomBy(event.deltaY < 0 ? WHEEL_ZOOM_IN_FACTOR : WHEEL_ZOOM_OUT_FACTOR, screenX, screenY);\n requestDraw();\n }}\n />\n );\n}\n","import type { WsiImageSource, WsiTerm } from \"./types\";\n\nexport interface RawImsInfo {\n width?: number | null;\n height?: number | null;\n tileSize?: number | null;\n zoom?: number | null;\n path?: string | null;\n mpp?: number | null;\n}\n\nexport interface RawWsiTerm {\n termId?: string | null;\n termName?: string | null;\n termColor?: string | null;\n}\n\nexport interface RawImagePayload {\n _id?: string | null;\n name?: string | null;\n width?: number | null;\n height?: number | null;\n tileSize?: number | null;\n zoom?: number | null;\n path?: string | null;\n mpp?: number | null;\n imsInfo?: RawImsInfo | null;\n terms?: RawWsiTerm[] | null;\n}\n\nfunction trimTrailingSlash(value: string): string {\n return String(value ?? \"\").replace(/\\/+$/, \"\");\n}\n\nfunction ensureLeadingSlash(value: string): string {\n const raw = String(value ?? \"\");\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nfunction joinImsTileRoot(tileBaseUrl: string): string {\n const base = trimTrailingSlash(tileBaseUrl);\n if (!base) return \"\";\n\n // Explicit TileGroup path already provided.\n if (/\\/TileGroup\\d+$/i.test(base)) return base;\n\n let parsed: URL | null = null;\n try {\n parsed = new URL(base);\n } catch {\n parsed = null;\n }\n\n if (parsed) {\n const origin = `${parsed.protocol}//${parsed.host}`;\n const path = trimTrailingSlash(parsed.pathname || \"\");\n\n // If caller passes /ims, keep /ims and append image path directly:\n // /ims + /tiles/<hash> + /tier/y_x.webp\n if (/\\/ims$/i.test(path)) return `${origin}${path}`;\n if (/\\/tiles$/i.test(path)) return `${origin}${path}`;\n return `${origin}${path}/tiles`;\n }\n\n // Relative path mode\n if (/\\/ims$/i.test(base)) return `/ims`;\n if (/\\/tiles$/i.test(base)) return `${base}`;\n return `${base}/tiles`;\n}\n\nexport function normalizeImageInfo(raw: RawImagePayload, tileBaseUrl: string): WsiImageSource {\n const ims = raw?.imsInfo ?? {};\n const isIms = !!raw?.imsInfo;\n\n const width = Number(ims.width ?? raw?.width ?? 0);\n const height = Number(ims.height ?? raw?.height ?? 0);\n const tileSize = Number(ims.tileSize ?? raw?.tileSize ?? 0);\n const maxTierZoom = Number(ims.zoom ?? raw?.zoom ?? 0);\n const tilePath = String(ims.path ?? raw?.path ?? \"\");\n const mpp = Number(ims.mpp ?? raw?.mpp ?? 0);\n\n if (!width || !height || !tileSize || !tilePath) {\n throw new Error(\"Incomplete image metadata: width/height/tileSize/path required\");\n }\n\n const terms: WsiTerm[] = Array.isArray(raw?.terms)\n ? raw.terms.map((term: RawWsiTerm) => ({\n termId: String(term?.termId ?? \"\"),\n termName: String(term?.termName ?? \"\"),\n termColor: String(term?.termColor ?? \"\"),\n }))\n : [];\n\n const normalizedPath = ensureLeadingSlash(tilePath);\n const imsTileRoot = joinImsTileRoot(tileBaseUrl);\n const tileUrlBuilder = isIms ? (tier: number, x: number, y: number): string => `${imsTileRoot}${normalizedPath}/${tier}/${y}_${x}.webp` : undefined;\n\n return {\n id: raw?._id || \"unknown\",\n name: raw?.name || \"unknown\",\n width,\n height,\n mpp: Number.isFinite(mpp) && mpp > 0 ? mpp : undefined,\n tileSize,\n maxTierZoom: Number.isFinite(maxTierZoom) ? Math.max(0, Math.floor(maxTierZoom)) : 0,\n tilePath,\n tileBaseUrl,\n terms,\n tileUrlBuilder,\n };\n}\n\nexport function toTileUrl(source: Pick<WsiImageSource, \"tilePath\" | \"tileBaseUrl\" | \"tileUrlBuilder\">, tier: number, x: number, y: number): string {\n if (source.tileUrlBuilder) {\n return source.tileUrlBuilder(tier, x, y);\n }\n const normalizedPath = ensureLeadingSlash(source.tilePath);\n return `${source.tileBaseUrl}${normalizedPath}/${tier}/${y}_${x}.webp`;\n}\n","import {\n\ttype CSSProperties,\n\ttype MutableRefObject,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype ReactNode,\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { toTileUrl } from \"../wsi/image-info\";\nimport type { WsiImageSource, WsiViewState } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\n\ntype Bounds = [number, number, number, number];\n\nexport interface OverviewMapProjector {\n\tgetViewState: () => WsiViewState;\n\tsetViewState: (next: Partial<WsiViewState>) => void;\n\tsetViewCenter?: (worldX: number, worldY: number) => void;\n\tgetViewBounds?: () => number[];\n\tgetViewCorners?: () => Array<[number, number]>;\n}\n\nexport type OverviewMapPosition =\n\t| \"bottom-right\"\n\t| \"bottom-left\"\n\t| \"top-right\"\n\t| \"top-left\";\n\nexport type ViewportBorderStyle = \"stroke\" | \"dash\";\n\nexport interface OverviewMapOptions {\n\twidth: number;\n\theight: number;\n\tmargin: number;\n\tposition: OverviewMapPosition;\n\tborderRadius: number;\n\tborderWidth: number;\n\tbackgroundColor: string;\n\tborderColor: string;\n\tviewportBorderColor: string;\n\tviewportBorderStyle: ViewportBorderStyle;\n\tviewportFillColor: string;\n\tinteractive: boolean;\n\tshowThumbnail: boolean;\n\tmaxThumbnailTiles: number;\n\tonClose?: () => void;\n\tcloseIcon?: ReactNode;\n\tcloseButtonStyle?: CSSProperties;\n}\n\nexport interface OverviewMapProps {\n\tsource: WsiImageSource;\n\tprojectorRef: RefObject<OverviewMapProjector | null>;\n\tauthToken?: string;\n\toptions?: Partial<OverviewMapOptions>;\n\tinvalidateRef?: MutableRefObject<(() => void) | null>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nconst DEFAULT_OVERVIEW_MAP_OPTIONS: OverviewMapOptions = {\n\twidth: 200,\n\theight: 125,\n\tmargin: 16,\n\tposition: \"bottom-right\",\n\tborderRadius: 6,\n\tborderWidth: 0,\n\tbackgroundColor: \"rgba(4, 10, 18, 0.88)\",\n\tborderColor: \"rgba(230, 244, 255, 0.35)\",\n\tviewportBorderColor: \"#171719\",\n\tviewportBorderStyle: \"dash\",\n\tviewportFillColor: \"transparent\",\n\tinteractive: true,\n\tshowThumbnail: true,\n\tmaxThumbnailTiles: 16,\n};\n\nfunction strokeSymmetricDashedPolygon(\n\tctx: CanvasRenderingContext2D,\n\tpoints: Array<[number, number]>,\n\tdashLen: number,\n\tgapLen: number,\n): void {\n\tconst len = points.length;\n\tif (len !== 4) return;\n\tif (dashLen <= 0 || gapLen <= 0) return;\n\n\tfor (let i = 0; i < len; i += 1) {\n\t\tconst from = points[i];\n\t\tconst to = points[(i + 1) % len];\n\t\tconst sideLen = Math.hypot(to[0] - from[0], to[1] - from[1]);\n\t\tif (sideLen < 1e-6) continue;\n\n\t\tconst n = Math.max(1, Math.round((sideLen + gapLen) / (dashLen + gapLen)));\n\t\tconst fittedLen = n * dashLen + (n - 1) * gapLen;\n\t\tconst scale = sideLen / Math.max(1e-6, fittedLen);\n\t\tconst adjDash = dashLen * scale;\n\t\tconst adjGap = gapLen * scale;\n\n\t\tctx.beginPath();\n\t\tctx.moveTo(from[0], from[1]);\n\t\tctx.lineTo(to[0], to[1]);\n\t\tctx.setLineDash([adjDash, adjGap]);\n\t\tctx.lineDashOffset = 0;\n\t\tctx.stroke();\n\t}\n\n\tctx.setLineDash([]);\n\tctx.lineDashOffset = 0;\n}\n\nfunction toPositiveNumber(\n\tvalue: number | undefined,\n\tfallback: number,\n\tmin = 1,\n): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n\treturn Math.max(min, value);\n}\n\nfunction isFiniteBounds(bounds: number[] | null | undefined): bounds is Bounds {\n\treturn (\n\t\tArray.isArray(bounds) &&\n\t\tbounds.length === 4 &&\n\t\tNumber.isFinite(bounds[0]) &&\n\t\tNumber.isFinite(bounds[1]) &&\n\t\tNumber.isFinite(bounds[2]) &&\n\t\tNumber.isFinite(bounds[3])\n\t);\n}\n\nconst DEFAULT_CLOSE_BUTTON_STYLE: CSSProperties = {\n\tposition: \"absolute\",\n\ttop: 4,\n\tright: 4,\n\tzIndex: 1,\n\twidth: 18,\n\theight: 18,\n\tborderRadius: 999,\n\tborder: \"1px solid rgba(255,255,255,0.4)\",\n\tbackground: \"rgba(16, 17, 19, 0.85)\",\n\tcolor: \"#fff\",\n\tfontSize: 12,\n\tlineHeight: 1,\n\tcursor: \"pointer\",\n\tpadding: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n};\n\nexport function OverviewMap({\n\tsource,\n\tprojectorRef,\n\tauthToken = \"\",\n\toptions,\n\tinvalidateRef,\n\tclassName,\n\tstyle,\n}: OverviewMapProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst thumbnailRef = useRef<HTMLCanvasElement | null>(null);\n\tconst lastBoundsRef = useRef<Bounds | null>(null);\n\tconst draggingRef = useRef<{ active: boolean; pointerId: number | null }>({\n\t\tactive: false,\n\t\tpointerId: null,\n\t});\n\tconst rafRef = useRef<number | null>(null);\n\tconst drawPendingRef = useRef(false);\n\n\tconst width = toPositiveNumber(\n\t\toptions?.width,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.width,\n\t\t64,\n\t);\n\tconst height = toPositiveNumber(\n\t\toptions?.height,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.height,\n\t\t48,\n\t);\n\n\tconst contentRect = useMemo(() => {\n\t\tconst imgW = Math.max(1, source.width);\n\t\tconst imgH = Math.max(1, source.height);\n\t\tconst imageAspect = imgW / imgH;\n\t\tconst boxAspect = width / height;\n\n\t\tlet cw: number;\n\t\tlet ch: number;\n\t\tif (imageAspect > boxAspect) {\n\t\t\tcw = width;\n\t\t\tch = width / imageAspect;\n\t\t} else {\n\t\t\tch = height;\n\t\t\tcw = height * imageAspect;\n\t\t}\n\n\t\treturn {\n\t\t\tx: (width - cw) / 2,\n\t\t\ty: (height - ch) / 2,\n\t\t\tw: cw,\n\t\t\th: ch,\n\t\t};\n\t}, [source.width, source.height, width, height]);\n\tconst margin = toPositiveNumber(\n\t\toptions?.margin,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.margin,\n\t\t0,\n\t);\n\tconst borderRadius = toPositiveNumber(\n\t\toptions?.borderRadius,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderRadius,\n\t\t0,\n\t);\n\tconst borderWidth = toPositiveNumber(\n\t\toptions?.borderWidth,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderWidth,\n\t\t0,\n\t);\n\tconst maxThumbnailTiles = Math.max(\n\t\t1,\n\t\tMath.round(\n\t\t\ttoPositiveNumber(\n\t\t\t\toptions?.maxThumbnailTiles,\n\t\t\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.maxThumbnailTiles,\n\t\t\t\t1,\n\t\t\t),\n\t\t),\n\t);\n\n\tconst backgroundColor =\n\t\toptions?.backgroundColor || DEFAULT_OVERVIEW_MAP_OPTIONS.backgroundColor;\n\tconst borderColor =\n\t\toptions?.borderColor || DEFAULT_OVERVIEW_MAP_OPTIONS.borderColor;\n\tconst viewportBorderColor =\n\t\toptions?.viewportBorderColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderColor;\n\tconst viewportBorderStyle =\n\t\toptions?.viewportBorderStyle === \"stroke\" || options?.viewportBorderStyle === \"dash\"\n\t\t\t? options.viewportBorderStyle\n\t\t\t: DEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderStyle;\n\tconst viewportFillColor =\n\t\toptions?.viewportFillColor ??\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportFillColor;\n\tconst interactive =\n\t\toptions?.interactive ?? DEFAULT_OVERVIEW_MAP_OPTIONS.interactive;\n\tconst showThumbnail =\n\t\toptions?.showThumbnail ?? DEFAULT_OVERVIEW_MAP_OPTIONS.showThumbnail;\n\tconst position =\n\t\toptions?.position || DEFAULT_OVERVIEW_MAP_OPTIONS.position;\n\tconst onClose = options?.onClose;\n\tconst closeIcon = options?.closeIcon;\n\tconst closeButtonStyle = options?.closeButtonStyle;\n\n\tconst mergedStyle = useMemo<CSSProperties>(() => {\n\t\tconst pos: CSSProperties = {};\n\t\tif (position === \"top-left\" || position === \"bottom-left\") pos.left = margin;\n\t\telse pos.right = margin;\n\t\tif (position === \"top-left\" || position === \"top-right\") pos.top = margin;\n\t\telse pos.bottom = margin;\n\n\t\treturn {\n\t\t\tposition: \"absolute\",\n\t\t\t...pos,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tborderRadius,\n\t\t\toverflow: \"hidden\",\n\t\t\tzIndex: 4,\n\t\t\tpointerEvents: interactive ? \"auto\" : \"none\",\n\t\t\ttouchAction: \"none\",\n\t\t\tboxShadow: \"0 10px 22px rgba(0, 0, 0, 0.3)\",\n\t\t\t...style,\n\t\t};\n\t}, [margin, position, width, height, borderRadius, interactive, style]);\n\n\tconst draw = useCallback(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\n\t\tconst cssW = width;\n\t\tconst cssH = height;\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst pixelW = Math.max(1, Math.round(cssW * dpr));\n\t\tconst pixelH = Math.max(1, Math.round(cssH * dpr));\n\t\tif (canvas.width !== pixelW || canvas.height !== pixelH) {\n\t\t\tcanvas.width = pixelW;\n\t\t\tcanvas.height = pixelH;\n\t\t}\n\n\t\tctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\tctx.clearRect(0, 0, canvas.width, canvas.height);\n\t\tctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, cssW, cssH);\n\n\t\tconst { x: cx, y: cy, w: cw, h: ch } = contentRect;\n\n\t\tconst preview = thumbnailRef.current;\n\t\tif (preview) {\n\t\t\tctx.drawImage(preview, cx, cy, cw, ch);\n\t\t}\n\n\t\tctx.strokeStyle = borderColor;\n\t\tctx.lineWidth = borderWidth;\n\t\tctx.strokeRect(\n\t\t\tborderWidth * 0.5,\n\t\t\tborderWidth * 0.5,\n\t\t\tcssW - borderWidth,\n\t\t\tcssH - borderWidth,\n\t\t);\n\n\t\tconst projector = projectorRef.current;\n\t\tconst bounds = projector?.getViewBounds?.();\n\t\tconst corners = projector?.getViewCorners?.();\n\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t? bounds\n\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t? lastBoundsRef.current\n\t\t\t\t: null;\n\t\tif (!safeBounds) return;\n\t\tlastBoundsRef.current = safeBounds;\n\n\t\tconst sx = cw / Math.max(1, source.width);\n\t\tconst sy = ch / Math.max(1, source.height);\n\n\t\tconst safeCorners =\n\t\t\tArray.isArray(corners) &&\n\t\t\tcorners.length >= 4 &&\n\t\t\tcorners.every(\n\t\t\t\t(point) =>\n\t\t\t\t\tArray.isArray(point) &&\n\t\t\t\t\tpoint.length >= 2 &&\n\t\t\t\t\tNumber.isFinite(point[0]) &&\n\t\t\t\t\tNumber.isFinite(point[1]),\n\t\t\t)\n\t\t\t\t? (corners as Array<[number, number]>)\n\t\t\t\t: null;\n\n\t\tconst isDash = viewportBorderStyle === \"dash\";\n\n\t\tif (safeCorners) {\n\t\t\tconst screenCorners: Array<[number, number]> = safeCorners.map(\n\t\t\t\t(point) => [cx + point[0] * sx, cy + point[1] * sy],\n\t\t\t);\n\n\t\t\tctx.save();\n\t\t\tctx.beginPath();\n\t\t\tctx.rect(cx, cy, cw, ch);\n\t\t\tctx.clip();\n\n\t\t\tctx.beginPath();\n\t\t\tfor (let i = 0; i < screenCorners.length; i += 1) {\n\t\t\t\tif (i === 0) ctx.moveTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t\telse ctx.lineTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t}\n\t\t\tctx.closePath();\n\t\t\tctx.fillStyle = viewportFillColor;\n\t\t\tctx.fill();\n\n\t\t\tctx.strokeStyle = viewportBorderColor;\n\t\t\tctx.lineWidth = 2.25;\n\t\t\tif (isDash) {\n\t\t\t\tstrokeSymmetricDashedPolygon(ctx, screenCorners, 4, 3);\n\t\t\t} else {\n\t\t\t\tctx.stroke();\n\t\t\t}\n\n\t\t\tctx.restore();\n\t\t\treturn;\n\t\t}\n\n\t\tconst left = clamp(cx + safeBounds[0] * sx, cx, cx + cw);\n\t\tconst top = clamp(cy + safeBounds[1] * sy, cy, cy + ch);\n\t\tconst right = clamp(cx + safeBounds[2] * sx, cx, cx + cw);\n\t\tconst bottom = clamp(cy + safeBounds[3] * sy, cy, cy + ch);\n\t\tconst rectW = Math.max(1, right - left);\n\t\tconst rectH = Math.max(1, bottom - top);\n\n\t\tctx.fillStyle = viewportFillColor;\n\t\tctx.fillRect(left, top, rectW, rectH);\n\n\t\tctx.strokeStyle = viewportBorderColor;\n\t\tctx.lineWidth = 2.25;\n\t\tif (isDash) {\n\t\t\tconst rectCorners: Array<[number, number]> = [\n\t\t\t\t[left + 0.5, top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t\t[left + 0.5, top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t];\n\t\t\tstrokeSymmetricDashedPolygon(ctx, rectCorners, 4, 3);\n\t\t} else {\n\t\t\tctx.strokeRect(\n\t\t\t\tleft + 0.5,\n\t\t\t\ttop + 0.5,\n\t\t\t\tMath.max(1, rectW - 1),\n\t\t\t\tMath.max(1, rectH - 1),\n\t\t\t);\n\t\t}\n\t}, [\n\t\twidth,\n\t\theight,\n\t\tcontentRect,\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tborderWidth,\n\t\tprojectorRef,\n\t\tsource.width,\n\t\tsource.height,\n\t\tviewportFillColor,\n\t\tviewportBorderColor,\n\t\tviewportBorderStyle,\n\t]);\n\n\tconst requestDraw = useCallback(() => {\n\t\tif (drawPendingRef.current) return;\n\t\tdrawPendingRef.current = true;\n\t\trafRef.current = requestAnimationFrame(() => {\n\t\t\tdrawPendingRef.current = false;\n\t\t\trafRef.current = null;\n\t\t\tdraw();\n\t\t});\n\t}, [draw]);\n\n\tconst toWorldFromClient = useCallback(\n\t\t(clientX: number, clientY: number): [number, number] | null => {\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return null;\n\n\t\t\tconst rect = canvas.getBoundingClientRect();\n\t\t\tif (!rect.width || !rect.height) return null;\n\n\t\t\tconst scaleX = rect.width / width;\n\t\t\tconst scaleY = rect.height / height;\n\t\t\tconst cxPx = contentRect.x * scaleX;\n\t\t\tconst cyPx = contentRect.y * scaleY;\n\t\t\tconst cwPx = contentRect.w * scaleX;\n\t\t\tconst chPx = contentRect.h * scaleY;\n\n\t\t\tconst nx = clamp((clientX - rect.left - cxPx) / cwPx, 0, 1);\n\t\t\tconst ny = clamp((clientY - rect.top - cyPx) / chPx, 0, 1);\n\t\t\treturn [nx * source.width, ny * source.height];\n\t\t},\n\t\t[source.width, source.height, width, height, contentRect],\n\t);\n\n\tconst recenterTo = useCallback(\n\t\t(worldX: number, worldY: number) => {\n\t\t\tconst projector = projectorRef.current;\n\t\t\tif (!projector) return;\n\n\t\t\tif (projector.setViewCenter) {\n\t\t\t\tprojector.setViewCenter(worldX, worldY);\n\t\t\t\trequestDraw();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bounds = projector.getViewBounds?.();\n\t\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t\t? bounds\n\t\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t\t? lastBoundsRef.current\n\t\t\t\t\t: null;\n\t\t\tif (!safeBounds) return;\n\n\t\t\tconst visibleW = Math.max(1e-6, safeBounds[2] - safeBounds[0]);\n\t\t\tconst visibleH = Math.max(1e-6, safeBounds[3] - safeBounds[1]);\n\n\t\t\tprojector.setViewState({\n\t\t\t\toffsetX: worldX - visibleW * 0.5,\n\t\t\t\toffsetY: worldY - visibleH * 0.5,\n\t\t\t});\n\t\t\trequestDraw();\n\t\t},\n\t\t[projectorRef, requestDraw],\n\t);\n\n\tconst handlePointerDown = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tif (!interactive) return;\n\t\t\tif (event.button !== 0) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tcanvas.setPointerCapture(event.pointerId);\n\t\t\tdraggingRef.current = { active: true, pointerId: event.pointerId };\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[interactive, toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerMove = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerUp = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (canvas && canvas.hasPointerCapture(event.pointerId)) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.releasePointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\trequestDraw();\n\t\t},\n\t\t[requestDraw],\n\t);\n\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\t\tthumbnailRef.current = null;\n\t\trequestDraw();\n\n\t\tconst tier = 0;\n\t\tconst levelScale = 2 ** (source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(source.height / levelScale);\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / source.tileSize));\n\t\tconst tileCount = tilesX * tilesY;\n\n\t\tif (!showThumbnail || tileCount > maxThumbnailTiles) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst preview = document.createElement(\"canvas\");\n\t\tpreview.width = Math.max(1, Math.round(contentRect.w));\n\t\tpreview.height = Math.max(1, Math.round(contentRect.h));\n\t\tconst ctx = preview.getContext(\"2d\");\n\t\tif (!ctx) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, preview.width, preview.height);\n\n\t\tconst requests: Array<{\n\t\t\turl: string;\n\t\t\tbounds: Bounds;\n\t\t}> = [];\n\n\t\tfor (let y = 0; y < tilesY; y += 1) {\n\t\t\tfor (let x = 0; x < tilesX; x += 1) {\n\t\t\t\tconst left = x * source.tileSize * levelScale;\n\t\t\t\tconst top = y * source.tileSize * levelScale;\n\t\t\t\tconst right =\n\t\t\t\t\tMath.min((x + 1) * source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom =\n\t\t\t\t\tMath.min((y + 1) * source.tileSize, levelHeight) * levelScale;\n\t\t\t\trequests.push({\n\t\t\t\t\turl: toTileUrl(source, tier, x, y),\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvoid Promise.allSettled(\n\t\t\trequests.map(async (tile) => {\n\t\t\t\tconst useAuthHeader = !!authToken;\n\t\t\t\tconst response = await fetch(tile.url, {\n\t\t\t\t\theaders: useAuthHeader ? { Authorization: authToken } : undefined,\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\tconst bitmap = await createImageBitmap(await response.blob());\n\t\t\t\treturn { tile, bitmap };\n\t\t\t}),\n\t\t).then((results) => {\n\t\t\tif (cancelled) {\n\t\t\t\tfor (const result of results) {\n\t\t\t\t\tif (result.status === \"fulfilled\") {\n\t\t\t\t\t\tresult.value.bitmap.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst sx = preview.width / Math.max(1, source.width);\n\t\t\tconst sy = preview.height / Math.max(1, source.height);\n\t\t\tfor (const result of results) {\n\t\t\t\tif (result.status !== \"fulfilled\") continue;\n\t\t\t\tconst {\n\t\t\t\t\ttile: { bounds },\n\t\t\t\t\tbitmap,\n\t\t\t\t} = result.value;\n\t\t\t\tconst dx = bounds[0] * sx;\n\t\t\t\tconst dy = bounds[1] * sy;\n\t\t\t\tconst dw = Math.max(1, (bounds[2] - bounds[0]) * sx);\n\t\t\t\tconst dh = Math.max(1, (bounds[3] - bounds[1]) * sy);\n\t\t\t\tctx.drawImage(bitmap, dx, dy, dw, dh);\n\t\t\t\tbitmap.close();\n\t\t\t}\n\n\t\t\tthumbnailRef.current = preview;\n\t\t\trequestDraw();\n\t\t});\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [\n\t\tsource,\n\t\tauthToken,\n\t\tcontentRect,\n\t\tbackgroundColor,\n\t\tshowThumbnail,\n\t\tmaxThumbnailTiles,\n\t\trequestDraw,\n\t]);\n\n\tuseEffect(() => {\n\t\trequestDraw();\n\t}, [requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!invalidateRef) return undefined;\n\t\tinvalidateRef.current = requestDraw;\n\t\treturn () => {\n\t\t\tif (invalidateRef.current === requestDraw) {\n\t\t\t\tinvalidateRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [invalidateRef, requestDraw]);\n\n\tuseEffect(\n\t\t() => () => {\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\tif (rafRef.current !== null) {\n\t\t\t\tcancelAnimationFrame(rafRef.current);\n\t\t\t\trafRef.current = null;\n\t\t\t}\n\t\t\tdrawPendingRef.current = false;\n\t\t},\n\t\t[],\n\t);\n\n\treturn (\n\t\t<div className={className} style={mergedStyle}>\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\tdisplay: \"block\",\n\t\t\t\t\tborderRadius: \"inherit\",\n\t\t\t\t}}\n\t\t\t\tonPointerDown={handlePointerDown}\n\t\t\t\tonPointerMove={handlePointerMove}\n\t\t\t\tonPointerUp={handlePointerUp}\n\t\t\t\tonPointerCancel={handlePointerUp}\n\t\t\t\tonContextMenu={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}}\n\t\t\t\tonWheel={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{onClose && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Hide overview map\"\n\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\tonClose();\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={closeButtonStyle\n\t\t\t\t\t\t? {...closeButtonStyle as CSSProperties}\n\t\t\t\t\t\t: { ...DEFAULT_CLOSE_BUTTON_STYLE as CSSProperties }\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{closeIcon ?? \"×\"}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","import { type CSSProperties, useEffect, useMemo, useRef } from \"react\";\nimport { M1TileRenderer } from \"../core/m1-tile-renderer\";\nimport type { ViewState } from \"../core/ortho-camera\";\nimport type { TileDefinition } from \"../core/types\";\n\nexport interface TileViewerCanvasProps {\n\timageWidth: number;\n\timageHeight: number;\n\ttiles: TileDefinition[];\n\tviewState?: Partial<ViewState>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nexport function TileViewerCanvas({\n\timageWidth,\n\timageHeight,\n\ttiles,\n\tviewState,\n\tclassName,\n\tstyle,\n}: TileViewerCanvasProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst rendererRef = useRef<M1TileRenderer | null>(null);\n\tconst mergedStyle = useMemo(\n\t\t() => ({ width: \"100%\", height: \"100%\", display: \"block\", ...style }),\n\t\t[style],\n\t);\n\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst renderer = new M1TileRenderer({\n\t\t\tcanvas,\n\t\t\timageWidth,\n\t\t\timageHeight,\n\t\t\tinitialViewState: viewState,\n\t\t});\n\n\t\trendererRef.current = renderer;\n\t\tvoid renderer.setTiles(tiles);\n\n\t\treturn () => {\n\t\t\trenderer.destroy();\n\t\t\trendererRef.current = null;\n\t\t};\n\t}, [imageWidth, imageHeight]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid renderer.setTiles(tiles);\n\t}, [tiles]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer || !viewState) {\n\t\t\treturn;\n\t\t}\n\n\t\trenderer.setViewState(viewState);\n\t}, [viewState]);\n\n\treturn <canvas ref={canvasRef} className={className} style={mergedStyle} />;\n}\n","import { pointInAnyPreparedPolygon, prepareRoiPolygons, type RoiCoordinate, type RoiGeometry } from \"./roi-geometry\";\nimport type { WsiPointData } from \"./types\";\nimport { sanitizePointCount } from \"./utils\";\n\nexport type { RoiCoordinate };\nexport type RoiPolygon = RoiGeometry;\n\nexport function filterPointDataByPolygons(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): WsiPointData | null {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const prepared = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n const empty: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointData.fillModes instanceof Uint8Array) {\n empty.fillModes = new Uint8Array(0);\n }\n if (pointData.ids instanceof Uint32Array) {\n empty.ids = new Uint32Array(0);\n }\n return empty;\n }\n\n const count = sanitizePointCount(pointData);\n const positions = pointData.positions;\n const terms = pointData.paletteIndices;\n const fillModes = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= count ? pointData.fillModes : null;\n const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= count ? pointData.ids : null;\n\n const nextPositions = new Float32Array(count * 2);\n const nextTerms = new Uint16Array(count);\n const nextFillModes = fillModes ? new Uint8Array(count) : null;\n const nextIds = pointIds ? new Uint32Array(count) : null;\n let cursor = 0;\n\n for (let i = 0; i < count; i += 1) {\n const x = positions[i * 2];\n const y = positions[i * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = terms[i];\n if (nextFillModes) {\n nextFillModes[cursor] = fillModes![i];\n }\n if (nextIds) {\n nextIds[cursor] = pointIds![i];\n }\n cursor += 1;\n }\n\n const output: WsiPointData = {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n };\n if (nextFillModes) {\n output.fillModes = nextFillModes.subarray(0, cursor);\n }\n if (nextIds) {\n output.ids = nextIds.subarray(0, cursor);\n }\n return output;\n}\n\nexport function filterPointIndicesByPolygons(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Uint32Array {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return new Uint32Array(0);\n }\n\n const prepared = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n return new Uint32Array(0);\n }\n\n const count = sanitizePointCount(pointData);\n if (count === 0) {\n return new Uint32Array(0);\n }\n\n const positions = pointData.positions;\n const out = new Uint32Array(count);\n let cursor = 0;\n\n for (let i = 0; i < count; i += 1) {\n const x = positions[i * 2];\n const y = positions[i * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n out[cursor] = i;\n cursor += 1;\n }\n\n return out.subarray(0, cursor);\n}\n","export interface WebGpuCapabilities {\n\tsupported: boolean;\n\tadapterName?: string;\n\tfeatures: string[];\n\tlimits?: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n}\n\ninterface NavigatorGpuLike {\n\trequestAdapter: () => Promise<GpuAdapterLike | null>;\n}\n\ninterface GpuAdapterLike {\n\tinfo?: {\n\t\tdescription?: string;\n\t\tvendor?: string;\n\t};\n\tfeatures: Iterable<string>;\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n\trequestDevice: () => Promise<GpuDeviceLike>;\n}\n\ninterface GpuBufferLike {\n\tdestroy: () => void;\n\tmapAsync: (mode: number) => Promise<void>;\n\tgetMappedRange: () => ArrayBuffer;\n\tunmap: () => void;\n}\n\ninterface GpuComputePassLike {\n\tsetPipeline: (pipeline: GpuComputePipelineLike) => void;\n\tsetBindGroup: (index: number, bindGroup: unknown) => void;\n\tdispatchWorkgroups: (x: number, y?: number, z?: number) => void;\n\tend: () => void;\n}\n\ninterface GpuCommandEncoderLike {\n\tbeginComputePass: () => GpuComputePassLike;\n\tcopyBufferToBuffer: (\n\t\tsource: GpuBufferLike,\n\t\tsourceOffset: number,\n\t\tdestination: GpuBufferLike,\n\t\tdestinationOffset: number,\n\t\tsize: number,\n\t) => void;\n\tfinish: () => unknown;\n}\n\ninterface GpuQueueLike {\n\twriteBuffer: (\n\t\tbuffer: GpuBufferLike,\n\t\tbufferOffset: number,\n\t\tdata: ArrayBufferView | ArrayBufferLike,\n\t\tdataOffset?: number,\n\t\tsize?: number,\n\t) => void;\n\tsubmit: (commands: unknown[]) => void;\n}\n\ninterface GpuComputePipelineLike {\n\treadonly _brand?: \"GpuComputePipelineLike\";\n}\n\ninterface GpuBindGroupLayoutLike {\n\treadonly _brand?: \"GpuBindGroupLayoutLike\";\n}\n\ninterface GpuDeviceLike {\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t};\n\tqueue: GpuQueueLike;\n\tcreateBindGroupLayout: (descriptor: unknown) => GpuBindGroupLayoutLike;\n\tcreatePipelineLayout: (descriptor: unknown) => unknown;\n\tcreateShaderModule: (descriptor: { code: string }) => unknown;\n\tcreateComputePipeline: (descriptor: unknown) => GpuComputePipelineLike;\n\tcreateBuffer: (descriptor: { size: number; usage: number }) => GpuBufferLike;\n\tcreateBindGroup: (descriptor: unknown) => unknown;\n\tcreateCommandEncoder: () => GpuCommandEncoderLike;\n}\n\ninterface WebGpuContext {\n\tdevice: GpuDeviceLike;\n\tpipeline: GpuComputePipelineLike;\n\tbindGroupLayout: GpuBindGroupLayoutLike;\n}\n\nlet contextPromise: Promise<WebGpuContext | null> | null = null;\n\nconst BBOX_PREFILTER_SHADER = `\nstruct Params {\n pointCount: u32,\n boundsCount: u32,\n _pad0: u32,\n _pad1: u32,\n};\n\n@group(0) @binding(0) var<storage, read> positions: array<vec2<f32>>;\n@group(0) @binding(1) var<storage, read> bounds: array<vec4<f32>>;\n@group(0) @binding(2) var<storage, read_write> outputMask: array<u32>;\n@group(0) @binding(3) var<uniform> params: Params;\n\n@compute @workgroup_size(256)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let i = gid.x;\n if (i >= params.pointCount) {\n return;\n }\n\n let p = positions[i];\n var inside: u32 = 0u;\n for (var bi: u32 = 0u; bi < params.boundsCount; bi = bi + 1u) {\n let b = bounds[bi];\n if (p.x >= b.x && p.x <= b.z && p.y >= b.y && p.y <= b.w) {\n inside = 1u;\n break;\n }\n }\n outputMask[i] = inside;\n}\n`;\n\nfunction hasWebGpu(): boolean {\n\tif (typeof navigator === \"undefined\") return false;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\treturn typeof nav.gpu === \"object\" && nav.gpu !== null;\n}\n\nfunction getNavigatorGpu(): NavigatorGpuLike | null {\n\tif (!hasWebGpu()) return null;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\tconst gpu = nav.gpu;\n\tif (!gpu || typeof gpu !== \"object\") return null;\n\tconst candidate = gpu as Partial<NavigatorGpuLike>;\n\tif (typeof candidate.requestAdapter !== \"function\") return null;\n\treturn candidate as NavigatorGpuLike;\n}\n\nconst GPU_SHADER_STAGE_COMPUTE =\n\t(globalThis as { GPUShaderStage?: { COMPUTE?: number } }).GPUShaderStage\n\t\t?.COMPUTE ?? 0x4;\nconst GPU_BUFFER_USAGE_STORAGE =\n\t(globalThis as { GPUBufferUsage?: { STORAGE?: number } }).GPUBufferUsage\n\t\t?.STORAGE ?? 0x80;\nconst GPU_BUFFER_USAGE_COPY_DST =\n\t(globalThis as { GPUBufferUsage?: { COPY_DST?: number } }).GPUBufferUsage\n\t\t?.COPY_DST ?? 0x08;\nconst GPU_BUFFER_USAGE_COPY_SRC =\n\t(globalThis as { GPUBufferUsage?: { COPY_SRC?: number } }).GPUBufferUsage\n\t\t?.COPY_SRC ?? 0x04;\nconst GPU_BUFFER_USAGE_UNIFORM =\n\t(globalThis as { GPUBufferUsage?: { UNIFORM?: number } }).GPUBufferUsage\n\t\t?.UNIFORM ?? 0x40;\nconst GPU_BUFFER_USAGE_MAP_READ =\n\t(globalThis as { GPUBufferUsage?: { MAP_READ?: number } }).GPUBufferUsage\n\t\t?.MAP_READ ?? 0x01;\nconst GPU_MAP_MODE_READ =\n\t(globalThis as { GPUMapMode?: { READ?: number } }).GPUMapMode?.READ ?? 0x01;\n\nexport async function getWebGpuCapabilities(): Promise<WebGpuCapabilities> {\n\tconst navGpu = getNavigatorGpu();\n\tif (!navGpu) {\n\t\treturn { supported: false, features: [] };\n\t}\n\tconst adapter = await navGpu.requestAdapter();\n\tif (!adapter) {\n\t\treturn { supported: false, features: [] };\n\t}\n\n\treturn {\n\t\tsupported: true,\n\t\tadapterName: adapter.info?.description ?? adapter.info?.vendor ?? \"unknown\",\n\t\tfeatures: Array.from(adapter.features),\n\t\tlimits: {\n\t\t\tmaxStorageBufferBindingSize: Number(\n\t\t\t\tadapter.limits.maxStorageBufferBindingSize,\n\t\t\t),\n\t\t\tmaxComputeInvocationsPerWorkgroup: Number(\n\t\t\t\tadapter.limits.maxComputeInvocationsPerWorkgroup,\n\t\t\t),\n\t\t\tmaxComputeWorkgroupSizeX: Number(adapter.limits.maxComputeWorkgroupSizeX),\n\t\t},\n\t};\n}\n\nasync function getContext(): Promise<WebGpuContext | null> {\n\tif (contextPromise) return contextPromise;\n\tcontextPromise = (async () => {\n\t\tconst navGpu = getNavigatorGpu();\n\t\tif (!navGpu) return null;\n\t\tconst adapter = await navGpu.requestAdapter();\n\t\tif (!adapter) return null;\n\t\tconst device = await adapter.requestDevice();\n\n\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: [\n\t\t\t\t{\n\t\t\t\t\tbinding: 0,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 1,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 2,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 3,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"uniform\" },\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tconst pipeline = device.createComputePipeline({\n\t\t\tlayout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }),\n\t\t\tcompute: {\n\t\t\t\tmodule: device.createShaderModule({ code: BBOX_PREFILTER_SHADER }),\n\t\t\t\tentryPoint: \"main\",\n\t\t\t},\n\t\t});\n\n\t\treturn { device, pipeline, bindGroupLayout };\n\t})();\n\n\treturn contextPromise;\n}\n\nfunction align(value: number, step: number): number {\n\treturn Math.ceil(value / step) * step;\n}\n\nexport async function prefilterPointsByBoundsWebGpu(\n\tpositions: Float32Array,\n\tpointCount: number,\n\tbounds: Float32Array,\n): Promise<Uint32Array | null> {\n\tconst ctx = await getContext();\n\tif (!ctx) return null;\n\n\tconst count = Math.max(0, Math.floor(pointCount));\n\tconst boundsCount = Math.max(0, Math.floor(bounds.length / 4));\n\tif (count === 0 || boundsCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst safePointCount = Math.min(count, Math.floor(positions.length / 2));\n\tif (safePointCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst positionBytes = safePointCount * 2 * Float32Array.BYTES_PER_ELEMENT;\n\tconst boundsBytes = boundsCount * 4 * Float32Array.BYTES_PER_ELEMENT;\n\tconst outputBytes = safePointCount * Uint32Array.BYTES_PER_ELEMENT;\n\n\tconst limit = Number(ctx.device.limits.maxStorageBufferBindingSize);\n\tif (positionBytes > limit || boundsBytes > limit || outputBytes > limit) {\n\t\treturn null;\n\t}\n\n\tconst positionsBuffer = ctx.device.createBuffer({\n\t\tsize: align(positionBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst boundsBuffer = ctx.device.createBuffer({\n\t\tsize: align(boundsBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst outputBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_SRC,\n\t});\n\tconst uniformBuffer = ctx.device.createBuffer({\n\t\tsize: 16,\n\t\tusage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst readBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,\n\t});\n\n\tctx.device.queue.writeBuffer(\n\t\tpositionsBuffer,\n\t\t0,\n\t\tpositions.buffer,\n\t\tpositions.byteOffset,\n\t\tpositionBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tboundsBuffer,\n\t\t0,\n\t\tbounds.buffer,\n\t\tbounds.byteOffset,\n\t\tboundsBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tuniformBuffer,\n\t\t0,\n\t\tnew Uint32Array([safePointCount, boundsCount, 0, 0]),\n\t);\n\n\tconst bindGroup = ctx.device.createBindGroup({\n\t\tlayout: ctx.bindGroupLayout,\n\t\tentries: [\n\t\t\t{ binding: 0, resource: { buffer: positionsBuffer } },\n\t\t\t{ binding: 1, resource: { buffer: boundsBuffer } },\n\t\t\t{ binding: 2, resource: { buffer: outputBuffer } },\n\t\t\t{ binding: 3, resource: { buffer: uniformBuffer } },\n\t\t],\n\t});\n\n\tconst commandEncoder = ctx.device.createCommandEncoder();\n\tconst pass = commandEncoder.beginComputePass();\n\tpass.setPipeline(ctx.pipeline);\n\tpass.setBindGroup(0, bindGroup);\n\tpass.dispatchWorkgroups(Math.ceil(safePointCount / 256));\n\tpass.end();\n\n\tcommandEncoder.copyBufferToBuffer(outputBuffer, 0, readBuffer, 0, outputBytes);\n\tctx.device.queue.submit([commandEncoder.finish()]);\n\n\tawait readBuffer.mapAsync(GPU_MAP_MODE_READ);\n\tconst mapped = readBuffer.getMappedRange();\n\tconst out = new Uint32Array(mapped.slice(0));\n\treadBuffer.unmap();\n\n\tpositionsBuffer.destroy();\n\tboundsBuffer.destroy();\n\toutputBuffer.destroy();\n\tuniformBuffer.destroy();\n\treadBuffer.destroy();\n\n\treturn out;\n}\n","import { filterPointDataByPolygons, type RoiPolygon } from \"./point-clip\";\nimport {\n pointInAnyPreparedPolygon,\n prepareRoiPolygons,\n} from \"./roi-geometry\";\nimport type { WsiPointData } from \"./types\";\nimport { nowMs, sanitizePointCount } from \"./utils\";\nimport { prefilterPointsByBoundsWebGpu } from \"./webgpu\";\n\nexport interface HybridPointClipOptions {\n bridgeToDraw?: boolean;\n}\n\nexport interface HybridPointClipResult {\n data: WsiPointData | null;\n meta: {\n mode: \"hybrid-webgpu\";\n durationMs: number;\n usedWebGpu: boolean;\n candidateCount: number;\n bridgedToDraw?: boolean;\n };\n}\n\nexport async function filterPointDataByPolygonsHybrid(\n pointData: WsiPointData | null | undefined,\n polygons: RoiPolygon[] | null | undefined,\n options: HybridPointClipOptions = {}\n): Promise<HybridPointClipResult> {\n const start = nowMs();\n const bridgeToDraw = options.bridgeToDraw === true;\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const prepared = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointData.fillModes instanceof Uint8Array) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointData.ids instanceof Uint32Array) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const safeCount = sanitizePointCount(pointData);\n const pointFillModes = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes : null;\n const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids : null;\n if (safeCount === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const bboxFlat = new Float32Array(prepared.length * 4);\n for (let i = 0; i < prepared.length; i += 1) {\n const base = i * 4;\n const polygon = prepared[i];\n bboxFlat[base] = polygon.minX;\n bboxFlat[base + 1] = polygon.minY;\n bboxFlat[base + 2] = polygon.maxX;\n bboxFlat[base + 3] = polygon.maxY;\n }\n\n let candidateMask: Uint32Array | null = null;\n let usedWebGpu = false;\n try {\n candidateMask = await prefilterPointsByBoundsWebGpu(pointData.positions, safeCount, bboxFlat);\n usedWebGpu = !!candidateMask;\n } catch {\n candidateMask = null;\n usedWebGpu = false;\n }\n\n if (!candidateMask) {\n const fallback = filterPointDataByPolygons(pointData, polygons);\n return {\n data: fallback,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: safeCount,\n bridgedToDraw: false,\n },\n };\n }\n\n let candidateCount = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] === 1) candidateCount += 1;\n }\n\n const candidateIndices = new Uint32Array(candidateCount);\n if (candidateCount > 0) {\n let candidateCursor = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] !== 1) continue;\n candidateIndices[candidateCursor] = i;\n candidateCursor += 1;\n }\n }\n\n if (candidateCount === 0) {\n if (bridgeToDraw) {\n const data: WsiPointData = {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: new Uint32Array(0),\n };\n if (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\n }\n if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: true,\n },\n };\n }\n\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n if (bridgeToDraw) {\n const drawIndices = new Uint32Array(candidateCount);\n let visibleCount = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n drawIndices[visibleCount] = pointIndex;\n visibleCount += 1;\n }\n\n const data: WsiPointData = {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: drawIndices.subarray(0, visibleCount),\n };\n if (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\n }\n if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: true,\n },\n };\n }\n\n const nextPositions = new Float32Array(candidateCount * 2);\n const nextTerms = new Uint16Array(candidateCount);\n const nextFillModes = pointFillModes ? new Uint8Array(candidateCount) : null;\n const nextIds = pointIds ? new Uint32Array(candidateCount) : null;\n let cursor = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = pointData.paletteIndices[pointIndex];\n if (nextFillModes) {\n nextFillModes[cursor] = pointFillModes![pointIndex];\n }\n if (nextIds) {\n nextIds[cursor] = pointIds![pointIndex];\n }\n cursor += 1;\n }\n\n const compactData: WsiPointData = {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n };\n if (nextFillModes) {\n compactData.fillModes = nextFillModes.subarray(0, cursor);\n }\n if (nextIds) {\n compactData.ids = nextIds.subarray(0, cursor);\n }\n\n return {\n data: compactData,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: false,\n },\n };\n}\n","export interface WorkerClientHandlers<Res extends { id: number }, Pending> {\n onResponse: (message: Res, pending: Pending) => void;\n rejectPending: (pending: Pending, error: Error) => void;\n}\n\nexport class WorkerClient<Res extends { id: number }, Pending> {\n private worker: Worker | null = null;\n private supported = true;\n private requestId = 1;\n private readonly pendingById = new Map<number, Pending>();\n\n private readonly handleMessage = (event: MessageEvent<Res>): void => {\n const message = event.data;\n if (!message) return;\n const pending = this.pendingById.get(message.id);\n if (!pending) return;\n this.pendingById.delete(message.id);\n this.handlers.onResponse(message, pending);\n };\n\n private readonly handleError = (): void => {\n this.supported = false;\n this.teardownWorker(\"worker crashed\");\n };\n\n constructor(\n private readonly createWorker: () => Worker,\n private readonly handlers: WorkerClientHandlers<Res, Pending>,\n ) {}\n\n beginRequest(pending: Pending): { id: number; worker: Worker } | null {\n const worker = this.getOrCreateWorker();\n if (!worker) return null;\n const id = this.requestId++;\n this.pendingById.set(id, pending);\n return { id, worker };\n }\n\n cancelRequest(id: number): Pending | undefined {\n const pending = this.pendingById.get(id);\n if (!pending) return undefined;\n this.pendingById.delete(id);\n return pending;\n }\n\n terminate(reason = \"worker terminated\"): void {\n this.teardownWorker(reason);\n }\n\n private getOrCreateWorker(): Worker | null {\n if (!this.supported) return null;\n if (this.worker) return this.worker;\n\n try {\n const worker = this.createWorker();\n worker.addEventListener(\"message\", this.handleMessage);\n worker.addEventListener(\"error\", this.handleError);\n this.worker = worker;\n return worker;\n } catch {\n this.supported = false;\n return null;\n }\n }\n\n private teardownWorker(reason: string): void {\n if (this.worker) {\n this.worker.removeEventListener(\"message\", this.handleMessage);\n this.worker.removeEventListener(\"error\", this.handleError);\n this.worker.terminate();\n this.worker = null;\n }\n\n const error = new Error(reason);\n for (const [, pending] of this.pendingById) {\n this.handlers.rejectPending(pending, error);\n }\n this.pendingById.clear();\n }\n}\n","import { filterPointDataByPolygons, filterPointIndicesByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { RoiClipWorkerRequest, RoiClipWorkerResponse } from \"./point-clip-worker-protocol\";\nimport type { WsiPointData } from \"./types\";\nimport { nowMs, sanitizePointCount } from \"./utils\";\nimport { WorkerClient } from \"./worker-client\";\n\nexport type PointClipMode = \"sync\" | \"worker\" | \"hybrid-webgpu\";\n\nexport interface PointClipResultMeta {\n mode: PointClipMode;\n durationMs: number;\n}\n\nexport interface PointClipResult {\n data: WsiPointData | null;\n meta: PointClipResultMeta;\n}\n\nexport interface PointClipIndexResult {\n indices: Uint32Array;\n meta: PointClipResultMeta;\n}\n\ninterface PendingDataWorkerRequest {\n kind: \"data\";\n resolve: (result: PointClipResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\ninterface PendingIndexWorkerRequest {\n kind: \"index\";\n resolve: (result: PointClipIndexResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\ntype PendingWorkerRequest = PendingDataWorkerRequest | PendingIndexWorkerRequest;\n\nconst workerClient = new WorkerClient<RoiClipWorkerResponse, PendingWorkerRequest>(\n () => new Worker(new URL(\"../workers/roi-clip-worker.ts\", import.meta.url), { type: \"module\" }),\n {\n onResponse: (msg, pending) => {\n if (msg.type === \"roi-clip-failure\") {\n pending.reject(new Error(msg.error || \"worker clip failed\"));\n return;\n }\n\n if (msg.type === \"roi-clip-index-success\") {\n if (pending.kind !== \"index\") {\n pending.reject(new Error(\"worker response mismatch: expected point data result\"));\n return;\n }\n const count = Math.max(0, Math.floor(msg.count));\n const indices = new Uint32Array(msg.indices).subarray(0, count);\n pending.resolve({\n indices,\n meta: {\n mode: \"worker\",\n durationMs:\n Number.isFinite(msg.durationMs)\n ? msg.durationMs\n : nowMs() - pending.startMs,\n },\n });\n return;\n }\n\n if (pending.kind !== \"data\") {\n pending.reject(new Error(\"worker response mismatch: expected index result\"));\n return;\n }\n\n const count = Math.max(0, Math.floor(msg.count));\n const positions = new Float32Array(msg.positions);\n const paletteIndices = new Uint16Array(msg.paletteIndices);\n const fillModes = msg.fillModes ? new Uint8Array(msg.fillModes) : null;\n const ids = msg.ids ? new Uint32Array(msg.ids) : null;\n const output: WsiPointData = {\n count,\n positions: positions.subarray(0, count * 2),\n paletteIndices: paletteIndices.subarray(0, count),\n };\n if (fillModes) {\n output.fillModes = fillModes.subarray(0, count);\n }\n if (ids) {\n output.ids = ids.subarray(0, count);\n }\n\n pending.resolve({\n data: output,\n meta: {\n mode: \"worker\",\n durationMs:\n Number.isFinite(msg.durationMs)\n ? msg.durationMs\n : nowMs() - pending.startMs,\n },\n });\n },\n rejectPending: (pending, error) => {\n pending.reject(error);\n },\n },\n);\n\nexport function terminateRoiClipWorker(): void {\n workerClient.terminate(\"worker terminated\");\n}\n\nexport async function filterPointDataByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const safeCount = sanitizePointCount(pointData);\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const termsCopy = pointData.paletteIndices.slice(0, safeCount);\n const fillModesCopy = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes.slice(0, safeCount) : null;\n const idsCopy = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.slice(0, safeCount) : null;\n\n return new Promise<PointClipResult>((resolve, reject) => {\n const startMs = nowMs();\n const requestTicket = workerClient.beginRequest({\n kind: \"data\",\n resolve,\n reject,\n startMs,\n });\n\n if (!requestTicket) {\n resolve({\n data: filterPointDataByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - startMs },\n });\n return;\n }\n\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-request\",\n id: requestTicket.id,\n count: safeCount,\n positions: positionsCopy.buffer,\n paletteIndices: termsCopy.buffer,\n fillModes: fillModesCopy?.buffer,\n ids: idsCopy?.buffer,\n polygons: polygons ?? [],\n };\n\n const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (fillModesCopy) transfer.push(fillModesCopy.buffer);\n if (idsCopy) transfer.push(idsCopy.buffer);\n\n try {\n requestTicket.worker.postMessage(msg, transfer);\n } catch (error) {\n const canceled = workerClient.cancelRequest(requestTicket.id);\n if (canceled) {\n canceled.reject(error);\n } else {\n reject(error);\n }\n }\n });\n}\n\nexport async function filterPointIndicesByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipIndexResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n indices: new Uint32Array(0),\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const safeCount = sanitizePointCount(pointData);\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n\n return new Promise<PointClipIndexResult>((resolve, reject) => {\n const startMs = nowMs();\n const requestTicket = workerClient.beginRequest({\n kind: \"index\",\n resolve,\n reject,\n startMs,\n });\n\n if (!requestTicket) {\n resolve({\n indices: filterPointIndicesByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - startMs },\n });\n return;\n }\n\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-index-request\",\n id: requestTicket.id,\n count: safeCount,\n positions: positionsCopy.buffer,\n polygons: polygons ?? [],\n };\n\n try {\n requestTicket.worker.postMessage(msg, [positionsCopy.buffer]);\n } catch (error) {\n const canceled = workerClient.cancelRequest(requestTicket.id);\n if (canceled) {\n canceled.reject(error);\n } else {\n reject(error);\n }\n }\n });\n}\n","export const MIN_POINT_HIT_GRID_SIZE = 24;\nexport const MAX_POINT_HIT_GRID_SIZE = 1024;\nexport const POINT_HIT_GRID_DENSITY_SCALE = 4;\nexport const HASH_EMPTY = -1;\n\nexport interface PointHitIndexBuildInput {\n count: number;\n positions: Float32Array;\n drawIndices?: Uint32Array | null;\n sourceWidth: number;\n sourceHeight: number;\n}\n\nexport interface PointHitIndexBuildResult {\n cellSize: number;\n safeCount: number;\n cellCount: number;\n hashCapacity: number;\n hashTable: Int32Array;\n cellKeys: Int32Array;\n cellOffsets: Uint32Array;\n cellLengths: Uint32Array;\n pointIndices: Uint32Array;\n}\n\nexport function cellHash(cellX: number, cellY: number, mask: number): number {\n return (((cellX * 73856093) ^ (cellY * 19349663)) >>> 0) & mask;\n}\n\nfunction resolveGridSize(sourceWidth: number, sourceHeight: number, visibleCount: number): number {\n if (sourceWidth <= 0 || sourceHeight <= 0 || visibleCount <= 0) return 256;\n const area = Math.max(1, sourceWidth * sourceHeight);\n const avgSpacing = Math.sqrt(area / Math.max(1, visibleCount));\n const raw = avgSpacing * POINT_HIT_GRID_DENSITY_SCALE;\n return Math.max(MIN_POINT_HIT_GRID_SIZE, Math.min(MAX_POINT_HIT_GRID_SIZE, raw));\n}\n\nfunction sanitizeDrawIndices(raw: Uint32Array | null | undefined, safeCount: number): Uint32Array | null {\n if (!(raw instanceof Uint32Array) || raw.length === 0) {\n return null;\n }\n\n let allValid = true;\n for (let i = 0; i < raw.length; i += 1) {\n if (raw[i] < safeCount) continue;\n allValid = false;\n break;\n }\n if (allValid) {\n return raw;\n }\n\n const filtered = new Uint32Array(raw.length);\n let cursor = 0;\n for (let i = 0; i < raw.length; i += 1) {\n if (raw[i] >= safeCount) continue;\n filtered[cursor] = raw[i];\n cursor += 1;\n }\n return cursor > 0 ? filtered.subarray(0, cursor) : null;\n}\n\nexport function buildPointHitIndex(input: PointHitIndexBuildInput): PointHitIndexBuildResult | null {\n const count = Math.max(0, Math.floor(input.count));\n const maxCountByPositions = Math.floor(input.positions.length / 2);\n const safeCount = Math.max(0, Math.min(count, maxCountByPositions));\n if (safeCount <= 0) {\n return null;\n }\n\n const drawIndices = sanitizeDrawIndices(input.drawIndices ?? null, safeCount);\n const visibleCount = drawIndices ? drawIndices.length : safeCount;\n if (visibleCount === 0) {\n return null;\n }\n\n const cellSize = resolveGridSize(input.sourceWidth, input.sourceHeight, visibleCount);\n const invCellSize = 1.0 / cellSize;\n\n const pointCellX = new Int32Array(visibleCount);\n const pointCellY = new Int32Array(visibleCount);\n let validCount = 0;\n\n if (drawIndices) {\n for (let i = 0; i < visibleCount; i += 1) {\n const pi = drawIndices[i];\n const px = input.positions[pi * 2];\n const py = input.positions[pi * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n pointCellX[validCount] = Math.floor(px * invCellSize);\n pointCellY[validCount] = Math.floor(py * invCellSize);\n validCount += 1;\n }\n } else {\n for (let i = 0; i < safeCount; i += 1) {\n const px = input.positions[i * 2];\n const py = input.positions[i * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n pointCellX[validCount] = Math.floor(px * invCellSize);\n pointCellY[validCount] = Math.floor(py * invCellSize);\n validCount += 1;\n }\n }\n\n if (validCount === 0) {\n return null;\n }\n\n let estimatedCells = Math.min(validCount, Math.max(64, validCount >>> 3));\n if (!Number.isFinite(estimatedCells) || estimatedCells <= 0) {\n estimatedCells = validCount;\n }\n\n let hashCapacity = 1;\n while (hashCapacity < estimatedCells * 2) hashCapacity <<= 1;\n let hashMask = hashCapacity - 1;\n\n let tempHashKeys = new Int32Array(hashCapacity * 2);\n let tempHashCounts = new Int32Array(hashCapacity);\n tempHashKeys.fill(0x7fffffff);\n let cellCount = 0;\n\n const pointCellSlot = new Int32Array(validCount);\n\n for (let i = 0; i < validCount; i += 1) {\n const cx = pointCellX[i];\n const cy = pointCellY[i];\n let slot = cellHash(cx, cy, hashMask);\n\n while (true) {\n const kx = tempHashKeys[slot * 2];\n if (kx === 0x7fffffff) {\n tempHashKeys[slot * 2] = cx;\n tempHashKeys[slot * 2 + 1] = cy;\n tempHashCounts[slot] = 1;\n pointCellSlot[i] = slot;\n cellCount += 1;\n\n if (cellCount * 4 > hashCapacity * 3) {\n const oldCap = hashCapacity;\n hashCapacity <<= 1;\n hashMask = hashCapacity - 1;\n\n const newKeys = new Int32Array(hashCapacity * 2);\n const newCounts = new Int32Array(hashCapacity);\n newKeys.fill(0x7fffffff);\n\n for (let s = 0; s < oldCap; s += 1) {\n if (tempHashKeys[s * 2] === 0x7fffffff) continue;\n const ocx = tempHashKeys[s * 2];\n const ocy = tempHashKeys[s * 2 + 1];\n let ns = cellHash(ocx, ocy, hashMask);\n while (newKeys[ns * 2] !== 0x7fffffff) ns = (ns + 1) & hashMask;\n newKeys[ns * 2] = ocx;\n newKeys[ns * 2 + 1] = ocy;\n newCounts[ns] = tempHashCounts[s];\n }\n\n tempHashKeys = newKeys;\n tempHashCounts = newCounts;\n\n slot = cellHash(cx, cy, hashMask);\n while (\n tempHashKeys[slot * 2] !== cx ||\n tempHashKeys[slot * 2 + 1] !== cy\n ) {\n slot = (slot + 1) & hashMask;\n }\n pointCellSlot[i] = slot;\n }\n break;\n }\n\n if (kx === cx && tempHashKeys[slot * 2 + 1] === cy) {\n tempHashCounts[slot] += 1;\n pointCellSlot[i] = slot;\n break;\n }\n\n slot = (slot + 1) & hashMask;\n }\n }\n\n const cellKeys = new Int32Array(cellCount * 2);\n const cellOffsets = new Uint32Array(cellCount);\n const cellLengths = new Uint32Array(cellCount);\n const slotToCellIndex = new Int32Array(hashCapacity);\n slotToCellIndex.fill(HASH_EMPTY);\n\n let cellIdx = 0;\n let offset = 0;\n for (let s = 0; s < hashCapacity; s += 1) {\n if (tempHashKeys[s * 2] === 0x7fffffff) continue;\n cellKeys[cellIdx * 2] = tempHashKeys[s * 2];\n cellKeys[cellIdx * 2 + 1] = tempHashKeys[s * 2 + 1];\n cellOffsets[cellIdx] = offset;\n cellLengths[cellIdx] = tempHashCounts[s];\n slotToCellIndex[s] = cellIdx;\n offset += tempHashCounts[s];\n cellIdx += 1;\n }\n\n const pointIndices = new Uint32Array(validCount);\n const fillCursor = new Uint32Array(cellCount);\n fillCursor.set(cellOffsets);\n\n if (drawIndices) {\n for (let i = 0; i < validCount; i += 1) {\n const ci = slotToCellIndex[pointCellSlot[i]];\n pointIndices[fillCursor[ci]] = drawIndices[i];\n fillCursor[ci] += 1;\n }\n } else {\n let srcIdx = 0;\n for (let i = 0; i < safeCount; i += 1) {\n const px = input.positions[i * 2];\n const py = input.positions[i * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n const ci = slotToCellIndex[pointCellSlot[srcIdx]];\n pointIndices[fillCursor[ci]] = i;\n fillCursor[ci] += 1;\n srcIdx += 1;\n }\n }\n\n let finalCap = 1;\n while (finalCap < cellCount * 2) finalCap <<= 1;\n const finalMask = finalCap - 1;\n const hashTable = new Int32Array(finalCap);\n hashTable.fill(HASH_EMPTY);\n\n for (let i = 0; i < cellCount; i += 1) {\n const cx = cellKeys[i * 2];\n const cy = cellKeys[i * 2 + 1];\n let slot = cellHash(cx, cy, finalMask);\n while (hashTable[slot] !== HASH_EMPTY) slot = (slot + 1) & finalMask;\n hashTable[slot] = i;\n }\n\n return {\n cellSize,\n safeCount,\n cellCount,\n hashCapacity: finalCap,\n hashTable,\n cellKeys,\n cellOffsets,\n cellLengths,\n pointIndices,\n };\n}\n","import { HASH_EMPTY, buildPointHitIndex, cellHash } from \"./point-hit-index-shared\";\nimport type {\n PointHitIndexWorkerRequest,\n PointHitIndexWorkerResponse,\n PointHitIndexWorkerSuccess,\n} from \"./point-hit-index-worker-protocol\";\nimport type { WsiImageSource, WsiPointData } from \"./types\";\nimport { sanitizePointCount } from \"./utils\";\nimport { WorkerClient } from \"./worker-client\";\n\nexport interface FlatPointSpatialIndex {\n cellSize: number;\n safeCount: number;\n positions: Float32Array;\n ids: Uint32Array | null;\n hashCapacity: number;\n hashMask: number;\n hashTable: Int32Array;\n cellKeys: Int32Array;\n cellOffsets: Uint32Array;\n cellLengths: Uint32Array;\n pointIndices: Uint32Array;\n}\n\nexport function lookupCellIndex(\n index: FlatPointSpatialIndex,\n cellX: number,\n cellY: number,\n): number {\n const { hashTable, cellKeys, hashMask } = index;\n let slot = cellHash(cellX, cellY, hashMask);\n while (true) {\n const ci = hashTable[slot];\n if (ci === HASH_EMPTY) return -1;\n if (cellKeys[ci * 2] === cellX && cellKeys[ci * 2 + 1] === cellY) return ci;\n slot = (slot + 1) & hashMask;\n }\n}\n\ninterface PendingRequest {\n resolve: (result: FlatPointSpatialIndex | null) => void;\n reject: (reason?: unknown) => void;\n pointData: WsiPointData;\n}\n\nfunction buildFromResponse(msg: PointHitIndexWorkerSuccess, pointData: WsiPointData): FlatPointSpatialIndex | null {\n if (msg.safeCount <= 0 || msg.cellCount <= 0) return null;\n\n const safeCount = msg.safeCount;\n return {\n cellSize: msg.cellSize,\n safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n ids:\n pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount\n ? pointData.ids.subarray(0, safeCount)\n : null,\n hashCapacity: msg.hashCapacity,\n hashMask: msg.hashCapacity - 1,\n hashTable: new Int32Array(msg.hashTable),\n cellKeys: new Int32Array(msg.cellKeys),\n cellOffsets: new Uint32Array(msg.cellOffsets),\n cellLengths: new Uint32Array(msg.cellLengths),\n pointIndices: new Uint32Array(msg.pointIndices),\n };\n}\n\nconst workerClient = new WorkerClient<PointHitIndexWorkerResponse, PendingRequest>(\n () =>\n new Worker(new URL(\"../workers/point-hit-index-worker.ts\", import.meta.url), {\n type: \"module\",\n }),\n {\n onResponse: (message, pending) => {\n if (message.type === \"point-hit-index-failure\") {\n pending.reject(new Error(message.error || \"worker index build failed\"));\n return;\n }\n pending.resolve(buildFromResponse(message, pending.pointData));\n },\n rejectPending: (pending, error) => {\n pending.reject(error);\n },\n },\n);\n\nexport function terminatePointHitIndexWorker(): void {\n workerClient.terminate(\"worker terminated\");\n}\n\nfunction buildSyncFallback(\n pointData: WsiPointData,\n source: WsiImageSource | null,\n): FlatPointSpatialIndex | null {\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) return null;\n\n const positions = pointData.positions.subarray(0, safeCount * 2);\n const result = buildPointHitIndex({\n count: safeCount,\n positions,\n drawIndices:\n pointData.drawIndices instanceof Uint32Array ? pointData.drawIndices : null,\n sourceWidth: source?.width ?? 0,\n sourceHeight: source?.height ?? 0,\n });\n if (!result) return null;\n\n return {\n cellSize: result.cellSize,\n safeCount,\n positions,\n ids:\n pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount\n ? pointData.ids.subarray(0, safeCount)\n : null,\n hashCapacity: result.hashCapacity,\n hashMask: result.hashCapacity - 1,\n hashTable: result.hashTable,\n cellKeys: result.cellKeys,\n cellOffsets: result.cellOffsets,\n cellLengths: result.cellLengths,\n pointIndices: result.pointIndices,\n };\n}\n\nexport async function buildPointSpatialIndexAsync(\n pointData: WsiPointData | null | undefined,\n source: WsiImageSource | null,\n): Promise<FlatPointSpatialIndex | null> {\n if (!pointData || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) return null;\n\n return new Promise<FlatPointSpatialIndex | null>((resolve, reject) => {\n const pending: PendingRequest = {\n resolve,\n reject,\n pointData,\n };\n const requestTicket = workerClient.beginRequest(pending);\n if (!requestTicket || !requestTicket.worker) {\n resolve(buildSyncFallback(pointData, source));\n return;\n }\n\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const drawIndicesCopy =\n pointData.drawIndices instanceof Uint32Array &&\n pointData.drawIndices.length > 0\n ? pointData.drawIndices.slice()\n : undefined;\n\n const msg: PointHitIndexWorkerRequest = {\n type: \"point-hit-index-request\",\n id: requestTicket.id,\n count: safeCount,\n positions: positionsCopy.buffer,\n drawIndices: drawIndicesCopy?.buffer,\n sourceWidth: source?.width ?? 0,\n sourceHeight: source?.height ?? 0,\n };\n const transfer: Transferable[] = [positionsCopy.buffer];\n if (drawIndicesCopy) transfer.push(drawIndicesCopy.buffer);\n\n try {\n requestTicket.worker.postMessage(msg, transfer);\n } catch (error) {\n const canceled = workerClient.cancelRequest(requestTicket.id);\n if (canceled) {\n canceled.reject(error);\n } else {\n reject(error);\n }\n }\n });\n}\n","import { type PreparedRoiPolygon, pointInPreparedPolygon, prepareRoiPolygons, toRoiGeometry } from \"./roi-geometry\";\nimport type { WsiPointData, WsiRegion } from \"./types\";\n\nexport interface RoiTermCount {\n termId: string;\n paletteIndex: number;\n count: number;\n}\n\nexport interface RoiPointGroup {\n regionId: string | number;\n regionIndex: number;\n totalCount: number;\n termCounts: RoiTermCount[];\n}\n\nexport interface RoiPointGroupOptions {\n paletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n includeEmptyRegions?: boolean;\n}\n\nexport interface RoiPointGroupStats {\n groups: RoiPointGroup[];\n inputPointCount: number;\n pointsInsideAnyRegion: number;\n unmatchedPointCount: number;\n}\n\ninterface PreparedRegion {\n regionId: string | number;\n regionIndex: number;\n polygons: PreparedRoiPolygon[];\n area: number;\n}\n\nfunction prepareRegions(regions: readonly WsiRegion[]): PreparedRegion[] {\n const prepared: PreparedRegion[] = [];\n for (let i = 0; i < regions.length; i += 1) {\n const region = regions[i];\n const polygons = prepareRoiPolygons([toRoiGeometry(region?.coordinates)]);\n if (polygons.length === 0) continue;\n\n let area = 0;\n for (const polygon of polygons) {\n area += polygon.area;\n }\n\n prepared.push({\n regionId: region.id ?? i,\n regionIndex: i,\n polygons,\n area: Math.max(1e-6, area),\n });\n }\n return prepared;\n}\n\nfunction resolveTermId(paletteIndex: number, paletteIndexToTermId: RoiPointGroupOptions[\"paletteIndexToTermId\"]): string {\n if (Array.isArray(paletteIndexToTermId)) {\n const fromArray = paletteIndexToTermId[paletteIndex];\n if (typeof fromArray === \"string\" && fromArray.length > 0) return fromArray;\n }\n if (paletteIndexToTermId instanceof Map) {\n const fromMap = paletteIndexToTermId.get(paletteIndex);\n if (typeof fromMap === \"string\" && fromMap.length > 0) return fromMap;\n }\n return String(paletteIndex);\n}\n\nexport function computeRoiPointGroups(pointData: WsiPointData | null | undefined, regions: readonly WsiRegion[] | null | undefined, options: RoiPointGroupOptions = {}): RoiPointGroupStats {\n const baseCount = Math.max(\n 0,\n Math.min(\n Math.floor(pointData?.count ?? 0),\n Math.floor((pointData?.positions?.length ?? 0) / 2),\n pointData?.paletteIndices?.length ?? 0,\n pointData?.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER\n )\n );\n\n let drawIndices: Uint32Array | null = null;\n if (pointData?.drawIndices instanceof Uint32Array) {\n const source = pointData.drawIndices;\n let valid = source.length;\n for (let i = 0; i < source.length; i += 1) {\n const idx = source[i];\n if (idx < baseCount) continue;\n valid -= 1;\n }\n if (valid === source.length) {\n drawIndices = source;\n } else if (valid > 0) {\n const filtered = new Uint32Array(valid);\n let cursor = 0;\n for (let i = 0; i < source.length; i += 1) {\n const idx = source[i];\n if (idx >= baseCount) continue;\n filtered[cursor] = idx;\n cursor += 1;\n }\n drawIndices = filtered;\n } else {\n drawIndices = new Uint32Array(0);\n }\n }\n\n const inputCount = drawIndices ? drawIndices.length : baseCount;\n\n const preparedRegions = prepareRegions(regions ?? []);\n if (!pointData || inputCount === 0 || preparedRegions.length === 0) {\n return {\n groups: [],\n inputPointCount: inputCount,\n pointsInsideAnyRegion: 0,\n unmatchedPointCount: inputCount,\n };\n }\n\n const regionTermCounters = new Map<number, Map<number, number>>();\n const regionTotalCounters = new Map<number, number>();\n let insideCount = 0;\n\n for (let i = 0; i < inputCount; i += 1) {\n const pointIndex = drawIndices ? drawIndices[i] : i;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n let bestRegion: PreparedRegion | null = null;\n\n for (const region of preparedRegions) {\n let inside = false;\n for (const polygon of region.polygons) {\n if (!pointInPreparedPolygon(x, y, polygon)) continue;\n inside = true;\n break;\n }\n if (!inside) continue;\n if (!bestRegion || region.area < bestRegion.area) {\n bestRegion = region;\n }\n }\n\n if (!bestRegion) continue;\n insideCount += 1;\n\n const paletteIndex = pointData.paletteIndices[pointIndex] ?? 0;\n const regionTermMap = regionTermCounters.get(bestRegion.regionIndex) ?? new Map<number, number>();\n regionTermMap.set(paletteIndex, (regionTermMap.get(paletteIndex) ?? 0) + 1);\n regionTermCounters.set(bestRegion.regionIndex, regionTermMap);\n regionTotalCounters.set(bestRegion.regionIndex, (regionTotalCounters.get(bestRegion.regionIndex) ?? 0) + 1);\n }\n\n const includeEmptyRegions = options.includeEmptyRegions ?? false;\n const groups: RoiPointGroup[] = [];\n for (const region of preparedRegions) {\n const totalCount = regionTotalCounters.get(region.regionIndex) ?? 0;\n if (!includeEmptyRegions && totalCount <= 0) continue;\n const termMap = regionTermCounters.get(region.regionIndex) ?? new Map();\n const termCounts: RoiTermCount[] = Array.from(termMap.entries())\n .map(([paletteIndex, count]) => ({\n termId: resolveTermId(paletteIndex, options.paletteIndexToTermId),\n paletteIndex,\n count,\n }))\n .sort((a, b) => b.count - a.count || a.paletteIndex - b.paletteIndex);\n\n groups.push({\n regionId: region.regionId,\n regionIndex: region.regionIndex,\n totalCount,\n termCounts,\n });\n }\n\n return {\n groups,\n inputPointCount: inputCount,\n pointsInsideAnyRegion: insideCount,\n unmatchedPointCount: Math.max(0, inputCount - insideCount),\n };\n}\n","import { nowMs } from \"./utils\";\n\nexport type TileBounds = [number, number, number, number];\n\nexport interface ScheduledTile {\n\tkey: string;\n\ttier: number;\n\tx: number;\n\ty: number;\n\tbounds: TileBounds;\n\tdistance2: number;\n\turl: string;\n}\n\nexport interface TileSchedulerSnapshot {\n\tinflight: number;\n\tqueued: number;\n\taborted: number;\n\tretries: number;\n\tfailed: number;\n}\n\nexport interface TileSchedulerOptions {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n\tauthToken?: string;\n\tonTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tonTileError?: (\n\t\ttile: ScheduledTile,\n\t\terror: unknown,\n\t\tattemptCount: number,\n\t) => void;\n\tonStateChange?: (snapshot: TileSchedulerSnapshot) => void;\n}\n\ninterface QueueItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\treadyAt: number;\n}\n\ninterface InflightItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\tcontroller: AbortController;\n}\n\nfunction shouldAttachAuthHeader(url: string, authToken: string): boolean {\n\tif (!authToken) return false;\n\ttry {\n\t\tconst parsed = new URL(url, typeof window !== \"undefined\" ? window.location.href : undefined);\n\t\tconst host = parsed.hostname.toLowerCase();\n\t\tconst isAwsS3 =\n\t\t\thost.includes(\"amazonaws.com\") || host.startsWith(\"s3.\") || host.includes(\".s3.\");\n\t\tif (isAwsS3) return false;\n\t} catch {\n\t\t// Fallback to attaching auth if URL parsing fails.\n\t}\n\treturn true;\n}\n\nexport class TileScheduler {\n\tprivate readonly maxConcurrency: number;\n\tprivate readonly maxRetries: number;\n\tprivate readonly retryBaseDelayMs: number;\n\tprivate readonly retryMaxDelayMs: number;\n\tprivate readonly onTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tprivate readonly onTileError?:\n\t\t| ((tile: ScheduledTile, error: unknown, attemptCount: number) => void)\n\t\t| undefined;\n\tprivate readonly onStateChange?:\n\t\t| ((snapshot: TileSchedulerSnapshot) => void)\n\t\t| undefined;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate queue: QueueItem[] = [];\n\tprivate queuedByKey = new Map<string, QueueItem>();\n\tprivate inflight = new Map<string, InflightItem>();\n\tprivate visibleKeys = new Set<string>();\n\tprivate timerId: number | null = null;\n\tprivate abortedCount = 0;\n\tprivate retryCount = 0;\n\tprivate failedCount = 0;\n\n\tconstructor(options: TileSchedulerOptions) {\n\t\tthis.maxConcurrency = Math.max(1, Math.floor(options.maxConcurrency ?? 12));\n\t\tthis.maxRetries = Math.max(0, Math.floor(options.maxRetries ?? 2));\n\t\tthis.retryBaseDelayMs = Math.max(\n\t\t\t10,\n\t\t\tMath.floor(options.retryBaseDelayMs ?? 120),\n\t\t);\n\t\tthis.retryMaxDelayMs = Math.max(\n\t\t\tthis.retryBaseDelayMs,\n\t\t\tMath.floor(options.retryMaxDelayMs ?? 1200),\n\t\t);\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.onTileLoad = options.onTileLoad;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onStateChange = options.onStateChange;\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t}\n\n\tschedule(tiles: readonly ScheduledTile[]): void {\n\t\tif (this.destroyed) return;\n\n\t\tconst nextVisibleKeys = new Set<string>();\n\t\tfor (const tile of tiles) {\n\t\t\tnextVisibleKeys.add(tile.key);\n\t\t}\n\t\tthis.visibleKeys = nextVisibleKeys;\n\n\t\tthis.dropInvisibleQueued(nextVisibleKeys);\n\t\tthis.abortInvisibleInflight(nextVisibleKeys);\n\n\t\tfor (const tile of tiles) {\n\t\t\tif (this.inflight.has(tile.key)) {\n\t\t\t\tconst inflight = this.inflight.get(tile.key);\n\t\t\t\tif (inflight) inflight.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst queued = this.queuedByKey.get(tile.key);\n\t\t\tif (queued) {\n\t\t\t\tqueued.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst item: QueueItem = {\n\t\t\t\ttile,\n\t\t\t\tattempt: 0,\n\t\t\t\treadyAt: nowMs(),\n\t\t\t};\n\t\t\tthis.queue.push(item);\n\t\t\tthis.queuedByKey.set(tile.key, item);\n\t\t}\n\n\t\tthis.sortQueue();\n\t\tthis.pump();\n\t\tthis.emitStateChange();\n\t}\n\n\tclear(): void {\n\t\tthis.clearPumpTimer();\n\t\tthis.visibleKeys.clear();\n\t\tthis.queue = [];\n\t\tthis.queuedByKey.clear();\n\n\t\tfor (const [, item] of this.inflight) {\n\t\t\titem.controller.abort();\n\t\t}\n\t\tthis.inflight.clear();\n\t\tthis.emitStateChange();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\t\tthis.clear();\n\t}\n\n\tgetInflightCount(): number {\n\t\treturn this.inflight.size;\n\t}\n\n\tgetSnapshot(): TileSchedulerSnapshot {\n\t\treturn {\n\t\t\tinflight: this.inflight.size,\n\t\t\tqueued: this.queue.length,\n\t\t\taborted: this.abortedCount,\n\t\t\tretries: this.retryCount,\n\t\t\tfailed: this.failedCount,\n\t\t};\n\t}\n\n\tprivate dropInvisibleQueued(visibleKeys: Set<string>): void {\n\t\tif (this.queue.length === 0) return;\n\t\tconst nextQueue: QueueItem[] = [];\n\t\tfor (const item of this.queue) {\n\t\t\tif (!visibleKeys.has(item.tile.key)) {\n\t\t\t\tthis.queuedByKey.delete(item.tile.key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextQueue.push(item);\n\t\t}\n\t\tthis.queue = nextQueue;\n\t}\n\n\tprivate abortInvisibleInflight(visibleKeys: Set<string>): void {\n\t\tfor (const [key, item] of this.inflight) {\n\t\t\tif (visibleKeys.has(key)) continue;\n\t\t\tthis.inflight.delete(key);\n\t\t\tthis.abortedCount += 1;\n\t\t\titem.controller.abort();\n\t\t}\n\t}\n\n\tprivate sortQueue(): void {\n\t\tthis.queue.sort((a, b) => {\n\t\t\tif (a.readyAt !== b.readyAt) return a.readyAt - b.readyAt;\n\t\t\tif (a.tile.distance2 !== b.tile.distance2) {\n\t\t\t\treturn a.tile.distance2 - b.tile.distance2;\n\t\t\t}\n\t\t\tif (a.tile.tier !== b.tile.tier) return b.tile.tier - a.tile.tier;\n\t\t\treturn a.tile.key.localeCompare(b.tile.key);\n\t\t});\n\t}\n\n\tprivate pump(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.clearPumpTimer();\n\n\t\twhile (this.inflight.size < this.maxConcurrency) {\n\t\t\tconst next = this.takeNextReadyQueueItem();\n\t\t\tif (!next) break;\n\t\t\tthis.startFetch(next);\n\t\t}\n\n\t\tif (this.inflight.size >= this.maxConcurrency) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queue.length === 0) return;\n\n\t\tconst earliestReadyAt = this.queue[0]?.readyAt;\n\t\tif (typeof earliestReadyAt !== \"number\") return;\n\t\tconst delay = Math.max(0, earliestReadyAt - nowMs());\n\t\tthis.timerId = window.setTimeout(() => {\n\t\t\tthis.timerId = null;\n\t\t\tthis.pump();\n\t\t}, delay);\n\t}\n\n\tprivate takeNextReadyQueueItem(): QueueItem | null {\n\t\tif (this.queue.length === 0) return null;\n\t\tconst now = nowMs();\n\t\tconst first = this.queue[0];\n\t\tif (!first || first.readyAt > now) return null;\n\n\t\tthis.queue.shift();\n\t\tthis.queuedByKey.delete(first.tile.key);\n\t\treturn first;\n\t}\n\n\tprivate startFetch(item: QueueItem): void {\n\t\tconst controller = new AbortController();\n\t\tconst inflightEntry: InflightItem = {\n\t\t\ttile: item.tile,\n\t\t\tattempt: item.attempt,\n\t\t\tcontroller,\n\t\t};\n\t\tthis.inflight.set(item.tile.key, inflightEntry);\n\t\tthis.emitStateChange();\n\n\t\tconst useAuthHeader = shouldAttachAuthHeader(item.tile.url, this.authToken);\n\t\tfetch(item.tile.url, {\n\t\t\tsignal: controller.signal,\n\t\t\theaders: useAuthHeader ? { Authorization: this.authToken } : undefined,\n\t\t})\n\t\t\t.then((response) => {\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\treturn response.blob();\n\t\t\t})\n\t\t\t.then((blob) => createImageBitmap(blob))\n\t\t\t.then((bitmap) => {\n\t\t\t\tif (this.destroyed || controller.signal.aborted) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this.visibleKeys.has(item.tile.key)) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.onTileLoad(item.tile, bitmap);\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (controller.signal.aborted || this.destroyed) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst shouldRetry =\n\t\t\t\t\titem.attempt < this.maxRetries && this.visibleKeys.has(item.tile.key);\n\t\t\t\tif (shouldRetry) {\n\t\t\t\t\tthis.retryCount += 1;\n\t\t\t\t\tconst nextAttempt = item.attempt + 1;\n\t\t\t\t\tconst retryDelay = this.getRetryDelay(nextAttempt);\n\t\t\t\t\tconst queued: QueueItem = {\n\t\t\t\t\t\ttile: item.tile,\n\t\t\t\t\t\tattempt: nextAttempt,\n\t\t\t\t\t\treadyAt: nowMs() + retryDelay,\n\t\t\t\t\t};\n\t\t\t\t\tconst existing = this.queuedByKey.get(item.tile.key);\n\t\t\t\t\tif (existing) {\n\t\t\t\t\t\texisting.tile = queued.tile;\n\t\t\t\t\t\texisting.readyAt = Math.min(existing.readyAt, queued.readyAt);\n\t\t\t\t\t\texisting.attempt = Math.max(existing.attempt, queued.attempt);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.queue.push(queued);\n\t\t\t\t\t\tthis.queuedByKey.set(queued.tile.key, queued);\n\t\t\t\t\t}\n\t\t\t\t\tthis.sortQueue();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.failedCount += 1;\n\t\t\t\tthis.onTileError?.(item.tile, error, item.attempt + 1);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.inflight.delete(item.tile.key);\n\t\t\t\tthis.pump();\n\t\t\t\tthis.emitStateChange();\n\t\t\t});\n\t}\n\n\tprivate getRetryDelay(attempt: number): number {\n\t\tconst exp = Math.max(0, attempt - 1);\n\t\tconst delay = Math.min(\n\t\t\tthis.retryMaxDelayMs,\n\t\t\tthis.retryBaseDelayMs * 2 ** exp,\n\t\t);\n\t\tconst jitter = 0.85 + Math.random() * 0.3;\n\t\treturn Math.round(delay * jitter);\n\t}\n\n\tprivate clearPumpTimer(): void {\n\t\tif (this.timerId === null) return;\n\t\twindow.clearTimeout(this.timerId);\n\t\tthis.timerId = null;\n\t}\n\n\tprivate emitStateChange(): void {\n\t\tthis.onStateChange?.(this.getSnapshot());\n\t}\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\n\nexport interface RendererCanvasHandlers {\n pointerDown: (event: PointerEvent) => void;\n pointerMove: (event: PointerEvent) => void;\n pointerUp: (event: PointerEvent) => void;\n wheel: (event: WheelEvent) => void;\n doubleClick: (event: MouseEvent) => void;\n contextMenu: (event: MouseEvent) => void;\n contextLost: (event: Event) => void;\n contextRestored: (event: Event) => void;\n}\n\nexport function addRendererCanvasEventListeners(canvas: HTMLCanvasElement, handlers: RendererCanvasHandlers): void {\n canvas.addEventListener(\"pointerdown\", handlers.pointerDown);\n canvas.addEventListener(\"pointermove\", handlers.pointerMove);\n canvas.addEventListener(\"pointerup\", handlers.pointerUp);\n canvas.addEventListener(\"pointercancel\", handlers.pointerUp);\n canvas.addEventListener(\"wheel\", handlers.wheel, { passive: false });\n canvas.addEventListener(\"dblclick\", handlers.doubleClick);\n canvas.addEventListener(\"contextmenu\", handlers.contextMenu);\n canvas.addEventListener(\"webglcontextlost\", handlers.contextLost);\n canvas.addEventListener(\"webglcontextrestored\", handlers.contextRestored);\n}\n\nexport function removeRendererCanvasEventListeners(canvas: HTMLCanvasElement, handlers: RendererCanvasHandlers): void {\n canvas.removeEventListener(\"pointerdown\", handlers.pointerDown);\n canvas.removeEventListener(\"pointermove\", handlers.pointerMove);\n canvas.removeEventListener(\"pointerup\", handlers.pointerUp);\n canvas.removeEventListener(\"pointercancel\", handlers.pointerUp);\n canvas.removeEventListener(\"wheel\", handlers.wheel);\n canvas.removeEventListener(\"dblclick\", handlers.doubleClick);\n canvas.removeEventListener(\"contextmenu\", handlers.contextMenu);\n canvas.removeEventListener(\"webglcontextlost\", handlers.contextLost);\n canvas.removeEventListener(\"webglcontextrestored\", handlers.contextRestored);\n}\n\nexport function resizeCanvasViewport(canvas: HTMLCanvasElement, gl: WebGL2RenderingContext, camera: OrthoCamera): void {\n const rect = canvas.getBoundingClientRect();\n const cssW = Math.max(1, rect.width || canvas.clientWidth || 1);\n const cssH = Math.max(1, rect.height || canvas.clientHeight || 1);\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n\n const pixelW = Math.max(1, Math.round(cssW * dpr));\n const pixelH = Math.max(1, Math.round(cssH * dpr));\n\n if (canvas.width !== pixelW || canvas.height !== pixelH) {\n canvas.width = pixelW;\n canvas.height = pixelH;\n }\n\n camera.setViewport(cssW, cssH);\n gl.viewport(0, 0, pixelW, pixelH);\n}\n","import type { WsiImageColorSettings } from \"./types\";\nimport { clamp } from \"./utils\";\nimport type { NormalizedImageColorSettings, PointSizeByZoom, PointSizeStop } from \"./wsi-renderer-types\";\n\nexport const DEFAULT_ROTATION_DRAG_SENSITIVITY = 0.35;\nexport const MIN_POINT_SIZE_PX = 0.5;\nexport const MAX_POINT_SIZE_PX = 256;\n\nexport const DEFAULT_POINT_SIZE_STOPS: readonly PointSizeStop[] = [\n { zoom: 1, size: 2.8 },\n { zoom: 2, size: 3.4 },\n { zoom: 3, size: 4.2 },\n { zoom: 4, size: 5.3 },\n { zoom: 5, size: 6.8 },\n { zoom: 6, size: 8.4 },\n { zoom: 7, size: 9.8 },\n { zoom: 8, size: 11.2 },\n { zoom: 9, size: 14.0 },\n { zoom: 10, size: 17.5 },\n { zoom: 11, size: 22.0 },\n { zoom: 12, size: 28.0 },\n];\n\nconst MIN_STROKE_SCALE = 0.1;\nconst MAX_STROKE_SCALE = 5.0;\nconst MIN_POINT_INNER_FILL_OPACITY = 0;\nconst MAX_POINT_INNER_FILL_OPACITY = 1;\nconst MIN_IMAGE_COLOR_INPUT = -100;\nconst MAX_IMAGE_COLOR_INPUT = 100;\nconst MAX_VIEW_TRANSITION_DURATION_MS = 2000;\n\nexport function toRadians(deg: number): number {\n return (deg * Math.PI) / 180;\n}\n\nexport function isSameArrayView(a: ArrayBufferView | null | undefined, b: ArrayBufferView | null | undefined): boolean {\n if (!a || !b) return a === b;\n return a.buffer === b.buffer && a.byteOffset === b.byteOffset && a.byteLength === b.byteLength;\n}\n\nexport function clonePointSizeStops(stops: readonly PointSizeStop[]): PointSizeStop[] {\n return stops.map(stop => ({ zoom: stop.zoom, size: stop.size }));\n}\n\nexport function normalizePointSizeStops(pointSizeByZoom: PointSizeByZoom | null | undefined): PointSizeStop[] {\n if (!pointSizeByZoom) return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\n const parsed = new Map<number, number>();\n for (const [zoomKey, rawSize] of Object.entries(pointSizeByZoom)) {\n const zoom = Number(zoomKey);\n const size = Number(rawSize);\n if (!Number.isFinite(zoom) || !Number.isFinite(size) || size <= 0) continue;\n parsed.set(zoom, size);\n }\n\n if (parsed.size === 0) {\n return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n }\n\n return Array.from(parsed.entries())\n .sort((a, b) => a[0] - b[0])\n .map(([zoom, size]) => ({ zoom, size }));\n}\n\nexport function arePointSizeStopsEqual(a: readonly PointSizeStop[], b: readonly PointSizeStop[]): boolean {\n if (a === b) return true;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i += 1) {\n if (a[i].zoom !== b[i].zoom || a[i].size !== b[i].size) {\n return false;\n }\n }\n return true;\n}\n\nexport function resolvePointSizeByZoomStops(continuousZoom: number, stops: readonly PointSizeStop[]): number {\n if (!Number.isFinite(continuousZoom)) return stops[0]?.size ?? MIN_POINT_SIZE_PX;\n if (stops.length === 0) return MIN_POINT_SIZE_PX;\n if (stops.length === 1) return stops[0].size;\n if (continuousZoom <= stops[0].zoom) return stops[0].size;\n\n for (let i = 1; i < stops.length; i += 1) {\n const prev = stops[i - 1];\n const next = stops[i];\n if (continuousZoom > next.zoom) continue;\n const span = Math.max(1e-6, next.zoom - prev.zoom);\n const t = clamp((continuousZoom - prev.zoom) / span, 0, 1);\n return prev.size + (next.size - prev.size) * t;\n }\n\n const last = stops[stops.length - 1];\n const prev = stops[stops.length - 2];\n const span = Math.max(1e-6, last.zoom - prev.zoom);\n const slope = (last.size - prev.size) / span;\n return last.size + (continuousZoom - last.zoom) * slope;\n}\n\nexport function normalizeStrokeScale(value: number | null | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 1.0;\n return clamp(value, MIN_STROKE_SCALE, MAX_STROKE_SCALE);\n}\n\nexport function normalizePointInnerFillOpacity(value: number | null | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n return clamp(value, MIN_POINT_INNER_FILL_OPACITY, MAX_POINT_INNER_FILL_OPACITY);\n}\n\nfunction normalizeImageColorInput(value: number | null | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n return clamp(value, MIN_IMAGE_COLOR_INPUT, MAX_IMAGE_COLOR_INPUT);\n}\n\nexport function toNormalizedImageColorSettings(settings: WsiImageColorSettings | null | undefined): NormalizedImageColorSettings {\n const brightnessInput = normalizeImageColorInput(settings?.brightness);\n const contrastInput = normalizeImageColorInput(settings?.contrast);\n const saturationInput = normalizeImageColorInput(settings?.saturation);\n return {\n brightness: brightnessInput / 200,\n contrast: contrastInput / 100,\n saturation: saturationInput / 100,\n };\n}\n\nexport function linearEasing(t: number): number {\n return t;\n}\n\nexport function normalizeViewTransitionDuration(duration: number | null | undefined): number {\n if (typeof duration !== \"number\" || !Number.isFinite(duration)) return 0;\n return clamp(duration, 0, MAX_VIEW_TRANSITION_DURATION_MS);\n}\n\nexport function normalizeZoomOverride(value: number | null | undefined): number | null {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) return null;\n return Math.max(1e-6, value);\n}\n\nexport function normalizeTransitionEasing(easing: ((t: number) => number) | null | undefined): (t: number) => number {\n return typeof easing === \"function\" ? easing : linearEasing;\n}\n","import { DEFAULT_ROTATION_DRAG_SENSITIVITY, toRadians } from \"./wsi-normalize\";\nimport type { InteractionConfig, InteractionState } from \"./wsi-renderer-types\";\n\ninterface PointerMoveOptions {\n event: PointerEvent;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n config: InteractionConfig;\n camera: {\n getViewState: () => {\n zoom: number;\n offsetX: number;\n offsetY: number;\n rotationDeg: number;\n };\n setViewState: (next: Partial<{ zoom: number; offsetX: number; offsetY: number; rotationDeg: number }>) => void;\n };\n clampViewState: () => void;\n emitViewState: () => void;\n requestRender: () => void;\n}\n\ninterface PointerDownOptions {\n event: PointerEvent;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n config: InteractionConfig;\n cancelViewAnimation: () => void;\n}\n\ninterface WheelOptions {\n event: WheelEvent;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\ninterface DoubleClickOptions {\n event: MouseEvent;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\nfunction getPointerAngleRad(canvas: HTMLCanvasElement, clientX: number, clientY: number): number {\n const rect = canvas.getBoundingClientRect();\n const x = clientX - rect.left - rect.width * 0.5;\n const y = clientY - rect.top - rect.height * 0.5;\n return Math.atan2(y, x);\n}\n\nexport function cancelDrag(canvas: HTMLCanvasElement, state: InteractionState): void {\n if (state.pointerId !== null && canvas.hasPointerCapture(state.pointerId)) {\n try {\n canvas.releasePointerCapture(state.pointerId);\n } catch {\n // noop\n }\n }\n state.dragging = false;\n state.mode = \"none\";\n state.rotateLastAngleRad = null;\n state.pointerId = null;\n canvas.classList.remove(\"dragging\");\n}\n\nexport function handlePointerDown(options: PointerDownOptions): void {\n const { event, canvas, state, config, cancelViewAnimation } = options;\n const wantsRotate = config.ctrlDragRotate && (event.ctrlKey || event.metaKey);\n const allowButton = event.button === 0 || (wantsRotate && event.button === 2);\n if (!allowButton) return;\n\n cancelViewAnimation();\n if (wantsRotate) {\n event.preventDefault();\n }\n\n state.dragging = true;\n state.mode = wantsRotate ? \"rotate\" : \"pan\";\n state.pointerId = event.pointerId;\n state.lastPointerX = event.clientX;\n state.lastPointerY = event.clientY;\n state.rotateLastAngleRad = state.mode === \"rotate\" ? getPointerAngleRad(canvas, event.clientX, event.clientY) : null;\n\n canvas.classList.add(\"dragging\");\n canvas.setPointerCapture(event.pointerId);\n}\n\nexport function handlePointerMove(options: PointerMoveOptions): void {\n const { event, canvas, state, config, camera, clampViewState, emitViewState, requestRender } = options;\n if (!state.dragging || event.pointerId !== state.pointerId) return;\n\n const dx = event.clientX - state.lastPointerX;\n const dy = event.clientY - state.lastPointerY;\n state.lastPointerX = event.clientX;\n state.lastPointerY = event.clientY;\n\n if (state.mode === \"rotate\") {\n const nextAngle = getPointerAngleRad(canvas, event.clientX, event.clientY);\n const prevAngle = state.rotateLastAngleRad;\n state.rotateLastAngleRad = nextAngle;\n if (prevAngle !== null) {\n const rawDelta = nextAngle - prevAngle;\n const delta = Math.atan2(Math.sin(rawDelta), Math.cos(rawDelta));\n const sensitivityScale = DEFAULT_ROTATION_DRAG_SENSITIVITY > 0 ? config.rotationDragSensitivityDegPerPixel / DEFAULT_ROTATION_DRAG_SENSITIVITY : 1;\n const viewState = camera.getViewState();\n camera.setViewState({\n rotationDeg: viewState.rotationDeg - ((delta * 180) / Math.PI) * sensitivityScale,\n });\n }\n } else {\n const viewState = camera.getViewState();\n const zoom = Math.max(1e-6, viewState.zoom);\n const rad = toRadians(viewState.rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const worldDx = (dx * cos - dy * sin) / zoom;\n const worldDy = (dx * sin + dy * cos) / zoom;\n camera.setViewState({\n offsetX: viewState.offsetX - worldDx,\n offsetY: viewState.offsetY - worldDy,\n });\n }\n\n clampViewState();\n emitViewState();\n requestRender();\n}\n\nexport function handlePointerUp(event: PointerEvent, canvas: HTMLCanvasElement, state: InteractionState): void {\n if (event.pointerId !== state.pointerId) return;\n cancelDrag(canvas, state);\n}\n\nexport function handleWheel(options: WheelOptions): void {\n const { event, canvas, onZoomBy } = options;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const factor = event.deltaY < 0 ? 1.12 : 0.89;\n onZoomBy(factor, x, y);\n}\n\nexport function handleDoubleClick(options: DoubleClickOptions): void {\n const { event, canvas, onZoomBy } = options;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n onZoomBy(event.shiftKey ? 0.8 : 1.25, x, y);\n}\n\nexport function handleContextMenu(event: MouseEvent, dragging: boolean): void {\n if (dragging || event.ctrlKey || event.metaKey) {\n event.preventDefault();\n }\n}\n","import { toTileUrl } from \"./image-info\";\nimport type { ScheduledTile } from \"./tile-scheduler\";\nimport type { WsiImageSource } from \"./types\";\nimport { clamp } from \"./utils\";\nimport type { Bounds } from \"./wsi-renderer-types\";\n\ninterface CameraViewLike {\n getViewCorners: () => [readonly [number, number], readonly [number, number], readonly [number, number], readonly [number, number]];\n getViewState: () => { zoom: number };\n getCenter: () => [number, number];\n setCenter: (x: number, y: number) => void;\n}\n\nexport function getViewBounds(camera: CameraViewLike): Bounds {\n const corners = camera.getViewCorners();\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of corners) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n return [minX, minY, maxX, maxY];\n}\n\nexport function clampViewState(camera: CameraViewLike, source: WsiImageSource): void {\n const bounds = getViewBounds(camera);\n const visibleW = Math.max(1e-6, bounds[2] - bounds[0]);\n const visibleH = Math.max(1e-6, bounds[3] - bounds[1]);\n const marginX = visibleW * 0.2;\n const marginY = visibleH * 0.2;\n\n const [centerX, centerY] = camera.getCenter();\n const halfW = visibleW * 0.5;\n const halfH = visibleH * 0.5;\n\n const minCenterX = halfW - marginX;\n const maxCenterX = source.width - halfW + marginX;\n const minCenterY = halfH - marginY;\n const maxCenterY = source.height - halfH + marginY;\n\n const nextCenterX = minCenterX <= maxCenterX ? clamp(centerX, minCenterX, maxCenterX) : source.width * 0.5;\n const nextCenterY = minCenterY <= maxCenterY ? clamp(centerY, minCenterY, maxCenterY) : source.height * 0.5;\n\n camera.setCenter(nextCenterX, nextCenterY);\n}\n\nexport function selectTier(camera: CameraViewLike, source: WsiImageSource): number {\n const zoom = Math.max(1e-6, camera.getViewState().zoom);\n const rawTier = source.maxTierZoom + Math.log2(zoom);\n return clamp(Math.floor(rawTier), 0, source.maxTierZoom);\n}\n\nexport function intersectsBounds(a: Bounds, b: Bounds): boolean {\n return !(a[2] <= b[0] || a[0] >= b[2] || a[3] <= b[1] || a[1] >= b[3]);\n}\n\nexport function getVisibleTilesForTier(camera: CameraViewLike, source: WsiImageSource, tier: number): ScheduledTile[] {\n const viewBounds = getViewBounds(camera);\n\n const levelScale = Math.pow(2, source.maxTierZoom - tier);\n const levelWidth = Math.ceil(source.width / levelScale);\n const levelHeight = Math.ceil(source.height / levelScale);\n\n const tilesX = Math.max(1, Math.ceil(levelWidth / source.tileSize));\n const tilesY = Math.max(1, Math.ceil(levelHeight / source.tileSize));\n\n const viewMinX = viewBounds[0];\n const viewMinY = viewBounds[1];\n const viewMaxX = viewBounds[2];\n const viewMaxY = viewBounds[3];\n\n const minTileX = clamp(Math.floor(viewMinX / levelScale / source.tileSize), 0, tilesX - 1);\n const maxTileX = clamp(Math.floor((viewMaxX - 1) / levelScale / source.tileSize), 0, tilesX - 1);\n const minTileY = clamp(Math.floor(viewMinY / levelScale / source.tileSize), 0, tilesY - 1);\n const maxTileY = clamp(Math.floor((viewMaxY - 1) / levelScale / source.tileSize), 0, tilesY - 1);\n\n if (minTileX > maxTileX || minTileY > maxTileY) {\n return [];\n }\n\n const centerTileX = ((viewMinX + viewMaxX) * 0.5) / levelScale / source.tileSize;\n const centerTileY = ((viewMinY + viewMaxY) * 0.5) / levelScale / source.tileSize;\n\n const visible: ScheduledTile[] = [];\n for (let y = minTileY; y <= maxTileY; y += 1) {\n for (let x = minTileX; x <= maxTileX; x += 1) {\n const left = x * source.tileSize * levelScale;\n const top = y * source.tileSize * levelScale;\n const right = Math.min((x + 1) * source.tileSize, levelWidth) * levelScale;\n const bottom = Math.min((y + 1) * source.tileSize, levelHeight) * levelScale;\n\n const dx = x - centerTileX;\n const dy = y - centerTileY;\n visible.push({\n key: `${tier}/${x}/${y}`,\n tier,\n x,\n y,\n bounds: [left, top, right, bottom],\n distance2: dx * dx + dy * dy,\n url: toTileUrl(source, tier, x, y),\n });\n }\n }\n\n visible.sort((a, b) => a.distance2 - b.distance2);\n return visible;\n}\n\nexport function getVisibleTiles(camera: CameraViewLike, source: WsiImageSource): { tier: number; visible: ScheduledTile[] } {\n const tier = selectTier(camera, source);\n return {\n tier,\n visible: getVisibleTilesForTier(camera, source, tier),\n };\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\nimport { cancelDrag as cancelInteractionDrag, handleContextMenu, handleDoubleClick, handlePointerDown, handlePointerMove, handlePointerUp, handleWheel } from \"./wsi-interaction\";\nimport type { RendererCanvasHandlers } from \"./wsi-canvas-lifecycle\";\nimport type { InteractionState } from \"./wsi-renderer-types\";\nimport type { WsiImageSource } from \"./types\";\nimport { clampViewState } from \"./wsi-tile-visibility\";\n\ninterface BaseInteractionOptions {\n interactionLocked: boolean;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n}\n\ninterface PointerDownWithLockOptions extends BaseInteractionOptions {\n event: PointerEvent;\n ctrlDragRotate: boolean;\n rotationDragSensitivityDegPerPixel: number;\n cancelViewAnimation: () => void;\n}\n\ninterface PointerMoveWithLockOptions extends BaseInteractionOptions {\n event: PointerEvent;\n ctrlDragRotate: boolean;\n rotationDragSensitivityDegPerPixel: number;\n camera: OrthoCamera;\n source: WsiImageSource;\n emitViewState: () => void;\n requestRender: () => void;\n}\n\ninterface PointerUpWithLockOptions extends BaseInteractionOptions {\n event: PointerEvent;\n}\n\ninterface WheelWithLockOptions {\n event: WheelEvent;\n interactionLocked: boolean;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\ninterface DoubleClickWithLockOptions {\n event: MouseEvent;\n interactionLocked: boolean;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\ninterface ContextMenuWithLockOptions {\n event: MouseEvent;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n}\n\nexport function onPointerDownWithLock(options: PointerDownWithLockOptions): void {\n if (options.interactionLocked) return;\n handlePointerDown({\n event: options.event,\n canvas: options.canvas,\n state: options.state,\n config: {\n ctrlDragRotate: options.ctrlDragRotate,\n rotationDragSensitivityDegPerPixel: options.rotationDragSensitivityDegPerPixel,\n },\n cancelViewAnimation: options.cancelViewAnimation,\n });\n}\n\nexport function onPointerMoveWithLock(options: PointerMoveWithLockOptions): void {\n if (options.interactionLocked) return;\n handlePointerMove({\n event: options.event,\n canvas: options.canvas,\n state: options.state,\n config: {\n ctrlDragRotate: options.ctrlDragRotate,\n rotationDragSensitivityDegPerPixel: options.rotationDragSensitivityDegPerPixel,\n },\n camera: options.camera,\n clampViewState: () => clampViewState(options.camera, options.source),\n emitViewState: options.emitViewState,\n requestRender: options.requestRender,\n });\n}\n\nexport function onPointerUpWithLock(options: PointerUpWithLockOptions): void {\n if (options.interactionLocked) return;\n handlePointerUp(options.event, options.canvas, options.state);\n}\n\nexport function onWheelWithLock(options: WheelWithLockOptions): void {\n if (options.interactionLocked) {\n options.event.preventDefault();\n return;\n }\n handleWheel({\n event: options.event,\n canvas: options.canvas,\n onZoomBy: options.onZoomBy,\n });\n}\n\nexport function onDoubleClickWithLock(options: DoubleClickWithLockOptions): void {\n if (options.interactionLocked) return;\n handleDoubleClick({\n event: options.event,\n canvas: options.canvas,\n onZoomBy: options.onZoomBy,\n });\n}\n\nexport function onContextMenuWithLock(options: ContextMenuWithLockOptions): void {\n handleContextMenu(options.event, options.state.dragging);\n}\n\nexport function cancelDrag(canvas: HTMLCanvasElement, state: InteractionState): void {\n cancelInteractionDrag(canvas, state);\n}\n\nexport interface CreateRendererInputHandlersOptions {\n canvas: HTMLCanvasElement;\n state: InteractionState;\n getInteractionLocked: () => boolean;\n getCtrlDragRotate: () => boolean;\n getRotationDragSensitivityDegPerPixel: () => number;\n cancelViewAnimation: () => void;\n camera: OrthoCamera;\n source: WsiImageSource;\n emitViewState: () => void;\n requestRender: () => void;\n zoomBy: (factor: number, x: number, y: number) => void;\n}\n\nexport function createRendererInputHandlers(options: CreateRendererInputHandlersOptions): Pick<RendererCanvasHandlers, \"pointerDown\" | \"pointerMove\" | \"pointerUp\" | \"wheel\" | \"doubleClick\" | \"contextMenu\"> {\n return {\n pointerDown: (event: PointerEvent) =>\n onPointerDownWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n state: options.state,\n ctrlDragRotate: options.getCtrlDragRotate(),\n rotationDragSensitivityDegPerPixel: options.getRotationDragSensitivityDegPerPixel(),\n cancelViewAnimation: options.cancelViewAnimation,\n }),\n pointerMove: (event: PointerEvent) =>\n onPointerMoveWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n state: options.state,\n ctrlDragRotate: options.getCtrlDragRotate(),\n rotationDragSensitivityDegPerPixel: options.getRotationDragSensitivityDegPerPixel(),\n camera: options.camera,\n source: options.source,\n emitViewState: options.emitViewState,\n requestRender: options.requestRender,\n }),\n pointerUp: (event: PointerEvent) =>\n onPointerUpWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n state: options.state,\n }),\n wheel: (event: WheelEvent) =>\n onWheelWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n onZoomBy: options.zoomBy,\n }),\n doubleClick: (event: MouseEvent) =>\n onDoubleClickWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n onZoomBy: options.zoomBy,\n }),\n contextMenu: (event: MouseEvent) =>\n onContextMenuWithLock({\n event,\n canvas: options.canvas,\n state: options.state,\n }),\n };\n}\n","import type {\n HandleTileLoadedOptions,\n TileCacheTrimOptions,\n} from \"./wsi-renderer-types\";\n\nexport function trimTileCache(options: TileCacheTrimOptions): void {\n const { gl, cache, maxCacheTiles } = options;\n if (cache.size <= maxCacheTiles) return;\n\n const entries = Array.from(cache.entries());\n entries.sort((a, b) => a[1].lastUsed - b[1].lastUsed);\n\n const removeCount = cache.size - maxCacheTiles;\n for (let i = 0; i < removeCount; i += 1) {\n const [key, value] = entries[i];\n gl.deleteTexture(value.texture);\n cache.delete(key);\n }\n}\n\nexport function createTextureFromBitmap(gl: WebGL2RenderingContext, bitmap: ImageBitmap): WebGLTexture | null {\n if (gl.isContextLost()) return null;\n\n const texture = gl.createTexture();\n if (!texture) return null;\n\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n return texture;\n}\n\nexport function handleTileLoaded(options: HandleTileLoadedOptions): void {\n const { gl, cache, tile, bitmap, frameSerial, maxCacheTiles, destroyed, contextLost, requestRender } = options;\n\n if (destroyed || contextLost || gl.isContextLost()) {\n bitmap.close();\n return;\n }\n if (cache.has(tile.key)) {\n bitmap.close();\n return;\n }\n\n const texture = createTextureFromBitmap(gl, bitmap);\n bitmap.close();\n if (!texture) return;\n\n cache.set(tile.key, {\n key: tile.key,\n texture,\n bounds: tile.bounds,\n tier: tile.tier,\n lastUsed: frameSerial,\n });\n trimTileCache({ gl, cache, maxCacheTiles });\n requestRender();\n}\n\nexport function deleteCachedTextures(gl: WebGL2RenderingContext, cache: Map<string, { texture: WebGLTexture }>): void {\n for (const [, value] of cache) {\n gl.deleteTexture(value.texture);\n }\n}\n","import type { TileScheduler } from \"./tile-scheduler\";\nimport type { CachedTile, PointProgram, TileVertexProgram } from \"./wsi-renderer-types\";\nimport { deleteCachedTextures } from \"./wsi-tile-cache\";\n\nexport interface ContextLostOptions {\n event: Event;\n destroyed: boolean;\n contextLost: boolean;\n frame: number | null;\n cancelViewAnimation: () => void;\n cancelDrag: () => void;\n tileScheduler: TileScheduler;\n cache: Map<string, CachedTile>;\n onContextLost?: () => void;\n}\n\nexport interface ContextLostResult {\n handled: boolean;\n frame: number | null;\n}\n\nexport function handleContextLost(options: ContextLostOptions): ContextLostResult {\n const { event, destroyed, contextLost, cancelViewAnimation, cancelDrag, tileScheduler, cache, onContextLost } = options;\n event.preventDefault();\n if (destroyed || contextLost) {\n return {\n handled: false,\n frame: options.frame,\n };\n }\n\n let frame = options.frame;\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n cancelViewAnimation();\n\n cancelDrag();\n tileScheduler.clear();\n cache.clear();\n onContextLost?.();\n\n return {\n handled: true,\n frame,\n };\n}\n\nexport interface DestroyRendererOptions {\n destroyed: boolean;\n frame: number | null;\n cancelViewAnimation: () => void;\n resizeObserver: ResizeObserver;\n removeCanvasEventListeners: () => void;\n cancelDrag: () => void;\n tileScheduler: TileScheduler;\n contextLost: boolean;\n gl: WebGL2RenderingContext;\n cache: Map<string, CachedTile>;\n tileProgram: TileVertexProgram;\n pointProgram: PointProgram;\n}\n\nexport interface DestroyRendererResult {\n didDestroy: boolean;\n frame: number | null;\n}\n\nexport function destroyRenderer(options: DestroyRendererOptions): DestroyRendererResult {\n if (options.destroyed) {\n return {\n didDestroy: false,\n frame: options.frame,\n };\n }\n\n let frame = options.frame;\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n options.cancelViewAnimation();\n\n options.resizeObserver.disconnect();\n options.removeCanvasEventListeners();\n options.cancelDrag();\n options.tileScheduler.destroy();\n\n if (!options.contextLost && !options.gl.isContextLost()) {\n deleteCachedTextures(options.gl, options.cache);\n options.gl.deleteBuffer(options.tileProgram.vbo);\n options.gl.deleteVertexArray(options.tileProgram.vao);\n options.gl.deleteProgram(options.tileProgram.program);\n\n options.gl.deleteBuffer(options.pointProgram.posBuffer);\n options.gl.deleteBuffer(options.pointProgram.termBuffer);\n options.gl.deleteBuffer(options.pointProgram.fillModeBuffer);\n options.gl.deleteBuffer(options.pointProgram.indexBuffer);\n options.gl.deleteTexture(options.pointProgram.paletteTexture);\n options.gl.deleteVertexArray(options.pointProgram.vao);\n options.gl.deleteProgram(options.pointProgram.program);\n }\n options.cache.clear();\n\n return {\n didDestroy: true,\n frame,\n };\n}\n","import type { WsiPointData } from \"./types\";\nimport { isSameArrayView } from \"./wsi-normalize\";\nimport type { PointProgram } from \"./wsi-renderer-types\";\n\nexport interface PointBufferRuntime {\n pointCount: number;\n usePointIndices: boolean;\n pointBuffersDirty: boolean;\n lastPointData: WsiPointData | null;\n zeroFillModes: Uint8Array<ArrayBufferLike>;\n lastPointPalette: Uint8Array<ArrayBufferLike> | null;\n pointPaletteSize: number;\n}\n\nfunction sanitizeDrawIndices(drawIndices: Uint32Array, maxExclusive: number): Uint32Array {\n if (maxExclusive <= 0 || drawIndices.length === 0) {\n return new Uint32Array(0);\n }\n\n let validCount = drawIndices.length;\n for (let i = 0; i < drawIndices.length; i += 1) {\n if (drawIndices[i] < maxExclusive) continue;\n validCount -= 1;\n }\n if (validCount === drawIndices.length) {\n return drawIndices;\n }\n if (validCount <= 0) {\n return new Uint32Array(0);\n }\n\n const filtered = new Uint32Array(validCount);\n let cursor = 0;\n for (let i = 0; i < drawIndices.length; i += 1) {\n const idx = drawIndices[i];\n if (idx >= maxExclusive) continue;\n filtered[cursor] = idx;\n cursor += 1;\n }\n return filtered;\n}\n\nfunction getZeroFillModes(zeroFillModes: Uint8Array<ArrayBufferLike>, count: number): Uint8Array<ArrayBufferLike> {\n if (count <= 0) return new Uint8Array(0);\n if (zeroFillModes.length < count) {\n return new Uint8Array(count);\n }\n return zeroFillModes.subarray(0, count);\n}\n\nexport function setPointPalette(runtime: PointBufferRuntime, gl: WebGL2RenderingContext, pointProgram: PointProgram, contextLost: boolean, colors: Uint8Array | null | undefined): PointBufferRuntime {\n if (!colors || colors.length === 0) {\n return {\n ...runtime,\n lastPointPalette: null,\n };\n }\n\n const nextPalette = new Uint8Array(colors);\n if (contextLost || gl.isContextLost()) {\n return {\n ...runtime,\n lastPointPalette: nextPalette,\n };\n }\n\n const paletteSize = Math.max(1, Math.floor(nextPalette.length / 4));\n gl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, paletteSize, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, nextPalette);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n return {\n ...runtime,\n lastPointPalette: nextPalette,\n pointPaletteSize: paletteSize,\n };\n}\n\nexport function setPointData(runtime: PointBufferRuntime, gl: WebGL2RenderingContext, pointProgram: PointProgram, contextLost: boolean, points: WsiPointData | null | undefined): PointBufferRuntime {\n if (!points || !points.count || !points.positions || !points.paletteIndices) {\n return {\n ...runtime,\n lastPointData: null,\n pointCount: 0,\n usePointIndices: false,\n };\n }\n\n const pointFillModes = points.fillModes instanceof Uint8Array ? points.fillModes : null;\n const hasFillModes = pointFillModes !== null;\n const safeCount = Math.max(0, Math.min(points.count, Math.floor(points.positions.length / 2), points.paletteIndices.length, hasFillModes ? pointFillModes.length : Number.MAX_SAFE_INTEGER));\n const nextPositions = points.positions.subarray(0, safeCount * 2);\n const nextPaletteIndices = points.paletteIndices.subarray(0, safeCount);\n const nextFillModes = hasFillModes ? pointFillModes.subarray(0, safeCount) : undefined;\n const hasDrawIndices = points.drawIndices instanceof Uint32Array;\n const nextDrawIndices = hasDrawIndices ? sanitizeDrawIndices(points.drawIndices as Uint32Array, safeCount) : null;\n\n const prev = runtime.lastPointData;\n const prevHasFillModes = prev?.fillModes instanceof Uint8Array;\n const geometryChanged =\n runtime.pointBuffersDirty ||\n !prev ||\n prev.count !== safeCount ||\n !isSameArrayView(prev.positions, nextPositions) ||\n !isSameArrayView(prev.paletteIndices, nextPaletteIndices) ||\n prevHasFillModes !== hasFillModes ||\n (hasFillModes && (!prev?.fillModes || !isSameArrayView(prev.fillModes, nextFillModes)));\n const drawIndicesChanged = runtime.pointBuffersDirty || (hasDrawIndices && (!prev?.drawIndices || !isSameArrayView(prev.drawIndices, nextDrawIndices))) || (!hasDrawIndices && !!prev?.drawIndices);\n\n const nextRuntime: PointBufferRuntime = {\n ...runtime,\n lastPointData: {\n count: safeCount,\n positions: nextPositions,\n paletteIndices: nextPaletteIndices,\n fillModes: nextFillModes,\n drawIndices: hasDrawIndices ? (nextDrawIndices ?? undefined) : undefined,\n },\n };\n\n if (contextLost || gl.isContextLost()) {\n return nextRuntime;\n }\n\n const currentPointData = nextRuntime.lastPointData;\n if (!currentPointData) {\n return nextRuntime;\n }\n\n if (geometryChanged) {\n gl.bindBuffer(gl.ARRAY_BUFFER, pointProgram.posBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, currentPointData.positions, gl.STATIC_DRAW);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, pointProgram.termBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, currentPointData.paletteIndices, gl.STATIC_DRAW);\n\n const zeroFillModes = getZeroFillModes(nextRuntime.zeroFillModes, safeCount);\n gl.bindBuffer(gl.ARRAY_BUFFER, pointProgram.fillModeBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, currentPointData.fillModes ?? zeroFillModes, gl.STATIC_DRAW);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n nextRuntime.zeroFillModes = zeroFillModes;\n }\n\n if (hasDrawIndices && drawIndicesChanged) {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, pointProgram.indexBuffer);\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, nextDrawIndices ?? new Uint32Array(0), gl.DYNAMIC_DRAW);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n }\n\n nextRuntime.usePointIndices = hasDrawIndices;\n nextRuntime.pointCount = hasDrawIndices ? (nextDrawIndices?.length ?? 0) : currentPointData.count;\n if (geometryChanged || drawIndicesChanged) {\n nextRuntime.pointBuffersDirty = false;\n }\n\n return nextRuntime;\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\nimport type { ScheduledTile, TileScheduler } from \"./tile-scheduler\";\nimport type { WsiImageSource } from \"./types\";\nimport type { Bounds, CachedTile, NormalizedImageColorSettings, PointProgram, TileVertexProgram } from \"./wsi-renderer-types\";\n\nexport interface RenderFrameOptions {\n gl: WebGL2RenderingContext;\n camera: OrthoCamera;\n source: WsiImageSource;\n cache: Map<string, CachedTile>;\n frameSerial: number;\n tileProgram: TileVertexProgram;\n pointProgram: PointProgram;\n imageColorSettings: NormalizedImageColorSettings;\n pointCount: number;\n usePointIndices: boolean;\n pointPaletteSize: number;\n pointStrokeScale: number;\n pointInnerFillOpacity: number;\n pointSizePx: number;\n tileScheduler: TileScheduler;\n getVisibleTiles: () => { tier: number; visible: ScheduledTile[] };\n getVisibleTilesForTier: (tier: number) => ScheduledTile[];\n getViewBounds: () => Bounds;\n intersectsBounds: (a: Bounds, b: Bounds) => boolean;\n}\n\nexport interface RenderFrameResult {\n tier: number;\n visible: number;\n rendered: number;\n points: number;\n fallback: number;\n cacheHits: number;\n cacheMisses: number;\n drawCalls: number;\n}\n\nexport function renderFrame(options: RenderFrameOptions): RenderFrameResult {\n const {\n gl,\n camera,\n source,\n cache,\n frameSerial,\n tileProgram,\n pointProgram,\n imageColorSettings,\n pointCount,\n usePointIndices,\n pointPaletteSize,\n pointStrokeScale,\n pointInnerFillOpacity,\n pointSizePx,\n tileScheduler,\n getVisibleTiles,\n getVisibleTilesForTier,\n getViewBounds,\n intersectsBounds,\n } = options;\n\n gl.clearColor(0.03, 0.06, 0.1, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const { tier, visible } = getVisibleTiles();\n const viewBounds = getViewBounds();\n const visibleKeys = new Set(visible.map(tile => tile.key));\n\n gl.useProgram(tileProgram.program);\n gl.bindVertexArray(tileProgram.vao);\n gl.uniformMatrix3fv(tileProgram.uCamera, false, camera.getMatrix());\n gl.uniform1i(tileProgram.uTexture, 0);\n gl.uniform1f(tileProgram.uBrightness, imageColorSettings.brightness);\n gl.uniform1f(tileProgram.uContrast, imageColorSettings.contrast);\n gl.uniform1f(tileProgram.uSaturation, imageColorSettings.saturation);\n\n const fallbackTiles: CachedTile[] = [];\n for (const [, cached] of cache) {\n if (visibleKeys.has(cached.key)) continue;\n if (!intersectsBounds(cached.bounds, viewBounds)) continue;\n fallbackTiles.push(cached);\n }\n fallbackTiles.sort((a, b) => a.tier - b.tier);\n\n for (const cached of fallbackTiles) {\n cached.lastUsed = frameSerial;\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, cached.texture);\n gl.uniform4f(tileProgram.uBounds, cached.bounds[0], cached.bounds[1], cached.bounds[2], cached.bounds[3]);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n }\n\n let renderedTiles = 0;\n const missingTiles: ScheduledTile[] = [];\n for (const tile of visible) {\n const cached = cache.get(tile.key);\n if (!cached) {\n missingTiles.push(tile);\n continue;\n }\n cached.lastUsed = frameSerial;\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, cached.texture);\n gl.uniform4f(tileProgram.uBounds, cached.bounds[0], cached.bounds[1], cached.bounds[2], cached.bounds[3]);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n renderedTiles += 1;\n }\n\n const tilesToSchedule: ScheduledTile[] = missingTiles.slice();\n const PREFETCH_DISTANCE_PENALTY = 1e6;\n const prefetchTiers: number[] = [];\n if (tier > 0) prefetchTiers.push(tier - 1);\n if (tier < source.maxTierZoom) prefetchTiers.push(tier + 1);\n for (const prefetchTier of prefetchTiers) {\n const prefetchCandidates = getVisibleTilesForTier(prefetchTier);\n for (const tile of prefetchCandidates) {\n if (cache.has(tile.key)) continue;\n tile.distance2 += PREFETCH_DISTANCE_PENALTY;\n tilesToSchedule.push(tile);\n }\n }\n tileScheduler.schedule(tilesToSchedule);\n\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.bindVertexArray(null);\n\n let renderedPoints = 0;\n if (pointCount > 0) {\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.useProgram(pointProgram.program);\n gl.bindVertexArray(pointProgram.vao);\n gl.uniformMatrix3fv(pointProgram.uCamera, false, camera.getMatrix());\n gl.uniform1f(pointProgram.uPointSize, pointSizePx);\n gl.uniform1f(pointProgram.uPointStrokeScale, pointStrokeScale);\n gl.uniform1f(pointProgram.uPointInnerFillAlpha, pointInnerFillOpacity);\n gl.uniform1f(pointProgram.uPaletteSize, pointPaletteSize);\n gl.uniform1i(pointProgram.uPalette, 1);\n gl.activeTexture(gl.TEXTURE1);\n gl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n if (usePointIndices) {\n gl.drawElements(gl.POINTS, pointCount, gl.UNSIGNED_INT, 0);\n } else {\n gl.drawArrays(gl.POINTS, 0, pointCount);\n }\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.bindVertexArray(null);\n renderedPoints = pointCount;\n }\n\n return {\n tier,\n visible: visible.length,\n rendered: renderedTiles,\n points: renderedPoints,\n fallback: fallbackTiles.length,\n cacheHits: renderedTiles,\n cacheMisses: missingTiles.length,\n drawCalls: fallbackTiles.length + renderedTiles + (renderedPoints > 0 ? 1 : 0),\n };\n}\n","import { createProgram, requireUniformLocation } from \"../core/gl-utils\";\nimport type { PointProgram, TileVertexProgram } from \"./wsi-renderer-types\";\n\nexport function initTileProgram(gl: WebGL2RenderingContext): TileVertexProgram {\n const vertex = `#version 300 es\n precision highp float;\n in vec2 aUnit;\n in vec2 aUv;\n uniform mat3 uCamera;\n uniform vec4 uBounds;\n out vec2 vUv;\n void main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n }`;\n\n const fragment = `#version 300 es\n precision highp float;\n in vec2 vUv;\n uniform sampler2D uTexture;\n uniform float uBrightness;\n uniform float uContrast;\n uniform float uSaturation;\n out vec4 outColor;\n void main() {\n vec4 color = texture(uTexture, vUv);\n\n color.rgb = clamp(\n (uContrast + 1.0) * color.rgb - (uContrast / 2.0),\n vec3(0.0),\n vec3(1.0)\n );\n\n float saturation = uSaturation + 1.0;\n float sr = (1.0 - saturation) * 0.2126;\n float sg = (1.0 - saturation) * 0.7152;\n float sb = (1.0 - saturation) * 0.0722;\n mat3 saturationMatrix = mat3(\n sr + saturation, sr, sr,\n sg, sg + saturation, sg,\n sb, sb, sb + saturation\n );\n color.rgb = clamp(saturationMatrix * color.rgb, vec3(0.0), vec3(1.0));\n\n color.rgb = clamp(color.rgb + uBrightness, vec3(0.0), vec3(1.0));\n outColor = color;\n }`;\n\n const program = createProgram(gl, vertex, fragment);\n const uCamera = requireUniformLocation(gl, program, \"uCamera\");\n const uBounds = requireUniformLocation(gl, program, \"uBounds\");\n const uTexture = requireUniformLocation(gl, program, \"uTexture\");\n const uBrightness = requireUniformLocation(gl, program, \"uBrightness\");\n const uContrast = requireUniformLocation(gl, program, \"uContrast\");\n const uSaturation = requireUniformLocation(gl, program, \"uSaturation\");\n\n const vao = gl.createVertexArray();\n const vbo = gl.createBuffer();\n if (!vao || !vbo) {\n throw new Error(\"buffer allocation failed\");\n }\n\n gl.bindVertexArray(vao);\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1]), gl.STATIC_DRAW);\n\n const aUnit = gl.getAttribLocation(program, \"aUnit\");\n const aUv = gl.getAttribLocation(program, \"aUv\");\n if (aUnit < 0 || aUv < 0) {\n throw new Error(\"tile attribute lookup failed\");\n }\n gl.enableVertexAttribArray(aUnit);\n gl.enableVertexAttribArray(aUv);\n gl.vertexAttribPointer(aUnit, 2, gl.FLOAT, false, 16, 0);\n gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);\n\n gl.bindVertexArray(null);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n\n return {\n program,\n vao,\n vbo,\n uCamera,\n uBounds,\n uTexture,\n uBrightness,\n uContrast,\n uSaturation,\n };\n}\n\nexport function initPointProgram(gl: WebGL2RenderingContext): PointProgram {\n const pointVertex = `#version 300 es\n precision highp float;\n in vec2 aPosition;\n in uint aTerm;\n in uint aFillMode;\n uniform mat3 uCamera;\n uniform float uPointSize;\n flat out uint vTerm;\n flat out uint vFillMode;\n void main() {\n vec3 clip = uCamera * vec3(aPosition, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n gl_PointSize = uPointSize;\n vTerm = aTerm;\n vFillMode = aFillMode;\n }`;\n\n const pointFragment = `#version 300 es\n precision highp float;\n flat in uint vTerm;\n flat in uint vFillMode;\n uniform sampler2D uPalette;\n uniform float uPaletteSize;\n uniform float uPointSize;\n uniform float uPointStrokeScale;\n uniform float uPointInnerFillAlpha;\n out vec4 outColor;\n void main() {\n vec2 pc = gl_PointCoord * 2.0 - 1.0;\n float r = length(pc);\n if (r > 1.0) discard;\n\n float idx = clamp(float(vTerm), 0.0, max(0.0, uPaletteSize - 1.0));\n vec2 uv = vec2((idx + 0.5) / uPaletteSize, 0.5);\n vec4 color = texture(uPalette, uv);\n if (color.a <= 0.0) discard;\n\n float aa = 1.5 / max(1.0, uPointSize);\n float outerMask = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, r);\n if (vFillMode != 0u) {\n float alpha = outerMask * color.a;\n if (alpha <= 0.001) discard;\n outColor = vec4(color.rgb * alpha, alpha);\n } else {\n float s = uPointStrokeScale;\n float ringWidth = clamp(3.0 * s / max(1.0, uPointSize), 0.12 * s, 0.62 * s);\n float innerRadius = 1.0 - ringWidth;\n float innerMask = smoothstep(innerRadius - aa, innerRadius + aa, r);\n float ringAlpha = outerMask * innerMask * color.a;\n float fillAlpha = outerMask * (1.0 - innerMask) * clamp(uPointInnerFillAlpha, 0.0, 1.0);\n float alpha = ringAlpha + fillAlpha;\n if (alpha <= 0.001) discard;\n // Premultiplied alpha output: inner fill is black, so it only contributes alpha.\n outColor = vec4(color.rgb * ringAlpha, alpha);\n }\n }`;\n\n const program = createProgram(gl, pointVertex, pointFragment);\n const uCamera = requireUniformLocation(gl, program, \"uCamera\");\n const uPointSize = requireUniformLocation(gl, program, \"uPointSize\");\n const uPointStrokeScale = requireUniformLocation(gl, program, \"uPointStrokeScale\");\n const uPointInnerFillAlpha = requireUniformLocation(gl, program, \"uPointInnerFillAlpha\");\n const uPalette = requireUniformLocation(gl, program, \"uPalette\");\n const uPaletteSize = requireUniformLocation(gl, program, \"uPaletteSize\");\n\n const vao = gl.createVertexArray();\n const posBuffer = gl.createBuffer();\n const termBuffer = gl.createBuffer();\n const fillModeBuffer = gl.createBuffer();\n const indexBuffer = gl.createBuffer();\n const paletteTexture = gl.createTexture();\n if (!vao || !posBuffer || !termBuffer || !fillModeBuffer || !indexBuffer || !paletteTexture) {\n throw new Error(\"point buffer allocation failed\");\n }\n\n gl.bindVertexArray(vao);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n const posLoc = gl.getAttribLocation(program, \"aPosition\");\n if (posLoc < 0) {\n throw new Error(\"point position attribute not found\");\n }\n gl.enableVertexAttribArray(posLoc);\n gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, termBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n const termLoc = gl.getAttribLocation(program, \"aTerm\");\n if (termLoc < 0) {\n throw new Error(\"point term attribute not found\");\n }\n gl.enableVertexAttribArray(termLoc);\n gl.vertexAttribIPointer(termLoc, 1, gl.UNSIGNED_SHORT, 0, 0);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, fillModeBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n const fillModeLoc = gl.getAttribLocation(program, \"aFillMode\");\n if (fillModeLoc < 0) {\n throw new Error(\"point fill mode attribute not found\");\n }\n gl.enableVertexAttribArray(fillModeLoc);\n gl.vertexAttribIPointer(fillModeLoc, 1, gl.UNSIGNED_BYTE, 0, 0);\n\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\n gl.bindVertexArray(null);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n gl.bindTexture(gl.TEXTURE_2D, paletteTexture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([160, 160, 160, 255]));\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n return {\n program,\n vao,\n posBuffer,\n termBuffer,\n fillModeBuffer,\n indexBuffer,\n paletteTexture,\n uCamera,\n uPointSize,\n uPointStrokeScale,\n uPointInnerFillAlpha,\n uPalette,\n uPaletteSize,\n };\n}\n","import { clamp } from \"./utils\";\nimport { nowMs } from \"./utils\";\nimport type { ViewAnimationRuntimeState, ViewAnimationStartOptions } from \"./wsi-renderer-types\";\n\nexport function cancelViewAnimation(state: ViewAnimationRuntimeState): void {\n state.animation = null;\n if (state.frame !== null) {\n cancelAnimationFrame(state.frame);\n state.frame = null;\n }\n}\n\nexport function startViewAnimation(options: ViewAnimationStartOptions): void {\n const { state, camera, target, durationMs, easing, onUpdate } = options;\n const from = camera.getViewState();\n cancelViewAnimation(state);\n state.animation = {\n startMs: nowMs(),\n durationMs: Math.max(0, durationMs),\n from,\n to: target,\n easing,\n };\n\n const step = (): void => {\n const animation = state.animation;\n if (!animation) return;\n\n const elapsed = Math.max(0, nowMs() - animation.startMs);\n const rawT = animation.durationMs <= 0 ? 1 : clamp(elapsed / animation.durationMs, 0, 1);\n let eased = rawT;\n try {\n eased = animation.easing(rawT);\n } catch {\n eased = rawT;\n }\n if (!Number.isFinite(eased)) {\n eased = rawT;\n }\n eased = clamp(eased, 0, 1);\n\n camera.setViewState({\n zoom: animation.from.zoom + (animation.to.zoom - animation.from.zoom) * eased,\n offsetX: animation.from.offsetX + (animation.to.offsetX - animation.from.offsetX) * eased,\n offsetY: animation.from.offsetY + (animation.to.offsetY - animation.from.offsetY) * eased,\n rotationDeg: animation.from.rotationDeg + (animation.to.rotationDeg - animation.from.rotationDeg) * eased,\n });\n onUpdate();\n\n if (rawT >= 1) {\n state.animation = null;\n state.frame = null;\n return;\n }\n\n state.frame = requestAnimationFrame(step);\n };\n\n state.frame = requestAnimationFrame(step);\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\nimport type { WsiImageSource, WsiViewState } from \"./types\";\nimport { clamp } from \"./utils\";\nimport { toRadians } from \"./wsi-normalize\";\n\nexport function resolveDefaultZoomBounds(fitZoom: number): { minZoom: number; maxZoom: number } {\n const minZoom = Math.max(fitZoom * 0.5, 1e-6);\n const maxZoom = Math.max(1, fitZoom * 8);\n return {\n minZoom,\n maxZoom: Math.max(minZoom, maxZoom),\n };\n}\n\nexport function resolveZoomBounds(fitZoom: number, minZoomOverride: number | null, maxZoomOverride: number | null): { minZoom: number; maxZoom: number } {\n const defaults = resolveDefaultZoomBounds(fitZoom);\n let minZoom = minZoomOverride ?? defaults.minZoom;\n let maxZoom = maxZoomOverride ?? defaults.maxZoom;\n minZoom = Math.max(1e-6, minZoom);\n maxZoom = Math.max(1e-6, maxZoom);\n if (minZoom > maxZoom) {\n minZoom = maxZoom;\n }\n return { minZoom, maxZoom };\n}\n\nexport function resolveTargetViewState(\n camera: OrthoCamera,\n minZoom: number,\n maxZoom: number,\n next: Partial<WsiViewState>,\n clampViewState: () => void,\n): WsiViewState {\n const current = camera.getViewState();\n const candidate: WsiViewState = {\n zoom: typeof next.zoom === \"number\" && Number.isFinite(next.zoom) ? clamp(next.zoom, minZoom, maxZoom) : current.zoom,\n offsetX: typeof next.offsetX === \"number\" && Number.isFinite(next.offsetX) ? next.offsetX : current.offsetX,\n offsetY: typeof next.offsetY === \"number\" && Number.isFinite(next.offsetY) ? next.offsetY : current.offsetY,\n rotationDeg: typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg) ? next.rotationDeg : current.rotationDeg,\n };\n\n camera.setViewState(candidate);\n clampViewState();\n const target = camera.getViewState();\n camera.setViewState(current);\n return target;\n}\n\nexport function computeFitToImageTarget(\n source: WsiImageSource,\n viewportWidth: number,\n viewportHeight: number,\n minZoom: number,\n maxZoom: number,\n): { fitZoom: number; target: WsiViewState } {\n const zoom = Math.min(viewportWidth / source.width, viewportHeight / source.height);\n const safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n const clampedZoom = clamp(safeZoom, minZoom, maxZoom);\n const visibleWorldW = viewportWidth / clampedZoom;\n const visibleWorldH = viewportHeight / clampedZoom;\n\n return {\n fitZoom: safeZoom,\n target: {\n zoom: clampedZoom,\n offsetX: (source.width - visibleWorldW) * 0.5,\n offsetY: (source.height - visibleWorldH) * 0.5,\n rotationDeg: 0,\n },\n };\n}\n\nexport function computeZoomByTarget(\n camera: OrthoCamera,\n minZoom: number,\n maxZoom: number,\n factor: number,\n screenX: number,\n screenY: number,\n): Partial<WsiViewState> | null {\n const state = camera.getViewState();\n const nextZoom = clamp(state.zoom * factor, minZoom, maxZoom);\n if (nextZoom === state.zoom) return null;\n\n const [worldX, worldY] = camera.screenToWorld(screenX, screenY);\n const vp = camera.getViewportSize();\n const dx = screenX - vp.width * 0.5;\n const dy = screenY - vp.height * 0.5;\n const rad = toRadians(state.rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const worldDx = (dx / nextZoom) * cos - (dy / nextZoom) * sin;\n const worldDy = (dx / nextZoom) * sin + (dy / nextZoom) * cos;\n const nextCenterX = worldX - worldDx;\n const nextCenterY = worldY - worldDy;\n\n return {\n zoom: nextZoom,\n offsetX: nextCenterX - vp.width / (2 * nextZoom),\n offsetY: nextCenterY - vp.height / (2 * nextZoom),\n };\n}\n","import { OrthoCamera } from \"../core/ortho-camera\";\nimport { TileScheduler } from \"./tile-scheduler\";\nimport type { WsiImageColorSettings, WsiImageSource, WsiPointData, WsiRenderStats, WsiViewState } from \"./types\";\nimport { clamp, isSameViewState, nowMs } from \"./utils\";\nimport { addRendererCanvasEventListeners, type RendererCanvasHandlers, removeRendererCanvasEventListeners, resizeCanvasViewport } from \"./wsi-canvas-lifecycle\";\nimport { cancelDrag as cancelInputDrag, createRendererInputHandlers } from \"./wsi-input-handlers\";\nimport { destroyRenderer, handleContextLost } from \"./wsi-lifecycle-ops\";\nimport {\n arePointSizeStopsEqual,\n clonePointSizeStops,\n DEFAULT_POINT_SIZE_STOPS,\n DEFAULT_ROTATION_DRAG_SENSITIVITY,\n linearEasing,\n MAX_POINT_SIZE_PX,\n MIN_POINT_SIZE_PX,\n normalizePointInnerFillOpacity,\n normalizePointSizeStops,\n normalizeStrokeScale,\n normalizeTransitionEasing,\n normalizeViewTransitionDuration,\n normalizeZoomOverride,\n resolvePointSizeByZoomStops,\n toNormalizedImageColorSettings,\n} from \"./wsi-normalize\";\nimport type { PointBufferRuntime } from \"./wsi-point-data\";\nimport { setPointData as setManagedPointData, setPointPalette as setManagedPointPalette } from \"./wsi-point-data\";\nimport { renderFrame } from \"./wsi-render-pass\";\nimport type {\n CachedTile,\n InteractionState,\n NormalizedImageColorSettings,\n PointProgram,\n PointSizeByZoom,\n PointSizeStop,\n TileVertexProgram,\n ViewAnimationRuntimeState,\n WorldPoint,\n WsiTileErrorEvent,\n WsiTileRendererOptions,\n WsiViewTransitionOptions,\n} from \"./wsi-renderer-types\";\nimport { initPointProgram, initTileProgram } from \"./wsi-shaders\";\nimport { handleTileLoaded as cacheTileLoaded } from \"./wsi-tile-cache\";\nimport {\n clampViewState as clampManagedViewState,\n getViewBounds as getManagedViewBounds,\n getVisibleTiles as getManagedVisibleTiles,\n getVisibleTilesForTier as getManagedVisibleTilesForTier,\n intersectsBounds as intersectsManagedBounds,\n} from \"./wsi-tile-visibility\";\nimport { cancelViewAnimation as cancelManagedViewAnimation, startViewAnimation } from \"./wsi-view-animation\";\nimport { computeFitToImageTarget, computeZoomByTarget, resolveTargetViewState as resolveManagedTargetViewState, resolveZoomBounds } from \"./wsi-view-ops\";\n\nexport type { PointSizeByZoom, WsiTileErrorEvent, WsiTileRendererOptions, WsiTileSchedulerConfig, WsiViewTransitionOptions } from \"./wsi-renderer-types\";\n\nexport class WsiTileRenderer {\n private readonly canvas: HTMLCanvasElement;\n private readonly source: WsiImageSource;\n private readonly gl: WebGL2RenderingContext;\n private readonly camera = new OrthoCamera();\n private readonly onViewStateChange?: (next: WsiViewState) => void;\n private readonly onStats?: (stats: WsiRenderStats) => void;\n private readonly onTileError?: (event: WsiTileErrorEvent) => void;\n private readonly onContextLost?: () => void;\n private readonly onContextRestored?: () => void;\n private readonly resizeObserver: ResizeObserver;\n private tileProgram: TileVertexProgram;\n private pointProgram: PointProgram;\n private readonly tileScheduler: TileScheduler;\n\n private authToken: string;\n private destroyed = false;\n private contextLost = false;\n private frame: number | null = null;\n private frameSerial = 0;\n private interactionState: InteractionState = {\n dragging: false,\n mode: \"none\",\n rotateLastAngleRad: null,\n pointerId: null,\n lastPointerX: 0,\n lastPointerY: 0,\n };\n private interactionLocked = false;\n private ctrlDragRotate = true;\n private rotationDragSensitivityDegPerPixel = DEFAULT_ROTATION_DRAG_SENSITIVITY;\n private maxCacheTiles: number;\n private fitZoom = 1;\n private minZoom = 1e-6;\n private maxZoom = 1;\n private minZoomOverride: number | null = null;\n private maxZoomOverride: number | null = null;\n private viewTransitionDurationMs = 0;\n private viewTransitionEasing: (t: number) => number = linearEasing;\n private viewAnimationState: ViewAnimationRuntimeState = {\n animation: null,\n frame: null,\n };\n private pointCount = 0;\n private usePointIndices = false;\n private pointBuffersDirty = true;\n private pointPaletteSize = 1;\n private pointSizeStops: PointSizeStop[] = clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n private pointStrokeScale = 1.0;\n private pointInnerFillOpacity = 0;\n private imageColorSettings: NormalizedImageColorSettings = {\n brightness: 0,\n contrast: 0,\n saturation: 0,\n };\n private lastPointData: WsiPointData | null = null;\n private lastPointPalette: Uint8Array<ArrayBufferLike> | null = null;\n private zeroFillModes: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n private cache = new Map<string, CachedTile>();\n\n private readonly boundPointerDown: (event: PointerEvent) => void;\n private readonly boundPointerMove: (event: PointerEvent) => void;\n private readonly boundPointerUp: (event: PointerEvent) => void;\n private readonly boundWheel: (event: WheelEvent) => void;\n private readonly boundDoubleClick: (event: MouseEvent) => void;\n private readonly boundContextMenu: (event: MouseEvent) => void;\n private readonly boundContextLost: (event: Event) => void;\n private readonly boundContextRestored: (event: Event) => void;\n\n private getCanvasHandlers(): RendererCanvasHandlers {\n return {\n pointerDown: this.boundPointerDown,\n pointerMove: this.boundPointerMove,\n pointerUp: this.boundPointerUp,\n wheel: this.boundWheel,\n doubleClick: this.boundDoubleClick,\n contextMenu: this.boundContextMenu,\n contextLost: this.boundContextLost,\n contextRestored: this.boundContextRestored,\n };\n }\n\n constructor(canvas: HTMLCanvasElement, source: WsiImageSource, options: WsiTileRendererOptions = {}) {\n this.canvas = canvas;\n this.source = source;\n this.onViewStateChange = options.onViewStateChange;\n this.onStats = options.onStats;\n this.onTileError = options.onTileError;\n this.onContextLost = options.onContextLost;\n this.onContextRestored = options.onContextRestored;\n this.authToken = options.authToken ?? \"\";\n this.maxCacheTiles = Math.max(32, Math.floor(options.maxCacheTiles ?? 320));\n this.ctrlDragRotate = options.ctrlDragRotate ?? true;\n this.rotationDragSensitivityDegPerPixel =\n typeof options.rotationDragSensitivityDegPerPixel === \"number\" && Number.isFinite(options.rotationDragSensitivityDegPerPixel)\n ? Math.max(0, options.rotationDragSensitivityDegPerPixel)\n : DEFAULT_ROTATION_DRAG_SENSITIVITY;\n this.pointSizeStops = normalizePointSizeStops(options.pointSizeByZoom);\n this.pointStrokeScale = normalizeStrokeScale(options.pointStrokeScale);\n this.pointInnerFillOpacity = normalizePointInnerFillOpacity(options.pointInnerFillOpacity);\n this.imageColorSettings = toNormalizedImageColorSettings(options.imageColorSettings);\n this.minZoomOverride = normalizeZoomOverride(options.minZoom);\n this.maxZoomOverride = normalizeZoomOverride(options.maxZoom);\n this.viewTransitionDurationMs = normalizeViewTransitionDuration(options.viewTransition?.duration);\n this.viewTransitionEasing = normalizeTransitionEasing(options.viewTransition?.easing);\n\n const gl = canvas.getContext(\"webgl2\", {\n alpha: false,\n antialias: false,\n depth: false,\n stencil: false,\n powerPreference: \"high-performance\",\n });\n if (!gl) {\n throw new Error(\"WebGL2 not supported\");\n }\n this.gl = gl;\n\n this.tileProgram = initTileProgram(this.gl);\n this.pointProgram = initPointProgram(this.gl);\n this.tileScheduler = new TileScheduler({\n authToken: this.authToken,\n maxConcurrency: options.tileScheduler?.maxConcurrency ?? 12,\n maxRetries: options.tileScheduler?.maxRetries ?? 2,\n retryBaseDelayMs: options.tileScheduler?.retryBaseDelayMs ?? 120,\n retryMaxDelayMs: options.tileScheduler?.retryMaxDelayMs ?? 1200,\n onTileLoad: (tile, bitmap) =>\n cacheTileLoaded({\n gl: this.gl,\n cache: this.cache,\n tile,\n bitmap,\n frameSerial: this.frameSerial,\n maxCacheTiles: this.maxCacheTiles,\n destroyed: this.destroyed,\n contextLost: this.contextLost,\n requestRender: () => this.requestRender(),\n }),\n onTileError: (tile, error, attemptCount) => {\n this.onTileError?.({ tile, error, attemptCount });\n console.warn(\"tile load failed\", tile.url, error);\n },\n });\n\n this.resizeObserver = new ResizeObserver(() => this.resize());\n this.resizeObserver.observe(canvas);\n\n const inputHandlers = createRendererInputHandlers({\n canvas: this.canvas,\n state: this.interactionState,\n getInteractionLocked: () => this.interactionLocked,\n getCtrlDragRotate: () => this.ctrlDragRotate,\n getRotationDragSensitivityDegPerPixel: () => this.rotationDragSensitivityDegPerPixel,\n cancelViewAnimation: () => this.cancelViewAnimation(),\n camera: this.camera,\n source: this.source,\n emitViewState: () => this.onViewStateChange?.(this.camera.getViewState()),\n requestRender: () => this.requestRender(),\n zoomBy: (factor, x, y) => this.zoomBy(factor, x, y),\n });\n this.boundPointerDown = inputHandlers.pointerDown;\n this.boundPointerMove = inputHandlers.pointerMove;\n this.boundPointerUp = inputHandlers.pointerUp;\n this.boundWheel = inputHandlers.wheel;\n this.boundDoubleClick = inputHandlers.doubleClick;\n this.boundContextMenu = inputHandlers.contextMenu;\n this.boundContextLost = (event: Event) => this.onWebGlContextLost(event);\n this.boundContextRestored = (event: Event) => this.onWebGlContextRestored(event);\n\n addRendererCanvasEventListeners(canvas, this.getCanvasHandlers());\n\n this.fitToImage({ duration: 0 });\n this.resize();\n }\n\n private applyZoomBounds(): void {\n const bounds = resolveZoomBounds(this.fitZoom, this.minZoomOverride, this.maxZoomOverride);\n this.minZoom = bounds.minZoom;\n this.maxZoom = bounds.maxZoom;\n }\n\n private resolveTargetViewState(next: Partial<WsiViewState>): WsiViewState {\n return resolveManagedTargetViewState(this.camera, this.minZoom, this.maxZoom, next, () => clampManagedViewState(this.camera, this.source));\n }\n\n private cancelViewAnimation(): void {\n cancelManagedViewAnimation(this.viewAnimationState);\n }\n\n private startViewAnimation(target: WsiViewState, durationMs: number, easing: (t: number) => number): void {\n startViewAnimation({\n state: this.viewAnimationState,\n camera: this.camera,\n target,\n durationMs,\n easing,\n onUpdate: () => {\n clampManagedViewState(this.camera, this.source);\n this.onViewStateChange?.(this.camera.getViewState());\n this.requestRender();\n },\n });\n }\n\n private getPointBufferRuntime(): PointBufferRuntime {\n return {\n pointCount: this.pointCount,\n usePointIndices: this.usePointIndices,\n pointBuffersDirty: this.pointBuffersDirty,\n lastPointData: this.lastPointData,\n zeroFillModes: this.zeroFillModes,\n lastPointPalette: this.lastPointPalette,\n pointPaletteSize: this.pointPaletteSize,\n };\n }\n\n private applyPointBufferRuntime(runtime: PointBufferRuntime): void {\n this.pointCount = runtime.pointCount;\n this.usePointIndices = runtime.usePointIndices;\n this.pointBuffersDirty = runtime.pointBuffersDirty;\n this.lastPointData = runtime.lastPointData;\n this.zeroFillModes = runtime.zeroFillModes;\n this.lastPointPalette = runtime.lastPointPalette;\n this.pointPaletteSize = runtime.pointPaletteSize;\n }\n\n private applyViewStateAndRender(next: WsiViewState, cancelAnimation = true): void {\n if (cancelAnimation) {\n this.cancelViewAnimation();\n }\n this.camera.setViewState(next);\n this.onViewStateChange?.(this.camera.getViewState());\n this.requestRender();\n }\n\n setAuthToken(token: string): void {\n this.authToken = String(token ?? \"\");\n this.tileScheduler.setAuthToken(this.authToken);\n }\n\n setZoomRange(minZoom: number | null | undefined, maxZoom: number | null | undefined): void {\n const nextMinOverride = normalizeZoomOverride(minZoom);\n const nextMaxOverride = normalizeZoomOverride(maxZoom);\n if (this.minZoomOverride === nextMinOverride && this.maxZoomOverride === nextMaxOverride) {\n return;\n }\n\n this.minZoomOverride = nextMinOverride;\n this.maxZoomOverride = nextMaxOverride;\n this.applyZoomBounds();\n\n const target = this.resolveTargetViewState({});\n const current = this.camera.getViewState();\n if (isSameViewState(current, target)) {\n return;\n }\n this.applyViewStateAndRender(target);\n }\n\n setViewTransition(options: WsiViewTransitionOptions | null | undefined): void {\n this.viewTransitionDurationMs = normalizeViewTransitionDuration(options?.duration);\n this.viewTransitionEasing = normalizeTransitionEasing(options?.easing);\n }\n\n setViewState(next: Partial<WsiViewState>, transition?: WsiViewTransitionOptions): void {\n const target = this.resolveTargetViewState(next);\n const current = this.camera.getViewState();\n if (isSameViewState(current, target)) return;\n\n const durationMs = normalizeViewTransitionDuration(transition?.duration ?? this.viewTransitionDurationMs);\n const easing = normalizeTransitionEasing(transition?.easing ?? this.viewTransitionEasing);\n if (durationMs <= 0) {\n this.applyViewStateAndRender(target);\n return;\n }\n\n this.startViewAnimation(target, durationMs, easing);\n }\n\n getViewState(): WsiViewState {\n return this.camera.getViewState();\n }\n\n getZoomRange(): { minZoom: number; maxZoom: number } {\n return { minZoom: this.minZoom, maxZoom: this.maxZoom };\n }\n\n setPointPalette(colors: Uint8Array | null | undefined): void {\n const nextRuntime = setManagedPointPalette(this.getPointBufferRuntime(), this.gl, this.pointProgram, this.contextLost, colors);\n this.applyPointBufferRuntime(nextRuntime);\n if (!colors || colors.length === 0) {\n return;\n }\n this.requestRender();\n }\n\n setPointData(points: WsiPointData | null | undefined): void {\n const nextRuntime = setManagedPointData(this.getPointBufferRuntime(), this.gl, this.pointProgram, this.contextLost, points);\n this.applyPointBufferRuntime(nextRuntime);\n this.requestRender();\n }\n\n setInteractionLock(locked: boolean): void {\n const next = Boolean(locked);\n if (this.interactionLocked === next) return;\n this.interactionLocked = next;\n if (next) this.cancelDrag();\n }\n\n setPointSizeByZoom(pointSizeByZoom: PointSizeByZoom | null | undefined): void {\n const nextStops = normalizePointSizeStops(pointSizeByZoom);\n if (arePointSizeStopsEqual(this.pointSizeStops, nextStops)) return;\n this.pointSizeStops = nextStops;\n this.requestRender();\n }\n\n setPointStrokeScale(scale: number | null | undefined): void {\n const next = normalizeStrokeScale(scale);\n if (this.pointStrokeScale === next) return;\n this.pointStrokeScale = next;\n this.requestRender();\n }\n\n setPointInnerFillOpacity(opacity: number | null | undefined): void {\n const next = normalizePointInnerFillOpacity(opacity);\n if (this.pointInnerFillOpacity === next) return;\n this.pointInnerFillOpacity = next;\n this.requestRender();\n }\n\n setImageColorSettings(settings: WsiImageColorSettings | null | undefined): void {\n const next = toNormalizedImageColorSettings(settings);\n const prev = this.imageColorSettings;\n if (prev.brightness === next.brightness && prev.contrast === next.contrast && prev.saturation === next.saturation) {\n return;\n }\n this.imageColorSettings = next;\n this.requestRender();\n }\n\n cancelDrag(): void {\n cancelInputDrag(this.canvas, this.interactionState);\n }\n\n screenToWorld(clientX: number, clientY: number): [number, number] {\n const rect = this.canvas.getBoundingClientRect();\n const sx = clientX - rect.left;\n const sy = clientY - rect.top;\n return this.camera.screenToWorld(sx, sy);\n }\n\n worldToScreen(worldX: number, worldY: number): [number, number] {\n return this.camera.worldToScreen(worldX, worldY);\n }\n\n setViewCenter(worldX: number, worldY: number, transition?: WsiViewTransitionOptions): void {\n if (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n const state = this.camera.getViewState();\n const zoom = Math.max(1e-6, state.zoom);\n const vp = this.camera.getViewportSize();\n this.setViewState(\n {\n offsetX: worldX - vp.width / (2 * zoom),\n offsetY: worldY - vp.height / (2 * zoom),\n },\n transition\n );\n }\n\n getViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n return this.camera.getViewCorners();\n }\n\n resetRotation(transition?: WsiViewTransitionOptions): void {\n const state = this.camera.getViewState();\n if (Math.abs(state.rotationDeg) < 1e-6) return;\n this.setViewState({ rotationDeg: 0 }, transition);\n }\n\n getPointSizeByZoom(): number {\n const zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n const continuousZoom = this.source.maxTierZoom + Math.log2(zoom);\n const size = resolvePointSizeByZoomStops(continuousZoom, this.pointSizeStops);\n return clamp(size, MIN_POINT_SIZE_PX, MAX_POINT_SIZE_PX);\n }\n\n fitToImage(transition?: WsiViewTransitionOptions): void {\n const rect = this.canvas.getBoundingClientRect();\n const vw = Math.max(1, rect.width || 1);\n const vh = Math.max(1, rect.height || 1);\n const fitTarget = computeFitToImageTarget(this.source, vw, vh, this.minZoom, this.maxZoom);\n this.fitZoom = fitTarget.fitZoom;\n this.applyZoomBounds();\n this.setViewState(fitTarget.target, transition);\n }\n\n zoomBy(factor: number, screenX: number, screenY: number, transition?: WsiViewTransitionOptions): void {\n const target = computeZoomByTarget(this.camera, this.minZoom, this.maxZoom, factor, screenX, screenY);\n if (!target) return;\n this.setViewState(target, transition);\n }\n\n render(): void {\n if (this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n const frameStartMs = this.onStats ? nowMs() : 0;\n this.frameSerial += 1;\n\n const result = renderFrame({\n gl: this.gl,\n camera: this.camera,\n source: this.source,\n cache: this.cache,\n frameSerial: this.frameSerial,\n tileProgram: this.tileProgram,\n pointProgram: this.pointProgram,\n imageColorSettings: this.imageColorSettings,\n pointCount: this.pointCount,\n usePointIndices: this.usePointIndices,\n pointPaletteSize: this.pointPaletteSize,\n pointStrokeScale: this.pointStrokeScale,\n pointInnerFillOpacity: this.pointInnerFillOpacity,\n pointSizePx: this.getPointSizeByZoom(),\n tileScheduler: this.tileScheduler,\n getVisibleTiles: () => getManagedVisibleTiles(this.camera, this.source),\n getVisibleTilesForTier: tier => getManagedVisibleTilesForTier(this.camera, this.source, tier),\n getViewBounds: () => getManagedViewBounds(this.camera),\n intersectsBounds: intersectsManagedBounds,\n });\n if (this.onStats) {\n const schedulerStats = this.tileScheduler.getSnapshot();\n this.onStats({\n tier: result.tier,\n visible: result.visible,\n rendered: result.rendered,\n points: result.points,\n fallback: result.fallback,\n cache: this.cache.size,\n inflight: schedulerStats.inflight,\n queued: schedulerStats.queued,\n retries: schedulerStats.retries,\n failed: schedulerStats.failed,\n aborted: schedulerStats.aborted,\n cacheHits: result.cacheHits,\n cacheMisses: result.cacheMisses,\n drawCalls: result.drawCalls,\n frameMs: nowMs() - frameStartMs,\n });\n }\n }\n\n requestRender(): void {\n if (this.frame !== null || this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n this.frame = requestAnimationFrame(() => {\n this.frame = null;\n this.render();\n });\n }\n\n resize(): void {\n resizeCanvasViewport(this.canvas, this.gl, this.camera);\n this.requestRender();\n }\n\n private onWebGlContextLost(event: Event): void {\n const result = handleContextLost({\n event,\n destroyed: this.destroyed,\n contextLost: this.contextLost,\n frame: this.frame,\n cancelViewAnimation: () => this.cancelViewAnimation(),\n cancelDrag: () => this.cancelDrag(),\n tileScheduler: this.tileScheduler,\n cache: this.cache,\n onContextLost: this.onContextLost,\n });\n if (!result.handled) return;\n this.frame = result.frame;\n this.contextLost = true;\n this.pointBuffersDirty = true;\n }\n\n private onWebGlContextRestored(_event: Event): void {\n if (this.destroyed) return;\n this.contextLost = false;\n this.cache.clear();\n\n this.tileProgram = initTileProgram(this.gl);\n this.pointProgram = initPointProgram(this.gl);\n this.pointBuffersDirty = true;\n\n if (this.lastPointPalette && this.lastPointPalette.length > 0) {\n this.setPointPalette(this.lastPointPalette);\n }\n if (this.lastPointData) {\n this.setPointData(this.lastPointData);\n } else {\n this.pointCount = 0;\n }\n\n this.resize();\n this.requestRender();\n this.onContextRestored?.();\n }\n\n destroy(): void {\n const result = destroyRenderer({\n destroyed: this.destroyed,\n frame: this.frame,\n cancelViewAnimation: () => this.cancelViewAnimation(),\n resizeObserver: this.resizeObserver,\n removeCanvasEventListeners: () => removeRendererCanvasEventListeners(this.canvas, this.getCanvasHandlers()),\n cancelDrag: () => this.cancelDrag(),\n tileScheduler: this.tileScheduler,\n contextLost: this.contextLost,\n gl: this.gl,\n cache: this.cache,\n tileProgram: this.tileProgram,\n pointProgram: this.pointProgram,\n });\n if (!result.didDestroy) return;\n this.destroyed = true;\n this.frame = result.frame;\n }\n}\n","import { type PreparedRoiPolygon, prepareRoiPolygons, toRoiGeometry } from \"../wsi/roi-geometry\";\nimport type { WsiRegion } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\nimport type { WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport { getTopAnchorFromPolygons, measureLabelTextWidth, mergeRegionLabelStyle } from \"./draw-layer-label\";\nimport type { DrawCoordinate, RegionLabelStyle, RegionLabelStyleResolver } from \"./draw-layer-types\";\nimport { toDrawCoordinate } from \"./draw-layer-utils\";\n\nconst REGION_CONTOUR_HIT_DISTANCE_PX = 6;\n\nexport interface PreparedRegionHit {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n polygons: PreparedRoiPolygon[];\n label: string;\n labelAnchor: DrawCoordinate | null;\n}\n\nexport function resolveRegionId(region: WsiRegion, index: number): string | number {\n return region.id ?? index;\n}\n\nfunction pointSegmentDistanceSq(px: number, py: number, ax: number, ay: number, bx: number, by: number): number {\n const abx = bx - ax;\n const aby = by - ay;\n const lengthSq = abx * abx + aby * aby;\n if (lengthSq <= 1e-12) {\n const dx = px - ax;\n const dy = py - ay;\n return dx * dx + dy * dy;\n }\n const t = clamp(((px - ax) * abx + (py - ay) * aby) / lengthSq, 0, 1);\n const nx = ax + abx * t;\n const ny = ay + aby * t;\n const dx = px - nx;\n const dy = py - ny;\n return dx * dx + dy * dy;\n}\n\nfunction isPointNearRing(x: number, y: number, ring: DrawCoordinate[], maxDistanceSq: number): boolean {\n for (let i = 1; i < ring.length; i += 1) {\n const prev = ring[i - 1];\n const next = ring[i];\n if (pointSegmentDistanceSq(x, y, prev[0], prev[1], next[0], next[1]) <= maxDistanceSq) {\n return true;\n }\n }\n return false;\n}\n\nfunction isPointNearPolygonContour(x: number, y: number, polygon: PreparedRoiPolygon, maxDistance: number): boolean {\n if (x < polygon.minX - maxDistance || x > polygon.maxX + maxDistance || y < polygon.minY - maxDistance || y > polygon.maxY + maxDistance) {\n return false;\n }\n const maxDistanceSq = maxDistance * maxDistance;\n if (isPointNearRing(x, y, polygon.outer, maxDistanceSq)) return true;\n for (const hole of polygon.holes) {\n if (isPointNearRing(x, y, hole, maxDistanceSq)) return true;\n }\n return false;\n}\n\nexport function isScreenPointInsideLabel(\n region: PreparedRegionHit,\n screenCoord: DrawCoordinate,\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n canvasWidth: number,\n canvasHeight: number\n): boolean {\n if (!region.label || !region.labelAnchor) return false;\n\n const anchorScreen = toDrawCoordinate(renderer.worldToScreen(region.labelAnchor[0], region.labelAnchor[1]));\n if (!anchorScreen) return false;\n\n const textWidth = measureLabelTextWidth(region.label, labelStyle);\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const x = clamp(anchorScreen[0], boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(anchorScreen[1] - labelStyle.offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const right = x + boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n const bottom = y + boxHeight * 0.5;\n\n return screenCoord[0] >= left && screenCoord[0] <= right && screenCoord[1] >= top && screenCoord[1] <= bottom;\n}\n\nexport function prepareRegionHits(regions: WsiRegion[]): PreparedRegionHit[] {\n const out: PreparedRegionHit[] = [];\n for (let i = 0; i < regions.length; i += 1) {\n const region = regions[i];\n const polygons = prepareRoiPolygons([toRoiGeometry(region?.coordinates)]);\n if (polygons.length === 0) continue;\n const label = typeof region?.label === \"string\" ? region.label.trim() : \"\";\n out.push({\n region,\n regionIndex: i,\n regionId: resolveRegionId(region, i),\n polygons,\n label,\n labelAnchor: label ? getTopAnchorFromPolygons(polygons) : null,\n });\n }\n return out;\n}\n\nexport function pickPreparedRegionAt(\n coord: DrawCoordinate,\n screenCoord: DrawCoordinate,\n regions: PreparedRegionHit[],\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n labelStyleResolver: RegionLabelStyleResolver | undefined,\n labelAutoLiftOffsetPx: number,\n canvasWidth: number,\n canvasHeight: number\n): {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n} | null {\n const x = coord[0];\n const y = coord[1];\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const labelAutoLiftOffset = Math.max(0, labelAutoLiftOffsetPx);\n const contourHitDistance = REGION_CONTOUR_HIT_DISTANCE_PX / zoom;\n for (let i = regions.length - 1; i >= 0; i -= 1) {\n const region = regions[i];\n for (const polygon of region.polygons) {\n if (!isPointNearPolygonContour(x, y, polygon, contourHitDistance)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n let dynamicLabelStyle = mergeRegionLabelStyle(\n labelStyle,\n labelStyleResolver?.({\n region: region.region,\n regionId: region.regionId,\n regionIndex: region.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n if (!isScreenPointInsideLabel(region, screenCoord, renderer, dynamicLabelStyle, canvasWidth, canvasHeight)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n return null;\n}\n","import {\n type CSSProperties,\n type MutableRefObject,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { filterPointDataByPolygons, type RoiPolygon } from \"../wsi/point-clip\";\nimport { filterPointDataByPolygonsHybrid } from \"../wsi/point-clip-hybrid\";\nimport { filterPointDataByPolygonsInWorker, type PointClipMode } from \"../wsi/point-clip-worker-client\";\nimport { buildPointSpatialIndexAsync, type FlatPointSpatialIndex, lookupCellIndex } from \"../wsi/point-hit-index-worker-client\";\nimport { type PreparedRoiPolygon, toRoiGeometry } from \"../wsi/roi-geometry\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type { WsiImageColorSettings, WsiImageSource, WsiPointData, WsiRegion, WsiRenderStats, WsiViewState } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\nimport { type PointSizeByZoom, type WsiTileErrorEvent, WsiTileRenderer, type WsiViewTransitionOptions } from \"../wsi/wsi-tile-renderer\";\nimport type {\n BrushOptions,\n DrawAreaTooltipOptions,\n DrawCoordinate,\n DrawOverlayShape,\n DrawRegionCoordinates,\n DrawResult,\n DrawTool,\n PatchDrawResult,\n RegionLabelStyle,\n RegionLabelStyleResolver,\n RegionStrokeStyle,\n RegionStrokeStyleResolver,\n StampOptions,\n} from \"./draw-layer\";\nimport { DrawLayer, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer\";\nimport { toDrawCoordinate } from \"./draw-layer-utils\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\nimport { type PreparedRegionHit, pickPreparedRegionAt, prepareRegionHits, resolveRegionId } from \"./wsi-region-hit-utils\";\n\nconst EMPTY_ROI_REGIONS: WsiRegion[] = [];\nconst EMPTY_ROI_POLYGONS: DrawRegionCoordinates[] = [];\nconst EMPTY_CLIPPED_POINTS: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n};\nconst POINT_HIT_RADIUS_SCALE = 0.65;\nconst MIN_POINT_HIT_RADIUS_PX = 4;\nconst REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS = 180;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\n\nexport interface RegionHoverEvent {\n region: WsiRegion | null;\n regionId: string | number | null;\n regionIndex: number;\n coordinate: DrawCoordinate | null;\n}\n\nexport interface RegionClickEvent {\n region: WsiRegion;\n regionId: string | number;\n regionIndex: number;\n coordinate: DrawCoordinate;\n}\n\nexport interface PointHitEvent {\n index: number;\n id: number | null;\n coordinate: DrawCoordinate;\n pointCoordinate: DrawCoordinate;\n}\n\nexport interface PointClickEvent extends PointHitEvent {\n button: number;\n}\n\nexport interface PointHoverEvent {\n index: number | null;\n id: number | null;\n coordinate: DrawCoordinate | null;\n pointCoordinate: DrawCoordinate | null;\n}\n\nexport interface PointClipStatsEvent {\n mode: PointClipMode;\n durationMs: number;\n inputCount: number;\n outputCount: number;\n polygonCount: number;\n usedWebGpu?: boolean;\n candidateCount?: number;\n bridgedToDraw?: boolean;\n}\n\nexport interface PointerWorldMoveEvent {\n coordinate: DrawCoordinate | null;\n clientX: number;\n clientY: number;\n insideImage: boolean;\n}\n\nexport interface WsiCustomLayerContext {\n source: WsiImageSource;\n viewState: WsiViewState;\n drawTool: DrawTool;\n interactionLock: boolean;\n worldToScreen: (worldX: number, worldY: number) => DrawCoordinate | null;\n screenToWorld: (clientX: number, clientY: number) => DrawCoordinate | null;\n requestRedraw: () => void;\n}\n\nexport interface WsiCustomLayer {\n id?: string | number;\n zIndex?: number;\n pointerEvents?: CSSProperties[\"pointerEvents\"];\n className?: string;\n style?: CSSProperties;\n render: (context: WsiCustomLayerContext) => ReactNode;\n}\n\nfunction smoothstep01(t: number): number {\n const x = clamp(t, 0, 1);\n return x * x * (3 - 2 * x);\n}\n\nexport interface OverviewMapConfig {\n show?: boolean;\n options?: Partial<OverviewMapOptions>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport interface WsiViewerCanvasProps {\n source: WsiImageSource | null;\n viewState?: Partial<WsiViewState> | null;\n imageColorSettings?: WsiImageColorSettings | null;\n onViewStateChange?: (next: WsiViewState) => void;\n onStats?: (stats: WsiRenderStats) => void;\n onTileError?: (event: WsiTileErrorEvent) => void;\n onContextLost?: () => void;\n onContextRestored?: () => void;\n debugOverlay?: boolean;\n debugOverlayStyle?: CSSProperties;\n fitNonce?: number;\n rotationResetNonce?: number;\n authToken?: string;\n ctrlDragRotate?: boolean;\n pointData?: WsiPointData | null;\n pointPalette?: Uint8Array | null;\n pointSizeByZoom?: PointSizeByZoom;\n pointStrokeScale?: number;\n pointInnerFillOpacity?: number;\n minZoom?: number;\n maxZoom?: number;\n viewTransition?: WsiViewTransitionOptions;\n roiRegions?: WsiRegion[];\n roiPolygons?: DrawRegionCoordinates[];\n clipPointsToRois?: boolean;\n clipMode?: PointClipMode;\n onClipStats?: (event: PointClipStatsEvent) => void;\n onRoiPointGroups?: (stats: RoiPointGroupStats) => void;\n roiPaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n interactionLock?: boolean;\n drawTool?: DrawTool;\n stampOptions?: StampOptions;\n brushOptions?: BrushOptions;\n drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n customLayers?: WsiCustomLayer[];\n patchRegions?: WsiRegion[];\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\n onPointerWorldMove?: (event: PointerWorldMoveEvent) => void;\n onPointHover?: (event: PointHoverEvent) => void;\n onPointClick?: (event: PointClickEvent) => void;\n onRegionHover?: (event: RegionHoverEvent) => void;\n onRegionClick?: (event: RegionClickEvent) => void;\n activeRegionId?: string | number | null;\n onActiveRegionChange?: (regionId: string | number | null) => void;\n getCellByCoordinatesRef?: MutableRefObject<((coordinate: DrawCoordinate) => PointHitEvent | null) | null>;\n onDrawComplete?: (result: DrawResult) => void;\n onPatchComplete?: (result: PatchDrawResult) => void;\n overviewMapConfig?: OverviewMapConfig;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function WsiViewerCanvas({\n source,\n viewState,\n imageColorSettings = null,\n onViewStateChange,\n onStats,\n onTileError,\n onContextLost,\n onContextRestored,\n debugOverlay = false,\n debugOverlayStyle,\n fitNonce = 0,\n rotationResetNonce = 0,\n authToken = \"\",\n ctrlDragRotate = true,\n pointData = null,\n pointPalette = null,\n pointSizeByZoom,\n pointStrokeScale,\n pointInnerFillOpacity,\n minZoom,\n maxZoom,\n viewTransition,\n roiRegions,\n roiPolygons,\n clipPointsToRois = false,\n clipMode = \"worker\",\n onClipStats,\n onRoiPointGroups,\n roiPaletteIndexToTermId,\n interactionLock = false,\n drawTool = \"cursor\",\n stampOptions,\n brushOptions,\n drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n onPointerWorldMove,\n onPointHover,\n onPointClick,\n onRegionHover,\n onRegionClick,\n activeRegionId: controlledActiveRegionId,\n onActiveRegionChange,\n getCellByCoordinatesRef,\n onDrawComplete,\n onPatchComplete,\n overviewMapConfig,\n className,\n style,\n}: WsiViewerCanvasProps): React.ReactElement {\n const showOverviewMap = overviewMapConfig?.show ?? false;\n const overviewMapOptions = overviewMapConfig?.options;\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const rendererRef = useRef<WsiTileRenderer | null>(null);\n const drawInvalidateRef = useRef<(() => void) | null>(null);\n const overviewInvalidateRef = useRef<(() => void) | null>(null);\n const onViewStateChangeRef = useRef<typeof onViewStateChange>(onViewStateChange);\n const onStatsRef = useRef<typeof onStats>(onStats);\n const debugOverlayRef = useRef(debugOverlay);\n const [hoveredRegionId, setHoveredRegionId] = useState<string | number | null>(null);\n const [uncontrolledActiveRegionId, setUncontrolledActiveRegionId] = useState<string | number | null>(() => controlledActiveRegionId ?? null);\n const isActiveRegionControlled = controlledActiveRegionId !== undefined;\n const activeRegionId = isActiveRegionControlled ? (controlledActiveRegionId ?? null) : uncontrolledActiveRegionId;\n const [customLayerViewState, setCustomLayerViewState] = useState<WsiViewState | null>(null);\n const [debugStats, setDebugStats] = useState<WsiRenderStats | null>(null);\n const [regionLabelAutoLiftOffsetPx, setRegionLabelAutoLiftOffsetPx] = useState(0);\n const hoveredRegionIdRef = useRef<string | number | null>(null);\n const hoveredPointIndexRef = useRef<number | null>(null);\n const hoveredPointIdRef = useRef<number | null>(null);\n const regionLabelAutoLiftOffsetRef = useRef(0);\n const regionLabelAutoLiftAnimationRef = useRef<{ rafId: number | null; startMs: number; from: number; to: number }>({\n rafId: null,\n startMs: 0,\n from: 0,\n to: 0,\n });\n const clipRunIdRef = useRef(0);\n const safeRoiRegions = roiRegions ?? EMPTY_ROI_REGIONS;\n const safePatchRegions = patchRegions ?? EMPTY_ROI_REGIONS;\n const safeRoiPolygons = roiPolygons ?? EMPTY_ROI_POLYGONS;\n const shouldTrackCustomLayerViewState = (customLayers?.length ?? 0) > 0;\n\n const mergedStyle = useMemo<CSSProperties>(() => ({ position: \"relative\", width: \"100%\", height: \"100%\", ...style }), [style]);\n const mergedDebugOverlayStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n top: 8,\n left: 8,\n zIndex: 7,\n margin: 0,\n padding: \"8px 10px\",\n maxWidth: \"min(420px, 80%)\",\n pointerEvents: \"none\",\n whiteSpace: \"pre-wrap\",\n lineHeight: 1.35,\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: 11,\n color: \"#cde6ff\",\n background: \"rgba(6, 12, 20, 0.82)\",\n border: \"1px solid rgba(173, 216, 255, 0.28)\",\n borderRadius: 8,\n boxShadow: \"0 8px 22px rgba(0,0,0,0.35)\",\n ...debugOverlayStyle,\n }),\n [debugOverlayStyle]\n );\n\n const effectiveRoiRegions = useMemo<WsiRegion[]>(() => {\n if (safeRoiRegions.length > 0) {\n return safeRoiRegions;\n }\n if (safeRoiPolygons.length === 0) {\n return EMPTY_ROI_REGIONS;\n }\n return safeRoiPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [safeRoiRegions, safeRoiPolygons]);\n const preparedRegionHits = useMemo(() => prepareRegionHits(effectiveRoiRegions), [effectiveRoiRegions]);\n const resolvedRegionLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n\n const applyRegionLabelAutoLiftOffset = useCallback((next: number) => {\n const clamped = clamp(next, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n if (Math.abs(regionLabelAutoLiftOffsetRef.current - clamped) < 1e-4) return;\n regionLabelAutoLiftOffsetRef.current = clamped;\n setRegionLabelAutoLiftOffsetPx(clamped);\n }, []);\n\n const cancelRegionLabelAutoLiftAnimation = useCallback(() => {\n const animation = regionLabelAutoLiftAnimationRef.current;\n if (animation.rafId !== null) {\n cancelAnimationFrame(animation.rafId);\n animation.rafId = null;\n }\n }, []);\n\n const animateRegionLabelAutoLiftTo = useCallback(\n (target: number) => {\n const clampedTarget = clamp(target, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n const animation = regionLabelAutoLiftAnimationRef.current;\n const from = regionLabelAutoLiftOffsetRef.current;\n if (Math.abs(from - clampedTarget) < 1e-4) {\n cancelRegionLabelAutoLiftAnimation();\n animation.to = clampedTarget;\n applyRegionLabelAutoLiftOffset(clampedTarget);\n return;\n }\n\n cancelRegionLabelAutoLiftAnimation();\n animation.startMs = performance.now();\n animation.from = from;\n animation.to = clampedTarget;\n\n const step = (timestamp: number) => {\n const current = regionLabelAutoLiftAnimationRef.current;\n const elapsed = Math.max(0, timestamp - current.startMs);\n const rawT = REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS <= 0 ? 1 : clamp(elapsed / REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS, 0, 1);\n const eased = smoothstep01(rawT);\n const nextValue = current.from + (current.to - current.from) * eased;\n applyRegionLabelAutoLiftOffset(nextValue);\n drawInvalidateRef.current?.();\n\n if (rawT >= 1) {\n current.rafId = null;\n applyRegionLabelAutoLiftOffset(current.to);\n return;\n }\n current.rafId = requestAnimationFrame(step);\n };\n\n animation.rafId = requestAnimationFrame(step);\n },\n [applyRegionLabelAutoLiftOffset, cancelRegionLabelAutoLiftAnimation]\n );\n\n const syncRegionLabelAutoLiftTarget = useCallback(\n (zoom: number | null | undefined) => {\n const renderer = rendererRef.current;\n if (!renderer || typeof zoom !== \"number\" || !Number.isFinite(zoom)) {\n animateRegionLabelAutoLiftTo(0);\n return;\n }\n const target = resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, renderer.getZoomRange());\n animateRegionLabelAutoLiftTo(target);\n },\n [autoLiftRegionLabelAtMaxZoom, animateRegionLabelAutoLiftTo]\n );\n\n const clipPolygons = useMemo<RoiPolygon[]>(() => effectiveRoiRegions.map(region => toRoiGeometry(region.coordinates)).filter((p): p is RoiPolygon => p != null), [effectiveRoiRegions]);\n\n const [renderPointData, setRenderPointData] = useState<WsiPointData | null>(pointData);\n\n useEffect(() => {\n const runId = ++clipRunIdRef.current;\n let cancelled = false;\n\n if (!clipPointsToRois) {\n setRenderPointData(pointData);\n return () => {\n cancelled = true;\n };\n }\n\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n setRenderPointData(null);\n return () => {\n cancelled = true;\n };\n }\n\n if (clipPolygons.length === 0) {\n setRenderPointData(EMPTY_CLIPPED_POINTS);\n onClipStats?.({\n mode: clipMode,\n durationMs: 0,\n inputCount: pointData.count,\n outputCount: 0,\n polygonCount: 0,\n });\n return () => {\n cancelled = true;\n };\n }\n\n const applyResult = (data: WsiPointData | null, stats: Omit<PointClipStatsEvent, \"inputCount\" | \"outputCount\" | \"polygonCount\">) => {\n if (cancelled || runId !== clipRunIdRef.current) return;\n const inputCount = pointData.count;\n const outputCount = data?.drawIndices ? data.drawIndices.length : (data?.count ?? 0);\n setRenderPointData(data);\n onClipStats?.({\n mode: stats.mode,\n durationMs: stats.durationMs,\n inputCount,\n outputCount,\n polygonCount: clipPolygons.length,\n usedWebGpu: stats.usedWebGpu,\n candidateCount: stats.candidateCount,\n bridgedToDraw: stats.bridgedToDraw,\n });\n };\n\n const run = async (): Promise<void> => {\n if (clipMode === \"sync\") {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n return;\n }\n\n if (clipMode === \"hybrid-webgpu\") {\n const result = await filterPointDataByPolygonsHybrid(pointData, clipPolygons, { bridgeToDraw: true });\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n usedWebGpu: result.meta.usedWebGpu,\n candidateCount: result.meta.candidateCount,\n bridgedToDraw: result.meta.bridgedToDraw,\n });\n return;\n }\n\n try {\n const result = await filterPointDataByPolygonsInWorker(pointData, clipPolygons);\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n });\n } catch {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [clipPointsToRois, clipMode, pointData, clipPolygons, onClipStats]);\n\n const shouldEnablePointHitTest = Boolean(onPointHover || onPointClick || getCellByCoordinatesRef);\n const [pointSpatialIndex, setPointSpatialIndex] = useState<FlatPointSpatialIndex | null>(null);\n\n useEffect(() => {\n if (!shouldEnablePointHitTest || !renderPointData) {\n setPointSpatialIndex(null);\n return;\n }\n let cancelled = false;\n\n buildPointSpatialIndexAsync(renderPointData, source).then(nextIndex => {\n if (!cancelled) setPointSpatialIndex(nextIndex);\n });\n\n return () => {\n cancelled = true;\n };\n }, [shouldEnablePointHitTest, renderPointData, source]);\n\n const getCellByCoordinates = useCallback(\n (coordinate: DrawCoordinate): PointHitEvent | null => {\n const renderer = rendererRef.current;\n if (!renderer || !pointSpatialIndex) return null;\n\n const x = Number(coordinate[0]);\n const y = Number(coordinate[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const pointSizePx = renderer.getPointSizeByZoom();\n const hitRadiusPx = Math.max(MIN_POINT_HIT_RADIUS_PX, pointSizePx * POINT_HIT_RADIUS_SCALE);\n const hitRadiusWorld = hitRadiusPx / zoom;\n if (!Number.isFinite(hitRadiusWorld) || hitRadiusWorld <= 0) return null;\n\n const { cellSize, cellOffsets, cellLengths, pointIndices: idxBuf, positions: posBuf, safeCount } = pointSpatialIndex;\n const baseCellX = Math.floor(x / cellSize);\n const baseCellY = Math.floor(y / cellSize);\n const cellRadius = Math.max(1, Math.ceil(hitRadiusWorld / cellSize));\n const maxDist2 = hitRadiusWorld * hitRadiusWorld;\n\n let nearestIndex = -1;\n let nearestDist2 = maxDist2;\n let nearestX = 0;\n let nearestY = 0;\n\n for (let cx = baseCellX - cellRadius; cx <= baseCellX + cellRadius; cx += 1) {\n for (let cy = baseCellY - cellRadius; cy <= baseCellY + cellRadius; cy += 1) {\n const ci = lookupCellIndex(pointSpatialIndex, cx, cy);\n if (ci < 0) continue;\n\n const off = cellOffsets[ci];\n const end = off + cellLengths[ci];\n for (let i = off; i < end; i += 1) {\n const pointIndex = idxBuf[i];\n if (pointIndex >= safeCount) continue;\n\n const px = posBuf[pointIndex * 2];\n const py = posBuf[pointIndex * 2 + 1];\n const dx = px - x;\n const dy = py - y;\n const dist2 = dx * dx + dy * dy;\n if (dist2 > nearestDist2) continue;\n\n nearestDist2 = dist2;\n nearestIndex = pointIndex;\n nearestX = px;\n nearestY = py;\n }\n }\n }\n\n if (nearestIndex < 0) return null;\n const pointId = pointSpatialIndex.ids ? Number(pointSpatialIndex.ids[nearestIndex]) : null;\n return {\n index: nearestIndex,\n id: pointId,\n coordinate: [x, y],\n pointCoordinate: [nearestX, nearestY],\n };\n },\n [pointSpatialIndex]\n );\n\n const emitPointHover = useCallback(\n (hit: PointHitEvent | null, coordinate: DrawCoordinate | null) => {\n if (!onPointHover) return;\n const nextIndex = hit?.index ?? null;\n const nextId = hit?.id ?? null;\n if (hoveredPointIndexRef.current === nextIndex && hoveredPointIdRef.current === nextId) return;\n hoveredPointIndexRef.current = nextIndex;\n hoveredPointIdRef.current = nextId;\n onPointHover({\n index: nextIndex,\n id: nextId,\n coordinate,\n pointCoordinate: hit?.pointCoordinate ?? null,\n });\n },\n [onPointHover]\n );\n\n const emitPointClick = useCallback(\n (coordinate: DrawCoordinate, button: number) => {\n if (!onPointClick) return;\n const hit = getCellByCoordinates(coordinate);\n if (!hit) return;\n onPointClick({\n ...hit,\n button,\n });\n },\n [onPointClick, getCellByCoordinates]\n );\n\n useEffect(() => {\n if (!getCellByCoordinatesRef) return;\n getCellByCoordinatesRef.current = getCellByCoordinates;\n return () => {\n if (getCellByCoordinatesRef.current === getCellByCoordinates) {\n getCellByCoordinatesRef.current = null;\n }\n };\n }, [getCellByCoordinatesRef, getCellByCoordinates]);\n\n useEffect(() => {\n if (!isActiveRegionControlled) return;\n setUncontrolledActiveRegionId(controlledActiveRegionId ?? null);\n }, [isActiveRegionControlled, controlledActiveRegionId]);\n\n const commitActiveRegion = useCallback(\n (next: string | number | null) => {\n if (String(activeRegionId) === String(next)) return;\n if (!isActiveRegionControlled) {\n setUncontrolledActiveRegionId(next);\n }\n onActiveRegionChange?.(next);\n },\n [activeRegionId, isActiveRegionControlled, onActiveRegionChange]\n );\n\n useEffect(() => {\n onViewStateChangeRef.current = onViewStateChange;\n }, [onViewStateChange]);\n\n useEffect(() => {\n onStatsRef.current = onStats;\n }, [onStats]);\n\n useEffect(() => {\n debugOverlayRef.current = debugOverlay;\n if (!debugOverlay) setDebugStats(null);\n }, [debugOverlay]);\n\n useEffect(() => {\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n };\n }, [cancelRegionLabelAutoLiftAnimation]);\n\n const handleRendererStats = useCallback((stats: WsiRenderStats): void => {\n onStatsRef.current?.(stats);\n if (debugOverlayRef.current) {\n setDebugStats(stats);\n }\n }, []);\n\n const debugOverlayText = useMemo(() => {\n if (!debugStats) {\n return \"stats: waiting for first frame...\";\n }\n return [\n `tier ${debugStats.tier} | frame ${debugStats.frameMs?.toFixed(2) ?? \"-\"} ms | drawCalls ${debugStats.drawCalls ?? \"-\"}`,\n `tiles visible ${debugStats.visible} | rendered ${debugStats.rendered} | fallback ${debugStats.fallback}`,\n `cache size ${debugStats.cache} | hit ${debugStats.cacheHits ?? \"-\"} | miss ${debugStats.cacheMisses ?? \"-\"}`,\n `queue inflight ${debugStats.inflight} | queued ${debugStats.queued ?? \"-\"} | retries ${debugStats.retries ?? \"-\"} | failed ${debugStats.failed ?? \"-\"} | aborted ${debugStats.aborted ?? \"-\"}`,\n `points ${debugStats.points}`,\n ].join(\"\\n\");\n }, [debugStats]);\n\n useEffect(() => {\n const hasActive = activeRegionId === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(activeRegionId));\n if (!hasActive && activeRegionId !== null) {\n commitActiveRegion(null);\n }\n\n const currentHover = hoveredRegionIdRef.current;\n const hasHover = currentHover === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(currentHover));\n\n if (!hasHover && currentHover !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n }, [effectiveRoiRegions, activeRegionId, onRegionHover, commitActiveRegion]);\n\n useEffect(() => {\n const hoveredPointIndex = hoveredPointIndexRef.current;\n if (hoveredPointIndex === null) return;\n if (pointSpatialIndex && hoveredPointIndex < pointSpatialIndex.safeCount) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [pointSpatialIndex, onPointHover]);\n\n const emitViewStateChange = useCallback(\n (next: WsiViewState): void => {\n syncRegionLabelAutoLiftTarget(next.zoom);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(next);\n }\n const callback = onViewStateChangeRef.current;\n if (callback) {\n callback(next);\n }\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n },\n [shouldTrackCustomLayerViewState, syncRegionLabelAutoLiftTarget]\n );\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [syncRegionLabelAutoLiftTarget, minZoom, maxZoom]);\n\n useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [drawTool, onRegionHover]);\n\n useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredPointIndexRef.current === null) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [drawTool, onPointHover]);\n\n const resolveWorldCoord = useCallback((clientX: number, clientY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.screenToWorld(clientX, clientY);\n if (!Array.isArray(raw) || raw.length < 2) return null;\n const x = Number(raw[0]);\n const y = Number(raw[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const resolveScreenCoord = useCallback((worldX: number, worldY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.worldToScreen(worldX, worldY);\n return toDrawCoordinate(raw);\n }, []);\n\n const resolveCanvasPointerSnapshot = useCallback((clientX: number, clientY: number): { screenCoord: DrawCoordinate; canvasWidth: number; canvasHeight: number } | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n if (!Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) {\n return null;\n }\n const screenX = clientX - rect.left;\n const screenY = clientY - rect.top;\n if (!Number.isFinite(screenX) || !Number.isFinite(screenY)) {\n return null;\n }\n return {\n screenCoord: [screenX, screenY],\n canvasWidth: Math.max(1, rect.width),\n canvasHeight: Math.max(1, rect.height),\n };\n }, []);\n\n const pickRegionHit = useCallback(\n (coord: DrawCoordinate, screenCoord: DrawCoordinate, canvasWidth: number, canvasHeight: number) => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n return pickPreparedRegionAt(coord, screenCoord, preparedRegionHits, renderer, resolvedRegionLabelStyle, resolveRegionLabelStyleProp, regionLabelAutoLiftOffsetPx, canvasWidth, canvasHeight);\n },\n [preparedRegionHits, resolvedRegionLabelStyle, resolveRegionLabelStyleProp, regionLabelAutoLiftOffsetPx]\n );\n\n const requestCustomLayerRedraw = useCallback(() => {\n rendererRef.current?.requestRender();\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n }, []);\n\n const effectiveCustomLayerViewState = useMemo<WsiViewState | null>(() => {\n return customLayerViewState ?? rendererRef.current?.getViewState() ?? null;\n }, [customLayerViewState]);\n\n const customLayerContext = useMemo<WsiCustomLayerContext | null>(() => {\n if (!source) return null;\n const viewStateForLayer = effectiveCustomLayerViewState;\n if (!viewStateForLayer) return null;\n return {\n source,\n viewState: viewStateForLayer,\n drawTool,\n interactionLock,\n worldToScreen: resolveScreenCoord,\n screenToWorld: resolveWorldCoord,\n requestRedraw: requestCustomLayerRedraw,\n };\n }, [source, effectiveCustomLayerViewState, drawTool, interactionLock, resolveScreenCoord, resolveWorldCoord, requestCustomLayerRedraw]);\n\n const handleRegionPointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n const isCanvasEvent = event.target === canvasRef.current;\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (onPointerWorldMove) {\n const insideImage = !!coord && coord[0] >= 0 && coord[1] >= 0 && !!source && coord[0] <= source.width && coord[1] <= source.height;\n onPointerWorldMove({\n coordinate: coord,\n clientX: event.clientX,\n clientY: event.clientY,\n insideImage,\n });\n }\n\n if (drawTool !== \"cursor\") return;\n if (!isCanvasEvent) {\n emitPointHover(null, null);\n if (hoveredRegionIdRef.current !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n return;\n }\n if (!coord) {\n emitPointHover(null, null);\n return;\n }\n\n if (onPointHover) {\n emitPointHover(getCellByCoordinates(coord), coord);\n }\n if (!preparedRegionHits.length) return;\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\n const nextHoverId = hit?.regionId ?? null;\n const prevHoverId = hoveredRegionIdRef.current;\n if (String(prevHoverId) === String(nextHoverId)) return;\n\n hoveredRegionIdRef.current = nextHoverId;\n setHoveredRegionId(nextHoverId);\n onRegionHover?.({\n region: hit?.region ?? null,\n regionId: nextHoverId,\n regionIndex: hit?.regionIndex ?? -1,\n coordinate: coord,\n });\n },\n [drawTool, preparedRegionHits, resolveWorldCoord, onRegionHover, onPointerWorldMove, source, emitPointHover, getCellByCoordinates, onPointHover, resolveCanvasPointerSnapshot, pickRegionHit]\n );\n\n const handleRegionPointerLeave = useCallback(() => {\n onPointerWorldMove?.({\n coordinate: null,\n clientX: -1,\n clientY: -1,\n insideImage: false,\n });\n emitPointHover(null, null);\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [onRegionHover, onPointerWorldMove, emitPointHover]);\n\n const handleRegionClick = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n\n if (!preparedRegionHits.length) {\n commitActiveRegion(null);\n return;\n }\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\n if (!hit) {\n commitActiveRegion(null);\n return;\n }\n\n const nextActive: string | number | null = activeRegionId !== null && String(activeRegionId) === String(hit.regionId) ? null : hit.regionId;\n commitActiveRegion(nextActive);\n onRegionClick?.({\n region: hit.region,\n regionId: hit.regionId,\n regionIndex: hit.regionIndex,\n coordinate: coord,\n });\n },\n [drawTool, preparedRegionHits, resolveWorldCoord, onRegionClick, activeRegionId, commitActiveRegion, emitPointClick, resolveCanvasPointerSnapshot, pickRegionHit]\n );\n\n const handleBrushTap = useCallback(\n (coord: DrawCoordinate): boolean => {\n if (drawTool !== \"brush\") return false;\n if (brushOptions?.clickSelectRoi !== true) return false;\n if (!preparedRegionHits.length) return false;\n\n const renderer = rendererRef.current;\n const canvas = canvasRef.current;\n if (!renderer || !canvas) return false;\n const rect = canvas.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return false;\n\n const screenCoord = toDrawCoordinate(renderer.worldToScreen(coord[0], coord[1]));\n if (!screenCoord) return false;\n const hit = pickRegionHit(coord, screenCoord, rect.width, rect.height);\n if (!hit) return false;\n\n const nextActive: string | number | null = activeRegionId !== null && String(activeRegionId) === String(hit.regionId) ? null : hit.regionId;\n commitActiveRegion(nextActive);\n onRegionClick?.({\n region: hit.region,\n regionId: hit.regionId,\n regionIndex: hit.regionIndex,\n coordinate: coord,\n });\n return true;\n },\n [drawTool, brushOptions?.clickSelectRoi, preparedRegionHits, activeRegionId, commitActiveRegion, onRegionClick, pickRegionHit]\n );\n\n const handleRegionContextMenu = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (!onPointClick) return;\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n event.preventDefault();\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n },\n [drawTool, resolveWorldCoord, emitPointClick, onPointClick]\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || !source) {\n return;\n }\n\n const renderer = new WsiTileRenderer(canvas, source, {\n onViewStateChange: emitViewStateChange,\n onStats: handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n imageColorSettings,\n ctrlDragRotate,\n pointSizeByZoom,\n pointStrokeScale,\n pointInnerFillOpacity,\n minZoom,\n maxZoom,\n viewTransition,\n });\n\n rendererRef.current = renderer;\n if (viewState) {\n renderer.setViewState(viewState);\n }\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n renderer.setInteractionLock(interactionLock);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(renderer.getViewState());\n }\n\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n applyRegionLabelAutoLiftOffset(0);\n renderer.destroy();\n rendererRef.current = null;\n };\n }, [\n source,\n handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n ctrlDragRotate,\n emitViewStateChange,\n shouldTrackCustomLayerViewState,\n syncRegionLabelAutoLiftTarget,\n cancelRegionLabelAutoLiftAnimation,\n applyRegionLabelAutoLiftOffset,\n ]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !viewState) {\n return;\n }\n renderer.setViewState(viewState);\n }, [viewState]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.fitToImage();\n }, [fitNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.resetRotation();\n }, [rotationResetNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !pointPalette) {\n return;\n }\n renderer.setPointPalette(pointPalette);\n }, [pointPalette]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setPointSizeByZoom(pointSizeByZoom);\n }, [pointSizeByZoom]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setPointStrokeScale(pointStrokeScale);\n }, [pointStrokeScale]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setPointInnerFillOpacity(pointInnerFillOpacity);\n }, [pointInnerFillOpacity]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setZoomRange(minZoom, maxZoom);\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [minZoom, maxZoom, syncRegionLabelAutoLiftTarget]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setViewTransition(viewTransition);\n }, [viewTransition]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setImageColorSettings(imageColorSettings);\n }, [imageColorSettings]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setPointData(renderPointData);\n }, [renderPointData]);\n\n useEffect(() => {\n if (!onRoiPointGroups) return;\n const sourcePoints = clipPointsToRois ? renderPointData : pointData;\n const stats = computeRoiPointGroups(sourcePoints, effectiveRoiRegions, {\n paletteIndexToTermId: roiPaletteIndexToTermId,\n includeEmptyRegions: true,\n });\n onRoiPointGroups(stats);\n }, [onRoiPointGroups, clipPointsToRois, pointData, renderPointData, effectiveRoiRegions, roiPaletteIndexToTermId]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setInteractionLock(interactionLock);\n }, [interactionLock]);\n\n return (\n <div\n className={className}\n style={mergedStyle}\n onPointerMove={handleRegionPointerMove}\n onPointerLeave={handleRegionPointerLeave}\n onClick={handleRegionClick}\n onContextMenu={handleRegionContextMenu}\n >\n <canvas\n ref={canvasRef}\n className=\"wsi-render-canvas\"\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 1,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n cursor: drawTool === \"cursor\" && hoveredRegionId !== null ? \"pointer\" : interactionLock ? \"crosshair\" : \"grab\",\n }}\n />\n {source && customLayerContext && Array.isArray(customLayers) && customLayers.length > 0\n ? customLayers.map((layer, index) => (\n <div\n key={layer.id ?? index}\n className={layer.className}\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: layer.zIndex ?? 3,\n pointerEvents: layer.pointerEvents ?? \"none\",\n ...layer.style,\n }}\n >\n {layer.render(customLayerContext)}\n </div>\n ))\n : null}\n {source ? (\n <DrawLayer\n tool={drawTool}\n enabled={drawTool !== \"cursor\"}\n imageWidth={source.width}\n imageHeight={source.height}\n imageMpp={source.mpp}\n imageZoom={source.maxTierZoom}\n stampOptions={stampOptions}\n brushOptions={brushOptions}\n drawFillColor={drawFillColor}\n projectorRef={rendererRef}\n onBrushTap={handleBrushTap}\n viewStateSignal={viewState}\n persistedRegions={effectiveRoiRegions}\n patchRegions={safePatchRegions}\n regionStrokeStyle={regionStrokeStyle}\n regionStrokeHoverStyle={regionStrokeHoverStyle}\n regionStrokeActiveStyle={regionStrokeActiveStyle}\n patchStrokeStyle={patchStrokeStyle}\n resolveRegionStrokeStyle={resolveRegionStrokeStyle}\n resolveRegionLabelStyle={resolveRegionLabelStyleProp}\n overlayShapes={overlayShapes}\n hoveredRegionId={hoveredRegionId}\n activeRegionId={activeRegionId}\n regionLabelStyle={regionLabelStyle}\n drawAreaTooltip={drawAreaTooltip}\n autoLiftRegionLabelAtMaxZoom={autoLiftRegionLabelAtMaxZoom}\n regionLabelAutoLiftOffsetPx={regionLabelAutoLiftOffsetPx}\n invalidateRef={drawInvalidateRef}\n onDrawComplete={onDrawComplete}\n onPatchComplete={onPatchComplete}\n />\n ) : null}\n {debugOverlay ? (\n <pre data-open-plant-debug-overlay style={mergedDebugOverlayStyle}>\n {debugOverlayText}\n </pre>\n ) : null}\n {source && showOverviewMap && (\n <OverviewMap\n source={source}\n projectorRef={rendererRef}\n authToken={authToken}\n options={overviewMapOptions}\n invalidateRef={overviewInvalidateRef}\n className={overviewMapConfig?.className}\n style={overviewMapConfig?.style}\n />\n )}\n </div>\n );\n}\n"],"names":["compileShader","gl","type","source","shader","log","createProgram","vertexSource","fragmentSource","vertexShader","fragmentShader","program","requireUniformLocation","uniformName","location","requireWebGL2","canvas","context","toRadians","deg","OrthoCamera","__publicField","width","height","next","zoom","centerX","centerY","screenX","screenY","rotationDeg","dx","dy","rad","cos","sin","worldX","worldY","rx","ry","w","h","viewWidth","viewHeight","sx","sy","tx","ty","ax","bx","ay","by","VERTEX_SHADER","FRAGMENT_SHADER","M1TileRenderer","options","vao","quadBuffer","quadVertices","unitLocation","uvLocation","stride","tiles","version","loaded","tile","viewState","response","blob","bitmap","texture","error","rect","cssWidth","cssHeight","dpr","targetWidth","targetHeight","viewport","safeZoom","visibleWorldWidth","visibleWorldHeight","offsetX","offsetY","toRoiGeometry","coords","isFiniteNumber","value","isCoordinatePair","isLinearRing","point","isPolygonRings","ring","isMultiPolygon","polygon","closeRoiRing","coordinates","out","x","y","prev","first","last","polygonSignedArea","sum","i","a","b","normalizePolygonRings","rings","normalized","closed","outerIndex","outerArea","area","normalizeRoiGeometry","geometry","pointInRing","inside","j","xi","yi","xj","yj","prepareRoiPolygons","geometries","prepared","multipolygon","outer","minX","minY","maxX","maxY","pointInPreparedPolygon","hole","pointInAnyPreparedPolygon","polygons","DEFAULT_POINT_COLOR","clamp","min","max","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","nowMs","sanitizePointCount","pointData","fillModesLength","isSameViewState","toBearerToken","trimmed","token","hexToRgba","hex","match","n","buildTermPalette","terms","palette","termToPaletteIndex","term","termId","colors","DEFAULT_MIN_RASTER_STEP","DEFAULT_MAX_RASTER_PIXELS","DEFAULT_MAX_RASTER_SIZE","DEFAULT_CIRCLE_SIDES","DEFAULT_SMOOTHING_PASSES","MAX_SMOOTHING_PASSES","MIN_RADIUS","ALPHA_THRESHOLD","sanitizePath","points","createCirclePolygon","center","radius","sides","t","closeRing","createBoundsFallback","pad","computeExpandedBounds","resolveRasterConfig","bounds","minRasterStep","maxRasterPixels","maxRasterSize","widthWorld","heightWorld","step","padding","createRasterContext","worldToRaster","config","rasterizeStrokeMask","path","p","image","buildBoundaryEdges","mask","edges","vertex","at","turnPriority","fromDir","toDir","delta","traceLoops","outgoing","entry","used","loops","startVertex","currentVertex","currentDir","loop","guard","guardLimit","candidates","bestIndex","bestPriority","edgeIndex","candidate","priority","toWorldRing","vertexLoop","id","removeCollinearVertices","epsilon","curr","cross","pointLineDistanceSquared","abx","aby","len2","simplifyRdp","tolerance","keep","tolerance2","stack","start","end","maxDist2","split","dist2","simplifyClosedRing","open","simplified","smoothClosedRingChaikin","iterations","pass","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","smoothingPasses","EMPTY_DASH","EMPTY_REGIONS","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","REGION_INTERACTION_SHADOW_COLOR","REGION_INTERACTION_SHADOW_WIDTH","DEFAULT_REGION_LABEL_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_OFFSET","REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX","REGION_LABEL_AUTO_LIFT_MAX_EPSILON","DEFAULT_DRAW_PREVIEW_FILL","FREEHAND_MIN_POINTS","FREEHAND_SCREEN_STEP","CIRCLE_SIDES","MIN_AREA_PX","MICRONS_PER_MM","DEFAULT_STAMP_RECTANGLE_AREA_MM2","DEFAULT_STAMP_CIRCLE_AREA_MM2","DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE","LEGACY_HPF_CIRCLE_AREA_MM2","WHEEL_ZOOM_IN_FACTOR","WHEEL_ZOOM_OUT_FACTOR","DEFAULT_BRUSH_RADIUS","DEFAULT_BRUSH_FILL_COLOR","DEFAULT_BRUSH_FILL_OPACITY","DEFAULT_BRUSH_CURSOR_COLOR","DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR","DEFAULT_BRUSH_CURSOR_LINE_WIDTH","DEFAULT_BRUSH_CURSOR_DASH","DEFAULT_BRUSH_EDGE_DETAIL","MIN_BRUSH_EDGE_DETAIL","MAX_BRUSH_EDGE_DETAIL","DEFAULT_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_EDGE_SMOOTHING","MAX_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_RASTER_STEP","BRUSH_RASTER_DIAMETER_SAMPLES","BRUSH_SCREEN_STEP","clampWorld","coord","imageWidth","imageHeight","toDrawCoordinate","toCoord","polygonArea","computeBounds","tracePath","ctx","close","drawPath","strokeStyle","fill","fillColor","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isCoordinateRing","collectOverlayRings","item","normalizeOverlayRings","sourceRings","clampPositiveOrFallback","fallback","clampUnitOpacity","drawRoundedRect","r","isNestedRingCoordinates","createRectangle","projection","startScreen","endScreen","screenCorners","worldCorners","corner","world","createCircle","normalizeDrawRegionPolygons","normalizedOuter","holes","sanitizeBrushLineDash","resolveBrushEdgeDetail","resolveBrushEdgeSmoothing","resolveBrushOptions","cursorLineWidth","edgeDetail","edgeSmoothing","drawBrushStrokePreview","session","resolvedBrushOptions","screenPoints","radiusPx","drawBrushCursor","projector","cursor","screen","LABEL_MEASURE_FALLBACK_EM","LABEL_MEASURE_CACHE_LIMIT","TOP_ANCHOR_Y_TOLERANCE","sharedLabelMeasureContext","labelTextWidthCache","getLabelMeasureContext","measureLabelTextWidth","label","labelStyle","key","cached","measured","getTopAnchor","getTopAnchorFromPolygons","best","anchor","resolveRegionLabelStyle","px","py","fs","bw","oy","br","mergeRegionLabelStyle","resolveRegionLabelAutoLiftOffsetPx","enabled","zoomRange","minZoom","maxZoom","resolveDrawAreaTooltipStyle","fontSize","borderRadius","paddingX","paddingY","resolveTooltipCursorOffset","defaultDrawAreaTooltipFormatter","areaMm2","resolveDrawAreaTooltipOptions","format","cursorOffset","drawRegionLabel","text","canvasWidth","canvasHeight","boxWidth","boxHeight","left","top","drawAreaTooltipBox","cursorScreen","drawInvertedFillMask","outerRing","holeRings","drawOverlayShapes","params","overlayShapes","imageOuterRing","worldToScreenPoints","baseStrokeStyle","onInvertedFillDebug","debugOverlay","shape","renderRings","closedRings","isStampTool","tool","resolveStampOptions","mm2ToUm2","createSquareFromCenter","halfLength","screenCenter","screenEdge","screenHL","createCircleFromCenter","buildStampCoords","stampTool","resolvedStampOptions","micronsToWorldPixels","getRectangleProjection","areaUm2","resolveRegionInteractionShadowStyle","resolveDrawPreviewFillColor","isValidPolygon","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","drawFillColor","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","resolveRegionLabelStyleProp","hoveredRegionId","activeRegionId","regionLabelStyle","drawAreaTooltip","autoLiftRegionLabelAtMaxZoom","regionLabelAutoLiftOffsetPx","invalidateRef","className","canvasRef","useRef","drawPendingRef","overlayDebugSnapshotRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","index","mergedPatchRegions","preparedPersistedRegions","region","preparedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedDrawPreviewFillColor","resolvedLabelStyle","resolvedDrawAreaTooltipOptions","mergedStyle","resizeCanvas","useCallback","localScreenToWorld","raw","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoordsCallback","buildPreviewCoords","drawOverlay","regionIndex","regionKey","state","resolved","interactionShadowStyle","screenOuter","screenHole","info","debugKey","debugSignature","preview","line","labelAutoLiftOffset","anchorWorld","anchorScreen","dynamicLabelStyle","areaCoords","areaPx","requestDraw","resetSession","preserveCursor","toWorld","event","toLocalScreen","finishSession","tapPoint","screenPath","screenPolygon","worldPolygon","handleStampAt","intent","result","appendBrushPoint","minScreenStep2","prevScreen","handlePointerDown","handlePointerMove","minWorldStep","minWorldStep2","handlePointerUp","handlePointerLeave","changed","useEffect","observer","onKeyDown","jsx","trimTrailingSlash","ensureLeadingSlash","joinImsTileRoot","tileBaseUrl","parsed","origin","normalizeImageInfo","ims","isIms","tileSize","maxTierZoom","tilePath","normalizedPath","imsTileRoot","tileUrlBuilder","tier","toTileUrl","DEFAULT_OVERVIEW_MAP_OPTIONS","strokeSymmetricDashedPolygon","dashLen","gapLen","len","from","to","sideLen","fittedLen","scale","adjDash","adjGap","toPositiveNumber","isFiniteBounds","DEFAULT_CLOSE_BUTTON_STYLE","OverviewMap","authToken","thumbnailRef","lastBoundsRef","draggingRef","rafRef","contentRect","imgW","imgH","imageAspect","boxAspect","cw","ch","margin","borderWidth","maxThumbnailTiles","backgroundColor","borderColor","viewportBorderColor","viewportBorderStyle","viewportFillColor","interactive","showThumbnail","position","onClose","closeIcon","closeButtonStyle","pos","draw","cssW","cssH","pixelW","pixelH","cx","cy","corners","safeBounds","safeCorners","isDash","right","bottom","rectW","rectH","rectCorners","toWorldFromClient","clientX","clientY","scaleX","scaleY","cxPx","cyPx","cwPx","chPx","nx","ny","recenterTo","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","dw","dh","jsxs","TileViewerCanvas","rendererRef","renderer","filterPointDataByPolygons","empty","count","positions","fillModes","pointIds","nextPositions","nextTerms","nextFillModes","nextIds","output","filterPointIndicesByPolygons","contextPromise","BBOX_PREFILTER_SHADER","hasWebGpu","nav","getNavigatorGpu","gpu","GPU_SHADER_STAGE_COMPUTE","GPU_BUFFER_USAGE_STORAGE","GPU_BUFFER_USAGE_COPY_DST","GPU_BUFFER_USAGE_COPY_SRC","GPU_BUFFER_USAGE_UNIFORM","GPU_BUFFER_USAGE_MAP_READ","GPU_MAP_MODE_READ","getWebGpuCapabilities","navGpu","adapter","getContext","device","bindGroupLayout","pipeline","align","prefilterPointsByBoundsWebGpu","pointCount","boundsCount","safePointCount","positionBytes","boundsBytes","outputBytes","limit","positionsBuffer","boundsBuffer","outputBuffer","uniformBuffer","readBuffer","bindGroup","commandEncoder","mapped","filterPointDataByPolygonsHybrid","bridgeToDraw","data","safeCount","pointFillModes","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","compactData","WorkerClient","createWorker","handlers","message","pending","worker","reason","workerClient","_documentCurrentScript","msg","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","fillModesCopy","idsCopy","resolve","reject","startMs","requestTicket","transfer","canceled","filterPointIndicesByPolygonsInWorker","MIN_POINT_HIT_GRID_SIZE","MAX_POINT_HIT_GRID_SIZE","POINT_HIT_GRID_DENSITY_SCALE","HASH_EMPTY","cellHash","cellX","cellY","resolveGridSize","sourceWidth","sourceHeight","sanitizeDrawIndices","allValid","filtered","buildPointHitIndex","input","maxCountByPositions","cellSize","invCellSize","pointCellX","pointCellY","validCount","pi","estimatedCells","hashCapacity","hashMask","tempHashKeys","tempHashCounts","cellCount","pointCellSlot","slot","kx","oldCap","newKeys","newCounts","s","ocx","ocy","ns","cellKeys","cellOffsets","cellLengths","slotToCellIndex","cellIdx","offset","pointIndices","fillCursor","ci","srcIdx","finalCap","finalMask","hashTable","lookupCellIndex","buildFromResponse","terminatePointHitIndexWorker","buildSyncFallback","buildPointSpatialIndexAsync","drawIndicesCopy","prepareRegions","regions","resolveTermId","paletteIndex","paletteIndexToTermId","fromArray","fromMap","computeRoiPointGroups","baseCount","valid","idx","inputCount","preparedRegions","regionTermCounters","regionTotalCounters","insideCount","bestRegion","regionTermMap","includeEmptyRegions","groups","totalCount","termMap","termCounts","shouldAttachAuthHeader","url","host","TileScheduler","nextVisibleKeys","inflight","queued","visibleKeys","nextQueue","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","addRendererCanvasEventListeners","removeRendererCanvasEventListeners","resizeCanvasViewport","camera","DEFAULT_ROTATION_DRAG_SENSITIVITY","MIN_POINT_SIZE_PX","MAX_POINT_SIZE_PX","DEFAULT_POINT_SIZE_STOPS","MIN_STROKE_SCALE","MAX_STROKE_SCALE","MIN_POINT_INNER_FILL_OPACITY","MAX_POINT_INNER_FILL_OPACITY","MIN_IMAGE_COLOR_INPUT","MAX_IMAGE_COLOR_INPUT","MAX_VIEW_TRANSITION_DURATION_MS","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","normalizeStrokeScale","normalizePointInnerFillOpacity","normalizeImageColorInput","toNormalizedImageColorSettings","settings","brightnessInput","contrastInput","saturationInput","linearEasing","normalizeViewTransitionDuration","duration","normalizeZoomOverride","normalizeTransitionEasing","easing","getPointerAngleRad","cancelDrag","cancelViewAnimation","wantsRotate","clampViewState","emitViewState","requestRender","nextAngle","prevAngle","rawDelta","sensitivityScale","worldDx","worldDy","handleWheel","onZoomBy","factor","handleDoubleClick","handleContextMenu","dragging","getViewBounds","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","nextCenterX","nextCenterY","selectTier","rawTier","intersectsBounds","getVisibleTilesForTier","viewBounds","viewMinX","viewMinY","viewMaxX","viewMaxY","minTileX","maxTileX","minTileY","maxTileY","centerTileX","centerTileY","visible","getVisibleTiles","onPointerDownWithLock","onPointerMoveWithLock","onPointerUpWithLock","onWheelWithLock","onDoubleClickWithLock","onContextMenuWithLock","cancelInteractionDrag","createRendererInputHandlers","trimTileCache","cache","maxCacheTiles","entries","removeCount","createTextureFromBitmap","handleTileLoaded","frameSerial","destroyed","contextLost","deleteCachedTextures","handleContextLost","tileScheduler","onContextLost","frame","destroyRenderer","maxExclusive","getZeroFillModes","zeroFillModes","setPointPalette","runtime","pointProgram","nextPalette","paletteSize","setPointData","hasFillModes","nextPaletteIndices","hasDrawIndices","nextDrawIndices","prevHasFillModes","geometryChanged","drawIndicesChanged","nextRuntime","currentPointData","renderFrame","tileProgram","imageColorSettings","usePointIndices","pointPaletteSize","pointStrokeScale","pointInnerFillOpacity","pointSizePx","fallbackTiles","renderedTiles","missingTiles","tilesToSchedule","PREFETCH_DISTANCE_PENALTY","prefetchTiers","prefetchTier","prefetchCandidates","renderedPoints","initTileProgram","uCamera","uBounds","uTexture","uBrightness","uContrast","uSaturation","vbo","aUnit","aUv","initPointProgram","uPointSize","uPointStrokeScale","uPointInnerFillAlpha","uPalette","uPaletteSize","posBuffer","termBuffer","fillModeBuffer","indexBuffer","paletteTexture","posLoc","termLoc","fillModeLoc","startViewAnimation","target","durationMs","onUpdate","animation","elapsed","rawT","eased","resolveDefaultZoomBounds","fitZoom","resolveZoomBounds","minZoomOverride","maxZoomOverride","defaults","resolveTargetViewState","current","computeFitToImageTarget","viewportWidth","viewportHeight","clampedZoom","visibleWorldW","visibleWorldH","computeZoomByTarget","nextZoom","vp","WsiTileRenderer","cacheTileLoaded","attemptCount","inputHandlers","resolveManagedTargetViewState","clampManagedViewState","cancelManagedViewAnimation","cancelAnimation","nextMinOverride","nextMaxOverride","transition","setManagedPointPalette","setManagedPointData","locked","nextStops","opacity","cancelInputDrag","vw","vh","fitTarget","frameStartMs","getManagedVisibleTiles","getManagedVisibleTilesForTier","getManagedViewBounds","intersectsManagedBounds","schedulerStats","_event","REGION_CONTOUR_HIT_DISTANCE_PX","resolveRegionId","pointSegmentDistanceSq","lengthSq","isPointNearRing","maxDistanceSq","isPointNearPolygonContour","maxDistance","isScreenPointInsideLabel","screenCoord","prepareRegionHits","pickPreparedRegionAt","labelStyleResolver","labelAutoLiftOffsetPx","contourHitDistance","EMPTY_ROI_REGIONS","EMPTY_ROI_POLYGONS","EMPTY_CLIPPED_POINTS","POINT_HIT_RADIUS_SCALE","MIN_POINT_HIT_RADIUS_PX","REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS","smoothstep01","WsiViewerCanvas","onViewStateChange","onStats","onTileError","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","viewTransition","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onPointHover","onPointClick","onRegionHover","onRegionClick","controlledActiveRegionId","onActiveRegionChange","getCellByCoordinatesRef","overviewMapConfig","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","setHoveredRegionId","useState","uncontrolledActiveRegionId","setUncontrolledActiveRegionId","isActiveRegionControlled","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","setRegionLabelAutoLiftOffsetPx","hoveredRegionIdRef","hoveredPointIndexRef","hoveredPointIdRef","regionLabelAutoLiftOffsetRef","regionLabelAutoLiftAnimationRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","preparedRegionHits","resolvedRegionLabelStyle","applyRegionLabelAutoLiftOffset","clamped","cancelRegionLabelAutoLiftAnimation","animateRegionLabelAutoLiftTo","clampedTarget","timestamp","nextValue","syncRegionLabelAutoLiftTarget","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","stats","outputCount","shouldEnablePointHitTest","pointSpatialIndex","setPointSpatialIndex","nextIndex","getCellByCoordinates","coordinate","hitRadiusWorld","idxBuf","posBuf","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","off","pointId","emitPointHover","hit","nextId","emitPointClick","button","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","hoveredPointIndex","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","resolveCanvasPointerSnapshot","pickRegionHit","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","pointerSnapshot","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","handleBrushTap","handleRegionContextMenu","layer"],"mappings":"wWAAA,SAASA,GAAcC,EAA4BC,EAAcC,EAA6B,CAC5F,MAAMC,EAASH,EAAG,aAAaC,CAAI,EACnC,GAAI,CAACE,EACH,MAAM,IAAI,MAAM,0BAA0B,EAO5C,GAJAH,EAAG,aAAaG,EAAQD,CAAM,EAC9BF,EAAG,cAAcG,CAAM,EAGnB,CADOH,EAAG,mBAAmBG,EAAQH,EAAG,cAAc,EACjD,CACP,MAAMI,EAAMJ,EAAG,iBAAiBG,CAAM,GAAK,uBAC3C,MAAAH,EAAG,aAAaG,CAAM,EAChB,IAAI,MAAMC,CAAG,CACrB,CAEA,OAAOD,CACT,CAEO,SAASE,GAAcL,EAA4BM,EAAsBC,EAAsC,CACpH,MAAMC,EAAeT,GAAcC,EAAIA,EAAG,cAAeM,CAAY,EAC/DG,EAAiBV,GAAcC,EAAIA,EAAG,gBAAiBO,CAAc,EAErEG,EAAUV,EAAG,cAAA,EACnB,GAAI,CAACU,EACH,MAAAV,EAAG,aAAaQ,CAAY,EAC5BR,EAAG,aAAaS,CAAc,EACxB,IAAI,MAAM,2BAA2B,EAW7C,GARAT,EAAG,aAAaU,EAASF,CAAY,EACrCR,EAAG,aAAaU,EAASD,CAAc,EACvCT,EAAG,YAAYU,CAAO,EAEtBV,EAAG,aAAaQ,CAAY,EAC5BR,EAAG,aAAaS,CAAc,EAG1B,CADOT,EAAG,oBAAoBU,EAASV,EAAG,WAAW,EAChD,CACP,MAAMI,EAAMJ,EAAG,kBAAkBU,CAAO,GAAK,qBAC7C,MAAAV,EAAG,cAAcU,CAAO,EAClB,IAAI,MAAMN,CAAG,CACrB,CAEA,OAAOM,CACT,CAEO,SAASC,GACdX,EACAU,EACAE,EACsB,CACtB,MAAMC,EAAWb,EAAG,mBAAmBU,EAASE,CAAW,EAC3D,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,mCAAmCD,CAAW,EAAE,EAElE,OAAOC,CACT,CAEO,SAASC,GAAcC,EAAmD,CAC/E,MAAMC,EAAUD,EAAO,WAAW,SAAU,CAC1C,MAAO,GACP,UAAW,GACX,MAAO,GACP,QAAS,GACT,sBAAuB,GACvB,gBAAiB,kBAAA,CAClB,EAED,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,0BAA0B,EAG5C,OAAOA,CACT,CCjEA,SAASC,GAAUC,EAAqB,CACtC,OAAQA,EAAM,KAAK,GAAM,GAC3B,CAEO,MAAMC,EAAY,CAAlB,cACGC,EAAA,qBAAgB,GAChBA,EAAA,sBAAiB,GAEjBA,EAAA,iBAAuB,CAC7B,QAAS,EACT,QAAS,EACT,KAAM,EACN,YAAa,CAAA,GAGf,YAAYC,EAAeC,EAAsB,CAC/C,KAAK,cAAgB,KAAK,IAAI,EAAGD,CAAK,EACtC,KAAK,eAAiB,KAAK,IAAI,EAAGC,CAAM,CAC1C,CAEA,iBAAqD,CACnD,MAAO,CACL,MAAO,KAAK,cACZ,OAAQ,KAAK,cAAA,CAEjB,CAEA,aAAaC,EAAgC,CACvCA,EAAK,UAAY,SACnB,KAAK,UAAU,QAAUA,EAAK,SAG5BA,EAAK,UAAY,SACnB,KAAK,UAAU,QAAUA,EAAK,SAG5BA,EAAK,OAAS,SAChB,KAAK,UAAU,KAAO,KAAK,IAAI,KAAQA,EAAK,IAAI,GAG9C,OAAOA,EAAK,aAAgB,UAAY,OAAO,SAASA,EAAK,WAAW,IAC1E,KAAK,UAAU,YAAcA,EAAK,YAEtC,CAEA,cAA0B,CACxB,MAAO,CAAE,GAAG,KAAK,SAAA,CACnB,CAEA,WAAwB,CACtB,MAAMC,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EAC/C,MAAO,CACL,KAAK,UAAU,QAAU,KAAK,eAAiB,EAAIA,GACnD,KAAK,UAAU,QAAU,KAAK,gBAAkB,EAAIA,EAAA,CAExD,CAEA,UAAUC,EAAiBC,EAAuB,CAChD,MAAMF,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EAC/C,KAAK,UAAU,QAAUC,EAAU,KAAK,eAAiB,EAAID,GAC7D,KAAK,UAAU,QAAUE,EAAU,KAAK,gBAAkB,EAAIF,EAChE,CAEA,cAAcG,EAAiBC,EAA6B,CAC1D,MAAMJ,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EACzC,CAACC,EAASC,CAAO,EAAI,KAAK,UAAA,EAC1BG,EAAc,KAAK,UAAU,aAAe,EAC5CC,GAAMH,EAAU,KAAK,cAAgB,IAAOH,EAC5CO,GAAMH,EAAU,KAAK,eAAiB,IAAOJ,EAC7CQ,EAAMf,GAAUY,CAAW,EAC3BI,EAAM,KAAK,IAAID,CAAG,EAClBE,EAAM,KAAK,IAAIF,CAAG,EACxB,MAAO,CAACP,EAAUK,EAAKG,EAAMF,EAAKG,EAAKR,EAAUI,EAAKI,EAAMH,EAAKE,CAAG,CACtE,CAEA,cAAcE,EAAgBC,EAA4B,CACxD,MAAMZ,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EACzC,CAACC,EAASC,CAAO,EAAI,KAAK,UAAA,EAC1BG,EAAc,KAAK,UAAU,aAAe,EAC5CC,EAAKK,EAASV,EACdM,EAAKK,EAASV,EACdM,EAAMf,GAAUY,CAAW,EAC3BI,EAAM,KAAK,IAAID,CAAG,EAClBE,EAAM,KAAK,IAAIF,CAAG,EAClBK,EAAKP,EAAKG,EAAMF,EAAKG,EACrBI,EAAK,CAACR,EAAKI,EAAMH,EAAKE,EAC5B,MAAO,CACL,KAAK,cAAgB,GAAMI,EAAKb,EAChC,KAAK,eAAiB,GAAMc,EAAKd,CAAA,CAErC,CAEA,gBAAmE,CACjE,MAAMe,EAAI,KAAK,cACTC,EAAI,KAAK,eACf,MAAO,CACL,KAAK,cAAc,EAAG,CAAC,EACvB,KAAK,cAAcD,EAAG,CAAC,EACvB,KAAK,cAAcA,EAAGC,CAAC,EACvB,KAAK,cAAc,EAAGA,CAAC,CAAA,CAE3B,CAEA,WAA0B,CACxB,MAAMhB,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EACzCK,EAAc,KAAK,UAAU,aAAe,EAElD,GAAIA,IAAgB,EAAG,CACrB,MAAMY,EAAY,KAAK,cAAgBjB,EACjCkB,EAAa,KAAK,eAAiBlB,EACnCmB,EAAK,EAAIF,EACTG,EAAK,GAAKF,EACVG,EAAK,GAAK,KAAK,UAAU,QAAUF,EACnCG,EAAK,EAAI,KAAK,UAAU,QAAUF,EACxC,OAAO,IAAI,aAAa,CAACD,EAAI,EAAG,EAAG,EAAGC,EAAI,EAAGC,EAAIC,EAAI,CAAC,CAAC,CACzD,CAEA,KAAM,CAACrB,EAASC,CAAO,EAAI,KAAK,UAAA,EAC1BM,EAAMf,GAAUY,CAAW,EAC3BI,EAAM,KAAK,IAAID,CAAG,EAClBE,EAAM,KAAK,IAAIF,CAAG,EAClBe,EAAM,EAAIvB,EAAOS,EAAO,KAAK,cAC7Be,EAAM,EAAIxB,EAAOU,EAAO,KAAK,cAC7Be,EAAM,EAAIzB,EAAOU,EAAO,KAAK,eAC7BgB,EAAM,GAAK1B,EAAOS,EAAO,KAAK,eAC9BY,EAAK,EAAEE,EAAKtB,EAAUuB,EAAKtB,GAC3BoB,EAAK,EAAEG,EAAKxB,EAAUyB,EAAKxB,GACjC,OAAO,IAAI,aAAa,CAACqB,EAAIE,EAAI,EAAGD,EAAIE,EAAI,EAAGL,EAAIC,EAAI,CAAC,CAAC,CAC3D,CACF,CCpHA,MAAMK,GAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBhBC,GAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAajB,MAAMC,EAAe,CAsB3B,YAAYC,EAAgC,CArB3BlC,EAAA,eACAA,EAAA,WACAA,EAAA,cAAS,IAAID,IACbC,EAAA,mBACAA,EAAA,oBACAA,EAAA,mBACAA,EAAA,gBACAA,EAAA,YACAA,EAAA,mBACAA,EAAA,wBACAA,EAAA,wBACAA,EAAA,yBACAA,EAAA,uBAETA,EAAA,aAAsB,CAAA,GACtBA,EAAA,eAAyB,MACzBA,EAAA,mBAAc,GACdA,EAAA,iBAAY,IACZA,EAAA,cAAS,IACTA,EAAA,2BAAsB,IAG7B,KAAK,OAASkC,EAAQ,OACtB,KAAK,WAAa,KAAK,IAAI,EAAGA,EAAQ,UAAU,EAChD,KAAK,YAAc,KAAK,IAAI,EAAGA,EAAQ,WAAW,EAClD,KAAK,WAAaA,EAAQ,YAAc,CAAC,IAAM,IAAM,IAAM,CAAC,EAE5D,KAAK,GAAKxC,GAAc,KAAK,MAAM,EACnC,KAAK,QAAUT,GAAc,KAAK,GAAI8C,GAAeC,EAAe,EAEpE,MAAMG,EAAM,KAAK,GAAG,kBAAA,EACdC,EAAa,KAAK,GAAG,aAAA,EAC3B,GAAI,CAACD,GAAO,CAACC,EACZ,MAAM,IAAI,MAAM,iCAAiC,EAGlD,KAAK,IAAMD,EACX,KAAK,WAAaC,EAElB,KAAK,GAAG,gBAAgB,KAAK,GAAG,EAChC,KAAK,GAAG,WAAW,KAAK,GAAG,aAAc,KAAK,UAAU,EAExD,MAAMC,EAAe,IAAI,aAAa,CACrC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAA,CAC7C,EAED,KAAK,GAAG,WAAW,KAAK,GAAG,aAAcA,EAAc,KAAK,GAAG,WAAW,EAE1E,MAAMC,EAAe,KAAK,GAAG,kBAAkB,KAAK,QAAS,OAAO,EAC9DC,EAAa,KAAK,GAAG,kBAAkB,KAAK,QAAS,KAAK,EAChE,GAAID,EAAe,GAAKC,EAAa,EACpC,MAAM,IAAI,MAAM,oCAAoC,EAGrD,MAAMC,EAAS,EAAI,aAAa,kBAChC,KAAK,GAAG,wBAAwBF,CAAY,EAC5C,KAAK,GAAG,oBACPA,EACA,EACA,KAAK,GAAG,MACR,GACAE,EACA,CAAA,EAED,KAAK,GAAG,wBAAwBD,CAAU,EAC1C,KAAK,GAAG,oBACPA,EACA,EACA,KAAK,GAAG,MACR,GACAC,EACA,EAAI,aAAa,iBAAA,EAGlB,KAAK,GAAG,gBAAgB,IAAI,EAC5B,KAAK,GAAG,WAAW,KAAK,GAAG,aAAc,IAAI,EAE7C,KAAK,gBAAkBjD,GACtB,KAAK,GACL,KAAK,QACL,SAAA,EAED,KAAK,gBAAkBA,GACtB,KAAK,GACL,KAAK,QACL,SAAA,EAED,KAAK,iBAAmBA,GACvB,KAAK,GACL,KAAK,QACL,UAAA,EAGG2C,EAAQ,mBACX,KAAK,oBAAsB,GAC3B,KAAK,OAAO,aAAaA,EAAQ,gBAAgB,GAGlD,KAAK,eAAiB,IAAI,eAAe,IAAM,CAC9C,KAAK,OAAA,CACN,CAAC,EAED,KAAK,eAAe,QAAQ,KAAK,MAAM,EACvC,KAAK,OAAA,CACN,CAEA,MAAM,SAASO,EAAwC,CACtD,GAAI,KAAK,UACR,OAGD,MAAMC,EAAU,EAAE,KAAK,YAEjBC,EAAS,MAAM,QAAQ,IAC5BF,EAAM,IAAI,MAAOG,GACG,MAAM,KAAK,SAASA,EAAMF,CAAO,CAEpD,CAAA,EAGF,GAAI,KAAK,WAAaA,IAAY,KAAK,YAAa,CACnD,UAAWE,KAAQD,EACdC,GACH,KAAK,GAAG,cAAcA,EAAK,OAAO,EAGpC,MACD,CAEA,KAAK,aAAa,KAAK,KAAK,EAC5B,KAAK,MAAQD,EAAO,OAAQC,GAA6BA,IAAS,IAAI,EACtE,KAAK,cAAA,CACN,CAEA,aAAaC,EAAqC,CACjD,KAAK,oBAAsB,GAC3B,KAAK,OAAO,aAAaA,CAAS,EAClC,KAAK,cAAA,CACN,CAEA,cAA0B,CACzB,OAAO,KAAK,OAAO,aAAA,CACpB,CAEA,SAAgB,CACX,KAAK,YAIT,KAAK,UAAY,GACjB,KAAK,aAAe,EAEhB,KAAK,UAAY,OACpB,qBAAqB,KAAK,OAAO,EACjC,KAAK,QAAU,MAGhB,KAAK,eAAe,WAAA,EACpB,KAAK,aAAa,KAAK,KAAK,EAC5B,KAAK,MAAQ,CAAA,EAEb,KAAK,GAAG,aAAa,KAAK,UAAU,EACpC,KAAK,GAAG,kBAAkB,KAAK,GAAG,EAClC,KAAK,GAAG,cAAc,KAAK,OAAO,EACnC,CAEA,MAAc,SACbD,EACAF,EAC6B,CAC7B,GAAI,CACH,MAAMI,EAAW,MAAM,MAAMF,EAAK,GAAG,EACrC,GAAI,CAACE,EAAS,GACb,MAAM,IAAI,MACT,sBAAsBA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAA,EAI9D,MAAMC,EAAO,MAAMD,EAAS,KAAA,EACtBE,EAAS,MAAM,kBAAkBD,CAAI,EAE3C,GAAI,KAAK,WAAaL,IAAY,KAAK,YACtC,OAAAM,EAAO,MAAA,EACA,KAGR,MAAMC,EAAU,KAAK,GAAG,cAAA,EACxB,GAAI,CAACA,EACJ,MAAAD,EAAO,MAAA,EACD,IAAI,MAAM,gCAAgC,EAGjD,YAAK,GAAG,YAAY,KAAK,GAAG,WAAYC,CAAO,EAC/C,KAAK,GAAG,YAAY,KAAK,GAAG,oBAAqB,CAAC,EAClD,KAAK,GAAG,cACP,KAAK,GAAG,WACR,KAAK,GAAG,eACR,KAAK,GAAG,aAAA,EAET,KAAK,GAAG,cACP,KAAK,GAAG,WACR,KAAK,GAAG,eACR,KAAK,GAAG,aAAA,EAET,KAAK,GAAG,cACP,KAAK,GAAG,WACR,KAAK,GAAG,mBACR,KAAK,GAAG,MAAA,EAET,KAAK,GAAG,cACP,KAAK,GAAG,WACR,KAAK,GAAG,mBACR,KAAK,GAAG,MAAA,EAET,KAAK,GAAG,WACP,KAAK,GAAG,WACR,EACA,KAAK,GAAG,KACR,KAAK,GAAG,KACR,KAAK,GAAG,cACRD,CAAA,EAED,KAAK,GAAG,YAAY,KAAK,GAAG,WAAY,IAAI,EAC5CA,EAAO,MAAA,EAEA,CACN,GAAIJ,EAAK,GACT,OAAQA,EAAK,OACb,QAAAK,CAAA,CAEF,OAASC,EAAO,CACf,eAAQ,MAAM,sCAAsCN,EAAK,EAAE,GAAIM,CAAK,EAC7D,IACR,CACD,CAEQ,QAAe,CACtB,GAAI,KAAK,UACR,OAGD,MAAMC,EAAO,KAAK,OAAO,sBAAA,EACnBC,EAAW,KAAK,IAAI,EAAGD,EAAK,OAAS,KAAK,OAAO,aAAe,CAAC,EACjEE,EAAY,KAAK,IAAI,EAAGF,EAAK,QAAU,KAAK,OAAO,cAAgB,CAAC,EACpEG,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAE9CC,EAAc,KAAK,IAAI,EAAG,KAAK,MAAMH,EAAWE,CAAG,CAAC,EACpDE,EAAe,KAAK,IAAI,EAAG,KAAK,MAAMH,EAAYC,CAAG,CAAC,GAG3D,KAAK,OAAO,QAAUC,GACtB,KAAK,OAAO,SAAWC,KAEvB,KAAK,OAAO,MAAQD,EACpB,KAAK,OAAO,OAASC,GAGtB,KAAK,OAAO,YAAYJ,EAAUC,CAAS,EAC3C,KAAK,GAAG,SAAS,EAAG,EAAG,KAAK,OAAO,MAAO,KAAK,OAAO,MAAM,EAExD,CAAC,KAAK,QAAU,CAAC,KAAK,sBACzB,KAAK,WAAA,EACL,KAAK,OAAS,IAGf,KAAK,cAAA,CACN,CAEQ,YAAmB,CAC1B,MAAMI,EAAW,KAAK,OAAO,gBAAA,EAEvBrD,EAAO,KAAK,IACjBqD,EAAS,MAAQ,KAAK,WACtBA,EAAS,OAAS,KAAK,WAAA,EAElBC,EAAW,OAAO,SAAStD,CAAI,GAAKA,EAAO,EAAIA,EAAO,EAEtDuD,EAAoBF,EAAS,MAAQC,EACrCE,EAAqBH,EAAS,OAASC,EAEvCG,GAAW,KAAK,WAAaF,GAAqB,GAClDG,GAAW,KAAK,YAAcF,GAAsB,GAE1D,KAAK,OAAO,aAAa,CACxB,KAAMF,EACN,QAAAG,EACA,QAAAC,CAAA,CACA,CACF,CAEQ,eAAsB,CACzB,KAAK,UAAY,MAAQ,KAAK,YAIlC,KAAK,QAAU,sBAAsB,IAAM,CAC1C,KAAK,QAAU,KACf,KAAK,OAAA,CACN,CAAC,EACF,CAEQ,QAAe,CACtB,GAAI,MAAK,UAIT,MAAK,GAAG,WACP,KAAK,WAAW,CAAC,EACjB,KAAK,WAAW,CAAC,EACjB,KAAK,WAAW,CAAC,EACjB,KAAK,WAAW,CAAC,CAAA,EAElB,KAAK,GAAG,MAAM,KAAK,GAAG,gBAAgB,EAEtC,KAAK,GAAG,WAAW,KAAK,OAAO,EAC/B,KAAK,GAAG,gBAAgB,KAAK,GAAG,EAChC,KAAK,GAAG,iBACP,KAAK,gBACL,GACA,KAAK,OAAO,UAAA,CAAU,EAEvB,KAAK,GAAG,UAAU,KAAK,iBAAkB,CAAC,EAE1C,UAAWlB,KAAQ,KAAK,MACvB,KAAK,GAAG,cAAc,KAAK,GAAG,QAAQ,EACtC,KAAK,GAAG,YAAY,KAAK,GAAG,WAAYA,EAAK,OAAO,EACpD,KAAK,GAAG,UACP,KAAK,gBACLA,EAAK,OAAO,CAAC,EACbA,EAAK,OAAO,CAAC,EACbA,EAAK,OAAO,CAAC,EACbA,EAAK,OAAO,CAAC,CAAA,EAEd,KAAK,GAAG,WAAW,KAAK,GAAG,eAAgB,EAAG,CAAC,EAGhD,KAAK,GAAG,YAAY,KAAK,GAAG,WAAY,IAAI,EAC5C,KAAK,GAAG,gBAAgB,IAAI,EAC7B,CAEQ,aAAaH,EAA2B,CAC/C,UAAWG,KAAQH,EAClB,KAAK,GAAG,cAAcG,EAAK,OAAO,CAEpC,CACD,CCzYO,SAASmB,GAAcC,EAAiD,CAC9E,OAAIA,GAAuB,IAE5B,CAYA,SAASC,GAAeC,EAAiC,CACxD,OAAO,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,CAC1D,CAEA,SAASC,GAAiBD,EAAwC,CACjE,OACC,MAAM,QAAQA,CAAK,GACnBA,EAAM,QAAU,GAChBD,GAAeC,EAAM,CAAC,CAAC,GACvBD,GAAeC,EAAM,CAAC,CAAC,CAEzB,CAEA,SAASE,GAAaF,EAAwC,CAC7D,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,GAAKA,EAAM,MAAMG,GAASF,GAAiBE,CAAK,CAAC,CAChG,CAEA,SAASC,GAAeJ,EAA0C,CACjE,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,GAAKA,EAAM,MAAMK,GAAQH,GAAaG,CAAI,CAAC,CAC1F,CAEA,SAASC,GAAeN,EAA0C,CACjE,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,GAAKA,EAAM,MAAMO,GAAWH,GAAeG,CAAO,CAAC,CAClG,CAEO,SAASC,GAAaC,EAAsD,CAClF,GAAI,CAAC,MAAM,QAAQA,CAAW,GAAKA,EAAY,OAAS,EAAG,MAAO,CAAA,EAClE,MAAMC,EAAqB,CAAA,EAC3B,UAAWP,KAASM,EAAa,CAChC,GAAI,CAAC,MAAM,QAAQN,CAAK,GAAKA,EAAM,OAAS,EAAG,SAC/C,MAAMQ,EAAI,OAAOR,EAAM,CAAC,CAAC,EACnBS,EAAI,OAAOT,EAAM,CAAC,CAAC,EACzB,GAAI,CAAC,OAAO,SAASQ,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAG,SAChD,MAAMC,EAAOH,EAAIA,EAAI,OAAS,CAAC,EAC3BG,GAAQA,EAAK,CAAC,IAAMF,GAAKE,EAAK,CAAC,IAAMD,GACzCF,EAAI,KAAK,CAACC,EAAGC,CAAC,CAAC,CAChB,CACA,GAAIF,EAAI,OAAS,EAAG,MAAO,CAAA,EAC3B,MAAMI,EAAQJ,EAAI,CAAC,EACbK,EAAOL,EAAIA,EAAI,OAAS,CAAC,EAC/B,OAAII,EAAM,CAAC,IAAMC,EAAK,CAAC,GAAKD,EAAM,CAAC,IAAMC,EAAK,CAAC,IAC9CL,EAAI,KAAK,CAACI,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAAC,EAEvBJ,EAAI,QAAU,EAAIA,EAAM,CAAA,CAChC,CAEO,SAASM,GAAkBX,EAA6B,CAC9D,GAAI,CAAC,MAAM,QAAQA,CAAI,GAAKA,EAAK,OAAS,EAAG,MAAO,GACpD,IAAIY,EAAM,EACV,QAASC,EAAI,EAAGA,EAAIb,EAAK,OAAS,EAAGa,GAAK,EAAG,CAC5C,MAAMC,EAAId,EAAKa,CAAC,EACVE,EAAIf,EAAKa,EAAI,CAAC,EACpBD,GAAOE,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAID,EAAE,CAAC,CAChC,CACA,OAAOF,EAAM,EACd,CAEA,SAASI,GAAsBC,EAAyC,CACvE,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,SAAW,EAAG,MAAO,CAAA,EACxD,MAAMC,EAA8B,CAAA,EACpC,UAAWlB,KAAQiB,EAAO,CACzB,MAAME,EAAShB,GAAaH,CAAI,EAC5BmB,EAAO,QAAU,GAAGD,EAAW,KAAKC,CAAM,CAC/C,CACA,GAAID,EAAW,SAAW,EAAG,MAAO,CAAA,EACpC,GAAIA,EAAW,SAAW,QAAU,CAACA,EAAW,CAAC,CAAC,EAElD,IAAIE,EAAa,EACbC,EAAY,EAChB,QAASR,EAAI,EAAGA,EAAIK,EAAW,OAAQL,GAAK,EAAG,CAC9C,MAAMS,EAAO,KAAK,IAAIX,GAAkBO,EAAWL,CAAC,CAAC,CAAC,EAClDS,GAAQD,IACZA,EAAYC,EACZF,EAAaP,EACd,CAEA,MAAMR,EAAuB,CAACa,EAAWE,CAAU,CAAC,EACpD,QAASP,EAAI,EAAGA,EAAIK,EAAW,OAAQL,GAAK,EACvCA,IAAMO,GACVf,EAAI,KAAKa,EAAWL,CAAC,CAAC,EAEvB,OAAOR,CACR,CAEO,SAASkB,GAAqBC,EAA2D,CAC/F,GAAI,CAACA,EAAU,MAAO,CAAA,EAEtB,GAAI3B,GAAa2B,CAAQ,EAAG,CAC3B,MAAMtB,EAAUc,GAAsB,CAACQ,CAAQ,CAAC,EAChD,OAAOtB,EAAQ,OAAS,EAAI,CAACA,CAAO,EAAI,CAAA,CACzC,CAEA,GAAIH,GAAeyB,CAAQ,EAAG,CAC7B,MAAMtB,EAAUc,GAAsBQ,CAAQ,EAC9C,OAAOtB,EAAQ,OAAS,EAAI,CAACA,CAAO,EAAI,CAAA,CACzC,CAEA,GAAID,GAAeuB,CAAQ,EAAG,CAC7B,MAAMnB,EAAuB,CAAA,EAC7B,UAAWH,KAAWsB,EAAU,CAC/B,MAAMN,EAAaF,GAAsBd,CAAO,EAC5CgB,EAAW,OAAS,GAAGb,EAAI,KAAKa,CAAU,CAC/C,CACA,OAAOb,CACR,CAEA,MAAO,CAAA,CACR,CAEO,SAASoB,GAAYnB,EAAWC,EAAWP,EAA8B,CAC/E,IAAI0B,EAAS,GACb,QAAS,EAAI,EAAGC,EAAI3B,EAAK,OAAS,EAAG,EAAIA,EAAK,OAAQ2B,EAAI,EAAG,GAAK,EAAG,CACpE,MAAMC,EAAK5B,EAAK,CAAC,EAAE,CAAC,EACd6B,EAAK7B,EAAK,CAAC,EAAE,CAAC,EACd8B,EAAK9B,EAAK2B,CAAC,EAAE,CAAC,EACdI,EAAK/B,EAAK2B,CAAC,EAAE,CAAC,EAEnBE,EAAKtB,GAAMwB,EAAKxB,GAChBD,GAAMwB,EAAKF,IAAOrB,EAAIsB,IAASE,EAAKF,GAAO,OAAO,SAAWD,MACtC,CAACF,EAC1B,CACA,OAAOA,CACR,CAmBO,SAASM,GACfC,EACuB,CACvB,MAAMC,EAAiC,CAAA,EACvC,UAAWV,KAAYS,GAAc,GAAI,CACxC,MAAME,EAAeZ,GAAqBC,CAAQ,EAClD,UAAWtB,KAAWiC,EAAc,CACnC,MAAMC,EAAQlC,EAAQ,CAAC,EACvB,GAAI,CAACkC,GAASA,EAAM,OAAS,EAAG,SAChC,IAAIC,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClC,EAAGC,CAAC,IAAK6B,EAChB9B,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GACjBC,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GAEtB,GACC,CAAC,OAAO,SAAS8B,CAAI,GACrB,CAAC,OAAO,SAASC,CAAI,GACrB,CAAC,OAAO,SAASC,CAAI,GACrB,CAAC,OAAO,SAASC,CAAI,EAErB,SAED,IAAIlB,EAAO,KAAK,IAAIX,GAAkByB,CAAK,CAAC,EAC5C,QAASvB,EAAI,EAAGA,EAAIX,EAAQ,OAAQW,GAAK,EACxCS,GAAQ,KAAK,IAAIX,GAAkBT,EAAQW,CAAC,CAAC,CAAC,EAE/CqB,EAAS,KAAK,CACb,MAAAE,EACA,MAAOlC,EAAQ,MAAM,CAAC,EACtB,KAAAmC,EACA,KAAAC,EACA,KAAAC,EACA,KAAAC,EACA,KAAM,KAAK,IAAI,KAAMlB,CAAI,CAAA,CACzB,CACF,CACD,CACA,OAAOY,CACR,CAEO,SAASO,GACfnC,EACAC,EACAL,EACU,CAIV,GAHII,EAAIJ,EAAQ,MAAQI,EAAIJ,EAAQ,MAAQK,EAAIL,EAAQ,MAAQK,EAAIL,EAAQ,MAGxE,CAACuB,GAAYnB,EAAGC,EAAGL,EAAQ,KAAK,EAAG,MAAO,GAC9C,UAAWwC,KAAQxC,EAAQ,MAC1B,GAAIuB,GAAYnB,EAAGC,EAAGmC,CAAI,EAAG,MAAO,GAErC,MAAO,EACR,CAEO,SAASC,GACfrC,EACAC,EACAqC,EACU,CACV,UAAW1C,KAAW0C,EACrB,GAAKH,GAAuBnC,EAAGC,EAAGL,CAAO,EACzC,MAAO,GAER,MAAO,EACR,CC5OO,MAAM2C,GAAwD,CACpE,IAAK,IAAK,IAAK,GAChB,ECCO,SAASC,EAAMnD,EAAeoD,EAAaC,EAAqB,CACtE,OAAO,KAAK,IAAID,EAAK,KAAK,IAAIC,EAAKrD,CAAK,CAAC,CAC1C,CAEO,SAASsD,GACfC,EACAC,EACAC,EACS,CACT,MAAMC,EAAM,OAAOH,CAAQ,EACrBI,EAAK,OAAOH,CAAS,EACrBI,EAAK,OAAOH,CAAW,EAC7B,MAAI,CAAC,OAAO,SAASC,CAAG,GAAKA,GAAO,EAAU,EAC1C,CAAC,OAAO,SAASC,CAAE,GAAK,CAAC,OAAO,SAASC,CAAE,EAAUF,EAClD,KAAK,IAAI,EAAGC,EAAKC,CAAE,EAAIF,CAC/B,CAEO,SAASG,GACfN,EACAC,EACAC,EACS,CAET,IAAIK,EAAS,IADMR,GAAoBC,EAAUC,EAAWC,CAAW,EAEvE,GAAI,OAAOF,CAAQ,EAAG,CACrB,IAAIQ,EAAO,KACX,OAAID,EAAS,MACZA,GAAU,IACVC,EAAO,MAED,GAAGD,EAAO,YAAY,CAAC,CAAC,IAAIC,CAAI,EACxC,CACA,MAAO,GAAG,KAAK,MAAMD,EAAS,GAAI,EAAI,GAAI,SAC3C,CAEO,SAASE,IAAgB,CAC/B,OAAI,OAAO,YAAgB,KAAe,OAAO,YAAY,KAAQ,WAC7D,YAAY,IAAA,EAEb,KAAK,IAAA,CACb,CAEO,SAASC,GAAmBC,EAAiC,CACnE,MAAMC,EACLD,EAAU,qBAAqB,WAC5BA,EAAU,UAAU,OACpB,OAAO,iBACX,OAAO,KAAK,IACX,EACA,KAAK,IACJ,KAAK,MAAMA,EAAU,OAAS,CAAC,EAC/B,KAAK,OAAOA,EAAU,WAAW,QAAU,GAAK,CAAC,EACjDA,EAAU,gBAAgB,QAAU,EACpCC,CAAA,CACD,CAEF,CAEO,SAASC,GACfjD,EACAC,EACU,CACV,MAAI,CAACD,GAAK,CAACC,EAAU,GACjB,CAACD,GAAK,CAACC,EAAU,GAEpB,KAAK,KAAKD,EAAE,MAAQ,IAAMC,EAAE,MAAQ,EAAE,EAAI,MAC1C,KAAK,KAAKD,EAAE,SAAW,IAAMC,EAAE,SAAW,EAAE,EAAI,MAChD,KAAK,KAAKD,EAAE,SAAW,IAAMC,EAAE,SAAW,EAAE,EAAI,MAChD,KAAK,KAAKD,EAAE,aAAe,IAAMC,EAAE,aAAe,EAAE,EAAI,IAE1D,CAEO,SAASiD,GAAcrE,EAA0C,CACvE,MAAMsE,EAAU,OAAOtE,GAAS,EAAE,EAAE,KAAA,EACpC,GAAI,CAACsE,EAAS,MAAO,GACrB,GAAI,cAAc,KAAKA,CAAO,EAAG,CAChC,MAAMC,EAAQD,EAAQ,QAAQ,cAAe,EAAE,EAAE,KAAA,EACjD,OAAOC,EAAQ,UAAUA,CAAK,GAAK,EACpC,CACA,MAAO,UAAUD,CAAO,EACzB,CAEO,SAASE,GACfC,EACmC,CAEnC,MAAMC,EADQ,OAAOD,GAAO,EAAE,EAAE,KAAA,EACZ,MAAM,sBAAsB,EAChD,GAAI,CAACC,EAAO,MAAO,CAAC,GAAGxB,EAAmB,EAE1C,MAAMyB,EAAI,OAAO,SAASD,EAAM,CAAC,EAAG,EAAE,EACtC,MAAO,CAAEC,GAAK,GAAM,IAAMA,GAAK,EAAK,IAAKA,EAAI,IAAK,GAAG,CACtD,CAEO,SAASC,GACfC,EAIc,CACd,MAAMC,EAAmD,CACxD,CAAC,GAAG5B,EAAmB,CAAA,EAElB6B,MAAyB,IAE/B,UAAWC,KAAQH,GAAS,GAAI,CAC/B,MAAMI,EAAS,OAAOD,GAAM,QAAU,EAAE,EACpC,CAACC,GAAUF,EAAmB,IAAIE,CAAM,IAE5CF,EAAmB,IAAIE,EAAQH,EAAQ,MAAM,EAC7CA,EAAQ,KAAKN,GAAUQ,GAAM,SAAS,CAAC,EACxC,CAEA,MAAME,EAAS,IAAI,WAAWJ,EAAQ,OAAS,CAAC,EAChD,QAAS,EAAI,EAAG,EAAIA,EAAQ,OAAQ,GAAK,EACxCI,EAAO,EAAI,CAAC,EAAIJ,EAAQ,CAAC,EAAE,CAAC,EAC5BI,EAAO,EAAI,EAAI,CAAC,EAAIJ,EAAQ,CAAC,EAAE,CAAC,EAChCI,EAAO,EAAI,EAAI,CAAC,EAAIJ,EAAQ,CAAC,EAAE,CAAC,EAChCI,EAAO,EAAI,EAAI,CAAC,EAAIJ,EAAQ,CAAC,EAAE,CAAC,EAGjC,MAAO,CAAE,OAAAI,EAAQ,mBAAAH,CAAA,CAClB,CC5FA,MAAMI,GAA0B,GAC1BC,GAA4B,IAC5BC,GAA0B,KAC1BC,GAAuB,GACvBC,GAA2B,EAC3BC,GAAuB,EACvBC,GAAa,KACbC,GAAkB,GAExB,SAASC,GACRC,EAC0B,CAC1B,GAAI,CAAC,MAAM,QAAQA,CAAM,GAAKA,EAAO,SAAW,EAAG,MAAO,CAAA,EAC1D,MAAMlF,EAA+B,CAAA,EACrC,UAAWP,KAASyF,EAAQ,CAC3B,GAAI,CAAC,MAAM,QAAQzF,CAAK,GAAKA,EAAM,OAAS,EAAG,SAC/C,MAAMQ,EAAI,OAAOR,EAAM,CAAC,CAAC,EACnBS,EAAI,OAAOT,EAAM,CAAC,CAAC,EACzB,GAAI,CAAC,OAAO,SAASQ,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAG,SAChD,MAAMC,EAAOH,EAAIA,EAAI,OAAS,CAAC,EAC3BG,GAAQ,KAAK,IAAIA,EAAK,CAAC,EAAIF,CAAC,EAAI,MAAQ,KAAK,IAAIE,EAAK,CAAC,EAAID,CAAC,EAAI,MAGpEF,EAAI,KAAK,CAACC,EAAGC,CAAC,CAAC,CAChB,CACA,OAAOF,CACR,CAEA,SAASmF,GACRC,EACAC,EACAC,EAC0B,CAC1B,GAAID,GAAUN,IAAcO,EAAQ,QAAU,CAAA,EAC9C,MAAM3F,EAAgC,CAAA,EACtC,QAAS,EAAI,EAAG,GAAK2F,EAAO,GAAK,EAAG,CACnC,MAAMC,EAAK,EAAID,EAAS,KAAK,GAAK,EAClC3F,EAAK,KAAK,CACTyF,EAAO,CAAC,EAAI,KAAK,IAAIG,CAAC,EAAIF,EAC1BD,EAAO,CAAC,EAAI,KAAK,IAAIG,CAAC,EAAIF,CAAA,CAC1B,CACF,CACA,OAAOG,GAAU7F,CAAI,CACtB,CAEA,SAAS8F,GACRP,EACAG,EAC0B,CAC1B,GAAI,CAACH,EAAO,OAAQ,MAAO,CAAA,EAC3B,IAAIlD,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClC,EAAGC,CAAC,IAAKgF,EAChBjF,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GACjBC,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GAEtB,GAAI,CAAC,OAAO,SAAS8B,CAAI,GAAK,CAAC,OAAO,SAASC,CAAI,EAAG,MAAO,CAAA,EAC7D,MAAMyD,EAAM,KAAK,IAAIL,EAAQ,CAAC,EAC9B,OAAOG,GAAU,CAChB,CAACxD,EAAO0D,EAAKzD,EAAOyD,CAAG,EACvB,CAACxD,EAAOwD,EAAKzD,EAAOyD,CAAG,EACvB,CAACxD,EAAOwD,EAAKvD,EAAOuD,CAAG,EACvB,CAAC1D,EAAO0D,EAAKvD,EAAOuD,CAAG,CAAA,CACvB,CACF,CAEA,SAASC,GACRT,EACAG,EACoB,CACpB,IAAIrD,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClC,EAAGC,CAAC,IAAKgF,EAChBjF,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GACjBC,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GAEtB,MAAMwF,EAAM,KAAK,IAAIL,EAAQ,CAAC,EAC9B,MAAO,CAACrD,EAAO0D,EAAKzD,EAAOyD,EAAKxD,EAAOwD,EAAKvD,EAAOuD,CAAG,CACvD,CAEA,SAASE,GACRC,EACAR,EACA/H,EACe,CACf,MAAMwI,EAAgB,KAAK,IAC1BrB,GACA,OAAOnH,EAAQ,aAAa,GAAK,CAAA,EAE5ByI,EAAkB,KAAK,IAC5B,MACA,KAAK,MAAMzI,EAAQ,iBAAmBoH,EAAyB,CAAA,EAE1DsB,EAAgB,KAAK,IAC1B,IACA,KAAK,MAAM1I,EAAQ,eAAiBqH,EAAuB,CAAA,EAGtDsB,EAAa,KAAK,IAAI,KAAMJ,EAAO,CAAC,EAAIA,EAAO,CAAC,CAAC,EACjDK,EAAc,KAAK,IAAI,KAAML,EAAO,CAAC,EAAIA,EAAO,CAAC,CAAC,EACxD,IAAIM,EAAO,KAAK,IAAIL,EAAe,OAAO,OAAO,EAC7CM,EAAU,EACV/K,EAAQ,KAAK,KAAK4K,EAAaE,CAAI,EAAIC,EAAU,EAAI,EACrD9K,EAAS,KAAK,KAAK4K,EAAcC,CAAI,EAAIC,EAAU,EAAI,EAE3D,MACC/K,EAAQ2K,GACR1K,EAAS0K,GACT3K,EAAQC,EAASyK,KAEjBI,GAAQ,KACR9K,EAAQ,KAAK,KAAK4K,EAAaE,CAAI,EAAIC,EAAU,EAAI,EACrD9K,EAAS,KAAK,KAAK4K,EAAcC,CAAI,EAAIC,EAAU,EAAI,EACnD,EAAAD,EAAO,KAAK,IAAIF,EAAYC,CAAW,KAA3C,CAKD,OAAA7K,EAAQ,KAAK,IAAI,EAAGA,CAAK,EACzBC,EAAS,KAAK,IAAI,EAAGA,CAAM,EAEpB,CACN,KAAMuK,EAAO,CAAC,EACd,KAAMA,EAAO,CAAC,EACd,KAAAM,EACA,QAAAC,EACA,MAAA/K,EACA,OAAAC,CAAA,CAEF,CAMA,SAAS+K,GACRhL,EACAC,EAC4B,CAC5B,GAAI,OAAO,gBAAoB,IAAa,CAE3C,MAAMN,EADS,IAAI,gBAAgBK,EAAOC,CAAM,EACzB,WAAW,KAAM,CAAE,mBAAoB,GAAM,EACpE,GAAIN,EAAS,OAAOA,CACrB,CACA,GAAI,OAAO,SAAa,IAAa,CACpC,MAAMD,EAAS,SAAS,cAAc,QAAQ,EAC9C,OAAAA,EAAO,MAAQM,EACfN,EAAO,OAASO,EACTP,EAAO,WAAW,KAAM,CAAE,mBAAoB,GAAM,CAC5D,CACA,OAAO,IACR,CAEA,SAASuL,GACR7G,EACA8G,EACwB,CACxB,MAAO,EACL9G,EAAM,CAAC,EAAI8G,EAAO,MAAQA,EAAO,KAAOA,EAAO,SAC/C9G,EAAM,CAAC,EAAI8G,EAAO,MAAQA,EAAO,KAAOA,EAAO,OAAA,CAElD,CAEA,SAASC,GACRC,EACApB,EACAkB,EACa,CACb,MAAMvL,EAAUqL,GAAoBE,EAAO,MAAOA,EAAO,MAAM,EAC/D,GAAI,CAACvL,EAAS,OAAO,IAAI,WAAW,CAAC,EAErCA,EAAQ,UAAU,EAAG,EAAGuL,EAAO,MAAOA,EAAO,MAAM,EACnDvL,EAAQ,UAAY,UACpBA,EAAQ,YAAc,UACtBA,EAAQ,QAAU,QAClBA,EAAQ,SAAW,QACnBA,EAAQ,UAAaqK,EAAS,EAAKkB,EAAO,KAE1C,MAAMrB,EAASuB,EAAK,OAAaH,GAAc7G,EAAO8G,CAAM,CAAC,EAC7D,GAAIrB,EAAO,QAAU,EAAG,CACvB,MAAMwB,EAAIxB,EAAO,CAAC,EAClB,GAAI,CAACwB,EAAG,OAAO,IAAI,WAAW,CAAC,EAC/B1L,EAAQ,UAAA,EACRA,EAAQ,IAAI0L,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGrB,EAASkB,EAAO,KAAM,EAAG,KAAK,GAAK,CAAC,EAC5DvL,EAAQ,KAAA,CACT,KAAO,CACNA,EAAQ,UAAA,EACRA,EAAQ,OAAOkK,EAAO,CAAC,EAAE,CAAC,EAAGA,EAAO,CAAC,EAAE,CAAC,CAAC,EACzC,QAAS1E,EAAI,EAAGA,EAAI0E,EAAO,OAAQ1E,GAAK,EACvCxF,EAAQ,OAAOkK,EAAO1E,CAAC,EAAE,CAAC,EAAG0E,EAAO1E,CAAC,EAAE,CAAC,CAAC,EAE1CxF,EAAQ,OAAA,CACT,CAEA,MAAM2L,EAAQ3L,EAAQ,aAAa,EAAG,EAAGuL,EAAO,MAAOA,EAAO,MAAM,EAC9DvG,EAAM,IAAI,WAAWuG,EAAO,MAAQA,EAAO,MAAM,EACvD,QAAS/F,EAAI,EAAGA,EAAIR,EAAI,OAAQQ,GAAK,EACpCR,EAAIQ,CAAC,EAAImG,EAAM,KAAKnG,EAAI,EAAI,CAAC,GAAKwE,GAAkB,EAAI,EAEzD,OAAOhF,CACR,CAEA,SAAS4G,GAAmBC,EAAkBxL,EAAeC,EAAgC,CAC5F,MAAMwL,EAAwB,CAAA,EACxBlJ,EAASvC,EAAQ,EACjB0L,EAAS,CAAC9G,EAAWC,IAAsBA,EAAItC,EAASqC,EACxD+G,EAAK,CAAC/G,EAAWC,IACtBD,GAAK,GAAKC,GAAK,GAAKD,EAAI5E,GAAS6E,EAAI5E,GAAUuL,EAAK3G,EAAI7E,EAAQ4E,CAAC,EAAI,EAEtE,QAASC,EAAI,EAAGA,EAAI5E,EAAQ4E,GAAK,EAChC,QAASD,EAAI,EAAGA,EAAI5E,EAAO4E,GAAK,EAC1B+G,EAAG/G,EAAGC,CAAC,IACP8G,EAAG/G,EAAGC,EAAI,CAAC,GACf4G,EAAM,KAAK,CACV,MAAOC,EAAO9G,EAAGC,CAAC,EAClB,IAAK6G,EAAO9G,EAAI,EAAGC,CAAC,EACpB,IAAK,CAAA,CACL,EAEG8G,EAAG/G,EAAI,EAAGC,CAAC,GACf4G,EAAM,KAAK,CACV,MAAOC,EAAO9G,EAAI,EAAGC,CAAC,EACtB,IAAK6G,EAAO9G,EAAI,EAAGC,EAAI,CAAC,EACxB,IAAK,CAAA,CACL,EAEG8G,EAAG/G,EAAGC,EAAI,CAAC,GACf4G,EAAM,KAAK,CACV,MAAOC,EAAO9G,EAAI,EAAGC,EAAI,CAAC,EAC1B,IAAK6G,EAAO9G,EAAGC,EAAI,CAAC,EACpB,IAAK,CAAA,CACL,EAEG8G,EAAG/G,EAAI,EAAGC,CAAC,GACf4G,EAAM,KAAK,CACV,MAAOC,EAAO9G,EAAGC,EAAI,CAAC,EACtB,IAAK6G,EAAO9G,EAAGC,CAAC,EAChB,IAAK,CAAA,CACL,GAKJ,OAAO4G,CACR,CAEA,SAASG,GAAaC,EAAiBC,EAAuB,CAC7D,MAAMC,GAASD,EAAQD,EAAU,GAAK,EACtC,OAAIE,IAAU,EAAU,EACpBA,IAAU,EAAU,EACpBA,IAAU,EAAU,EACjB,CACR,CAEA,SAASC,GAAWP,EAAmC,CACtD,GAAI,CAACA,EAAM,OAAQ,MAAO,CAAA,EAE1B,MAAMQ,MAAe,IACrB,QAAS,EAAI,EAAG,EAAIR,EAAM,OAAQ,GAAK,EAAG,CACzC,MAAMS,EAAQD,EAAS,IAAIR,EAAM,CAAC,EAAE,KAAK,EACrCS,EACHA,EAAM,KAAK,CAAC,EAEZD,EAAS,IAAIR,EAAM,CAAC,EAAE,MAAO,CAAC,CAAC,CAAC,CAElC,CAEA,MAAMU,EAAO,IAAI,WAAWV,EAAM,MAAM,EAClCW,EAAoB,CAAA,EAE1B,QAAS,EAAI,EAAG,EAAIX,EAAM,OAAQ,GAAK,EAAG,CACzC,GAAIU,EAAK,CAAC,EAAG,SAEb,MAAMpH,EAAQ0G,EAAM,CAAC,EACfY,EAActH,EAAM,MAC1B,IAAIuH,EAAgBvH,EAAM,IACtBwH,EAAaxH,EAAM,IACvB,MAAMyH,EAAiB,CAACzH,EAAM,MAAOA,EAAM,GAAG,EAC9CoH,EAAK,CAAC,EAAI,EAEV,IAAIM,EAAQ,EACZ,MAAMC,EAAajB,EAAM,OAAS,EAClC,KAAOa,IAAkBD,GAAeI,EAAQC,GAAY,CAC3D,MAAMC,EAAaV,EAAS,IAAIK,CAAa,EAC7C,GAAI,CAACK,GAAcA,EAAW,SAAW,EAAG,MAE5C,IAAIC,EAAY,GACZC,EAAe,IACnB,UAAWC,KAAaH,EAAY,CACnC,GAAIR,EAAKW,CAAS,EAAG,SACrB,MAAMC,EAAYtB,EAAMqB,CAAS,EAC3BE,EAAWpB,GAAaW,EAAYQ,EAAU,GAAG,EACnDC,EAAWH,IACdA,EAAeG,EACfJ,EAAYE,EAEd,CAEA,GAAIF,EAAY,EAAG,MACnBT,EAAKS,CAAS,EAAI,EAClB,MAAM1M,EAAOuL,EAAMmB,CAAS,EAC5BN,EAAgBpM,EAAK,IACrBqM,EAAarM,EAAK,IAClBsM,EAAK,KAAKF,CAAa,EACvBG,GAAS,CACV,CAGCD,EAAK,QAAU,GACfA,EAAK,CAAC,IAAMA,EAAKA,EAAK,OAAS,CAAC,GAEhCJ,EAAM,KAAKI,CAAI,CAEjB,CAEA,OAAOJ,CACR,CAEA,SAASa,GACRC,EACAlN,EACAkL,EAC0B,CAC1B,MAAM3I,EAASvC,EAAQ,EACjBsE,EAAgC,CAAA,EACtC,UAAW6I,KAAMD,EAAY,CAC5B,MAAMtI,EAAIuI,EAAK5K,EACTsC,EAAI,KAAK,MAAMsI,EAAK5K,CAAM,EAChC+B,EAAK,KAAK,CACT4G,EAAO,MAAQtG,EAAIsG,EAAO,SAAWA,EAAO,KAC5CA,EAAO,MAAQrG,EAAIqG,EAAO,SAAWA,EAAO,IAAA,CAC5C,CACF,CACA,OAAOf,GAAU7F,CAAI,CACtB,CAEA,SAAS8I,GACR9I,EACA+I,EAAU,KACgB,CAC1B,MAAM5H,EAAS0E,GAAU7F,CAAI,EAC7B,GAAImB,EAAO,OAAS,EAAG,OAAOA,EAC9B,MAAMd,EAA+B,CAACc,EAAO,CAAC,CAAC,EAC/C,QAAS,EAAI,EAAG,EAAIA,EAAO,OAAS,EAAG,GAAK,EAAG,CAC9C,MAAMX,EAAOH,EAAIA,EAAI,OAAS,CAAC,EACzB2I,EAAO7H,EAAO,CAAC,EACfvF,EAAOuF,EAAO,EAAI,CAAC,EACnB8H,GACJD,EAAK,CAAC,EAAIxI,EAAK,CAAC,IAAM5E,EAAK,CAAC,EAAIoN,EAAK,CAAC,IACtCA,EAAK,CAAC,EAAIxI,EAAK,CAAC,IAAM5E,EAAK,CAAC,EAAIoN,EAAK,CAAC,GACpC,KAAK,IAAIC,CAAK,GAAKF,GACvB1I,EAAI,KAAK2I,CAAI,CACd,CACA,OAAA3I,EAAI,KAAKA,EAAI,CAAC,CAAC,EACRwF,GAAUxF,CAAG,CACrB,CAEA,SAAS6I,GACRnC,EACAjG,EACAC,EACS,CACT,MAAMoI,EAAMpI,EAAE,CAAC,EAAID,EAAE,CAAC,EAChBsI,EAAMrI,EAAE,CAAC,EAAID,EAAE,CAAC,EAChBuI,EAAOF,EAAMA,EAAMC,EAAMA,EAC/B,GAAIC,GAAQ,MAAO,CAClB,MAAMlN,EAAK4K,EAAE,CAAC,EAAIjG,EAAE,CAAC,EACf1E,EAAK2K,EAAE,CAAC,EAAIjG,EAAE,CAAC,EACrB,OAAO3E,EAAKA,EAAKC,EAAKA,CACvB,CACA,MAAMwJ,EAAI9C,IACPiE,EAAE,CAAC,EAAIjG,EAAE,CAAC,GAAKqI,GAAOpC,EAAE,CAAC,EAAIjG,EAAE,CAAC,GAAKsI,GAAOC,EAC9C,EACA,CAAA,EAEK/I,EAAIQ,EAAE,CAAC,EAAIqI,EAAMvD,EACjBrF,EAAIO,EAAE,CAAC,EAAIsI,EAAMxD,EACjBzJ,EAAK4K,EAAE,CAAC,EAAIzG,EACZlE,EAAK2K,EAAE,CAAC,EAAIxG,EAClB,OAAOpE,EAAKA,EAAKC,EAAKA,CACvB,CAEA,SAASkN,GACR/D,EACAgE,EAC0B,CAC1B,GAAIhE,EAAO,QAAU,GAAKgE,GAAa,EAAG,OAAOhE,EAAO,MAAA,EAExD,MAAMiE,EAAO,IAAI,WAAWjE,EAAO,MAAM,EACzCiE,EAAK,CAAC,EAAI,EACVA,EAAKjE,EAAO,OAAS,CAAC,EAAI,EAC1B,MAAMkE,EAAaF,EAAYA,EACzBG,EAAiC,CAAC,CAAC,EAAGnE,EAAO,OAAS,CAAC,CAAC,EAE9D,KAAOmE,EAAM,OAAS,GAAG,CACxB,MAAM9N,EAAO8N,EAAM,IAAA,EACnB,GAAI,CAAC9N,EAAM,MACX,KAAM,CAAC+N,EAAOC,CAAG,EAAIhO,EACrB,GAAIgO,EAAMD,GAAS,EAAG,SAEtB,IAAIE,EAAW,EACXC,EAAQ,GACZ,QAASjJ,EAAI8I,EAAQ,EAAG9I,EAAI+I,EAAK/I,GAAK,EAAG,CACxC,MAAMkJ,EAAQb,GAAyB3D,EAAO1E,CAAC,EAAG0E,EAAOoE,CAAK,EAAGpE,EAAOqE,CAAG,CAAC,EACxEG,EAAQF,IACXA,EAAWE,EACXD,EAAQjJ,EAEV,CAEIiJ,GAAS,GAAKD,EAAWJ,IAC5BD,EAAKM,CAAK,EAAI,EACdJ,EAAM,KAAK,CAACC,EAAOG,CAAK,EAAG,CAACA,EAAOF,CAAG,CAAC,EAEzC,CAEA,MAAMvJ,EAA+B,CAAA,EACrC,QAASQ,EAAI,EAAGA,EAAI0E,EAAO,OAAQ1E,GAAK,EACnC2I,EAAK3I,CAAC,KAAO,KAAK0E,EAAO1E,CAAC,CAAC,EAEhC,OAAOR,CACR,CAEA,SAAS2J,GACRhK,EACAuJ,EAC0B,CAC1B,MAAMpI,EAAS0E,GAAU7F,CAAI,EAC7B,GAAImB,EAAO,OAAS,GAAKoI,GAAa,EAAG,OAAOpI,EAChD,MAAM8I,EAAO9I,EAAO,MAAM,EAAG,EAAE,EACzB+I,EAAaZ,GAAYW,EAAMV,CAAS,EAC9C,OAAIW,EAAW,OAAS,EAAU/I,EAC3B0E,GAAUqE,CAAU,CAC5B,CAEA,SAASC,GACRnK,EACAoK,EAC0B,CAC1B,IAAI/J,EAAMwF,GAAU7F,CAAI,EACxB,GAAIoK,GAAc,GAAK/J,EAAI,OAAS,EAAG,OAAOA,EAE9C,QAASgK,EAAO,EAAGA,EAAOD,EAAYC,GAAQ,EAAG,CAChD,MAAMJ,EAAO5J,EAAI,MAAM,EAAG,EAAE,EAC5B,GAAI4J,EAAK,OAAS,EAAG,MACrB,MAAMrO,EAAgC,CAAA,EACtC,QAASiF,EAAI,EAAGA,EAAIoJ,EAAK,OAAQpJ,GAAK,EAAG,CACxC,MAAM,EAAIoJ,EAAKpJ,CAAC,EACVE,EAAIkJ,GAAMpJ,EAAI,GAAKoJ,EAAK,MAAM,EACpCrO,EAAK,KACJ,CAAC,EAAE,CAAC,EAAI,IAAOmF,EAAE,CAAC,EAAI,IAAM,EAAE,CAAC,EAAI,IAAOA,EAAE,CAAC,EAAI,GAAI,EACrD,CAAC,EAAE,CAAC,EAAI,IAAOA,EAAE,CAAC,EAAI,IAAM,EAAE,CAAC,EAAI,IAAOA,EAAE,CAAC,EAAI,GAAI,CAAA,CAEvD,CACAV,EAAMwF,GAAUjK,CAAI,CACrB,CACA,OAAOyE,CACR,CAEA,SAASiK,GACRtK,EACAkG,EAC0B,CAC1B,OAAKA,EACEL,GACN7F,EAAK,IAAI,CAAC,CAACM,EAAGC,CAAC,IAAM,CACpBuC,EAAMxC,EAAG4F,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,EAC7BpD,EAAMvC,EAAG2F,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,CAAA,CACJ,CAAA,EALPlG,CAOrB,CAEO,SAASuK,GACfzD,EACAnJ,EAC0B,CAC1B,MAAM4H,EAASD,GAAawB,CAAI,EAC1BpB,EAAS,KAAK,IAAIN,GAAY,OAAOzH,EAAQ,MAAM,GAAK,CAAC,EAC/D,GAAI4H,EAAO,SAAW,GAAK,CAAC,OAAO,SAASG,CAAM,EAAG,MAAO,CAAA,EAE5D,MAAM8E,EAAc,KAAK,IAAI,GAAI,KAAK,MAAM7M,EAAQ,aAAesH,EAAoB,CAAC,EACxF,GAAIM,EAAO,SAAW,EACrB,OAAO+E,GACN9E,GAAoBD,EAAO,CAAC,EAAGG,EAAQ8E,CAAW,EAClD7M,EAAQ,UAAA,EAIV,MAAMuI,EAASF,GAAsBT,EAAQG,CAAM,EAC7C+E,EAASxE,GAAoBC,EAAQR,EAAQ/H,CAAO,EACpDuJ,EAAOL,GAAoBtB,EAAQG,EAAQ+E,CAAM,EACvD,GAAI,CAACvD,EAAK,OACT,OAAOoD,GAAkBxE,GAAqBP,EAAQG,CAAM,EAAG/H,EAAQ,UAAU,EAGlF,MAAMwJ,EAAQF,GAAmBC,EAAMuD,EAAO,MAAOA,EAAO,MAAM,EAC5D3C,EAAQJ,GAAWP,CAAK,EAC9B,GAAI,CAACW,EAAM,OACV,OAAOwC,GAAkBxE,GAAqBP,EAAQG,CAAM,EAAG/H,EAAQ,UAAU,EAGlF,IAAI+M,EAAoC,CAAA,EACpCC,EAAW,EACf,UAAWzC,KAAQJ,EAAO,CACzB,MAAM9H,EAAO2I,GAAYT,EAAMuC,EAAO,MAAOA,CAAM,EAC7CnJ,EAAO,KAAK,IAAIX,GAAkBX,CAAI,CAAC,EACzCsB,GAAQqJ,IACZA,EAAWrJ,EACXoJ,EAAW1K,EACZ,CAEA,GAAI,CAAC0K,EAAS,OACb,OAAOJ,GAAkBxE,GAAqBP,EAAQG,CAAM,EAAG/H,EAAQ,UAAU,EAGlF,MAAM4L,EACL,OAAO5L,EAAQ,mBAAsB,UAAY,OAAO,SAASA,EAAQ,iBAAiB,EACvF,KAAK,IAAI,EAAGA,EAAQ,iBAAiB,EACrC8M,EAAO,KAAO,GACZG,EACL,OAAOjN,EAAQ,iBAAoB,UAAY,OAAO,SAASA,EAAQ,eAAe,EACnF,KAAK,MAAMmF,EAAMnF,EAAQ,gBAAiB,EAAGwH,EAAoB,CAAC,EAClED,GACEgF,EAAaF,GAClBG,GACCrB,GAAwB4B,EAAUD,EAAO,KAAO,IAAI,EACpDG,CAAA,EAEDrB,CAAA,EAED,OAAOe,GAAkBJ,EAAYvM,EAAQ,UAAU,CACxD,CCvVO,MAAMkN,GAAuB,CAAA,EACvBC,GAA8B,CAAA,EAE9BC,GAAiD,CAC5D,MAAO,UACP,MAAO,EAEP,SAAU,QACV,QAAS,QACT,YAAa,mBACb,WAAY,EACZ,cAAe,EACf,cAAe,CACjB,EAEaC,GAAgD,CAC3D,MAAO,UACP,MAAO,EACP,SAAU,CAAC,GAAI,CAAC,EAChB,SAAU,QACV,QAAS,QACT,YAAa,mBACb,WAAY,EACZ,cAAe,EACf,cAAe,CACjB,EAEaC,GAAkC,wBAClCC,GAAkC,EAElCC,GAA+C,CAC1D,WAAY,wEACZ,SAAU,GACV,WAAY,IACZ,UAAW,UACX,gBAAiB,UACjB,YAAa,mBACb,YAAa,EACb,SAAU,EACV,SAAU,EACV,QAAS,GACT,aAAc,CAChB,EAEaC,GAAwD,CACnE,WAAY,wEACZ,SAAU,GACV,WAAY,IACZ,UAAW,UACX,gBAAiB,wBACjB,aAAc,EACd,SAAU,EACV,SAAU,CACZ,EAEaC,GAAmC,CAC9C,EAAG,GACH,EAAG,GACL,EAEaC,GAAuC,GACvCC,GAAqC,KAGrCC,GAA4B,cAC5BC,GAAsB,EACtBC,GAAuB,EACvBC,GAAe,GACfC,GAAc,EACdC,GAAiB,IACjBC,GAAmC,EACnCC,GAAgC,EAChCC,GAAqC,KACrCC,GAA6B,GAC7BC,GAAuB,KACvBC,GAAwB,IACxBC,GAAuB,GACvBC,GAA2B,UAC3BC,GAA6B,GAC7BC,GAA6B,UAC7BC,GAAoC,UACpCC,GAAkC,IAClCC,GAA4B,CAAC,EAAG,CAAC,EACjCC,GAA4B,EAC5BC,GAAwB,IACxBC,GAAwB,EACxBC,GAA+B,EAC/BC,GAA2B,EAC3BC,GAA2B,EAC3BC,GAAwB,IACxBC,GAAgC,IAChCC,GAAoB,ICxT1B,SAASC,GAAWC,EAAuBC,EAAoBC,EAAqC,CACzG,MAAO,CAACzK,EAAMuK,EAAM,CAAC,EAAG,EAAGC,CAAU,EAAGxK,EAAMuK,EAAM,CAAC,EAAG,EAAGE,CAAW,CAAC,CACzE,CAEO,SAASC,GAAiB7N,EAAuC,CACtE,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,EAAG,OAAO,KACtD,MAAMW,EAAI,OAAOX,EAAM,CAAC,CAAC,EACnBY,EAAI,OAAOZ,EAAM,CAAC,CAAC,EACzB,MAAI,CAAC,OAAO,SAASW,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,CAEO,MAAMkN,GAAUD,GAEhB,SAAS3H,GAAUpG,EAA4C,CACpE,OAAOU,GAAaV,CAAM,CAC5B,CAEO,SAASiO,GAAYjO,EAAkC,CAC5D,OAAO,KAAK,IAAIkB,GAAkBkF,GAAUpG,CAAM,CAAC,CAAC,CACtD,CAEO,SAASkO,GAAclO,EAAsC,CAClE,GAAI,CAAC,MAAM,QAAQA,CAAM,GAAKA,EAAO,SAAW,EAAG,MAAO,CAAC,EAAG,EAAG,EAAG,CAAC,EAErE,IAAI4C,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KAEX,SAAW,CAAClC,EAAGC,CAAC,IAAKd,EACfa,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GACjBC,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GAGvB,MAAO,CAAC8B,EAAMC,EAAMC,EAAMC,CAAI,CAChC,CAEO,SAASoL,GAAUC,EAA+BtI,EAA0BuI,EAAQ,GAAa,CACtG,GAAIvI,EAAO,SAAW,EAEtB,CAAAsI,EAAI,OAAOtI,EAAO,CAAC,EAAE,CAAC,EAAGA,EAAO,CAAC,EAAE,CAAC,CAAC,EACrC,QAAS1E,EAAI,EAAGA,EAAI0E,EAAO,OAAQ1E,GAAK,EACtCgN,EAAI,OAAOtI,EAAO1E,CAAC,EAAE,CAAC,EAAG0E,EAAO1E,CAAC,EAAE,CAAC,CAAC,EAGnCiN,GACFD,EAAI,UAAA,EAER,CAEO,SAASE,GAASF,EAA+BtI,EAA0ByI,EAAgCF,EAAQ,GAAOG,EAAO,GAAOC,EAAY,0BAAiC,CACtL3I,EAAO,SAAW,IAEtBsI,EAAI,UAAA,EACJD,GAAUC,EAAKtI,EAAQuI,CAAK,EACxBG,GAAQH,IACVD,EAAI,UAAYK,EAChBL,EAAI,KAAA,GAGNA,EAAI,YAAcG,EAAY,MAC9BH,EAAI,UAAYG,EAAY,MAC5BH,EAAI,SAAWG,EAAY,SAC3BH,EAAI,QAAUG,EAAY,QAC1BH,EAAI,YAAcG,EAAY,YAC9BH,EAAI,WAAaG,EAAY,WAC7BH,EAAI,cAAgBG,EAAY,cAChCH,EAAI,cAAgBG,EAAY,cAChCH,EAAI,YAAYG,EAAY,QAAQ,EACpCH,EAAI,OAAA,EACJA,EAAI,YAAYhD,EAAU,EAC1BgD,EAAI,YAAc,mBAClBA,EAAI,WAAa,EACjBA,EAAI,cAAgB,EACpBA,EAAI,cAAgB,EACtB,CAEO,SAASM,GAAmBC,EAAkE,CACnG,MAAMC,EAAO,MAAM,QAAQD,GAAO,QAAQ,EAAIA,EAAM,SAAS,OAAOzO,GAAS,OAAO,SAASA,CAAK,GAAKA,GAAS,CAAC,EAAIkL,GAC/GnP,EAAQ,OAAO0S,GAAO,OAAU,UAAY,OAAO,SAASA,EAAM,KAAK,EAAI,KAAK,IAAI,EAAGA,EAAM,KAAK,EAAIrD,GAA4B,MAClIuD,EAAa,OAAOF,GAAO,YAAe,UAAY,OAAO,SAASA,EAAM,UAAU,EAAI,KAAK,IAAI,EAAGA,EAAM,UAAU,EAAIrD,GAA4B,WACtJwD,EAAgB,OAAOH,GAAO,eAAkB,UAAY,OAAO,SAASA,EAAM,aAAa,EAAIA,EAAM,cAAgBrD,GAA4B,cACrJyD,EAAgB,OAAOJ,GAAO,eAAkB,UAAY,OAAO,SAASA,EAAM,aAAa,EAAIA,EAAM,cAAgBrD,GAA4B,cAC3J,MAAO,CACL,MAAOqD,GAAO,OAASrD,GAA4B,MACnD,MAAArP,EACA,SAAU2S,EAAK,OAASA,EAAOxD,GAC/B,SAAUuD,GAAO,UAAYrD,GAA4B,SACzD,QAASqD,GAAO,SAAWrD,GAA4B,QACvD,YAAaqD,GAAO,aAAerD,GAA4B,YAC/D,WAAAuD,EACA,cAAAC,EACA,cAAAC,CAAA,CAEJ,CAEO,SAASC,GAAiBC,EAAyBC,EAAqE,CAC7H,OAAKA,EACER,GAAmB,CACxB,MAAOQ,EAAS,OAASD,EAAK,MAC9B,MAAOC,EAAS,OAASD,EAAK,MAC9B,SAAUC,EAAS,UAAYD,EAAK,SACpC,SAAUC,EAAS,UAAYD,EAAK,SACpC,QAASC,EAAS,SAAWD,EAAK,QAClC,YAAaC,EAAS,aAAeD,EAAK,YAC1C,WAAYC,EAAS,YAAcD,EAAK,WACxC,cAAeC,EAAS,eAAiBD,EAAK,cAC9C,cAAeC,EAAS,eAAiBD,EAAK,aAAA,CAC/C,EAXqBA,CAYxB,CAEO,SAASE,GAAe9N,EAAuCC,EAAgD,CACpH,OAAID,GAAM,MAA2BC,IAAM,MAAQA,IAAM,OAChD,GAEF,OAAOD,CAAC,IAAM,OAAOC,CAAC,CAC/B,CAEO,SAASrB,GAAeC,EAAiC,CAC9D,OAAO,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,CAC3D,CAEO,SAASC,GAAiBD,EAA2C,CAC1E,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,QAAU,GAAKD,GAAeC,EAAM,CAAC,CAAC,GAAKD,GAAeC,EAAM,CAAC,CAAC,CACzG,CAEO,SAASkP,GAAiBlP,EAA2C,CAC1E,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,QAAU,GAAKA,EAAM,MAAMG,GAASF,GAAiBE,CAAK,CAAC,CAClG,CAEA,SAASgP,GAAoBnP,EAAgBU,EAA+B,CAC1E,GAAI,GAAC,MAAM,QAAQV,CAAK,GAAKA,EAAM,SAAW,GAC9C,IAAIkP,GAAiBlP,CAAK,EAAG,CAC3BU,EAAI,KAAKV,EAAM,IAAI,CAAC,CAACW,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,CAAC,EACxD,MACF,CACA,UAAWwO,KAAQpP,EACjBmP,GAAoBC,EAAM1O,CAAG,EAEjC,CAEO,SAAS2O,GAAsB5O,EAAqC0N,EAAoC,CAC7G,MAAMmB,EAAkC,CAAA,EACxCH,GAAoB1O,EAAa6O,CAAW,EAC5C,MAAM5O,EAA0B,CAAA,EAChC,UAAWL,KAAQiP,EAAa,CAC9B,GAAIjP,EAAK,OAAS,EAAG,SACrB,MAAMkB,EAAa4M,EAAQjI,GAAU7F,CAAI,EAAIA,EACzCkB,EAAW,SAAW4M,EAAQ,EAAI,IACpCzN,EAAI,KAAKa,CAAU,CAEvB,CACA,OAAOb,CACT,CAEO,SAAS6O,GAAwBvP,EAA2BwP,EAA0B,CAC3F,OAAI,OAAOxP,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,GAAKA,GAAS,EAC5DwP,EAEFxP,CACT,CAEO,SAASyP,GAAiBzP,EAA2BwP,EAA0B,CACpF,OAAI,OAAOxP,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUwP,EAC1DrM,EAAMnD,EAAO,EAAG,CAAC,CAC1B,CAEO,SAAS0P,GAAgBxB,EAA+BvN,EAAWC,EAAW7E,EAAeC,EAAgB+J,EAAsB,CACxI,MAAM4J,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI5J,EAAQhK,EAAQ,GAAKC,EAAS,EAAG,CAAC,EACjEkS,EAAI,UAAA,EACJA,EAAI,OAAOvN,EAAIgP,EAAG/O,CAAC,EACnBsN,EAAI,OAAOvN,EAAI5E,EAAQ4T,EAAG/O,CAAC,EAC3BsN,EAAI,iBAAiBvN,EAAI5E,EAAO6E,EAAGD,EAAI5E,EAAO6E,EAAI+O,CAAC,EACnDzB,EAAI,OAAOvN,EAAI5E,EAAO6E,EAAI5E,EAAS2T,CAAC,EACpCzB,EAAI,iBAAiBvN,EAAI5E,EAAO6E,EAAI5E,EAAQ2E,EAAI5E,EAAQ4T,EAAG/O,EAAI5E,CAAM,EACrEkS,EAAI,OAAOvN,EAAIgP,EAAG/O,EAAI5E,CAAM,EAC5BkS,EAAI,iBAAiBvN,EAAGC,EAAI5E,EAAQ2E,EAAGC,EAAI5E,EAAS2T,CAAC,EACrDzB,EAAI,OAAOvN,EAAGC,EAAI+O,CAAC,EACnBzB,EAAI,iBAAiBvN,EAAGC,EAAGD,EAAIgP,EAAG/O,CAAC,EACnCsN,EAAI,UAAA,CACN,CAEO,SAAS0B,GAAwBnP,EAA8C,CACpF,MAAMK,EAAQL,EAAY,CAAC,EAC3B,OAAO,MAAM,QAAQK,CAAK,GAAK,MAAM,QAAQA,EAAM,CAAC,CAAC,CACvD,CAEO,SAAS+O,GACd7F,EACAC,EACA6F,EAIkB,CAClB,GAAI,CAAC9F,GAAS,CAACC,QAAY,CAAA,EAE3B,GAAI6F,EAAY,CACd,MAAMC,EAAcD,EAAW,cAAc9F,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EACzDgG,EAAYF,EAAW,cAAc7F,EAAI,CAAC,EAAGA,EAAI,CAAC,CAAC,EAEzD,GAAI8F,GAAeC,EAAW,CAC5B,MAAMC,EAAkC,CACtC,CAACF,EAAY,CAAC,EAAGA,EAAY,CAAC,CAAC,EAC/B,CAACC,EAAU,CAAC,EAAGD,EAAY,CAAC,CAAC,EAC7B,CAACC,EAAU,CAAC,EAAGA,EAAU,CAAC,CAAC,EAC3B,CAACD,EAAY,CAAC,EAAGC,EAAU,CAAC,CAAC,CAAA,EAEzBE,EAAiC,CAAA,EACvC,UAAWC,KAAUF,EAAe,CAClC,MAAMG,EAAQN,EAAW,cAAcK,CAAM,EAC7C,GAAI,CAACC,EAAO,OAAOP,GAAgB7F,EAAOC,CAAG,EAC7CiG,EAAa,KAAKE,CAAK,CACzB,CACA,OAAOlK,GAAUgK,CAAY,CAC/B,CACF,CAEA,OAAOhK,GAAU,CACf,CAAC8D,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EACnB,CAACC,EAAI,CAAC,EAAGD,EAAM,CAAC,CAAC,EACjB,CAACC,EAAI,CAAC,EAAGA,EAAI,CAAC,CAAC,EACf,CAACD,EAAM,CAAC,EAAGC,EAAI,CAAC,CAAC,CAAA,CAClB,CACH,CAEO,SAASoG,GAAarG,EAA8BC,EAA4BjE,EAAQgG,GAAgC,CAC7H,GAAI,CAAChC,GAAS,CAACC,QAAY,CAAA,EAE3B,MAAM9N,GAAW6N,EAAM,CAAC,EAAIC,EAAI,CAAC,GAAK,GAChC7N,GAAW4N,EAAM,CAAC,EAAIC,EAAI,CAAC,GAAK,GAChClE,EAAS,KAAK,MAAMkE,EAAI,CAAC,EAAID,EAAM,CAAC,EAAGC,EAAI,CAAC,EAAID,EAAM,CAAC,CAAC,EAAI,GAClE,GAAIjE,EAAS,EAAG,MAAO,CAAA,EAEvB,MAAMjG,EAA2B,CAAA,EACjC,QAASoB,EAAI,EAAGA,GAAK8E,EAAO9E,GAAK,EAAG,CAClC,MAAM+E,EAAK/E,EAAI8E,EAAS,KAAK,GAAK,EAClClG,EAAO,KAAK,CAAC3D,EAAU,KAAK,IAAI8J,CAAC,EAAIF,EAAQ3J,EAAU,KAAK,IAAI6J,CAAC,EAAIF,CAAM,CAAC,CAC9E,CAEA,OAAOG,GAAUpG,CAAM,CACzB,CAEO,SAASwQ,GAA4B7P,EAAmE,CAC7G,MAAM+B,EAAeZ,GAAqB/B,GAAcY,CAAW,CAAC,EACpE,GAAI+B,EAAa,SAAW,EAAG,MAAO,CAAA,EAEtC,MAAM9B,EAAqC,CAAA,EAC3C,UAAWH,KAAWiC,EAAc,CAClC,MAAMC,EAAQlC,EAAQ,CAAC,EACvB,GAAI,CAACkC,GAASA,EAAM,OAAS,EAAG,SAChC,MAAM8N,EAAkB9N,EAAM,IAAI,CAAC,CAAC9B,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,EAChE4P,EAA4B,CAAA,EAClC,QAAStP,EAAI,EAAGA,EAAIX,EAAQ,OAAQW,GAAK,EAAG,CAC1C,MAAM6B,EAAOxC,EAAQW,CAAC,EAClB,CAAC6B,GAAQA,EAAK,OAAS,GAC3ByN,EAAM,KAAKzN,EAAK,IAAI,CAAC,CAACpC,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,CAAC,CAC3D,CACAF,EAAI,KAAK,CACP,MAAO6P,EACP,MAAAC,CAAA,CACD,CACH,CACA,OAAO9P,CACT,CC7PO,SAAS+P,GAAsBzQ,EAAuC,CAC3E,GAAI,CAAC,MAAM,QAAQA,CAAK,EAAG,OAAO+M,GAClC,MAAMrM,EAAMV,EAAM,OAAOoP,GAAQ,OAAO,SAASA,CAAI,GAAKA,GAAQ,CAAC,EACnE,OAAO1O,EAAI,OAAS,EAAIA,EAAMqM,EAChC,CAEO,SAAS2D,GAAuB1Q,EAAmC,CACxE,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUgN,GAC1D7J,EAAMnD,EAAOiN,GAAuBC,EAAqB,CAClE,CAEO,SAASyD,GAA0B3Q,EAAmC,CAC3E,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUmN,GAC1D,KAAK,MAAMhK,EAAMnD,EAAOoN,GAA0BC,EAAwB,CAAC,CACpF,CAEO,SAASuD,GAAoB5S,EAAyD,CAC3F,MAAM+H,EAASwJ,GAAwBvR,GAAS,OAAQyO,EAAoB,EACtEoE,EAAkBtB,GAAwBvR,GAAS,gBAAiB8O,EAA+B,EACnGgE,EAAaJ,GAAuB1S,GAAS,UAAU,EACvD+S,EAAgBJ,GAA0B3S,GAAS,aAAa,EACtE,MAAO,CACL,OAAA+H,EACA,WAAA+K,EACA,cAAAC,EACA,eAAgB/S,GAAS,iBAAmB,GAC5C,UAAWA,GAAS,WAAa0O,GACjC,YAAa+C,GAAiBzR,GAAS,YAAa2O,EAA0B,EAC9E,YAAa3O,GAAS,aAAe4O,GACrC,kBAAmB5O,GAAS,mBAAqB6O,GACjD,gBAAAgE,EACA,eAAgBJ,GAAsBzS,GAAS,cAAc,CAAA,CAEjE,CAEO,SAASgT,GAAuB9C,EAA+B+C,EAAsBC,EAAkD,CAC5I,GAAI,CAACD,EAAQ,WAAaA,EAAQ,aAAa,SAAW,EAAG,OAC7D,MAAME,EAAeF,EAAQ,aAC7B,GAAIE,EAAa,SAAW,EAAG,OAC/B,MAAMC,EAAWF,EAAqB,OACtC,GAAI,GAAC,OAAO,SAASE,CAAQ,GAAKA,GAAY,GAS9C,IAPAlD,EAAI,KAAA,EACJA,EAAI,YAAcgD,EAAqB,YACvChD,EAAI,UAAYgD,EAAqB,UACrChD,EAAI,YAAcgD,EAAqB,UACvChD,EAAI,QAAU,QACdA,EAAI,SAAW,QACfA,EAAI,UAAYkD,EAAW,EACvBD,EAAa,SAAW,EAC1BjD,EAAI,UAAA,EACJA,EAAI,IAAIiD,EAAa,CAAC,EAAE,CAAC,EAAGA,EAAa,CAAC,EAAE,CAAC,EAAGC,EAAU,EAAG,KAAK,GAAK,CAAC,EACxElD,EAAI,KAAA,MACC,CACLA,EAAI,UAAA,EACJA,EAAI,OAAOiD,EAAa,CAAC,EAAE,CAAC,EAAGA,EAAa,CAAC,EAAE,CAAC,CAAC,EACjD,QAASjQ,EAAI,EAAGA,EAAIiQ,EAAa,OAAQjQ,GAAK,EAC5CgN,EAAI,OAAOiD,EAAajQ,CAAC,EAAE,CAAC,EAAGiQ,EAAajQ,CAAC,EAAE,CAAC,CAAC,EAEnDgN,EAAI,OAAA,CACN,CACAA,EAAI,QAAA,EACN,CAEO,SAASmD,GAAgBnD,EAA+B+C,EAAsBK,EAAiCJ,EAAkD,CACtK,MAAMK,EAASN,EAAQ,OACvB,GAAI,CAACM,EAAQ,OACb,MAAMC,EAASP,EAAQ,cAAgBnD,GAAQwD,GAAW,cAAcC,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,GAAK,CAAA,CAAE,EACnG,GAAI,CAACC,EAAQ,OACb,MAAMJ,EAAWF,EAAqB,OAClC,CAAC,OAAO,SAASE,CAAQ,GAAKA,GAAY,IAE9ClD,EAAI,KAAA,EACJA,EAAI,UAAA,EACJA,EAAI,IAAIsD,EAAO,CAAC,EAAGA,EAAO,CAAC,EAAGJ,EAAU,EAAG,KAAK,GAAK,CAAC,EACtDlD,EAAI,YAAc+C,EAAQ,UAAYC,EAAqB,kBAAoBA,EAAqB,YACpGhD,EAAI,UAAYgD,EAAqB,gBACrChD,EAAI,YAAYgD,EAAqB,cAAc,EACnDhD,EAAI,OAAA,EACJA,EAAI,YAAYhD,EAAU,EAC1BgD,EAAI,QAAA,EACN,CC5FA,MAAMuD,GAA4B,IAC5BC,GAA4B,KAC5BC,GAAyB,GAE/B,IAAIC,GAA6D,KACjE,MAAMC,OAA0B,IAEhC,SAASC,IAA0D,CACjE,GAAIF,GAA2B,OAAOA,GACtC,GAAI,OAAO,SAAa,IAAa,OAAO,KAE5C,MAAM1D,EADS,SAAS,cAAc,QAAQ,EAC3B,WAAW,IAAI,EAClC,OAAKA,GACL0D,GAA4B1D,EACrB0D,IAFU,IAGnB,CAEO,SAASG,GAAsBC,EAAeC,EAA2F,CAC9I,MAAMC,EAAM,GAAGD,EAAW,UAAU,IAAIA,EAAW,QAAQ,IAAIA,EAAW,UAAU,IAAID,CAAK,GACvFG,EAASN,GAAoB,IAAIK,CAAG,EAC1C,GAAIC,IAAW,OAAW,OAAOA,EAEjC,MAAM3C,EAAWwC,EAAM,OAASC,EAAW,SAAWR,GAChDvD,EAAM4D,GAAA,EACZ,IAAI/V,EAAQyT,EACZ,GAAItB,EAAK,CACPA,EAAI,KAAO,GAAG+D,EAAW,UAAU,IAAIA,EAAW,QAAQ,MAAMA,EAAW,UAAU,GACrF,MAAMG,EAAWlE,EAAI,YAAY8D,CAAK,EAAE,MACpC,OAAO,SAASI,CAAQ,GAAKA,GAAY,IAC3CrW,EAAQqW,EAEZ,CAEA,OAAIP,GAAoB,KAAOH,IAC7BG,GAAoB,MAAA,EAEtBA,GAAoB,IAAIK,EAAKnW,CAAK,EAC3BA,CACT,CAEO,SAASsW,GAAavS,EAAiD,CAC5E,GAAI,CAACA,EAAO,OAAQ,OAAO,KAE3B,IAAI6C,EAAO,IACX,UAAWxC,KAASL,EACdK,EAAM,CAAC,EAAIwC,IAAMA,EAAOxC,EAAM,CAAC,GAErC,GAAI,CAAC,OAAO,SAASwC,CAAI,EAAG,OAAO,KAEnC,IAAID,EAAO,IACPE,EAAO,KACX,UAAWzC,KAASL,EACd,KAAK,IAAIK,EAAM,CAAC,EAAIwC,CAAI,EAAIgP,KAC5BxR,EAAM,CAAC,EAAIuC,IAAMA,EAAOvC,EAAM,CAAC,GAC/BA,EAAM,CAAC,EAAIyC,IAAMA,EAAOzC,EAAM,CAAC,IAGrC,MAAI,CAAC,OAAO,SAASuC,CAAI,GAAK,CAAC,OAAO,SAASE,CAAI,EAAU,KACtD,EAAEF,EAAOE,GAAQ,GAAKD,CAAI,CACnC,CAEO,SAAS2P,GAAgErP,EAAsC,CACpH,IAAIsP,EAA8B,KAClC,UAAWhS,KAAW0C,EAAU,CAC9B,MAAMuP,EAASH,GAAa9R,EAAQ,KAAK,EACpCiS,IACD,CAACD,GAAQC,EAAO,CAAC,EAAID,EAAK,CAAC,GAAMC,EAAO,CAAC,IAAMD,EAAK,CAAC,GAAKC,EAAO,CAAC,EAAID,EAAK,CAAC,KAC9EA,EAAOC,EAEX,CACA,OAAOD,CACT,CAEO,SAASE,GAAwBhE,EAAgE,CACtG,MAAMiE,EAAK,OAAOjE,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIjD,GAA2B,SACvImH,EAAK,OAAOlE,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIjD,GAA2B,SACvIoH,EAAK,OAAOnE,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIjD,GAA2B,SACvIqH,EAAK,OAAOpE,GAAO,aAAgB,UAAY,OAAO,SAASA,EAAM,WAAW,EAAI,KAAK,IAAI,EAAGA,EAAM,WAAW,EAAIjD,GAA2B,YAChJsH,EAAK,OAAOrE,GAAO,SAAY,UAAY,OAAO,SAASA,EAAM,OAAO,EAAIA,EAAM,QAAUjD,GAA2B,QACvHuH,EAAK,OAAOtE,GAAO,cAAiB,UAAY,OAAO,SAASA,EAAM,YAAY,EAAI,KAAK,IAAI,EAAGA,EAAM,YAAY,EAAIjD,GAA2B,aACzJ,MAAO,CACL,WAAYiD,GAAO,YAAcjD,GAA2B,WAC5D,SAAUoH,EACV,WAAYnE,GAAO,YAAcjD,GAA2B,WAC5D,UAAWiD,GAAO,WAAajD,GAA2B,UAC1D,gBAAiBiD,GAAO,iBAAmBjD,GAA2B,gBACtE,YAAaiD,GAAO,aAAejD,GAA2B,YAC9D,YAAaqH,EACb,SAAUH,EACV,SAAUC,EACV,QAASG,EACT,aAAcC,CAAA,CAElB,CAEO,SAASC,GAAsBjE,EAAwBC,EAA0E,CACtI,OAAKA,EACEyD,GAAwB,CAC7B,WAAYzD,EAAS,YAAcD,EAAK,WACxC,SAAUC,EAAS,UAAYD,EAAK,SACpC,WAAYC,EAAS,YAAcD,EAAK,WACxC,UAAWC,EAAS,WAAaD,EAAK,UACtC,gBAAiBC,EAAS,iBAAmBD,EAAK,gBAClD,YAAaC,EAAS,aAAeD,EAAK,YAC1C,YAAaC,EAAS,aAAeD,EAAK,YAC1C,SAAUC,EAAS,UAAYD,EAAK,SACpC,SAAUC,EAAS,UAAYD,EAAK,SACpC,QAASC,EAAS,SAAWD,EAAK,QAClC,aAAcC,EAAS,cAAgBD,EAAK,YAAA,CAC7C,EAbqBA,CAcxB,CAEO,SAASkE,GAAmCC,EAA8BhX,EAAciX,EAA4E,CAEzK,GADI,CAACD,GACD,CAACC,EAAW,MAAO,GAEvB,MAAMC,EAAU,OAAOD,EAAU,OAAO,EAClCE,EAAU,OAAOF,EAAU,OAAO,EAIxC,MAHI,CAAC,OAAO,SAASC,CAAO,GAAK,CAAC,OAAO,SAASC,CAAO,GAErDA,EAAUD,GAAWxH,IACrB,CAAC,OAAO,SAAS1P,CAAI,EAAU,EAC5BA,GAAQmX,EAAUzH,GAAqCD,GAAuC,CACvG,CAEA,SAAS2H,GAA4B7E,EAAwE,CAC3G,MAAM8E,EAAW,OAAO9E,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIhD,GAAgC,SAClJ+H,EAAe,OAAO/E,GAAO,cAAiB,UAAY,OAAO,SAASA,EAAM,YAAY,EAAI,KAAK,IAAI,EAAGA,EAAM,YAAY,EAAIhD,GAAgC,aAClKgI,EAAW,OAAOhF,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIhD,GAAgC,SAClJiI,EAAW,OAAOjF,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIhD,GAAgC,SACxJ,MAAO,CACL,WAAYgD,GAAO,YAAchD,GAAgC,WACjE,SAAA8H,EACA,WAAY9E,GAAO,YAAchD,GAAgC,WACjE,UAAWgD,GAAO,WAAahD,GAAgC,UAC/D,gBAAiBgD,GAAO,iBAAmBhD,GAAgC,gBAC3E,aAAA+H,EACA,SAAAC,EACA,SAAAC,CAAA,CAEJ,CAEA,SAASC,GAA2B3T,EAAyE,CAC3G,MAAMW,EAAI,OAAOX,GAAO,GAAM,UAAY,OAAO,SAASA,EAAM,CAAC,EAAIA,EAAM,EAAI0L,GAAiC,EAC1G9K,EAAI,OAAOZ,GAAO,GAAM,UAAY,OAAO,SAASA,EAAM,CAAC,EAAIA,EAAM,EAAI0L,GAAiC,EAChH,MAAO,CAAE,EAAA/K,EAAG,EAAAC,CAAA,CACd,CAEO,SAASgT,GAAgCC,EAAyB,CACvE,OAAK,OAAO,SAASA,CAAO,EACrB,GAAG,KAAK,IAAI,EAAGA,CAAO,EAAE,QAAQ,CAAC,CAAC,OADH,WAExC,CAEO,SAASC,GAA8B9V,EAA6E,CACzH,MAAM+V,EAAS,OAAO/V,GAAS,QAAW,WAAaA,EAAQ,OAAS4V,GAClEI,EAAeL,GAA2B3V,GAAS,YAAY,EACrE,MAAO,CACL,QAASA,GAAS,UAAY,GAC9B,OAAA+V,EACA,MAAOT,GAA4BtV,GAAS,KAAK,EACjD,cAAegW,EAAa,EAC5B,cAAeA,EAAa,CAAA,CAEhC,CAEO,SAASC,GAAgB/F,EAA+BgG,EAAc1B,EAAwB2B,EAAqBC,EAAsBnC,EAAoC,CAClL,MAAMD,EAAQkC,EAAK,KAAA,EACnB,GAAI,CAAClC,EAAO,OAEZ9D,EAAI,KAAA,EACJA,EAAI,KAAO,GAAG+D,EAAW,UAAU,IAAIA,EAAW,QAAQ,MAAMA,EAAW,UAAU,GACrF/D,EAAI,UAAY,SAChBA,EAAI,aAAe,SAGnB,MAAMmG,EADYtC,GAAsBC,EAAOC,CAAU,EAC5BA,EAAW,SAAW,EAC7CqC,EAAYrC,EAAW,SAAWA,EAAW,SAAW,EAExDtR,EAAIwC,EAAMqP,EAAO,CAAC,EAAG6B,EAAW,GAAM,EAAGF,EAAcE,EAAW,GAAM,CAAC,EACzEzT,EAAIuC,EAAMqP,EAAO,CAAC,EAAIP,EAAW,QAASqC,EAAY,GAAM,EAAGF,EAAeE,EAAY,GAAM,CAAC,EACjGC,EAAO5T,EAAI0T,EAAW,GACtBG,EAAM5T,EAAI0T,EAAY,GAE5BpG,EAAI,UAAY+D,EAAW,gBAC3B/D,EAAI,YAAc+D,EAAW,YAC7B/D,EAAI,UAAY+D,EAAW,YAC3BvC,GAAgBxB,EAAKqG,EAAMC,EAAKH,EAAUC,EAAWrC,EAAW,YAAY,EAC5E/D,EAAI,KAAA,EACA+D,EAAW,YAAc,GAC3B/D,EAAI,OAAA,EAGNA,EAAI,UAAY+D,EAAW,UAC3B/D,EAAI,SAAS8D,EAAOrR,EAAGC,EAAI,EAAG,EAC9BsN,EAAI,QAAA,CACN,CAEO,SAASuG,GACdvG,EACAgG,EACAQ,EACAP,EACAC,EACA3F,EACA9O,EACAC,EACM,CACN,MAAMoS,EAAQkC,EAAK,KAAA,EACnB,GAAI,CAAClC,EAAO,OAEZ9D,EAAI,KAAA,EACJA,EAAI,KAAO,GAAGO,EAAM,UAAU,IAAIA,EAAM,QAAQ,MAAMA,EAAM,UAAU,GACtEP,EAAI,UAAY,SAChBA,EAAI,aAAe,SAGnB,MAAMmG,EADYtC,GAAsBC,EAAOvD,CAAK,EACvBA,EAAM,SAAW,EACxC6F,EAAY7F,EAAM,SAAWA,EAAM,SAAW,EAE9C9N,EAAIwC,EAAMuR,EAAa,CAAC,EAAI/U,EAAS0U,EAAW,GAAM,EAAGF,EAAcE,EAAW,GAAM,CAAC,EACzF,EAAIlR,EAAMuR,EAAa,CAAC,EAAI9U,EAAS0U,EAAY,GAAM,EAAGF,EAAeE,EAAY,GAAM,CAAC,EAC5FC,EAAO5T,EAAI0T,EAAW,GACtBG,EAAM,EAAIF,EAAY,GAE5BpG,EAAI,UAAYO,EAAM,gBACtBiB,GAAgBxB,EAAKqG,EAAMC,EAAKH,EAAUC,EAAW7F,EAAM,YAAY,EACvEP,EAAI,KAAA,EAEJA,EAAI,UAAYO,EAAM,UACtBP,EAAI,SAAS8D,EAAOrR,EAAG,EAAI,EAAG,EAC9BuN,EAAI,QAAA,CACN,CC9OO,SAASyG,GAAqBzG,EAA+B0G,EAA6BC,EAA+BtG,EAAyB,CACvJ,GAAI,EAAAqG,EAAU,OAAS,GAAKC,EAAU,SAAW,GACjD,CAAA3G,EAAI,KAAA,EACJA,EAAI,UAAA,EACJD,GAAUC,EAAK0G,EAAW,EAAI,EAC9B,UAAWvU,KAAQwU,EACbxU,EAAK,OAAS,GAClB4N,GAAUC,EAAK7N,EAAM,EAAI,EAE3B6N,EAAI,UAAYK,EAChBL,EAAI,KAAK,SAAS,EAClBA,EAAI,QAAA,EACN,CAWO,SAAS4G,GAAkBC,EAAuC,CACvE,KAAM,CAAE,IAAA7G,EAAK,cAAA8G,EAAe,eAAAC,EAAgB,oBAAAC,EAAqB,gBAAAC,EAAiB,oBAAAC,GAAwBL,EAEpGM,EAAe,EAAS,WAA0D,6BAExF,QAASnU,EAAI,EAAGA,EAAI8T,EAAc,OAAQ9T,GAAK,EAAG,CAChD,MAAMoU,EAAQN,EAAc9T,CAAC,EAC7B,GAAI,CAACoU,GAAO,aAAa,QAAUA,EAAM,UAAY,GAAO,SAE5D,MAAM9T,EAAS8T,EAAM,QAAU1F,GAAwB0F,EAAM,WAAW,EAClEC,EAAclG,GAAsBiG,EAAM,YAAa9T,CAAM,EAEnE,GAAI8T,EAAM,cAAc,UAAW,CACjC,MAAMT,EAAgC,CAAA,EAChCW,EAAcnG,GAAsBiG,EAAM,YAAa,EAAI,EACjE,UAAWjV,KAAQmV,EAAa,CAC9B,MAAMhE,EAAS0D,EAAoB7U,CAAI,EACnCmR,EAAO,QAAU,GACnBqD,EAAU,KAAKrD,CAAM,CAEzB,CACI6D,GAAgBD,GAClBA,EAAoB,CAClB,GAAIE,EAAM,IAAMpU,EAChB,gBAAiB+T,EAAe,OAChC,gBAAiBO,EAAY,OAC7B,cAAeX,EAAU,OACzB,UAAWS,EAAM,aAAa,SAAA,CAC/B,EAEHX,GAAqBzG,EAAK+G,EAAgBJ,EAAWS,EAAM,aAAa,SAAS,CACnF,CAEA,GAAIC,EAAY,SAAW,EAAG,SAC9B,MAAMlH,EAAcS,GAAiBqG,EAAiBG,EAAM,QAAUA,EAAM,WAAW,EACvF,UAAWjV,KAAQkV,EAAa,CAC9B,MAAM/D,EAAS0D,EAAoB7U,CAAI,EACnCmR,EAAO,OAAS,GACpBpD,GAASF,EAAKsD,EAAQnD,EAAa7M,EAAQ8T,EAAM,MAAQ,EAAK,CAChE,CACF,CACF,CC7DO,SAASG,GAAYC,EAAuC,CACjE,OACEA,IAAS,mBAAqBA,IAAS,gBAAkBA,IAAS,0BAA4BA,IAAS,wBAA0BA,IAAS,qBAAuBA,IAAS,yBAE9K,CAEO,SAASC,GAAoB3X,EAA2D,CAC7F,MAAO,CACL,iBAAkBuR,GAAwBvR,GAAS,iBAAkBmO,EAAgC,EACrG,cAAeoD,GAAwBvR,GAAS,cAAeoO,EAA6B,EAC5F,mBAAoBmD,GAAwBvR,GAAS,mBAAoBqO,EAAkC,CAAA,CAE/G,CAEA,MAAMH,GAAiB,IAEhB,SAAS0J,GAAS/B,EAAyB,CAChD,OAAOA,EAAU3H,GAAiBA,EACpC,CAEO,SAAS2J,GACd/P,EACAgQ,EACAhG,EAIkB,CAClB,GAAI,CAAChK,GAAU,CAAC,OAAO,SAASgQ,CAAU,GAAKA,GAAc,EAAG,MAAO,CAAA,EAEvE,GAAIhG,EAAY,CACd,MAAMiG,EAAejG,EAAW,cAAchK,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,EAC5DkQ,EAAalG,EAAW,cAAchK,EAAO,CAAC,EAAIgQ,EAAYhQ,EAAO,CAAC,CAAC,EAC7E,GAAIiQ,GAAgBC,EAAY,CAC9B,MAAMC,EAAW,KAAK,MAAMD,EAAW,CAAC,EAAID,EAAa,CAAC,EAAGC,EAAW,CAAC,EAAID,EAAa,CAAC,CAAC,EACtF9F,EAAkC,CACtC,CAAC8F,EAAa,CAAC,EAAIE,EAAUF,EAAa,CAAC,EAAIE,CAAQ,EACvD,CAACF,EAAa,CAAC,EAAIE,EAAUF,EAAa,CAAC,EAAIE,CAAQ,EACvD,CAACF,EAAa,CAAC,EAAIE,EAAUF,EAAa,CAAC,EAAIE,CAAQ,EACvD,CAACF,EAAa,CAAC,EAAIE,EAAUF,EAAa,CAAC,EAAIE,CAAQ,CAAA,EAEnD/F,EAAiC,CAAA,EACvC,UAAWC,KAAUF,EAAe,CAClC,MAAMG,EAAQN,EAAW,cAAcK,CAAM,EAC7C,GAAI,CAACC,EAAO,MAAM,IAAI,MAAM,4BAA4B,EACxDF,EAAa,KAAKE,CAAK,CACzB,CACA,OAAOlK,GAAUgK,CAAY,CAC/B,CACF,CAEA,OAAOhK,GAAU,CACf,CAACJ,EAAO,CAAC,EAAIgQ,EAAYhQ,EAAO,CAAC,EAAIgQ,CAAU,EAC/C,CAAChQ,EAAO,CAAC,EAAIgQ,EAAYhQ,EAAO,CAAC,EAAIgQ,CAAU,EAC/C,CAAChQ,EAAO,CAAC,EAAIgQ,EAAYhQ,EAAO,CAAC,EAAIgQ,CAAU,EAC/C,CAAChQ,EAAO,CAAC,EAAIgQ,EAAYhQ,EAAO,CAAC,EAAIgQ,CAAU,CAAA,CAChD,CACH,CAEO,SAASI,GAAuBpQ,EAA+BC,EAAgBC,EAAQgG,GAAgC,CAC5H,GAAI,CAAClG,GAAU,CAAC,OAAO,SAASC,CAAM,GAAKA,GAAU,EAAG,MAAO,CAAA,EAE/D,MAAMjG,EAA2B,CAAA,EACjC,QAAS,EAAI,EAAG,GAAKkG,EAAO,GAAK,EAAG,CAClC,MAAMC,EAAK,EAAID,EAAS,KAAK,GAAK,EAClClG,EAAO,KAAK,CAACgG,EAAO,CAAC,EAAI,KAAK,IAAIG,CAAC,EAAIF,EAAQD,EAAO,CAAC,EAAI,KAAK,IAAIG,CAAC,EAAIF,CAAM,CAAC,CAClF,CAEA,OAAOG,GAAUpG,CAAM,CACzB,CAiBO,SAASqW,GAAiBpB,EAAkD,CACjF,KAAM,CAAE,UAAAqB,EAAW,OAAAtQ,EAAQ,qBAAAuQ,EAAsB,WAAA1I,EAAY,YAAAC,EAAa,qBAAA0I,EAAsB,uBAAAC,GAA2BxB,EAE3H,GAAI,CAACjP,EAAQ,MAAO,CAAA,EAEpB,GAAIsQ,IAAc,yBAA0B,CAC1C,MAAMN,EAAaO,EAAqB,mBAAqB,GAC7D,OAAOR,GAAuB/P,EAAQgQ,EAAYS,EAAA,CAAwB,EAAE,IAAIpW,GAASsN,GAAWtN,EAAOwN,EAAYC,CAAW,CAAC,CACrI,CAEA,IAAIiG,EAAU,EAMd,GALIuC,IAAc,mBAAqBA,IAAc,uBACnDvC,EAAUuC,IAAc,uBAAyBjK,GAAmCkK,EAAqB,kBAChGD,IAAc,gBAAkBA,IAAc,qBAAuBA,IAAc,6BAC5FvC,EAAUuC,IAAc,0BAA4B9J,GAA6B8J,IAAc,oBAAsBhK,GAAgCiK,EAAqB,eAExK,CAAC,OAAO,SAASxC,CAAO,GAAKA,GAAW,QAAU,CAAA,EAEtD,MAAM2C,EAAUZ,GAAS/B,CAAO,EAChC,IAAI/T,EAA2B,CAAA,EAC/B,GAAIsW,IAAc,mBAAqBA,IAAc,uBAAwB,CAC3E,MAAMN,EAAaQ,EAAqB,KAAK,KAAKE,CAAO,EAAI,EAAG,EAChE1W,EAAS+V,GAAuB/P,EAAQgQ,EAAYS,EAAA,CAAwB,CAC9E,SAAWH,IAAc,gBAAkBA,IAAc,qBAAuBA,IAAc,0BAA2B,CACvH,MAAMrQ,EAASuQ,EAAqB,KAAK,KAAKE,EAAU,KAAK,EAAE,CAAC,EAChE1W,EAASoW,GAAuBpQ,EAAQC,CAAM,CAChD,CAEA,OAAKjG,EAAO,OACLA,EAAO,IAAIK,GAASsN,GAAWtN,EAAOwN,EAAYC,CAAW,CAAC,EAD1C,CAAA,CAE7B,CCxCA,SAAS6I,GAAoCpI,EAA6G,CACxJ,MAAO,CACL,MAAO/C,GACP,MAAOC,GACP,SAAUL,GACV,SAAUmD,EAAY,SACtB,QAASA,EAAY,QACrB,YAAa,mBACb,WAAY,EACZ,cAAe,EACf,cAAe,CAAA,CAEnB,CAEA,SAASqI,GAA4B1W,EAAmC,CACtE,GAAI,OAAOA,GAAU,SAAU,OAAO6L,GACtC,MAAM5P,EAAO+D,EAAM,KAAA,EACnB,OAAO/D,EAAK,OAAS,EAAIA,EAAO4P,EAClC,CAEA,SAAS8K,GAAe7W,EAAgE,CACtF,OAAO,MAAM,QAAQA,CAAM,GAAKA,EAAO,QAAU,GAAKiO,GAAYjO,CAAM,EAAImM,EAC9E,CAEO,SAAS2K,GAAU,CACxB,KAAAlB,EACA,WAAA/H,EACA,YAAAC,EACA,SAAArK,EACA,UAAAC,EACA,aAAAqT,EACA,aAAAC,EACA,aAAAC,EACA,WAAAC,EACA,eAAAC,EACA,gBAAAC,EACA,QAAAhE,EACA,gBAAAiE,EACA,iBAAAC,EACA,aAAAC,EACA,kBAAAC,EACA,cAAAC,EACA,kBAAAC,EACA,uBAAAC,EACA,wBAAAC,EACA,iBAAAC,EACA,yBAAAC,EACA,wBAAyBC,EACzB,cAAA7C,GACA,gBAAA8C,EAAkB,KAClB,eAAAC,GAAiB,KACjB,iBAAAC,GACA,gBAAAC,GACA,6BAAAC,GAA+B,GAC/B,4BAAAC,EACA,cAAAC,EACA,UAAAC,EACA,MAAA5J,CACF,EAAuC,CACrC,MAAM6J,EAAYC,EAAAA,OAAiC,IAAI,EACjDC,GAAiBD,EAAAA,OAAO,EAAK,EAC7BE,GAA0BF,EAAAA,OAA4B,IAAI,GAAK,EAC/DG,GAAcH,EAAAA,OAAiB7C,CAAI,EACnCiD,GAAaJ,EAAAA,OAAoB,CACrC,UAAW,GACX,UAAW,KACX,MAAO,KACP,QAAS,KACT,OAAQ,KACR,aAAc,KACd,OAAQ,CAAA,EACR,aAAc,CAAA,EACd,YAAa,IAAA,CACd,EAEKK,GAAS1F,GAAWwC,IAAS,SAC7BmD,EAAyBC,EAAAA,QAAsB,IAC/C1B,GAAoBA,EAAiB,OAAS,EACzCA,EAEL,CAACE,GAAqBA,EAAkB,SAAW,EAC9CnM,GAEFmM,EAAkB,IAAI,CAAC7W,EAAasY,KAAW,CACpD,GAAIA,EACJ,YAAAtY,CAAA,EACA,EACD,CAAC2W,EAAkBE,CAAiB,CAAC,EAClC0B,EAAqBF,EAAAA,QAAsB,IAAMzB,GAAgBlM,GAAe,CAACkM,CAAY,CAAC,EAC9F4B,EAA2BH,EAAAA,QAAkC,IAAM,CACvE,MAAMpY,EAAgC,CAAA,EACtC,QAASQ,EAAI,EAAGA,EAAI2X,EAAuB,OAAQ3X,GAAK,EAAG,CACzD,MAAMgY,EAASL,EAAuB3X,CAAC,EACjC+B,EAAWqN,GAA4B4I,EAAO,WAAW,EAC3DjW,EAAS,SAAW,GACxBvC,EAAI,KAAK,CACP,OAAAwY,EACA,YAAahY,EACb,UAAWgY,EAAO,IAAMhY,EACxB,SAAA+B,CAAA,CACD,CACH,CACA,OAAOvC,CACT,EAAG,CAACmY,CAAsB,CAAC,EACrBM,GAAuBL,EAAAA,QAAkC,IAAM,CACnE,MAAMpY,EAAgC,CAAA,EACtC,QAASQ,EAAI,EAAGA,EAAI8X,EAAmB,OAAQ9X,GAAK,EAAG,CACrD,MAAMgY,EAASF,EAAmB9X,CAAC,EAC7B+B,EAAWqN,GAA4B4I,EAAO,WAAW,EAC3DjW,EAAS,SAAW,GACxBvC,EAAI,KAAK,CACP,OAAAwY,EACA,YAAahY,EACb,UAAWgY,EAAO,IAAMhY,EACxB,SAAA+B,CAAA,CACD,CACH,CACA,OAAOvC,CACT,EAAG,CAACsY,CAAkB,CAAC,EAEjBI,EAAsBN,EAAAA,QAAQ,IAAMtK,GAAmBgJ,CAAiB,EAAG,CAACA,CAAiB,CAAC,EAC9F6B,GAA2BP,UAAQ,IAAMhK,GAAiBsK,EAAqB3B,CAAsB,EAAG,CAAC2B,EAAqB3B,CAAsB,CAAC,EACrJ6B,GAA4BR,UAAQ,IAAMhK,GAAiBsK,EAAqB1B,CAAuB,EAAG,CAAC0B,EAAqB1B,CAAuB,CAAC,EACxJ6B,GAA2BT,EAAAA,QAAQ,IAAMhK,GAAiBzD,GAA4BsM,CAAgB,EAAG,CAACA,CAAgB,CAAC,EAC3H6B,EAA+BV,EAAAA,QAAQ,IAAMpC,GAA4Ba,CAAa,EAAG,CAACA,CAAa,CAAC,EAExGkC,GAAqBX,EAAAA,QAAQ,IAAMrG,GAAwBuF,EAAgB,EAAG,CAACA,EAAgB,CAAC,EAChG0B,GAAiCZ,EAAAA,QAAQ,IAAMhF,GAA8BmE,EAAe,EAAG,CAACA,EAAe,CAAC,EAChH5B,GAAuByC,EAAAA,QAAQ,IAAMnD,GAAoBkB,CAAY,EAAG,CAACA,CAAY,CAAC,EACtF3F,EAAuB4H,EAAAA,QAAQ,IAAMlI,GAAoBkG,CAAY,EAAG,CAACA,CAAY,CAAC,EAEtF6C,GAAcb,EAAAA,QAClB,KAAO,CACL,SAAU,WACV,MAAO,EACP,OAAQ,EACR,MAAO,OACP,OAAQ,OACR,QAAS,QACT,YAAa,OACb,cAAeF,GAAS,OAAS,OACjC,OAAQA,GAAUlD,IAAS,QAAU,OAAS,YAAe,UAC7D,GAAGjH,CAAA,GAEL,CAACmK,GAAQlD,EAAMjH,CAAK,CAAA,EAGhBmL,GAAeC,EAAAA,YAAY,IAAM,CACrC,MAAMpe,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAEb,MAAMwD,EAAOxD,EAAO,sBAAA,EACd2D,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAC9CnC,EAAI,KAAK,IAAI,EAAG,KAAK,MAAMgC,EAAK,MAAQG,CAAG,CAAC,EAC5ClC,EAAI,KAAK,IAAI,EAAG,KAAK,MAAM+B,EAAK,OAASG,CAAG,CAAC,GAE/C3D,EAAO,QAAUwB,GAAKxB,EAAO,SAAWyB,KAC1CzB,EAAO,MAAQwB,EACfxB,EAAO,OAASyB,EAEpB,EAAG,CAAA,CAAE,EAECgY,EAAsB2E,EAAAA,YACzBjU,GAAyG,CACxG,MAAM0L,EAAYyF,EAAa,QAC/B,GAAI,CAACzF,GAAa1L,EAAO,SAAW,QAAU,CAAA,EAE9C,MAAMlF,EAAM,IAAI,MAAmDkF,EAAO,MAAM,EAChF,QAAS1E,EAAI,EAAGA,EAAI0E,EAAO,OAAQ1E,GAAK,EAAG,CACzC,MAAMwM,EAAQI,GAAQwD,EAAU,cAAc1L,EAAO1E,CAAC,EAAE,CAAC,EAAG0E,EAAO1E,CAAC,EAAE,CAAC,CAAC,CAAC,EACzE,GAAI,CAACwM,EAAO,MAAO,CAAA,EACnBhN,EAAIQ,CAAC,EAAIwM,CACX,CACA,OAAOhN,CACT,EACA,CAACqW,CAAY,CAAA,EAGT+C,GAAqBD,EAAAA,YACxBrI,GAA4G,CAC3G,MAAMF,EAAYyF,EAAa,QACzBtb,EAAS6c,EAAU,QACzB,GAAI,CAAChH,GAAa,CAAC7V,EAAQ,OAAO,KAClC,MAAMwD,EAAOxD,EAAO,sBAAA,EACdse,EAAMjM,GAAQwD,EAAU,cAAcrS,EAAK,KAAOuS,EAAO,CAAC,EAAGvS,EAAK,IAAMuS,EAAO,CAAC,CAAC,CAAC,EACxF,OAAKuI,EACEtM,GAAWsM,EAAKpM,EAAYC,CAAW,EAD7B,IAEnB,EACA,CAACmJ,EAAcpJ,EAAYC,CAAW,CAAA,EAGlC2I,GAAyBsD,EAAAA,YAAY,IAAM,CAC/C,MAAMvI,EAAYyF,EAAa,QACzBxa,EAAc+U,GAAW,eAAA,EAAiB,aAAe,EAC/D,GAAI,OAAK,IAAI/U,EAAc,GAAG,EAAI,KAAQ,CAAC+U,GAE3C,MAAO,CACL,cAAe,CAAC3Q,EAAWC,IAAkEkN,GAAQwD,EAAU,cAAc3Q,EAAGC,CAAC,CAAC,EAClI,cAAekZ,EAAA,CAEnB,EAAG,CAAC/C,EAAc+C,EAAkB,CAAC,EAE/BxD,GAAuBuD,EAAAA,YAC1BG,GAA6B,CAC5B,GAAI,CAAC,OAAO,SAASA,CAAQ,GAAKA,GAAY,EAAG,MAAO,GAExD,MAAMC,EAAW,OAAO1W,GAAa,UAAY,OAAO,SAASA,CAAQ,GAAKA,EAAW,EAAIA,EAAW,EAClG2W,EAAiB,OAAO1W,GAAc,UAAY,OAAO,SAASA,CAAS,EAAIA,EAAY,EAC3F2W,EAAcpD,EAAa,SAAS,eAAA,EAAiB,KACrDqD,EAAW,OAAOD,GAAgB,UAAY,OAAO,SAASA,CAAW,GAAKA,EAAc,EAAIA,EAAc,EAC9GE,GAAiBH,EAAiB,KAAK,KAAKE,CAAQ,EACpDE,EAAmB,KAAK,IAAI,KAAMhX,GAAoB2W,EAAUC,EAAgBG,EAAc,CAAC,EAErG,OADqBL,EAAWM,EACVF,CACxB,EACA,CAAC7W,EAAUC,EAAWuT,CAAY,CAAA,EAG9BwD,GAA2BV,EAAAA,YAC/B,CAACzD,EAA0BtQ,IAClBqQ,GAAiB,CACtB,UAAAC,EACA,OAAAtQ,EACA,qBAAAuQ,GACA,WAAA1I,EACA,YAAAC,EACA,qBAAA0I,GACA,uBAAAC,EAAA,CACD,EAEH,CAACD,GAAsB3I,EAAYC,EAAayI,GAAsBE,EAAsB,CAAA,EAGxFiE,GAAqBX,EAAAA,YAAY,IAAqD,CAC1F,MAAM5I,EAAU0H,GAAW,QAC3B,OAAIlD,GAAYC,CAAI,EACX6E,GAAyB7E,EAAMzE,EAAQ,WAAW,EAEvDyE,IAAS,QACJ,CAAA,EAEJzE,EAAQ,UAETyE,IAAS,WACJzE,EAAQ,OAEbyE,IAAS,YACJ7F,GAAgBoB,EAAQ,MAAOA,EAAQ,QAASsF,IAAwB,EAE7Eb,IAAS,WACJrF,GAAaY,EAAQ,MAAOA,EAAQ,OAAO,EAG7C,CAAA,EAZwB,CAAA,CAajC,EAAG,CAACyE,EAAM6E,GAA0BhE,EAAsB,CAAC,EAErDkE,GAAcZ,EAAAA,YAAY,IAAM,CACpCD,GAAA,EAEA,MAAMne,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAEb,MAAMyS,EAAMzS,EAAO,WAAW,IAAI,EAClC,GAAI,CAACyS,EAAK,OAEV,MAAM9O,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAC9C+U,EAAc1Y,EAAO,MAAQ2D,EAC7BgV,EAAe3Y,EAAO,OAAS2D,EAKrC,GAJA8O,EAAI,aAAa,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EACjCA,EAAI,UAAU,EAAG,EAAGzS,EAAO,MAAOA,EAAO,MAAM,EAC/CyS,EAAI,aAAa9O,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,EAEjC6Z,EAAyB,OAAS,EACpC,UAAWhR,KAASgR,EAA0B,CAC5C,KAAM,CAAE,OAAAC,GAAQ,SAAAjW,EAAU,YAAAyX,GAAa,UAAAC,IAAc1S,EAC/C2S,GAAwC3L,GAAe8I,GAAgB4C,EAAS,EAAI,SAAW1L,GAAe6I,EAAiB6C,EAAS,EAAI,QAAU,UAC5J,IAAItM,GAAcuM,KAAU,SAAWtB,GAA4BsB,KAAU,QAAUvB,GAA2BD,EAElH,GAAIxB,EAA0B,CAC5B,MAAMiD,GAAWjD,EAAyB,CACxC,OAAAsB,GACA,SAAUyB,GACV,YAAAD,GACA,MAAAE,EAAA,CACD,EACDvM,GAAcS,GAAiBT,GAAawM,IAAY,MAAS,CACnE,CACA,MAAMC,GAAyBF,KAAU,UAAY,KAAOnE,GAAoCpI,EAAW,EAE3G,UAAW9N,MAAW0C,EAAU,CAC9B,MAAM8X,GAAc7F,EAAoB3U,GAAQ,KAAK,EACjDwa,GAAY,QAAU,IACpBD,IACF1M,GAASF,EAAK6M,GAAaD,GAAwB,GAAM,EAAK,EAEhE1M,GAASF,EAAK6M,GAAa1M,GAAa,GAAM,EAAK,GAErD,UAAWtL,MAAQxC,GAAQ,MAAO,CAChC,MAAMya,GAAa9F,EAAoBnS,EAAI,EACvCiY,GAAW,QAAU,IACnBF,IACF1M,GAASF,EAAK8M,GAAYF,GAAwB,GAAM,EAAK,EAE/D1M,GAASF,EAAK8M,GAAY3M,GAAa,GAAM,EAAK,EAEtD,CACF,CACF,CAGF,GAAI8K,GAAqB,OAAS,EAChC,UAAWlR,KAASkR,GAClB,UAAW5Y,MAAW0H,EAAM,SAAU,CACpC,MAAM8S,EAAc7F,EAAoB3U,GAAQ,KAAK,EACjDwa,EAAY,QAAU,GACxB3M,GAASF,EAAK6M,EAAaxB,GAA0B,GAAM,EAAK,EAElE,UAAWxW,MAAQxC,GAAQ,MAAO,CAChC,MAAMya,GAAa9F,EAAoBnS,EAAI,EACvCiY,GAAW,QAAU,GACvB5M,GAASF,EAAK8M,GAAYzB,GAA0B,GAAM,EAAK,CAEnE,CACF,CAIJ,GAAI,MAAM,QAAQvE,EAAa,GAAKA,GAAc,OAAS,EAAG,CAC5D,MAAMC,EAAiBC,EACrBhP,GAAU,CACR,CAAC,EAAG,CAAC,EACL,CAACyH,EAAY,CAAC,EACd,CAACA,EAAYC,CAAW,EACxB,CAAC,EAAGA,CAAW,CAAA,CAChB,CAAA,EAEHkH,GAAkB,CAChB,IAAA5G,EACA,cAAA8G,GACA,eAAAC,EACA,oBAAAC,EACA,gBAAiBkE,EACjB,oBAAsB,WAA0D,6BAC5E6B,IAAQ,CACN,MAAMC,EAAW,OAAOD,GAAK,EAAE,EACzBE,GAAiB,GAAGF,GAAK,eAAe,IAAIA,GAAK,eAAe,IAAIA,GAAK,aAAa,IAAIA,GAAK,SAAS,GAC1GxC,GAAwB,QAAQ,IAAIyC,CAAQ,IAAMC,KACpD1C,GAAwB,QAAQ,IAAIyC,EAAUC,EAAc,EAC5D,QAAQ,MAAM,4BAA6BF,EAAI,EAEnD,EACA,MAAA,CACL,CACH,CAEA,MAAMG,GAAUZ,GAAA,EAEhB,GAAI5B,IACF,GAAIlD,IAAS,QACX1E,GAAuB9C,EAAKyK,GAAW,QAASzH,CAAoB,EACpEG,GAAgBnD,EAAKyK,GAAW,QAAS5B,EAAa,QAAS7F,CAAoB,UAC1EkK,GAAQ,OAAS,EAC1B,GAAI1F,IAAS,WAAY,CACvB,MAAM2F,EAAOnG,EAAoBkG,EAAO,EACpCC,EAAK,QAAU,GACjBjN,GAASF,EAAKmN,EAAMjC,EAAqB,GAAO,EAAK,EAEnDiC,EAAK,QAAU,GACjBjN,GAASF,EAAKgH,EAAoBhP,GAAUkV,EAAO,CAAC,EAAGhC,EAAqB,GAAM,GAAMI,CAA4B,CAExH,KAAO,CACL,MAAMjZ,EAAU2U,EAAoBkG,EAAO,EACvC7a,EAAQ,QAAU,GACpB6N,GAASF,EAAK3N,EAAS6Y,EAAqB,GAAM,GAAMI,CAA4B,CAExF,EAIJ,GAAIP,EAAyB,OAAS,EAAG,CACvC,MAAM/c,EAAO,KAAK,IAAI,KAAM6a,EAAa,SAAS,eAAA,EAAiB,MAAQ,CAAC,EACtEuE,GACJ,OAAOnD,GAAgC,UAAY,OAAO,SAASA,CAA2B,EAC1F,KAAK,IAAI,EAAGA,CAA2B,EACvClF,GAAmCiF,GAA8Bhc,EAAM6a,EAAa,SAAS,gBAAgB,EACnH,UAAW9O,KAASgR,EAA0B,CAC5C,GAAI,CAAChR,EAAM,OAAO,MAAO,SACzB,MAAMsT,GAAcjJ,GAAyBrK,EAAM,QAAQ,EAC3D,GAAI,CAACsT,GAAa,SAClB,MAAMC,GAAe1N,GAAQiJ,EAAa,SAAS,cAAcwE,GAAY,CAAC,EAAGA,GAAY,CAAC,CAAC,GAAK,CAAA,CAAE,EACtG,GAAI,CAACC,GAAc,SACnB,IAAIC,GAAoBzI,GACtByG,GACA5B,IAA8B,CAC5B,OAAQ5P,EAAM,OACd,SAAUA,EAAM,UAChB,YAAaA,EAAM,YACnB,KAAA/L,CAAA,CACD,CAAA,EAECof,GAAsB,IACxBG,GAAoB,CAClB,GAAGA,GACH,QAASA,GAAkB,QAAUH,EAAA,GAGzCrH,GAAgB/F,EAAKjG,EAAM,OAAO,MAAOuT,GAAcrH,EAAaC,EAAcqH,EAAiB,CACrG,CACF,CAEA,GAAI/B,GAA+B,SAAWd,KAAWlD,IAAS,YAAcA,IAAS,aAAeA,IAAS,YAAa,CAC5H,MAAMzE,EAAU0H,GAAW,QAC3B,GAAI1H,EAAQ,UAAW,CACrB,MAAMyK,GAAahG,IAAS,WAAaxP,GAAUkV,EAAO,EAAIA,GAC9D,GAAIM,GAAW,QAAU,EAAG,CAC1B,MAAMC,EAAS5N,GAAY2N,EAAU,EAC/BhY,GAAM,OAAOH,GAAa,UAAY,OAAO,SAASA,CAAQ,GAAKA,EAAW,EAAIA,EAAW,EAC7FsQ,GAAUnQ,GAAM,EAAKiY,EAASjY,GAAMA,IAAQwI,GAAiBA,IAAkB,EAC/EgI,GAAOwF,GAA+B,OAAO7F,EAAO,EAEpDtC,GAASN,EAAQ,eAAiBA,EAAQ,QAAUnD,GAAQiJ,EAAa,SAAS,cAAc9F,EAAQ,QAAQ,CAAC,EAAGA,EAAQ,QAAQ,CAAC,CAAC,GAAK,EAAE,EAAI,MACnJM,IACFkD,GACEvG,EACAgG,GACA3C,GACA4C,EACAC,EACAsF,GAA+B,MAC/BA,GAA+B,cAC/BA,GAA+B,aAAA,CAGrC,CACF,CACF,CACF,EAAG,CACDd,GACAlD,EACA8E,GACAZ,GACA1E,EACAvH,EACAC,EACAmJ,EACAkC,EACAjE,GACA8C,EACAC,GACAqB,EACAC,GACAC,GACAE,EACAL,GACAI,GACA3B,EACAC,EACA4B,GACAC,GACAxB,GACAC,EACA5U,EACA2N,CAAA,CACD,EAEK0K,EAAc/B,EAAAA,YAAY,IAAM,CAChCrB,GAAe,UACnBA,GAAe,QAAU,GACzB,sBAAsB,IAAM,CAC1BA,GAAe,QAAU,GACzBiC,GAAA,CACF,CAAC,EACH,EAAG,CAACA,EAAW,CAAC,EAEVoB,EAAehC,EAAAA,YAAY,CAACiC,EAAiB,KAAU,CAC3D,MAAM7K,EAAU0H,GAAW,QACrBld,EAAS6c,EAAU,QAErB7c,GAAUwV,EAAQ,YAAc,MAAQxV,EAAO,kBAAkBwV,EAAQ,SAAS,GACpFxV,EAAO,sBAAsBwV,EAAQ,SAAS,EAGhDA,EAAQ,UAAY,GACpBA,EAAQ,UAAY,KACpBA,EAAQ,MAAQ,KAChBA,EAAQ,QAAU,KAClBA,EAAQ,OAAS,CAAA,EACjBA,EAAQ,aAAe,CAAA,EACvBA,EAAQ,YAAc,KACjB6K,IACH7K,EAAQ,OAAS,KACjBA,EAAQ,aAAe,KAE3B,EAAG,CAAA,CAAE,EAEC8K,GAAUlC,EAAAA,YACbmC,GAAoG,CACnG,MAAM1K,EAAYyF,EAAa,QAC/B,GAAI,CAACzF,GAAa3D,GAAc,GAAKC,GAAe,EAAG,OAAO,KAE9D,MAAMmM,EAAMjM,GAAQwD,EAAU,cAAc0K,EAAM,QAASA,EAAM,OAAO,CAAC,EACzE,OAAKjC,EACEtM,GAAWsM,EAAKpM,EAAYC,CAAW,EAD7B,IAEnB,EACA,CAACmJ,EAAcpJ,EAAYC,CAAW,CAAA,EAGlCqO,GAAgBpC,cAAamC,GAAoG,CACrI,MAAMvgB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAAO,KACpB,MAAMwD,EAAOxD,EAAO,sBAAA,EACdkF,EAAIwC,EAAM6Y,EAAM,QAAU/c,EAAK,KAAM,EAAGA,EAAK,KAAK,EAClD2B,EAAIuC,EAAM6Y,EAAM,QAAU/c,EAAK,IAAK,EAAGA,EAAK,MAAM,EACxD,MAAI,CAAC,OAAO,SAAS0B,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,EAAG,CAAA,CAAE,EAECsb,GAAgBrC,EAAAA,YAAY,IAAM,CACtC,MAAM5I,EAAU0H,GAAW,QAC3B,GAAI,CAAC1H,EAAQ,UAAW,CACtB4K,EAAa,EAAI,EACjBD,EAAA,EACA,MACF,CAEA,IAAInb,EAA6D,CAAA,EACjE,GAAIiV,IAAS,WACPzE,EAAQ,OAAO,QAAUnF,KAC3BrL,EAAcyF,GAAU+K,EAAQ,MAAM,WAE/ByE,IAAS,YAClBjV,EAAcoP,GAAgBoB,EAAQ,MAAOA,EAAQ,QAASsF,IAAwB,UAC7Eb,IAAS,WAClBjV,EAAc4P,GAAaY,EAAQ,MAAOA,EAAQ,OAAO,UAChDyE,IAAS,QAAS,CAC3B,MAAMyG,EAAWlL,EAAQ,OAAOA,EAAQ,OAAO,OAAS,CAAC,GAAKA,EAAQ,SAAWA,EAAQ,MACzF,GAAIC,EAAqB,gBAAkBiL,GAAYlL,EAAQ,OAAO,QAAU,GAAK+F,IAAamF,CAAQ,EAAG,CAC3GN,EAAa,EAAI,EACjBD,EAAA,EACA,MACF,CACA,MAAM9K,EAAaI,EAAqB,WAClC1K,EAAgB,KAAK,IAAI8G,GAAwB4D,EAAqB,OAAS,GAAM3D,GAAgCuD,EAAW,EAChIsL,GAAanL,EAAQ,aAAa,OAAS,EAAIA,EAAQ,aAAeiE,EAAoBjE,EAAQ,MAAM,EACxGoL,EAAgBzR,GAAwBwR,GAAY,CACxD,OAAQlL,EAAqB,OAC7B,cAAA1K,EACA,YAAa,KAAK,IAAI,GAAI,KAAK,MAAM,GAAKsK,CAAU,CAAC,EACrD,kBAAmBtK,EAAgB,IACnC,gBAAiB0K,EAAqB,aAAA,CACvC,EACKoL,GAA8D,CAAA,EACpE,UAAWnc,KAASkc,EAAe,CACjC,MAAMjM,GAAQ0J,GAAmB3Z,CAAK,EACjCiQ,IACLkM,GAAa,KAAKlM,EAAK,CACzB,CACA3P,EAAcyF,GAAUoW,EAAY,CACtC,EAEK5G,IAAS,YAAcA,IAAS,aAAeA,IAAS,YAAcA,IAAS,UAAYiB,GAAelW,CAAW,GAAKwW,GAE7HA,EAAe,CACb,KAAAvB,EACA,OAHsDA,IAAS,QAAU,QAAU,MAInF,YAAAjV,EACA,KAAMuN,GAAcvN,CAAW,EAC/B,OAAQsN,GAAYtN,CAAW,CAAA,CAChC,EAGHob,EAAa,EAAI,EACjBD,EAAA,CACF,EAAG,CACDlG,EACAuB,EACA4E,EACAD,EACA1G,EACA4E,GACAvD,GACArF,EAAqB,OACrBA,EAAqB,WACrBA,EAAqB,cACrBA,EAAqB,eACrB8F,CAAA,CACD,EAEKuF,GAAgB1C,EAAAA,YACpB,CAACzD,EAA0BtQ,IAA8D,CACvF,MAAMrF,EAAc8Z,GAAyBnE,EAAWtQ,CAAM,EAC9D,GAAI,CAAC6Q,GAAelW,CAAW,EAAG,OAClC,MAAM+b,EAAkDpG,IAAc,yBAA2B,QAAU,MACrGqG,EAAkD,CACtD,KAAMrG,EACN,OAAAoG,EACA,YAAA/b,EACA,KAAMuN,GAAcvN,CAAW,EAC/B,OAAQsN,GAAYtN,CAAW,CAAA,EAEjCwW,IAAiBwF,CAAM,EACnBD,IAAW,SAAWtF,GACxBA,EAAgBuF,CAAsD,CAE1E,EACA,CAAClC,GAA0BtD,EAAgBC,CAAe,CAAA,EAGtDwF,GAAmB7C,EAAAA,YAAY,CAAC5I,EAAsBb,EAAoDoB,IAA8D,CAC5K,MAAMmL,EAAiBnP,GAAoBA,GACrCoP,EAAa3L,EAAQ,aAAaA,EAAQ,aAAa,OAAS,CAAC,EACvE,GAAI,CAAC2L,EAAY,CACf3L,EAAQ,OAAO,KAAKb,CAAK,EACzBa,EAAQ,aAAa,KAAKO,CAAM,EAChCP,EAAQ,QAAUb,EAClB,MACF,CACA,MAAM5T,GAAKgV,EAAO,CAAC,EAAIoL,EAAW,CAAC,EAC7BngB,EAAK+U,EAAO,CAAC,EAAIoL,EAAW,CAAC,EAC/BpgB,GAAKA,GAAKC,EAAKA,GAAMkgB,GACvB1L,EAAQ,OAAO,KAAKb,CAAK,EACzBa,EAAQ,aAAa,KAAKO,CAAM,IAEhCP,EAAQ,OAAOA,EAAQ,OAAO,OAAS,CAAC,EAAIb,EAC5Ca,EAAQ,aAAaA,EAAQ,aAAa,OAAS,CAAC,EAAIO,GAE1DP,EAAQ,QAAUb,CACpB,EAAG,CAAA,CAAE,EAECyM,GAAoBhD,EAAAA,YACvBmC,GAAgD,CAG/C,GAFI,CAACpD,IACDlD,IAAS,UACTsG,EAAM,SAAW,EAAG,OAExB,MAAM5L,EAAQ2L,GAAQC,CAAK,EAC3B,GAAI,CAAC5L,EAAO,OACZ,MAAMoB,EAASyK,GAAcD,CAAK,EAClC,GAAI,CAACxK,EAAQ,OAKb,GAHAwK,EAAM,eAAA,EACNA,EAAM,gBAAA,EAEFvG,GAAYC,CAAI,EAAG,CACrB,MAAMzE,GAAU0H,GAAW,QAC3B1H,GAAQ,YAAcb,EACtBmM,GAAc7G,EAAMtF,CAAK,EACzBwL,EAAA,EACA,MACF,CAEA,MAAMngB,EAAS6c,EAAU,QACrB7c,GACFA,EAAO,kBAAkBugB,EAAM,SAAS,EAG1C,MAAM/K,EAAU0H,GAAW,QAC3B1H,EAAQ,UAAY,GACpBA,EAAQ,UAAY+K,EAAM,UAC1B/K,EAAQ,MAAQb,EAChBa,EAAQ,QAAUb,EAClBa,EAAQ,OAASb,EACjBa,EAAQ,aAAeO,EACvBP,EAAQ,OAASyE,IAAS,YAAcA,IAAS,QAAU,CAACtF,CAAK,EAAI,CAAA,EACrEa,EAAQ,aAAeyE,IAAS,QAAU,CAAClE,CAAM,EAAI,CAAA,EACrDoK,EAAA,CACF,EACA,CAAChD,GAAQlD,EAAMqG,GAASE,GAAeM,GAAeX,CAAW,CAAA,EAG7DkB,GAAoBjD,EAAAA,YACvBmC,GAAgD,CAE/C,GADI,CAACpD,IACDlD,IAAS,SAAU,OAEvB,MAAMtF,EAAQ2L,GAAQC,CAAK,EAC3B,GAAI,CAAC5L,EAAO,OACZ,MAAMoB,EAASyK,GAAcD,CAAK,EAClC,GAAI,CAACxK,EAAQ,OAEb,MAAMP,EAAU0H,GAAW,QAI3B,GAHA1H,EAAQ,OAASb,EACjBa,EAAQ,aAAeO,EAEnBiE,GAAYC,CAAI,EAAG,CACrBzE,EAAQ,YAAcb,EACtB4L,EAAM,eAAA,EACNA,EAAM,gBAAA,EACNJ,EAAA,EACA,MACF,CAEA,GAAIlG,IAAS,QAAS,CACpB,GAAI,CAACzE,EAAQ,WAAaA,EAAQ,YAAc+K,EAAM,UAAW,CAC/DJ,EAAA,EACA,MACF,CACAI,EAAM,eAAA,EACNA,EAAM,gBAAA,EACNU,GAAiBzL,EAASb,EAAOoB,CAAM,EACvCoK,EAAA,EACA,MACF,CAEA,GAAI,GAAC3K,EAAQ,WAAaA,EAAQ,YAAc+K,EAAM,WAMtD,IAHAA,EAAM,eAAA,EACNA,EAAM,gBAAA,EAEFtG,IAAS,WAAY,CACvB,MAAMpE,EAAYyF,EAAa,QACzB7a,GAAO,KAAK,IAAI,KAAMoV,GAAW,eAAA,EAAiB,MAAQ,CAAC,EAC3DyL,EAAehR,GAAuB7P,GACtC8gB,GAAgBD,EAAeA,EAC/Blc,EAAOoQ,EAAQ,OAAOA,EAAQ,OAAO,OAAS,CAAC,EAErD,GAAI,CAACpQ,EACHoQ,EAAQ,OAAO,KAAKb,CAAK,MACpB,CACL,MAAM5T,GAAK4T,EAAM,CAAC,EAAIvP,EAAK,CAAC,EACtBpE,GAAK2T,EAAM,CAAC,EAAIvP,EAAK,CAAC,EACxBrE,GAAKA,GAAKC,GAAKA,IAAMugB,IACvB/L,EAAQ,OAAO,KAAKb,CAAK,CAE7B,CACF,MACEa,EAAQ,QAAUb,EAGpBwL,EAAA,EACF,EACA,CAAChD,GAAQlD,EAAMqG,GAASE,GAAeL,EAAa7E,EAAc2F,EAAgB,CAAA,EAG9EO,GAAkBpD,EAAAA,YACrBmC,GAAgD,CAC/C,MAAM/K,EAAU0H,GAAW,QAC3B,GAAI,CAAC1H,EAAQ,WAAaA,EAAQ,YAAc+K,EAAM,UAAW,OAEjEA,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,MAAM5L,EAAQ2L,GAAQC,CAAK,EACrBxK,EAASyK,GAAcD,CAAK,EAC9B5L,IACFa,EAAQ,OAASb,EACboB,IACFP,EAAQ,aAAeO,GAErBkE,IAAS,QACPlE,GACFkL,GAAiBzL,EAASb,EAAOoB,CAAM,EAGzCP,EAAQ,QAAUb,GAGtB,MAAM3U,EAAS6c,EAAU,QACrB7c,GAAUA,EAAO,kBAAkBugB,EAAM,SAAS,GACpDvgB,EAAO,sBAAsBugB,EAAM,SAAS,EAG9CE,GAAA,CACF,EACA,CAACA,GAAeH,GAASE,GAAevG,EAAMgH,EAAgB,CAAA,EAG1DQ,GAAqBrD,EAAAA,YAAY,IAAM,CAC3C,MAAM5I,EAAU0H,GAAW,QAC3B,IAAIwE,EAAU,GACVzH,IAAS,SAAW,CAACzE,EAAQ,WAAaA,EAAQ,SACpDA,EAAQ,OAAS,KACjBA,EAAQ,aAAe,KACvBkM,EAAU,IAER1H,GAAYC,CAAI,GAAKzE,EAAQ,cAC/BA,EAAQ,YAAc,KACtBkM,EAAU,IAERA,GACFvB,EAAA,CAEJ,EAAG,CAAClG,EAAMkG,CAAW,CAAC,EAEtBwB,OAAAA,EAAAA,UAAU,IAAM,CACdxD,GAAA,EACAgC,EAAA,EAEA,MAAMngB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAEb,MAAM4hB,EAAW,IAAI,eAAe,IAAM,CACxCzD,GAAA,EACAgC,EAAA,CACF,CAAC,EACD,OAAAyB,EAAS,QAAQ5hB,CAAM,EAEhB,IAAM,CACX4hB,EAAS,WAAA,CACX,CACF,EAAG,CAACzD,GAAcgC,CAAW,CAAC,EAE9BwB,EAAAA,UAAU,IAAM,CACTxE,IACHiD,EAAA,EAEFD,EAAA,CACF,EAAG,CAAChD,GAAQgD,EAAaC,CAAY,CAAC,EAEtCuB,EAAAA,UAAU,IAAM,CACV1E,GAAY,UAAYhD,IAG5BgD,GAAY,QAAUhD,EACtBmG,EAAA,EACAD,EAAA,EACF,EAAG,CAAClG,EAAMmG,EAAcD,CAAW,CAAC,EAEpCwB,EAAAA,UAAU,IAAM,CACdxB,EAAA,CACF,EAAG,CAACzE,EAAiB0B,EAAwB7D,GAAe4G,CAAW,CAAC,EAExEwB,EAAAA,UAAU,IAAM,CACd,GAAKhF,EACL,OAAAA,EAAc,QAAUwD,EACjB,IAAM,CACPxD,EAAc,UAAYwD,IAC5BxD,EAAc,QAAU,KAE5B,CACF,EAAG,CAACA,EAAewD,CAAW,CAAC,EAE/BwB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACxE,GAAQ,OAEb,MAAM0E,EAAatB,GAA+B,CAC5CA,EAAM,MAAQ,WAClBH,EAAA,EACAD,EAAA,EACF,EAEA,cAAO,iBAAiB,UAAW0B,CAAS,EACrC,IAAM,CACX,OAAO,oBAAoB,UAAWA,CAAS,CACjD,CACF,EAAG,CAAC1E,GAAQiD,EAAcD,CAAW,CAAC,EAGpC2B,GAAAA,IAAC,SAAA,CACC,IAAKjF,EACL,UAAAD,EACA,MAAOsB,GACP,cAAekD,GACf,cAAeC,GACf,YAAaG,GACb,gBAAiBA,GACjB,eAAgBC,GAChB,cAAelB,GAAS,CAClBpD,MAAc,eAAA,CACpB,EACA,QAASoD,GAAS,CAChB,GAAI,CAACpD,GAAQ,OACb,MAAMnd,EAAS6c,EAAU,QACnBhH,EAAYyF,EAAa,QAC/B,GAAI,CAACtb,GAAU,OAAO6V,GAAW,QAAW,WAAY,OACxD0K,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,MAAM/c,EAAOxD,EAAO,sBAAA,EACdY,EAAU2f,EAAM,QAAU/c,EAAK,KAC/B3C,GAAU0f,EAAM,QAAU/c,EAAK,IACrCqS,EAAU,OAAO0K,EAAM,OAAS,EAAIzP,GAAuBC,GAAuBnQ,EAASC,EAAO,EAClGsf,EAAA,CACF,CAAA,CAAA,CAGN,CC/5BA,SAAS4B,GAAkBxd,EAAuB,CAChD,OAAO,OAAOA,GAAS,EAAE,EAAE,QAAQ,OAAQ,EAAE,CAC/C,CAEA,SAASyd,GAAmBzd,EAAuB,CACjD,MAAM+Z,EAAM,OAAO/Z,GAAS,EAAE,EAC9B,OAAO+Z,EAAI,WAAW,GAAG,EAAIA,EAAM,IAAIA,CAAG,EAC5C,CAEA,SAAS2D,GAAgBC,EAA6B,CACpD,MAAM5O,EAAOyO,GAAkBG,CAAW,EAC1C,GAAI,CAAC5O,EAAM,MAAO,GAGlB,GAAI,mBAAmB,KAAKA,CAAI,EAAG,OAAOA,EAE1C,IAAI6O,EAAqB,KACzB,GAAI,CACFA,EAAS,IAAI,IAAI7O,CAAI,CACvB,MAAQ,CACN6O,EAAS,IACX,CAEA,GAAIA,EAAQ,CACV,MAAMC,EAAS,GAAGD,EAAO,QAAQ,KAAKA,EAAO,IAAI,GAC3CzW,EAAOqW,GAAkBI,EAAO,UAAY,EAAE,EAIpD,MAAI,UAAU,KAAKzW,CAAI,EAAU,GAAG0W,CAAM,GAAG1W,CAAI,GAC7C,YAAY,KAAKA,CAAI,EAAU,GAAG0W,CAAM,GAAG1W,CAAI,GAC5C,GAAG0W,CAAM,GAAG1W,CAAI,QACzB,CAGA,MAAI,UAAU,KAAK4H,CAAI,EAAU,OAC7B,YAAY,KAAKA,CAAI,EAAU,GAAGA,CAAI,GACnC,GAAGA,CAAI,QAChB,CAEO,SAAS+O,GAAmB/D,EAAsB4D,EAAqC,CAC5F,MAAMI,EAAMhE,GAAK,SAAW,CAAA,EACtBiE,EAAQ,CAAC,CAACjE,GAAK,QAEfhe,EAAQ,OAAOgiB,EAAI,OAAShE,GAAK,OAAS,CAAC,EAC3C/d,EAAS,OAAO+hB,EAAI,QAAUhE,GAAK,QAAU,CAAC,EAC9CkE,EAAW,OAAOF,EAAI,UAAYhE,GAAK,UAAY,CAAC,EACpDmE,EAAc,OAAOH,EAAI,MAAQhE,GAAK,MAAQ,CAAC,EAC/CoE,EAAW,OAAOJ,EAAI,MAAQhE,GAAK,MAAQ,EAAE,EAC7CrW,EAAM,OAAOqa,EAAI,KAAOhE,GAAK,KAAO,CAAC,EAE3C,GAAI,CAAChe,GAAS,CAACC,GAAU,CAACiiB,GAAY,CAACE,EACrC,MAAM,IAAI,MAAM,gEAAgE,EAGlF,MAAMtZ,EAAmB,MAAM,QAAQkV,GAAK,KAAK,EAC7CA,EAAI,MAAM,IAAK/U,IAAsB,CACnC,OAAQ,OAAOA,GAAM,QAAU,EAAE,EACjC,SAAU,OAAOA,GAAM,UAAY,EAAE,EACrC,UAAW,OAAOA,GAAM,WAAa,EAAE,CAAA,EACvC,EACF,CAAA,EAEEoZ,EAAiBX,GAAmBU,CAAQ,EAC5CE,EAAcX,GAAgBC,CAAW,EACzCW,EAAiBN,EAAQ,CAACO,EAAc5d,EAAWC,IAAsB,GAAGyd,CAAW,GAAGD,CAAc,IAAIG,CAAI,IAAI3d,CAAC,IAAID,CAAC,QAAU,OAE1I,MAAO,CACL,GAAIoZ,GAAK,KAAO,UAChB,KAAMA,GAAK,MAAQ,UACnB,MAAAhe,EACA,OAAAC,EACA,IAAK,OAAO,SAAS0H,CAAG,GAAKA,EAAM,EAAIA,EAAM,OAC7C,SAAAua,EACA,YAAa,OAAO,SAASC,CAAW,EAAI,KAAK,IAAI,EAAG,KAAK,MAAMA,CAAW,CAAC,EAAI,EACnF,SAAAC,EACA,YAAAR,EACA,MAAA9Y,EACA,eAAAyZ,CAAA,CAEJ,CAEO,SAASE,GAAU5jB,EAA6E2jB,EAAc5d,EAAWC,EAAmB,CACjJ,GAAIhG,EAAO,eACT,OAAOA,EAAO,eAAe2jB,EAAM5d,EAAGC,CAAC,EAEzC,MAAMwd,EAAiBX,GAAmB7iB,EAAO,QAAQ,EACzD,MAAO,GAAGA,EAAO,WAAW,GAAGwjB,CAAc,IAAIG,CAAI,IAAI3d,CAAC,IAAID,CAAC,OACjE,CCvDA,MAAM8d,GAAmD,CACxD,MAAO,IACP,OAAQ,IACR,OAAQ,GACR,SAAU,eACV,aAAc,EACd,YAAa,EACb,gBAAiB,wBACjB,YAAa,4BACb,oBAAqB,UACrB,oBAAqB,OACrB,kBAAmB,cACnB,YAAa,GACb,cAAe,GACf,kBAAmB,EACpB,EAEA,SAASC,GACRxQ,EACAtI,EACA+Y,EACAC,EACO,CACP,MAAMC,EAAMjZ,EAAO,OACnB,GAAIiZ,IAAQ,EAGZ,SAAS3d,EAAI,EAAGA,EAAI2d,EAAK3d,GAAK,EAAG,CAChC,MAAM4d,EAAOlZ,EAAO1E,CAAC,EACf6d,EAAKnZ,GAAQ1E,EAAI,GAAK2d,CAAG,EACzBG,EAAU,KAAK,MAAMD,EAAG,CAAC,EAAID,EAAK,CAAC,EAAGC,EAAG,CAAC,EAAID,EAAK,CAAC,CAAC,EAC3D,GAAIE,EAAU,KAAM,SAEpB,MAAMra,EAAI,KAAK,IAAI,EAAG,KAAK,OAAOqa,EAAUJ,IAAWD,EAAUC,EAAO,CAAC,EACnEK,EAAYta,EAAIga,GAAWha,EAAI,GAAKia,EACpCM,EAAQF,EAAU,KAAK,IAAI,KAAMC,CAAS,EAC1CE,EAAUR,EAAUO,EACpBE,EAASR,EAASM,EAExBhR,EAAI,UAAA,EACJA,EAAI,OAAO4Q,EAAK,CAAC,EAAGA,EAAK,CAAC,CAAC,EAC3B5Q,EAAI,OAAO6Q,EAAG,CAAC,EAAGA,EAAG,CAAC,CAAC,EACvB7Q,EAAI,YAAY,CAACiR,EAASC,CAAM,CAAC,EACjClR,EAAI,eAAiB,EACrBA,EAAI,OAAA,CACL,CAEAA,EAAI,YAAY,EAAE,EAClBA,EAAI,eAAiB,EACtB,CAEA,SAASmR,GACRrf,EACAwP,EACApM,EAAM,EACG,CACT,OAAI,OAAOpD,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUwP,EAC1D,KAAK,IAAIpM,EAAKpD,CAAK,CAC3B,CAEA,SAASsf,GAAe/Y,EAAuD,CAC9E,OACC,MAAM,QAAQA,CAAM,GACpBA,EAAO,SAAW,GAClB,OAAO,SAASA,EAAO,CAAC,CAAC,GACzB,OAAO,SAASA,EAAO,CAAC,CAAC,GACzB,OAAO,SAASA,EAAO,CAAC,CAAC,GACzB,OAAO,SAASA,EAAO,CAAC,CAAC,CAE3B,CAEA,MAAMgZ,GAA4C,CACjD,SAAU,WACV,IAAK,EACL,MAAO,EACP,OAAQ,EACR,MAAO,GACP,OAAQ,GACR,aAAc,IACd,OAAQ,kCACR,WAAY,yBACZ,MAAO,OACP,SAAU,GACV,WAAY,EACZ,OAAQ,UACR,QAAS,EACT,QAAS,OACT,WAAY,SACZ,eAAgB,QACjB,EAEO,SAASC,GAAY,CAC3B,OAAA5kB,EACA,aAAAmc,EACA,UAAA0I,EAAY,GACZ,QAAAzhB,EACA,cAAAoa,EACA,UAAAC,EACA,MAAA5J,CACD,EAAyC,CACxC,MAAM6J,EAAYC,EAAAA,OAAiC,IAAI,EACjDmH,EAAenH,EAAAA,OAAiC,IAAI,EACpDoH,EAAgBpH,EAAAA,OAAsB,IAAI,EAC1CqH,EAAcrH,EAAAA,OAAsD,CACzE,OAAQ,GACR,UAAW,IAAA,CACX,EACKsH,EAAStH,EAAAA,OAAsB,IAAI,EACnCC,EAAiBD,EAAAA,OAAO,EAAK,EAE7Bxc,EAAQsjB,GACbrhB,GAAS,MACTygB,GAA6B,MAC7B,EAAA,EAEKziB,EAASqjB,GACdrhB,GAAS,OACTygB,GAA6B,OAC7B,EAAA,EAGKqB,EAAchH,EAAAA,QAAQ,IAAM,CACjC,MAAMiH,EAAO,KAAK,IAAI,EAAGnlB,EAAO,KAAK,EAC/BolB,EAAO,KAAK,IAAI,EAAGplB,EAAO,MAAM,EAChCqlB,EAAcF,EAAOC,EACrBE,GAAYnkB,EAAQC,EAE1B,IAAImkB,EACAC,GACJ,OAAIH,EAAcC,IACjBC,EAAKpkB,EACLqkB,GAAKrkB,EAAQkkB,IAEbG,GAAKpkB,EACLmkB,EAAKnkB,EAASikB,GAGR,CACN,GAAIlkB,EAAQokB,GAAM,EAClB,GAAInkB,EAASokB,IAAM,EACnB,EAAGD,EACH,EAAGC,EAAA,CAEL,EAAG,CAACxlB,EAAO,MAAOA,EAAO,OAAQmB,EAAOC,CAAM,CAAC,EACzCqkB,EAAShB,GACdrhB,GAAS,OACTygB,GAA6B,OAC7B,CAAA,EAEKjL,EAAe6L,GACpBrhB,GAAS,aACTygB,GAA6B,aAC7B,CAAA,EAEK6B,EAAcjB,GACnBrhB,GAAS,YACTygB,GAA6B,YAC7B,CAAA,EAEK8B,EAAoB,KAAK,IAC9B,EACA,KAAK,MACJlB,GACCrhB,GAAS,kBACTygB,GAA6B,kBAC7B,CAAA,CACD,CACD,EAGK+B,EACLxiB,GAAS,iBAAmBygB,GAA6B,gBACpDgC,EACLziB,GAAS,aAAeygB,GAA6B,YAChDiC,EACL1iB,GAAS,qBACTygB,GAA6B,oBACxBkC,GACL3iB,GAAS,sBAAwB,UAAYA,GAAS,sBAAwB,OAC3EA,EAAQ,oBACRygB,GAA6B,oBAC3BmC,EACL5iB,GAAS,mBACTygB,GAA6B,kBACxBoC,GACL7iB,GAAS,aAAeygB,GAA6B,YAChDqC,GACL9iB,GAAS,eAAiBygB,GAA6B,cAClDsC,GACL/iB,GAAS,UAAYygB,GAA6B,SAC7CuC,GAAUhjB,GAAS,QACnBijB,EAAYjjB,GAAS,UACrBkjB,EAAmBljB,GAAS,iBAE5B2b,EAAcb,EAAAA,QAAuB,IAAM,CAChD,MAAMqI,EAAqB,CAAA,EAC3B,OAAIJ,KAAa,YAAcA,KAAa,gBAAmB,KAAOV,IAC7D,MAAQA,EACbU,KAAa,YAAcA,KAAa,cAAiB,IAAMV,IAC1D,OAASA,EAEX,CACN,SAAU,WACV,GAAGc,EACH,MAAAplB,EACA,OAAAC,EACA,aAAAwX,EACA,SAAU,SACV,OAAQ,EACR,cAAeqN,GAAc,OAAS,OACtC,YAAa,OACb,UAAW,iCACX,GAAGpS,CAAA,CAEL,EAAG,CAAC4R,EAAQU,GAAUhlB,EAAOC,EAAQwX,EAAcqN,GAAapS,CAAK,CAAC,EAEhE2S,EAAOvH,EAAAA,YAAY,IAAM,CAC9B,MAAMpe,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAEb,MAAMyS,EAAMzS,EAAO,WAAW,IAAI,EAClC,GAAI,CAACyS,EAAK,OAEV,MAAMmT,EAAOtlB,EACPulB,GAAOtlB,EACPoD,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAE9CmiB,GAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOjiB,CAAG,CAAC,EAC3CoiB,GAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,GAAOliB,CAAG,CAAC,GAC7C3D,EAAO,QAAU8lB,IAAU9lB,EAAO,SAAW+lB,MAChD/lB,EAAO,MAAQ8lB,GACf9lB,EAAO,OAAS+lB,IAGjBtT,EAAI,aAAa,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EACjCA,EAAI,UAAU,EAAG,EAAGzS,EAAO,MAAOA,EAAO,MAAM,EAC/CyS,EAAI,aAAa9O,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,EAErC8O,EAAI,UAAYsS,EAChBtS,EAAI,SAAS,EAAG,EAAGmT,EAAMC,EAAI,EAE7B,KAAM,CAAE,EAAGG,GAAI,EAAGC,EAAI,EAAGvB,GAAI,EAAGC,EAAA,EAAON,EAEjC1E,GAAUsE,EAAa,QACzBtE,IACHlN,EAAI,UAAUkN,GAASqG,GAAIC,EAAIvB,GAAIC,EAAE,EAGtClS,EAAI,YAAcuS,EAClBvS,EAAI,UAAYoS,EAChBpS,EAAI,WACHoS,EAAc,GACdA,EAAc,GACde,EAAOf,EACPgB,GAAOhB,CAAA,EAGR,MAAMhP,EAAYyF,EAAa,QACzBxQ,GAAS+K,GAAW,gBAAA,EACpBqQ,GAAUrQ,GAAW,iBAAA,EACrBsQ,EAAatC,GAAe/Y,EAAM,EACrCA,GACA+Y,GAAeK,EAAc,OAAO,EACnCA,EAAc,QACd,KACJ,GAAI,CAACiC,EAAY,OACjBjC,EAAc,QAAUiC,EAExB,MAAMvkB,GAAK8iB,GAAK,KAAK,IAAI,EAAGvlB,EAAO,KAAK,EAClC0C,GAAK8iB,GAAK,KAAK,IAAI,EAAGxlB,EAAO,MAAM,EAEnCinB,GACL,MAAM,QAAQF,EAAO,GACrBA,GAAQ,QAAU,GAClBA,GAAQ,MACNxhB,IACA,MAAM,QAAQA,EAAK,GACnBA,GAAM,QAAU,GAChB,OAAO,SAASA,GAAM,CAAC,CAAC,GACxB,OAAO,SAASA,GAAM,CAAC,CAAC,CAAA,EAEtBwhB,GACD,KAEEG,GAASnB,KAAwB,OAEvC,GAAIkB,GAAa,CAChB,MAAM5R,GAAyC4R,GAAY,IACzD1hB,IAAU,CAACshB,GAAKthB,GAAM,CAAC,EAAI9C,GAAIqkB,EAAKvhB,GAAM,CAAC,EAAI7C,EAAE,CAAA,EAGnD4Q,EAAI,KAAA,EACJA,EAAI,UAAA,EACJA,EAAI,KAAKuT,GAAIC,EAAIvB,GAAIC,EAAE,EACvBlS,EAAI,KAAA,EAEJA,EAAI,UAAA,EACJ,QAAShN,GAAI,EAAGA,GAAI+O,GAAc,OAAQ/O,IAAK,EAC1CA,KAAM,EAAGgN,EAAI,OAAO+B,GAAc/O,EAAC,EAAE,CAAC,EAAG+O,GAAc/O,EAAC,EAAE,CAAC,CAAC,EAC3DgN,EAAI,OAAO+B,GAAc/O,EAAC,EAAE,CAAC,EAAG+O,GAAc/O,EAAC,EAAE,CAAC,CAAC,EAEzDgN,EAAI,UAAA,EACJA,EAAI,UAAY0S,EAChB1S,EAAI,KAAA,EAEJA,EAAI,YAAcwS,EAClBxS,EAAI,UAAY,KACZ4T,GACHpD,GAA6BxQ,EAAK+B,GAAe,EAAG,CAAC,EAErD/B,EAAI,OAAA,EAGLA,EAAI,QAAA,EACJ,MACD,CAEA,MAAMqG,GAAOpR,EAAMse,GAAKG,EAAW,CAAC,EAAIvkB,GAAIokB,GAAIA,GAAKtB,EAAE,EACjD3L,GAAMrR,EAAMue,EAAKE,EAAW,CAAC,EAAItkB,GAAIokB,EAAIA,EAAKtB,EAAE,EAChD2B,EAAQ5e,EAAMse,GAAKG,EAAW,CAAC,EAAIvkB,GAAIokB,GAAIA,GAAKtB,EAAE,EAClD6B,EAAS7e,EAAMue,EAAKE,EAAW,CAAC,EAAItkB,GAAIokB,EAAIA,EAAKtB,EAAE,EACnD6B,GAAQ,KAAK,IAAI,EAAGF,EAAQxN,EAAI,EAChC2N,GAAQ,KAAK,IAAI,EAAGF,EAASxN,EAAG,EAOtC,GALAtG,EAAI,UAAY0S,EAChB1S,EAAI,SAASqG,GAAMC,GAAKyN,GAAOC,EAAK,EAEpChU,EAAI,YAAcwS,EAClBxS,EAAI,UAAY,KACZ4T,GAAQ,CACX,MAAMK,GAAuC,CAC5C,CAAC5N,GAAO,GAAKC,GAAM,EAAG,EACtB,CAACD,GAAO,GAAM,KAAK,IAAI,EAAG0N,GAAQ,CAAC,EAAGzN,GAAM,EAAG,EAC/C,CAACD,GAAO,GAAM,KAAK,IAAI,EAAG0N,GAAQ,CAAC,EAAGzN,GAAM,GAAM,KAAK,IAAI,EAAG0N,GAAQ,CAAC,CAAC,EACxE,CAAC3N,GAAO,GAAKC,GAAM,GAAM,KAAK,IAAI,EAAG0N,GAAQ,CAAC,CAAC,CAAA,EAEhDxD,GAA6BxQ,EAAKiU,GAAa,EAAG,CAAC,CACpD,MACCjU,EAAI,WACHqG,GAAO,GACPC,GAAM,GACN,KAAK,IAAI,EAAGyN,GAAQ,CAAC,EACrB,KAAK,IAAI,EAAGC,GAAQ,CAAC,CAAA,CAGxB,EAAG,CACFnmB,EACAC,EACA8jB,EACAU,EACAC,EACAH,EACAvJ,EACAnc,EAAO,MACPA,EAAO,OACPgmB,EACAF,EACAC,EAAA,CACA,EAEK/E,EAAc/B,EAAAA,YAAY,IAAM,CACjCrB,EAAe,UACnBA,EAAe,QAAU,GACzBqH,EAAO,QAAU,sBAAsB,IAAM,CAC5CrH,EAAe,QAAU,GACzBqH,EAAO,QAAU,KACjBuB,EAAA,CACD,CAAC,EACF,EAAG,CAACA,CAAI,CAAC,EAEHgB,GAAoBvI,EAAAA,YACzB,CAACwI,EAAiBC,IAA6C,CAC9D,MAAM7mB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAAO,KAEpB,MAAMwD,GAAOxD,EAAO,sBAAA,EACpB,GAAI,CAACwD,GAAK,OAAS,CAACA,GAAK,OAAQ,OAAO,KAExC,MAAMsjB,EAAStjB,GAAK,MAAQlD,EACtBymB,GAASvjB,GAAK,OAASjD,EACvBymB,GAAO3C,EAAY,EAAIyC,EACvBG,GAAO5C,EAAY,EAAI0C,GACvBG,EAAO7C,EAAY,EAAIyC,EACvBK,GAAO9C,EAAY,EAAI0C,GAEvBK,GAAK1f,GAAOkf,EAAUpjB,GAAK,KAAOwjB,IAAQE,EAAM,EAAG,CAAC,EACpDG,GAAK3f,GAAOmf,EAAUrjB,GAAK,IAAMyjB,IAAQE,GAAM,EAAG,CAAC,EACzD,MAAO,CAACC,GAAKjoB,EAAO,MAAOkoB,GAAKloB,EAAO,MAAM,CAC9C,EACA,CAACA,EAAO,MAAOA,EAAO,OAAQmB,EAAOC,EAAQ8jB,CAAW,CAAA,EAGnDiD,GAAalJ,EAAAA,YAClB,CAAChd,EAAgBC,IAAmB,CACnC,MAAMwU,EAAYyF,EAAa,QAC/B,GAAI,CAACzF,EAAW,OAEhB,GAAIA,EAAU,cAAe,CAC5BA,EAAU,cAAczU,EAAQC,CAAM,EACtC8e,EAAA,EACA,MACD,CAEA,MAAMrV,GAAS+K,EAAU,gBAAA,EACnBsQ,EAAatC,GAAe/Y,EAAM,EACrCA,GACA+Y,GAAeK,EAAc,OAAO,EACnCA,EAAc,QACd,KACJ,GAAI,CAACiC,EAAY,OAEjB,MAAMoB,GAAW,KAAK,IAAI,KAAMpB,EAAW,CAAC,EAAIA,EAAW,CAAC,CAAC,EACvDqB,GAAW,KAAK,IAAI,KAAMrB,EAAW,CAAC,EAAIA,EAAW,CAAC,CAAC,EAE7DtQ,EAAU,aAAa,CACtB,QAASzU,EAASmmB,GAAW,GAC7B,QAASlmB,EAASmmB,GAAW,EAAA,CAC7B,EACDrH,EAAA,CACD,EACA,CAAC7E,EAAc6E,CAAW,CAAA,EAGrBiB,GAAoBhD,EAAAA,YACxBmC,GAAgD,CAEhD,GADI,CAAC6E,IACD7E,EAAM,SAAW,EAAG,OAExB,MAAMvgB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAEb,MAAM2U,EAAQgS,GAAkBpG,EAAM,QAASA,EAAM,OAAO,EACvD5L,IAEL4L,EAAM,eAAA,EACNA,EAAM,gBAAA,EAENvgB,EAAO,kBAAkBugB,EAAM,SAAS,EACxC4D,EAAY,QAAU,CAAE,OAAQ,GAAM,UAAW5D,EAAM,SAAA,EACvD+G,GAAW3S,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC9B,EACA,CAACyQ,GAAauB,GAAmBW,EAAU,CAAA,EAGtCjG,GAAoBjD,EAAAA,YACxBmC,GAAgD,CAChD,MAAMkH,EAAOtD,EAAY,QACzB,GAAI,CAACsD,EAAK,QAAUA,EAAK,YAAclH,EAAM,UAAW,OAExD,MAAM5L,EAAQgS,GAAkBpG,EAAM,QAASA,EAAM,OAAO,EACvD5L,IAEL4L,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN+G,GAAW3S,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC9B,EACA,CAACgS,GAAmBW,EAAU,CAAA,EAGzB9F,GAAkBpD,EAAAA,YACtBmC,GAAgD,CAChD,MAAMkH,EAAOtD,EAAY,QACzB,GAAI,CAACsD,EAAK,QAAUA,EAAK,YAAclH,EAAM,UAAW,OAExD,MAAMvgB,EAAS6c,EAAU,QACzB,GAAI7c,GAAUA,EAAO,kBAAkBugB,EAAM,SAAS,EACrD,GAAI,CACHvgB,EAAO,sBAAsBugB,EAAM,SAAS,CAC7C,MAAQ,CAER,CAGD4D,EAAY,QAAU,CAAE,OAAQ,GAAO,UAAW,IAAA,EAClDhE,EAAA,CACD,EACA,CAACA,CAAW,CAAA,EAGbwB,OAAAA,EAAAA,UAAU,IAAM,CACf,IAAI+F,EAAY,GAChBzD,EAAa,QAAU,KACvB9D,EAAA,EAEA,MAAM2C,EAAO,EACP6E,EAAa,IAAMxoB,EAAO,YAAc2jB,GACxC8E,GAAa,KAAK,KAAKzoB,EAAO,MAAQwoB,CAAU,EAChDE,EAAc,KAAK,KAAK1oB,EAAO,OAASwoB,CAAU,EAClDG,GAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,GAAazoB,EAAO,QAAQ,CAAC,EAC5D4oB,GAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAc1oB,EAAO,QAAQ,CAAC,EAC7D6oB,GAAYF,GAASC,GAE3B,GAAI,CAAC1C,IAAiB2C,GAAYlD,EACjC,OAGD,MAAMnF,EAAU,SAAS,cAAc,QAAQ,EAC/CA,EAAQ,MAAQ,KAAK,IAAI,EAAG,KAAK,MAAM0E,EAAY,CAAC,CAAC,EACrD1E,EAAQ,OAAS,KAAK,IAAI,EAAG,KAAK,MAAM0E,EAAY,CAAC,CAAC,EACtD,MAAM5R,GAAMkN,EAAQ,WAAW,IAAI,EACnC,GAAI,CAAClN,GACJ,OAGDA,GAAI,UAAYsS,EAChBtS,GAAI,SAAS,EAAG,EAAGkN,EAAQ,MAAOA,EAAQ,MAAM,EAEhD,MAAMsI,GAGD,CAAA,EAEL,QAAS9iB,GAAI,EAAGA,GAAI4iB,GAAQ5iB,IAAK,EAChC,QAASD,EAAI,EAAGA,EAAI4iB,GAAQ5iB,GAAK,EAAG,CACnC,MAAM4T,GAAO5T,EAAI/F,EAAO,SAAWwoB,EAC7B5O,GAAM5T,GAAIhG,EAAO,SAAWwoB,EAC5BrB,EACL,KAAK,KAAKphB,EAAI,GAAK/F,EAAO,SAAUyoB,EAAU,EAAID,EAC7CpB,GACL,KAAK,KAAKphB,GAAI,GAAKhG,EAAO,SAAU0oB,CAAW,EAAIF,EACpDM,GAAS,KAAK,CACb,IAAKlF,GAAU5jB,EAAQ2jB,EAAM5d,EAAGC,EAAC,EACjC,OAAQ,CAAC2T,GAAMC,GAAKuN,EAAOC,EAAM,CAAA,CACjC,CACF,CAGD,OAAK,QAAQ,WACZ0B,GAAS,IAAI,MAAOhlB,IAAS,CAC5B,MAAMilB,EAAgB,CAAC,CAAClE,EAClB7gB,GAAW,MAAM,MAAMF,GAAK,IAAK,CACtC,QAASilB,EAAgB,CAAE,cAAelE,GAAc,MAAA,CACxD,EACD,GAAI,CAAC7gB,GAAS,GACb,MAAM,IAAI,MAAM,QAAQA,GAAS,MAAM,EAAE,EAE1C,MAAME,GAAS,MAAM,kBAAkB,MAAMF,GAAS,MAAM,EAC5D,MAAO,CAAE,KAAAF,GAAM,OAAAI,EAAA,CAChB,CAAC,CAAA,EACA,KAAM8kB,IAAY,CACnB,GAAIT,EAAW,CACd,UAAW1G,MAAUmH,GAChBnH,GAAO,SAAW,aACrBA,GAAO,MAAM,OAAO,MAAA,EAGtB,MACD,CAEA,MAAMpf,EAAK+d,EAAQ,MAAQ,KAAK,IAAI,EAAGxgB,EAAO,KAAK,EAC7C0C,GAAK8d,EAAQ,OAAS,KAAK,IAAI,EAAGxgB,EAAO,MAAM,EACrD,UAAW6hB,MAAUmH,GAAS,CAC7B,GAAInH,GAAO,SAAW,YAAa,SACnC,KAAM,CACL,KAAM,CAAE,OAAAlW,CAAA,EACR,OAAAzH,EAAA,EACG2d,GAAO,MACLjgB,GAAK+J,EAAO,CAAC,EAAIlJ,EACjBZ,GAAK8J,EAAO,CAAC,EAAIjJ,GACjBumB,GAAK,KAAK,IAAI,GAAItd,EAAO,CAAC,EAAIA,EAAO,CAAC,GAAKlJ,CAAE,EAC7CymB,GAAK,KAAK,IAAI,GAAIvd,EAAO,CAAC,EAAIA,EAAO,CAAC,GAAKjJ,EAAE,EACnD4Q,GAAI,UAAUpP,GAAQtC,GAAIC,GAAIonB,GAAIC,EAAE,EACpChlB,GAAO,MAAA,CACR,CAEA4gB,EAAa,QAAUtE,EACvBQ,EAAA,CACD,CAAC,EAEM,IAAM,CACZuH,EAAY,EACb,CACD,EAAG,CACFvoB,EACA6kB,EACAK,EACAU,EACAM,GACAP,EACA3E,CAAA,CACA,EAEDwB,EAAAA,UAAU,IAAM,CACfxB,EAAA,CACD,EAAG,CAACA,CAAW,CAAC,EAEhBwB,EAAAA,UAAU,IAAM,CACf,GAAKhF,EACL,OAAAA,EAAc,QAAUwD,EACjB,IAAM,CACRxD,EAAc,UAAYwD,IAC7BxD,EAAc,QAAU,KAE1B,CACD,EAAG,CAACA,EAAewD,CAAW,CAAC,EAE/BwB,EAAAA,UACC,IAAM,IAAM,CACXwC,EAAY,QAAU,CAAE,OAAQ,GAAO,UAAW,IAAA,EAC9CC,EAAO,UAAY,OACtB,qBAAqBA,EAAO,OAAO,EACnCA,EAAO,QAAU,MAElBrH,EAAe,QAAU,EAC1B,EACA,CAAA,CAAC,EAIDuL,GAAAA,KAAC,MAAA,CAAI,UAAA1L,EAAsB,MAAOsB,EACjC,SAAA,CAAA4D,GAAAA,IAAC,SAAA,CACA,IAAKjF,EACL,MAAO,CACN,MAAO,OACP,OAAQ,OACR,QAAS,QACT,aAAc,SAAA,EAEf,cAAeuE,GACf,cAAeC,GACf,YAAaG,GACb,gBAAiBA,GACjB,cAAgBjB,GAAU,CACzBA,EAAM,eAAA,CACP,EACA,QAAUA,GAAU,CACnBA,EAAM,eAAA,EACNA,EAAM,gBAAA,CACP,CAAA,CAAA,EAEAgF,IACAzD,GAAAA,IAAC,SAAA,CACA,KAAK,SACL,aAAW,oBACX,QAAUvB,GAAU,CACnBA,EAAM,gBAAA,EACNgF,GAAA,CACD,EACA,MAAOE,EACJ,CAAC,GAAGA,GACJ,CAAE,GAAG3B,EAAA,EAGP,SAAA0B,GAAa,GAAA,CAAA,CACf,EAEF,CAEF,CCzrBO,SAAS+C,GAAiB,CAChC,WAAArW,EACA,YAAAC,EACA,MAAArP,EACA,UAAAI,EACA,UAAA0Z,EACA,MAAA5J,CACD,EAA8C,CAC7C,MAAM6J,EAAYC,EAAAA,OAAiC,IAAI,EACjD0L,EAAc1L,EAAAA,OAA8B,IAAI,EAChDoB,EAAcb,EAAAA,QACnB,KAAO,CAAE,MAAO,OAAQ,OAAQ,OAAQ,QAAS,QAAS,GAAGrK,IAC7D,CAACA,CAAK,CAAA,EAGP2O,OAAAA,EAAAA,UAAU,IAAM,CACf,MAAM3hB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EACJ,OAGD,MAAMyoB,EAAW,IAAInmB,GAAe,CACnC,OAAAtC,EACA,WAAAkS,EACA,YAAAC,EACA,iBAAkBjP,CAAA,CAClB,EAED,OAAAslB,EAAY,QAAUC,EACjBA,EAAS,SAAS3lB,CAAK,EAErB,IAAM,CACZ2lB,EAAS,QAAA,EACTD,EAAY,QAAU,IACvB,CACD,EAAG,CAACtW,EAAYC,CAAW,CAAC,EAE5BwP,EAAAA,UAAU,IAAM,CACf,MAAM8G,EAAWD,EAAY,QACxBC,GAIAA,EAAS,SAAS3lB,CAAK,CAC7B,EAAG,CAACA,CAAK,CAAC,EAEV6e,EAAAA,UAAU,IAAM,CACf,MAAM8G,EAAWD,EAAY,QACzB,CAACC,GAAY,CAACvlB,GAIlBulB,EAAS,aAAavlB,CAAS,CAChC,EAAG,CAACA,CAAS,CAAC,SAEN,SAAA,CAAO,IAAK2Z,EAAW,UAAAD,EAAsB,MAAOsB,EAAa,CAC1E,CC/DO,SAASwK,GAA0BjgB,EAA4CjB,EAAgE,CACpJ,GAAI,CAACiB,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,OAAO,KAGT,MAAM3B,EAAWF,GAAmBY,GAAY,EAAE,EAClD,GAAIV,EAAS,SAAW,EAAG,CACzB,MAAM6hB,EAAsB,CAC1B,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAEnC,OAAIlgB,EAAU,qBAAqB,aACjCkgB,EAAM,UAAY,IAAI,WAAW,CAAC,GAEhClgB,EAAU,eAAe,cAC3BkgB,EAAM,IAAM,IAAI,YAAY,CAAC,GAExBA,CACT,CAEA,MAAMC,EAAQpgB,GAAmBC,CAAS,EACpCogB,EAAYpgB,EAAU,UACtBW,EAAQX,EAAU,eAClBqgB,EAAYrgB,EAAU,qBAAqB,YAAcA,EAAU,UAAU,QAAUmgB,EAAQngB,EAAU,UAAY,KACrHsgB,EAAWtgB,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUmgB,EAAQngB,EAAU,IAAM,KAEnGugB,EAAgB,IAAI,aAAaJ,EAAQ,CAAC,EAC1CK,EAAY,IAAI,YAAYL,CAAK,EACjCM,EAAgBJ,EAAY,IAAI,WAAWF,CAAK,EAAI,KACpDO,EAAUJ,EAAW,IAAI,YAAYH,CAAK,EAAI,KACpD,IAAI9S,EAAS,EAEb,QAASrQ,EAAI,EAAGA,EAAImjB,EAAOnjB,GAAK,EAAG,CACjC,MAAMP,EAAI2jB,EAAUpjB,EAAI,CAAC,EACnBN,EAAI0jB,EAAUpjB,EAAI,EAAI,CAAC,EACxB8B,GAA0BrC,EAAGC,EAAG2B,CAAQ,IAC7CkiB,EAAclT,EAAS,CAAC,EAAI5Q,EAC5B8jB,EAAclT,EAAS,EAAI,CAAC,EAAI3Q,EAChC8jB,EAAUnT,CAAM,EAAI1M,EAAM3D,CAAC,EACvByjB,IACFA,EAAcpT,CAAM,EAAIgT,EAAWrjB,CAAC,GAElC0jB,IACFA,EAAQrT,CAAM,EAAIiT,EAAUtjB,CAAC,GAE/BqQ,GAAU,EACZ,CAEA,MAAMsT,EAAuB,CAC3B,MAAOtT,EACP,UAAWkT,EAAc,SAAS,EAAGlT,EAAS,CAAC,EAC/C,eAAgBmT,EAAU,SAAS,EAAGnT,CAAM,CAAA,EAE9C,OAAIoT,IACFE,EAAO,UAAYF,EAAc,SAAS,EAAGpT,CAAM,GAEjDqT,IACFC,EAAO,IAAMD,EAAQ,SAAS,EAAGrT,CAAM,GAElCsT,CACT,CAEO,SAASC,GAA6B5gB,EAA4CjB,EAAwD,CAC/I,GAAI,CAACiB,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,OAAO,IAAI,YAAY,CAAC,EAG1B,MAAM3B,EAAWF,GAAmBY,GAAY,EAAE,EAClD,GAAIV,EAAS,SAAW,EACtB,OAAO,IAAI,YAAY,CAAC,EAG1B,MAAM8hB,EAAQpgB,GAAmBC,CAAS,EAC1C,GAAImgB,IAAU,EACZ,OAAO,IAAI,YAAY,CAAC,EAG1B,MAAMC,EAAYpgB,EAAU,UACtBxD,EAAM,IAAI,YAAY2jB,CAAK,EACjC,IAAI9S,EAAS,EAEb,QAASrQ,EAAI,EAAGA,EAAImjB,EAAOnjB,GAAK,EAAG,CACjC,MAAMP,EAAI2jB,EAAUpjB,EAAI,CAAC,EACnBN,EAAI0jB,EAAUpjB,EAAI,EAAI,CAAC,EACxB8B,GAA0BrC,EAAGC,EAAG2B,CAAQ,IAC7C7B,EAAI6Q,CAAM,EAAIrQ,EACdqQ,GAAU,EACZ,CAEA,OAAO7Q,EAAI,SAAS,EAAG6Q,CAAM,CAC/B,CCJA,IAAIwT,GAAuD,KAE3D,MAAMC,GAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiC9B,SAASC,IAAqB,CAC7B,GAAI,OAAO,UAAc,IAAa,MAAO,GAC7C,MAAMC,EAAM,UACZ,OAAO,OAAOA,EAAI,KAAQ,UAAYA,EAAI,MAAQ,IACnD,CAEA,SAASC,IAA2C,CACnD,GAAI,CAACF,GAAA,EAAa,OAAO,KAEzB,MAAMG,EADM,UACI,IAChB,GAAI,CAACA,GAAO,OAAOA,GAAQ,SAAU,OAAO,KAC5C,MAAMtc,EAAYsc,EAClB,OAAI,OAAOtc,EAAU,gBAAmB,WAAmB,KACpDA,CACR,CAEA,MAAMuc,GACJ,WAAyD,gBACvD,SAAW,EACTC,GACJ,WAAyD,gBACvD,SAAW,IACTC,GACJ,WAA0D,gBACxD,UAAY,EACVC,GACJ,WAA0D,gBACxD,UAAY,EACVC,GACJ,WAAyD,gBACvD,SAAW,GACTC,GACJ,WAA0D,gBACxD,UAAY,EACVC,GACJ,WAAkD,YAAY,MAAQ,EAExE,eAAsBC,IAAqD,CAC1E,MAAMC,EAASV,GAAA,EACf,GAAI,CAACU,EACJ,MAAO,CAAE,UAAW,GAAO,SAAU,CAAA,CAAC,EAEvC,MAAMC,EAAU,MAAMD,EAAO,eAAA,EAC7B,OAAKC,EAIE,CACN,UAAW,GACX,YAAaA,EAAQ,MAAM,aAAeA,EAAQ,MAAM,QAAU,UAClE,SAAU,MAAM,KAAKA,EAAQ,QAAQ,EACrC,OAAQ,CACP,4BAA6B,OAC5BA,EAAQ,OAAO,2BAAA,EAEhB,kCAAmC,OAClCA,EAAQ,OAAO,iCAAA,EAEhB,yBAA0B,OAAOA,EAAQ,OAAO,wBAAwB,CAAA,CACzE,EAfO,CAAE,UAAW,GAAO,SAAU,CAAA,CAAC,CAiBxC,CAEA,eAAeC,IAA4C,CAC1D,OAAIhB,KACJA,IAAkB,SAAY,CAC7B,MAAMc,EAASV,GAAA,EACf,GAAI,CAACU,EAAQ,OAAO,KACpB,MAAMC,EAAU,MAAMD,EAAO,eAAA,EAC7B,GAAI,CAACC,EAAS,OAAO,KACrB,MAAME,EAAS,MAAMF,EAAQ,cAAA,EAEvBG,EAAkBD,EAAO,sBAAsB,CACpD,QAAS,CACR,CACC,QAAS,EACT,WAAYX,GACZ,OAAQ,CAAE,KAAM,mBAAA,CAAoB,EAErC,CACC,QAAS,EACT,WAAYA,GACZ,OAAQ,CAAE,KAAM,mBAAA,CAAoB,EAErC,CACC,QAAS,EACT,WAAYA,GACZ,OAAQ,CAAE,KAAM,SAAA,CAAU,EAE3B,CACC,QAAS,EACT,WAAYA,GACZ,OAAQ,CAAE,KAAM,SAAA,CAAU,CAC3B,CACD,CACA,EAEKa,EAAWF,EAAO,sBAAsB,CAC7C,OAAQA,EAAO,qBAAqB,CAAE,iBAAkB,CAACC,CAAe,EAAG,EAC3E,QAAS,CACR,OAAQD,EAAO,mBAAmB,CAAE,KAAMhB,GAAuB,EACjE,WAAY,MAAA,CACb,CACA,EAED,MAAO,CAAE,OAAAgB,EAAQ,SAAAE,EAAU,gBAAAD,CAAA,CAC5B,GAAA,EAEOlB,GACR,CAEA,SAASoB,GAAMnmB,EAAe6G,EAAsB,CACnD,OAAO,KAAK,KAAK7G,EAAQ6G,CAAI,EAAIA,CAClC,CAEA,eAAsBuf,GACrB9B,EACA+B,EACA9f,EAC8B,CAC9B,MAAM2H,EAAM,MAAM6X,GAAA,EAClB,GAAI,CAAC7X,EAAK,OAAO,KAEjB,MAAMmW,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMgC,CAAU,CAAC,EAC1CC,EAAc,KAAK,IAAI,EAAG,KAAK,MAAM/f,EAAO,OAAS,CAAC,CAAC,EAC7D,GAAI8d,IAAU,GAAKiC,IAAgB,EAClC,OAAO,IAAI,YAAY,CAAC,EAGzB,MAAMC,EAAiB,KAAK,IAAIlC,EAAO,KAAK,MAAMC,EAAU,OAAS,CAAC,CAAC,EACvE,GAAIiC,IAAmB,EACtB,OAAO,IAAI,YAAY,CAAC,EAGzB,MAAMC,EAAgBD,EAAiB,EAAI,aAAa,kBAClDE,EAAcH,EAAc,EAAI,aAAa,kBAC7CI,EAAcH,EAAiB,YAAY,kBAE3CI,EAAQ,OAAOzY,EAAI,OAAO,OAAO,2BAA2B,EAClE,GAAIsY,EAAgBG,GAASF,EAAcE,GAASD,EAAcC,EACjE,OAAO,KAGR,MAAMC,EAAkB1Y,EAAI,OAAO,aAAa,CAC/C,KAAMiY,GAAMK,EAAe,CAAC,EAC5B,MAAOlB,GAA2BC,EAAA,CAClC,EACKsB,EAAe3Y,EAAI,OAAO,aAAa,CAC5C,KAAMiY,GAAMM,EAAa,CAAC,EAC1B,MAAOnB,GAA2BC,EAAA,CAClC,EACKuB,EAAe5Y,EAAI,OAAO,aAAa,CAC5C,KAAMiY,GAAMO,EAAa,CAAC,EAC1B,MAAOpB,GAA2BE,EAAA,CAClC,EACKuB,EAAgB7Y,EAAI,OAAO,aAAa,CAC7C,KAAM,GACN,MAAOuX,GAA2BF,EAAA,CAClC,EACKyB,EAAa9Y,EAAI,OAAO,aAAa,CAC1C,KAAMiY,GAAMO,EAAa,CAAC,EAC1B,MAAOnB,GAA4BG,EAAA,CACnC,EAEDxX,EAAI,OAAO,MAAM,YAChB0Y,EACA,EACAtC,EAAU,OACVA,EAAU,WACVkC,CAAA,EAEDtY,EAAI,OAAO,MAAM,YAChB2Y,EACA,EACAtgB,EAAO,OACPA,EAAO,WACPkgB,CAAA,EAEDvY,EAAI,OAAO,MAAM,YAChB6Y,EACA,EACA,IAAI,YAAY,CAACR,EAAgBD,EAAa,EAAG,CAAC,CAAC,CAAA,EAGpD,MAAMW,EAAY/Y,EAAI,OAAO,gBAAgB,CAC5C,OAAQA,EAAI,gBACZ,QAAS,CACR,CAAE,QAAS,EAAG,SAAU,CAAE,OAAQ0Y,EAAgB,EAClD,CAAE,QAAS,EAAG,SAAU,CAAE,OAAQC,EAAa,EAC/C,CAAE,QAAS,EAAG,SAAU,CAAE,OAAQC,EAAa,EAC/C,CAAE,QAAS,EAAG,SAAU,CAAE,OAAQC,EAAc,CAAE,CACnD,CACA,EAEKG,EAAiBhZ,EAAI,OAAO,qBAAA,EAC5BxD,EAAOwc,EAAe,iBAAA,EAC5Bxc,EAAK,YAAYwD,EAAI,QAAQ,EAC7BxD,EAAK,aAAa,EAAGuc,CAAS,EAC9Bvc,EAAK,mBAAmB,KAAK,KAAK6b,EAAiB,GAAG,CAAC,EACvD7b,EAAK,IAAA,EAELwc,EAAe,mBAAmBJ,EAAc,EAAGE,EAAY,EAAGN,CAAW,EAC7ExY,EAAI,OAAO,MAAM,OAAO,CAACgZ,EAAe,OAAA,CAAQ,CAAC,EAEjD,MAAMF,EAAW,SAASrB,EAAiB,EAC3C,MAAMwB,EAASH,EAAW,eAAA,EACpBtmB,EAAM,IAAI,YAAYymB,EAAO,MAAM,CAAC,CAAC,EAC3C,OAAAH,EAAW,MAAA,EAEXJ,EAAgB,QAAA,EAChBC,EAAa,QAAA,EACbC,EAAa,QAAA,EACbC,EAAc,QAAA,EACdC,EAAW,QAAA,EAEJtmB,CACR,CCjUA,eAAsB0mB,GACpBljB,EACAjB,EACAjF,EAAkC,CAAA,EACF,CAChC,MAAMgM,EAAQhG,GAAA,EACRqjB,EAAerpB,EAAQ,eAAiB,GAC9C,GAAI,CAACkG,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,MAAO,CACL,KAAM,KACN,KAAM,CACJ,KAAM,gBACN,WAAYF,KAAUgG,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,EAIJ,MAAMzH,EAAWF,GAAmBY,GAAY,EAAE,EAClD,GAAIV,EAAS,SAAW,EAAG,CACzB,MAAM+kB,EAAqB,CACzB,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAEnC,OAAIpjB,EAAU,qBAAqB,aACjCojB,EAAK,UAAY,IAAI,WAAW,CAAC,GAE/BpjB,EAAU,eAAe,cAC3BojB,EAAK,IAAM,IAAI,YAAY,CAAC,GAEvB,CACL,KAAAA,EACA,KAAM,CACJ,KAAM,gBACN,WAAYtjB,KAAUgG,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMud,EAAYtjB,GAAmBC,CAAS,EACxCsjB,EAAiBtjB,EAAU,qBAAqB,YAAcA,EAAU,UAAU,QAAUqjB,EAAYrjB,EAAU,UAAY,KAC9HsgB,EAAWtgB,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUqjB,EAAYrjB,EAAU,IAAM,KAC7G,GAAIqjB,IAAc,EAAG,CACnB,MAAMD,EAAqB,CACzB,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAEnC,OAAIE,IACFF,EAAK,UAAY,IAAI,WAAW,CAAC,GAE/B9C,IACF8C,EAAK,IAAM,IAAI,YAAY,CAAC,GAEvB,CACL,KAAAA,EACA,KAAM,CACJ,KAAM,gBACN,WAAYtjB,KAAUgG,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMyd,EAAW,IAAI,aAAallB,EAAS,OAAS,CAAC,EACrD,QAASrB,EAAI,EAAGA,EAAIqB,EAAS,OAAQrB,GAAK,EAAG,CAC3C,MAAM6N,EAAO7N,EAAI,EACXX,EAAUgC,EAASrB,CAAC,EAC1BumB,EAAS1Y,CAAI,EAAIxO,EAAQ,KACzBknB,EAAS1Y,EAAO,CAAC,EAAIxO,EAAQ,KAC7BknB,EAAS1Y,EAAO,CAAC,EAAIxO,EAAQ,KAC7BknB,EAAS1Y,EAAO,CAAC,EAAIxO,EAAQ,IAC/B,CAEA,IAAImnB,EAAoC,KACpCC,EAAa,GACjB,GAAI,CACFD,EAAgB,MAAMtB,GAA8BliB,EAAU,UAAWqjB,EAAWE,CAAQ,EAC5FE,EAAa,CAAC,CAACD,CACjB,MAAQ,CACNA,EAAgB,KAChBC,EAAa,EACf,CAEA,GAAI,CAACD,EAEH,MAAO,CACL,KAFevD,GAA0BjgB,EAAWjB,CAAQ,EAG5D,KAAM,CACJ,KAAM,gBACN,WAAYe,KAAUgG,EACtB,WAAY,GACZ,eAAgBud,EAChB,cAAe,EAAA,CACjB,EAIJ,IAAIK,EAAiB,EACrB,QAAS1mB,EAAI,EAAGA,EAAIqmB,EAAWrmB,GAAK,EAC9BwmB,EAAcxmB,CAAC,IAAM,IAAG0mB,GAAkB,GAGhD,MAAMC,EAAmB,IAAI,YAAYD,CAAc,EACvD,GAAIA,EAAiB,EAAG,CACtB,IAAIE,EAAkB,EACtB,QAAS5mB,EAAI,EAAGA,EAAIqmB,EAAWrmB,GAAK,EAC9BwmB,EAAcxmB,CAAC,IAAM,IACzB2mB,EAAiBC,CAAe,EAAI5mB,EACpC4mB,GAAmB,EAEvB,CAEA,GAAIF,IAAmB,EAAG,CACxB,GAAIP,EAAc,CAChB,MAAMC,EAAqB,CACzB,MAAOC,EACP,UAAWrjB,EAAU,UAAU,SAAS,EAAGqjB,EAAY,CAAC,EACxD,eAAgBrjB,EAAU,eAAe,SAAS,EAAGqjB,CAAS,EAC9D,YAAa,IAAI,YAAY,CAAC,CAAA,EAEhC,OAAIC,IACFF,EAAK,UAAYE,EAAe,SAAS,EAAGD,CAAS,GAEnD/C,IACF8C,EAAK,IAAM9C,EAAS,SAAS,EAAG+C,CAAS,GAEpC,CACL,KAAAD,EACA,KAAM,CACJ,KAAM,gBACN,WAAYtjB,KAAUgG,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMsd,EAAqB,CACzB,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAEnC,OAAIE,IACFF,EAAK,UAAY,IAAI,WAAW,CAAC,GAE/B9C,IACF8C,EAAK,IAAM,IAAI,YAAY,CAAC,GAEvB,CACL,KAAAA,EACA,KAAM,CACJ,KAAM,gBACN,WAAYtjB,KAAUgG,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,GAAIqd,EAAc,CAChB,MAAMU,EAAc,IAAI,YAAYH,CAAc,EAClD,IAAII,EAAe,EAEnB,QAAS9mB,GAAI,EAAGA,GAAI0mB,EAAgB1mB,IAAK,EAAG,CAC1C,MAAM+mB,EAAaJ,EAAiB3mB,EAAC,GAAK,EACpCP,GAAIuD,EAAU,UAAU+jB,EAAa,CAAC,EACtCrnB,GAAIsD,EAAU,UAAU+jB,EAAa,EAAI,CAAC,EAC3CjlB,GAA0BrC,GAAGC,GAAG2B,CAAQ,IAC7CwlB,EAAYC,CAAY,EAAIC,EAC5BD,GAAgB,EAClB,CAEA,MAAMV,EAAqB,CACzB,MAAOC,EACP,UAAWrjB,EAAU,UAAU,SAAS,EAAGqjB,EAAY,CAAC,EACxD,eAAgBrjB,EAAU,eAAe,SAAS,EAAGqjB,CAAS,EAC9D,YAAaQ,EAAY,SAAS,EAAGC,CAAY,CAAA,EAEnD,OAAIR,IACFF,EAAK,UAAYE,EAAe,SAAS,EAAGD,CAAS,GAEnD/C,IACF8C,EAAK,IAAM9C,EAAS,SAAS,EAAG+C,CAAS,GAGpC,CACL,KAAAD,EACA,KAAM,CACJ,KAAM,gBACN,WAAYtjB,KAAUgG,EACtB,WAAY,GACZ,eAAA4d,EACA,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMnD,EAAgB,IAAI,aAAamD,EAAiB,CAAC,EACnDlD,EAAY,IAAI,YAAYkD,CAAc,EAC1CjD,EAAgB6C,EAAiB,IAAI,WAAWI,CAAc,EAAI,KAClEhD,EAAUJ,EAAW,IAAI,YAAYoD,CAAc,EAAI,KAC7D,IAAIrW,EAAS,EAEb,QAASrQ,EAAI,EAAGA,EAAI0mB,EAAgB1mB,GAAK,EAAG,CAC1C,MAAM+mB,EAAaJ,EAAiB3mB,CAAC,GAAK,EACpCP,EAAIuD,EAAU,UAAU+jB,EAAa,CAAC,EACtCrnB,GAAIsD,EAAU,UAAU+jB,EAAa,EAAI,CAAC,EAC3CjlB,GAA0BrC,EAAGC,GAAG2B,CAAQ,IAC7CkiB,EAAclT,EAAS,CAAC,EAAI5Q,EAC5B8jB,EAAclT,EAAS,EAAI,CAAC,EAAI3Q,GAChC8jB,EAAUnT,CAAM,EAAIrN,EAAU,eAAe+jB,CAAU,EACnDtD,IACFA,EAAcpT,CAAM,EAAIiW,EAAgBS,CAAU,GAEhDrD,IACFA,EAAQrT,CAAM,EAAIiT,EAAUyD,CAAU,GAExC1W,GAAU,EACZ,CAEA,MAAM2W,EAA4B,CAChC,MAAO3W,EACP,UAAWkT,EAAc,SAAS,EAAGlT,EAAS,CAAC,EAC/C,eAAgBmT,EAAU,SAAS,EAAGnT,CAAM,CAAA,EAE9C,OAAIoT,IACFuD,EAAY,UAAYvD,EAAc,SAAS,EAAGpT,CAAM,GAEtDqT,IACFsD,EAAY,IAAMtD,EAAQ,SAAS,EAAGrT,CAAM,GAGvC,CACL,KAAM2W,EACN,KAAM,CACJ,KAAM,gBACN,WAAYlkB,KAAUgG,EACtB,WAAY,GACZ,eAAA4d,EACA,cAAe,EAAA,CACjB,CAEJ,CChRO,MAAMO,EAAkD,CAoB7D,YACmBC,EACAC,EACjB,CAtBMvsB,EAAA,cAAwB,MACxBA,EAAA,iBAAY,IACZA,EAAA,iBAAY,GACHA,EAAA,uBAAkB,KAElBA,EAAA,qBAAiBkgB,GAAmC,CACnE,MAAMsM,EAAUtM,EAAM,KACtB,GAAI,CAACsM,EAAS,OACd,MAAMC,EAAU,KAAK,YAAY,IAAID,EAAQ,EAAE,EAC1CC,IACL,KAAK,YAAY,OAAOD,EAAQ,EAAE,EAClC,KAAK,SAAS,WAAWA,EAASC,CAAO,EAC3C,GAEiBzsB,EAAA,mBAAc,IAAY,CACzC,KAAK,UAAY,GACjB,KAAK,eAAe,gBAAgB,CACtC,GAGmB,KAAA,aAAAssB,EACA,KAAA,SAAAC,CAChB,CAEH,aAAaE,EAAyD,CACpE,MAAMC,EAAS,KAAK,kBAAA,EACpB,GAAI,CAACA,EAAQ,OAAO,KACpB,MAAMtf,EAAK,KAAK,YAChB,YAAK,YAAY,IAAIA,EAAIqf,CAAO,EACzB,CAAE,GAAArf,EAAI,OAAAsf,CAAA,CACf,CAEA,cAActf,EAAiC,CAC7C,MAAMqf,EAAU,KAAK,YAAY,IAAIrf,CAAE,EACvC,GAAKqf,EACL,YAAK,YAAY,OAAOrf,CAAE,EACnBqf,CACT,CAEA,UAAUE,EAAS,oBAA2B,CAC5C,KAAK,eAAeA,CAAM,CAC5B,CAEQ,mBAAmC,CACzC,GAAI,CAAC,KAAK,UAAW,OAAO,KAC5B,GAAI,KAAK,OAAQ,OAAO,KAAK,OAE7B,GAAI,CACF,MAAMD,EAAS,KAAK,aAAA,EACpB,OAAAA,EAAO,iBAAiB,UAAW,KAAK,aAAa,EACrDA,EAAO,iBAAiB,QAAS,KAAK,WAAW,EACjD,KAAK,OAASA,EACPA,CACT,MAAQ,CACN,YAAK,UAAY,GACV,IACT,CACF,CAEQ,eAAeC,EAAsB,CACvC,KAAK,SACP,KAAK,OAAO,oBAAoB,UAAW,KAAK,aAAa,EAC7D,KAAK,OAAO,oBAAoB,QAAS,KAAK,WAAW,EACzD,KAAK,OAAO,UAAA,EACZ,KAAK,OAAS,MAGhB,MAAMzpB,EAAQ,IAAI,MAAMypB,CAAM,EAC9B,SAAW,CAAA,CAAGF,CAAO,IAAK,KAAK,YAC7B,KAAK,SAAS,cAAcA,EAASvpB,CAAK,EAE5C,KAAK,YAAY,MAAA,CACnB,CACF,CCxCA,MAAM0pB,GAAe,IAAIP,GACvB,IAAM,IAAI,OAAO,IAAA,IAAA,IAAA,OAAA,SAAA,IAAA,QAAA,KAAA,EAAA,cAAA,UAAA,qCAAA,EAAA,KAAA,IAAA,IAAA,qCAAA,SAAA,eAAA,SAAA,cAAA,QAAA,YAAA,IAAA,UAAA,SAAA,cAAA,KAAA,SAAA,OAAA,EAAA,MAAA,OAAA,SAAA,IAAA,QAAA,KAAA,EAAA,cAAA,UAAA,EAAA,KAAAQ,IAAAA,GAAA,QAAA,YAAA,IAAA,UAAAA,GAAA,KAAA,IAAA,IAAA,YAAA,SAAA,OAAA,EAAA,IAAA,EAA2D,CAAE,KAAM,SAAU,EAC9F,CACE,WAAY,CAACC,EAAKL,IAAY,CAC5B,GAAIK,EAAI,OAAS,mBAAoB,CACnCL,EAAQ,OAAO,IAAI,MAAMK,EAAI,OAAS,oBAAoB,CAAC,EAC3D,MACF,CAEA,GAAIA,EAAI,OAAS,yBAA0B,CACzC,GAAIL,EAAQ,OAAS,QAAS,CAC5BA,EAAQ,OAAO,IAAI,MAAM,sDAAsD,CAAC,EAChF,MACF,CACA,MAAMlE,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMuE,EAAI,KAAK,CAAC,EACzCC,EAAU,IAAI,YAAYD,EAAI,OAAO,EAAE,SAAS,EAAGvE,CAAK,EAC9DkE,EAAQ,QAAQ,CACd,QAAAM,EACA,KAAM,CACJ,KAAM,SACN,WACE,OAAO,SAASD,EAAI,UAAU,EAC1BA,EAAI,WACJ5kB,GAAA,EAAUukB,EAAQ,OAAA,CAC1B,CACD,EACD,MACF,CAEA,GAAIA,EAAQ,OAAS,OAAQ,CAC3BA,EAAQ,OAAO,IAAI,MAAM,iDAAiD,CAAC,EAC3E,MACF,CAEA,MAAMlE,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMuE,EAAI,KAAK,CAAC,EACzCtE,EAAY,IAAI,aAAasE,EAAI,SAAS,EAC1CE,EAAiB,IAAI,YAAYF,EAAI,cAAc,EACnDrE,EAAYqE,EAAI,UAAY,IAAI,WAAWA,EAAI,SAAS,EAAI,KAC5DG,EAAMH,EAAI,IAAM,IAAI,YAAYA,EAAI,GAAG,EAAI,KAC3C/D,EAAuB,CAC3B,MAAAR,EACA,UAAWC,EAAU,SAAS,EAAGD,EAAQ,CAAC,EAC1C,eAAgByE,EAAe,SAAS,EAAGzE,CAAK,CAAA,EAE9CE,IACFM,EAAO,UAAYN,EAAU,SAAS,EAAGF,CAAK,GAE5C0E,IACFlE,EAAO,IAAMkE,EAAI,SAAS,EAAG1E,CAAK,GAGpCkE,EAAQ,QAAQ,CACd,KAAM1D,EACN,KAAM,CACJ,KAAM,SACN,WACE,OAAO,SAAS+D,EAAI,UAAU,EAC1BA,EAAI,WACJ5kB,GAAA,EAAUukB,EAAQ,OAAA,CAC1B,CACD,CACH,EACA,cAAe,CAACA,EAASvpB,IAAU,CACjCupB,EAAQ,OAAOvpB,CAAK,CACtB,CAAA,CAEJ,EAEO,SAASgqB,IAA+B,CAC7CN,GAAa,UAAU,mBAAmB,CAC5C,CAEA,eAAsBO,GAAkC/kB,EAA4CjB,EAAqE,CACvK,GAAI,CAACiB,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,MAAO,CACL,KAAM,KACN,KAAM,CAAE,KAAM,SAAU,WAAY,CAAA,CAAE,EAI1C,MAAMqjB,EAAYtjB,GAAmBC,CAAS,EACxCglB,EAAgBhlB,EAAU,UAAU,MAAM,EAAGqjB,EAAY,CAAC,EAC1D4B,EAAYjlB,EAAU,eAAe,MAAM,EAAGqjB,CAAS,EACvD6B,EAAgBllB,EAAU,qBAAqB,YAAcA,EAAU,UAAU,QAAUqjB,EAAYrjB,EAAU,UAAU,MAAM,EAAGqjB,CAAS,EAAI,KACjJ8B,EAAUnlB,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUqjB,EAAYrjB,EAAU,IAAI,MAAM,EAAGqjB,CAAS,EAAI,KAEhI,OAAO,IAAI,QAAyB,CAAC+B,EAASC,IAAW,CACvD,MAAMC,EAAUxlB,GAAA,EACVylB,EAAgBf,GAAa,aAAa,CAC9C,KAAM,OACN,QAAAY,EACA,OAAAC,EACA,QAAAC,CAAA,CACD,EAED,GAAI,CAACC,EAAe,CAClBH,EAAQ,CACN,KAAMnF,GAA0BjgB,EAAWjB,CAAQ,EACnD,KAAM,CAAE,KAAM,OAAQ,WAAYe,GAAA,EAAUwlB,CAAA,CAAQ,CACrD,EACD,MACF,CAEA,MAAMZ,EAA4B,CAChC,KAAM,mBACN,GAAIa,EAAc,GAClB,MAAOlC,EACP,UAAW2B,EAAc,OACzB,eAAgBC,EAAU,OAC1B,UAAWC,GAAe,OAC1B,IAAKC,GAAS,OACd,SAAUpmB,GAAY,CAAA,CAAC,EAGnBymB,EAA2B,CAACR,EAAc,OAAQC,EAAU,MAAM,EACpEC,GAAeM,EAAS,KAAKN,EAAc,MAAM,EACjDC,GAASK,EAAS,KAAKL,EAAQ,MAAM,EAEzC,GAAI,CACFI,EAAc,OAAO,YAAYb,EAAKc,CAAQ,CAChD,OAAS1qB,EAAO,CACd,MAAM2qB,EAAWjB,GAAa,cAAce,EAAc,EAAE,EACxDE,EACFA,EAAS,OAAO3qB,CAAK,EAErBuqB,EAAOvqB,CAAK,CAEhB,CACF,CAAC,CACH,CAEA,eAAsB4qB,GAAqC1lB,EAA4CjB,EAA0E,CAC/K,GAAI,CAACiB,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,MAAO,CACL,QAAS,IAAI,YAAY,CAAC,EAC1B,KAAM,CAAE,KAAM,SAAU,WAAY,CAAA,CAAE,EAI1C,MAAMqjB,EAAYtjB,GAAmBC,CAAS,EACxCglB,EAAgBhlB,EAAU,UAAU,MAAM,EAAGqjB,EAAY,CAAC,EAEhE,OAAO,IAAI,QAA8B,CAAC+B,EAASC,IAAW,CAC5D,MAAMC,EAAUxlB,GAAA,EACVylB,EAAgBf,GAAa,aAAa,CAC9C,KAAM,QACN,QAAAY,EACA,OAAAC,EACA,QAAAC,CAAA,CACD,EAED,GAAI,CAACC,EAAe,CAClBH,EAAQ,CACN,QAASxE,GAA6B5gB,EAAWjB,CAAQ,EACzD,KAAM,CAAE,KAAM,OAAQ,WAAYe,GAAA,EAAUwlB,CAAA,CAAQ,CACrD,EACD,MACF,CAEA,MAAMZ,EAA4B,CAChC,KAAM,yBACN,GAAIa,EAAc,GAClB,MAAOlC,EACP,UAAW2B,EAAc,OACzB,SAAUjmB,GAAY,CAAA,CAAC,EAGzB,GAAI,CACFwmB,EAAc,OAAO,YAAYb,EAAK,CAACM,EAAc,MAAM,CAAC,CAC9D,OAASlqB,EAAO,CACd,MAAM2qB,EAAWjB,GAAa,cAAce,EAAc,EAAE,EACxDE,EACFA,EAAS,OAAO3qB,CAAK,EAErBuqB,EAAOvqB,CAAK,CAEhB,CACF,CAAC,CACH,CCzNO,MAAM6qB,GAA0B,GAC1BC,GAA0B,KAC1BC,GAA+B,EAC/BC,GAAa,GAsBnB,SAASC,GAASC,EAAeC,EAAe5iB,EAAsB,CAC3E,OAAU2iB,EAAQ,SAAaC,EAAQ,YAAe,EAAK5iB,CAC7D,CAEA,SAAS6iB,GAAgBC,EAAqBC,EAAsBtC,EAA8B,CAChG,GAAIqC,GAAe,GAAKC,GAAgB,GAAKtC,GAAgB,EAAG,MAAO,KACvE,MAAMrmB,EAAO,KAAK,IAAI,EAAG0oB,EAAcC,CAAY,EAE7CvQ,EADa,KAAK,KAAKpY,EAAO,KAAK,IAAI,EAAGqmB,CAAY,CAAC,EACpC+B,GACzB,OAAO,KAAK,IAAIF,GAAyB,KAAK,IAAIC,GAAyB/P,CAAG,CAAC,CACjF,CAEA,SAASwQ,GAAoBxQ,EAAqCwN,EAAuC,CACvG,GAAI,EAAExN,aAAe,cAAgBA,EAAI,SAAW,EAClD,OAAO,KAGT,IAAIyQ,EAAW,GACf,QAAStpB,EAAI,EAAGA,EAAI6Y,EAAI,OAAQ7Y,GAAK,EACnC,GAAI,EAAA6Y,EAAI7Y,CAAC,EAAIqmB,GACb,CAAAiD,EAAW,GACX,MAEF,GAAIA,EACF,OAAOzQ,EAGT,MAAM0Q,EAAW,IAAI,YAAY1Q,EAAI,MAAM,EAC3C,IAAIxI,EAAS,EACb,QAASrQ,EAAI,EAAGA,EAAI6Y,EAAI,OAAQ7Y,GAAK,EAC/B6Y,EAAI7Y,CAAC,GAAKqmB,IACdkD,EAASlZ,CAAM,EAAIwI,EAAI7Y,CAAC,EACxBqQ,GAAU,GAEZ,OAAOA,EAAS,EAAIkZ,EAAS,SAAS,EAAGlZ,CAAM,EAAI,IACrD,CAEO,SAASmZ,GAAmBC,EAAiE,CAClG,MAAMtG,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMsG,EAAM,KAAK,CAAC,EAC3CC,EAAsB,KAAK,MAAMD,EAAM,UAAU,OAAS,CAAC,EAC3DpD,EAAY,KAAK,IAAI,EAAG,KAAK,IAAIlD,EAAOuG,CAAmB,CAAC,EAClE,GAAIrD,GAAa,EACf,OAAO,KAGT,MAAMQ,EAAcwC,GAAoBI,EAAM,aAAe,KAAMpD,CAAS,EACtES,EAAeD,EAAcA,EAAY,OAASR,EACxD,GAAIS,IAAiB,EACnB,OAAO,KAGT,MAAM6C,EAAWT,GAAgBO,EAAM,YAAaA,EAAM,aAAc3C,CAAY,EAC9E8C,EAAc,EAAMD,EAEpBE,EAAa,IAAI,WAAW/C,CAAY,EACxCgD,EAAa,IAAI,WAAWhD,CAAY,EAC9C,IAAIiD,EAAa,EAEjB,GAAIlD,EACF,QAAS7mB,EAAI,EAAGA,EAAI8mB,EAAc9mB,GAAK,EAAG,CACxC,MAAMgqB,EAAKnD,EAAY7mB,CAAC,EAClBwR,EAAKiY,EAAM,UAAUO,EAAK,CAAC,EAC3BvY,EAAKgY,EAAM,UAAUO,EAAK,EAAI,CAAC,EACjC,CAAC,OAAO,SAASxY,CAAE,GAAK,CAAC,OAAO,SAASC,CAAE,IAC/CoY,EAAWE,CAAU,EAAI,KAAK,MAAMvY,EAAKoY,CAAW,EACpDE,EAAWC,CAAU,EAAI,KAAK,MAAMtY,EAAKmY,CAAW,EACpDG,GAAc,EAChB,KAEA,SAAS/pB,EAAI,EAAGA,EAAIqmB,EAAWrmB,GAAK,EAAG,CACrC,MAAMwR,EAAKiY,EAAM,UAAUzpB,EAAI,CAAC,EAC1ByR,EAAKgY,EAAM,UAAUzpB,EAAI,EAAI,CAAC,EAChC,CAAC,OAAO,SAASwR,CAAE,GAAK,CAAC,OAAO,SAASC,CAAE,IAC/CoY,EAAWE,CAAU,EAAI,KAAK,MAAMvY,EAAKoY,CAAW,EACpDE,EAAWC,CAAU,EAAI,KAAK,MAAMtY,EAAKmY,CAAW,EACpDG,GAAc,EAChB,CAGF,GAAIA,IAAe,EACjB,OAAO,KAGT,IAAIE,EAAiB,KAAK,IAAIF,EAAY,KAAK,IAAI,GAAIA,IAAe,CAAC,CAAC,GACpE,CAAC,OAAO,SAASE,CAAc,GAAKA,GAAkB,KACxDA,EAAiBF,GAGnB,IAAIG,EAAe,EACnB,KAAOA,EAAeD,EAAiB,GAAGC,IAAiB,EAC3D,IAAIC,EAAWD,EAAe,EAE1BE,EAAe,IAAI,WAAWF,EAAe,CAAC,EAC9CG,EAAiB,IAAI,WAAWH,CAAY,EAChDE,EAAa,KAAK,UAAU,EAC5B,IAAIE,EAAY,EAEhB,MAAMC,EAAgB,IAAI,WAAWR,CAAU,EAE/C,QAAS/pB,EAAI,EAAGA,EAAI+pB,EAAY/pB,GAAK,EAAG,CACtC,MAAMugB,EAAKsJ,EAAW7pB,CAAC,EACjBwgB,EAAKsJ,EAAW9pB,CAAC,EACvB,IAAIwqB,EAAOzB,GAASxI,EAAIC,EAAI2J,CAAQ,EAEpC,OAAa,CACX,MAAMM,EAAKL,EAAaI,EAAO,CAAC,EAChC,GAAIC,IAAO,WAAY,CAOrB,GANAL,EAAaI,EAAO,CAAC,EAAIjK,EACzB6J,EAAaI,EAAO,EAAI,CAAC,EAAIhK,EAC7B6J,EAAeG,CAAI,EAAI,EACvBD,EAAcvqB,CAAC,EAAIwqB,EACnBF,GAAa,EAETA,EAAY,EAAIJ,EAAe,EAAG,CACpC,MAAMQ,GAASR,EACfA,IAAiB,EACjBC,EAAWD,EAAe,EAE1B,MAAMS,GAAU,IAAI,WAAWT,EAAe,CAAC,EACzCU,GAAY,IAAI,WAAWV,CAAY,EAC7CS,GAAQ,KAAK,UAAU,EAEvB,QAASE,GAAI,EAAGA,GAAIH,GAAQG,IAAK,EAAG,CAClC,GAAIT,EAAaS,GAAI,CAAC,IAAM,WAAY,SACxC,MAAMC,GAAMV,EAAaS,GAAI,CAAC,EACxBE,EAAMX,EAAaS,GAAI,EAAI,CAAC,EAClC,IAAIG,EAAKjC,GAAS+B,GAAKC,EAAKZ,CAAQ,EACpC,KAAOQ,GAAQK,EAAK,CAAC,IAAM,YAAYA,EAAMA,EAAK,EAAKb,EACvDQ,GAAQK,EAAK,CAAC,EAAIF,GAClBH,GAAQK,EAAK,EAAI,CAAC,EAAID,EACtBH,GAAUI,CAAE,EAAIX,EAAeQ,EAAC,CAClC,CAMA,IAJAT,EAAeO,GACfN,EAAiBO,GAEjBJ,EAAOzB,GAASxI,EAAIC,EAAI2J,CAAQ,EAE9BC,EAAaI,EAAO,CAAC,IAAMjK,GAC3B6J,EAAaI,EAAO,EAAI,CAAC,IAAMhK,GAE/BgK,EAAQA,EAAO,EAAKL,EAEtBI,EAAcvqB,CAAC,EAAIwqB,CACrB,CACA,KACF,CAEA,GAAIC,IAAOlK,GAAM6J,EAAaI,EAAO,EAAI,CAAC,IAAMhK,EAAI,CAClD6J,EAAeG,CAAI,GAAK,EACxBD,EAAcvqB,CAAC,EAAIwqB,EACnB,KACF,CAEAA,EAAQA,EAAO,EAAKL,CACtB,CACF,CAEA,MAAMc,EAAW,IAAI,WAAWX,EAAY,CAAC,EACvCY,EAAc,IAAI,YAAYZ,CAAS,EACvCa,EAAc,IAAI,YAAYb,CAAS,EACvCc,EAAkB,IAAI,WAAWlB,CAAY,EACnDkB,EAAgB,KAAKtC,EAAU,EAE/B,IAAIuC,EAAU,EACVC,GAAS,EACb,QAAST,EAAI,EAAGA,EAAIX,EAAcW,GAAK,EACjCT,EAAaS,EAAI,CAAC,IAAM,aAC5BI,EAASI,EAAU,CAAC,EAAIjB,EAAaS,EAAI,CAAC,EAC1CI,EAASI,EAAU,EAAI,CAAC,EAAIjB,EAAaS,EAAI,EAAI,CAAC,EAClDK,EAAYG,CAAO,EAAIC,GACvBH,EAAYE,CAAO,EAAIhB,EAAeQ,CAAC,EACvCO,EAAgBP,CAAC,EAAIQ,EACrBC,IAAUjB,EAAeQ,CAAC,EAC1BQ,GAAW,GAGb,MAAME,EAAe,IAAI,YAAYxB,CAAU,EACzCyB,GAAa,IAAI,YAAYlB,CAAS,EAG5C,GAFAkB,GAAW,IAAIN,CAAW,EAEtBrE,EACF,QAAS7mB,EAAI,EAAGA,EAAI+pB,EAAY/pB,GAAK,EAAG,CACtC,MAAMyrB,EAAKL,EAAgBb,EAAcvqB,CAAC,CAAC,EAC3CurB,EAAaC,GAAWC,CAAE,CAAC,EAAI5E,EAAY7mB,CAAC,EAC5CwrB,GAAWC,CAAE,GAAK,CACpB,KACK,CACL,IAAIC,EAAS,EACb,QAAS1rB,EAAI,EAAGA,EAAIqmB,EAAWrmB,GAAK,EAAG,CACrC,MAAMwR,EAAKiY,EAAM,UAAUzpB,EAAI,CAAC,EAC1ByR,EAAKgY,EAAM,UAAUzpB,EAAI,EAAI,CAAC,EACpC,GAAI,CAAC,OAAO,SAASwR,CAAE,GAAK,CAAC,OAAO,SAASC,CAAE,EAAG,SAClD,MAAMga,EAAKL,EAAgBb,EAAcmB,CAAM,CAAC,EAChDH,EAAaC,GAAWC,CAAE,CAAC,EAAIzrB,EAC/BwrB,GAAWC,CAAE,GAAK,EAClBC,GAAU,CACZ,CACF,CAEA,IAAIC,GAAW,EACf,KAAOA,GAAWrB,EAAY,GAAGqB,KAAa,EAC9C,MAAMC,GAAYD,GAAW,EACvBE,GAAY,IAAI,WAAWF,EAAQ,EACzCE,GAAU,KAAK/C,EAAU,EAEzB,QAAS9oB,EAAI,EAAGA,EAAIsqB,EAAWtqB,GAAK,EAAG,CACrC,MAAMugB,EAAK0K,EAASjrB,EAAI,CAAC,EACnBwgB,EAAKyK,EAASjrB,EAAI,EAAI,CAAC,EAC7B,IAAIwqB,EAAOzB,GAASxI,EAAIC,EAAIoL,EAAS,EACrC,KAAOC,GAAUrB,CAAI,IAAM1B,IAAY0B,EAAQA,EAAO,EAAKoB,GAC3DC,GAAUrB,CAAI,EAAIxqB,CACpB,CAEA,MAAO,CACL,SAAA2pB,EACA,UAAAtD,EACA,UAAAiE,EACA,aAAcqB,GACd,UAAAE,GACA,SAAAZ,EACA,YAAAC,EACA,YAAAC,EACA,aAAAI,CAAA,CAEJ,CClOO,SAASO,GACdjU,EACAmR,EACAC,EACQ,CACR,KAAM,CAAE,UAAA4C,EAAW,SAAAZ,EAAU,SAAAd,CAAA,EAAatS,EAC1C,IAAI2S,EAAOzB,GAASC,EAAOC,EAAOkB,CAAQ,EAC1C,OAAa,CACX,MAAMsB,EAAKI,EAAUrB,CAAI,EACzB,GAAIiB,IAAO3C,GAAY,MAAO,GAC9B,GAAImC,EAASQ,EAAK,CAAC,IAAMzC,GAASiC,EAASQ,EAAK,EAAI,CAAC,IAAMxC,EAAO,OAAOwC,EACzEjB,EAAQA,EAAO,EAAKL,CACtB,CACF,CAQA,SAAS4B,GAAkBrE,EAAiC1kB,EAAuD,CACjH,GAAI0kB,EAAI,WAAa,GAAKA,EAAI,WAAa,EAAG,OAAO,KAErD,MAAMrB,EAAYqB,EAAI,UACtB,MAAO,CACL,SAAUA,EAAI,SACd,UAAArB,EACA,UAAWrjB,EAAU,UAAU,SAAS,EAAGqjB,EAAY,CAAC,EACxD,IACErjB,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUqjB,EAC5DrjB,EAAU,IAAI,SAAS,EAAGqjB,CAAS,EACnC,KACN,aAAcqB,EAAI,aAClB,SAAUA,EAAI,aAAe,EAC7B,UAAW,IAAI,WAAWA,EAAI,SAAS,EACvC,SAAU,IAAI,WAAWA,EAAI,QAAQ,EACrC,YAAa,IAAI,YAAYA,EAAI,WAAW,EAC5C,YAAa,IAAI,YAAYA,EAAI,WAAW,EAC5C,aAAc,IAAI,YAAYA,EAAI,YAAY,CAAA,CAElD,CAEA,MAAMF,GAAe,IAAIP,GACvB,IACE,IAAI,OAAO,IAAA,IAAA,IAAA,OAAA,SAAA,IAAA,QAAA,KAAA,EAAA,cAAA,UAAA,4CAAA,EAAA,KAAA,IAAA,IAAA,4CAAA,SAAA,eAAA,SAAA,cAAA,QAAA,YAAA,IAAA,UAAA,SAAA,cAAA,KAAA,SAAA,OAAA,EAAA,MAAA,OAAA,SAAA,IAAA,QAAA,KAAA,EAAA,cAAA,UAAA,EAAA,KAAAQ,IAAAA,GAAA,QAAA,YAAA,IAAA,UAAAA,GAAA,KAAA,IAAA,IAAA,YAAA,SAAA,OAAA,EAAA,IAAA,EAAkE,CAC3E,KAAM,QAAA,CACP,EACH,CACE,WAAY,CAACL,EAASC,IAAY,CAChC,GAAID,EAAQ,OAAS,0BAA2B,CAC9CC,EAAQ,OAAO,IAAI,MAAMD,EAAQ,OAAS,2BAA2B,CAAC,EACtE,MACF,CACAC,EAAQ,QAAQ0E,GAAkB3E,EAASC,EAAQ,SAAS,CAAC,CAC/D,EACA,cAAe,CAACA,EAASvpB,IAAU,CACjCupB,EAAQ,OAAOvpB,CAAK,CACtB,CAAA,CAEJ,EAEO,SAASkuB,IAAqC,CACnDxE,GAAa,UAAU,mBAAmB,CAC5C,CAEA,SAASyE,GACPjpB,EACAtJ,EAC8B,CAC9B,MAAM2sB,EAAYtjB,GAAmBC,CAAS,EAC9C,GAAIqjB,GAAa,EAAG,OAAO,KAE3B,MAAMjD,EAAYpgB,EAAU,UAAU,SAAS,EAAGqjB,EAAY,CAAC,EACzD9K,EAASiO,GAAmB,CAChC,MAAOnD,EACP,UAAAjD,EACA,YACEpgB,EAAU,uBAAuB,YAAcA,EAAU,YAAc,KACzE,YAAatJ,GAAQ,OAAS,EAC9B,aAAcA,GAAQ,QAAU,CAAA,CACjC,EACD,OAAK6hB,EAEE,CACL,SAAUA,EAAO,SACjB,UAAA8K,EACA,UAAAjD,EACA,IACEpgB,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUqjB,EAC5DrjB,EAAU,IAAI,SAAS,EAAGqjB,CAAS,EACnC,KACN,aAAc9K,EAAO,aACrB,SAAUA,EAAO,aAAe,EAChC,UAAWA,EAAO,UAClB,SAAUA,EAAO,SACjB,YAAaA,EAAO,YACpB,YAAaA,EAAO,YACpB,aAAcA,EAAO,YAAA,EAhBH,IAkBtB,CAEA,eAAsB2Q,GACpBlpB,EACAtJ,EACuC,CACvC,GAAI,CAACsJ,GAAa,CAACA,EAAU,WAAa,CAACA,EAAU,eACnD,OAAO,KAGT,MAAMqjB,EAAYtjB,GAAmBC,CAAS,EAC9C,OAAIqjB,GAAa,EAAU,KAEpB,IAAI,QAAsC,CAAC+B,EAASC,IAAW,CACpE,MAAMhB,EAA0B,CAC9B,QAAAe,EACA,OAAAC,EACA,UAAArlB,CAAA,EAEIulB,EAAgBf,GAAa,aAAaH,CAAO,EACvD,GAAI,CAACkB,GAAiB,CAACA,EAAc,OAAQ,CAC3CH,EAAQ6D,GAAkBjpB,EAAWtJ,CAAM,CAAC,EAC5C,MACF,CAEA,MAAMsuB,EAAgBhlB,EAAU,UAAU,MAAM,EAAGqjB,EAAY,CAAC,EAC1D8F,EACJnpB,EAAU,uBAAuB,aACjCA,EAAU,YAAY,OAAS,EAC3BA,EAAU,YAAY,MAAA,EACtB,OAEA0kB,EAAkC,CACtC,KAAM,0BACN,GAAIa,EAAc,GAClB,MAAOlC,EACP,UAAW2B,EAAc,OACzB,YAAamE,GAAiB,OAC9B,YAAazyB,GAAQ,OAAS,EAC9B,aAAcA,GAAQ,QAAU,CAAA,EAE5B8uB,EAA2B,CAACR,EAAc,MAAM,EAClDmE,GAAiB3D,EAAS,KAAK2D,EAAgB,MAAM,EAEzD,GAAI,CACF5D,EAAc,OAAO,YAAYb,EAAKc,CAAQ,CAChD,OAAS1qB,EAAO,CACd,MAAM2qB,EAAWjB,GAAa,cAAce,EAAc,EAAE,EACxDE,EACFA,EAAS,OAAO3qB,CAAK,EAErBuqB,EAAOvqB,CAAK,CAEhB,CACF,CAAC,CACH,CChJA,SAASsuB,GAAeC,EAAiD,CACvE,MAAMhrB,EAA6B,CAAA,EACnC,QAASrB,EAAI,EAAGA,EAAIqsB,EAAQ,OAAQrsB,GAAK,EAAG,CAC1C,MAAMgY,EAASqU,EAAQrsB,CAAC,EAClB+B,EAAWZ,GAAmB,CAACxC,GAAcqZ,GAAQ,WAAW,CAAC,CAAC,EACxE,GAAIjW,EAAS,SAAW,EAAG,SAE3B,IAAItB,EAAO,EACX,UAAWpB,KAAW0C,EACpBtB,GAAQpB,EAAQ,KAGlBgC,EAAS,KAAK,CACZ,SAAU2W,EAAO,IAAMhY,EACvB,YAAaA,EACb,SAAA+B,EACA,KAAM,KAAK,IAAI,KAAMtB,CAAI,CAAA,CAC1B,CACH,CACA,OAAOY,CACT,CAEA,SAASirB,GAAcC,EAAsBC,EAA4E,CACvH,GAAI,MAAM,QAAQA,CAAoB,EAAG,CACvC,MAAMC,EAAYD,EAAqBD,CAAY,EACnD,GAAI,OAAOE,GAAc,UAAYA,EAAU,OAAS,EAAG,OAAOA,CACpE,CACA,GAAID,aAAgC,IAAK,CACvC,MAAME,EAAUF,EAAqB,IAAID,CAAY,EACrD,GAAI,OAAOG,GAAY,UAAYA,EAAQ,OAAS,EAAG,OAAOA,CAChE,CACA,OAAO,OAAOH,CAAY,CAC5B,CAEO,SAASI,GAAsB3pB,EAA4CqpB,EAAkDvvB,EAAgC,CAAA,EAAwB,CAC1L,MAAM8vB,EAAY,KAAK,IACrB,EACA,KAAK,IACH,KAAK,MAAM5pB,GAAW,OAAS,CAAC,EAChC,KAAK,OAAOA,GAAW,WAAW,QAAU,GAAK,CAAC,EAClDA,GAAW,gBAAgB,QAAU,EACrCA,GAAW,qBAAqB,WAAaA,EAAU,UAAU,OAAS,OAAO,gBAAA,CACnF,EAGF,IAAI6jB,EAAkC,KACtC,GAAI7jB,GAAW,uBAAuB,YAAa,CACjD,MAAMtJ,EAASsJ,EAAU,YACzB,IAAI6pB,EAAQnzB,EAAO,OACnB,QAASsG,EAAI,EAAGA,EAAItG,EAAO,OAAQsG,GAAK,EAC1BtG,EAAOsG,CAAC,EACV4sB,IACVC,GAAS,GAEX,GAAIA,IAAUnzB,EAAO,OACnBmtB,EAAcntB,UACLmzB,EAAQ,EAAG,CACpB,MAAMtD,EAAW,IAAI,YAAYsD,CAAK,EACtC,IAAIxc,EAAS,EACb,QAASrQ,EAAI,EAAGA,EAAItG,EAAO,OAAQsG,GAAK,EAAG,CACzC,MAAM8sB,EAAMpzB,EAAOsG,CAAC,EAChB8sB,GAAOF,IACXrD,EAASlZ,CAAM,EAAIyc,EACnBzc,GAAU,EACZ,CACAwW,EAAc0C,CAChB,MACE1C,EAAc,IAAI,YAAY,CAAC,CAEnC,CAEA,MAAMkG,EAAalG,EAAcA,EAAY,OAAS+F,EAEhDI,EAAkBZ,GAAeC,GAAW,EAAE,EACpD,GAAI,CAACrpB,GAAa+pB,IAAe,GAAKC,EAAgB,SAAW,EAC/D,MAAO,CACL,OAAQ,CAAA,EACR,gBAAiBD,EACjB,sBAAuB,EACvB,oBAAqBA,CAAA,EAIzB,MAAME,MAAyB,IACzBC,MAA0B,IAChC,IAAIC,EAAc,EAElB,QAASntB,EAAI,EAAGA,EAAI+sB,EAAY/sB,GAAK,EAAG,CACtC,MAAM+mB,EAAaF,EAAcA,EAAY7mB,CAAC,EAAIA,EAC5CP,EAAIuD,EAAU,UAAU+jB,EAAa,CAAC,EACtCrnB,EAAIsD,EAAU,UAAU+jB,EAAa,EAAI,CAAC,EAChD,IAAIqG,EAAoC,KAExC,UAAWpV,KAAUgV,EAAiB,CACpC,IAAInsB,EAAS,GACb,UAAWxB,KAAW2Y,EAAO,SAC3B,GAAKpW,GAAuBnC,EAAGC,EAAGL,CAAO,EACzC,CAAAwB,EAAS,GACT,MAEGA,IACD,CAACusB,GAAcpV,EAAO,KAAOoV,EAAW,QAC1CA,EAAapV,EAEjB,CAEA,GAAI,CAACoV,EAAY,SACjBD,GAAe,EAEf,MAAMZ,EAAevpB,EAAU,eAAe+jB,CAAU,GAAK,EACvDsG,EAAgBJ,EAAmB,IAAIG,EAAW,WAAW,OAAS,IAC5EC,EAAc,IAAId,GAAec,EAAc,IAAId,CAAY,GAAK,GAAK,CAAC,EAC1EU,EAAmB,IAAIG,EAAW,YAAaC,CAAa,EAC5DH,EAAoB,IAAIE,EAAW,aAAcF,EAAoB,IAAIE,EAAW,WAAW,GAAK,GAAK,CAAC,CAC5G,CAEA,MAAME,EAAsBxwB,EAAQ,qBAAuB,GACrDywB,EAA0B,CAAA,EAChC,UAAWvV,KAAUgV,EAAiB,CACpC,MAAMQ,EAAaN,EAAoB,IAAIlV,EAAO,WAAW,GAAK,EAClE,GAAI,CAACsV,GAAuBE,GAAc,EAAG,SAC7C,MAAMC,EAAUR,EAAmB,IAAIjV,EAAO,WAAW,OAAS,IAC5D0V,EAA6B,MAAM,KAAKD,EAAQ,SAAS,EAC5D,IAAI,CAAC,CAAClB,EAAcpJ,CAAK,KAAO,CAC/B,OAAQmJ,GAAcC,EAAczvB,EAAQ,oBAAoB,EAChE,aAAAyvB,EACA,MAAApJ,CAAA,EACA,EACD,KAAK,CAACljB,EAAGC,IAAMA,EAAE,MAAQD,EAAE,OAASA,EAAE,aAAeC,EAAE,YAAY,EAEtEqtB,EAAO,KAAK,CACV,SAAUvV,EAAO,SACjB,YAAaA,EAAO,YACpB,WAAAwV,EACA,WAAAE,CAAA,CACD,CACH,CAEA,MAAO,CACL,OAAAH,EACA,gBAAiBR,EACjB,sBAAuBI,EACvB,oBAAqB,KAAK,IAAI,EAAGJ,EAAaI,CAAW,CAAA,CAE7D,CClIA,SAASQ,GAAuBC,EAAarP,EAA4B,CACxE,GAAI,CAACA,EAAW,MAAO,GACvB,GAAI,CAEH,MAAMsP,EADS,IAAI,IAAID,EAAK,OAAO,OAAW,IAAc,OAAO,SAAS,KAAO,MAAS,EACxE,SAAS,YAAA,EAG7B,GADCC,EAAK,SAAS,eAAe,GAAKA,EAAK,WAAW,KAAK,GAAKA,EAAK,SAAS,MAAM,EACpE,MAAO,EACrB,MAAQ,CAER,CACA,MAAO,EACR,CAEO,MAAMC,EAAc,CAwB1B,YAAYhxB,EAA+B,CAvB1BlC,EAAA,uBACAA,EAAA,mBACAA,EAAA,yBACAA,EAAA,wBACAA,EAAA,mBACAA,EAAA,oBAGAA,EAAA,sBAITA,EAAA,kBACAA,EAAA,iBAAY,IACZA,EAAA,aAAqB,CAAA,GACrBA,EAAA,uBAAkB,KAClBA,EAAA,oBAAe,KACfA,EAAA,uBAAkB,KAClBA,EAAA,eAAyB,MACzBA,EAAA,oBAAe,GACfA,EAAA,kBAAa,GACbA,EAAA,mBAAc,GAGrB,KAAK,eAAiB,KAAK,IAAI,EAAG,KAAK,MAAMkC,EAAQ,gBAAkB,EAAE,CAAC,EAC1E,KAAK,WAAa,KAAK,IAAI,EAAG,KAAK,MAAMA,EAAQ,YAAc,CAAC,CAAC,EACjE,KAAK,iBAAmB,KAAK,IAC5B,GACA,KAAK,MAAMA,EAAQ,kBAAoB,GAAG,CAAA,EAE3C,KAAK,gBAAkB,KAAK,IAC3B,KAAK,iBACL,KAAK,MAAMA,EAAQ,iBAAmB,IAAI,CAAA,EAE3C,KAAK,UAAYA,EAAQ,WAAa,GACtC,KAAK,WAAaA,EAAQ,WAC1B,KAAK,YAAcA,EAAQ,YAC3B,KAAK,cAAgBA,EAAQ,aAC9B,CAEA,aAAauG,EAAqB,CACjC,KAAK,UAAY,OAAOA,GAAS,EAAE,CACpC,CAEA,SAAShG,EAAuC,CAC/C,GAAI,KAAK,UAAW,OAEpB,MAAM0wB,MAAsB,IAC5B,UAAWvwB,KAAQH,EAClB0wB,EAAgB,IAAIvwB,EAAK,GAAG,EAE7B,KAAK,YAAcuwB,EAEnB,KAAK,oBAAoBA,CAAe,EACxC,KAAK,uBAAuBA,CAAe,EAE3C,UAAWvwB,KAAQH,EAAO,CACzB,GAAI,KAAK,SAAS,IAAIG,EAAK,GAAG,EAAG,CAChC,MAAMwwB,EAAW,KAAK,SAAS,IAAIxwB,EAAK,GAAG,EACvCwwB,MAAmB,KAAOxwB,GAC9B,QACD,CAEA,MAAMywB,EAAS,KAAK,YAAY,IAAIzwB,EAAK,GAAG,EAC5C,GAAIywB,EAAQ,CACXA,EAAO,KAAOzwB,EACd,QACD,CAEA,MAAM0Q,EAAkB,CACvB,KAAA1Q,EACA,QAAS,EACT,QAASsF,GAAA,CAAM,EAEhB,KAAK,MAAM,KAAKoL,CAAI,EACpB,KAAK,YAAY,IAAI1Q,EAAK,IAAK0Q,CAAI,CACpC,CAEA,KAAK,UAAA,EACL,KAAK,KAAA,EACL,KAAK,gBAAA,CACN,CAEA,OAAc,CACb,KAAK,eAAA,EACL,KAAK,YAAY,MAAA,EACjB,KAAK,MAAQ,CAAA,EACb,KAAK,YAAY,MAAA,EAEjB,SAAW,CAAA,CAAGA,CAAI,IAAK,KAAK,SAC3BA,EAAK,WAAW,MAAA,EAEjB,KAAK,SAAS,MAAA,EACd,KAAK,gBAAA,CACN,CAEA,SAAgB,CACX,KAAK,YACT,KAAK,UAAY,GACjB,KAAK,MAAA,EACN,CAEA,kBAA2B,CAC1B,OAAO,KAAK,SAAS,IACtB,CAEA,aAAqC,CACpC,MAAO,CACN,SAAU,KAAK,SAAS,KACxB,OAAQ,KAAK,MAAM,OACnB,QAAS,KAAK,aACd,QAAS,KAAK,WACd,OAAQ,KAAK,WAAA,CAEf,CAEQ,oBAAoBggB,EAAgC,CAC3D,GAAI,KAAK,MAAM,SAAW,EAAG,OAC7B,MAAMC,EAAyB,CAAA,EAC/B,UAAWjgB,KAAQ,KAAK,MAAO,CAC9B,GAAI,CAACggB,EAAY,IAAIhgB,EAAK,KAAK,GAAG,EAAG,CACpC,KAAK,YAAY,OAAOA,EAAK,KAAK,GAAG,EACrC,QACD,CACAigB,EAAU,KAAKjgB,CAAI,CACpB,CACA,KAAK,MAAQigB,CACd,CAEQ,uBAAuBD,EAAgC,CAC9D,SAAW,CAACld,EAAK9C,CAAI,IAAK,KAAK,SAC1BggB,EAAY,IAAIld,CAAG,IACvB,KAAK,SAAS,OAAOA,CAAG,EACxB,KAAK,cAAgB,EACrB9C,EAAK,WAAW,MAAA,EAElB,CAEQ,WAAkB,CACzB,KAAK,MAAM,KAAK,CAACjO,EAAGC,IACfD,EAAE,UAAYC,EAAE,QAAgBD,EAAE,QAAUC,EAAE,QAC9CD,EAAE,KAAK,YAAcC,EAAE,KAAK,UACxBD,EAAE,KAAK,UAAYC,EAAE,KAAK,UAE9BD,EAAE,KAAK,OAASC,EAAE,KAAK,KAAaA,EAAE,KAAK,KAAOD,EAAE,KAAK,KACtDA,EAAE,KAAK,IAAI,cAAcC,EAAE,KAAK,GAAG,CAC1C,CACF,CAEQ,MAAa,CACpB,GAAI,KAAK,UAAW,OAGpB,IAFA,KAAK,eAAA,EAEE,KAAK,SAAS,KAAO,KAAK,gBAAgB,CAChD,MAAMnF,EAAO,KAAK,uBAAA,EAClB,GAAI,CAACA,EAAM,MACX,KAAK,WAAWA,CAAI,CACrB,CAMA,GAJI,KAAK,SAAS,MAAQ,KAAK,gBAI3B,KAAK,MAAM,SAAW,EAAG,OAE7B,MAAMqzB,EAAkB,KAAK,MAAM,CAAC,GAAG,QACvC,GAAI,OAAOA,GAAoB,SAAU,OACzC,MAAMC,EAAQ,KAAK,IAAI,EAAGD,EAAkBtrB,IAAO,EACnD,KAAK,QAAU,OAAO,WAAW,IAAM,CACtC,KAAK,QAAU,KACf,KAAK,KAAA,CACN,EAAGurB,CAAK,CACT,CAEQ,wBAA2C,CAClD,GAAI,KAAK,MAAM,SAAW,EAAG,OAAO,KACpC,MAAMC,EAAMxrB,GAAA,EACNlD,EAAQ,KAAK,MAAM,CAAC,EAC1B,MAAI,CAACA,GAASA,EAAM,QAAU0uB,EAAY,MAE1C,KAAK,MAAM,MAAA,EACX,KAAK,YAAY,OAAO1uB,EAAM,KAAK,GAAG,EAC/BA,EACR,CAEQ,WAAWsO,EAAuB,CACzC,MAAMqgB,EAAa,IAAI,gBACjBC,EAA8B,CACnC,KAAMtgB,EAAK,KACX,QAASA,EAAK,QACd,WAAAqgB,CAAA,EAED,KAAK,SAAS,IAAIrgB,EAAK,KAAK,IAAKsgB,CAAa,EAC9C,KAAK,gBAAA,EAEL,MAAM/L,EAAgBkL,GAAuBzf,EAAK,KAAK,IAAK,KAAK,SAAS,EAC1E,MAAMA,EAAK,KAAK,IAAK,CACpB,OAAQqgB,EAAW,OACnB,QAAS9L,EAAgB,CAAE,cAAe,KAAK,WAAc,MAAA,CAC7D,EACC,KAAM/kB,GAAa,CACnB,GAAI,CAACA,EAAS,GACb,MAAM,IAAI,MAAM,QAAQA,EAAS,MAAM,EAAE,EAE1C,OAAOA,EAAS,KAAA,CACjB,CAAC,EACA,KAAMC,GAAS,kBAAkBA,CAAI,CAAC,EACtC,KAAMC,GAAW,CACjB,GAAI,KAAK,WAAa2wB,EAAW,OAAO,QAAS,CAChD3wB,EAAO,MAAA,EACP,MACD,CACA,GAAI,CAAC,KAAK,YAAY,IAAIsQ,EAAK,KAAK,GAAG,EAAG,CACzCtQ,EAAO,MAAA,EACP,MACD,CACA,KAAK,WAAWsQ,EAAK,KAAMtQ,CAAM,CAClC,CAAC,EACA,MAAOE,GAAmB,CAC1B,GAAIywB,EAAW,OAAO,SAAW,KAAK,UACrC,OAKD,GADCrgB,EAAK,QAAU,KAAK,YAAc,KAAK,YAAY,IAAIA,EAAK,KAAK,GAAG,EACpD,CAChB,KAAK,YAAc,EACnB,MAAMugB,EAAcvgB,EAAK,QAAU,EAC7BwgB,EAAa,KAAK,cAAcD,CAAW,EAC3CR,EAAoB,CACzB,KAAM/f,EAAK,KACX,QAASugB,EACT,QAAS3rB,KAAU4rB,CAAA,EAEdC,EAAW,KAAK,YAAY,IAAIzgB,EAAK,KAAK,GAAG,EAC/CygB,GACHA,EAAS,KAAOV,EAAO,KACvBU,EAAS,QAAU,KAAK,IAAIA,EAAS,QAASV,EAAO,OAAO,EAC5DU,EAAS,QAAU,KAAK,IAAIA,EAAS,QAASV,EAAO,OAAO,IAE5D,KAAK,MAAM,KAAKA,CAAM,EACtB,KAAK,YAAY,IAAIA,EAAO,KAAK,IAAKA,CAAM,GAE7C,KAAK,UAAA,EACL,MACD,CAEA,KAAK,aAAe,EACpB,KAAK,cAAc/f,EAAK,KAAMpQ,EAAOoQ,EAAK,QAAU,CAAC,CACtD,CAAC,EACA,QAAQ,IAAM,CACd,KAAK,SAAS,OAAOA,EAAK,KAAK,GAAG,EAClC,KAAK,KAAA,EACL,KAAK,gBAAA,CACN,CAAC,CACH,CAEQ,cAAc0gB,EAAyB,CAC9C,MAAMC,EAAM,KAAK,IAAI,EAAGD,EAAU,CAAC,EAC7BP,EAAQ,KAAK,IAClB,KAAK,gBACL,KAAK,iBAAmB,GAAKQ,CAAA,EAExBC,EAAS,IAAO,KAAK,OAAA,EAAW,GACtC,OAAO,KAAK,MAAMT,EAAQS,CAAM,CACjC,CAEQ,gBAAuB,CAC1B,KAAK,UAAY,OACrB,OAAO,aAAa,KAAK,OAAO,EAChC,KAAK,QAAU,KAChB,CAEQ,iBAAwB,CAC/B,KAAK,gBAAgB,KAAK,aAAa,CACxC,CACD,CCvUO,SAASC,GAAgCx0B,EAA2B4sB,EAAwC,CACjH5sB,EAAO,iBAAiB,cAAe4sB,EAAS,WAAW,EAC3D5sB,EAAO,iBAAiB,cAAe4sB,EAAS,WAAW,EAC3D5sB,EAAO,iBAAiB,YAAa4sB,EAAS,SAAS,EACvD5sB,EAAO,iBAAiB,gBAAiB4sB,EAAS,SAAS,EAC3D5sB,EAAO,iBAAiB,QAAS4sB,EAAS,MAAO,CAAE,QAAS,GAAO,EACnE5sB,EAAO,iBAAiB,WAAY4sB,EAAS,WAAW,EACxD5sB,EAAO,iBAAiB,cAAe4sB,EAAS,WAAW,EAC3D5sB,EAAO,iBAAiB,mBAAoB4sB,EAAS,WAAW,EAChE5sB,EAAO,iBAAiB,uBAAwB4sB,EAAS,eAAe,CAC1E,CAEO,SAAS6H,GAAmCz0B,EAA2B4sB,EAAwC,CACpH5sB,EAAO,oBAAoB,cAAe4sB,EAAS,WAAW,EAC9D5sB,EAAO,oBAAoB,cAAe4sB,EAAS,WAAW,EAC9D5sB,EAAO,oBAAoB,YAAa4sB,EAAS,SAAS,EAC1D5sB,EAAO,oBAAoB,gBAAiB4sB,EAAS,SAAS,EAC9D5sB,EAAO,oBAAoB,QAAS4sB,EAAS,KAAK,EAClD5sB,EAAO,oBAAoB,WAAY4sB,EAAS,WAAW,EAC3D5sB,EAAO,oBAAoB,cAAe4sB,EAAS,WAAW,EAC9D5sB,EAAO,oBAAoB,mBAAoB4sB,EAAS,WAAW,EACnE5sB,EAAO,oBAAoB,uBAAwB4sB,EAAS,eAAe,CAC7E,CAEO,SAAS8H,GAAqB10B,EAA2Bf,EAA4B01B,EAA2B,CACrH,MAAMnxB,EAAOxD,EAAO,sBAAA,EACd4lB,EAAO,KAAK,IAAI,EAAGpiB,EAAK,OAASxD,EAAO,aAAe,CAAC,EACxD6lB,EAAO,KAAK,IAAI,EAAGriB,EAAK,QAAUxD,EAAO,cAAgB,CAAC,EAC1D2D,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAE9CmiB,EAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOjiB,CAAG,CAAC,EAC3CoiB,EAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOliB,CAAG,CAAC,GAE7C3D,EAAO,QAAU8lB,GAAU9lB,EAAO,SAAW+lB,KAC/C/lB,EAAO,MAAQ8lB,EACf9lB,EAAO,OAAS+lB,GAGlB4O,EAAO,YAAY/O,EAAMC,CAAI,EAC7B5mB,EAAG,SAAS,EAAG,EAAG6mB,EAAQC,CAAM,CAClC,CCjDO,MAAM6O,GAAoC,IACpCC,GAAoB,GACpBC,GAAoB,IAEpBC,GAAqD,CAChE,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,GAAA,EACjB,CAAE,KAAM,EAAG,KAAM,IAAA,EACjB,CAAE,KAAM,EAAG,KAAM,EAAA,EACjB,CAAE,KAAM,GAAI,KAAM,IAAA,EAClB,CAAE,KAAM,GAAI,KAAM,EAAA,EAClB,CAAE,KAAM,GAAI,KAAM,EAAA,CACpB,EAEMC,GAAmB,GACnBC,GAAmB,EACnBC,GAA+B,EAC/BC,GAA+B,EAC/BC,GAAwB,KACxBC,GAAwB,IACxBC,GAAkC,IAEjC,SAASp1B,GAAUC,EAAqB,CAC7C,OAAQA,EAAM,KAAK,GAAM,GAC3B,CAEO,SAASo1B,GAAgB7vB,EAAuCC,EAAgD,CACrH,MAAI,CAACD,GAAK,CAACC,EAAUD,IAAMC,EACpBD,EAAE,SAAWC,EAAE,QAAUD,EAAE,aAAeC,EAAE,YAAcD,EAAE,aAAeC,EAAE,UACtF,CAEO,SAAS6vB,GAAoBC,EAAkD,CACpF,OAAOA,EAAM,IAAIC,IAAS,CAAE,KAAMA,EAAK,KAAM,KAAMA,EAAK,IAAA,EAAO,CACjE,CAEO,SAASC,GAAwBC,EAAsE,CAC5G,GAAI,CAACA,EAAiB,OAAOJ,GAAoBT,EAAwB,EAEzE,MAAM5S,MAAa,IACnB,SAAW,CAAC0T,EAASC,CAAO,IAAK,OAAO,QAAQF,CAAe,EAAG,CAChE,MAAMn1B,EAAO,OAAOo1B,CAAO,EACrBE,EAAO,OAAOD,CAAO,EACvB,CAAC,OAAO,SAASr1B,CAAI,GAAK,CAAC,OAAO,SAASs1B,CAAI,GAAKA,GAAQ,GAChE5T,EAAO,IAAI1hB,EAAMs1B,CAAI,CACvB,CAEA,OAAI5T,EAAO,OAAS,EACXqT,GAAoBT,EAAwB,EAG9C,MAAM,KAAK5S,EAAO,QAAA,CAAS,EAC/B,KAAK,CAACzc,EAAGC,IAAMD,EAAE,CAAC,EAAIC,EAAE,CAAC,CAAC,EAC1B,IAAI,CAAC,CAAClF,EAAMs1B,CAAI,KAAO,CAAE,KAAAt1B,EAAM,KAAAs1B,CAAA,EAAO,CAC3C,CAEO,SAASC,GAAuBtwB,EAA6BC,EAAsC,CACxG,GAAID,IAAMC,EAAG,MAAO,GACpB,GAAID,EAAE,SAAWC,EAAE,OAAQ,MAAO,GAClC,QAASF,EAAI,EAAGA,EAAIC,EAAE,OAAQD,GAAK,EACjC,GAAIC,EAAED,CAAC,EAAE,OAASE,EAAEF,CAAC,EAAE,MAAQC,EAAED,CAAC,EAAE,OAASE,EAAEF,CAAC,EAAE,KAChD,MAAO,GAGX,MAAO,EACT,CAEO,SAASwwB,GAA4BrX,EAAwB6W,EAAyC,CAC3G,GAAI,CAAC,OAAO,SAAS7W,CAAc,EAAG,OAAO6W,EAAM,CAAC,GAAG,MAAQZ,GAC/D,GAAIY,EAAM,SAAW,EAAG,OAAOZ,GAE/B,GADIY,EAAM,SAAW,GACjB7W,GAAkB6W,EAAM,CAAC,EAAE,KAAM,OAAOA,EAAM,CAAC,EAAE,KAErD,QAAShwB,EAAI,EAAGA,EAAIgwB,EAAM,OAAQhwB,GAAK,EAAG,CACxC,MAAML,EAAOqwB,EAAMhwB,EAAI,CAAC,EAClBjF,EAAOi1B,EAAMhwB,CAAC,EACpB,GAAImZ,EAAiBpe,EAAK,KAAM,SAChC,MAAM01B,EAAO,KAAK,IAAI,KAAM11B,EAAK,KAAO4E,EAAK,IAAI,EAC3CoF,EAAI9C,GAAOkX,EAAiBxZ,EAAK,MAAQ8wB,EAAM,EAAG,CAAC,EACzD,OAAO9wB,EAAK,MAAQ5E,EAAK,KAAO4E,EAAK,MAAQoF,CAC/C,CAEA,MAAMlF,EAAOmwB,EAAMA,EAAM,OAAS,CAAC,EAC7BrwB,EAAOqwB,EAAMA,EAAM,OAAS,CAAC,EAC7BS,EAAO,KAAK,IAAI,KAAM5wB,EAAK,KAAOF,EAAK,IAAI,EAC3C+wB,GAAS7wB,EAAK,KAAOF,EAAK,MAAQ8wB,EACxC,OAAO5wB,EAAK,MAAQsZ,EAAiBtZ,EAAK,MAAQ6wB,CACpD,CAEO,SAASC,GAAqB7xB,EAA0C,CAC7E,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU,EAC1DmD,EAAMnD,EAAOywB,GAAkBC,EAAgB,CACxD,CAEO,SAASoB,GAA+B9xB,EAA0C,CACvF,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU,EAC1DmD,EAAMnD,EAAO2wB,GAA8BC,EAA4B,CAChF,CAEA,SAASmB,GAAyB/xB,EAA0C,CAC1E,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU,EAC1DmD,EAAMnD,EAAO6wB,GAAuBC,EAAqB,CAClE,CAEO,SAASkB,GAA+BC,EAAkF,CAC/H,MAAMC,EAAkBH,GAAyBE,GAAU,UAAU,EAC/DE,EAAgBJ,GAAyBE,GAAU,QAAQ,EAC3DG,EAAkBL,GAAyBE,GAAU,UAAU,EACrE,MAAO,CACL,WAAYC,EAAkB,IAC9B,SAAUC,EAAgB,IAC1B,WAAYC,EAAkB,GAAA,CAElC,CAEO,SAASC,GAAapsB,EAAmB,CAC9C,OAAOA,CACT,CAEO,SAASqsB,GAAgCC,EAA6C,CAC3F,OAAI,OAAOA,GAAa,UAAY,CAAC,OAAO,SAASA,CAAQ,EAAU,EAChEpvB,EAAMovB,EAAU,EAAGxB,EAA+B,CAC3D,CAEO,SAASyB,GAAsBxyB,EAAiD,CACrF,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,GAAKA,GAAS,EAAU,KACxE,KAAK,IAAI,KAAMA,CAAK,CAC7B,CAEO,SAASyyB,GAA0BC,EAA2E,CACnH,OAAO,OAAOA,GAAW,WAAaA,EAASL,EACjD,CCjGA,SAASM,GAAmBl3B,EAA2B4mB,EAAiBC,EAAyB,CAC/F,MAAMrjB,EAAOxD,EAAO,sBAAA,EACdkF,EAAI0hB,EAAUpjB,EAAK,KAAOA,EAAK,MAAQ,GACvC2B,EAAI0hB,EAAUrjB,EAAK,IAAMA,EAAK,OAAS,GAC7C,OAAO,KAAK,MAAM2B,EAAGD,CAAC,CACxB,CAEO,SAASiyB,GAAWn3B,EAA2Bmf,EAA+B,CACnF,GAAIA,EAAM,YAAc,MAAQnf,EAAO,kBAAkBmf,EAAM,SAAS,EACtE,GAAI,CACFnf,EAAO,sBAAsBmf,EAAM,SAAS,CAC9C,MAAQ,CAER,CAEFA,EAAM,SAAW,GACjBA,EAAM,KAAO,OACbA,EAAM,mBAAqB,KAC3BA,EAAM,UAAY,KAClBnf,EAAO,UAAU,OAAO,UAAU,CACpC,CAEO,SAASohB,GAAkB7e,EAAmC,CACnE,KAAM,CAAE,MAAAge,EAAO,OAAAvgB,EAAQ,MAAAmf,EAAO,OAAA3T,EAAQ,oBAAA4rB,GAAwB70B,EACxD80B,EAAc7rB,EAAO,iBAAmB+U,EAAM,SAAWA,EAAM,UACjDA,EAAM,SAAW,GAAM8W,GAAe9W,EAAM,SAAW,KAG3E6W,EAAA,EACIC,GACF9W,EAAM,eAAA,EAGRpB,EAAM,SAAW,GACjBA,EAAM,KAAOkY,EAAc,SAAW,MACtClY,EAAM,UAAYoB,EAAM,UACxBpB,EAAM,aAAeoB,EAAM,QAC3BpB,EAAM,aAAeoB,EAAM,QAC3BpB,EAAM,mBAAqBA,EAAM,OAAS,SAAW+X,GAAmBl3B,EAAQugB,EAAM,QAASA,EAAM,OAAO,EAAI,KAEhHvgB,EAAO,UAAU,IAAI,UAAU,EAC/BA,EAAO,kBAAkBugB,EAAM,SAAS,EAC1C,CAEO,SAASc,GAAkB9e,EAAmC,CACnE,KAAM,CAAE,MAAAge,EAAO,OAAAvgB,EAAQ,MAAAmf,EAAO,OAAA3T,EAAQ,OAAAmpB,EAAQ,eAAA2C,EAAgB,cAAAC,EAAe,cAAAC,CAAA,EAAkBj1B,EAC/F,GAAI,CAAC4c,EAAM,UAAYoB,EAAM,YAAcpB,EAAM,UAAW,OAE5D,MAAMpe,EAAKwf,EAAM,QAAUpB,EAAM,aAC3Bne,EAAKuf,EAAM,QAAUpB,EAAM,aAIjC,GAHAA,EAAM,aAAeoB,EAAM,QAC3BpB,EAAM,aAAeoB,EAAM,QAEvBpB,EAAM,OAAS,SAAU,CAC3B,MAAMsY,EAAYP,GAAmBl3B,EAAQugB,EAAM,QAASA,EAAM,OAAO,EACnEmX,EAAYvY,EAAM,mBAExB,GADAA,EAAM,mBAAqBsY,EACvBC,IAAc,KAAM,CACtB,MAAMC,EAAWF,EAAYC,EACvBrrB,EAAQ,KAAK,MAAM,KAAK,IAAIsrB,CAAQ,EAAG,KAAK,IAAIA,CAAQ,CAAC,EACzDC,EAA2DpsB,EAAO,mCAAqCopB,GACvG1xB,EAAYyxB,EAAO,aAAA,EACzBA,EAAO,aAAa,CAClB,YAAazxB,EAAU,YAAgBmJ,EAAQ,IAAO,KAAK,GAAMurB,CAAA,CAClE,CACH,CACF,KAAO,CACL,MAAM10B,EAAYyxB,EAAO,aAAA,EACnBl0B,EAAO,KAAK,IAAI,KAAMyC,EAAU,IAAI,EACpCjC,EAAMf,GAAUgD,EAAU,WAAW,EACrChC,EAAM,KAAK,IAAID,CAAG,EAClBE,EAAM,KAAK,IAAIF,CAAG,EAClB42B,GAAW92B,EAAKG,EAAMF,EAAKG,GAAOV,EAClCq3B,GAAW/2B,EAAKI,EAAMH,EAAKE,GAAOT,EACxCk0B,EAAO,aAAa,CAClB,QAASzxB,EAAU,QAAU20B,EAC7B,QAAS30B,EAAU,QAAU40B,CAAA,CAC9B,CACH,CAEAR,EAAA,EACAC,EAAA,EACAC,EAAA,CACF,CAEO,SAAShW,GAAgBjB,EAAqBvgB,EAA2Bmf,EAA+B,CACzGoB,EAAM,YAAcpB,EAAM,WAC9BgY,GAAWn3B,EAAQmf,CAAK,CAC1B,CAEO,SAAS4Y,GAAYx1B,EAA6B,CACvD,KAAM,CAAE,MAAAge,EAAO,OAAAvgB,EAAQ,SAAAg4B,CAAA,EAAaz1B,EACpCge,EAAM,eAAA,EACN,MAAM/c,EAAOxD,EAAO,sBAAA,EACdkF,EAAIqb,EAAM,QAAU/c,EAAK,KACzB2B,EAAIob,EAAM,QAAU/c,EAAK,IACzBy0B,EAAS1X,EAAM,OAAS,EAAI,KAAO,IACzCyX,EAASC,EAAQ/yB,EAAGC,CAAC,CACvB,CAEO,SAAS+yB,GAAkB31B,EAAmC,CACnE,KAAM,CAAE,MAAAge,EAAO,OAAAvgB,EAAQ,SAAAg4B,CAAA,EAAaz1B,EAC9BiB,EAAOxD,EAAO,sBAAA,EACdkF,EAAIqb,EAAM,QAAU/c,EAAK,KACzB2B,EAAIob,EAAM,QAAU/c,EAAK,IAC/Bw0B,EAASzX,EAAM,SAAW,GAAM,KAAMrb,EAAGC,CAAC,CAC5C,CAEO,SAASgzB,GAAkB5X,EAAmB6X,EAAyB,EACxEA,GAAY7X,EAAM,SAAWA,EAAM,UACrCA,EAAM,eAAA,CAEV,CC7IO,SAAS8X,GAAc1D,EAAgC,CAC5D,MAAMzO,EAAUyO,EAAO,eAAA,EACvB,IAAI1tB,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClC,EAAGC,CAAC,IAAK+gB,EACfhhB,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GACjBC,EAAI+B,IAAMA,EAAO/B,GACjBA,EAAIiC,IAAMA,EAAOjC,GAEvB,MAAO,CAAC8B,EAAMC,EAAMC,EAAMC,CAAI,CAChC,CAEO,SAASkwB,GAAe3C,EAAwBx1B,EAA8B,CACnF,MAAM2L,EAASutB,GAAc1D,CAAM,EAC7BpN,EAAW,KAAK,IAAI,KAAMzc,EAAO,CAAC,EAAIA,EAAO,CAAC,CAAC,EAC/C0c,EAAW,KAAK,IAAI,KAAM1c,EAAO,CAAC,EAAIA,EAAO,CAAC,CAAC,EAC/CwtB,EAAU/Q,EAAW,GACrBgR,EAAU/Q,EAAW,GAErB,CAAC9mB,EAASC,CAAO,EAAIg0B,EAAO,UAAA,EAC5B6D,EAAQjR,EAAW,GACnBkR,EAAQjR,EAAW,GAEnBkR,EAAaF,EAAQF,EACrBK,EAAax5B,EAAO,MAAQq5B,EAAQF,EACpCM,EAAaH,EAAQF,EACrBM,EAAa15B,EAAO,OAASs5B,EAAQF,EAErCO,EAAcJ,GAAcC,EAAajxB,EAAMhH,EAASg4B,EAAYC,CAAU,EAAIx5B,EAAO,MAAQ,GACjG45B,EAAcH,GAAcC,EAAanxB,EAAM/G,EAASi4B,EAAYC,CAAU,EAAI15B,EAAO,OAAS,GAExGw1B,EAAO,UAAUmE,EAAaC,CAAW,CAC3C,CAEO,SAASC,GAAWrE,EAAwBx1B,EAAgC,CACjF,MAAMsB,EAAO,KAAK,IAAI,KAAMk0B,EAAO,aAAA,EAAe,IAAI,EAChDsE,EAAU95B,EAAO,YAAc,KAAK,KAAKsB,CAAI,EACnD,OAAOiH,EAAM,KAAK,MAAMuxB,CAAO,EAAG,EAAG95B,EAAO,WAAW,CACzD,CAEO,SAAS+5B,GAAiBxzB,EAAWC,EAAoB,CAC9D,MAAO,EAAED,EAAE,CAAC,GAAKC,EAAE,CAAC,GAAKD,EAAE,CAAC,GAAKC,EAAE,CAAC,GAAKD,EAAE,CAAC,GAAKC,EAAE,CAAC,GAAKD,EAAE,CAAC,GAAKC,EAAE,CAAC,EACtE,CAEO,SAASwzB,GAAuBxE,EAAwBx1B,EAAwB2jB,EAA+B,CACpH,MAAMsW,EAAaf,GAAc1D,CAAM,EAEjChN,EAAa,KAAK,IAAI,EAAGxoB,EAAO,YAAc2jB,CAAI,EAClD8E,EAAa,KAAK,KAAKzoB,EAAO,MAAQwoB,CAAU,EAChDE,EAAc,KAAK,KAAK1oB,EAAO,OAASwoB,CAAU,EAElDG,EAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAazoB,EAAO,QAAQ,CAAC,EAC5D4oB,EAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAc1oB,EAAO,QAAQ,CAAC,EAE7Dk6B,EAAWD,EAAW,CAAC,EACvBE,EAAWF,EAAW,CAAC,EACvBG,EAAWH,EAAW,CAAC,EACvBI,EAAWJ,EAAW,CAAC,EAEvBK,EAAW/xB,EAAM,KAAK,MAAM2xB,EAAW1R,EAAaxoB,EAAO,QAAQ,EAAG,EAAG2oB,EAAS,CAAC,EACnF4R,EAAWhyB,EAAM,KAAK,OAAO6xB,EAAW,GAAK5R,EAAaxoB,EAAO,QAAQ,EAAG,EAAG2oB,EAAS,CAAC,EACzF6R,EAAWjyB,EAAM,KAAK,MAAM4xB,EAAW3R,EAAaxoB,EAAO,QAAQ,EAAG,EAAG4oB,EAAS,CAAC,EACnF6R,EAAWlyB,EAAM,KAAK,OAAO8xB,EAAW,GAAK7R,EAAaxoB,EAAO,QAAQ,EAAG,EAAG4oB,EAAS,CAAC,EAE/F,GAAI0R,EAAWC,GAAYC,EAAWC,EACpC,MAAO,CAAA,EAGT,MAAMC,GAAgBR,EAAWE,GAAY,GAAO5R,EAAaxoB,EAAO,SAClE26B,GAAgBR,EAAWE,GAAY,GAAO7R,EAAaxoB,EAAO,SAElE46B,EAA2B,CAAA,EACjC,QAAS50B,EAAIw0B,EAAUx0B,GAAKy0B,EAAUz0B,GAAK,EACzC,QAASD,EAAIu0B,EAAUv0B,GAAKw0B,EAAUx0B,GAAK,EAAG,CAC5C,MAAM4T,EAAO5T,EAAI/F,EAAO,SAAWwoB,EAC7B5O,GAAM5T,EAAIhG,EAAO,SAAWwoB,EAC5BrB,EAAQ,KAAK,KAAKphB,EAAI,GAAK/F,EAAO,SAAUyoB,CAAU,EAAID,EAC1DpB,GAAS,KAAK,KAAKphB,EAAI,GAAKhG,EAAO,SAAU0oB,CAAW,EAAIF,EAE5D5mB,GAAKmE,EAAI20B,EACT74B,GAAKmE,EAAI20B,EACfC,EAAQ,KAAK,CACX,IAAK,GAAGjX,CAAI,IAAI5d,CAAC,IAAIC,CAAC,GACtB,KAAA2d,EACA,EAAA5d,EACA,EAAAC,EACA,OAAQ,CAAC2T,EAAMC,GAAKuN,EAAOC,EAAM,EACjC,UAAWxlB,GAAKA,GAAKC,GAAKA,GAC1B,IAAK+hB,GAAU5jB,EAAQ2jB,EAAM5d,EAAGC,CAAC,CAAA,CAClC,CACH,CAGF,OAAA40B,EAAQ,KAAK,CAACr0B,EAAGC,IAAMD,EAAE,UAAYC,EAAE,SAAS,EACzCo0B,CACT,CAEO,SAASC,GAAgBrF,EAAwBx1B,EAAoE,CAC1H,MAAM2jB,EAAOkW,GAAWrE,EAAQx1B,CAAM,EACtC,MAAO,CACL,KAAA2jB,EACA,QAASqW,GAAuBxE,EAAQx1B,EAAQ2jB,CAAI,CAAA,CAExD,CCjEO,SAASmX,GAAsB13B,EAA2C,CAC3EA,EAAQ,mBACZ6e,GAAkB,CAChB,MAAO7e,EAAQ,MACf,OAAQA,EAAQ,OAChB,MAAOA,EAAQ,MACf,OAAQ,CACN,eAAgBA,EAAQ,eACxB,mCAAoCA,EAAQ,kCAAA,EAE9C,oBAAqBA,EAAQ,mBAAA,CAC9B,CACH,CAEO,SAAS23B,GAAsB33B,EAA2C,CAC3EA,EAAQ,mBACZ8e,GAAkB,CAChB,MAAO9e,EAAQ,MACf,OAAQA,EAAQ,OAChB,MAAOA,EAAQ,MACf,OAAQ,CACN,eAAgBA,EAAQ,eACxB,mCAAoCA,EAAQ,kCAAA,EAE9C,OAAQA,EAAQ,OAChB,eAAgB,IAAM+0B,GAAe/0B,EAAQ,OAAQA,EAAQ,MAAM,EACnE,cAAeA,EAAQ,cACvB,cAAeA,EAAQ,aAAA,CACxB,CACH,CAEO,SAAS43B,GAAoB53B,EAAyC,CACvEA,EAAQ,mBACZif,GAAgBjf,EAAQ,MAAOA,EAAQ,OAAQA,EAAQ,KAAK,CAC9D,CAEO,SAAS63B,GAAgB73B,EAAqC,CACnE,GAAIA,EAAQ,kBAAmB,CAC7BA,EAAQ,MAAM,eAAA,EACd,MACF,CACAw1B,GAAY,CACV,MAAOx1B,EAAQ,MACf,OAAQA,EAAQ,OAChB,SAAUA,EAAQ,QAAA,CACnB,CACH,CAEO,SAAS83B,GAAsB93B,EAA2C,CAC3EA,EAAQ,mBACZ21B,GAAkB,CAChB,MAAO31B,EAAQ,MACf,OAAQA,EAAQ,OAChB,SAAUA,EAAQ,QAAA,CACnB,CACH,CAEO,SAAS+3B,GAAsB/3B,EAA2C,CAC/E41B,GAAkB51B,EAAQ,MAAOA,EAAQ,MAAM,QAAQ,CACzD,CAEO,SAAS40B,GAAWn3B,EAA2Bmf,EAA+B,CACnFob,GAAsBv6B,EAAQmf,CAAK,CACrC,CAgBO,SAASqb,GAA4Bj4B,EAAkK,CAC5M,MAAO,CACL,YAAcge,GACZ0Z,GAAsB,CACpB,MAAA1Z,EACA,kBAAmBhe,EAAQ,qBAAA,EAC3B,OAAQA,EAAQ,OAChB,MAAOA,EAAQ,MACf,eAAgBA,EAAQ,kBAAA,EACxB,mCAAoCA,EAAQ,sCAAA,EAC5C,oBAAqBA,EAAQ,mBAAA,CAC9B,EACH,YAAcge,GACZ2Z,GAAsB,CACpB,MAAA3Z,EACA,kBAAmBhe,EAAQ,qBAAA,EAC3B,OAAQA,EAAQ,OAChB,MAAOA,EAAQ,MACf,eAAgBA,EAAQ,kBAAA,EACxB,mCAAoCA,EAAQ,sCAAA,EAC5C,OAAQA,EAAQ,OAChB,OAAQA,EAAQ,OAChB,cAAeA,EAAQ,cACvB,cAAeA,EAAQ,aAAA,CACxB,EACH,UAAYge,GACV4Z,GAAoB,CAClB,MAAA5Z,EACA,kBAAmBhe,EAAQ,qBAAA,EAC3B,OAAQA,EAAQ,OAChB,MAAOA,EAAQ,KAAA,CAChB,EACH,MAAQge,GACN6Z,GAAgB,CACd,MAAA7Z,EACA,kBAAmBhe,EAAQ,qBAAA,EAC3B,OAAQA,EAAQ,OAChB,SAAUA,EAAQ,MAAA,CACnB,EACH,YAAcge,GACZ8Z,GAAsB,CACpB,MAAA9Z,EACA,kBAAmBhe,EAAQ,qBAAA,EAC3B,OAAQA,EAAQ,OAChB,SAAUA,EAAQ,MAAA,CACnB,EACH,YAAcge,GACZ+Z,GAAsB,CACpB,MAAA/Z,EACA,OAAQhe,EAAQ,OAChB,MAAOA,EAAQ,KAAA,CAChB,CAAA,CAEP,CCrLO,SAASk4B,GAAcl4B,EAAqC,CACjE,KAAM,CAAE,GAAAtD,EAAI,MAAAy7B,EAAO,cAAAC,CAAA,EAAkBp4B,EACrC,GAAIm4B,EAAM,MAAQC,EAAe,OAEjC,MAAMC,EAAU,MAAM,KAAKF,EAAM,SAAS,EAC1CE,EAAQ,KAAK,CAACl1B,EAAGC,IAAMD,EAAE,CAAC,EAAE,SAAWC,EAAE,CAAC,EAAE,QAAQ,EAEpD,MAAMk1B,EAAcH,EAAM,KAAOC,EACjC,QAASl1B,EAAI,EAAGA,EAAIo1B,EAAap1B,GAAK,EAAG,CACvC,KAAM,CAACgR,EAAKlS,CAAK,EAAIq2B,EAAQn1B,CAAC,EAC9BxG,EAAG,cAAcsF,EAAM,OAAO,EAC9Bm2B,EAAM,OAAOjkB,CAAG,CAClB,CACF,CAEO,SAASqkB,GAAwB77B,EAA4BoE,EAA0C,CAC5G,GAAIpE,EAAG,cAAA,EAAiB,OAAO,KAE/B,MAAMqE,EAAUrE,EAAG,cAAA,EACnB,OAAKqE,GAELrE,EAAG,YAAYA,EAAG,WAAYqE,CAAO,EACrCrE,EAAG,YAAYA,EAAG,oBAAqB,CAAC,EACxCA,EAAG,cAAcA,EAAG,WAAYA,EAAG,eAAgBA,EAAG,aAAa,EACnEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,eAAgBA,EAAG,aAAa,EACnEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,MAAM,EAChEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,MAAM,EAChEA,EAAG,WAAWA,EAAG,WAAY,EAAGA,EAAG,KAAMA,EAAG,KAAMA,EAAG,cAAeoE,CAAM,EAC1EpE,EAAG,YAAYA,EAAG,WAAY,IAAI,EAE3BqE,GAXc,IAYvB,CAEO,SAASy3B,GAAiBx4B,EAAwC,CACvE,KAAM,CAAE,GAAAtD,EAAI,MAAAy7B,EAAO,KAAAz3B,EAAM,OAAAI,EAAQ,YAAA23B,EAAa,cAAAL,EAAe,UAAAM,EAAW,YAAAC,EAAa,cAAA1D,CAAA,EAAkBj1B,EAEvG,GAAI04B,GAAaC,GAAej8B,EAAG,cAAA,EAAiB,CAClDoE,EAAO,MAAA,EACP,MACF,CACA,GAAIq3B,EAAM,IAAIz3B,EAAK,GAAG,EAAG,CACvBI,EAAO,MAAA,EACP,MACF,CAEA,MAAMC,EAAUw3B,GAAwB77B,EAAIoE,CAAM,EAClDA,EAAO,MAAA,EACFC,IAELo3B,EAAM,IAAIz3B,EAAK,IAAK,CAClB,IAAKA,EAAK,IACV,QAAAK,EACA,OAAQL,EAAK,OACb,KAAMA,EAAK,KACX,SAAU+3B,CAAA,CACX,EACDP,GAAc,CAAE,GAAAx7B,EAAI,MAAAy7B,EAAO,cAAAC,CAAA,CAAe,EAC1CnD,EAAA,EACF,CAEO,SAAS2D,GAAqBl8B,EAA4By7B,EAAqD,CACpH,SAAW,CAAA,CAAGn2B,CAAK,IAAKm2B,EACtBz7B,EAAG,cAAcsF,EAAM,OAAO,CAElC,CChDO,SAAS62B,GAAkB74B,EAAgD,CAChF,KAAM,CAAE,MAAAge,EAAO,UAAA0a,EAAW,YAAAC,EAAa,oBAAA9D,EAAqB,WAAAD,EAAY,cAAAkE,EAAe,MAAAX,EAAO,cAAAY,CAAA,EAAkB/4B,EAEhH,GADAge,EAAM,eAAA,EACF0a,GAAaC,EACf,MAAO,CACL,QAAS,GACT,MAAO34B,EAAQ,KAAA,EAInB,IAAIg5B,EAAQh5B,EAAQ,MACpB,OAAIg5B,IAAU,OACZ,qBAAqBA,CAAK,EAC1BA,EAAQ,MAEVnE,EAAA,EAEAD,EAAA,EACAkE,EAAc,MAAA,EACdX,EAAM,MAAA,EACNY,IAAA,EAEO,CACL,QAAS,GACT,MAAAC,CAAA,CAEJ,CAsBO,SAASC,GAAgBj5B,EAAwD,CACtF,GAAIA,EAAQ,UACV,MAAO,CACL,WAAY,GACZ,MAAOA,EAAQ,KAAA,EAInB,IAAIg5B,EAAQh5B,EAAQ,MACpB,OAAIg5B,IAAU,OACZ,qBAAqBA,CAAK,EAC1BA,EAAQ,MAEVh5B,EAAQ,oBAAA,EAERA,EAAQ,eAAe,WAAA,EACvBA,EAAQ,2BAAA,EACRA,EAAQ,WAAA,EACRA,EAAQ,cAAc,QAAA,EAElB,CAACA,EAAQ,aAAe,CAACA,EAAQ,GAAG,kBACtC44B,GAAqB54B,EAAQ,GAAIA,EAAQ,KAAK,EAC9CA,EAAQ,GAAG,aAAaA,EAAQ,YAAY,GAAG,EAC/CA,EAAQ,GAAG,kBAAkBA,EAAQ,YAAY,GAAG,EACpDA,EAAQ,GAAG,cAAcA,EAAQ,YAAY,OAAO,EAEpDA,EAAQ,GAAG,aAAaA,EAAQ,aAAa,SAAS,EACtDA,EAAQ,GAAG,aAAaA,EAAQ,aAAa,UAAU,EACvDA,EAAQ,GAAG,aAAaA,EAAQ,aAAa,cAAc,EAC3DA,EAAQ,GAAG,aAAaA,EAAQ,aAAa,WAAW,EACxDA,EAAQ,GAAG,cAAcA,EAAQ,aAAa,cAAc,EAC5DA,EAAQ,GAAG,kBAAkBA,EAAQ,aAAa,GAAG,EACrDA,EAAQ,GAAG,cAAcA,EAAQ,aAAa,OAAO,GAEvDA,EAAQ,MAAM,MAAA,EAEP,CACL,WAAY,GACZ,MAAAg5B,CAAA,CAEJ,CC/FA,SAASzM,GAAoBxC,EAA0BmP,EAAmC,CACxF,GAAIA,GAAgB,GAAKnP,EAAY,SAAW,EAC9C,OAAO,IAAI,YAAY,CAAC,EAG1B,IAAIkD,EAAalD,EAAY,OAC7B,QAAS7mB,EAAI,EAAGA,EAAI6mB,EAAY,OAAQ7mB,GAAK,EACvC6mB,EAAY7mB,CAAC,EAAIg2B,IACrBjM,GAAc,GAEhB,GAAIA,IAAelD,EAAY,OAC7B,OAAOA,EAET,GAAIkD,GAAc,EAChB,OAAO,IAAI,YAAY,CAAC,EAG1B,MAAMR,EAAW,IAAI,YAAYQ,CAAU,EAC3C,IAAI1Z,EAAS,EACb,QAASrQ,EAAI,EAAGA,EAAI6mB,EAAY,OAAQ7mB,GAAK,EAAG,CAC9C,MAAM8sB,EAAMjG,EAAY7mB,CAAC,EACrB8sB,GAAOkJ,IACXzM,EAASlZ,CAAM,EAAIyc,EACnBzc,GAAU,EACZ,CACA,OAAOkZ,CACT,CAEA,SAAS0M,GAAiBC,EAA4C/S,EAA4C,CAChH,OAAIA,GAAS,EAAU,IAAI,WAAW,CAAC,EACnC+S,EAAc,OAAS/S,EAClB,IAAI,WAAWA,CAAK,EAEtB+S,EAAc,SAAS,EAAG/S,CAAK,CACxC,CAEO,SAASgT,GAAgBC,EAA6B58B,EAA4B68B,EAA4BZ,EAAsBzxB,EAA2D,CACpM,GAAI,CAACA,GAAUA,EAAO,SAAW,EAC/B,MAAO,CACL,GAAGoyB,EACH,iBAAkB,IAAA,EAItB,MAAME,EAAc,IAAI,WAAWtyB,CAAM,EACzC,GAAIyxB,GAAej8B,EAAG,gBACpB,MAAO,CACL,GAAG48B,EACH,iBAAkBE,CAAA,EAItB,MAAMC,EAAc,KAAK,IAAI,EAAG,KAAK,MAAMD,EAAY,OAAS,CAAC,CAAC,EAClE,OAAA98B,EAAG,YAAYA,EAAG,WAAY68B,EAAa,cAAc,EACzD78B,EAAG,WAAWA,EAAG,WAAY,EAAGA,EAAG,KAAM+8B,EAAa,EAAG,EAAG/8B,EAAG,KAAMA,EAAG,cAAe88B,CAAW,EAClG98B,EAAG,YAAYA,EAAG,WAAY,IAAI,EAE3B,CACL,GAAG48B,EACH,iBAAkBE,EAClB,iBAAkBC,CAAA,CAEtB,CAEO,SAASC,GAAaJ,EAA6B58B,EAA4B68B,EAA4BZ,EAAsB/wB,EAA6D,CACnM,GAAI,CAACA,GAAU,CAACA,EAAO,OAAS,CAACA,EAAO,WAAa,CAACA,EAAO,eAC3D,MAAO,CACL,GAAG0xB,EACH,cAAe,KACf,WAAY,EACZ,gBAAiB,EAAA,EAIrB,MAAM9P,EAAiB5hB,EAAO,qBAAqB,WAAaA,EAAO,UAAY,KAC7E+xB,EAAenQ,IAAmB,KAClCD,EAAY,KAAK,IAAI,EAAG,KAAK,IAAI3hB,EAAO,MAAO,KAAK,MAAMA,EAAO,UAAU,OAAS,CAAC,EAAGA,EAAO,eAAe,OAAQ+xB,EAAenQ,EAAe,OAAS,OAAO,gBAAgB,CAAC,EACrL/C,EAAgB7e,EAAO,UAAU,SAAS,EAAG2hB,EAAY,CAAC,EAC1DqQ,EAAqBhyB,EAAO,eAAe,SAAS,EAAG2hB,CAAS,EAChE5C,EAAgBgT,EAAenQ,EAAe,SAAS,EAAGD,CAAS,EAAI,OACvEsQ,EAAiBjyB,EAAO,uBAAuB,YAC/CkyB,EAAkBD,EAAiBtN,GAAoB3kB,EAAO,YAA4B2hB,CAAS,EAAI,KAEvG1mB,EAAOy2B,EAAQ,cACfS,EAAmBl3B,GAAM,qBAAqB,WAC9Cm3B,EACJV,EAAQ,mBACR,CAACz2B,GACDA,EAAK,QAAU0mB,GACf,CAACyJ,GAAgBnwB,EAAK,UAAW4jB,CAAa,GAC9C,CAACuM,GAAgBnwB,EAAK,eAAgB+2B,CAAkB,GACxDG,IAAqBJ,GACpBA,IAAiB,CAAC92B,GAAM,WAAa,CAACmwB,GAAgBnwB,EAAK,UAAW8jB,CAAa,GAChFsT,EAAqBX,EAAQ,mBAAsBO,IAAmB,CAACh3B,GAAM,aAAe,CAACmwB,GAAgBnwB,EAAK,YAAai3B,CAAe,IAAQ,CAACD,GAAkB,CAAC,CAACh3B,GAAM,YAEjLq3B,EAAkC,CACtC,GAAGZ,EACH,cAAe,CACb,MAAO/P,EACP,UAAW9C,EACX,eAAgBmT,EAChB,UAAWjT,EACX,YAAakT,EAAkBC,GAAmB,OAAa,MAAA,CACjE,EAGF,GAAInB,GAAej8B,EAAG,gBACpB,OAAOw9B,EAGT,MAAMC,EAAmBD,EAAY,cACrC,GAAI,CAACC,EACH,OAAOD,EAGT,GAAIF,EAAiB,CACnBt9B,EAAG,WAAWA,EAAG,aAAc68B,EAAa,SAAS,EACrD78B,EAAG,WAAWA,EAAG,aAAcy9B,EAAiB,UAAWz9B,EAAG,WAAW,EAEzEA,EAAG,WAAWA,EAAG,aAAc68B,EAAa,UAAU,EACtD78B,EAAG,WAAWA,EAAG,aAAcy9B,EAAiB,eAAgBz9B,EAAG,WAAW,EAE9E,MAAM08B,EAAgBD,GAAiBe,EAAY,cAAe3Q,CAAS,EAC3E7sB,EAAG,WAAWA,EAAG,aAAc68B,EAAa,cAAc,EAC1D78B,EAAG,WAAWA,EAAG,aAAcy9B,EAAiB,WAAaf,EAAe18B,EAAG,WAAW,EAC1FA,EAAG,WAAWA,EAAG,aAAc,IAAI,EACnCw9B,EAAY,cAAgBd,CAC9B,CAEA,OAAIS,GAAkBI,IACpBv9B,EAAG,WAAWA,EAAG,qBAAsB68B,EAAa,WAAW,EAC/D78B,EAAG,WAAWA,EAAG,qBAAsBo9B,GAAmB,IAAI,YAAY,CAAC,EAAGp9B,EAAG,YAAY,EAC7FA,EAAG,WAAWA,EAAG,qBAAsB,IAAI,GAG7Cw9B,EAAY,gBAAkBL,EAC9BK,EAAY,WAAaL,EAAkBC,GAAiB,QAAU,EAAKK,EAAiB,OACxFH,GAAmBC,KACrBC,EAAY,kBAAoB,IAG3BA,CACT,CCtHO,SAASE,GAAYp6B,EAAgD,CAC1E,KAAM,CACJ,GAAAtD,EACA,OAAA01B,EACA,OAAAx1B,EACA,MAAAu7B,EACA,YAAAM,EACA,YAAA4B,EACA,aAAAd,EACA,mBAAAe,EACA,WAAAjS,EACA,gBAAAkS,EACA,iBAAAC,EACA,iBAAAC,EACA,sBAAAC,EACA,YAAAC,EACA,cAAA7B,EACA,gBAAArB,EACA,uBAAAb,EACA,cAAAd,EACA,iBAAAa,CAAA,EACE32B,EAEJtD,EAAG,WAAW,IAAM,IAAM,GAAK,CAAC,EAChCA,EAAG,MAAMA,EAAG,gBAAgB,EAE5B,KAAM,CAAE,KAAA6jB,EAAM,QAAAiX,CAAA,EAAYC,EAAA,EACpBZ,EAAaf,EAAA,EACb1E,GAAc,IAAI,IAAIoG,EAAQ,IAAI92B,GAAQA,EAAK,GAAG,CAAC,EAEzDhE,EAAG,WAAW29B,EAAY,OAAO,EACjC39B,EAAG,gBAAgB29B,EAAY,GAAG,EAClC39B,EAAG,iBAAiB29B,EAAY,QAAS,GAAOjI,EAAO,WAAW,EAClE11B,EAAG,UAAU29B,EAAY,SAAU,CAAC,EACpC39B,EAAG,UAAU29B,EAAY,YAAaC,EAAmB,UAAU,EACnE59B,EAAG,UAAU29B,EAAY,UAAWC,EAAmB,QAAQ,EAC/D59B,EAAG,UAAU29B,EAAY,YAAaC,EAAmB,UAAU,EAEnE,MAAMM,EAA8B,CAAA,EACpC,SAAW,CAAA,CAAGzmB,CAAM,IAAKgkB,EACnB/G,GAAY,IAAIjd,EAAO,GAAG,GACzBwiB,EAAiBxiB,EAAO,OAAQ0iB,CAAU,GAC/C+D,EAAc,KAAKzmB,CAAM,EAE3BymB,EAAc,KAAK,CAACz3B,EAAGC,IAAMD,EAAE,KAAOC,EAAE,IAAI,EAE5C,UAAW+Q,KAAUymB,EACnBzmB,EAAO,SAAWskB,EAClB/7B,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,WAAYyX,EAAO,OAAO,EAC5CzX,EAAG,UAAU29B,EAAY,QAASlmB,EAAO,OAAO,CAAC,EAAGA,EAAO,OAAO,CAAC,EAAGA,EAAO,OAAO,CAAC,EAAGA,EAAO,OAAO,CAAC,CAAC,EACxGzX,EAAG,WAAWA,EAAG,eAAgB,EAAG,CAAC,EAGvC,IAAIm+B,GAAgB,EACpB,MAAMC,GAAgC,CAAA,EACtC,UAAWp6B,KAAQ82B,EAAS,CAC1B,MAAMrjB,EAASgkB,EAAM,IAAIz3B,EAAK,GAAG,EACjC,GAAI,CAACyT,EAAQ,CACX2mB,GAAa,KAAKp6B,CAAI,EACtB,QACF,CACAyT,EAAO,SAAWskB,EAClB/7B,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,WAAYyX,EAAO,OAAO,EAC5CzX,EAAG,UAAU29B,EAAY,QAASlmB,EAAO,OAAO,CAAC,EAAGA,EAAO,OAAO,CAAC,EAAGA,EAAO,OAAO,CAAC,EAAGA,EAAO,OAAO,CAAC,CAAC,EACxGzX,EAAG,WAAWA,EAAG,eAAgB,EAAG,CAAC,EACrCm+B,IAAiB,CACnB,CAEA,MAAME,GAAmCD,GAAa,MAAA,EAChDE,GAA4B,IAC5BC,EAA0B,CAAA,EAC5B1a,EAAO,GAAG0a,EAAc,KAAK1a,EAAO,CAAC,EACrCA,EAAO3jB,EAAO,aAAaq+B,EAAc,KAAK1a,EAAO,CAAC,EAC1D,UAAW2a,KAAgBD,EAAe,CACxC,MAAME,EAAqBvE,EAAuBsE,CAAY,EAC9D,UAAWx6B,KAAQy6B,EACbhD,EAAM,IAAIz3B,EAAK,GAAG,IACtBA,EAAK,WAAas6B,GAClBD,GAAgB,KAAKr6B,CAAI,EAE7B,CACAo4B,EAAc,SAASiC,EAAe,EAEtCr+B,EAAG,YAAYA,EAAG,WAAY,IAAI,EAClCA,EAAG,gBAAgB,IAAI,EAEvB,IAAI0+B,EAAiB,EACrB,OAAI/S,EAAa,IACf3rB,EAAG,OAAOA,EAAG,KAAK,EAClBA,EAAG,UAAUA,EAAG,IAAKA,EAAG,mBAAmB,EAC3CA,EAAG,WAAW68B,EAAa,OAAO,EAClC78B,EAAG,gBAAgB68B,EAAa,GAAG,EACnC78B,EAAG,iBAAiB68B,EAAa,QAAS,GAAOnH,EAAO,WAAW,EACnE11B,EAAG,UAAU68B,EAAa,WAAYoB,CAAW,EACjDj+B,EAAG,UAAU68B,EAAa,kBAAmBkB,CAAgB,EAC7D/9B,EAAG,UAAU68B,EAAa,qBAAsBmB,CAAqB,EACrEh+B,EAAG,UAAU68B,EAAa,aAAciB,CAAgB,EACxD99B,EAAG,UAAU68B,EAAa,SAAU,CAAC,EACrC78B,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,WAAY68B,EAAa,cAAc,EACrDgB,EACF79B,EAAG,aAAaA,EAAG,OAAQ2rB,EAAY3rB,EAAG,aAAc,CAAC,EAEzDA,EAAG,WAAWA,EAAG,OAAQ,EAAG2rB,CAAU,EAExC3rB,EAAG,YAAYA,EAAG,WAAY,IAAI,EAClCA,EAAG,gBAAgB,IAAI,EACvB0+B,EAAiB/S,GAGZ,CACL,KAAA9H,EACA,QAASiX,EAAQ,OACjB,SAAUqD,GACV,OAAQO,EACR,SAAUR,EAAc,OACxB,UAAWC,GACX,YAAaC,GAAa,OAC1B,UAAWF,EAAc,OAASC,IAAiBO,EAAiB,EAAI,EAAI,EAAA,CAEhF,CC7JO,SAASC,GAAgB3+B,EAA+C,CAkD7E,MAAMU,EAAUL,GAAcL,EAjDf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAiBE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAgCiC,EAC5C4+B,EAAUj+B,GAAuBX,EAAIU,EAAS,SAAS,EACvDm+B,EAAUl+B,GAAuBX,EAAIU,EAAS,SAAS,EACvDo+B,EAAWn+B,GAAuBX,EAAIU,EAAS,UAAU,EACzDq+B,EAAcp+B,GAAuBX,EAAIU,EAAS,aAAa,EAC/Ds+B,EAAYr+B,GAAuBX,EAAIU,EAAS,WAAW,EAC3Du+B,EAAct+B,GAAuBX,EAAIU,EAAS,aAAa,EAE/D6C,EAAMvD,EAAG,kBAAA,EACTk/B,EAAMl/B,EAAG,aAAA,EACf,GAAI,CAACuD,GAAO,CAAC27B,EACX,MAAM,IAAI,MAAM,0BAA0B,EAG5Cl/B,EAAG,gBAAgBuD,CAAG,EACtBvD,EAAG,WAAWA,EAAG,aAAck/B,CAAG,EAClCl/B,EAAG,WAAWA,EAAG,aAAc,IAAI,aAAa,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,CAAC,EAAGA,EAAG,WAAW,EAEjH,MAAMm/B,EAAQn/B,EAAG,kBAAkBU,EAAS,OAAO,EAC7C0+B,EAAMp/B,EAAG,kBAAkBU,EAAS,KAAK,EAC/C,GAAIy+B,EAAQ,GAAKC,EAAM,EACrB,MAAM,IAAI,MAAM,8BAA8B,EAEhD,OAAAp/B,EAAG,wBAAwBm/B,CAAK,EAChCn/B,EAAG,wBAAwBo/B,CAAG,EAC9Bp/B,EAAG,oBAAoBm/B,EAAO,EAAGn/B,EAAG,MAAO,GAAO,GAAI,CAAC,EACvDA,EAAG,oBAAoBo/B,EAAK,EAAGp/B,EAAG,MAAO,GAAO,GAAI,CAAC,EAErDA,EAAG,gBAAgB,IAAI,EACvBA,EAAG,WAAWA,EAAG,aAAc,IAAI,EAE5B,CACL,QAAAU,EACA,IAAA6C,EACA,IAAA27B,EACA,QAAAN,EACA,QAAAC,EACA,SAAAC,EACA,YAAAC,EACA,UAAAC,EACA,YAAAC,CAAA,CAEJ,CAEO,SAASI,GAAiBr/B,EAA0C,CA0DzE,MAAMU,EAAUL,GAAcL,EAzDV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,OAiBE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAwCsC,EACtD4+B,EAAUj+B,GAAuBX,EAAIU,EAAS,SAAS,EACvD4+B,EAAa3+B,GAAuBX,EAAIU,EAAS,YAAY,EAC7D6+B,EAAoB5+B,GAAuBX,EAAIU,EAAS,mBAAmB,EAC3E8+B,EAAuB7+B,GAAuBX,EAAIU,EAAS,sBAAsB,EACjF++B,EAAW9+B,GAAuBX,EAAIU,EAAS,UAAU,EACzDg/B,EAAe/+B,GAAuBX,EAAIU,EAAS,cAAc,EAEjE6C,EAAMvD,EAAG,kBAAA,EACT2/B,EAAY3/B,EAAG,aAAA,EACf4/B,EAAa5/B,EAAG,aAAA,EAChB6/B,EAAiB7/B,EAAG,aAAA,EACpB8/B,EAAc9/B,EAAG,aAAA,EACjB+/B,EAAiB//B,EAAG,cAAA,EAC1B,GAAI,CAACuD,GAAO,CAACo8B,GAAa,CAACC,GAAc,CAACC,GAAkB,CAACC,GAAe,CAACC,EAC3E,MAAM,IAAI,MAAM,gCAAgC,EAGlD//B,EAAG,gBAAgBuD,CAAG,EAEtBvD,EAAG,WAAWA,EAAG,aAAc2/B,CAAS,EACxC3/B,EAAG,WAAWA,EAAG,aAAc,EAAGA,EAAG,YAAY,EACjD,MAAMggC,EAAShgC,EAAG,kBAAkBU,EAAS,WAAW,EACxD,GAAIs/B,EAAS,EACX,MAAM,IAAI,MAAM,oCAAoC,EAEtDhgC,EAAG,wBAAwBggC,CAAM,EACjChgC,EAAG,oBAAoBggC,EAAQ,EAAGhgC,EAAG,MAAO,GAAO,EAAG,CAAC,EAEvDA,EAAG,WAAWA,EAAG,aAAc4/B,CAAU,EACzC5/B,EAAG,WAAWA,EAAG,aAAc,EAAGA,EAAG,YAAY,EACjD,MAAMigC,EAAUjgC,EAAG,kBAAkBU,EAAS,OAAO,EACrD,GAAIu/B,EAAU,EACZ,MAAM,IAAI,MAAM,gCAAgC,EAElDjgC,EAAG,wBAAwBigC,CAAO,EAClCjgC,EAAG,qBAAqBigC,EAAS,EAAGjgC,EAAG,eAAgB,EAAG,CAAC,EAE3DA,EAAG,WAAWA,EAAG,aAAc6/B,CAAc,EAC7C7/B,EAAG,WAAWA,EAAG,aAAc,EAAGA,EAAG,YAAY,EACjD,MAAMkgC,EAAclgC,EAAG,kBAAkBU,EAAS,WAAW,EAC7D,GAAIw/B,EAAc,EAChB,MAAM,IAAI,MAAM,qCAAqC,EAEvD,OAAAlgC,EAAG,wBAAwBkgC,CAAW,EACtClgC,EAAG,qBAAqBkgC,EAAa,EAAGlgC,EAAG,cAAe,EAAG,CAAC,EAE9DA,EAAG,WAAWA,EAAG,qBAAsB8/B,CAAW,EAClD9/B,EAAG,WAAWA,EAAG,qBAAsB,EAAGA,EAAG,YAAY,EAEzDA,EAAG,gBAAgB,IAAI,EACvBA,EAAG,WAAWA,EAAG,aAAc,IAAI,EACnCA,EAAG,WAAWA,EAAG,qBAAsB,IAAI,EAE3CA,EAAG,YAAYA,EAAG,WAAY+/B,CAAc,EAC5C//B,EAAG,cAAcA,EAAG,WAAYA,EAAG,eAAgBA,EAAG,aAAa,EACnEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,eAAgBA,EAAG,aAAa,EACnEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,OAAO,EACjEA,EAAG,cAAcA,EAAG,WAAYA,EAAG,mBAAoBA,EAAG,OAAO,EACjEA,EAAG,WAAWA,EAAG,WAAY,EAAGA,EAAG,KAAM,EAAG,EAAG,EAAGA,EAAG,KAAMA,EAAG,cAAe,IAAI,WAAW,CAAC,IAAK,IAAK,IAAK,GAAG,CAAC,CAAC,EACjHA,EAAG,YAAYA,EAAG,WAAY,IAAI,EAE3B,CACL,QAAAU,EACA,IAAA6C,EACA,UAAAo8B,EACA,WAAAC,EACA,eAAAC,EACA,YAAAC,EACA,eAAAC,EACA,QAAAnB,EACA,WAAAU,EACA,kBAAAC,EACA,qBAAAC,EACA,SAAAC,EACA,aAAAC,CAAA,CAEJ,CCpOO,SAASvH,GAAoBjY,EAAwC,CAC1EA,EAAM,UAAY,KACdA,EAAM,QAAU,OAClB,qBAAqBA,EAAM,KAAK,EAChCA,EAAM,MAAQ,KAElB,CAEO,SAASigB,GAAmB78B,EAA0C,CAC3E,KAAM,CAAE,MAAA4c,EAAO,OAAAwV,EAAQ,OAAA0K,EAAQ,WAAAC,EAAY,OAAArI,EAAQ,SAAAsI,GAAah9B,EAC1D8gB,EAAOsR,EAAO,aAAA,EACpByC,GAAoBjY,CAAK,EACzBA,EAAM,UAAY,CAChB,QAAS5W,GAAA,EACT,WAAY,KAAK,IAAI,EAAG+2B,CAAU,EAClC,KAAAjc,EACA,GAAIgc,EACJ,OAAApI,CAAA,EAGF,MAAM7rB,EAAO,IAAY,CACvB,MAAMo0B,EAAYrgB,EAAM,UACxB,GAAI,CAACqgB,EAAW,OAEhB,MAAMC,EAAU,KAAK,IAAI,EAAGl3B,GAAA,EAAUi3B,EAAU,OAAO,EACjDE,EAAOF,EAAU,YAAc,EAAI,EAAI93B,EAAM+3B,EAAUD,EAAU,WAAY,EAAG,CAAC,EACvF,IAAIG,EAAQD,EACZ,GAAI,CACFC,EAAQH,EAAU,OAAOE,CAAI,CAC/B,MAAQ,CACNC,EAAQD,CACV,CAcA,GAbK,OAAO,SAASC,CAAK,IACxBA,EAAQD,GAEVC,EAAQj4B,EAAMi4B,EAAO,EAAG,CAAC,EAEzBhL,EAAO,aAAa,CAClB,KAAM6K,EAAU,KAAK,MAAQA,EAAU,GAAG,KAAOA,EAAU,KAAK,MAAQG,EACxE,QAASH,EAAU,KAAK,SAAWA,EAAU,GAAG,QAAUA,EAAU,KAAK,SAAWG,EACpF,QAASH,EAAU,KAAK,SAAWA,EAAU,GAAG,QAAUA,EAAU,KAAK,SAAWG,EACpF,YAAaH,EAAU,KAAK,aAAeA,EAAU,GAAG,YAAcA,EAAU,KAAK,aAAeG,CAAA,CACrG,EACDJ,EAAA,EAEIG,GAAQ,EAAG,CACbvgB,EAAM,UAAY,KAClBA,EAAM,MAAQ,KACd,MACF,CAEAA,EAAM,MAAQ,sBAAsB/T,CAAI,CAC1C,EAEA+T,EAAM,MAAQ,sBAAsB/T,CAAI,CAC1C,CCtDO,SAASw0B,GAAyBC,EAAuD,CAC9F,MAAMloB,EAAU,KAAK,IAAIkoB,EAAU,GAAK,IAAI,EACtCjoB,EAAU,KAAK,IAAI,EAAGioB,EAAU,CAAC,EACvC,MAAO,CACL,QAAAloB,EACA,QAAS,KAAK,IAAIA,EAASC,CAAO,CAAA,CAEtC,CAEO,SAASkoB,GAAkBD,EAAiBE,EAAgCC,EAAsE,CACvJ,MAAMC,EAAWL,GAAyBC,CAAO,EACjD,IAAIloB,EAAUooB,GAAmBE,EAAS,QACtCroB,EAAUooB,GAAmBC,EAAS,QAC1C,OAAAtoB,EAAU,KAAK,IAAI,KAAMA,CAAO,EAChCC,EAAU,KAAK,IAAI,KAAMA,CAAO,EAC5BD,EAAUC,IACZD,EAAUC,GAEL,CAAE,QAAAD,EAAS,QAAAC,CAAA,CACpB,CAEO,SAASsoB,GACdvL,EACAhd,EACAC,EACApX,EACA82B,EACc,CACd,MAAM6I,EAAUxL,EAAO,aAAA,EACjBtnB,EAA0B,CAC9B,KAAM,OAAO7M,EAAK,MAAS,UAAY,OAAO,SAASA,EAAK,IAAI,EAAIkH,EAAMlH,EAAK,KAAMmX,EAASC,CAAO,EAAIuoB,EAAQ,KACjH,QAAS,OAAO3/B,EAAK,SAAY,UAAY,OAAO,SAASA,EAAK,OAAO,EAAIA,EAAK,QAAU2/B,EAAQ,QACpG,QAAS,OAAO3/B,EAAK,SAAY,UAAY,OAAO,SAASA,EAAK,OAAO,EAAIA,EAAK,QAAU2/B,EAAQ,QACpG,YAAa,OAAO3/B,EAAK,aAAgB,UAAY,OAAO,SAASA,EAAK,WAAW,EAAIA,EAAK,YAAc2/B,EAAQ,WAAA,EAGtHxL,EAAO,aAAatnB,CAAS,EAC7BiqB,EAAA,EACA,MAAM+H,EAAS1K,EAAO,aAAA,EACtB,OAAAA,EAAO,aAAawL,CAAO,EACpBd,CACT,CAEO,SAASe,GACdjhC,EACAkhC,EACAC,EACA3oB,EACAC,EAC2C,CAC3C,MAAMnX,EAAO,KAAK,IAAI4/B,EAAgBlhC,EAAO,MAAOmhC,EAAiBnhC,EAAO,MAAM,EAC5E4E,EAAW,OAAO,SAAStD,CAAI,GAAKA,EAAO,EAAIA,EAAO,EACtD8/B,EAAc74B,EAAM3D,EAAU4T,EAASC,CAAO,EAC9C4oB,EAAgBH,EAAgBE,EAChCE,EAAgBH,EAAiBC,EAEvC,MAAO,CACL,QAASx8B,EACT,OAAQ,CACN,KAAMw8B,EACN,SAAUphC,EAAO,MAAQqhC,GAAiB,GAC1C,SAAUrhC,EAAO,OAASshC,GAAiB,GAC3C,YAAa,CAAA,CACf,CAEJ,CAEO,SAASC,GACd/L,EACAhd,EACAC,EACAqgB,EACAr3B,EACAC,EAC8B,CAC9B,MAAMse,EAAQwV,EAAO,aAAA,EACfgM,EAAWj5B,EAAMyX,EAAM,KAAO8Y,EAAQtgB,EAASC,CAAO,EAC5D,GAAI+oB,IAAaxhB,EAAM,KAAM,OAAO,KAEpC,KAAM,CAAC/d,EAAQC,CAAM,EAAIszB,EAAO,cAAc/zB,EAASC,CAAO,EACxD+/B,EAAKjM,EAAO,gBAAA,EACZ5zB,EAAKH,EAAUggC,EAAG,MAAQ,GAC1B5/B,EAAKH,EAAU+/B,EAAG,OAAS,GAC3B3/B,EAAMf,GAAUif,EAAM,WAAW,EACjCje,EAAM,KAAK,IAAID,CAAG,EAClBE,EAAM,KAAK,IAAIF,CAAG,EAClB42B,EAAW92B,EAAK4/B,EAAYz/B,EAAOF,EAAK2/B,EAAYx/B,EACpD22B,EAAW/2B,EAAK4/B,EAAYx/B,EAAOH,EAAK2/B,EAAYz/B,EACpD43B,EAAc13B,EAASy2B,EACvBkB,EAAc13B,EAASy2B,EAE7B,MAAO,CACL,KAAM6I,EACN,QAAS7H,EAAc8H,EAAG,OAAS,EAAID,GACvC,QAAS5H,EAAc6H,EAAG,QAAU,EAAID,EAAA,CAE5C,CC9CO,MAAME,EAAgB,CAkF3B,YAAY7gC,EAA2Bb,EAAwBoD,EAAkC,CAAA,EAAI,CAjFpFlC,EAAA,eACAA,EAAA,eACAA,EAAA,WACAA,EAAA,cAAS,IAAID,IACbC,EAAA,0BACAA,EAAA,gBACAA,EAAA,oBACAA,EAAA,sBACAA,EAAA,0BACAA,EAAA,uBACTA,EAAA,oBACAA,EAAA,qBACSA,EAAA,sBAETA,EAAA,kBACAA,EAAA,iBAAY,IACZA,EAAA,mBAAc,IACdA,EAAA,aAAuB,MACvBA,EAAA,mBAAc,GACdA,EAAA,wBAAqC,CAC3C,SAAU,GACV,KAAM,OACN,mBAAoB,KACpB,UAAW,KACX,aAAc,EACd,aAAc,CAAA,GAERA,EAAA,yBAAoB,IACpBA,EAAA,sBAAiB,IACjBA,EAAA,0CAAqCu0B,IACrCv0B,EAAA,sBACAA,EAAA,eAAU,GACVA,EAAA,eAAU,MACVA,EAAA,eAAU,GACVA,EAAA,uBAAiC,MACjCA,EAAA,uBAAiC,MACjCA,EAAA,gCAA2B,GAC3BA,EAAA,4BAA8Cu2B,IAC9Cv2B,EAAA,0BAAgD,CACtD,UAAW,KACX,MAAO,IAAA,GAEDA,EAAA,kBAAa,GACbA,EAAA,uBAAkB,IAClBA,EAAA,yBAAoB,IACpBA,EAAA,wBAAmB,GACnBA,EAAA,sBAAkCm1B,GAAoBT,EAAwB,GAC9E10B,EAAA,wBAAmB,GACnBA,EAAA,6BAAwB,GACxBA,EAAA,0BAAmD,CACzD,WAAY,EACZ,SAAU,EACV,WAAY,CAAA,GAENA,EAAA,qBAAqC,MACrCA,EAAA,wBAAuD,MACvDA,EAAA,qBAA6C,IAAI,WAAW,CAAC,GAC7DA,EAAA,iBAAY,KAEHA,EAAA,yBACAA,EAAA,yBACAA,EAAA,uBACAA,EAAA,mBACAA,EAAA,yBACAA,EAAA,yBACAA,EAAA,yBACAA,EAAA,6BAgBf,KAAK,OAASL,EACd,KAAK,OAASb,EACd,KAAK,kBAAoBoD,EAAQ,kBACjC,KAAK,QAAUA,EAAQ,QACvB,KAAK,YAAcA,EAAQ,YAC3B,KAAK,cAAgBA,EAAQ,cAC7B,KAAK,kBAAoBA,EAAQ,kBACjC,KAAK,UAAYA,EAAQ,WAAa,GACtC,KAAK,cAAgB,KAAK,IAAI,GAAI,KAAK,MAAMA,EAAQ,eAAiB,GAAG,CAAC,EAC1E,KAAK,eAAiBA,EAAQ,gBAAkB,GAChD,KAAK,mCACH,OAAOA,EAAQ,oCAAuC,UAAY,OAAO,SAASA,EAAQ,kCAAkC,EACxH,KAAK,IAAI,EAAGA,EAAQ,kCAAkC,EACtDqyB,GACN,KAAK,eAAiBe,GAAwBpzB,EAAQ,eAAe,EACrE,KAAK,iBAAmB6zB,GAAqB7zB,EAAQ,gBAAgB,EACrE,KAAK,sBAAwB8zB,GAA+B9zB,EAAQ,qBAAqB,EACzF,KAAK,mBAAqBg0B,GAA+Bh0B,EAAQ,kBAAkB,EACnF,KAAK,gBAAkBw0B,GAAsBx0B,EAAQ,OAAO,EAC5D,KAAK,gBAAkBw0B,GAAsBx0B,EAAQ,OAAO,EAC5D,KAAK,yBAA2Bs0B,GAAgCt0B,EAAQ,gBAAgB,QAAQ,EAChG,KAAK,qBAAuBy0B,GAA0Bz0B,EAAQ,gBAAgB,MAAM,EAEpF,MAAMtD,EAAKe,EAAO,WAAW,SAAU,CACrC,MAAO,GACP,UAAW,GACX,MAAO,GACP,QAAS,GACT,gBAAiB,kBAAA,CAClB,EACD,GAAI,CAACf,EACH,MAAM,IAAI,MAAM,sBAAsB,EAExC,KAAK,GAAKA,EAEV,KAAK,YAAc2+B,GAAgB,KAAK,EAAE,EAC1C,KAAK,aAAeU,GAAiB,KAAK,EAAE,EAC5C,KAAK,cAAgB,IAAI/K,GAAc,CACrC,UAAW,KAAK,UAChB,eAAgBhxB,EAAQ,eAAe,gBAAkB,GACzD,WAAYA,EAAQ,eAAe,YAAc,EACjD,iBAAkBA,EAAQ,eAAe,kBAAoB,IAC7D,gBAAiBA,EAAQ,eAAe,iBAAmB,KAC3D,WAAY,CAACU,EAAMI,IACjBy9B,GAAgB,CACd,GAAI,KAAK,GACT,MAAO,KAAK,MACZ,KAAA79B,EACA,OAAAI,EACA,YAAa,KAAK,YAClB,cAAe,KAAK,cACpB,UAAW,KAAK,UAChB,YAAa,KAAK,YAClB,cAAe,IAAM,KAAK,cAAA,CAAc,CACzC,EACH,YAAa,CAACJ,EAAMM,EAAOw9B,IAAiB,CAC1C,KAAK,cAAc,CAAE,KAAA99B,EAAM,MAAAM,EAAO,aAAAw9B,EAAc,EAChD,QAAQ,KAAK,mBAAoB99B,EAAK,IAAKM,CAAK,CAClD,CAAA,CACD,EAED,KAAK,eAAiB,IAAI,eAAe,IAAM,KAAK,QAAQ,EAC5D,KAAK,eAAe,QAAQvD,CAAM,EAElC,MAAMghC,EAAgBxG,GAA4B,CAChD,OAAQ,KAAK,OACb,MAAO,KAAK,iBACZ,qBAAsB,IAAM,KAAK,kBACjC,kBAAmB,IAAM,KAAK,eAC9B,sCAAuC,IAAM,KAAK,mCAClD,oBAAqB,IAAM,KAAK,oBAAA,EAChC,OAAQ,KAAK,OACb,OAAQ,KAAK,OACb,cAAe,IAAM,KAAK,oBAAoB,KAAK,OAAO,cAAc,EACxE,cAAe,IAAM,KAAK,cAAA,EAC1B,OAAQ,CAACvC,EAAQ/yB,EAAGC,IAAM,KAAK,OAAO8yB,EAAQ/yB,EAAGC,CAAC,CAAA,CACnD,EACD,KAAK,iBAAmB67B,EAAc,YACtC,KAAK,iBAAmBA,EAAc,YACtC,KAAK,eAAiBA,EAAc,UACpC,KAAK,WAAaA,EAAc,MAChC,KAAK,iBAAmBA,EAAc,YACtC,KAAK,iBAAmBA,EAAc,YACtC,KAAK,iBAAoBzgB,GAAiB,KAAK,mBAAmBA,CAAK,EACvE,KAAK,qBAAwBA,GAAiB,KAAK,uBAAuBA,CAAK,EAE/EiU,GAAgCx0B,EAAQ,KAAK,mBAAmB,EAEhE,KAAK,WAAW,CAAE,SAAU,CAAA,CAAG,EAC/B,KAAK,OAAA,CACP,CAxGQ,mBAA4C,CAClD,MAAO,CACL,YAAa,KAAK,iBAClB,YAAa,KAAK,iBAClB,UAAW,KAAK,eAChB,MAAO,KAAK,WACZ,YAAa,KAAK,iBAClB,YAAa,KAAK,iBAClB,YAAa,KAAK,iBAClB,gBAAiB,KAAK,oBAAA,CAE1B,CA+FQ,iBAAwB,CAC9B,MAAM8K,EAASg1B,GAAkB,KAAK,QAAS,KAAK,gBAAiB,KAAK,eAAe,EACzF,KAAK,QAAUh1B,EAAO,QACtB,KAAK,QAAUA,EAAO,OACxB,CAEQ,uBAAuBtK,EAA2C,CACxE,OAAOygC,GAA8B,KAAK,OAAQ,KAAK,QAAS,KAAK,QAASzgC,EAAM,IAAM0gC,GAAsB,KAAK,OAAQ,KAAK,MAAM,CAAC,CAC3I,CAEQ,qBAA4B,CAClCC,GAA2B,KAAK,kBAAkB,CACpD,CAEQ,mBAAmB9B,EAAsBC,EAAoBrI,EAAqC,CACxGmI,GAAmB,CACjB,MAAO,KAAK,mBACZ,OAAQ,KAAK,OACb,OAAAC,EACA,WAAAC,EACA,OAAArI,EACA,SAAU,IAAM,CACdiK,GAAsB,KAAK,OAAQ,KAAK,MAAM,EAC9C,KAAK,oBAAoB,KAAK,OAAO,aAAA,CAAc,EACnD,KAAK,cAAA,CACP,CAAA,CACD,CACH,CAEQ,uBAA4C,CAClD,MAAO,CACL,WAAY,KAAK,WACjB,gBAAiB,KAAK,gBACtB,kBAAmB,KAAK,kBACxB,cAAe,KAAK,cACpB,cAAe,KAAK,cACpB,iBAAkB,KAAK,iBACvB,iBAAkB,KAAK,gBAAA,CAE3B,CAEQ,wBAAwBrF,EAAmC,CACjE,KAAK,WAAaA,EAAQ,WAC1B,KAAK,gBAAkBA,EAAQ,gBAC/B,KAAK,kBAAoBA,EAAQ,kBACjC,KAAK,cAAgBA,EAAQ,cAC7B,KAAK,cAAgBA,EAAQ,cAC7B,KAAK,iBAAmBA,EAAQ,iBAChC,KAAK,iBAAmBA,EAAQ,gBAClC,CAEQ,wBAAwBr7B,EAAoB4gC,EAAkB,GAAY,CAC5EA,GACF,KAAK,oBAAA,EAEP,KAAK,OAAO,aAAa5gC,CAAI,EAC7B,KAAK,oBAAoB,KAAK,OAAO,aAAA,CAAc,EACnD,KAAK,cAAA,CACP,CAEA,aAAasI,EAAqB,CAChC,KAAK,UAAY,OAAOA,GAAS,EAAE,EACnC,KAAK,cAAc,aAAa,KAAK,SAAS,CAChD,CAEA,aAAa6O,EAAoCC,EAA0C,CACzF,MAAMypB,EAAkBtK,GAAsBpf,CAAO,EAC/C2pB,EAAkBvK,GAAsBnf,CAAO,EACrD,GAAI,KAAK,kBAAoBypB,GAAmB,KAAK,kBAAoBC,EACvE,OAGF,KAAK,gBAAkBD,EACvB,KAAK,gBAAkBC,EACvB,KAAK,gBAAA,EAEL,MAAMjC,EAAS,KAAK,uBAAuB,EAAE,EACvCc,EAAU,KAAK,OAAO,aAAA,EACxBx3B,GAAgBw3B,EAASd,CAAM,GAGnC,KAAK,wBAAwBA,CAAM,CACrC,CAEA,kBAAkB98B,EAA4D,CAC5E,KAAK,yBAA2Bs0B,GAAgCt0B,GAAS,QAAQ,EACjF,KAAK,qBAAuBy0B,GAA0Bz0B,GAAS,MAAM,CACvE,CAEA,aAAa/B,EAA6B+gC,EAA6C,CACrF,MAAMlC,EAAS,KAAK,uBAAuB7+B,CAAI,EACzC2/B,EAAU,KAAK,OAAO,aAAA,EAC5B,GAAIx3B,GAAgBw3B,EAASd,CAAM,EAAG,OAEtC,MAAMC,EAAazI,GAAgC0K,GAAY,UAAY,KAAK,wBAAwB,EAClGtK,EAASD,GAA0BuK,GAAY,QAAU,KAAK,oBAAoB,EACxF,GAAIjC,GAAc,EAAG,CACnB,KAAK,wBAAwBD,CAAM,EACnC,MACF,CAEA,KAAK,mBAAmBA,EAAQC,EAAYrI,CAAM,CACpD,CAEA,cAA6B,CAC3B,OAAO,KAAK,OAAO,aAAA,CACrB,CAEA,cAAqD,CACnD,MAAO,CAAE,QAAS,KAAK,QAAS,QAAS,KAAK,OAAA,CAChD,CAEA,gBAAgBxtB,EAA6C,CAC3D,MAAMgzB,EAAc+E,GAAuB,KAAK,sBAAA,EAAyB,KAAK,GAAI,KAAK,aAAc,KAAK,YAAa/3B,CAAM,EAC7H,KAAK,wBAAwBgzB,CAAW,EACpC,GAAChzB,GAAUA,EAAO,SAAW,IAGjC,KAAK,cAAA,CACP,CAEA,aAAaU,EAA+C,CAC1D,MAAMsyB,EAAcgF,GAAoB,KAAK,sBAAA,EAAyB,KAAK,GAAI,KAAK,aAAc,KAAK,YAAat3B,CAAM,EAC1H,KAAK,wBAAwBsyB,CAAW,EACxC,KAAK,cAAA,CACP,CAEA,mBAAmBiF,EAAuB,CACxC,MAAMlhC,EAAO,EAAQkhC,EACjB,KAAK,oBAAsBlhC,IAC/B,KAAK,kBAAoBA,EACrBA,QAAW,WAAA,EACjB,CAEA,mBAAmBo1B,EAA2D,CAC5E,MAAM+L,EAAYhM,GAAwBC,CAAe,EACrDI,GAAuB,KAAK,eAAgB2L,CAAS,IACzD,KAAK,eAAiBA,EACtB,KAAK,cAAA,EACP,CAEA,oBAAoBle,EAAwC,CAC1D,MAAMjjB,EAAO41B,GAAqB3S,CAAK,EACnC,KAAK,mBAAqBjjB,IAC9B,KAAK,iBAAmBA,EACxB,KAAK,cAAA,EACP,CAEA,yBAAyBohC,EAA0C,CACjE,MAAMphC,EAAO61B,GAA+BuL,CAAO,EAC/C,KAAK,wBAA0BphC,IACnC,KAAK,sBAAwBA,EAC7B,KAAK,cAAA,EACP,CAEA,sBAAsBg2B,EAA0D,CAC9E,MAAMh2B,EAAO+1B,GAA+BC,CAAQ,EAC9CpxB,EAAO,KAAK,mBACdA,EAAK,aAAe5E,EAAK,YAAc4E,EAAK,WAAa5E,EAAK,UAAY4E,EAAK,aAAe5E,EAAK,aAGvG,KAAK,mBAAqBA,EAC1B,KAAK,cAAA,EACP,CAEA,YAAmB,CACjBqhC,GAAgB,KAAK,OAAQ,KAAK,gBAAgB,CACpD,CAEA,cAAcjb,EAAiBC,EAAmC,CAChE,MAAMrjB,EAAO,KAAK,OAAO,sBAAA,EACnB5B,EAAKglB,EAAUpjB,EAAK,KACpB3B,EAAKglB,EAAUrjB,EAAK,IAC1B,OAAO,KAAK,OAAO,cAAc5B,EAAIC,CAAE,CACzC,CAEA,cAAcT,EAAgBC,EAAkC,CAC9D,OAAO,KAAK,OAAO,cAAcD,EAAQC,CAAM,CACjD,CAEA,cAAcD,EAAgBC,EAAgBkgC,EAA6C,CACzF,GAAI,CAAC,OAAO,SAASngC,CAAM,GAAK,CAAC,OAAO,SAASC,CAAM,EAAG,OAC1D,MAAM8d,EAAQ,KAAK,OAAO,aAAA,EACpB1e,EAAO,KAAK,IAAI,KAAM0e,EAAM,IAAI,EAChCyhB,EAAK,KAAK,OAAO,gBAAA,EACvB,KAAK,aACH,CACE,QAASx/B,EAASw/B,EAAG,OAAS,EAAIngC,GAClC,QAASY,EAASu/B,EAAG,QAAU,EAAIngC,EAAA,EAErC8gC,CAAA,CAEJ,CAEA,gBAAmE,CACjE,OAAO,KAAK,OAAO,eAAA,CACrB,CAEA,cAAcA,EAA6C,CACzD,MAAMpiB,EAAQ,KAAK,OAAO,aAAA,EACtB,KAAK,IAAIA,EAAM,WAAW,EAAI,MAClC,KAAK,aAAa,CAAE,YAAa,CAAA,EAAKoiB,CAAU,CAClD,CAEA,oBAA6B,CAC3B,MAAM9gC,EAAO,KAAK,IAAI,KAAM,KAAK,OAAO,aAAA,EAAe,IAAI,EACrDme,EAAiB,KAAK,OAAO,YAAc,KAAK,KAAKne,CAAI,EACzDs1B,EAAOE,GAA4BrX,EAAgB,KAAK,cAAc,EAC5E,OAAOlX,EAAMquB,EAAMlB,GAAmBC,EAAiB,CACzD,CAEA,WAAWyM,EAA6C,CACtD,MAAM/9B,EAAO,KAAK,OAAO,sBAAA,EACnBs+B,EAAK,KAAK,IAAI,EAAGt+B,EAAK,OAAS,CAAC,EAChCu+B,EAAK,KAAK,IAAI,EAAGv+B,EAAK,QAAU,CAAC,EACjCw+B,EAAY5B,GAAwB,KAAK,OAAQ0B,EAAIC,EAAI,KAAK,QAAS,KAAK,OAAO,EACzF,KAAK,QAAUC,EAAU,QACzB,KAAK,gBAAA,EACL,KAAK,aAAaA,EAAU,OAAQT,CAAU,CAChD,CAEA,OAAOtJ,EAAgBr3B,EAAiBC,EAAiB0gC,EAA6C,CACpG,MAAMlC,EAASqB,GAAoB,KAAK,OAAQ,KAAK,QAAS,KAAK,QAASzI,EAAQr3B,EAASC,CAAO,EAC/Fw+B,GACL,KAAK,aAAaA,EAAQkC,CAAU,CACtC,CAEA,QAAe,CACb,GAAI,KAAK,WAAa,KAAK,aAAe,KAAK,GAAG,gBAAiB,OACnE,MAAMU,EAAe,KAAK,QAAU15B,GAAA,EAAU,EAC9C,KAAK,aAAe,EAEpB,MAAMyY,EAAS2b,GAAY,CACzB,GAAI,KAAK,GACT,OAAQ,KAAK,OACb,OAAQ,KAAK,OACb,MAAO,KAAK,MACZ,YAAa,KAAK,YAClB,YAAa,KAAK,YAClB,aAAc,KAAK,aACnB,mBAAoB,KAAK,mBACzB,WAAY,KAAK,WACjB,gBAAiB,KAAK,gBACtB,iBAAkB,KAAK,iBACvB,iBAAkB,KAAK,iBACvB,sBAAuB,KAAK,sBAC5B,YAAa,KAAK,mBAAA,EAClB,cAAe,KAAK,cACpB,gBAAiB,IAAMuF,GAAuB,KAAK,OAAQ,KAAK,MAAM,EACtE,uBAAwBpf,GAAQqf,GAA8B,KAAK,OAAQ,KAAK,OAAQrf,CAAI,EAC5F,cAAe,IAAMsf,GAAqB,KAAK,MAAM,EACrD,iBAAkBC,EAAA,CACnB,EACD,GAAI,KAAK,QAAS,CAChB,MAAMC,EAAiB,KAAK,cAAc,YAAA,EAC1C,KAAK,QAAQ,CACX,KAAMthB,EAAO,KACb,QAASA,EAAO,QAChB,SAAUA,EAAO,SACjB,OAAQA,EAAO,OACf,SAAUA,EAAO,SACjB,MAAO,KAAK,MAAM,KAClB,SAAUshB,EAAe,SACzB,OAAQA,EAAe,OACvB,QAASA,EAAe,QACxB,OAAQA,EAAe,OACvB,QAASA,EAAe,QACxB,UAAWthB,EAAO,UAClB,YAAaA,EAAO,YACpB,UAAWA,EAAO,UAClB,QAASzY,KAAU05B,CAAA,CACpB,CACH,CACF,CAEA,eAAsB,CAChB,KAAK,QAAU,MAAQ,KAAK,WAAa,KAAK,aAAe,KAAK,GAAG,cAAA,IACzE,KAAK,MAAQ,sBAAsB,IAAM,CACvC,KAAK,MAAQ,KACb,KAAK,OAAA,CACP,CAAC,EACH,CAEA,QAAe,CACbvN,GAAqB,KAAK,OAAQ,KAAK,GAAI,KAAK,MAAM,EACtD,KAAK,cAAA,CACP,CAEQ,mBAAmBnU,EAAoB,CAC7C,MAAMS,EAASoa,GAAkB,CAC/B,MAAA7a,EACA,UAAW,KAAK,UAChB,YAAa,KAAK,YAClB,MAAO,KAAK,MACZ,oBAAqB,IAAM,KAAK,oBAAA,EAChC,WAAY,IAAM,KAAK,WAAA,EACvB,cAAe,KAAK,cACpB,MAAO,KAAK,MACZ,cAAe,KAAK,aAAA,CACrB,EACIS,EAAO,UACZ,KAAK,MAAQA,EAAO,MACpB,KAAK,YAAc,GACnB,KAAK,kBAAoB,GAC3B,CAEQ,uBAAuBuhB,EAAqB,CAC9C,KAAK,YACT,KAAK,YAAc,GACnB,KAAK,MAAM,MAAA,EAEX,KAAK,YAAc3E,GAAgB,KAAK,EAAE,EAC1C,KAAK,aAAeU,GAAiB,KAAK,EAAE,EAC5C,KAAK,kBAAoB,GAErB,KAAK,kBAAoB,KAAK,iBAAiB,OAAS,GAC1D,KAAK,gBAAgB,KAAK,gBAAgB,EAExC,KAAK,cACP,KAAK,aAAa,KAAK,aAAa,EAEpC,KAAK,WAAa,EAGpB,KAAK,OAAA,EACL,KAAK,cAAA,EACL,KAAK,oBAAA,EACP,CAEA,SAAgB,CACd,MAAMtd,EAASwa,GAAgB,CAC7B,UAAW,KAAK,UAChB,MAAO,KAAK,MACZ,oBAAqB,IAAM,KAAK,oBAAA,EAChC,eAAgB,KAAK,eACrB,2BAA4B,IAAM/G,GAAmC,KAAK,OAAQ,KAAK,mBAAmB,EAC1G,WAAY,IAAM,KAAK,WAAA,EACvB,cAAe,KAAK,cACpB,YAAa,KAAK,YAClB,GAAI,KAAK,GACT,MAAO,KAAK,MACZ,YAAa,KAAK,YAClB,aAAc,KAAK,YAAA,CACpB,EACIzT,EAAO,aACZ,KAAK,UAAY,GACjB,KAAK,MAAQA,EAAO,MACtB,CACF,CC1jBA,MAAMwhB,GAAiC,EAWhC,SAASC,GAAgBhlB,EAAmBH,EAAgC,CACjF,OAAOG,EAAO,IAAMH,CACtB,CAEA,SAASolB,GAAuBzrB,EAAYC,EAAYlV,EAAYE,EAAYD,EAAYE,EAAoB,CAC9G,MAAM4L,EAAM9L,EAAKD,EACXgM,EAAM7L,EAAKD,EACXygC,EAAW50B,EAAMA,EAAMC,EAAMA,EACnC,GAAI20B,GAAY,MAAO,CACrB,MAAM5hC,EAAKkW,EAAKjV,EACVhB,EAAKkW,EAAKhV,EAChB,OAAOnB,EAAKA,EAAKC,EAAKA,CACxB,CACA,MAAMwJ,EAAI9C,IAAQuP,EAAKjV,GAAM+L,GAAOmJ,EAAKhV,GAAM8L,GAAO20B,EAAU,EAAG,CAAC,EAC9Dvb,EAAKplB,EAAK+L,EAAMvD,EAChB6c,EAAKnlB,EAAK8L,EAAMxD,EAChBzJ,EAAKkW,EAAKmQ,EACVpmB,EAAKkW,EAAKmQ,EAChB,OAAOtmB,EAAKA,EAAKC,EAAKA,CACxB,CAEA,SAAS4hC,GAAgB19B,EAAWC,EAAWP,EAAwBi+B,EAAgC,CACrG,QAAS,EAAI,EAAG,EAAIj+B,EAAK,OAAQ,GAAK,EAAG,CACvC,MAAMQ,EAAOR,EAAK,EAAI,CAAC,EACjBpE,EAAOoE,EAAK,CAAC,EACnB,GAAI89B,GAAuBx9B,EAAGC,EAAGC,EAAK,CAAC,EAAGA,EAAK,CAAC,EAAG5E,EAAK,CAAC,EAAGA,EAAK,CAAC,CAAC,GAAKqiC,EACtE,MAAO,EAEX,CACA,MAAO,EACT,CAEA,SAASC,GAA0B59B,EAAWC,EAAWL,EAA6Bi+B,EAA8B,CAClH,GAAI79B,EAAIJ,EAAQ,KAAOi+B,GAAe79B,EAAIJ,EAAQ,KAAOi+B,GAAe59B,EAAIL,EAAQ,KAAOi+B,GAAe59B,EAAIL,EAAQ,KAAOi+B,EAC3H,MAAO,GAET,MAAMF,EAAgBE,EAAcA,EACpC,GAAIH,GAAgB19B,EAAGC,EAAGL,EAAQ,MAAO+9B,CAAa,EAAG,MAAO,GAChE,UAAWv7B,KAAQxC,EAAQ,MACzB,GAAI89B,GAAgB19B,EAAGC,EAAGmC,EAAMu7B,CAAa,EAAG,MAAO,GAEzD,MAAO,EACT,CAEO,SAASG,GACdvlB,EACAwlB,EACAxa,EACAjS,EACAkC,EACAC,EACS,CACT,GAAI,CAAC8E,EAAO,OAAS,CAACA,EAAO,YAAa,MAAO,GAEjD,MAAMsC,EAAe3N,GAAiBqW,EAAS,cAAchL,EAAO,YAAY,CAAC,EAAGA,EAAO,YAAY,CAAC,CAAC,CAAC,EAC1G,GAAI,CAACsC,EAAc,MAAO,GAG1B,MAAMnH,EADYtC,GAAsBmH,EAAO,MAAOjH,CAAU,EACnCA,EAAW,SAAW,EAC7CqC,EAAYrC,EAAW,SAAWA,EAAW,SAAW,EAExDtR,EAAIwC,EAAMqY,EAAa,CAAC,EAAGnH,EAAW,GAAM,EAAGF,EAAcE,EAAW,GAAM,CAAC,EAC/EzT,EAAIuC,EAAMqY,EAAa,CAAC,EAAIvJ,EAAW,QAASqC,EAAY,GAAM,EAAGF,EAAeE,EAAY,GAAM,CAAC,EACvGC,EAAO5T,EAAI0T,EAAW,GACtB0N,EAAQphB,EAAI0T,EAAW,GACvBG,EAAM5T,EAAI0T,EAAY,GACtB0N,EAASphB,EAAI0T,EAAY,GAE/B,OAAOoqB,EAAY,CAAC,GAAKnqB,GAAQmqB,EAAY,CAAC,GAAK3c,GAAS2c,EAAY,CAAC,GAAKlqB,GAAOkqB,EAAY,CAAC,GAAK1c,CACzG,CAEO,SAAS2c,GAAkBpR,EAA2C,CAC3E,MAAM7sB,EAA2B,CAAA,EACjC,QAASQ,EAAI,EAAGA,EAAIqsB,EAAQ,OAAQrsB,GAAK,EAAG,CAC1C,MAAMgY,EAASqU,EAAQrsB,CAAC,EAClB+B,EAAWZ,GAAmB,CAACxC,GAAcqZ,GAAQ,WAAW,CAAC,CAAC,EACxE,GAAIjW,EAAS,SAAW,EAAG,SAC3B,MAAM+O,EAAQ,OAAOkH,GAAQ,OAAU,SAAWA,EAAO,MAAM,OAAS,GACxExY,EAAI,KAAK,CACP,OAAAwY,EACA,YAAahY,EACb,SAAUg9B,GAAgBhlB,EAAQhY,CAAC,EACnC,SAAA+B,EACA,MAAA+O,EACA,YAAaA,EAAQM,GAAyBrP,CAAQ,EAAI,IAAA,CAC3D,CACH,CACA,OAAOvC,CACT,CAEO,SAASk+B,GACdlxB,EACAgxB,EACAnR,EACArJ,EACAjS,EACA4sB,EACAC,EACA3qB,EACAC,EAKO,CACP,MAAMzT,EAAI+M,EAAM,CAAC,EACX9M,EAAI8M,EAAM,CAAC,EACXxR,EAAO,KAAK,IAAI,KAAMgoB,EAAS,aAAA,EAAe,IAAI,EAClD5I,EAAsB,KAAK,IAAI,EAAGwjB,CAAqB,EACvDC,EAAqBd,GAAiC/hC,EAC5D,QAASgF,EAAIqsB,EAAQ,OAAS,EAAGrsB,GAAK,EAAGA,GAAK,EAAG,CAC/C,MAAMgY,EAASqU,EAAQrsB,CAAC,EACxB,UAAWX,KAAW2Y,EAAO,SAC3B,GAAKqlB,GAA0B59B,EAAGC,EAAGL,EAASw+B,CAAkB,EAChE,MAAO,CACL,OAAQ7lB,EAAO,OACf,YAAaA,EAAO,YACpB,SAAUA,EAAO,QAAA,EAGrB,IAAIuC,EAAoBzI,GACtBf,EACA4sB,IAAqB,CACnB,OAAQ3lB,EAAO,OACf,SAAUA,EAAO,SACjB,YAAaA,EAAO,YACpB,KAAAhd,CAAA,CACD,CAAA,EAQH,GANIof,EAAsB,IACxBG,EAAoB,CAClB,GAAGA,EACH,QAASA,EAAkB,QAAUH,CAAA,GAGrC,EAACmjB,GAAyBvlB,EAAQwlB,EAAaxa,EAAUzI,EAAmBtH,EAAaC,CAAY,EACzG,MAAO,CACL,OAAQ8E,EAAO,OACf,YAAaA,EAAO,YACpB,SAAUA,EAAO,QAAA,CAErB,CACA,OAAO,IACT,CCzHA,MAAM8lB,GAAiC,CAAA,EACjCC,GAA8C,CAAA,EAC9CC,GAAqC,CACzC,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CACnC,EACMC,GAAyB,IACzBC,GAA0B,EAC1BC,GAA+C,IAC/C1zB,GAAuC,GAuE7C,SAAS2zB,GAAar5B,EAAmB,CACvC,MAAMtF,EAAIwC,EAAM8C,EAAG,EAAG,CAAC,EACvB,OAAOtF,EAAIA,GAAK,EAAI,EAAIA,EAC1B,CAuEO,SAAS4+B,GAAgB,CAC9B,OAAA3kC,EACA,UAAA+D,EACA,mBAAA25B,EAAqB,KACrB,kBAAAkH,EACA,QAAAC,EACA,YAAAC,EACA,cAAA3I,EACA,kBAAA4I,EACA,aAAAtqB,EAAe,GACf,kBAAAuqB,EACA,SAAAC,EAAW,EACX,mBAAAC,EAAqB,EACrB,UAAArgB,EAAY,GACZ,eAAAsgB,EAAiB,GACjB,UAAA77B,EAAY,KACZ,aAAA87B,EAAe,KACf,gBAAA3O,EACA,iBAAAoH,EACA,sBAAAC,EACA,QAAAtlB,EACA,QAAAC,EACA,eAAA4sB,EACA,WAAAC,EACA,YAAAC,GACA,iBAAAC,EAAmB,GACnB,SAAAC,GAAW,SACX,YAAAC,GACA,iBAAAC,GACA,wBAAAC,GACA,gBAAAC,EAAkB,GAClB,SAAAC,EAAW,SACX,aAAA7pB,EACA,aAAAC,EACA,cAAAS,EACA,kBAAAC,GACA,uBAAAC,GACA,wBAAAC,GACA,iBAAAC,GACA,yBAAAC,GACA,wBAAyBC,EACzB,cAAA7C,EACA,aAAA2rB,EACA,aAAAtpB,GACA,iBAAAW,EACA,gBAAAC,GACA,6BAAAC,GAA+B,GAC/B,mBAAA0oB,GACA,aAAAC,EACA,aAAAC,GACA,cAAAC,GACA,cAAAC,GACA,eAAgBC,EAChB,qBAAAC,GACA,wBAAAC,GACA,eAAAlqB,EACA,gBAAAC,GACA,kBAAAkqB,GACA,UAAA/oB,GACA,MAAA5J,EACF,EAA6C,CAC3C,MAAM4yB,GAAkBD,IAAmB,MAAQ,GAC7CE,GAAqBF,IAAmB,QACxC9oB,EAAYC,EAAAA,OAAiC,IAAI,EACjD0L,EAAc1L,EAAAA,OAA+B,IAAI,EACjDgpB,GAAoBhpB,EAAAA,OAA4B,IAAI,EACpDipB,GAAwBjpB,EAAAA,OAA4B,IAAI,EACxDkpB,GAAuBlpB,EAAAA,OAAiCinB,CAAiB,EACzEkC,GAAanpB,EAAAA,OAAuBknB,CAAO,EAC3CkC,GAAkBppB,EAAAA,OAAOlD,CAAY,EACrC,CAACyC,GAAiB8pB,EAAkB,EAAIC,EAAAA,SAAiC,IAAI,EAC7E,CAACC,GAA4BC,EAA6B,EAAIF,EAAAA,SAAiC,IAAMZ,GAA4B,IAAI,EACrIe,EAA2Bf,IAA6B,OACxDlpB,EAAiBiqB,EAA4Bf,GAA4B,KAAQa,GACjF,CAACG,EAAsBC,CAAuB,EAAIL,EAAAA,SAA8B,IAAI,EACpF,CAACM,EAAYC,EAAa,EAAIP,EAAAA,SAAgC,IAAI,EAClE,CAAC1pB,EAA6BkqB,EAA8B,EAAIR,EAAAA,SAAS,CAAC,EAC1ES,EAAqB/pB,EAAAA,OAA+B,IAAI,EACxDgqB,GAAuBhqB,EAAAA,OAAsB,IAAI,EACjDiqB,GAAoBjqB,EAAAA,OAAsB,IAAI,EAC9CkqB,GAA+BlqB,EAAAA,OAAO,CAAC,EACvCmqB,GAAkCnqB,EAAAA,OAA4E,CAClH,MAAO,KACP,QAAS,EACT,KAAM,EACN,GAAI,CAAA,CACL,EACKoqB,GAAepqB,EAAAA,OAAO,CAAC,EACvBqqB,GAAiB1C,GAAclB,GAC/B6D,GAAmBxrB,IAAgB2nB,GACnC8D,GAAkB3C,IAAelB,GACjC8D,IAAmCpC,GAAc,QAAU,GAAK,EAEhEhnB,GAAcb,EAAAA,QAAuB,KAAO,CAAE,SAAU,WAAY,MAAO,OAAQ,OAAQ,OAAQ,GAAGrK,EAAA,GAAU,CAACA,EAAK,CAAC,EACvHu0B,GAA0BlqB,EAAAA,QAC9B,KAAO,CACL,SAAU,WACV,IAAK,EACL,KAAM,EACN,OAAQ,EACR,OAAQ,EACR,QAAS,WACT,SAAU,kBACV,cAAe,OACf,WAAY,WACZ,WAAY,KACZ,WAAY,mEACZ,SAAU,GACV,MAAO,UACP,WAAY,wBACZ,OAAQ,sCACR,aAAc,EACd,UAAW,8BACX,GAAG8mB,CAAA,GAEL,CAACA,CAAiB,CAAA,EAGdqD,GAAsBnqB,EAAAA,QAAqB,IAC3C8pB,GAAe,OAAS,EACnBA,GAELE,GAAgB,SAAW,EACtB9D,GAEF8D,GAAgB,IAAI,CAACriC,EAAasY,KAAW,CAClD,GAAIA,EACJ,YAAAtY,CAAA,EACA,EACD,CAACmiC,GAAgBE,EAAe,CAAC,EAC9BI,GAAqBpqB,EAAAA,QAAQ,IAAM6lB,GAAkBsE,EAAmB,EAAG,CAACA,EAAmB,CAAC,EAChGE,GAA2BrqB,EAAAA,QAAQ,IAAMrG,GAAwBuF,CAAgB,EAAG,CAACA,CAAgB,CAAC,EAEtGorB,GAAiCvpB,cAAa5d,GAAiB,CACnE,MAAMonC,EAAUlgC,EAAMlH,EAAM,EAAG0P,EAAoC,EAC/D,KAAK,IAAI82B,GAA6B,QAAUY,CAAO,EAAI,OAC/DZ,GAA6B,QAAUY,EACvChB,GAA+BgB,CAAO,EACxC,EAAG,CAAA,CAAE,EAECC,GAAqCzpB,EAAAA,YAAY,IAAM,CAC3D,MAAMohB,EAAYyH,GAAgC,QAC9CzH,EAAU,QAAU,OACtB,qBAAqBA,EAAU,KAAK,EACpCA,EAAU,MAAQ,KAEtB,EAAG,CAAA,CAAE,EAECsI,GAA+B1pB,EAAAA,YAClCihB,GAAmB,CAClB,MAAM0I,EAAgBrgC,EAAM23B,EAAQ,EAAGnvB,EAAoC,EACrEsvB,EAAYyH,GAAgC,QAC5C5jB,EAAO2jB,GAA6B,QAC1C,GAAI,KAAK,IAAI3jB,EAAO0kB,CAAa,EAAI,KAAM,CACzCF,GAAA,EACArI,EAAU,GAAKuI,EACfJ,GAA+BI,CAAa,EAC5C,MACF,CAEAF,GAAA,EACArI,EAAU,QAAU,YAAY,IAAA,EAChCA,EAAU,KAAOnc,EACjBmc,EAAU,GAAKuI,EAEf,MAAM38B,EAAQ48B,GAAsB,CAClC,MAAM7H,GAAU8G,GAAgC,QAC1CxH,GAAU,KAAK,IAAI,EAAGuI,EAAY7H,GAAQ,OAAO,EACjDT,GAA+Dh4B,EAAM+3B,GAAUmE,GAA8C,EAAG,CAAC,EACjIjE,GAAQkE,GAAanE,EAAI,EACzBuI,GAAY9H,GAAQ,MAAQA,GAAQ,GAAKA,GAAQ,MAAQR,GAI/D,GAHAgI,GAA+BM,EAAS,EACxCnC,GAAkB,UAAA,EAEdpG,IAAQ,EAAG,CACbS,GAAQ,MAAQ,KAChBwH,GAA+BxH,GAAQ,EAAE,EACzC,MACF,CACAA,GAAQ,MAAQ,sBAAsB/0B,CAAI,CAC5C,EAEAo0B,EAAU,MAAQ,sBAAsBp0B,CAAI,CAC9C,EACA,CAACu8B,GAAgCE,EAAkC,CAAA,EAG/DK,GAAgC9pB,EAAAA,YACnC3d,GAAoC,CACnC,MAAMgoB,EAAWD,EAAY,QAC7B,GAAI,CAACC,GAAY,OAAOhoB,GAAS,UAAY,CAAC,OAAO,SAASA,CAAI,EAAG,CACnEqnC,GAA6B,CAAC,EAC9B,MACF,CACA,MAAMzI,EAAS7nB,GAAmCiF,GAA8Bhc,EAAMgoB,EAAS,cAAc,EAC7Gqf,GAA6BzI,CAAM,CACrC,EACA,CAAC5iB,GAA8BqrB,EAA4B,CAAA,EAGvDK,GAAe9qB,EAAAA,QAAsB,IAAMmqB,GAAoB,IAAI/pB,GAAUrZ,GAAcqZ,EAAO,WAAW,CAAC,EAAE,OAAQ,GAAuB,GAAK,IAAI,EAAG,CAAC+pB,EAAmB,CAAC,EAEhL,CAACY,GAAiBC,EAAkB,EAAIjC,EAAAA,SAA8B39B,CAAS,EAErFkZ,EAAAA,UAAU,IAAM,CACd,MAAM2mB,EAAQ,EAAEpB,GAAa,QAC7B,IAAIxf,EAAY,GAEhB,GAAI,CAACid,EACH,OAAA0D,GAAmB5/B,CAAS,EACrB,IAAM,CACXif,EAAY,EACd,EAGF,GAAI,CAACjf,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,OAAA4/B,GAAmB,IAAI,EAChB,IAAM,CACX3gB,EAAY,EACd,EAGF,GAAIygB,GAAa,SAAW,EAC1B,OAAAE,GAAmB5E,EAAoB,EACvCoB,KAAc,CACZ,KAAMD,GACN,WAAY,EACZ,WAAYn8B,EAAU,MACtB,YAAa,EACb,aAAc,CAAA,CACf,EACM,IAAM,CACXif,EAAY,EACd,EAGF,MAAM6gB,EAAc,CAAC1c,EAA2B2c,IAAoF,CAClI,GAAI9gB,GAAa4gB,IAAUpB,GAAa,QAAS,OACjD,MAAM1U,GAAa/pB,EAAU,MACvBggC,GAAc5c,GAAM,YAAcA,EAAK,YAAY,OAAUA,GAAM,OAAS,EAClFwc,GAAmBxc,CAAI,EACvBgZ,KAAc,CACZ,KAAM2D,EAAM,KACZ,WAAYA,EAAM,WAClB,WAAAhW,GACA,YAAAiW,GACA,aAAcN,GAAa,OAC3B,WAAYK,EAAM,WAClB,eAAgBA,EAAM,eACtB,cAAeA,EAAM,aAAA,CACtB,CACH,EAyCA,OAvCY,SAA2B,CACrC,GAAI5D,KAAa,OAAQ,CACvB,MAAMr2B,EAAQ,YAAY,IAAA,EACpBsd,EAAOnD,GAA0BjgB,EAAW0/B,EAAY,EAC9DI,EAAY1c,EAAM,CAChB,KAAM,OACN,WAAY,YAAY,MAAQtd,CAAA,CACjC,EACD,MACF,CAEA,GAAIq2B,KAAa,gBAAiB,CAChC,MAAM5jB,EAAS,MAAM2K,GAAgCljB,EAAW0/B,GAAc,CAAE,aAAc,GAAM,EACpGI,EAAYvnB,EAAO,KAAM,CACvB,KAAMA,EAAO,KAAK,KAClB,WAAYA,EAAO,KAAK,WACxB,WAAYA,EAAO,KAAK,WACxB,eAAgBA,EAAO,KAAK,eAC5B,cAAeA,EAAO,KAAK,aAAA,CAC5B,EACD,MACF,CAEA,GAAI,CACF,MAAMA,EAAS,MAAMwM,GAAkC/kB,EAAW0/B,EAAY,EAC9EI,EAAYvnB,EAAO,KAAM,CACvB,KAAMA,EAAO,KAAK,KAClB,WAAYA,EAAO,KAAK,UAAA,CACzB,CACH,MAAQ,CACN,MAAMzS,EAAQ,YAAY,IAAA,EACpBsd,EAAOnD,GAA0BjgB,EAAW0/B,EAAY,EAC9DI,EAAY1c,EAAM,CAChB,KAAM,OACN,WAAY,YAAY,MAAQtd,CAAA,CACjC,CACH,CACF,GAEK,EACE,IAAM,CACXmZ,EAAY,EACd,CACF,EAAG,CAACid,EAAkBC,GAAUn8B,EAAW0/B,GAActD,EAAW,CAAC,EAErE,MAAM6D,GAA2B,GAAQtD,GAAgBC,IAAgBK,IACnE,CAACiD,GAAmBC,EAAoB,EAAIxC,EAAAA,SAAuC,IAAI,EAE7FzkB,EAAAA,UAAU,IAAM,CACd,GAAI,CAAC+mB,IAA4B,CAACN,GAAiB,CACjDQ,GAAqB,IAAI,EACzB,MACF,CACA,IAAIlhB,EAAY,GAEhB,OAAAiK,GAA4ByW,GAAiBjpC,CAAM,EAAE,KAAK0pC,GAAa,CAChEnhB,GAAWkhB,GAAqBC,CAAS,CAChD,CAAC,EAEM,IAAM,CACXnhB,EAAY,EACd,CACF,EAAG,CAACghB,GAA0BN,GAAiBjpC,CAAM,CAAC,EAEtD,MAAM2pC,GAAuB1qB,EAAAA,YAC1B2qB,GAAqD,CACpD,MAAMtgB,EAAWD,EAAY,QAC7B,GAAI,CAACC,GAAY,CAACkgB,GAAmB,OAAO,KAE5C,MAAMzjC,EAAI,OAAO6jC,EAAW,CAAC,CAAC,EACxB5jC,EAAI,OAAO4jC,EAAW,CAAC,CAAC,EAC9B,GAAI,CAAC,OAAO,SAAS7jC,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAG,OAAO,KAEvD,MAAM1E,EAAO,KAAK,IAAI,KAAMgoB,EAAS,aAAA,EAAe,IAAI,EAClDyU,EAAczU,EAAS,mBAAA,EAEvBugB,GADc,KAAK,IAAIrF,GAAyBzG,EAAcwG,EAAsB,EACrDjjC,EACrC,GAAI,CAAC,OAAO,SAASuoC,EAAc,GAAKA,IAAkB,EAAG,OAAO,KAEpE,KAAM,CAAE,SAAA5Z,GAAU,YAAAuB,GAAa,YAAAC,GAAa,aAAcqY,GAAQ,UAAWC,GAAQ,UAAApd,EAAA,EAAc6c,GAC7FQ,GAAY,KAAK,MAAMjkC,EAAIkqB,EAAQ,EACnCga,GAAY,KAAK,MAAMjkC,EAAIiqB,EAAQ,EACnCia,GAAa,KAAK,IAAI,EAAG,KAAK,KAAKL,GAAiB5Z,EAAQ,CAAC,EAC7D3gB,GAAWu6B,GAAiBA,GAElC,IAAIM,GAAe,GACfC,GAAe96B,GACf+6B,GAAW,EACXC,GAAW,EAEf,QAASzjB,GAAKmjB,GAAYE,GAAYrjB,IAAMmjB,GAAYE,GAAYrjB,IAAM,EACxE,QAASC,GAAKmjB,GAAYC,GAAYpjB,IAAMmjB,GAAYC,GAAYpjB,IAAM,EAAG,CAC3E,MAAMiL,GAAKK,GAAgBoX,GAAmB3iB,GAAIC,EAAE,EACpD,GAAIiL,GAAK,EAAG,SAEZ,MAAMwY,GAAM/Y,GAAYO,EAAE,EACpB1iB,GAAMk7B,GAAM9Y,GAAYM,EAAE,EAChC,QAASzrB,GAAIikC,GAAKjkC,GAAI+I,GAAK/I,IAAK,EAAG,CACjC,MAAM+mB,GAAayc,GAAOxjC,EAAC,EAC3B,GAAI+mB,IAAcV,GAAW,SAE7B,MAAM7U,GAAKiyB,GAAO1c,GAAa,CAAC,EAC1BtV,GAAKgyB,GAAO1c,GAAa,EAAI,CAAC,EAC9BzrB,GAAKkW,GAAK/R,EACVlE,GAAKkW,GAAK/R,EACVwJ,GAAQ5N,GAAKA,GAAKC,GAAKA,GACzB2N,GAAQ46B,KAEZA,GAAe56B,GACf26B,GAAe9c,GACfgd,GAAWvyB,GACXwyB,GAAWvyB,GACb,CACF,CAGF,GAAIoyB,GAAe,EAAG,OAAO,KAC7B,MAAMK,GAAUhB,GAAkB,IAAM,OAAOA,GAAkB,IAAIW,EAAY,CAAC,EAAI,KACtF,MAAO,CACL,MAAOA,GACP,GAAIK,GACJ,WAAY,CAACzkC,EAAGC,CAAC,EACjB,gBAAiB,CAACqkC,GAAUC,EAAQ,CAAA,CAExC,EACA,CAACd,EAAiB,CAAA,EAGdiB,GAAiBxrB,EAAAA,YACrB,CAACyrB,EAA2Bd,IAAsC,CAChE,GAAI,CAAC3D,EAAc,OACnB,MAAMyD,EAAYgB,GAAK,OAAS,KAC1BC,EAASD,GAAK,IAAM,KACtB/C,GAAqB,UAAY+B,GAAa9B,GAAkB,UAAY+C,IAChFhD,GAAqB,QAAU+B,EAC/B9B,GAAkB,QAAU+C,EAC5B1E,EAAa,CACX,MAAOyD,EACP,GAAIiB,EACJ,WAAAf,EACA,gBAAiBc,GAAK,iBAAmB,IAAA,CAC1C,EACH,EACA,CAACzE,CAAY,CAAA,EAGT2E,GAAiB3rB,EAAAA,YACrB,CAAC2qB,EAA4BiB,IAAmB,CAC9C,GAAI,CAAC3E,GAAc,OACnB,MAAMwE,EAAMf,GAAqBC,CAAU,EACtCc,GACLxE,GAAa,CACX,GAAGwE,EACH,OAAAG,CAAA,CACD,CACH,EACA,CAAC3E,GAAcyD,EAAoB,CAAA,EAGrCnnB,EAAAA,UAAU,IAAM,CACd,GAAK+jB,GACL,OAAAA,GAAwB,QAAUoD,GAC3B,IAAM,CACPpD,GAAwB,UAAYoD,KACtCpD,GAAwB,QAAU,KAEtC,CACF,EAAG,CAACA,GAAyBoD,EAAoB,CAAC,EAElDnnB,EAAAA,UAAU,IAAM,CACT4kB,GACLD,GAA8Bd,GAA4B,IAAI,CAChE,EAAG,CAACe,EAA0Bf,CAAwB,CAAC,EAEvD,MAAMyE,GAAqB7rB,EAAAA,YACxB5d,GAAiC,CAC5B,OAAO8b,CAAc,IAAM,OAAO9b,CAAI,IACrC+lC,GACHD,GAA8B9lC,CAAI,EAEpCilC,KAAuBjlC,CAAI,EAC7B,EACA,CAAC8b,EAAgBiqB,EAA0Bd,EAAoB,CAAA,EAGjE9jB,EAAAA,UAAU,IAAM,CACdqkB,GAAqB,QAAUjC,CACjC,EAAG,CAACA,CAAiB,CAAC,EAEtBpiB,EAAAA,UAAU,IAAM,CACdskB,GAAW,QAAUjC,CACvB,EAAG,CAACA,CAAO,CAAC,EAEZriB,EAAAA,UAAU,IAAM,CACdukB,GAAgB,QAAUtsB,EACrBA,GAAc+sB,GAAc,IAAI,CACvC,EAAG,CAAC/sB,CAAY,CAAC,EAEjB+H,EAAAA,UAAU,IACD,IAAM,CACXkmB,GAAA,CACF,EACC,CAACA,EAAkC,CAAC,EAEvC,MAAMqC,GAAsB9rB,cAAaoqB,GAAgC,CACvEvC,GAAW,UAAUuC,CAAK,EACtBtC,GAAgB,SAClBS,GAAc6B,CAAK,CAEvB,EAAG,CAAA,CAAE,EAEC2B,GAAmB9sB,EAAAA,QAAQ,IAC1BqpB,EAGE,CACL,QAAQA,EAAW,IAAI,YAAYA,EAAW,SAAS,QAAQ,CAAC,GAAK,GAAG,mBAAmBA,EAAW,WAAa,GAAG,GACtH,iBAAiBA,EAAW,OAAO,eAAeA,EAAW,QAAQ,eAAeA,EAAW,QAAQ,GACvG,cAAcA,EAAW,KAAK,UAAUA,EAAW,WAAa,GAAG,WAAWA,EAAW,aAAe,GAAG,GAC3G,kBAAkBA,EAAW,QAAQ,aAAaA,EAAW,QAAU,GAAG,cAAcA,EAAW,SAAW,GAAG,aAAaA,EAAW,QAAU,GAAG,cAAcA,EAAW,SAAW,GAAG,GAC7L,UAAUA,EAAW,MAAM,EAAA,EAC3B,KAAK;AAAA,CAAI,EARF,oCASR,CAACA,CAAU,CAAC,EAEf/kB,EAAAA,UAAU,IAAM,CAEV,EADcrF,IAAmB,KAAO,GAAOkrB,GAAoB,KAAK,CAAC/pB,EAAQH,IAAU,OAAOmlB,GAAgBhlB,EAAQH,CAAK,CAAC,IAAM,OAAOhB,CAAc,CAAC,IAC9IA,IAAmB,MACnC2tB,GAAmB,IAAI,EAGzB,MAAMG,EAAevD,EAAmB,QAGpC,EAFauD,IAAiB,KAAO,GAAO5C,GAAoB,KAAK,CAAC/pB,EAAQH,IAAU,OAAOmlB,GAAgBhlB,EAAQH,CAAK,CAAC,IAAM,OAAO8sB,CAAY,CAAC,IAE1IA,IAAiB,OAChCvD,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,EAEL,EAAG,CAACkC,GAAqBlrB,EAAgBgpB,GAAe2E,EAAkB,CAAC,EAE3EtoB,EAAAA,UAAU,IAAM,CACd,MAAM0oB,EAAoBvD,GAAqB,QAC3CuD,IAAsB,OACtB1B,IAAqB0B,EAAoB1B,GAAkB,YAC/D7B,GAAqB,QAAU,KAC/BC,GAAkB,QAAU,KAC5B3B,IAAe,CACb,MAAO,KACP,GAAI,KACJ,WAAY,KACZ,gBAAiB,IAAA,CAClB,GACH,EAAG,CAACuD,GAAmBvD,CAAY,CAAC,EAEpC,MAAMkF,GAAsBlsB,EAAAA,YACzB5d,GAA6B,CAC5B0nC,GAA8B1nC,EAAK,IAAI,EACnC8mC,IACFb,EAAwBjmC,CAAI,EAE9B,MAAM+pC,EAAWvE,GAAqB,QAClCuE,GACFA,EAAS/pC,CAAI,EAEfslC,GAAkB,UAAA,EAClBC,GAAsB,UAAA,CACxB,EACA,CAACuB,GAAiCY,EAA6B,CAAA,EAGjEvmB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GACLyf,GAA8Bzf,EAAS,aAAA,EAAe,IAAI,CAC5D,EAAG,CAACyf,GAA+BvwB,EAASC,CAAO,CAAC,EAEpD+J,EAAAA,UAAU,IAAM,CACVsjB,IAAa,UACb4B,EAAmB,UAAY,OACnCA,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,EACH,EAAG,CAACL,EAAUK,EAAa,CAAC,EAE5B3jB,EAAAA,UAAU,IAAM,CACVsjB,IAAa,UACb6B,GAAqB,UAAY,OACrCA,GAAqB,QAAU,KAC/BC,GAAkB,QAAU,KAC5B3B,IAAe,CACb,MAAO,KACP,GAAI,KACJ,WAAY,KACZ,gBAAiB,IAAA,CAClB,EACH,EAAG,CAACH,EAAUG,CAAY,CAAC,EAE3B,MAAMoF,GAAoBpsB,EAAAA,YAAY,CAACwI,EAAiBC,IAA2C,CACjG,MAAM4B,EAAWD,EAAY,QAC7B,GAAI,CAACC,EAAU,OAAO,KACtB,MAAMnK,EAAMmK,EAAS,cAAc7B,EAASC,CAAO,EACnD,GAAI,CAAC,MAAM,QAAQvI,CAAG,GAAKA,EAAI,OAAS,EAAG,OAAO,KAClD,MAAMpZ,EAAI,OAAOoZ,EAAI,CAAC,CAAC,EACjBnZ,EAAI,OAAOmZ,EAAI,CAAC,CAAC,EACvB,MAAI,CAAC,OAAO,SAASpZ,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,EAAG,CAAA,CAAE,EAECslC,GAAqBrsB,EAAAA,YAAY,CAAChd,EAAgBC,IAA0C,CAChG,MAAMonB,EAAWD,EAAY,QAC7B,GAAI,CAACC,EAAU,OAAO,KACtB,MAAMnK,EAAMmK,EAAS,cAAcrnB,EAAQC,CAAM,EACjD,OAAO+Q,GAAiBkM,CAAG,CAC7B,EAAG,CAAA,CAAE,EAECosB,GAA+BtsB,EAAAA,YAAY,CAACwI,EAAiBC,IAAuG,CACxK,MAAM7mB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,EAAQ,OAAO,KACpB,MAAMwD,EAAOxD,EAAO,sBAAA,EACpB,GAAI,CAAC,OAAO,SAASwD,EAAK,KAAK,GAAK,CAAC,OAAO,SAASA,EAAK,MAAM,GAAKA,EAAK,OAAS,GAAKA,EAAK,QAAU,EACrG,OAAO,KAET,MAAM5C,EAAUgmB,EAAUpjB,EAAK,KACzB3C,EAAUgmB,EAAUrjB,EAAK,IAC/B,MAAI,CAAC,OAAO,SAAS5C,CAAO,GAAK,CAAC,OAAO,SAASC,CAAO,EAChD,KAEF,CACL,YAAa,CAACD,EAASC,CAAO,EAC9B,YAAa,KAAK,IAAI,EAAG2C,EAAK,KAAK,EACnC,aAAc,KAAK,IAAI,EAAGA,EAAK,MAAM,CAAA,CAEzC,EAAG,CAAA,CAAE,EAECmnC,GAAgBvsB,EAAAA,YACpB,CAACnM,EAAuBgxB,EAA6BvqB,EAAqBC,IAAyB,CACjG,MAAM8P,EAAWD,EAAY,QAC7B,OAAKC,EACE0a,GAAqBlxB,EAAOgxB,EAAawE,GAAoBhf,EAAUif,GAA0BtrB,EAA6BM,EAA6BhE,EAAaC,CAAY,EADrK,IAExB,EACA,CAAC8uB,GAAoBC,GAA0BtrB,EAA6BM,CAA2B,CAAA,EAGnGkuB,GAA2BxsB,EAAAA,YAAY,IAAM,CACjDoK,EAAY,SAAS,cAAA,EACrBsd,GAAkB,UAAA,EAClBC,GAAsB,UAAA,CACxB,EAAG,CAAA,CAAE,EAEC8E,GAAgCxtB,EAAAA,QAA6B,IAC1DmpB,GAAwBhe,EAAY,SAAS,aAAA,GAAkB,KACrE,CAACge,CAAoB,CAAC,EAEnBsE,GAAqBztB,EAAAA,QAAsC,IAAM,CACrE,GAAI,CAACle,EAAQ,OAAO,KACpB,MAAM4rC,EAAoBF,GAC1B,OAAKE,EACE,CACL,OAAA5rC,EACA,UAAW4rC,EACX,SAAA9F,EACA,gBAAAD,EACA,cAAeyF,GACf,cAAeD,GACf,cAAeI,EAAA,EARc,IAUjC,EAAG,CAACzrC,EAAQ0rC,GAA+B5F,EAAUD,EAAiByF,GAAoBD,GAAmBI,EAAwB,CAAC,EAEhII,GAA0B5sB,EAAAA,YAC7BmC,GAA6C,CAC5C,MAAM0qB,EAAgB1qB,EAAM,SAAW1D,EAAU,QAC3C5K,EAAQu4B,GAAkBjqB,EAAM,QAASA,EAAM,OAAO,EAC5D,GAAI4kB,GAAoB,CACtB,MAAM+F,GAAc,CAAC,CAACj5B,GAASA,EAAM,CAAC,GAAK,GAAKA,EAAM,CAAC,GAAK,GAAK,CAAC,CAAC9S,GAAU8S,EAAM,CAAC,GAAK9S,EAAO,OAAS8S,EAAM,CAAC,GAAK9S,EAAO,OAC5HgmC,GAAmB,CACjB,WAAYlzB,EACZ,QAASsO,EAAM,QACf,QAASA,EAAM,QACf,YAAA2qB,EAAA,CACD,CACH,CAEA,GAAIjG,IAAa,SAAU,OAC3B,GAAI,CAACgG,EAAe,CAClBrB,GAAe,KAAM,IAAI,EACrB/C,EAAmB,UAAY,OACjCA,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,GAEH,MACF,CACA,GAAI,CAACrzB,EAAO,CACV23B,GAAe,KAAM,IAAI,EACzB,MACF,CAKA,GAHIxE,GACFwE,GAAed,GAAqB72B,CAAK,EAAGA,CAAK,EAE/C,CAACw1B,GAAmB,OAAQ,OAEhC,MAAM0D,EAAkBT,GAA6BnqB,EAAM,QAASA,EAAM,OAAO,EACjF,GAAI,CAAC4qB,EAAiB,OAEtB,MAAMtB,EAAMc,GAAc14B,EAAOk5B,EAAgB,YAAaA,EAAgB,YAAaA,EAAgB,YAAY,EACjHC,EAAcvB,GAAK,UAAY,KAC/BwB,GAAcxE,EAAmB,QACnC,OAAOwE,EAAW,IAAM,OAAOD,CAAW,IAE9CvE,EAAmB,QAAUuE,EAC7BjF,GAAmBiF,CAAW,EAC9B9F,KAAgB,CACd,OAAQuE,GAAK,QAAU,KACvB,SAAUuB,EACV,YAAavB,GAAK,aAAe,GACjC,WAAY53B,CAAA,CACb,EACH,EACA,CAACgzB,EAAUwC,GAAoB+C,GAAmBlF,GAAeH,GAAoBhmC,EAAQyqC,GAAgBd,GAAsB1D,EAAcsF,GAA8BC,EAAa,CAAA,EAGxLW,GAA2BltB,EAAAA,YAAY,IAAM,CACjD+mB,KAAqB,CACnB,WAAY,KACZ,QAAS,GACT,QAAS,GACT,YAAa,EAAA,CACd,EACDyE,GAAe,KAAM,IAAI,EACrB/C,EAAmB,UAAY,OACnCA,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,EACH,EAAG,CAACA,GAAeH,GAAoByE,EAAc,CAAC,EAEhD2B,GAAoBntB,EAAAA,YACvBmC,GAA2C,CAE1C,GADI0kB,IAAa,UACb1kB,EAAM,SAAW1D,EAAU,QAAS,OAExC,MAAM5K,EAAQu4B,GAAkBjqB,EAAM,QAASA,EAAM,OAAO,EAC5D,GAAI,CAACtO,EAAO,OAGZ,GAFA83B,GAAe93B,EAAOsO,EAAM,MAAM,EAE9B,CAACknB,GAAmB,OAAQ,CAC9BwC,GAAmB,IAAI,EACvB,MACF,CAEA,MAAMkB,EAAkBT,GAA6BnqB,EAAM,QAASA,EAAM,OAAO,EACjF,GAAI,CAAC4qB,EAAiB,OAEtB,MAAMtB,EAAMc,GAAc14B,EAAOk5B,EAAgB,YAAaA,EAAgB,YAAaA,EAAgB,YAAY,EACvH,GAAI,CAACtB,EAAK,CACRI,GAAmB,IAAI,EACvB,MACF,CAEA,MAAMuB,EAAqClvB,IAAmB,MAAQ,OAAOA,CAAc,IAAM,OAAOutB,EAAI,QAAQ,EAAI,KAAOA,EAAI,SACnII,GAAmBuB,CAAU,EAC7BjG,KAAgB,CACd,OAAQsE,EAAI,OACZ,SAAUA,EAAI,SACd,YAAaA,EAAI,YACjB,WAAY53B,CAAA,CACb,CACH,EACA,CAACgzB,EAAUwC,GAAoB+C,GAAmBjF,GAAejpB,EAAgB2tB,GAAoBF,GAAgBW,GAA8BC,EAAa,CAAA,EAG5Jc,GAAiBrtB,EAAAA,YACpBnM,GAAmC,CAGlC,GAFIgzB,IAAa,SACb5pB,GAAc,iBAAmB,IACjC,CAACosB,GAAmB,OAAQ,MAAO,GAEvC,MAAMhf,EAAWD,EAAY,QACvBxoB,EAAS6c,EAAU,QACzB,GAAI,CAAC4L,GAAY,CAACzoB,EAAQ,MAAO,GACjC,MAAMwD,EAAOxD,EAAO,sBAAA,EACpB,GAAIwD,EAAK,OAAS,GAAKA,EAAK,QAAU,EAAG,MAAO,GAEhD,MAAMy/B,EAAc7wB,GAAiBqW,EAAS,cAAcxW,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAAC,EAC/E,GAAI,CAACgxB,EAAa,MAAO,GACzB,MAAM4G,EAAMc,GAAc14B,EAAOgxB,EAAaz/B,EAAK,MAAOA,EAAK,MAAM,EACrE,GAAI,CAACqmC,EAAK,MAAO,GAEjB,MAAM2B,GAAqClvB,IAAmB,MAAQ,OAAOA,CAAc,IAAM,OAAOutB,EAAI,QAAQ,EAAI,KAAOA,EAAI,SACnI,OAAAI,GAAmBuB,EAAU,EAC7BjG,KAAgB,CACd,OAAQsE,EAAI,OACZ,SAAUA,EAAI,SACd,YAAaA,EAAI,YACjB,WAAY53B,CAAA,CACb,EACM,EACT,EACA,CAACgzB,EAAU5pB,GAAc,eAAgBosB,GAAoBnrB,EAAgB2tB,GAAoB1E,GAAeoF,EAAa,CAAA,EAGzHe,GAA0BttB,EAAAA,YAC7BmC,GAA2C,CAG1C,GAFI,CAAC8kB,IACDJ,IAAa,UACb1kB,EAAM,SAAW1D,EAAU,QAAS,OACxC0D,EAAM,eAAA,EACN,MAAMtO,EAAQu4B,GAAkBjqB,EAAM,QAASA,EAAM,OAAO,EACvDtO,GACL83B,GAAe93B,EAAOsO,EAAM,MAAM,CACpC,EACA,CAAC0kB,EAAUuF,GAAmBT,GAAgB1E,EAAY,CAAA,EAG5D1jB,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAM3hB,EAAS6c,EAAU,QACzB,GAAI,CAAC7c,GAAU,CAACb,EACd,OAGF,MAAMspB,EAAW,IAAIoY,GAAgB7gC,EAAQb,EAAQ,CACnD,kBAAmBmrC,GACnB,QAASJ,GACT,YAAAjG,EACA,cAAA3I,EACA,kBAAA4I,EACA,UAAAlgB,EACA,mBAAA6Y,EACA,eAAAyH,EACA,gBAAA1O,EACA,iBAAAoH,EACA,sBAAAC,EACA,QAAAtlB,EACA,QAAAC,EACA,eAAA4sB,CAAA,CACD,EAED,OAAAhc,EAAY,QAAUC,EAClBvlB,GACFulB,EAAS,aAAavlB,CAAS,EAEjCglC,GAA8Bzf,EAAS,aAAA,EAAe,IAAI,EAC1DA,EAAS,mBAAmBuc,CAAe,EACvCsC,IACFb,EAAwBhe,EAAS,cAAc,EAG1C,IAAM,CACXof,GAAA,EACAF,GAA+B,CAAC,EAChClf,EAAS,QAAA,EACTD,EAAY,QAAU,IACxB,CACF,EAAG,CACDrpB,EACA+qC,GACAjG,EACA3I,EACA4I,EACAlgB,EACAsgB,EACAgG,GACAhD,GACAY,GACAL,GACAF,EAAA,CACD,EAEDhmB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACzB,CAACC,GAAY,CAACvlB,GAGlBulB,EAAS,aAAavlB,CAAS,CACjC,EAAG,CAACA,CAAS,CAAC,EAEdye,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GAGLA,EAAS,WAAA,CACX,EAAG,CAAC2b,CAAQ,CAAC,EAEbziB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GACLA,EAAS,cAAA,CACX,EAAG,CAAC4b,CAAkB,CAAC,EAEvB1iB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACzB,CAACC,GAAY,CAAC8b,GAGlB9b,EAAS,gBAAgB8b,CAAY,CACvC,EAAG,CAACA,CAAY,CAAC,EAEjB5iB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GAGLA,EAAS,mBAAmBmN,CAAe,CAC7C,EAAG,CAACA,CAAe,CAAC,EAEpBjU,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GACLA,EAAS,oBAAoBuU,CAAgB,CAC/C,EAAG,CAACA,CAAgB,CAAC,EAErBrb,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GACLA,EAAS,yBAAyBwU,CAAqB,CACzD,EAAG,CAACA,CAAqB,CAAC,EAE1Btb,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,IACLA,EAAS,aAAa9Q,EAASC,CAAO,EACtCswB,GAA8Bzf,EAAS,aAAA,EAAe,IAAI,EAC5D,EAAG,CAAC9Q,EAASC,EAASswB,EAA6B,CAAC,EAEpDvmB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GACLA,EAAS,kBAAkB+b,CAAc,CAC3C,EAAG,CAACA,CAAc,CAAC,EAEnB7iB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GACLA,EAAS,sBAAsBoU,CAAkB,CACnD,EAAG,CAACA,CAAkB,CAAC,EAEvBlb,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GAGLA,EAAS,aAAa2f,EAAe,CACvC,EAAG,CAACA,EAAe,CAAC,EAEpBzmB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACmjB,GAAkB,OAEvB,MAAM0D,EAAQpW,GADOuS,EAAmByD,GAAkB3/B,EACR++B,GAAqB,CACrE,qBAAsBzC,GACtB,oBAAqB,EAAA,CACtB,EACDD,GAAiB0D,CAAK,CACxB,EAAG,CAAC1D,GAAkBH,EAAkBl8B,EAAW2/B,GAAiBZ,GAAqBzC,EAAuB,CAAC,EAEjHpjB,EAAAA,UAAU,IAAM,CACd,MAAM8G,EAAWD,EAAY,QACxBC,GAGLA,EAAS,mBAAmBuc,CAAe,CAC7C,EAAG,CAACA,CAAe,CAAC,EAGlB1c,GAAAA,KAAC,MAAA,CACC,UAAA1L,GACA,MAAOsB,GACP,cAAe8sB,GACf,eAAgBM,GAChB,QAASC,GACT,cAAeG,GAEf,SAAA,CAAA5pB,GAAAA,IAAC,SAAA,CACC,IAAKjF,EACL,UAAU,oBACV,MAAO,CACL,SAAU,WACV,MAAO,EACP,OAAQ,EACR,MAAO,OACP,OAAQ,OACR,QAAS,QACT,YAAa,OACb,OAAQooB,IAAa,UAAY5oB,KAAoB,KAAO,UAAY2oB,EAAkB,YAAc,MAAA,CAC1G,CAAA,EAED7lC,GAAU2rC,IAAsB,MAAM,QAAQ5F,CAAY,GAAKA,EAAa,OAAS,EAClFA,EAAa,IAAI,CAACyG,EAAOruB,IACvBwE,GAAAA,IAAC,MAAA,CAEC,UAAW6pB,EAAM,UACjB,MAAO,CACL,SAAU,WACV,MAAO,EACP,OAAQA,EAAM,QAAU,EACxB,cAAeA,EAAM,eAAiB,OACtC,GAAGA,EAAM,KAAA,EAGV,SAAAA,EAAM,OAAOb,EAAkB,CAAA,EAV3Ba,EAAM,IAAMruB,CAAA,CAYpB,EACD,KACHne,EACC2iB,GAAAA,IAAC3G,GAAA,CACC,KAAM8pB,EACN,QAASA,IAAa,SACtB,WAAY9lC,EAAO,MACnB,YAAaA,EAAO,OACpB,SAAUA,EAAO,IACjB,UAAWA,EAAO,YAClB,aAAAic,EACA,aAAAC,EACA,cAAAS,EACA,aAAc0M,EACd,WAAYijB,GACZ,gBAAiBvoC,EACjB,iBAAkBskC,GAClB,aAAcJ,GACd,kBAAArrB,GACA,uBAAAC,GACA,wBAAAC,GACA,iBAAAC,GACA,yBAAAC,GACA,wBAAyBC,EACzB,cAAA7C,EACA,gBAAA8C,GACA,eAAAC,EACA,iBAAAC,EACA,gBAAAC,GACA,6BAAAC,GACA,4BAAAC,EACA,cAAeopB,GACf,eAAAtqB,EACA,gBAAAC,EAAA,CAAA,EAEA,KACH7B,SACE,MAAA,CAAI,gCAA6B,GAAC,MAAO2tB,GACvC,YACH,EACE,KACHpoC,GAAUymC,IACT9jB,GAAAA,IAACiC,GAAA,CACC,OAAA5kB,EACA,aAAcqpB,EACd,UAAAxE,EACA,QAAS6hB,GACT,cAAeE,GACf,UAAWJ,IAAmB,UAC9B,MAAOA,IAAmB,KAAA,CAAA,CAC5B,CAAA,CAAA,CAIR"}
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/core/gl-utils.ts","../src/core/ortho-camera.ts","../src/core/m1-tile-renderer.ts","../src/wsi/roi-geometry.ts","../src/wsi/constants.ts","../src/wsi/utils.ts","../src/wsi/brush-stroke.ts","../src/react/draw-layer-types.ts","../src/react/draw-layer-utils.ts","../src/react/draw-layer-brush.ts","../src/react/draw-layer-label.ts","../src/react/draw-layer-overlay.ts","../src/react/draw-layer-stamp.ts","../src/react/draw-layer.tsx","../src/wsi/image-info.ts","../src/react/overview-map.tsx","../src/react/tile-viewer-canvas.tsx","../src/wsi/point-clip.ts","../src/wsi/webgpu.ts","../src/wsi/point-clip-hybrid.ts","../src/wsi/worker-client.ts","../src/wsi/point-clip-worker-client.ts","../src/wsi/point-hit-index-shared.ts","../src/wsi/point-hit-index-worker-client.ts","../src/wsi/roi-term-stats.ts","../src/wsi/tile-scheduler.ts","../src/wsi/wsi-canvas-lifecycle.ts","../src/wsi/wsi-normalize.ts","../src/wsi/wsi-interaction.ts","../src/wsi/wsi-tile-visibility.ts","../src/wsi/wsi-input-handlers.ts","../src/wsi/wsi-tile-cache.ts","../src/wsi/wsi-lifecycle-ops.ts","../src/wsi/wsi-point-data.ts","../src/wsi/wsi-render-pass.ts","../src/wsi/wsi-shaders.ts","../src/wsi/wsi-view-animation.ts","../src/wsi/wsi-view-ops.ts","../src/wsi/wsi-tile-renderer.ts","../src/react/wsi-region-hit-utils.ts","../src/react/wsi-viewer-canvas.tsx"],"sourcesContent":["function compileShader(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader {\n const shader = gl.createShader(type);\n if (!shader) {\n throw new Error(\"Failed to create shader.\");\n }\n\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n\n const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS);\n if (!ok) {\n const log = gl.getShaderInfoLog(shader) ?? \"unknown shader error\";\n gl.deleteShader(shader);\n throw new Error(log);\n }\n\n return shader;\n}\n\nexport function createProgram(gl: WebGL2RenderingContext, vertexSource: string, fragmentSource: string): WebGLProgram {\n const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexSource);\n const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentSource);\n\n const program = gl.createProgram();\n if (!program) {\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n throw new Error(\"Failed to create program.\");\n }\n\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n\n gl.deleteShader(vertexShader);\n gl.deleteShader(fragmentShader);\n\n const ok = gl.getProgramParameter(program, gl.LINK_STATUS);\n if (!ok) {\n const log = gl.getProgramInfoLog(program) ?? \"unknown link error\";\n gl.deleteProgram(program);\n throw new Error(log);\n }\n\n return program;\n}\n\nexport function requireUniformLocation(\n gl: WebGL2RenderingContext,\n program: WebGLProgram,\n uniformName: string,\n): WebGLUniformLocation {\n const location = gl.getUniformLocation(program, uniformName);\n if (!location) {\n throw new Error(`Failed to get uniform location: ${uniformName}`);\n }\n return location;\n}\n\nexport function requireWebGL2(canvas: HTMLCanvasElement): WebGL2RenderingContext {\n const context = canvas.getContext(\"webgl2\", {\n alpha: false,\n antialias: false,\n depth: false,\n stencil: false,\n preserveDrawingBuffer: false,\n powerPreference: \"high-performance\",\n });\n\n if (!context) {\n throw new Error(\"WebGL2 is not available.\");\n }\n\n return context;\n}\n","export interface ViewState {\n offsetX: number;\n offsetY: number;\n zoom: number;\n rotationDeg: number;\n}\n\nexport type WorldPoint = [number, number];\n\nfunction toRadians(deg: number): number {\n return (deg * Math.PI) / 180;\n}\n\nexport class OrthoCamera {\n private viewportWidth = 1;\n private viewportHeight = 1;\n\n private viewState: ViewState = {\n offsetX: 0,\n offsetY: 0,\n zoom: 1,\n rotationDeg: 0,\n };\n\n setViewport(width: number, height: number): void {\n this.viewportWidth = Math.max(1, width);\n this.viewportHeight = Math.max(1, height);\n }\n\n getViewportSize(): { width: number; height: number } {\n return {\n width: this.viewportWidth,\n height: this.viewportHeight,\n };\n }\n\n setViewState(next: Partial<ViewState>): void {\n if (next.offsetX !== undefined) {\n this.viewState.offsetX = next.offsetX;\n }\n\n if (next.offsetY !== undefined) {\n this.viewState.offsetY = next.offsetY;\n }\n\n if (next.zoom !== undefined) {\n this.viewState.zoom = Math.max(0.0001, next.zoom);\n }\n\n if (typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)) {\n this.viewState.rotationDeg = next.rotationDeg;\n }\n }\n\n getViewState(): ViewState {\n return { ...this.viewState };\n }\n\n getCenter(): WorldPoint {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n return [\n this.viewState.offsetX + this.viewportWidth / (2 * zoom),\n this.viewState.offsetY + this.viewportHeight / (2 * zoom),\n ];\n }\n\n setCenter(centerX: number, centerY: number): void {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n this.viewState.offsetX = centerX - this.viewportWidth / (2 * zoom);\n this.viewState.offsetY = centerY - this.viewportHeight / (2 * zoom);\n }\n\n screenToWorld(screenX: number, screenY: number): WorldPoint {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n const [centerX, centerY] = this.getCenter();\n const rotationDeg = this.viewState.rotationDeg ?? 0;\n const dx = (screenX - this.viewportWidth * 0.5) / zoom;\n const dy = (screenY - this.viewportHeight * 0.5) / zoom;\n const rad = toRadians(rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n return [centerX + dx * cos - dy * sin, centerY + dx * sin + dy * cos];\n }\n\n worldToScreen(worldX: number, worldY: number): WorldPoint {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n const [centerX, centerY] = this.getCenter();\n const rotationDeg = this.viewState.rotationDeg ?? 0;\n const dx = worldX - centerX;\n const dy = worldY - centerY;\n const rad = toRadians(rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const rx = dx * cos + dy * sin;\n const ry = -dx * sin + dy * cos;\n return [\n this.viewportWidth * 0.5 + rx * zoom,\n this.viewportHeight * 0.5 + ry * zoom,\n ];\n }\n\n getViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n const w = this.viewportWidth;\n const h = this.viewportHeight;\n return [\n this.screenToWorld(0, 0),\n this.screenToWorld(w, 0),\n this.screenToWorld(w, h),\n this.screenToWorld(0, h),\n ];\n }\n\n getMatrix(): Float32Array {\n const zoom = Math.max(1e-6, this.viewState.zoom);\n const rotationDeg = this.viewState.rotationDeg ?? 0;\n\n if (rotationDeg === 0) {\n const viewWidth = this.viewportWidth / zoom;\n const viewHeight = this.viewportHeight / zoom;\n const sx = 2 / viewWidth;\n const sy = -2 / viewHeight;\n const tx = -1 - this.viewState.offsetX * sx;\n const ty = 1 - this.viewState.offsetY * sy;\n return new Float32Array([sx, 0, 0, 0, sy, 0, tx, ty, 1]);\n }\n\n const [centerX, centerY] = this.getCenter();\n const rad = toRadians(rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const ax = (2 * zoom * cos) / this.viewportWidth;\n const bx = (2 * zoom * sin) / this.viewportWidth;\n const ay = (2 * zoom * sin) / this.viewportHeight;\n const by = (-2 * zoom * cos) / this.viewportHeight;\n const tx = -(ax * centerX + bx * centerY);\n const ty = -(ay * centerX + by * centerY);\n return new Float32Array([ax, ay, 0, bx, by, 0, tx, ty, 1]);\n }\n}\n","import {\n\tcreateProgram,\n\trequireUniformLocation,\n\trequireWebGL2,\n} from \"./gl-utils\";\nimport { OrthoCamera, type ViewState } from \"./ortho-camera\";\nimport type { Bounds, TileDefinition } from \"./types\";\n\ninterface LoadedTile {\n\tid: string;\n\tbounds: Bounds;\n\ttexture: WebGLTexture;\n}\n\nexport interface M1TileRendererOptions {\n\tcanvas: HTMLCanvasElement;\n\timageWidth: number;\n\timageHeight: number;\n\tclearColor?: [number, number, number, number];\n\tinitialViewState?: Partial<ViewState>;\n}\n\nconst VERTEX_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 aUnit;\nin vec2 aUv;\n\nuniform mat3 uCamera;\nuniform vec4 uBounds;\n\nout vec2 vUv;\n\nvoid main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\n\nin vec2 vUv;\nuniform sampler2D uTexture;\n\nout vec4 outColor;\n\nvoid main() {\n outColor = texture(uTexture, vUv);\n}\n`;\n\nexport class M1TileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly imageWidth: number;\n\tprivate readonly imageHeight: number;\n\tprivate readonly clearColor: [number, number, number, number];\n\tprivate readonly program: WebGLProgram;\n\tprivate readonly vao: WebGLVertexArrayObject;\n\tprivate readonly quadBuffer: WebGLBuffer;\n\tprivate readonly uCameraLocation: WebGLUniformLocation;\n\tprivate readonly uBoundsLocation: WebGLUniformLocation;\n\tprivate readonly uTextureLocation: WebGLUniformLocation;\n\tprivate readonly resizeObserver: ResizeObserver;\n\n\tprivate tiles: LoadedTile[] = [];\n\tprivate frameId: number | null = null;\n\tprivate loadVersion = 0;\n\tprivate destroyed = false;\n\tprivate fitted = false;\n\tprivate controlledViewState = false;\n\n\tconstructor(options: M1TileRendererOptions) {\n\t\tthis.canvas = options.canvas;\n\t\tthis.imageWidth = Math.max(1, options.imageWidth);\n\t\tthis.imageHeight = Math.max(1, options.imageHeight);\n\t\tthis.clearColor = options.clearColor ?? [0.03, 0.05, 0.08, 1];\n\n\t\tthis.gl = requireWebGL2(this.canvas);\n\t\tthis.program = createProgram(this.gl, VERTEX_SHADER, FRAGMENT_SHADER);\n\n\t\tconst vao = this.gl.createVertexArray();\n\t\tconst quadBuffer = this.gl.createBuffer();\n\t\tif (!vao || !quadBuffer) {\n\t\t\tthrow new Error(\"Failed to create WebGL buffers.\");\n\t\t}\n\n\t\tthis.vao = vao;\n\t\tthis.quadBuffer = quadBuffer;\n\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.quadBuffer);\n\n\t\tconst quadVertices = new Float32Array([\n\t\t\t0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1,\n\t\t]);\n\n\t\tthis.gl.bufferData(this.gl.ARRAY_BUFFER, quadVertices, this.gl.STATIC_DRAW);\n\n\t\tconst unitLocation = this.gl.getAttribLocation(this.program, \"aUnit\");\n\t\tconst uvLocation = this.gl.getAttribLocation(this.program, \"aUv\");\n\t\tif (unitLocation < 0 || uvLocation < 0) {\n\t\t\tthrow new Error(\"Failed to get attribute locations.\");\n\t\t}\n\n\t\tconst stride = 4 * Float32Array.BYTES_PER_ELEMENT;\n\t\tthis.gl.enableVertexAttribArray(unitLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tunitLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t0,\n\t\t);\n\t\tthis.gl.enableVertexAttribArray(uvLocation);\n\t\tthis.gl.vertexAttribPointer(\n\t\t\tuvLocation,\n\t\t\t2,\n\t\t\tthis.gl.FLOAT,\n\t\t\tfalse,\n\t\t\tstride,\n\t\t\t2 * Float32Array.BYTES_PER_ELEMENT,\n\t\t);\n\n\t\tthis.gl.bindVertexArray(null);\n\t\tthis.gl.bindBuffer(this.gl.ARRAY_BUFFER, null);\n\n\t\tthis.uCameraLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uCamera\",\n\t\t);\n\t\tthis.uBoundsLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uBounds\",\n\t\t);\n\t\tthis.uTextureLocation = requireUniformLocation(\n\t\t\tthis.gl,\n\t\t\tthis.program,\n\t\t\t\"uTexture\",\n\t\t);\n\n\t\tif (options.initialViewState) {\n\t\t\tthis.controlledViewState = true;\n\t\t\tthis.camera.setViewState(options.initialViewState);\n\t\t}\n\n\t\tthis.resizeObserver = new ResizeObserver(() => {\n\t\t\tthis.resize();\n\t\t});\n\n\t\tthis.resizeObserver.observe(this.canvas);\n\t\tthis.resize();\n\t}\n\n\tasync setTiles(tiles: TileDefinition[]): Promise<void> {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst version = ++this.loadVersion;\n\n\t\tconst loaded = await Promise.all(\n\t\t\ttiles.map(async (tile) => {\n\t\t\t\tconst loadedTile = await this.loadTile(tile, version);\n\t\t\t\treturn loadedTile;\n\t\t\t}),\n\t\t);\n\n\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\tfor (const tile of loaded) {\n\t\t\t\tif (tile) {\n\t\t\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = loaded.filter((tile): tile is LoadedTile => tile !== null);\n\t\tthis.requestRender();\n\t}\n\n\tsetViewState(viewState: Partial<ViewState>): void {\n\t\tthis.controlledViewState = true;\n\t\tthis.camera.setViewState(viewState);\n\t\tthis.requestRender();\n\t}\n\n\tgetViewState(): ViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.destroyed = true;\n\t\tthis.loadVersion += 1;\n\n\t\tif (this.frameId !== null) {\n\t\t\tcancelAnimationFrame(this.frameId);\n\t\t\tthis.frameId = null;\n\t\t}\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.disposeTiles(this.tiles);\n\t\tthis.tiles = [];\n\n\t\tthis.gl.deleteBuffer(this.quadBuffer);\n\t\tthis.gl.deleteVertexArray(this.vao);\n\t\tthis.gl.deleteProgram(this.program);\n\t}\n\n\tprivate async loadTile(\n\t\ttile: TileDefinition,\n\t\tversion: number,\n\t): Promise<LoadedTile | null> {\n\t\ttry {\n\t\t\tconst response = await fetch(tile.url);\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Tile fetch failed: ${response.status} ${response.statusText}`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst blob = await response.blob();\n\t\t\tconst bitmap = await createImageBitmap(blob);\n\n\t\t\tif (this.destroyed || version !== this.loadVersion) {\n\t\t\t\tbitmap.close();\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tconst texture = this.gl.createTexture();\n\t\t\tif (!texture) {\n\t\t\t\tbitmap.close();\n\t\t\t\tthrow new Error(\"Failed to create tile texture.\");\n\t\t\t}\n\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, texture);\n\t\t\tthis.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_S,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_WRAP_T,\n\t\t\t\tthis.gl.CLAMP_TO_EDGE,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MIN_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texParameteri(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\tthis.gl.TEXTURE_MAG_FILTER,\n\t\t\t\tthis.gl.LINEAR,\n\t\t\t);\n\t\t\tthis.gl.texImage2D(\n\t\t\t\tthis.gl.TEXTURE_2D,\n\t\t\t\t0,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.RGBA,\n\t\t\t\tthis.gl.UNSIGNED_BYTE,\n\t\t\t\tbitmap,\n\t\t\t);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\t\tbitmap.close();\n\n\t\t\treturn {\n\t\t\t\tid: tile.id,\n\t\t\t\tbounds: tile.bounds,\n\t\t\t\ttexture,\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconsole.error(`[M1TileRenderer] tile load failed: ${tile.id}`, error);\n\t\t\treturn null;\n\t\t}\n\t}\n\n\tprivate resize(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssWidth = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssHeight = Math.max(1, rect.height || this.canvas.clientHeight || 1);\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst targetWidth = Math.max(1, Math.round(cssWidth * dpr));\n\t\tconst targetHeight = Math.max(1, Math.round(cssHeight * dpr));\n\n\t\tif (\n\t\t\tthis.canvas.width !== targetWidth ||\n\t\t\tthis.canvas.height !== targetHeight\n\t\t) {\n\t\t\tthis.canvas.width = targetWidth;\n\t\t\tthis.canvas.height = targetHeight;\n\t\t}\n\n\t\tthis.camera.setViewport(cssWidth, cssHeight);\n\t\tthis.gl.viewport(0, 0, this.canvas.width, this.canvas.height);\n\n\t\tif (!this.fitted && !this.controlledViewState) {\n\t\t\tthis.fitToImage();\n\t\t\tthis.fitted = true;\n\t\t}\n\n\t\tthis.requestRender();\n\t}\n\n\tprivate fitToImage(): void {\n\t\tconst viewport = this.camera.getViewportSize();\n\n\t\tconst zoom = Math.min(\n\t\t\tviewport.width / this.imageWidth,\n\t\t\tviewport.height / this.imageHeight,\n\t\t);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tconst visibleWorldWidth = viewport.width / safeZoom;\n\t\tconst visibleWorldHeight = viewport.height / safeZoom;\n\n\t\tconst offsetX = (this.imageWidth - visibleWorldWidth) * 0.5;\n\t\tconst offsetY = (this.imageHeight - visibleWorldHeight) * 0.5;\n\n\t\tthis.camera.setViewState({\n\t\t\tzoom: safeZoom,\n\t\t\toffsetX,\n\t\t\toffsetY,\n\t\t});\n\t}\n\n\tprivate requestRender(): void {\n\t\tif (this.frameId !== null || this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.frameId = requestAnimationFrame(() => {\n\t\t\tthis.frameId = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tprivate render(): void {\n\t\tif (this.destroyed) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.gl.clearColor(\n\t\t\tthis.clearColor[0],\n\t\t\tthis.clearColor[1],\n\t\t\tthis.clearColor[2],\n\t\t\tthis.clearColor[3],\n\t\t);\n\t\tthis.gl.clear(this.gl.COLOR_BUFFER_BIT);\n\n\t\tthis.gl.useProgram(this.program);\n\t\tthis.gl.bindVertexArray(this.vao);\n\t\tthis.gl.uniformMatrix3fv(\n\t\t\tthis.uCameraLocation,\n\t\t\tfalse,\n\t\t\tthis.camera.getMatrix(),\n\t\t);\n\t\tthis.gl.uniform1i(this.uTextureLocation, 0);\n\n\t\tfor (const tile of this.tiles) {\n\t\t\tthis.gl.activeTexture(this.gl.TEXTURE0);\n\t\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, tile.texture);\n\t\t\tthis.gl.uniform4f(\n\t\t\t\tthis.uBoundsLocation,\n\t\t\t\ttile.bounds[0],\n\t\t\t\ttile.bounds[1],\n\t\t\t\ttile.bounds[2],\n\t\t\t\ttile.bounds[3],\n\t\t\t);\n\t\t\tthis.gl.drawArrays(this.gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tthis.gl.bindTexture(this.gl.TEXTURE_2D, null);\n\t\tthis.gl.bindVertexArray(null);\n\t}\n\n\tprivate disposeTiles(tiles: LoadedTile[]): void {\n\t\tfor (const tile of tiles) {\n\t\t\tthis.gl.deleteTexture(tile.texture);\n\t\t}\n\t}\n}\n","import type { WsiRegionCoordinates } from \"./types\";\n\nexport type RoiCoordinate = [number, number];\nexport type RoiLinearRing = RoiCoordinate[];\nexport type RoiPolygonRings = RoiLinearRing[];\nexport type RoiMultiPolygon = RoiPolygonRings[];\nexport type RoiGeometry = RoiLinearRing | RoiPolygonRings | RoiMultiPolygon;\n\nexport function toRoiGeometry(coords: WsiRegionCoordinates | null | undefined): RoiGeometry | null | undefined;\nexport function toRoiGeometry(coords: unknown): RoiGeometry | null | undefined;\nexport function toRoiGeometry(coords: unknown): RoiGeometry | null | undefined {\n\tif (coords == null) return null;\n\treturn coords as RoiGeometry;\n}\n\nexport interface PreparedRoiPolygon {\n\touter: RoiLinearRing;\n\tholes: RoiLinearRing[];\n\tminX: number;\n\tminY: number;\n\tmaxX: number;\n\tmaxY: number;\n\tarea: number;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is RoiCoordinate {\n\treturn (\n\t\tArray.isArray(value) &&\n\t\tvalue.length >= 2 &&\n\t\tisFiniteNumber(value[0]) &&\n\t\tisFiniteNumber(value[1])\n\t);\n}\n\nfunction isLinearRing(value: unknown): value is RoiLinearRing {\n\treturn Array.isArray(value) && value.length > 0 && value.every(point => isCoordinatePair(point));\n}\n\nfunction isPolygonRings(value: unknown): value is RoiPolygonRings {\n\treturn Array.isArray(value) && value.length > 0 && value.every(ring => isLinearRing(ring));\n}\n\nfunction isMultiPolygon(value: unknown): value is RoiMultiPolygon {\n\treturn Array.isArray(value) && value.length > 0 && value.every(polygon => isPolygonRings(polygon));\n}\n\nexport function closeRoiRing(coordinates: readonly RoiCoordinate[]): RoiLinearRing {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out: RoiLinearRing = [];\n\tfor (const point of coordinates) {\n\t\tif (!Array.isArray(point) || point.length < 2) continue;\n\t\tconst x = Number(point[0]);\n\t\tconst y = Number(point[1]);\n\t\tif (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && prev[0] === x && prev[1] === y) continue;\n\t\tout.push([x, y]);\n\t}\n\tif (out.length < 3) return [];\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out.length >= 4 ? out : [];\n}\n\nexport function polygonSignedArea(ring: RoiLinearRing): number {\n\tif (!Array.isArray(ring) || ring.length < 4) return 0;\n\tlet sum = 0;\n\tfor (let i = 0; i < ring.length - 1; i += 1) {\n\t\tconst a = ring[i];\n\t\tconst b = ring[i + 1];\n\t\tsum += a[0] * b[1] - b[0] * a[1];\n\t}\n\treturn sum * 0.5;\n}\n\nfunction normalizePolygonRings(rings: RoiPolygonRings): RoiPolygonRings {\n\tif (!Array.isArray(rings) || rings.length === 0) return [];\n\tconst normalized: RoiLinearRing[] = [];\n\tfor (const ring of rings) {\n\t\tconst closed = closeRoiRing(ring);\n\t\tif (closed.length >= 4) normalized.push(closed);\n\t}\n\tif (normalized.length === 0) return [];\n\tif (normalized.length === 1) return [normalized[0]];\n\n\tlet outerIndex = 0;\n\tlet outerArea = 0;\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tconst area = Math.abs(polygonSignedArea(normalized[i]));\n\t\tif (area <= outerArea) continue;\n\t\touterArea = area;\n\t\touterIndex = i;\n\t}\n\n\tconst out: RoiPolygonRings = [normalized[outerIndex]];\n\tfor (let i = 0; i < normalized.length; i += 1) {\n\t\tif (i === outerIndex) continue;\n\t\tout.push(normalized[i]);\n\t}\n\treturn out;\n}\n\nexport function normalizeRoiGeometry(geometry: RoiGeometry | null | undefined): RoiMultiPolygon {\n\tif (!geometry) return [];\n\n\tif (isLinearRing(geometry)) {\n\t\tconst polygon = normalizePolygonRings([geometry]);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isPolygonRings(geometry)) {\n\t\tconst polygon = normalizePolygonRings(geometry);\n\t\treturn polygon.length > 0 ? [polygon] : [];\n\t}\n\n\tif (isMultiPolygon(geometry)) {\n\t\tconst out: RoiMultiPolygon = [];\n\t\tfor (const polygon of geometry) {\n\t\t\tconst normalized = normalizePolygonRings(polygon);\n\t\t\tif (normalized.length > 0) out.push(normalized);\n\t\t}\n\t\treturn out;\n\t}\n\n\treturn [];\n}\n\nexport function pointInRing(x: number, y: number, ring: RoiLinearRing): boolean {\n\tlet inside = false;\n\tfor (let i = 0, j = ring.length - 1; i < ring.length; j = i, i += 1) {\n\t\tconst xi = ring[i][0];\n\t\tconst yi = ring[i][1];\n\t\tconst xj = ring[j][0];\n\t\tconst yj = ring[j][1];\n\t\tconst intersect =\n\t\t\tyi > y !== yj > y &&\n\t\t\tx < ((xj - xi) * (y - yi)) / ((yj - yi) || Number.EPSILON) + xi;\n\t\tif (intersect) inside = !inside;\n\t}\n\treturn inside;\n}\n\nexport function pointInPolygonWithHoles(\n\tx: number,\n\ty: number,\n\tpolygon: RoiPolygonRings,\n): boolean {\n\tif (!Array.isArray(polygon) || polygon.length === 0) return false;\n\tconst outer = polygon[0];\n\tif (!outer || outer.length < 4) return false;\n\tif (!pointInRing(x, y, outer)) return false;\n\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\tconst hole = polygon[i];\n\t\tif (!hole || hole.length < 4) continue;\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function prepareRoiPolygons(\n\tgeometries: readonly (RoiGeometry | null | undefined)[] | null | undefined,\n): PreparedRoiPolygon[] {\n\tconst prepared: PreparedRoiPolygon[] = [];\n\tfor (const geometry of geometries ?? []) {\n\t\tconst multipolygon = normalizeRoiGeometry(geometry);\n\t\tfor (const polygon of multipolygon) {\n\t\t\tconst outer = polygon[0];\n\t\t\tif (!outer || outer.length < 4) continue;\n\t\t\tlet minX = Infinity;\n\t\t\tlet minY = Infinity;\n\t\t\tlet maxX = -Infinity;\n\t\t\tlet maxY = -Infinity;\n\t\t\tfor (const [x, y] of outer) {\n\t\t\t\tif (x < minX) minX = x;\n\t\t\t\tif (x > maxX) maxX = x;\n\t\t\t\tif (y < minY) minY = y;\n\t\t\t\tif (y > maxY) maxY = y;\n\t\t\t}\n\t\t\tif (\n\t\t\t\t!Number.isFinite(minX) ||\n\t\t\t\t!Number.isFinite(minY) ||\n\t\t\t\t!Number.isFinite(maxX) ||\n\t\t\t\t!Number.isFinite(maxY)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet area = Math.abs(polygonSignedArea(outer));\n\t\t\tfor (let i = 1; i < polygon.length; i += 1) {\n\t\t\t\tarea -= Math.abs(polygonSignedArea(polygon[i]));\n\t\t\t}\n\t\t\tprepared.push({\n\t\t\t\touter,\n\t\t\t\tholes: polygon.slice(1),\n\t\t\t\tminX,\n\t\t\t\tminY,\n\t\t\t\tmaxX,\n\t\t\t\tmaxY,\n\t\t\t\tarea: Math.max(1e-6, area),\n\t\t\t});\n\t\t}\n\t}\n\treturn prepared;\n}\n\nexport function pointInPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygon: PreparedRoiPolygon,\n): boolean {\n\tif (x < polygon.minX || x > polygon.maxX || y < polygon.minY || y > polygon.maxY) {\n\t\treturn false;\n\t}\n\tif (!pointInRing(x, y, polygon.outer)) return false;\n\tfor (const hole of polygon.holes) {\n\t\tif (pointInRing(x, y, hole)) return false;\n\t}\n\treturn true;\n}\n\nexport function pointInAnyPreparedPolygon(\n\tx: number,\n\ty: number,\n\tpolygons: readonly PreparedRoiPolygon[],\n): boolean {\n\tfor (const polygon of polygons) {\n\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\treturn true;\n\t}\n\treturn false;\n}\n","export const DEFAULT_POINT_COLOR: [number, number, number, number] = [\n\t160, 160, 160, 255,\n];\n","import { DEFAULT_POINT_COLOR } from \"./constants\";\nimport type { TermPalette, WsiPointData, WsiViewState } from \"./types\";\n\nexport function clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nexport function calcScaleResolution(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): number {\n\tconst mpp = Number(imageMpp);\n\tconst z0 = Number(imageZoom);\n\tconst z1 = Number(currentZoom);\n\tif (!Number.isFinite(mpp) || mpp <= 0) return 1;\n\tif (!Number.isFinite(z0) || !Number.isFinite(z1)) return mpp;\n\treturn Math.pow(2, z0 - z1) * mpp;\n}\n\nexport function calcScaleLength(\n\timageMpp: number,\n\timageZoom: number,\n\tcurrentZoom: number,\n): string {\n\tconst resolution = calcScaleResolution(imageMpp, imageZoom, currentZoom);\n\tlet length = 100 * resolution;\n\tif (Number(imageMpp)) {\n\t\tlet unit = \"μm\";\n\t\tif (length > 1000) {\n\t\t\tlength /= 1000;\n\t\t\tunit = \"mm\";\n\t\t}\n\t\treturn `${length.toPrecision(3)} ${unit}`;\n\t}\n\treturn `${Math.round(length * 1000) / 1000} pixels`;\n}\n\nexport function nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nexport function sanitizePointCount(pointData: WsiPointData): number {\n\tconst fillModesLength =\n\t\tpointData.fillModes instanceof Uint8Array\n\t\t\t? pointData.fillModes.length\n\t\t\t: Number.MAX_SAFE_INTEGER;\n\treturn Math.max(\n\t\t0,\n\t\tMath.min(\n\t\t\tMath.floor(pointData.count ?? 0),\n\t\t\tMath.floor((pointData.positions?.length ?? 0) / 2),\n\t\t\tpointData.paletteIndices?.length ?? 0,\n\t\t\tfillModesLength,\n\t\t),\n\t);\n}\n\nexport function isSameViewState(\n\ta: Partial<WsiViewState> | null | undefined,\n\tb: Partial<WsiViewState> | null | undefined,\n): boolean {\n\tif (!a && !b) return true;\n\tif (!a || !b) return false;\n\treturn (\n\t\tMath.abs((a.zoom ?? 0) - (b.zoom ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetX ?? 0) - (b.offsetX ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.offsetY ?? 0) - (b.offsetY ?? 0)) < 1e-6 &&\n\t\tMath.abs((a.rotationDeg ?? 0) - (b.rotationDeg ?? 0)) < 1e-6\n\t);\n}\n\nexport function toBearerToken(value: string | null | undefined): string {\n\tconst trimmed = String(value ?? \"\").trim();\n\tif (!trimmed) return \"\";\n\tif (/^bearer\\s+/i.test(trimmed)) {\n\t\tconst token = trimmed.replace(/^bearer\\s+/i, \"\").trim();\n\t\treturn token ? `Bearer ${token}` : \"\";\n\t}\n\treturn `Bearer ${trimmed}`;\n}\n\nexport function hexToRgba(\n\thex: string | null | undefined,\n): [number, number, number, number] {\n\tconst value = String(hex ?? \"\").trim();\n\tconst match = value.match(/^#?([0-9a-fA-F]{6})$/);\n\tif (!match) return [...DEFAULT_POINT_COLOR];\n\n\tconst n = Number.parseInt(match[1], 16);\n\treturn [(n >> 16) & 255, (n >> 8) & 255, n & 255, 255];\n}\n\nexport function buildTermPalette(\n\tterms:\n\t\t| Array<{ termId?: string | null; termColor?: string | null }>\n\t\t| null\n\t\t| undefined,\n): TermPalette {\n\tconst palette: Array<[number, number, number, number]> = [\n\t\t[...DEFAULT_POINT_COLOR],\n\t];\n\tconst termToPaletteIndex = new Map<string, number>();\n\n\tfor (const term of terms ?? []) {\n\t\tconst termId = String(term?.termId ?? \"\");\n\t\tif (!termId || termToPaletteIndex.has(termId)) continue;\n\n\t\ttermToPaletteIndex.set(termId, palette.length);\n\t\tpalette.push(hexToRgba(term?.termColor));\n\t}\n\n\tconst colors = new Uint8Array(palette.length * 4);\n\tfor (let i = 0; i < palette.length; i += 1) {\n\t\tcolors[i * 4] = palette[i][0];\n\t\tcolors[i * 4 + 1] = palette[i][1];\n\t\tcolors[i * 4 + 2] = palette[i][2];\n\t\tcolors[i * 4 + 3] = palette[i][3];\n\t}\n\n\treturn { colors, termToPaletteIndex };\n}\n","import { closeRoiRing as closeRing, polygonSignedArea } from \"./roi-geometry\";\nimport { clamp } from \"./utils\";\n\nexport type BrushStrokeCoordinate = [number, number];\nexport type BrushStrokeBounds = [number, number, number, number];\n\nexport interface BrushStrokePolygonOptions {\n\tradius: number;\n\tclipBounds?: BrushStrokeBounds;\n\tminRasterStep?: number;\n\tmaxRasterPixels?: number;\n\tmaxRasterSize?: number;\n\tsimplifyTolerance?: number;\n\tcircleSides?: number;\n\tsmoothingPasses?: number;\n}\n\ninterface RasterConfig {\n\tminX: number;\n\tminY: number;\n\tstep: number;\n\tpadding: number;\n\twidth: number;\n\theight: number;\n}\n\ninterface BoundaryEdge {\n\tstart: number;\n\tend: number;\n\tdir: 0 | 1 | 2 | 3;\n}\n\nconst DEFAULT_MIN_RASTER_STEP = 0.1;\nconst DEFAULT_MAX_RASTER_PIXELS = 4_000_000;\nconst DEFAULT_MAX_RASTER_SIZE = 4096;\nconst DEFAULT_CIRCLE_SIDES = 64;\nconst DEFAULT_SMOOTHING_PASSES = 1;\nconst MAX_SMOOTHING_PASSES = 4;\nconst MIN_RADIUS = 1e-6;\nconst ALPHA_THRESHOLD = 24;\n\nfunction sanitizePath(\n\tpoints: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(points) || points.length === 0) return [];\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (const point of points) {\n\t\tif (!Array.isArray(point) || point.length < 2) continue;\n\t\tconst x = Number(point[0]);\n\t\tconst y = Number(point[1]);\n\t\tif (!Number.isFinite(x) || !Number.isFinite(y)) continue;\n\t\tconst prev = out[out.length - 1];\n\t\tif (prev && Math.abs(prev[0] - x) < 1e-9 && Math.abs(prev[1] - y) < 1e-9) {\n\t\t\tcontinue;\n\t\t}\n\t\tout.push([x, y]);\n\t}\n\treturn out;\n}\n\nfunction createCirclePolygon(\n\tcenter: BrushStrokeCoordinate,\n\tradius: number,\n\tsides: number,\n): BrushStrokeCoordinate[] {\n\tif (radius <= MIN_RADIUS || sides < 8) return [];\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i <= sides; i += 1) {\n\t\tconst t = (i / sides) * Math.PI * 2;\n\t\tring.push([\n\t\t\tcenter[0] + Math.cos(t) * radius,\n\t\t\tcenter[1] + Math.sin(t) * radius,\n\t\t]);\n\t}\n\treturn closeRing(ring);\n}\n\nfunction createBoundsFallback(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeCoordinate[] {\n\tif (!points.length) return [];\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\n\t\tif (x < minX) minX = x;\n\t\tif (x > maxX) maxX = x;\n\t\tif (y < minY) minY = y;\n\t\tif (y > maxY) maxY = y;\n\t}\n\tif (!Number.isFinite(minX) || !Number.isFinite(minY)) return [];\n\tconst pad = Math.max(radius, 1);\n\treturn closeRing([\n\t\t[minX - pad, minY - pad],\n\t\t[maxX + pad, minY - pad],\n\t\t[maxX + pad, maxY + pad],\n\t\t[minX - pad, maxY + pad],\n\t]);\n}\n\nfunction computeExpandedBounds(\n\tpoints: BrushStrokeCoordinate[],\n\tradius: number,\n): BrushStrokeBounds {\n\tlet minX = Infinity;\n\tlet minY = Infinity;\n\tlet maxX = -Infinity;\n\tlet maxY = -Infinity;\n\tfor (const [x, y] of points) {\n\t\tif (x < minX) minX = x;\n\t\tif (x > maxX) maxX = x;\n\t\tif (y < minY) minY = y;\n\t\tif (y > maxY) maxY = y;\n\t}\n\tconst pad = Math.max(radius, 1);\n\treturn [minX - pad, minY - pad, maxX + pad, maxY + pad];\n}\n\nfunction resolveRasterConfig(\n\tbounds: BrushStrokeBounds,\n\tradius: number,\n\toptions: BrushStrokePolygonOptions,\n): RasterConfig {\n\tconst minRasterStep = Math.max(\n\t\tDEFAULT_MIN_RASTER_STEP,\n\t\tNumber(options.minRasterStep) || 0,\n\t);\n\tconst maxRasterPixels = Math.max(\n\t\t32_768,\n\t\tMath.floor(options.maxRasterPixels || DEFAULT_MAX_RASTER_PIXELS),\n\t);\n\tconst maxRasterSize = Math.max(\n\t\t256,\n\t\tMath.floor(options.maxRasterSize || DEFAULT_MAX_RASTER_SIZE),\n\t);\n\n\tconst widthWorld = Math.max(1e-3, bounds[2] - bounds[0]);\n\tconst heightWorld = Math.max(1e-3, bounds[3] - bounds[1]);\n\tlet step = Math.max(minRasterStep, Number.EPSILON);\n\tlet padding = 3;\n\tlet width = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\tlet height = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\n\twhile (\n\t\twidth > maxRasterSize ||\n\t\theight > maxRasterSize ||\n\t\twidth * height > maxRasterPixels\n\t) {\n\t\tstep *= 1.15;\n\t\twidth = Math.ceil(widthWorld / step) + padding * 2 + 1;\n\t\theight = Math.ceil(heightWorld / step) + padding * 2 + 1;\n\t\tif (step > Math.max(widthWorld, heightWorld)) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\twidth = Math.max(8, width);\n\theight = Math.max(8, height);\n\n\treturn {\n\t\tminX: bounds[0],\n\t\tminY: bounds[1],\n\t\tstep,\n\t\tpadding,\n\t\twidth,\n\t\theight,\n\t};\n}\n\ntype AnyCanvas2DContext =\n\t| CanvasRenderingContext2D\n\t| OffscreenCanvasRenderingContext2D;\n\nfunction createRasterContext(\n\twidth: number,\n\theight: number,\n): AnyCanvas2DContext | null {\n\tif (typeof OffscreenCanvas !== \"undefined\") {\n\t\tconst canvas = new OffscreenCanvas(width, height);\n\t\tconst context = canvas.getContext(\"2d\", { willReadFrequently: true });\n\t\tif (context) return context;\n\t}\n\tif (typeof document !== \"undefined\") {\n\t\tconst canvas = document.createElement(\"canvas\");\n\t\tcanvas.width = width;\n\t\tcanvas.height = height;\n\t\treturn canvas.getContext(\"2d\", { willReadFrequently: true });\n\t}\n\treturn null;\n}\n\nfunction worldToRaster(\n\tpoint: BrushStrokeCoordinate,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate {\n\treturn [\n\t\t(point[0] - config.minX) / config.step + config.padding,\n\t\t(point[1] - config.minY) / config.step + config.padding,\n\t];\n}\n\nfunction rasterizeStrokeMask(\n\tpath: BrushStrokeCoordinate[],\n\tradius: number,\n\tconfig: RasterConfig,\n): Uint8Array {\n\tconst context = createRasterContext(config.width, config.height);\n\tif (!context) return new Uint8Array(0);\n\n\tcontext.clearRect(0, 0, config.width, config.height);\n\tcontext.fillStyle = \"#ffffff\";\n\tcontext.strokeStyle = \"#ffffff\";\n\tcontext.lineCap = \"round\";\n\tcontext.lineJoin = \"round\";\n\tcontext.lineWidth = (radius * 2) / config.step;\n\n\tconst points = path.map(point => worldToRaster(point, config));\n\tif (points.length <= 1) {\n\t\tconst p = points[0];\n\t\tif (!p) return new Uint8Array(0);\n\t\tcontext.beginPath();\n\t\tcontext.arc(p[0], p[1], radius / config.step, 0, Math.PI * 2);\n\t\tcontext.fill();\n\t} else {\n\t\tcontext.beginPath();\n\t\tcontext.moveTo(points[0][0], points[0][1]);\n\t\tfor (let i = 1; i < points.length; i += 1) {\n\t\t\tcontext.lineTo(points[i][0], points[i][1]);\n\t\t}\n\t\tcontext.stroke();\n\t}\n\n\tconst image = context.getImageData(0, 0, config.width, config.height);\n\tconst out = new Uint8Array(config.width * config.height);\n\tfor (let i = 0; i < out.length; i += 1) {\n\t\tout[i] = image.data[i * 4 + 3] >= ALPHA_THRESHOLD ? 1 : 0;\n\t}\n\treturn out;\n}\n\nfunction buildBoundaryEdges(mask: Uint8Array, width: number, height: number): BoundaryEdge[] {\n\tconst edges: BoundaryEdge[] = [];\n\tconst stride = width + 1;\n\tconst vertex = (x: number, y: number): number => y * stride + x;\n\tconst at = (x: number, y: number): boolean =>\n\t\tx >= 0 && y >= 0 && x < width && y < height && mask[y * width + x] > 0;\n\n\tfor (let y = 0; y < height; y += 1) {\n\t\tfor (let x = 0; x < width; x += 1) {\n\t\t\tif (!at(x, y)) continue;\n\t\t\tif (!at(x, y - 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y),\n\t\t\t\t\tend: vertex(x + 1, y),\n\t\t\t\t\tdir: 0,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x + 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y),\n\t\t\t\t\tend: vertex(x + 1, y + 1),\n\t\t\t\t\tdir: 1,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x, y + 1)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x + 1, y + 1),\n\t\t\t\t\tend: vertex(x, y + 1),\n\t\t\t\t\tdir: 2,\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!at(x - 1, y)) {\n\t\t\t\tedges.push({\n\t\t\t\t\tstart: vertex(x, y + 1),\n\t\t\t\t\tend: vertex(x, y),\n\t\t\t\t\tdir: 3,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\treturn edges;\n}\n\nfunction turnPriority(fromDir: number, toDir: number): number {\n\tconst delta = (toDir - fromDir + 4) % 4;\n\tif (delta === 1) return 0; // right\n\tif (delta === 0) return 1; // straight\n\tif (delta === 3) return 2; // left\n\treturn 3; // reverse\n}\n\nfunction traceLoops(edges: BoundaryEdge[]): number[][] {\n\tif (!edges.length) return [];\n\n\tconst outgoing = new Map<number, number[]>();\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tconst entry = outgoing.get(edges[i].start);\n\t\tif (entry) {\n\t\t\tentry.push(i);\n\t\t} else {\n\t\t\toutgoing.set(edges[i].start, [i]);\n\t\t}\n\t}\n\n\tconst used = new Uint8Array(edges.length);\n\tconst loops: number[][] = [];\n\n\tfor (let i = 0; i < edges.length; i += 1) {\n\t\tif (used[i]) continue;\n\n\t\tconst first = edges[i];\n\t\tconst startVertex = first.start;\n\t\tlet currentVertex = first.end;\n\t\tlet currentDir = first.dir;\n\t\tconst loop: number[] = [first.start, first.end];\n\t\tused[i] = 1;\n\n\t\tlet guard = 0;\n\t\tconst guardLimit = edges.length * 3;\n\t\twhile (currentVertex !== startVertex && guard < guardLimit) {\n\t\t\tconst candidates = outgoing.get(currentVertex);\n\t\t\tif (!candidates || candidates.length === 0) break;\n\n\t\t\tlet bestIndex = -1;\n\t\t\tlet bestPriority = Infinity;\n\t\t\tfor (const edgeIndex of candidates) {\n\t\t\t\tif (used[edgeIndex]) continue;\n\t\t\t\tconst candidate = edges[edgeIndex];\n\t\t\t\tconst priority = turnPriority(currentDir, candidate.dir);\n\t\t\t\tif (priority < bestPriority) {\n\t\t\t\t\tbestPriority = priority;\n\t\t\t\t\tbestIndex = edgeIndex;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (bestIndex < 0) break;\n\t\t\tused[bestIndex] = 1;\n\t\t\tconst next = edges[bestIndex];\n\t\t\tcurrentVertex = next.end;\n\t\t\tcurrentDir = next.dir;\n\t\t\tloop.push(currentVertex);\n\t\t\tguard += 1;\n\t\t}\n\n\t\tif (\n\t\t\tloop.length >= 4 &&\n\t\t\tloop[0] === loop[loop.length - 1]\n\t\t) {\n\t\t\tloops.push(loop);\n\t\t}\n\t}\n\n\treturn loops;\n}\n\nfunction toWorldRing(\n\tvertexLoop: number[],\n\twidth: number,\n\tconfig: RasterConfig,\n): BrushStrokeCoordinate[] {\n\tconst stride = width + 1;\n\tconst ring: BrushStrokeCoordinate[] = [];\n\tfor (const id of vertexLoop) {\n\t\tconst x = id % stride;\n\t\tconst y = Math.floor(id / stride);\n\t\tring.push([\n\t\t\tconfig.minX + (x - config.padding) * config.step,\n\t\t\tconfig.minY + (y - config.padding) * config.step,\n\t\t]);\n\t}\n\treturn closeRing(ring);\n}\n\nfunction removeCollinearVertices(\n\tring: BrushStrokeCoordinate[],\n\tepsilon = 1e-9,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5) return closed;\n\tconst out: BrushStrokeCoordinate[] = [closed[0]];\n\tfor (let i = 1; i < closed.length - 1; i += 1) {\n\t\tconst prev = out[out.length - 1];\n\t\tconst curr = closed[i];\n\t\tconst next = closed[i + 1];\n\t\tconst cross =\n\t\t\t(curr[0] - prev[0]) * (next[1] - curr[1]) -\n\t\t\t(curr[1] - prev[1]) * (next[0] - curr[0]);\n\t\tif (Math.abs(cross) <= epsilon) continue;\n\t\tout.push(curr);\n\t}\n\tout.push(out[0]);\n\treturn closeRing(out);\n}\n\nfunction pointLineDistanceSquared(\n\tp: BrushStrokeCoordinate,\n\ta: BrushStrokeCoordinate,\n\tb: BrushStrokeCoordinate,\n): number {\n\tconst abx = b[0] - a[0];\n\tconst aby = b[1] - a[1];\n\tconst len2 = abx * abx + aby * aby;\n\tif (len2 <= 1e-12) {\n\t\tconst dx = p[0] - a[0];\n\t\tconst dy = p[1] - a[1];\n\t\treturn dx * dx + dy * dy;\n\t}\n\tconst t = clamp(\n\t\t((p[0] - a[0]) * abx + (p[1] - a[1]) * aby) / len2,\n\t\t0,\n\t\t1,\n\t);\n\tconst x = a[0] + abx * t;\n\tconst y = a[1] + aby * t;\n\tconst dx = p[0] - x;\n\tconst dy = p[1] - y;\n\treturn dx * dx + dy * dy;\n}\n\nfunction simplifyRdp(\n\tpoints: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tif (points.length <= 2 || tolerance <= 0) return points.slice();\n\n\tconst keep = new Uint8Array(points.length);\n\tkeep[0] = 1;\n\tkeep[points.length - 1] = 1;\n\tconst tolerance2 = tolerance * tolerance;\n\tconst stack: Array<[number, number]> = [[0, points.length - 1]];\n\n\twhile (stack.length > 0) {\n\t\tconst next = stack.pop();\n\t\tif (!next) break;\n\t\tconst [start, end] = next;\n\t\tif (end - start <= 1) continue;\n\n\t\tlet maxDist2 = 0;\n\t\tlet split = -1;\n\t\tfor (let i = start + 1; i < end; i += 1) {\n\t\t\tconst dist2 = pointLineDistanceSquared(points[i], points[start], points[end]);\n\t\t\tif (dist2 > maxDist2) {\n\t\t\t\tmaxDist2 = dist2;\n\t\t\t\tsplit = i;\n\t\t\t}\n\t\t}\n\n\t\tif (split >= 0 && maxDist2 > tolerance2) {\n\t\t\tkeep[split] = 1;\n\t\t\tstack.push([start, split], [split, end]);\n\t\t}\n\t}\n\n\tconst out: BrushStrokeCoordinate[] = [];\n\tfor (let i = 0; i < points.length; i += 1) {\n\t\tif (keep[i]) out.push(points[i]);\n\t}\n\treturn out;\n}\n\nfunction simplifyClosedRing(\n\tring: BrushStrokeCoordinate[],\n\ttolerance: number,\n): BrushStrokeCoordinate[] {\n\tconst closed = closeRing(ring);\n\tif (closed.length < 5 || tolerance <= 0) return closed;\n\tconst open = closed.slice(0, -1);\n\tconst simplified = simplifyRdp(open, tolerance);\n\tif (simplified.length < 3) return closed;\n\treturn closeRing(simplified);\n}\n\nfunction smoothClosedRingChaikin(\n\tring: BrushStrokeCoordinate[],\n\titerations: number,\n): BrushStrokeCoordinate[] {\n\tlet out = closeRing(ring);\n\tif (iterations <= 0 || out.length < 5) return out;\n\n\tfor (let pass = 0; pass < iterations; pass += 1) {\n\t\tconst open = out.slice(0, -1);\n\t\tif (open.length < 3) break;\n\t\tconst next: BrushStrokeCoordinate[] = [];\n\t\tfor (let i = 0; i < open.length; i += 1) {\n\t\t\tconst a = open[i];\n\t\t\tconst b = open[(i + 1) % open.length];\n\t\t\tnext.push(\n\t\t\t\t[a[0] * 0.75 + b[0] * 0.25, a[1] * 0.75 + b[1] * 0.25],\n\t\t\t\t[a[0] * 0.25 + b[0] * 0.75, a[1] * 0.25 + b[1] * 0.75],\n\t\t\t);\n\t\t}\n\t\tout = closeRing(next);\n\t}\n\treturn out;\n}\n\nfunction clampRingToBounds(\n\tring: BrushStrokeCoordinate[],\n\tbounds: BrushStrokeBounds | undefined,\n): BrushStrokeCoordinate[] {\n\tif (!bounds) return ring;\n\treturn closeRing(\n\t\tring.map(([x, y]) => [\n\t\t\tclamp(x, bounds[0], bounds[2]),\n\t\t\tclamp(y, bounds[1], bounds[3]),\n\t\t] as BrushStrokeCoordinate),\n\t);\n}\n\nexport function buildBrushStrokePolygon(\n\tpath: BrushStrokeCoordinate[],\n\toptions: BrushStrokePolygonOptions,\n): BrushStrokeCoordinate[] {\n\tconst points = sanitizePath(path);\n\tconst radius = Math.max(MIN_RADIUS, Number(options.radius) || 0);\n\tif (points.length === 0 || !Number.isFinite(radius)) return [];\n\n\tconst circleSides = Math.max(12, Math.floor(options.circleSides || DEFAULT_CIRCLE_SIDES));\n\tif (points.length === 1) {\n\t\treturn clampRingToBounds(\n\t\t\tcreateCirclePolygon(points[0], radius, circleSides),\n\t\t\toptions.clipBounds,\n\t\t);\n\t}\n\n\tconst bounds = computeExpandedBounds(points, radius);\n\tconst raster = resolveRasterConfig(bounds, radius, options);\n\tconst mask = rasterizeStrokeMask(points, radius, raster);\n\tif (!mask.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst edges = buildBoundaryEdges(mask, raster.width, raster.height);\n\tconst loops = traceLoops(edges);\n\tif (!loops.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tlet bestRing: BrushStrokeCoordinate[] = [];\n\tlet bestArea = 0;\n\tfor (const loop of loops) {\n\t\tconst ring = toWorldRing(loop, raster.width, raster);\n\t\tconst area = Math.abs(polygonSignedArea(ring));\n\t\tif (area <= bestArea) continue;\n\t\tbestArea = area;\n\t\tbestRing = ring;\n\t}\n\n\tif (!bestRing.length) {\n\t\treturn clampRingToBounds(createBoundsFallback(points, radius), options.clipBounds);\n\t}\n\n\tconst tolerance =\n\t\ttypeof options.simplifyTolerance === \"number\" && Number.isFinite(options.simplifyTolerance)\n\t\t\t? Math.max(0, options.simplifyTolerance)\n\t\t\t: raster.step * 0.2;\n\tconst smoothingPasses =\n\t\ttypeof options.smoothingPasses === \"number\" && Number.isFinite(options.smoothingPasses)\n\t\t\t? Math.round(clamp(options.smoothingPasses, 0, MAX_SMOOTHING_PASSES))\n\t\t\t: DEFAULT_SMOOTHING_PASSES;\n\tconst simplified = simplifyClosedRing(\n\t\tsmoothClosedRingChaikin(\n\t\t\tremoveCollinearVertices(bestRing, raster.step * 1e-3),\n\t\t\tsmoothingPasses,\n\t\t),\n\t\ttolerance,\n\t);\n\treturn clampRingToBounds(simplified, options.clipBounds);\n}\n","import type { CSSProperties, MutableRefObject, RefObject } from \"react\";\n\nexport type StampDrawTool =\n | \"stamp-rectangle\"\n | \"stamp-circle\"\n | \"stamp-rectangle-4096px\"\n | \"stamp-rectangle-2mm2\"\n | \"stamp-circle-2mm2\"\n | \"stamp-circle-hpf-0.2mm2\";\n\nexport type DrawTool = \"cursor\" | \"freehand\" | \"rectangle\" | \"circular\" | \"brush\" | StampDrawTool;\n\nexport type DrawCoordinate = [number, number];\n\nexport type DrawBounds = [number, number, number, number];\nexport type DrawRegionCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\n\nexport type DrawIntent = \"roi\" | \"patch\" | \"brush\";\n\nexport interface DrawResult {\n tool: Exclude<DrawTool, \"cursor\">;\n intent: DrawIntent;\n coordinates: DrawCoordinate[];\n bbox: DrawBounds;\n areaPx: number;\n}\n\nexport type PatchDrawResult = DrawResult & {\n tool: \"stamp-rectangle-4096px\";\n intent: \"patch\";\n};\n\nexport interface DrawRegion {\n id?: string | number;\n coordinates: DrawRegionCoordinates;\n label?: string;\n}\n\nexport interface RegionStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n state: \"default\" | \"hover\" | \"active\";\n}\n\nexport type RegionStrokeStyleResolver = (context: RegionStyleContext) => Partial<RegionStrokeStyle> | null | undefined;\n\nexport interface RegionLabelStyleContext {\n region: DrawRegion;\n regionId: string | number;\n regionIndex: number;\n zoom: number;\n}\n\nexport type RegionLabelStyleResolver = (context: RegionLabelStyleContext) => Partial<RegionLabelStyle> | null | undefined;\n\nexport type DrawOverlayCoordinates = DrawCoordinate[] | DrawCoordinate[][] | DrawCoordinate[][][];\n\nexport interface DrawOverlayShape {\n id?: string | number;\n coordinates: DrawOverlayCoordinates;\n closed?: boolean;\n fill?: boolean;\n stroke?: Partial<RegionStrokeStyle>;\n strokeStyle?: Partial<RegionStrokeStyle>;\n invertedFill?: DrawOverlayInvertedFillStyle;\n visible?: boolean;\n}\n\nexport interface DrawOverlayInvertedFillStyle {\n fillColor: string;\n}\n\nexport interface RegionStrokeStyle {\n color: string;\n width: number;\n lineDash: number[];\n lineJoin: CanvasLineJoin;\n lineCap: CanvasLineCap;\n shadowColor: string;\n shadowBlur: number;\n shadowOffsetX: number;\n shadowOffsetY: number;\n}\n\nexport interface RegionLabelStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderColor: string;\n borderWidth: number;\n paddingX: number;\n paddingY: number;\n offsetY: number;\n borderRadius: number;\n}\n\nexport type RegionLabelAnchorMode = \"top-center\" | \"top-left\";\n\nexport interface DrawAreaTooltipStyle {\n fontFamily: string;\n fontSize: number;\n fontWeight: string | number;\n textColor: string;\n backgroundColor: string;\n borderRadius: number;\n paddingX: number;\n paddingY: number;\n}\n\nexport interface DrawAreaTooltipOptions {\n enabled?: boolean;\n format?: (areaMm2: number) => string;\n style?: Partial<DrawAreaTooltipStyle>;\n cursorOffset?: {\n x: number;\n y: number;\n };\n}\n\nexport interface DrawProjector {\n screenToWorld(clientX: number, clientY: number): DrawCoordinate | number[];\n worldToScreen(worldX: number, worldY: number): DrawCoordinate | number[];\n getViewState?: () => { zoom: number; rotationDeg?: number };\n getZoomRange?: () => { minZoom: number; maxZoom: number };\n zoomBy?: (factor: number, screenX: number, screenY: number) => void;\n}\n\nexport interface StampOptions {\n rectangleAreaMm2?: number;\n circleAreaMm2?: number;\n rectanglePixelSize?: number;\n}\n\nexport interface BrushOptions {\n radius: number;\n edgeDetail?: number;\n edgeSmoothing?: number;\n clickSelectRoi?: boolean;\n fillColor?: string;\n fillOpacity?: number;\n cursorColor?: string;\n cursorActiveColor?: string;\n cursorLineWidth?: number;\n cursorLineDash?: number[];\n}\n\nexport interface DrawLayerProps {\n tool: DrawTool;\n imageWidth: number;\n imageHeight: number;\n imageMpp?: number;\n imageZoom?: number;\n stampOptions?: StampOptions;\n brushOptions?: BrushOptions;\n projectorRef: RefObject<DrawProjector | null>;\n onBrushTap?: (coordinate: DrawCoordinate) => boolean;\n onDrawComplete?: (result: DrawResult) => void;\n onPatchComplete?: (result: PatchDrawResult) => void;\n enabled?: boolean;\n viewStateSignal?: unknown;\n persistedRegions?: DrawRegion[];\n patchRegions?: DrawRegion[];\n persistedPolygons?: DrawRegionCoordinates[];\n drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n hoveredRegionId?: string | number | null;\n activeRegionId?: string | number | null;\n regionLabelStyle?: Partial<RegionLabelStyle>;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\n regionLabelAnchor?: RegionLabelAnchorMode;\n clampRegionLabelToViewport?: boolean;\n regionLabelAutoLiftOffsetPx?: number;\n invalidateRef?: MutableRefObject<(() => void) | null>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport interface DrawSession {\n isDrawing: boolean;\n pointerId: number | null;\n start: DrawCoordinate | null;\n current: DrawCoordinate | null;\n cursor: DrawCoordinate | null;\n cursorScreen: DrawCoordinate | null;\n points: DrawCoordinate[];\n screenPoints: DrawCoordinate[];\n stampCenter: DrawCoordinate | null;\n}\n\nexport interface NormalizedDrawRegionPolygon {\n outer: DrawCoordinate[];\n holes: DrawCoordinate[][];\n}\n\nexport interface PreparedRenderedRegion {\n region: DrawRegion;\n regionIndex: number;\n regionKey: string | number;\n polygons: NormalizedDrawRegionPolygon[];\n}\n\nexport interface ResolvedBrushOptions {\n radius: number;\n edgeDetail: number;\n edgeSmoothing: number;\n clickSelectRoi: boolean;\n fillColor: string;\n fillOpacity: number;\n cursorColor: string;\n cursorActiveColor: string;\n cursorLineWidth: number;\n cursorLineDash: number[];\n}\n\nexport interface ResolvedDrawAreaTooltipOptions {\n enabled: boolean;\n format: (areaMm2: number) => string;\n style: DrawAreaTooltipStyle;\n cursorOffsetX: number;\n cursorOffsetY: number;\n}\n\nexport const EMPTY_DASH: number[] = [];\nexport const EMPTY_REGIONS: DrawRegion[] = [];\n\nexport const DEFAULT_REGION_STROKE_STYLE: RegionStrokeStyle = {\n color: \"#ff4d4f\",\n width: 2,\n lineDash: EMPTY_DASH,\n lineJoin: \"round\",\n lineCap: \"round\",\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n};\n\nexport const DEFAULT_PATCH_STROKE_STYLE: RegionStrokeStyle = {\n color: \"#4cc9f0\",\n width: 2,\n lineDash: [10, 8],\n lineJoin: \"round\",\n lineCap: \"round\",\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n};\n\nexport const REGION_INTERACTION_SHADOW_COLOR = \"rgba(23, 23, 25, 0.1)\";\nexport const REGION_INTERACTION_SHADOW_WIDTH = 6;\n\nexport const DEFAULT_REGION_LABEL_STYLE: RegionLabelStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 11,\n fontWeight: 600,\n textColor: \"#171719\",\n backgroundColor: \"#FFCC00\",\n borderColor: \"rgba(0, 0, 0, 0)\",\n borderWidth: 0,\n paddingX: 8,\n paddingY: 4,\n offsetY: 10,\n borderRadius: 4,\n};\n\nexport const DEFAULT_DRAW_AREA_TOOLTIP_STYLE: DrawAreaTooltipStyle = {\n fontFamily: \"Pretendard, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif\",\n fontSize: 13,\n fontWeight: 500,\n textColor: \"#FFFFFF\",\n backgroundColor: \"rgba(23, 23, 25, 0.5)\",\n borderRadius: 4,\n paddingX: 6,\n paddingY: 3,\n};\n\nexport const DEFAULT_DRAW_AREA_TOOLTIP_OFFSET = {\n x: 16,\n y: -24,\n} as const;\n\nexport const REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\nexport const REGION_LABEL_AUTO_LIFT_MAX_EPSILON = 1e-6;\n\nexport const DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nexport const DEFAULT_DRAW_PREVIEW_FILL = \"transparent\";\nexport const FREEHAND_MIN_POINTS = 3;\nexport const FREEHAND_SCREEN_STEP = 2;\nexport const CIRCLE_SIDES = 96;\nexport const MIN_AREA_PX = 1;\nexport const MICRONS_PER_MM = 1000;\nexport const DEFAULT_STAMP_RECTANGLE_AREA_MM2 = 2;\nexport const DEFAULT_STAMP_CIRCLE_AREA_MM2 = 2;\nexport const DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE = 4096;\nexport const LEGACY_HPF_CIRCLE_AREA_MM2 = 0.2;\nexport const WHEEL_ZOOM_IN_FACTOR = 1.12;\nexport const WHEEL_ZOOM_OUT_FACTOR = 0.89;\nexport const DEFAULT_BRUSH_RADIUS = 32;\nexport const DEFAULT_BRUSH_FILL_COLOR = \"#000000\";\nexport const DEFAULT_BRUSH_FILL_OPACITY = 0.1;\nexport const DEFAULT_BRUSH_CURSOR_COLOR = \"#FFCF00\";\nexport const DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR = \"#FF0000\";\nexport const DEFAULT_BRUSH_CURSOR_LINE_WIDTH = 1.5;\nexport const DEFAULT_BRUSH_CURSOR_DASH = [2, 2];\nexport const DEFAULT_BRUSH_EDGE_DETAIL = 1;\nexport const MIN_BRUSH_EDGE_DETAIL = 0.25;\nexport const MAX_BRUSH_EDGE_DETAIL = 4;\nexport const DEFAULT_BRUSH_EDGE_SMOOTHING = 1;\nexport const MIN_BRUSH_EDGE_SMOOTHING = 0;\nexport const MAX_BRUSH_EDGE_SMOOTHING = 4;\nexport const MIN_BRUSH_RASTER_STEP = 0.05;\nexport const BRUSH_RASTER_DIAMETER_SAMPLES = 256;\nexport const BRUSH_SCREEN_STEP = 1.5;\n","import { closeRoiRing, normalizeRoiGeometry, polygonSignedArea, toRoiGeometry } from \"../wsi/roi-geometry\";\nimport { clamp } from \"../wsi/utils\";\nimport type { DrawCoordinate, DrawOverlayCoordinates, DrawRegionCoordinates, NormalizedDrawRegionPolygon, RegionStrokeStyle } from \"./draw-layer-types\";\nimport { CIRCLE_SIDES, DEFAULT_REGION_STROKE_STYLE, type DrawBounds, EMPTY_DASH } from \"./draw-layer-types\";\n\nexport { clamp };\n\nexport function clampWorld(coord: DrawCoordinate, imageWidth: number, imageHeight: number): DrawCoordinate {\n return [clamp(coord[0], 0, imageWidth), clamp(coord[1], 0, imageHeight)];\n}\n\nexport function toDrawCoordinate(value: unknown): DrawCoordinate | null {\n if (!Array.isArray(value) || value.length < 2) return null;\n const x = Number(value[0]);\n const y = Number(value[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n}\n\nexport const toCoord = toDrawCoordinate;\n\nexport function closeRing(coords: DrawCoordinate[]): DrawCoordinate[] {\n return closeRoiRing(coords) as DrawCoordinate[];\n}\n\nexport function polygonArea(coords: DrawCoordinate[]): number {\n return Math.abs(polygonSignedArea(closeRing(coords)));\n}\n\nexport function computeBounds(coords: DrawCoordinate[]): DrawBounds {\n if (!Array.isArray(coords) || coords.length === 0) return [0, 0, 0, 0];\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const [x, y] of coords) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n\n return [minX, minY, maxX, maxY];\n}\n\nexport function tracePath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], close = false): void {\n if (points.length === 0) return;\n\n ctx.moveTo(points[0][0], points[0][1]);\n for (let i = 1; i < points.length; i += 1) {\n ctx.lineTo(points[i][0], points[i][1]);\n }\n\n if (close) {\n ctx.closePath();\n }\n}\n\nexport function drawPath(ctx: CanvasRenderingContext2D, points: DrawCoordinate[], strokeStyle: RegionStrokeStyle, close = false, fill = false, fillColor = \"rgba(255, 77, 79, 0.16)\"): void {\n if (points.length === 0) return;\n\n ctx.beginPath();\n tracePath(ctx, points, close);\n if (fill && close) {\n ctx.fillStyle = fillColor;\n ctx.fill();\n }\n\n ctx.strokeStyle = strokeStyle.color;\n ctx.lineWidth = strokeStyle.width;\n ctx.lineJoin = strokeStyle.lineJoin;\n ctx.lineCap = strokeStyle.lineCap;\n ctx.shadowColor = strokeStyle.shadowColor;\n ctx.shadowBlur = strokeStyle.shadowBlur;\n ctx.shadowOffsetX = strokeStyle.shadowOffsetX;\n ctx.shadowOffsetY = strokeStyle.shadowOffsetY;\n ctx.setLineDash(strokeStyle.lineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.shadowColor = \"rgba(0, 0, 0, 0)\";\n ctx.shadowBlur = 0;\n ctx.shadowOffsetX = 0;\n ctx.shadowOffsetY = 0;\n}\n\nexport function resolveStrokeStyle(style: Partial<RegionStrokeStyle> | undefined): RegionStrokeStyle {\n const dash = Array.isArray(style?.lineDash) ? style.lineDash.filter(value => Number.isFinite(value) && value >= 0) : EMPTY_DASH;\n const width = typeof style?.width === \"number\" && Number.isFinite(style.width) ? Math.max(0, style.width) : DEFAULT_REGION_STROKE_STYLE.width;\n const shadowBlur = typeof style?.shadowBlur === \"number\" && Number.isFinite(style.shadowBlur) ? Math.max(0, style.shadowBlur) : DEFAULT_REGION_STROKE_STYLE.shadowBlur;\n const shadowOffsetX = typeof style?.shadowOffsetX === \"number\" && Number.isFinite(style.shadowOffsetX) ? style.shadowOffsetX : DEFAULT_REGION_STROKE_STYLE.shadowOffsetX;\n const shadowOffsetY = typeof style?.shadowOffsetY === \"number\" && Number.isFinite(style.shadowOffsetY) ? style.shadowOffsetY : DEFAULT_REGION_STROKE_STYLE.shadowOffsetY;\n return {\n color: style?.color || DEFAULT_REGION_STROKE_STYLE.color,\n width,\n lineDash: dash.length ? dash : EMPTY_DASH,\n lineJoin: style?.lineJoin || DEFAULT_REGION_STROKE_STYLE.lineJoin,\n lineCap: style?.lineCap || DEFAULT_REGION_STROKE_STYLE.lineCap,\n shadowColor: style?.shadowColor || DEFAULT_REGION_STROKE_STYLE.shadowColor,\n shadowBlur,\n shadowOffsetX,\n shadowOffsetY,\n };\n}\n\nexport function mergeStrokeStyle(base: RegionStrokeStyle, override: Partial<RegionStrokeStyle> | undefined): RegionStrokeStyle {\n if (!override) return base;\n return resolveStrokeStyle({\n color: override.color ?? base.color,\n width: override.width ?? base.width,\n lineDash: override.lineDash ?? base.lineDash,\n lineJoin: override.lineJoin ?? base.lineJoin,\n lineCap: override.lineCap ?? base.lineCap,\n shadowColor: override.shadowColor ?? base.shadowColor,\n shadowBlur: override.shadowBlur ?? base.shadowBlur,\n shadowOffsetX: override.shadowOffsetX ?? base.shadowOffsetX,\n shadowOffsetY: override.shadowOffsetY ?? base.shadowOffsetY,\n });\n}\n\nexport function isSameRegionId(a: string | number | null | undefined, b: string | number | null | undefined): boolean {\n if (a === null || a === undefined || b === null || b === undefined) {\n return false;\n }\n return String(a) === String(b);\n}\n\nexport function isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nexport function isCoordinatePair(value: unknown): value is [number, number] {\n return Array.isArray(value) && value.length >= 2 && isFiniteNumber(value[0]) && isFiniteNumber(value[1]);\n}\n\nexport function isCoordinateRing(value: unknown): value is DrawCoordinate[] {\n return Array.isArray(value) && value.length >= 2 && value.every(point => isCoordinatePair(point));\n}\n\nfunction collectOverlayRings(value: unknown, out: DrawCoordinate[][]): void {\n if (!Array.isArray(value) || value.length === 0) return;\n if (isCoordinateRing(value)) {\n out.push(value.map(([x, y]) => [x, y] as DrawCoordinate));\n return;\n }\n for (const item of value) {\n collectOverlayRings(item, out);\n }\n}\n\nexport function normalizeOverlayRings(coordinates: DrawOverlayCoordinates, close: boolean): DrawCoordinate[][] {\n const sourceRings: DrawCoordinate[][] = [];\n collectOverlayRings(coordinates, sourceRings);\n const out: DrawCoordinate[][] = [];\n for (const ring of sourceRings) {\n if (ring.length < 2) continue;\n const normalized = close ? closeRing(ring) : ring;\n if (normalized.length >= (close ? 4 : 2)) {\n out.push(normalized);\n }\n }\n return out;\n}\n\nexport function clampPositiveOrFallback(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n return fallback;\n }\n return value;\n}\n\nexport function clampUnitOpacity(value: number | undefined, fallback: number): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n return clamp(value, 0, 1);\n}\n\nexport function drawRoundedRect(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number, radius: number): void {\n const r = Math.max(0, Math.min(radius, width * 0.5, height * 0.5));\n ctx.beginPath();\n ctx.moveTo(x + r, y);\n ctx.lineTo(x + width - r, y);\n ctx.quadraticCurveTo(x + width, y, x + width, y + r);\n ctx.lineTo(x + width, y + height - r);\n ctx.quadraticCurveTo(x + width, y + height, x + width - r, y + height);\n ctx.lineTo(x + r, y + height);\n ctx.quadraticCurveTo(x, y + height, x, y + height - r);\n ctx.lineTo(x, y + r);\n ctx.quadraticCurveTo(x, y, x + r, y);\n ctx.closePath();\n}\n\nexport function isNestedRingCoordinates(coordinates: DrawOverlayCoordinates): boolean {\n const first = coordinates[0];\n return Array.isArray(first) && Array.isArray(first[0]);\n}\n\nexport function createRectangle(\n start: DrawCoordinate | null,\n end: DrawCoordinate | null,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n }\n): DrawCoordinate[] {\n if (!start || !end) return [];\n\n if (projection) {\n const startScreen = projection.worldToScreen(start[0], start[1]);\n const endScreen = projection.worldToScreen(end[0], end[1]);\n\n if (startScreen && endScreen) {\n const screenCorners: DrawCoordinate[] = [\n [startScreen[0], startScreen[1]],\n [endScreen[0], startScreen[1]],\n [endScreen[0], endScreen[1]],\n [startScreen[0], endScreen[1]],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) return createRectangle(start, end);\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\n\n return closeRing([\n [start[0], start[1]],\n [end[0], start[1]],\n [end[0], end[1]],\n [start[0], end[1]],\n ]);\n}\n\nexport function createCircle(start: DrawCoordinate | null, end: DrawCoordinate | null, sides = CIRCLE_SIDES): DrawCoordinate[] {\n if (!start || !end) return [];\n\n const centerX = (start[0] + end[0]) * 0.5;\n const centerY = (start[1] + end[1]) * 0.5;\n const radius = Math.hypot(end[0] - start[0], end[1] - start[1]) * 0.5;\n if (radius < 1) return [];\n\n const coords: DrawCoordinate[] = [];\n for (let i = 0; i <= sides; i += 1) {\n const t = (i / sides) * Math.PI * 2;\n coords.push([centerX + Math.cos(t) * radius, centerY + Math.sin(t) * radius]);\n }\n\n return closeRing(coords);\n}\n\nexport function normalizeDrawRegionPolygons(coordinates: DrawRegionCoordinates): NormalizedDrawRegionPolygon[] {\n const multipolygon = normalizeRoiGeometry(toRoiGeometry(coordinates));\n if (multipolygon.length === 0) return [];\n\n const out: NormalizedDrawRegionPolygon[] = [];\n for (const polygon of multipolygon) {\n const outer = polygon[0];\n if (!outer || outer.length < 4) continue;\n const normalizedOuter = outer.map(([x, y]) => [x, y] as DrawCoordinate);\n const holes: DrawCoordinate[][] = [];\n for (let i = 1; i < polygon.length; i += 1) {\n const hole = polygon[i];\n if (!hole || hole.length < 4) continue;\n holes.push(hole.map(([x, y]) => [x, y] as DrawCoordinate));\n }\n out.push({\n outer: normalizedOuter,\n holes,\n });\n }\n return out;\n}\n","import type { BrushOptions, DrawCoordinate, DrawProjector, DrawSession, ResolvedBrushOptions } from \"./draw-layer-types\";\nimport {\n DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR,\n DEFAULT_BRUSH_CURSOR_COLOR,\n DEFAULT_BRUSH_CURSOR_DASH,\n DEFAULT_BRUSH_CURSOR_LINE_WIDTH,\n DEFAULT_BRUSH_EDGE_DETAIL,\n DEFAULT_BRUSH_EDGE_SMOOTHING,\n DEFAULT_BRUSH_FILL_COLOR,\n DEFAULT_BRUSH_FILL_OPACITY,\n DEFAULT_BRUSH_RADIUS,\n EMPTY_DASH,\n MAX_BRUSH_EDGE_DETAIL,\n MAX_BRUSH_EDGE_SMOOTHING,\n MIN_BRUSH_EDGE_DETAIL,\n MIN_BRUSH_EDGE_SMOOTHING,\n} from \"./draw-layer-types\";\nimport { clamp, clampPositiveOrFallback, clampUnitOpacity, toCoord } from \"./draw-layer-utils\";\n\nexport type { BrushOptions, ResolvedBrushOptions };\n\nexport function sanitizeBrushLineDash(value: number[] | undefined): number[] {\n if (!Array.isArray(value)) return DEFAULT_BRUSH_CURSOR_DASH;\n const out = value.filter(item => Number.isFinite(item) && item >= 0);\n return out.length > 0 ? out : DEFAULT_BRUSH_CURSOR_DASH;\n}\n\nexport function resolveBrushEdgeDetail(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_DETAIL;\n return clamp(value, MIN_BRUSH_EDGE_DETAIL, MAX_BRUSH_EDGE_DETAIL);\n}\n\nexport function resolveBrushEdgeSmoothing(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return DEFAULT_BRUSH_EDGE_SMOOTHING;\n return Math.round(clamp(value, MIN_BRUSH_EDGE_SMOOTHING, MAX_BRUSH_EDGE_SMOOTHING));\n}\n\nexport function resolveBrushOptions(options: BrushOptions | undefined): ResolvedBrushOptions {\n const radius = clampPositiveOrFallback(options?.radius, DEFAULT_BRUSH_RADIUS);\n const cursorLineWidth = clampPositiveOrFallback(options?.cursorLineWidth, DEFAULT_BRUSH_CURSOR_LINE_WIDTH);\n const edgeDetail = resolveBrushEdgeDetail(options?.edgeDetail);\n const edgeSmoothing = resolveBrushEdgeSmoothing(options?.edgeSmoothing);\n return {\n radius,\n edgeDetail,\n edgeSmoothing,\n clickSelectRoi: options?.clickSelectRoi === true,\n fillColor: options?.fillColor || DEFAULT_BRUSH_FILL_COLOR,\n fillOpacity: clampUnitOpacity(options?.fillOpacity, DEFAULT_BRUSH_FILL_OPACITY),\n cursorColor: options?.cursorColor || DEFAULT_BRUSH_CURSOR_COLOR,\n cursorActiveColor: options?.cursorActiveColor || DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR,\n cursorLineWidth,\n cursorLineDash: sanitizeBrushLineDash(options?.cursorLineDash),\n };\n}\n\nexport function drawBrushStrokePreview(ctx: CanvasRenderingContext2D, session: DrawSession, resolvedBrushOptions: ResolvedBrushOptions): void {\n if (!session.isDrawing || session.screenPoints.length === 0) return;\n const screenPoints = session.screenPoints;\n if (screenPoints.length === 0) return;\n const radiusPx = resolvedBrushOptions.radius;\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.globalAlpha = resolvedBrushOptions.fillOpacity;\n ctx.fillStyle = resolvedBrushOptions.fillColor;\n ctx.strokeStyle = resolvedBrushOptions.fillColor;\n ctx.lineCap = \"round\";\n ctx.lineJoin = \"round\";\n ctx.lineWidth = radiusPx * 2;\n if (screenPoints.length === 1) {\n ctx.beginPath();\n ctx.arc(screenPoints[0][0], screenPoints[0][1], radiusPx, 0, Math.PI * 2);\n ctx.fill();\n } else {\n ctx.beginPath();\n ctx.moveTo(screenPoints[0][0], screenPoints[0][1]);\n for (let i = 1; i < screenPoints.length; i += 1) {\n ctx.lineTo(screenPoints[i][0], screenPoints[i][1]);\n }\n ctx.stroke();\n }\n ctx.restore();\n}\n\nexport function drawBrushCursor(ctx: CanvasRenderingContext2D, session: DrawSession, projector: DrawProjector | null, resolvedBrushOptions: ResolvedBrushOptions): void {\n const cursor = session.cursor;\n if (!cursor) return;\n const screen = session.cursorScreen ?? toCoord(projector?.worldToScreen(cursor[0], cursor[1]) ?? []);\n if (!screen) return;\n const radiusPx = resolvedBrushOptions.radius;\n if (!Number.isFinite(radiusPx) || radiusPx <= 0) return;\n\n ctx.save();\n ctx.beginPath();\n ctx.arc(screen[0], screen[1], radiusPx, 0, Math.PI * 2);\n ctx.strokeStyle = session.isDrawing ? resolvedBrushOptions.cursorActiveColor : resolvedBrushOptions.cursorColor;\n ctx.lineWidth = resolvedBrushOptions.cursorLineWidth;\n ctx.setLineDash(resolvedBrushOptions.cursorLineDash);\n ctx.stroke();\n ctx.setLineDash(EMPTY_DASH);\n ctx.restore();\n}\n","import type { DrawAreaTooltipOptions, DrawAreaTooltipStyle, DrawCoordinate, RegionLabelAnchorMode, RegionLabelStyle, ResolvedDrawAreaTooltipOptions } from \"./draw-layer-types\";\nimport {\n DEFAULT_DRAW_AREA_TOOLTIP_OFFSET,\n DEFAULT_DRAW_AREA_TOOLTIP_STYLE,\n DEFAULT_REGION_LABEL_STYLE,\n REGION_LABEL_AUTO_LIFT_MAX_EPSILON,\n REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX,\n} from \"./draw-layer-types\";\nimport { clamp, drawRoundedRect } from \"./draw-layer-utils\";\n\nconst LABEL_MEASURE_FALLBACK_EM = 0.58;\nconst LABEL_MEASURE_CACHE_LIMIT = 4096;\nconst TOP_ANCHOR_Y_TOLERANCE = 0.5;\n\nlet sharedLabelMeasureContext: CanvasRenderingContext2D | null = null;\nconst labelTextWidthCache = new Map<string, number>();\n\nfunction getLabelMeasureContext(): CanvasRenderingContext2D | null {\n if (sharedLabelMeasureContext) return sharedLabelMeasureContext;\n if (typeof document === \"undefined\") return null;\n const canvas = document.createElement(\"canvas\");\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return null;\n sharedLabelMeasureContext = ctx;\n return sharedLabelMeasureContext;\n}\n\nexport function measureLabelTextWidth(label: string, labelStyle: { fontFamily: string; fontSize: number; fontWeight: string | number }): number {\n const key = `${labelStyle.fontWeight}|${labelStyle.fontSize}|${labelStyle.fontFamily}|${label}`;\n const cached = labelTextWidthCache.get(key);\n if (cached !== undefined) return cached;\n\n const fallback = label.length * labelStyle.fontSize * LABEL_MEASURE_FALLBACK_EM;\n const ctx = getLabelMeasureContext();\n let width = fallback;\n if (ctx) {\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n const measured = ctx.measureText(label).width;\n if (Number.isFinite(measured) && measured >= 0) {\n width = measured;\n }\n }\n\n if (labelTextWidthCache.size > LABEL_MEASURE_CACHE_LIMIT) {\n labelTextWidthCache.clear();\n }\n labelTextWidthCache.set(key, width);\n return width;\n}\n\nexport function getTopAnchor(coords: DrawCoordinate[], anchorMode: RegionLabelAnchorMode = \"top-center\"): DrawCoordinate | null {\n if (!coords.length) return null;\n\n let minY = Infinity;\n for (const point of coords) {\n if (point[1] < minY) minY = point[1];\n }\n if (!Number.isFinite(minY)) return null;\n\n let minX = Infinity;\n let maxX = -Infinity;\n for (const point of coords) {\n if (Math.abs(point[1] - minY) > TOP_ANCHOR_Y_TOLERANCE) continue;\n if (point[0] < minX) minX = point[0];\n if (point[0] > maxX) maxX = point[0];\n }\n\n if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n if (anchorMode === \"top-center\") {\n return [(minX + maxX) * 0.5, minY];\n }\n return [minX, minY];\n}\n\nexport function getTopAnchorFromPolygons<T extends { outer: DrawCoordinate[] }>(polygons: T[], anchorMode: RegionLabelAnchorMode = \"top-center\"): DrawCoordinate | null {\n let best: DrawCoordinate | null = null;\n for (const polygon of polygons) {\n const anchor = getTopAnchor(polygon.outer, anchorMode);\n if (!anchor) continue;\n if (!best || anchor[1] < best[1] || (anchor[1] === best[1] && anchor[0] < best[0])) {\n best = anchor;\n }\n }\n return best;\n}\n\nexport function resolveRegionLabelStyle(style: Partial<RegionLabelStyle> | undefined): RegionLabelStyle {\n const px = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_REGION_LABEL_STYLE.paddingX;\n const py = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_REGION_LABEL_STYLE.paddingY;\n const fs = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_REGION_LABEL_STYLE.fontSize;\n const bw = typeof style?.borderWidth === \"number\" && Number.isFinite(style.borderWidth) ? Math.max(0, style.borderWidth) : DEFAULT_REGION_LABEL_STYLE.borderWidth;\n const oy = typeof style?.offsetY === \"number\" && Number.isFinite(style.offsetY) ? style.offsetY : DEFAULT_REGION_LABEL_STYLE.offsetY;\n const br = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_REGION_LABEL_STYLE.borderRadius;\n return {\n fontFamily: style?.fontFamily || DEFAULT_REGION_LABEL_STYLE.fontFamily,\n fontSize: fs,\n fontWeight: style?.fontWeight || DEFAULT_REGION_LABEL_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_REGION_LABEL_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_REGION_LABEL_STYLE.backgroundColor,\n borderColor: style?.borderColor || DEFAULT_REGION_LABEL_STYLE.borderColor,\n borderWidth: bw,\n paddingX: px,\n paddingY: py,\n offsetY: oy,\n borderRadius: br,\n };\n}\n\nexport function mergeRegionLabelStyle(base: RegionLabelStyle, override: Partial<RegionLabelStyle> | null | undefined): RegionLabelStyle {\n if (!override) return base;\n return resolveRegionLabelStyle({\n fontFamily: override.fontFamily ?? base.fontFamily,\n fontSize: override.fontSize ?? base.fontSize,\n fontWeight: override.fontWeight ?? base.fontWeight,\n textColor: override.textColor ?? base.textColor,\n backgroundColor: override.backgroundColor ?? base.backgroundColor,\n borderColor: override.borderColor ?? base.borderColor,\n borderWidth: override.borderWidth ?? base.borderWidth,\n paddingX: override.paddingX ?? base.paddingX,\n paddingY: override.paddingY ?? base.paddingY,\n offsetY: override.offsetY ?? base.offsetY,\n borderRadius: override.borderRadius ?? base.borderRadius,\n });\n}\n\nexport function resolveRegionLabelAutoLiftOffsetPx(enabled: boolean | undefined, zoom: number, zoomRange: { minZoom: number; maxZoom: number } | null | undefined): number {\n if (!enabled) return 0;\n if (!zoomRange) return 0;\n\n const minZoom = Number(zoomRange.minZoom);\n const maxZoom = Number(zoomRange.maxZoom);\n if (!Number.isFinite(minZoom) || !Number.isFinite(maxZoom)) return 0;\n\n if (maxZoom - minZoom <= REGION_LABEL_AUTO_LIFT_MAX_EPSILON) return 0;\n if (!Number.isFinite(zoom)) return 0;\n return zoom >= maxZoom - REGION_LABEL_AUTO_LIFT_MAX_EPSILON ? REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX : 0;\n}\n\nfunction resolveDrawAreaTooltipStyle(style: Partial<DrawAreaTooltipStyle> | undefined): DrawAreaTooltipStyle {\n const fontSize = typeof style?.fontSize === \"number\" && Number.isFinite(style.fontSize) ? Math.max(8, style.fontSize) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontSize;\n const borderRadius = typeof style?.borderRadius === \"number\" && Number.isFinite(style.borderRadius) ? Math.max(0, style.borderRadius) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.borderRadius;\n const paddingX = typeof style?.paddingX === \"number\" && Number.isFinite(style.paddingX) ? Math.max(0, style.paddingX) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingX;\n const paddingY = typeof style?.paddingY === \"number\" && Number.isFinite(style.paddingY) ? Math.max(0, style.paddingY) : DEFAULT_DRAW_AREA_TOOLTIP_STYLE.paddingY;\n return {\n fontFamily: style?.fontFamily || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontFamily,\n fontSize,\n fontWeight: style?.fontWeight || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.fontWeight,\n textColor: style?.textColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.textColor,\n backgroundColor: style?.backgroundColor || DEFAULT_DRAW_AREA_TOOLTIP_STYLE.backgroundColor,\n borderRadius,\n paddingX,\n paddingY,\n };\n}\n\nfunction resolveTooltipCursorOffset(value: DrawAreaTooltipOptions[\"cursorOffset\"]): { x: number; y: number } {\n const x = typeof value?.x === \"number\" && Number.isFinite(value.x) ? value.x : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.x;\n const y = typeof value?.y === \"number\" && Number.isFinite(value.y) ? value.y : DEFAULT_DRAW_AREA_TOOLTIP_OFFSET.y;\n return { x, y };\n}\n\nexport function defaultDrawAreaTooltipFormatter(areaMm2: number): string {\n if (!Number.isFinite(areaMm2)) return \"0.000 mm²\";\n return `${Math.max(0, areaMm2).toFixed(3)} mm²`;\n}\n\nexport function resolveDrawAreaTooltipOptions(options: DrawAreaTooltipOptions | undefined): ResolvedDrawAreaTooltipOptions {\n const format = typeof options?.format === \"function\" ? options.format : defaultDrawAreaTooltipFormatter;\n const cursorOffset = resolveTooltipCursorOffset(options?.cursorOffset);\n return {\n enabled: options?.enabled === true,\n format,\n style: resolveDrawAreaTooltipStyle(options?.style),\n cursorOffsetX: cursorOffset.x,\n cursorOffsetY: cursorOffset.y,\n };\n}\n\nexport function drawRegionLabel(\n ctx: CanvasRenderingContext2D,\n text: string,\n anchor: DrawCoordinate,\n canvasWidth: number,\n canvasHeight: number,\n labelStyle: RegionLabelStyle,\n clampToViewport = true\n): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${labelStyle.fontWeight} ${labelStyle.fontSize}px ${labelStyle.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = measureLabelTextWidth(label, labelStyle);\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const rawX = anchor[0];\n const rawY = anchor[1] - labelStyle.offsetY;\n const x = clampToViewport ? clamp(rawX, boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1) : rawX;\n const y = clampToViewport ? clamp(rawY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1) : rawY;\n const left = x - boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n\n ctx.fillStyle = labelStyle.backgroundColor;\n ctx.strokeStyle = labelStyle.borderColor;\n ctx.lineWidth = labelStyle.borderWidth;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, labelStyle.borderRadius);\n ctx.fill();\n if (labelStyle.borderWidth > 0) {\n ctx.stroke();\n }\n\n ctx.fillStyle = labelStyle.textColor;\n ctx.fillText(label, x, y + 0.5);\n ctx.restore();\n}\n\nexport function drawAreaTooltipBox(\n ctx: CanvasRenderingContext2D,\n text: string,\n cursorScreen: DrawCoordinate,\n canvasWidth: number,\n canvasHeight: number,\n style: DrawAreaTooltipStyle,\n offsetX: number,\n offsetY: number\n): void {\n const label = text.trim();\n if (!label) return;\n\n ctx.save();\n ctx.font = `${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`;\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n\n const textWidth = measureLabelTextWidth(label, style);\n const boxWidth = textWidth + style.paddingX * 2;\n const boxHeight = style.fontSize + style.paddingY * 2;\n\n const x = clamp(cursorScreen[0] + offsetX, boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1);\n const y = clamp(cursorScreen[1] + offsetY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1);\n const left = x - boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n\n ctx.fillStyle = style.backgroundColor;\n drawRoundedRect(ctx, left, top, boxWidth, boxHeight, style.borderRadius);\n ctx.fill();\n\n ctx.fillStyle = style.textColor;\n ctx.fillText(label, x, y + 0.5);\n ctx.restore();\n}\n","import type { DrawCoordinate, DrawOverlayShape, RegionStrokeStyle } from \"./draw-layer-types\";\nimport { drawPath, isNestedRingCoordinates, mergeStrokeStyle, normalizeOverlayRings, tracePath } from \"./draw-layer-utils\";\n\nexport function drawInvertedFillMask(ctx: CanvasRenderingContext2D, outerRing: DrawCoordinate[], holeRings: DrawCoordinate[][], fillColor: string): void {\n if (outerRing.length < 4 || holeRings.length === 0) return;\n ctx.save();\n ctx.beginPath();\n tracePath(ctx, outerRing, true);\n for (const ring of holeRings) {\n if (ring.length < 4) continue;\n tracePath(ctx, ring, true);\n }\n ctx.fillStyle = fillColor;\n ctx.fill(\"evenodd\");\n ctx.restore();\n}\n\nexport interface DrawOverlayShapesParams {\n ctx: CanvasRenderingContext2D;\n overlayShapes: DrawOverlayShape[];\n imageOuterRing: DrawCoordinate[];\n worldToScreenPoints: (points: DrawCoordinate[]) => DrawCoordinate[];\n baseStrokeStyle: RegionStrokeStyle;\n onInvertedFillDebug?: (info: { id: string | number; outerRingPoints: number; sourceRingCount: number; holeRingCount: number; fillColor: string }) => void;\n}\n\nexport function drawOverlayShapes(params: DrawOverlayShapesParams): void {\n const { ctx, overlayShapes, imageOuterRing, worldToScreenPoints, baseStrokeStyle, onInvertedFillDebug } = params;\n\n const debugOverlay = Boolean((globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__);\n\n for (let i = 0; i < overlayShapes.length; i += 1) {\n const shape = overlayShapes[i];\n if (!shape?.coordinates?.length || shape.visible === false) continue;\n\n const closed = shape.closed ?? isNestedRingCoordinates(shape.coordinates);\n const renderRings = normalizeOverlayRings(shape.coordinates, closed);\n\n if (shape.invertedFill?.fillColor) {\n const holeRings: DrawCoordinate[][] = [];\n const closedRings = normalizeOverlayRings(shape.coordinates, true);\n for (const ring of closedRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length >= 4) {\n holeRings.push(screen);\n }\n }\n if (debugOverlay && onInvertedFillDebug) {\n onInvertedFillDebug({\n id: shape.id ?? i,\n outerRingPoints: imageOuterRing.length,\n sourceRingCount: closedRings.length,\n holeRingCount: holeRings.length,\n fillColor: shape.invertedFill.fillColor,\n });\n }\n drawInvertedFillMask(ctx, imageOuterRing, holeRings, shape.invertedFill.fillColor);\n }\n\n if (renderRings.length === 0) continue;\n const strokeStyle = mergeStrokeStyle(baseStrokeStyle, shape.stroke ?? shape.strokeStyle);\n for (const ring of renderRings) {\n const screen = worldToScreenPoints(ring);\n if (screen.length < 2) continue;\n drawPath(ctx, screen, strokeStyle, closed, shape.fill ?? false);\n }\n }\n}\n","import type { DrawCoordinate, DrawTool, StampDrawTool, StampOptions } from \"./draw-layer-types\";\nimport { CIRCLE_SIDES, DEFAULT_STAMP_CIRCLE_AREA_MM2, DEFAULT_STAMP_RECTANGLE_AREA_MM2, DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE, LEGACY_HPF_CIRCLE_AREA_MM2 } from \"./draw-layer-types\";\nimport { clampPositiveOrFallback, clampWorld, closeRing } from \"./draw-layer-utils\";\n\nexport type { StampDrawTool, StampOptions };\n\nexport function isStampTool(tool: DrawTool): tool is StampDrawTool {\n return (\n tool === \"stamp-rectangle\" || tool === \"stamp-circle\" || tool === \"stamp-rectangle-4096px\" || tool === \"stamp-rectangle-2mm2\" || tool === \"stamp-circle-2mm2\" || tool === \"stamp-circle-hpf-0.2mm2\"\n );\n}\n\nexport function resolveStampOptions(options: StampOptions | undefined): Required<StampOptions> {\n return {\n rectangleAreaMm2: clampPositiveOrFallback(options?.rectangleAreaMm2, DEFAULT_STAMP_RECTANGLE_AREA_MM2),\n circleAreaMm2: clampPositiveOrFallback(options?.circleAreaMm2, DEFAULT_STAMP_CIRCLE_AREA_MM2),\n rectanglePixelSize: clampPositiveOrFallback(options?.rectanglePixelSize, DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE),\n };\n}\n\nconst MICRONS_PER_MM = 1000;\n\nexport function mm2ToUm2(areaMm2: number): number {\n return areaMm2 * MICRONS_PER_MM * MICRONS_PER_MM;\n}\n\nexport function createSquareFromCenter(\n center: DrawCoordinate | null,\n halfLength: number,\n projection?: {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n }\n): DrawCoordinate[] {\n if (!center || !Number.isFinite(halfLength) || halfLength <= 0) return [];\n\n if (projection) {\n const screenCenter = projection.worldToScreen(center[0], center[1]);\n const screenEdge = projection.worldToScreen(center[0] + halfLength, center[1]);\n if (screenCenter && screenEdge) {\n const screenHL = Math.hypot(screenEdge[0] - screenCenter[0], screenEdge[1] - screenCenter[1]);\n const screenCorners: DrawCoordinate[] = [\n [screenCenter[0] - screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] - screenHL],\n [screenCenter[0] + screenHL, screenCenter[1] + screenHL],\n [screenCenter[0] - screenHL, screenCenter[1] + screenHL],\n ];\n const worldCorners: DrawCoordinate[] = [];\n for (const corner of screenCorners) {\n const world = projection.screenToWorld(corner);\n if (!world) throw new Error(\"Failed to create rectangle\");\n worldCorners.push(world);\n }\n return closeRing(worldCorners);\n }\n }\n\n return closeRing([\n [center[0] - halfLength, center[1] - halfLength],\n [center[0] + halfLength, center[1] - halfLength],\n [center[0] + halfLength, center[1] + halfLength],\n [center[0] - halfLength, center[1] + halfLength],\n ]);\n}\n\nexport function createCircleFromCenter(center: DrawCoordinate | null, radius: number, sides = CIRCLE_SIDES): DrawCoordinate[] {\n if (!center || !Number.isFinite(radius) || radius <= 0) return [];\n\n const coords: DrawCoordinate[] = [];\n for (let i = 0; i <= sides; i += 1) {\n const t = (i / sides) * Math.PI * 2;\n coords.push([center[0] + Math.cos(t) * radius, center[1] + Math.sin(t) * radius]);\n }\n\n return closeRing(coords);\n}\n\nexport interface BuildStampCoordsParams {\n stampTool: StampDrawTool;\n center: DrawCoordinate | null;\n resolvedStampOptions: Required<StampOptions>;\n imageWidth: number;\n imageHeight: number;\n micronsToWorldPixels: (lengthUm: number) => number;\n getRectangleProjection: () =>\n | {\n worldToScreen: (x: number, y: number) => DrawCoordinate | null;\n screenToWorld: (screen: DrawCoordinate) => DrawCoordinate | null;\n }\n | undefined;\n}\n\nexport function buildStampCoords(params: BuildStampCoordsParams): DrawCoordinate[] {\n const { stampTool, center, resolvedStampOptions, imageWidth, imageHeight, micronsToWorldPixels, getRectangleProjection } = params;\n\n if (!center) return [];\n\n if (stampTool === \"stamp-rectangle-4096px\") {\n const halfLength = resolvedStampOptions.rectanglePixelSize * 0.5;\n return createSquareFromCenter(center, halfLength, getRectangleProjection()).map(point => clampWorld(point, imageWidth, imageHeight));\n }\n\n let areaMm2 = 0;\n if (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n areaMm2 = stampTool === \"stamp-rectangle-2mm2\" ? DEFAULT_STAMP_RECTANGLE_AREA_MM2 : resolvedStampOptions.rectangleAreaMm2;\n } else if (stampTool === \"stamp-circle\" || stampTool === \"stamp-circle-2mm2\" || stampTool === \"stamp-circle-hpf-0.2mm2\") {\n areaMm2 = stampTool === \"stamp-circle-hpf-0.2mm2\" ? LEGACY_HPF_CIRCLE_AREA_MM2 : stampTool === \"stamp-circle-2mm2\" ? DEFAULT_STAMP_CIRCLE_AREA_MM2 : resolvedStampOptions.circleAreaMm2;\n }\n if (!Number.isFinite(areaMm2) || areaMm2 <= 0) return [];\n\n const areaUm2 = mm2ToUm2(areaMm2);\n let coords: DrawCoordinate[] = [];\n if (stampTool === \"stamp-rectangle\" || stampTool === \"stamp-rectangle-2mm2\") {\n const halfLength = micronsToWorldPixels(Math.sqrt(areaUm2) * 0.5);\n coords = createSquareFromCenter(center, halfLength, getRectangleProjection());\n } else if (stampTool === \"stamp-circle\" || stampTool === \"stamp-circle-2mm2\" || stampTool === \"stamp-circle-hpf-0.2mm2\") {\n const radius = micronsToWorldPixels(Math.sqrt(areaUm2 / Math.PI));\n coords = createCircleFromCenter(center, radius);\n }\n\n if (!coords.length) return [];\n return coords.map(point => clampWorld(point, imageWidth, imageHeight));\n}\n","import { type CSSProperties, type PointerEvent as ReactPointerEvent, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { buildBrushStrokePolygon } from \"../wsi/brush-stroke\";\nimport { calcScaleResolution } from \"../wsi/utils\";\nimport { drawBrushCursor, drawBrushStrokePreview, resolveBrushOptions } from \"./draw-layer-brush\";\nimport {\n drawAreaTooltipBox,\n drawRegionLabel,\n getTopAnchorFromPolygons,\n mergeRegionLabelStyle,\n resolveDrawAreaTooltipOptions,\n resolveRegionLabelAutoLiftOffsetPx,\n resolveRegionLabelStyle,\n} from \"./draw-layer-label\";\nimport { drawOverlayShapes } from \"./draw-layer-overlay\";\nimport { buildStampCoords, isStampTool, resolveStampOptions } from \"./draw-layer-stamp\";\nimport {\n BRUSH_RASTER_DIAMETER_SAMPLES,\n BRUSH_SCREEN_STEP,\n DEFAULT_DRAW_PREVIEW_FILL,\n DEFAULT_PATCH_STROKE_STYLE,\n type DrawLayerProps,\n type DrawRegion,\n type DrawSession,\n type DrawTool,\n EMPTY_DASH,\n EMPTY_REGIONS,\n FREEHAND_MIN_POINTS,\n FREEHAND_SCREEN_STEP,\n MICRONS_PER_MM,\n MIN_AREA_PX,\n MIN_BRUSH_RASTER_STEP,\n type PreparedRenderedRegion,\n REGION_INTERACTION_SHADOW_COLOR,\n REGION_INTERACTION_SHADOW_WIDTH,\n type StampDrawTool,\n WHEEL_ZOOM_IN_FACTOR,\n WHEEL_ZOOM_OUT_FACTOR,\n} from \"./draw-layer-types\";\nimport {\n clamp,\n clampWorld,\n closeRing,\n computeBounds,\n createCircle,\n createRectangle,\n drawPath,\n isSameRegionId,\n mergeStrokeStyle,\n normalizeDrawRegionPolygons,\n polygonArea,\n resolveStrokeStyle,\n toCoord,\n} from \"./draw-layer-utils\";\n\nexport { mergeRegionLabelStyle, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer-label\";\nexport type {\n BrushOptions,\n DrawAreaTooltipOptions,\n DrawAreaTooltipStyle,\n DrawBounds,\n DrawCoordinate,\n DrawIntent,\n DrawOverlayCoordinates,\n DrawOverlayInvertedFillStyle,\n DrawOverlayShape,\n DrawProjector,\n DrawRegion,\n DrawRegionCoordinates,\n DrawResult,\n DrawTool,\n PatchDrawResult,\n RegionLabelStyle,\n RegionLabelAnchorMode,\n RegionLabelStyleContext,\n RegionLabelStyleResolver,\n RegionStrokeStyle,\n RegionStrokeStyleResolver,\n RegionStyleContext,\n StampDrawTool,\n StampOptions,\n} from \"./draw-layer-types\";\nexport { closeRing, createCircle, createRectangle } from \"./draw-layer-utils\";\n\nfunction resolveRegionInteractionShadowStyle(strokeStyle: import(\"./draw-layer-types\").RegionStrokeStyle): import(\"./draw-layer-types\").RegionStrokeStyle {\n return {\n color: REGION_INTERACTION_SHADOW_COLOR,\n width: REGION_INTERACTION_SHADOW_WIDTH,\n lineDash: EMPTY_DASH,\n lineJoin: strokeStyle.lineJoin,\n lineCap: strokeStyle.lineCap,\n shadowColor: \"rgba(0, 0, 0, 0)\",\n shadowBlur: 0,\n shadowOffsetX: 0,\n shadowOffsetY: 0,\n };\n}\n\nfunction resolveDrawPreviewFillColor(value: string | undefined): string {\n if (typeof value !== \"string\") return DEFAULT_DRAW_PREVIEW_FILL;\n const next = value.trim();\n return next.length > 0 ? next : DEFAULT_DRAW_PREVIEW_FILL;\n}\n\nfunction isValidPolygon(coords: import(\"./draw-layer-types\").DrawCoordinate[]): boolean {\n return Array.isArray(coords) && coords.length >= 4 && polygonArea(coords) > MIN_AREA_PX;\n}\n\nexport function DrawLayer({\n tool,\n imageWidth,\n imageHeight,\n imageMpp,\n imageZoom,\n stampOptions,\n brushOptions,\n projectorRef,\n onBrushTap,\n onDrawComplete,\n onPatchComplete,\n enabled,\n viewStateSignal,\n persistedRegions,\n patchRegions,\n persistedPolygons,\n drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n hoveredRegionId = null,\n activeRegionId = null,\n regionLabelStyle,\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n regionLabelAnchor = \"top-center\",\n clampRegionLabelToViewport = true,\n regionLabelAutoLiftOffsetPx,\n invalidateRef,\n className,\n style,\n}: DrawLayerProps): React.ReactElement {\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const drawPendingRef = useRef(false);\n const overlayDebugSnapshotRef = useRef<Map<string, string>>(new Map());\n const lastToolRef = useRef<DrawTool>(tool);\n const sessionRef = useRef<DrawSession>({\n isDrawing: false,\n pointerId: null,\n start: null,\n current: null,\n cursor: null,\n cursorScreen: null,\n points: [],\n screenPoints: [],\n stampCenter: null,\n });\n\n const active = enabled ?? tool !== \"cursor\";\n const mergedPersistedRegions = useMemo<DrawRegion[]>(() => {\n if (persistedRegions && persistedRegions.length > 0) {\n return persistedRegions;\n }\n if (!persistedPolygons || persistedPolygons.length === 0) {\n return EMPTY_REGIONS;\n }\n return persistedPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [persistedRegions, persistedPolygons]);\n const mergedPatchRegions = useMemo<DrawRegion[]>(() => patchRegions ?? EMPTY_REGIONS, [patchRegions]);\n const preparedPersistedRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPersistedRegions.length; i += 1) {\n const region = mergedPersistedRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPersistedRegions]);\n const preparedPatchRegions = useMemo<PreparedRenderedRegion[]>(() => {\n const out: PreparedRenderedRegion[] = [];\n for (let i = 0; i < mergedPatchRegions.length; i += 1) {\n const region = mergedPatchRegions[i];\n const polygons = normalizeDrawRegionPolygons(region.coordinates);\n if (polygons.length === 0) continue;\n out.push({\n region,\n regionIndex: i,\n regionKey: region.id ?? i,\n polygons,\n });\n }\n return out;\n }, [mergedPatchRegions]);\n\n const resolvedStrokeStyle = useMemo(() => resolveStrokeStyle(regionStrokeStyle), [regionStrokeStyle]);\n const resolvedHoverStrokeStyle = useMemo(() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeHoverStyle), [resolvedStrokeStyle, regionStrokeHoverStyle]);\n const resolvedActiveStrokeStyle = useMemo(() => mergeStrokeStyle(resolvedStrokeStyle, regionStrokeActiveStyle), [resolvedStrokeStyle, regionStrokeActiveStyle]);\n const resolvedPatchStrokeStyle = useMemo(() => mergeStrokeStyle(DEFAULT_PATCH_STROKE_STYLE, patchStrokeStyle), [patchStrokeStyle]);\n const resolvedDrawPreviewFillColor = useMemo(() => resolveDrawPreviewFillColor(drawFillColor), [drawFillColor]);\n\n const resolvedLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n const resolvedDrawAreaTooltipOptions = useMemo(() => resolveDrawAreaTooltipOptions(drawAreaTooltip), [drawAreaTooltip]);\n const resolvedStampOptions = useMemo(() => resolveStampOptions(stampOptions), [stampOptions]);\n const resolvedBrushOptions = useMemo(() => resolveBrushOptions(brushOptions), [brushOptions]);\n\n const mergedStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n inset: 0,\n zIndex: 2,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n pointerEvents: active ? \"auto\" : \"none\",\n cursor: active ? (tool === \"brush\" ? \"none\" : \"crosshair\") : \"default\",\n ...style,\n }),\n [active, tool, style]\n );\n\n const resizeCanvas = useCallback(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const w = Math.max(1, Math.round(rect.width * dpr));\n const h = Math.max(1, Math.round(rect.height * dpr));\n\n if (canvas.width !== w || canvas.height !== h) {\n canvas.width = w;\n canvas.height = h;\n }\n }, []);\n\n const worldToScreenPoints = useCallback(\n (points: import(\"./draw-layer-types\").DrawCoordinate[]): import(\"./draw-layer-types\").DrawCoordinate[] => {\n const projector = projectorRef.current;\n if (!projector || points.length === 0) return [];\n\n const out = new Array<import(\"./draw-layer-types\").DrawCoordinate>(points.length);\n for (let i = 0; i < points.length; i += 1) {\n const coord = toCoord(projector.worldToScreen(points[i][0], points[i][1]));\n if (!coord) return [];\n out[i] = coord;\n }\n return out;\n },\n [projectorRef]\n );\n\n const localScreenToWorld = useCallback(\n (screen: import(\"./draw-layer-types\").DrawCoordinate): import(\"./draw-layer-types\").DrawCoordinate | null => {\n const projector = projectorRef.current;\n const canvas = canvasRef.current;\n if (!projector || !canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const raw = toCoord(projector.screenToWorld(rect.left + screen[0], rect.top + screen[1]));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const getRectangleProjection = useCallback(() => {\n const projector = projectorRef.current;\n const rotationDeg = projector?.getViewState?.().rotationDeg ?? 0;\n if (Math.abs(rotationDeg % 360) < 0.01 || !projector) return undefined;\n\n return {\n worldToScreen: (x: number, y: number): import(\"./draw-layer-types\").DrawCoordinate | null => toCoord(projector.worldToScreen(x, y)),\n screenToWorld: localScreenToWorld,\n };\n }, [projectorRef, localScreenToWorld]);\n\n const micronsToWorldPixels = useCallback(\n (lengthUm: number): number => {\n if (!Number.isFinite(lengthUm) || lengthUm <= 0) return 0;\n\n const mppValue = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 1;\n const imageZoomValue = typeof imageZoom === \"number\" && Number.isFinite(imageZoom) ? imageZoom : 0;\n const viewZoomRaw = projectorRef.current?.getViewState?.().zoom;\n const viewZoom = typeof viewZoomRaw === \"number\" && Number.isFinite(viewZoomRaw) && viewZoomRaw > 0 ? viewZoomRaw : 1;\n const continuousZoom = imageZoomValue + Math.log2(viewZoom);\n const umPerScreenPixel = Math.max(1e-9, calcScaleResolution(mppValue, imageZoomValue, continuousZoom));\n const screenPixels = lengthUm / umPerScreenPixel;\n return screenPixels / viewZoom;\n },\n [imageMpp, imageZoom, projectorRef]\n );\n\n const buildStampCoordsCallback = useCallback(\n (stampTool: StampDrawTool, center: import(\"./draw-layer-types\").DrawCoordinate | null): import(\"./draw-layer-types\").DrawCoordinate[] => {\n return buildStampCoords({\n stampTool,\n center,\n resolvedStampOptions,\n imageWidth,\n imageHeight,\n micronsToWorldPixels,\n getRectangleProjection,\n });\n },\n [micronsToWorldPixels, imageWidth, imageHeight, resolvedStampOptions, getRectangleProjection]\n );\n\n const buildPreviewCoords = useCallback((): import(\"./draw-layer-types\").DrawCoordinate[] => {\n const session = sessionRef.current;\n if (isStampTool(tool)) {\n return buildStampCoordsCallback(tool, session.stampCenter);\n }\n if (tool === \"brush\") {\n return [];\n }\n if (!session.isDrawing) return [];\n\n if (tool === \"freehand\") {\n return session.points;\n }\n if (tool === \"rectangle\") {\n return createRectangle(session.start, session.current, getRectangleProjection());\n }\n if (tool === \"circular\") {\n return createCircle(session.start, session.current);\n }\n\n return [];\n }, [tool, buildStampCoordsCallback, getRectangleProjection]);\n\n const drawOverlay = useCallback(() => {\n resizeCanvas();\n\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const ctx = canvas.getContext(\"2d\");\n if (!ctx) return;\n\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n const canvasWidth = canvas.width / dpr;\n const canvasHeight = canvas.height / dpr;\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n if (preparedPersistedRegions.length > 0) {\n for (const entry of preparedPersistedRegions) {\n const { region, polygons, regionIndex, regionKey } = entry;\n const state: \"default\" | \"hover\" | \"active\" = isSameRegionId(activeRegionId, regionKey) ? \"active\" : isSameRegionId(hoveredRegionId, regionKey) ? \"hover\" : \"default\";\n let strokeStyle = state === \"active\" ? resolvedActiveStrokeStyle : state === \"hover\" ? resolvedHoverStrokeStyle : resolvedStrokeStyle;\n\n if (resolveRegionStrokeStyle) {\n const resolved = resolveRegionStrokeStyle({\n region,\n regionId: regionKey,\n regionIndex,\n state,\n });\n strokeStyle = mergeStrokeStyle(strokeStyle, resolved || undefined);\n }\n const interactionShadowStyle = state === \"default\" ? null : resolveRegionInteractionShadowStyle(strokeStyle);\n\n for (const polygon of polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenOuter, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenOuter, strokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n if (interactionShadowStyle) {\n drawPath(ctx, screenHole, interactionShadowStyle, true, false);\n }\n drawPath(ctx, screenHole, strokeStyle, true, false);\n }\n }\n }\n }\n }\n\n if (preparedPatchRegions.length > 0) {\n for (const entry of preparedPatchRegions) {\n for (const polygon of entry.polygons) {\n const screenOuter = worldToScreenPoints(polygon.outer);\n if (screenOuter.length >= 4) {\n drawPath(ctx, screenOuter, resolvedPatchStrokeStyle, true, false);\n }\n for (const hole of polygon.holes) {\n const screenHole = worldToScreenPoints(hole);\n if (screenHole.length >= 4) {\n drawPath(ctx, screenHole, resolvedPatchStrokeStyle, true, false);\n }\n }\n }\n }\n }\n\n if (Array.isArray(overlayShapes) && overlayShapes.length > 0) {\n const imageOuterRing = worldToScreenPoints(\n closeRing([\n [0, 0],\n [imageWidth, 0],\n [imageWidth, imageHeight],\n [0, imageHeight],\n ])\n );\n drawOverlayShapes({\n ctx,\n overlayShapes,\n imageOuterRing,\n worldToScreenPoints,\n baseStrokeStyle: resolvedStrokeStyle,\n onInvertedFillDebug: (globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__\n ? info => {\n const debugKey = String(info.id);\n const debugSignature = `${info.outerRingPoints}|${info.sourceRingCount}|${info.holeRingCount}|${info.fillColor}`;\n if (overlayDebugSnapshotRef.current.get(debugKey) !== debugSignature) {\n overlayDebugSnapshotRef.current.set(debugKey, debugSignature);\n console.debug(\"[open-plant] invertedFill\", info);\n }\n }\n : undefined,\n });\n }\n\n const preview = buildPreviewCoords();\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx, sessionRef.current, resolvedBrushOptions);\n drawBrushCursor(ctx, sessionRef.current, projectorRef.current, resolvedBrushOptions);\n } else if (preview.length > 0) {\n if (tool === \"freehand\") {\n const line = worldToScreenPoints(preview);\n if (line.length >= 2) {\n drawPath(ctx, line, resolvedStrokeStyle, false, false);\n }\n if (line.length >= 3) {\n drawPath(ctx, worldToScreenPoints(closeRing(preview)), resolvedStrokeStyle, true, true, resolvedDrawPreviewFillColor);\n }\n } else {\n const polygon = worldToScreenPoints(preview);\n if (polygon.length >= 4) {\n drawPath(ctx, polygon, resolvedStrokeStyle, true, true, resolvedDrawPreviewFillColor);\n }\n }\n }\n }\n\n if (preparedPersistedRegions.length > 0) {\n const zoom = Math.max(1e-6, projectorRef.current?.getViewState?.().zoom ?? 1);\n const labelAutoLiftOffset =\n typeof regionLabelAutoLiftOffsetPx === \"number\" && Number.isFinite(regionLabelAutoLiftOffsetPx)\n ? Math.max(0, regionLabelAutoLiftOffsetPx)\n : resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, projectorRef.current?.getZoomRange?.());\n for (const entry of preparedPersistedRegions) {\n if (!entry.region.label) continue;\n const anchorWorld = getTopAnchorFromPolygons(entry.polygons, regionLabelAnchor);\n if (!anchorWorld) continue;\n const anchorScreen = toCoord(projectorRef.current?.worldToScreen(anchorWorld[0], anchorWorld[1]) ?? []);\n if (!anchorScreen) continue;\n let dynamicLabelStyle = mergeRegionLabelStyle(\n resolvedLabelStyle,\n resolveRegionLabelStyleProp?.({\n region: entry.region,\n regionId: entry.regionKey,\n regionIndex: entry.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n drawRegionLabel(ctx, entry.region.label, anchorScreen, canvasWidth, canvasHeight, dynamicLabelStyle, clampRegionLabelToViewport);\n }\n }\n\n if (resolvedDrawAreaTooltipOptions.enabled && active && (tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\")) {\n const session = sessionRef.current;\n if (session.isDrawing) {\n const areaCoords = tool === \"freehand\" ? closeRing(preview) : preview;\n if (areaCoords.length >= 4) {\n const areaPx = polygonArea(areaCoords);\n const mpp = typeof imageMpp === \"number\" && Number.isFinite(imageMpp) && imageMpp > 0 ? imageMpp : 0;\n const areaMm2 = mpp > 0 ? (areaPx * mpp * mpp) / (MICRONS_PER_MM * MICRONS_PER_MM) : 0;\n const text = resolvedDrawAreaTooltipOptions.format(areaMm2);\n\n const cursor = session.cursorScreen ?? (session.current ? toCoord(projectorRef.current?.worldToScreen(session.current[0], session.current[1]) ?? []) : null);\n if (cursor) {\n drawAreaTooltipBox(\n ctx,\n text,\n cursor,\n canvasWidth,\n canvasHeight,\n resolvedDrawAreaTooltipOptions.style,\n resolvedDrawAreaTooltipOptions.cursorOffsetX,\n resolvedDrawAreaTooltipOptions.cursorOffsetY\n );\n }\n }\n }\n }\n }, [\n active,\n tool,\n buildPreviewCoords,\n resizeCanvas,\n worldToScreenPoints,\n imageWidth,\n imageHeight,\n projectorRef,\n preparedPersistedRegions,\n overlayShapes,\n hoveredRegionId,\n activeRegionId,\n resolvedStrokeStyle,\n resolvedHoverStrokeStyle,\n resolvedActiveStrokeStyle,\n resolvedDrawPreviewFillColor,\n preparedPatchRegions,\n resolvedPatchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyleProp,\n resolvedLabelStyle,\n resolvedDrawAreaTooltipOptions,\n autoLiftRegionLabelAtMaxZoom,\n regionLabelAnchor,\n clampRegionLabelToViewport,\n regionLabelAutoLiftOffsetPx,\n imageMpp,\n resolvedBrushOptions,\n ]);\n\n const requestDraw = useCallback(() => {\n if (drawPendingRef.current) return;\n drawPendingRef.current = true;\n requestAnimationFrame(() => {\n drawPendingRef.current = false;\n drawOverlay();\n });\n }, [drawOverlay]);\n\n const resetSession = useCallback((preserveCursor = false) => {\n const session = sessionRef.current;\n const canvas = canvasRef.current;\n\n if (canvas && session.pointerId !== null && canvas.hasPointerCapture(session.pointerId)) {\n canvas.releasePointerCapture(session.pointerId);\n }\n\n session.isDrawing = false;\n session.pointerId = null;\n session.start = null;\n session.current = null;\n session.points = [];\n session.screenPoints = [];\n session.stampCenter = null;\n if (!preserveCursor) {\n session.cursor = null;\n session.cursorScreen = null;\n }\n }, []);\n\n const toWorld = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>): import(\"./draw-layer-types\").DrawCoordinate | null => {\n const projector = projectorRef.current;\n if (!projector || imageWidth <= 0 || imageHeight <= 0) return null;\n\n const raw = toCoord(projector.screenToWorld(event.clientX, event.clientY));\n if (!raw) return null;\n return clampWorld(raw, imageWidth, imageHeight);\n },\n [projectorRef, imageWidth, imageHeight]\n );\n\n const toLocalScreen = useCallback((event: ReactPointerEvent<HTMLCanvasElement>): import(\"./draw-layer-types\").DrawCoordinate | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n const x = clamp(event.clientX - rect.left, 0, rect.width);\n const y = clamp(event.clientY - rect.top, 0, rect.height);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const finishSession = useCallback(() => {\n const session = sessionRef.current;\n if (!session.isDrawing) {\n resetSession(true);\n requestDraw();\n return;\n }\n\n let coordinates: import(\"./draw-layer-types\").DrawCoordinate[] = [];\n if (tool === \"freehand\") {\n if (session.points.length >= FREEHAND_MIN_POINTS) {\n coordinates = closeRing(session.points);\n }\n } else if (tool === \"rectangle\") {\n coordinates = createRectangle(session.start, session.current, getRectangleProjection());\n } else if (tool === \"circular\") {\n coordinates = createCircle(session.start, session.current);\n } else if (tool === \"brush\") {\n const tapPoint = session.points[session.points.length - 1] ?? session.current ?? session.start;\n if (resolvedBrushOptions.clickSelectRoi && tapPoint && session.points.length <= 1 && onBrushTap?.(tapPoint)) {\n resetSession(true);\n requestDraw();\n return;\n }\n const edgeDetail = resolvedBrushOptions.edgeDetail;\n const minRasterStep = Math.max(MIN_BRUSH_RASTER_STEP, (resolvedBrushOptions.radius * 2) / (BRUSH_RASTER_DIAMETER_SAMPLES * edgeDetail));\n const screenPath = session.screenPoints.length > 0 ? session.screenPoints : worldToScreenPoints(session.points);\n const screenPolygon = buildBrushStrokePolygon(screenPath, {\n radius: resolvedBrushOptions.radius,\n minRasterStep,\n circleSides: Math.max(24, Math.round(64 * edgeDetail)),\n simplifyTolerance: minRasterStep * 0.25,\n smoothingPasses: resolvedBrushOptions.edgeSmoothing,\n }) as import(\"./draw-layer-types\").DrawCoordinate[];\n const worldPolygon: import(\"./draw-layer-types\").DrawCoordinate[] = [];\n for (const point of screenPolygon) {\n const world = localScreenToWorld(point);\n if (!world) continue;\n worldPolygon.push(world);\n }\n coordinates = closeRing(worldPolygon);\n }\n\n if ((tool === \"freehand\" || tool === \"rectangle\" || tool === \"circular\" || tool === \"brush\") && isValidPolygon(coordinates) && onDrawComplete) {\n const intent: import(\"./draw-layer-types\").DrawIntent = tool === \"brush\" ? \"brush\" : \"roi\";\n onDrawComplete({\n tool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n });\n }\n\n resetSession(true);\n requestDraw();\n }, [\n tool,\n onDrawComplete,\n resetSession,\n requestDraw,\n worldToScreenPoints,\n localScreenToWorld,\n getRectangleProjection,\n resolvedBrushOptions.radius,\n resolvedBrushOptions.edgeDetail,\n resolvedBrushOptions.edgeSmoothing,\n resolvedBrushOptions.clickSelectRoi,\n onBrushTap,\n ]);\n\n const handleStampAt = useCallback(\n (stampTool: StampDrawTool, center: import(\"./draw-layer-types\").DrawCoordinate): void => {\n const coordinates = buildStampCoordsCallback(stampTool, center);\n if (!isValidPolygon(coordinates)) return;\n const intent: import(\"./draw-layer-types\").DrawIntent = stampTool === \"stamp-rectangle-4096px\" ? \"patch\" : \"roi\";\n const result: import(\"./draw-layer-types\").DrawResult = {\n tool: stampTool,\n intent,\n coordinates,\n bbox: computeBounds(coordinates),\n areaPx: polygonArea(coordinates),\n };\n onDrawComplete?.(result);\n if (intent === \"patch\" && onPatchComplete) {\n onPatchComplete(result as import(\"./draw-layer-types\").PatchDrawResult);\n }\n },\n [buildStampCoordsCallback, onDrawComplete, onPatchComplete]\n );\n\n const appendBrushPoint = useCallback((session: DrawSession, world: import(\"./draw-layer-types\").DrawCoordinate, screen: import(\"./draw-layer-types\").DrawCoordinate): void => {\n const minScreenStep2 = BRUSH_SCREEN_STEP * BRUSH_SCREEN_STEP;\n const prevScreen = session.screenPoints[session.screenPoints.length - 1];\n if (!prevScreen) {\n session.points.push(world);\n session.screenPoints.push(screen);\n session.current = world;\n return;\n }\n const dx = screen[0] - prevScreen[0];\n const dy = screen[1] - prevScreen[1];\n if (dx * dx + dy * dy >= minScreenStep2) {\n session.points.push(world);\n session.screenPoints.push(screen);\n } else {\n session.points[session.points.length - 1] = world;\n session.screenPoints[session.screenPoints.length - 1] = screen;\n }\n session.current = world;\n }, []);\n\n const handlePointerDown = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n if (!active) return;\n if (tool === \"cursor\") return;\n if (event.button !== 0) return;\n\n const world = toWorld(event);\n if (!world) return;\n const screen = toLocalScreen(event);\n if (!screen) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n if (isStampTool(tool)) {\n const session = sessionRef.current;\n session.stampCenter = world;\n handleStampAt(tool, world);\n requestDraw();\n return;\n }\n\n const canvas = canvasRef.current;\n if (canvas) {\n canvas.setPointerCapture(event.pointerId);\n }\n\n const session = sessionRef.current;\n session.isDrawing = true;\n session.pointerId = event.pointerId;\n session.start = world;\n session.current = world;\n session.cursor = world;\n session.cursorScreen = screen;\n session.points = tool === \"freehand\" || tool === \"brush\" ? [world] : [];\n session.screenPoints = tool === \"brush\" ? [screen] : [];\n requestDraw();\n },\n [active, tool, toWorld, toLocalScreen, handleStampAt, requestDraw]\n );\n\n const handlePointerMove = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n if (!active) return;\n if (tool === \"cursor\") return;\n\n const world = toWorld(event);\n if (!world) return;\n const screen = toLocalScreen(event);\n if (!screen) return;\n\n const session = sessionRef.current;\n session.cursor = world;\n session.cursorScreen = screen;\n\n if (isStampTool(tool)) {\n session.stampCenter = world;\n event.preventDefault();\n event.stopPropagation();\n requestDraw();\n return;\n }\n\n if (tool === \"brush\") {\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n requestDraw();\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n appendBrushPoint(session, world, screen);\n requestDraw();\n return;\n }\n\n if (!session.isDrawing || session.pointerId !== event.pointerId) {\n return;\n }\n event.preventDefault();\n event.stopPropagation();\n\n if (tool === \"freehand\") {\n const projector = projectorRef.current;\n const zoom = Math.max(1e-6, projector?.getViewState?.().zoom ?? 1);\n const minWorldStep = FREEHAND_SCREEN_STEP / zoom;\n const minWorldStep2 = minWorldStep * minWorldStep;\n const prev = session.points[session.points.length - 1];\n\n if (!prev) {\n session.points.push(world);\n } else {\n const dx = world[0] - prev[0];\n const dy = world[1] - prev[1];\n if (dx * dx + dy * dy >= minWorldStep2) {\n session.points.push(world);\n }\n }\n } else {\n session.current = world;\n }\n\n requestDraw();\n },\n [active, tool, toWorld, toLocalScreen, requestDraw, projectorRef, appendBrushPoint]\n );\n\n const handlePointerUp = useCallback(\n (event: ReactPointerEvent<HTMLCanvasElement>) => {\n const session = sessionRef.current;\n if (!session.isDrawing || session.pointerId !== event.pointerId) return;\n\n event.preventDefault();\n event.stopPropagation();\n const world = toWorld(event);\n const screen = toLocalScreen(event);\n if (world) {\n session.cursor = world;\n if (screen) {\n session.cursorScreen = screen;\n }\n if (tool === \"brush\") {\n if (screen) {\n appendBrushPoint(session, world, screen);\n }\n } else {\n session.current = world;\n }\n }\n const canvas = canvasRef.current;\n if (canvas && canvas.hasPointerCapture(event.pointerId)) {\n canvas.releasePointerCapture(event.pointerId);\n }\n\n finishSession();\n },\n [finishSession, toWorld, toLocalScreen, tool, appendBrushPoint]\n );\n\n const handlePointerLeave = useCallback(() => {\n const session = sessionRef.current;\n let changed = false;\n if (tool === \"brush\" && !session.isDrawing && session.cursor) {\n session.cursor = null;\n session.cursorScreen = null;\n changed = true;\n }\n if (isStampTool(tool) && session.stampCenter) {\n session.stampCenter = null;\n changed = true;\n }\n if (changed) {\n requestDraw();\n }\n }, [tool, requestDraw]);\n\n useEffect(() => {\n resizeCanvas();\n requestDraw();\n\n const canvas = canvasRef.current;\n if (!canvas) return undefined;\n\n const observer = new ResizeObserver(() => {\n resizeCanvas();\n requestDraw();\n });\n observer.observe(canvas);\n\n return () => {\n observer.disconnect();\n };\n }, [resizeCanvas, requestDraw]);\n\n useEffect(() => {\n if (!active) {\n resetSession();\n }\n requestDraw();\n }, [active, requestDraw, resetSession]);\n\n useEffect(() => {\n if (lastToolRef.current === tool) {\n return;\n }\n lastToolRef.current = tool;\n resetSession();\n requestDraw();\n }, [tool, resetSession, requestDraw]);\n\n useEffect(() => {\n requestDraw();\n }, [viewStateSignal, mergedPersistedRegions, overlayShapes, requestDraw]);\n\n useEffect(() => {\n if (!invalidateRef) return undefined;\n invalidateRef.current = requestDraw;\n return () => {\n if (invalidateRef.current === requestDraw) {\n invalidateRef.current = null;\n }\n };\n }, [invalidateRef, requestDraw]);\n\n useEffect(() => {\n if (!active) return undefined;\n\n const onKeyDown = (event: KeyboardEvent): void => {\n if (event.key !== \"Escape\") return;\n resetSession();\n requestDraw();\n };\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [active, resetSession, requestDraw]);\n\n return (\n <canvas\n ref={canvasRef}\n className={className}\n style={mergedStyle}\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={handlePointerUp}\n onPointerCancel={handlePointerUp}\n onPointerLeave={handlePointerLeave}\n onContextMenu={event => {\n if (active) event.preventDefault();\n }}\n onWheel={event => {\n if (!active) return;\n const canvas = canvasRef.current;\n const projector = projectorRef.current;\n if (!canvas || typeof projector?.zoomBy !== \"function\") return;\n event.preventDefault();\n event.stopPropagation();\n const rect = canvas.getBoundingClientRect();\n const screenX = event.clientX - rect.left;\n const screenY = event.clientY - rect.top;\n projector.zoomBy(event.deltaY < 0 ? WHEEL_ZOOM_IN_FACTOR : WHEEL_ZOOM_OUT_FACTOR, screenX, screenY);\n requestDraw();\n }}\n />\n );\n}\n","import type { WsiImageSource, WsiTerm } from \"./types\";\n\nexport interface RawImsInfo {\n width?: number | null;\n height?: number | null;\n tileSize?: number | null;\n zoom?: number | null;\n path?: string | null;\n mpp?: number | null;\n}\n\nexport interface RawWsiTerm {\n termId?: string | null;\n termName?: string | null;\n termColor?: string | null;\n}\n\nexport interface RawImagePayload {\n _id?: string | null;\n name?: string | null;\n width?: number | null;\n height?: number | null;\n tileSize?: number | null;\n zoom?: number | null;\n path?: string | null;\n mpp?: number | null;\n imsInfo?: RawImsInfo | null;\n terms?: RawWsiTerm[] | null;\n}\n\nfunction trimTrailingSlash(value: string): string {\n return String(value ?? \"\").replace(/\\/+$/, \"\");\n}\n\nfunction ensureLeadingSlash(value: string): string {\n const raw = String(value ?? \"\");\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nfunction joinImsTileRoot(tileBaseUrl: string): string {\n const base = trimTrailingSlash(tileBaseUrl);\n if (!base) return \"\";\n\n // Explicit TileGroup path already provided.\n if (/\\/TileGroup\\d+$/i.test(base)) return base;\n\n let parsed: URL | null = null;\n try {\n parsed = new URL(base);\n } catch {\n parsed = null;\n }\n\n if (parsed) {\n const origin = `${parsed.protocol}//${parsed.host}`;\n const path = trimTrailingSlash(parsed.pathname || \"\");\n\n // If caller passes /ims, keep /ims and append image path directly:\n // /ims + /tiles/<hash> + /tier/y_x.webp\n if (/\\/ims$/i.test(path)) return `${origin}${path}`;\n if (/\\/tiles$/i.test(path)) return `${origin}${path}`;\n return `${origin}${path}/tiles`;\n }\n\n // Relative path mode\n if (/\\/ims$/i.test(base)) return `/ims`;\n if (/\\/tiles$/i.test(base)) return `${base}`;\n return `${base}/tiles`;\n}\n\nexport function normalizeImageInfo(raw: RawImagePayload, tileBaseUrl: string): WsiImageSource {\n const ims = raw?.imsInfo ?? {};\n const isIms = !!raw?.imsInfo;\n\n const width = Number(ims.width ?? raw?.width ?? 0);\n const height = Number(ims.height ?? raw?.height ?? 0);\n const tileSize = Number(ims.tileSize ?? raw?.tileSize ?? 0);\n const maxTierZoom = Number(ims.zoom ?? raw?.zoom ?? 0);\n const tilePath = String(ims.path ?? raw?.path ?? \"\");\n const mpp = Number(ims.mpp ?? raw?.mpp ?? 0);\n\n if (!width || !height || !tileSize || !tilePath) {\n throw new Error(\"Incomplete image metadata: width/height/tileSize/path required\");\n }\n\n const terms: WsiTerm[] = Array.isArray(raw?.terms)\n ? raw.terms.map((term: RawWsiTerm) => ({\n termId: String(term?.termId ?? \"\"),\n termName: String(term?.termName ?? \"\"),\n termColor: String(term?.termColor ?? \"\"),\n }))\n : [];\n\n const normalizedPath = ensureLeadingSlash(tilePath);\n const imsTileRoot = joinImsTileRoot(tileBaseUrl);\n const tileUrlBuilder = isIms ? (tier: number, x: number, y: number): string => `${imsTileRoot}${normalizedPath}/${tier}/${y}_${x}.webp` : undefined;\n\n return {\n id: raw?._id || \"unknown\",\n name: raw?.name || \"unknown\",\n width,\n height,\n mpp: Number.isFinite(mpp) && mpp > 0 ? mpp : undefined,\n tileSize,\n maxTierZoom: Number.isFinite(maxTierZoom) ? Math.max(0, Math.floor(maxTierZoom)) : 0,\n tilePath,\n tileBaseUrl,\n terms,\n tileUrlBuilder,\n };\n}\n\nexport function toTileUrl(source: Pick<WsiImageSource, \"tilePath\" | \"tileBaseUrl\" | \"tileUrlBuilder\">, tier: number, x: number, y: number): string {\n if (source.tileUrlBuilder) {\n return source.tileUrlBuilder(tier, x, y);\n }\n const normalizedPath = ensureLeadingSlash(source.tilePath);\n return `${source.tileBaseUrl}${normalizedPath}/${tier}/${y}_${x}.webp`;\n}\n","import {\n\ttype CSSProperties,\n\ttype MutableRefObject,\n\ttype PointerEvent as ReactPointerEvent,\n\ttype ReactNode,\n\ttype RefObject,\n\tuseCallback,\n\tuseEffect,\n\tuseMemo,\n\tuseRef,\n} from \"react\";\nimport { toTileUrl } from \"../wsi/image-info\";\nimport type { WsiImageSource, WsiViewState } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\n\ntype Bounds = [number, number, number, number];\n\nexport interface OverviewMapProjector {\n\tgetViewState: () => WsiViewState;\n\tsetViewState: (next: Partial<WsiViewState>) => void;\n\tsetViewCenter?: (worldX: number, worldY: number) => void;\n\tgetViewBounds?: () => number[];\n\tgetViewCorners?: () => Array<[number, number]>;\n}\n\nexport type OverviewMapPosition =\n\t| \"bottom-right\"\n\t| \"bottom-left\"\n\t| \"top-right\"\n\t| \"top-left\";\n\nexport type ViewportBorderStyle = \"stroke\" | \"dash\";\n\nexport interface OverviewMapOptions {\n\twidth: number;\n\theight: number;\n\tmargin: number;\n\tposition: OverviewMapPosition;\n\tborderRadius: number;\n\tborderWidth: number;\n\tbackgroundColor: string;\n\tborderColor: string;\n\tviewportBorderColor: string;\n\tviewportBorderStyle: ViewportBorderStyle;\n\tviewportFillColor: string;\n\tinteractive: boolean;\n\tshowThumbnail: boolean;\n\tmaxThumbnailTiles: number;\n\tonClose?: () => void;\n\tcloseIcon?: ReactNode;\n\tcloseButtonStyle?: CSSProperties;\n}\n\nexport interface OverviewMapProps {\n\tsource: WsiImageSource;\n\tprojectorRef: RefObject<OverviewMapProjector | null>;\n\tauthToken?: string;\n\toptions?: Partial<OverviewMapOptions>;\n\tinvalidateRef?: MutableRefObject<(() => void) | null>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nconst DEFAULT_OVERVIEW_MAP_OPTIONS: OverviewMapOptions = {\n\twidth: 200,\n\theight: 125,\n\tmargin: 16,\n\tposition: \"bottom-right\",\n\tborderRadius: 6,\n\tborderWidth: 0,\n\tbackgroundColor: \"rgba(4, 10, 18, 0.88)\",\n\tborderColor: \"rgba(230, 244, 255, 0.35)\",\n\tviewportBorderColor: \"#171719\",\n\tviewportBorderStyle: \"dash\",\n\tviewportFillColor: \"transparent\",\n\tinteractive: true,\n\tshowThumbnail: true,\n\tmaxThumbnailTiles: 16,\n};\n\nfunction strokeSymmetricDashedPolygon(\n\tctx: CanvasRenderingContext2D,\n\tpoints: Array<[number, number]>,\n\tdashLen: number,\n\tgapLen: number,\n): void {\n\tconst len = points.length;\n\tif (len !== 4) return;\n\tif (dashLen <= 0 || gapLen <= 0) return;\n\n\tfor (let i = 0; i < len; i += 1) {\n\t\tconst from = points[i];\n\t\tconst to = points[(i + 1) % len];\n\t\tconst sideLen = Math.hypot(to[0] - from[0], to[1] - from[1]);\n\t\tif (sideLen < 1e-6) continue;\n\n\t\tconst n = Math.max(1, Math.round((sideLen + gapLen) / (dashLen + gapLen)));\n\t\tconst fittedLen = n * dashLen + (n - 1) * gapLen;\n\t\tconst scale = sideLen / Math.max(1e-6, fittedLen);\n\t\tconst adjDash = dashLen * scale;\n\t\tconst adjGap = gapLen * scale;\n\n\t\tctx.beginPath();\n\t\tctx.moveTo(from[0], from[1]);\n\t\tctx.lineTo(to[0], to[1]);\n\t\tctx.setLineDash([adjDash, adjGap]);\n\t\tctx.lineDashOffset = 0;\n\t\tctx.stroke();\n\t}\n\n\tctx.setLineDash([]);\n\tctx.lineDashOffset = 0;\n}\n\nfunction toPositiveNumber(\n\tvalue: number | undefined,\n\tfallback: number,\n\tmin = 1,\n): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return fallback;\n\treturn Math.max(min, value);\n}\n\nfunction isFiniteBounds(bounds: number[] | null | undefined): bounds is Bounds {\n\treturn (\n\t\tArray.isArray(bounds) &&\n\t\tbounds.length === 4 &&\n\t\tNumber.isFinite(bounds[0]) &&\n\t\tNumber.isFinite(bounds[1]) &&\n\t\tNumber.isFinite(bounds[2]) &&\n\t\tNumber.isFinite(bounds[3])\n\t);\n}\n\nconst DEFAULT_CLOSE_BUTTON_STYLE: CSSProperties = {\n\tposition: \"absolute\",\n\ttop: 4,\n\tright: 4,\n\tzIndex: 1,\n\twidth: 18,\n\theight: 18,\n\tborderRadius: 999,\n\tborder: \"1px solid rgba(255,255,255,0.4)\",\n\tbackground: \"rgba(16, 17, 19, 0.85)\",\n\tcolor: \"#fff\",\n\tfontSize: 12,\n\tlineHeight: 1,\n\tcursor: \"pointer\",\n\tpadding: 0,\n\tdisplay: \"flex\",\n\talignItems: \"center\",\n\tjustifyContent: \"center\",\n};\n\nexport function OverviewMap({\n\tsource,\n\tprojectorRef,\n\tauthToken = \"\",\n\toptions,\n\tinvalidateRef,\n\tclassName,\n\tstyle,\n}: OverviewMapProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst thumbnailRef = useRef<HTMLCanvasElement | null>(null);\n\tconst lastBoundsRef = useRef<Bounds | null>(null);\n\tconst draggingRef = useRef<{ active: boolean; pointerId: number | null }>({\n\t\tactive: false,\n\t\tpointerId: null,\n\t});\n\tconst rafRef = useRef<number | null>(null);\n\tconst drawPendingRef = useRef(false);\n\n\tconst width = toPositiveNumber(\n\t\toptions?.width,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.width,\n\t\t64,\n\t);\n\tconst height = toPositiveNumber(\n\t\toptions?.height,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.height,\n\t\t48,\n\t);\n\n\tconst contentRect = useMemo(() => {\n\t\tconst imgW = Math.max(1, source.width);\n\t\tconst imgH = Math.max(1, source.height);\n\t\tconst imageAspect = imgW / imgH;\n\t\tconst boxAspect = width / height;\n\n\t\tlet cw: number;\n\t\tlet ch: number;\n\t\tif (imageAspect > boxAspect) {\n\t\t\tcw = width;\n\t\t\tch = width / imageAspect;\n\t\t} else {\n\t\t\tch = height;\n\t\t\tcw = height * imageAspect;\n\t\t}\n\n\t\treturn {\n\t\t\tx: (width - cw) / 2,\n\t\t\ty: (height - ch) / 2,\n\t\t\tw: cw,\n\t\t\th: ch,\n\t\t};\n\t}, [source.width, source.height, width, height]);\n\tconst margin = toPositiveNumber(\n\t\toptions?.margin,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.margin,\n\t\t0,\n\t);\n\tconst borderRadius = toPositiveNumber(\n\t\toptions?.borderRadius,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderRadius,\n\t\t0,\n\t);\n\tconst borderWidth = toPositiveNumber(\n\t\toptions?.borderWidth,\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.borderWidth,\n\t\t0,\n\t);\n\tconst maxThumbnailTiles = Math.max(\n\t\t1,\n\t\tMath.round(\n\t\t\ttoPositiveNumber(\n\t\t\t\toptions?.maxThumbnailTiles,\n\t\t\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.maxThumbnailTiles,\n\t\t\t\t1,\n\t\t\t),\n\t\t),\n\t);\n\n\tconst backgroundColor =\n\t\toptions?.backgroundColor || DEFAULT_OVERVIEW_MAP_OPTIONS.backgroundColor;\n\tconst borderColor =\n\t\toptions?.borderColor || DEFAULT_OVERVIEW_MAP_OPTIONS.borderColor;\n\tconst viewportBorderColor =\n\t\toptions?.viewportBorderColor ||\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderColor;\n\tconst viewportBorderStyle =\n\t\toptions?.viewportBorderStyle === \"stroke\" || options?.viewportBorderStyle === \"dash\"\n\t\t\t? options.viewportBorderStyle\n\t\t\t: DEFAULT_OVERVIEW_MAP_OPTIONS.viewportBorderStyle;\n\tconst viewportFillColor =\n\t\toptions?.viewportFillColor ??\n\t\tDEFAULT_OVERVIEW_MAP_OPTIONS.viewportFillColor;\n\tconst interactive =\n\t\toptions?.interactive ?? DEFAULT_OVERVIEW_MAP_OPTIONS.interactive;\n\tconst showThumbnail =\n\t\toptions?.showThumbnail ?? DEFAULT_OVERVIEW_MAP_OPTIONS.showThumbnail;\n\tconst position =\n\t\toptions?.position || DEFAULT_OVERVIEW_MAP_OPTIONS.position;\n\tconst onClose = options?.onClose;\n\tconst closeIcon = options?.closeIcon;\n\tconst closeButtonStyle = options?.closeButtonStyle;\n\n\tconst mergedStyle = useMemo<CSSProperties>(() => {\n\t\tconst pos: CSSProperties = {};\n\t\tif (position === \"top-left\" || position === \"bottom-left\") pos.left = margin;\n\t\telse pos.right = margin;\n\t\tif (position === \"top-left\" || position === \"top-right\") pos.top = margin;\n\t\telse pos.bottom = margin;\n\n\t\treturn {\n\t\t\tposition: \"absolute\",\n\t\t\t...pos,\n\t\t\twidth,\n\t\t\theight,\n\t\t\tborderRadius,\n\t\t\toverflow: \"hidden\",\n\t\t\tzIndex: 4,\n\t\t\tpointerEvents: interactive ? \"auto\" : \"none\",\n\t\t\ttouchAction: \"none\",\n\t\t\tboxShadow: \"0 10px 22px rgba(0, 0, 0, 0.3)\",\n\t\t\t...style,\n\t\t};\n\t}, [margin, position, width, height, borderRadius, interactive, style]);\n\n\tconst draw = useCallback(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) return;\n\n\t\tconst ctx = canvas.getContext(\"2d\");\n\t\tif (!ctx) return;\n\n\t\tconst cssW = width;\n\t\tconst cssH = height;\n\t\tconst dpr = Math.max(1, window.devicePixelRatio || 1);\n\n\t\tconst pixelW = Math.max(1, Math.round(cssW * dpr));\n\t\tconst pixelH = Math.max(1, Math.round(cssH * dpr));\n\t\tif (canvas.width !== pixelW || canvas.height !== pixelH) {\n\t\t\tcanvas.width = pixelW;\n\t\t\tcanvas.height = pixelH;\n\t\t}\n\n\t\tctx.setTransform(1, 0, 0, 1, 0, 0);\n\t\tctx.clearRect(0, 0, canvas.width, canvas.height);\n\t\tctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, cssW, cssH);\n\n\t\tconst { x: cx, y: cy, w: cw, h: ch } = contentRect;\n\n\t\tconst preview = thumbnailRef.current;\n\t\tif (preview) {\n\t\t\tctx.drawImage(preview, cx, cy, cw, ch);\n\t\t}\n\n\t\tctx.strokeStyle = borderColor;\n\t\tctx.lineWidth = borderWidth;\n\t\tctx.strokeRect(\n\t\t\tborderWidth * 0.5,\n\t\t\tborderWidth * 0.5,\n\t\t\tcssW - borderWidth,\n\t\t\tcssH - borderWidth,\n\t\t);\n\n\t\tconst projector = projectorRef.current;\n\t\tconst bounds = projector?.getViewBounds?.();\n\t\tconst corners = projector?.getViewCorners?.();\n\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t? bounds\n\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t? lastBoundsRef.current\n\t\t\t\t: null;\n\t\tif (!safeBounds) return;\n\t\tlastBoundsRef.current = safeBounds;\n\n\t\tconst sx = cw / Math.max(1, source.width);\n\t\tconst sy = ch / Math.max(1, source.height);\n\n\t\tconst safeCorners =\n\t\t\tArray.isArray(corners) &&\n\t\t\tcorners.length >= 4 &&\n\t\t\tcorners.every(\n\t\t\t\t(point) =>\n\t\t\t\t\tArray.isArray(point) &&\n\t\t\t\t\tpoint.length >= 2 &&\n\t\t\t\t\tNumber.isFinite(point[0]) &&\n\t\t\t\t\tNumber.isFinite(point[1]),\n\t\t\t)\n\t\t\t\t? (corners as Array<[number, number]>)\n\t\t\t\t: null;\n\n\t\tconst isDash = viewportBorderStyle === \"dash\";\n\n\t\tif (safeCorners) {\n\t\t\tconst screenCorners: Array<[number, number]> = safeCorners.map(\n\t\t\t\t(point) => [cx + point[0] * sx, cy + point[1] * sy],\n\t\t\t);\n\n\t\t\tctx.save();\n\t\t\tctx.beginPath();\n\t\t\tctx.rect(cx, cy, cw, ch);\n\t\t\tctx.clip();\n\n\t\t\tctx.beginPath();\n\t\t\tfor (let i = 0; i < screenCorners.length; i += 1) {\n\t\t\t\tif (i === 0) ctx.moveTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t\telse ctx.lineTo(screenCorners[i][0], screenCorners[i][1]);\n\t\t\t}\n\t\t\tctx.closePath();\n\t\t\tctx.fillStyle = viewportFillColor;\n\t\t\tctx.fill();\n\n\t\t\tctx.strokeStyle = viewportBorderColor;\n\t\t\tctx.lineWidth = 2.25;\n\t\t\tif (isDash) {\n\t\t\t\tstrokeSymmetricDashedPolygon(ctx, screenCorners, 4, 3);\n\t\t\t} else {\n\t\t\t\tctx.stroke();\n\t\t\t}\n\n\t\t\tctx.restore();\n\t\t\treturn;\n\t\t}\n\n\t\tconst left = clamp(cx + safeBounds[0] * sx, cx, cx + cw);\n\t\tconst top = clamp(cy + safeBounds[1] * sy, cy, cy + ch);\n\t\tconst right = clamp(cx + safeBounds[2] * sx, cx, cx + cw);\n\t\tconst bottom = clamp(cy + safeBounds[3] * sy, cy, cy + ch);\n\t\tconst rectW = Math.max(1, right - left);\n\t\tconst rectH = Math.max(1, bottom - top);\n\n\t\tctx.fillStyle = viewportFillColor;\n\t\tctx.fillRect(left, top, rectW, rectH);\n\n\t\tctx.strokeStyle = viewportBorderColor;\n\t\tctx.lineWidth = 2.25;\n\t\tif (isDash) {\n\t\t\tconst rectCorners: Array<[number, number]> = [\n\t\t\t\t[left + 0.5, top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5],\n\t\t\t\t[left + 0.5 + Math.max(1, rectW - 1), top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t\t[left + 0.5, top + 0.5 + Math.max(1, rectH - 1)],\n\t\t\t];\n\t\t\tstrokeSymmetricDashedPolygon(ctx, rectCorners, 4, 3);\n\t\t} else {\n\t\t\tctx.strokeRect(\n\t\t\t\tleft + 0.5,\n\t\t\t\ttop + 0.5,\n\t\t\t\tMath.max(1, rectW - 1),\n\t\t\t\tMath.max(1, rectH - 1),\n\t\t\t);\n\t\t}\n\t}, [\n\t\twidth,\n\t\theight,\n\t\tcontentRect,\n\t\tbackgroundColor,\n\t\tborderColor,\n\t\tborderWidth,\n\t\tprojectorRef,\n\t\tsource.width,\n\t\tsource.height,\n\t\tviewportFillColor,\n\t\tviewportBorderColor,\n\t\tviewportBorderStyle,\n\t]);\n\n\tconst requestDraw = useCallback(() => {\n\t\tif (drawPendingRef.current) return;\n\t\tdrawPendingRef.current = true;\n\t\trafRef.current = requestAnimationFrame(() => {\n\t\t\tdrawPendingRef.current = false;\n\t\t\trafRef.current = null;\n\t\t\tdraw();\n\t\t});\n\t}, [draw]);\n\n\tconst toWorldFromClient = useCallback(\n\t\t(clientX: number, clientY: number): [number, number] | null => {\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return null;\n\n\t\t\tconst rect = canvas.getBoundingClientRect();\n\t\t\tif (!rect.width || !rect.height) return null;\n\n\t\t\tconst scaleX = rect.width / width;\n\t\t\tconst scaleY = rect.height / height;\n\t\t\tconst cxPx = contentRect.x * scaleX;\n\t\t\tconst cyPx = contentRect.y * scaleY;\n\t\t\tconst cwPx = contentRect.w * scaleX;\n\t\t\tconst chPx = contentRect.h * scaleY;\n\n\t\t\tconst nx = clamp((clientX - rect.left - cxPx) / cwPx, 0, 1);\n\t\t\tconst ny = clamp((clientY - rect.top - cyPx) / chPx, 0, 1);\n\t\t\treturn [nx * source.width, ny * source.height];\n\t\t},\n\t\t[source.width, source.height, width, height, contentRect],\n\t);\n\n\tconst recenterTo = useCallback(\n\t\t(worldX: number, worldY: number) => {\n\t\t\tconst projector = projectorRef.current;\n\t\t\tif (!projector) return;\n\n\t\t\tif (projector.setViewCenter) {\n\t\t\t\tprojector.setViewCenter(worldX, worldY);\n\t\t\t\trequestDraw();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst bounds = projector.getViewBounds?.();\n\t\t\tconst safeBounds = isFiniteBounds(bounds)\n\t\t\t\t? bounds\n\t\t\t\t: isFiniteBounds(lastBoundsRef.current)\n\t\t\t\t\t? lastBoundsRef.current\n\t\t\t\t\t: null;\n\t\t\tif (!safeBounds) return;\n\n\t\t\tconst visibleW = Math.max(1e-6, safeBounds[2] - safeBounds[0]);\n\t\t\tconst visibleH = Math.max(1e-6, safeBounds[3] - safeBounds[1]);\n\n\t\t\tprojector.setViewState({\n\t\t\t\toffsetX: worldX - visibleW * 0.5,\n\t\t\t\toffsetY: worldY - visibleH * 0.5,\n\t\t\t});\n\t\t\trequestDraw();\n\t\t},\n\t\t[projectorRef, requestDraw],\n\t);\n\n\tconst handlePointerDown = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tif (!interactive) return;\n\t\t\tif (event.button !== 0) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (!canvas) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\n\t\t\tcanvas.setPointerCapture(event.pointerId);\n\t\t\tdraggingRef.current = { active: true, pointerId: event.pointerId };\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[interactive, toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerMove = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst world = toWorldFromClient(event.clientX, event.clientY);\n\t\t\tif (!world) return;\n\n\t\t\tevent.preventDefault();\n\t\t\tevent.stopPropagation();\n\t\t\trecenterTo(world[0], world[1]);\n\t\t},\n\t\t[toWorldFromClient, recenterTo],\n\t);\n\n\tconst handlePointerUp = useCallback(\n\t\t(event: ReactPointerEvent<HTMLCanvasElement>) => {\n\t\t\tconst drag = draggingRef.current;\n\t\t\tif (!drag.active || drag.pointerId !== event.pointerId) return;\n\n\t\t\tconst canvas = canvasRef.current;\n\t\t\tif (canvas && canvas.hasPointerCapture(event.pointerId)) {\n\t\t\t\ttry {\n\t\t\t\t\tcanvas.releasePointerCapture(event.pointerId);\n\t\t\t\t} catch {\n\t\t\t\t\t// noop\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\trequestDraw();\n\t\t},\n\t\t[requestDraw],\n\t);\n\n\tuseEffect(() => {\n\t\tlet cancelled = false;\n\t\tthumbnailRef.current = null;\n\t\trequestDraw();\n\n\t\tconst tier = 0;\n\t\tconst levelScale = 2 ** (source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(source.height / levelScale);\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / source.tileSize));\n\t\tconst tileCount = tilesX * tilesY;\n\n\t\tif (!showThumbnail || tileCount > maxThumbnailTiles) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tconst preview = document.createElement(\"canvas\");\n\t\tpreview.width = Math.max(1, Math.round(contentRect.w));\n\t\tpreview.height = Math.max(1, Math.round(contentRect.h));\n\t\tconst ctx = preview.getContext(\"2d\");\n\t\tif (!ctx) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tctx.fillStyle = backgroundColor;\n\t\tctx.fillRect(0, 0, preview.width, preview.height);\n\n\t\tconst requests: Array<{\n\t\t\turl: string;\n\t\t\tbounds: Bounds;\n\t\t}> = [];\n\n\t\tfor (let y = 0; y < tilesY; y += 1) {\n\t\t\tfor (let x = 0; x < tilesX; x += 1) {\n\t\t\t\tconst left = x * source.tileSize * levelScale;\n\t\t\t\tconst top = y * source.tileSize * levelScale;\n\t\t\t\tconst right =\n\t\t\t\t\tMath.min((x + 1) * source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom =\n\t\t\t\t\tMath.min((y + 1) * source.tileSize, levelHeight) * levelScale;\n\t\t\t\trequests.push({\n\t\t\t\t\turl: toTileUrl(source, tier, x, y),\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvoid Promise.allSettled(\n\t\t\trequests.map(async (tile) => {\n\t\t\t\tconst useAuthHeader = !!authToken;\n\t\t\t\tconst response = await fetch(tile.url, {\n\t\t\t\t\theaders: useAuthHeader ? { Authorization: authToken } : undefined,\n\t\t\t\t});\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\tconst bitmap = await createImageBitmap(await response.blob());\n\t\t\t\treturn { tile, bitmap };\n\t\t\t}),\n\t\t).then((results) => {\n\t\t\tif (cancelled) {\n\t\t\t\tfor (const result of results) {\n\t\t\t\t\tif (result.status === \"fulfilled\") {\n\t\t\t\t\t\tresult.value.bitmap.close();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst sx = preview.width / Math.max(1, source.width);\n\t\t\tconst sy = preview.height / Math.max(1, source.height);\n\t\t\tfor (const result of results) {\n\t\t\t\tif (result.status !== \"fulfilled\") continue;\n\t\t\t\tconst {\n\t\t\t\t\ttile: { bounds },\n\t\t\t\t\tbitmap,\n\t\t\t\t} = result.value;\n\t\t\t\tconst dx = bounds[0] * sx;\n\t\t\t\tconst dy = bounds[1] * sy;\n\t\t\t\tconst dw = Math.max(1, (bounds[2] - bounds[0]) * sx);\n\t\t\t\tconst dh = Math.max(1, (bounds[3] - bounds[1]) * sy);\n\t\t\t\tctx.drawImage(bitmap, dx, dy, dw, dh);\n\t\t\t\tbitmap.close();\n\t\t\t}\n\n\t\t\tthumbnailRef.current = preview;\n\t\t\trequestDraw();\n\t\t});\n\n\t\treturn () => {\n\t\t\tcancelled = true;\n\t\t};\n\t}, [\n\t\tsource,\n\t\tauthToken,\n\t\tcontentRect,\n\t\tbackgroundColor,\n\t\tshowThumbnail,\n\t\tmaxThumbnailTiles,\n\t\trequestDraw,\n\t]);\n\n\tuseEffect(() => {\n\t\trequestDraw();\n\t}, [requestDraw]);\n\n\tuseEffect(() => {\n\t\tif (!invalidateRef) return undefined;\n\t\tinvalidateRef.current = requestDraw;\n\t\treturn () => {\n\t\t\tif (invalidateRef.current === requestDraw) {\n\t\t\t\tinvalidateRef.current = null;\n\t\t\t}\n\t\t};\n\t}, [invalidateRef, requestDraw]);\n\n\tuseEffect(\n\t\t() => () => {\n\t\t\tdraggingRef.current = { active: false, pointerId: null };\n\t\t\tif (rafRef.current !== null) {\n\t\t\t\tcancelAnimationFrame(rafRef.current);\n\t\t\t\trafRef.current = null;\n\t\t\t}\n\t\t\tdrawPendingRef.current = false;\n\t\t},\n\t\t[],\n\t);\n\n\treturn (\n\t\t<div className={className} style={mergedStyle}>\n\t\t\t<canvas\n\t\t\t\tref={canvasRef}\n\t\t\t\tstyle={{\n\t\t\t\t\twidth: \"100%\",\n\t\t\t\t\theight: \"100%\",\n\t\t\t\t\tdisplay: \"block\",\n\t\t\t\t\tborderRadius: \"inherit\",\n\t\t\t\t}}\n\t\t\t\tonPointerDown={handlePointerDown}\n\t\t\t\tonPointerMove={handlePointerMove}\n\t\t\t\tonPointerUp={handlePointerUp}\n\t\t\t\tonPointerCancel={handlePointerUp}\n\t\t\t\tonContextMenu={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}}\n\t\t\t\tonWheel={(event) => {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}}\n\t\t\t/>\n\t\t\t{onClose && (\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\taria-label=\"Hide overview map\"\n\t\t\t\t\tonClick={(event) => {\n\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\tonClose();\n\t\t\t\t\t}}\n\t\t\t\t\tstyle={closeButtonStyle\n\t\t\t\t\t\t? {...closeButtonStyle as CSSProperties}\n\t\t\t\t\t\t: { ...DEFAULT_CLOSE_BUTTON_STYLE as CSSProperties }\n\t\t\t\t\t}\n\t\t\t\t>\n\t\t\t\t\t{closeIcon ?? \"×\"}\n\t\t\t\t</button>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","import { type CSSProperties, useEffect, useMemo, useRef } from \"react\";\nimport { M1TileRenderer } from \"../core/m1-tile-renderer\";\nimport type { ViewState } from \"../core/ortho-camera\";\nimport type { TileDefinition } from \"../core/types\";\n\nexport interface TileViewerCanvasProps {\n\timageWidth: number;\n\timageHeight: number;\n\ttiles: TileDefinition[];\n\tviewState?: Partial<ViewState>;\n\tclassName?: string;\n\tstyle?: CSSProperties;\n}\n\nexport function TileViewerCanvas({\n\timageWidth,\n\timageHeight,\n\ttiles,\n\tviewState,\n\tclassName,\n\tstyle,\n}: TileViewerCanvasProps): React.ReactElement {\n\tconst canvasRef = useRef<HTMLCanvasElement | null>(null);\n\tconst rendererRef = useRef<M1TileRenderer | null>(null);\n\tconst mergedStyle = useMemo(\n\t\t() => ({ width: \"100%\", height: \"100%\", display: \"block\", ...style }),\n\t\t[style],\n\t);\n\n\tuseEffect(() => {\n\t\tconst canvas = canvasRef.current;\n\t\tif (!canvas) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst renderer = new M1TileRenderer({\n\t\t\tcanvas,\n\t\t\timageWidth,\n\t\t\timageHeight,\n\t\t\tinitialViewState: viewState,\n\t\t});\n\n\t\trendererRef.current = renderer;\n\t\tvoid renderer.setTiles(tiles);\n\n\t\treturn () => {\n\t\t\trenderer.destroy();\n\t\t\trendererRef.current = null;\n\t\t};\n\t}, [imageWidth, imageHeight]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer) {\n\t\t\treturn;\n\t\t}\n\n\t\tvoid renderer.setTiles(tiles);\n\t}, [tiles]);\n\n\tuseEffect(() => {\n\t\tconst renderer = rendererRef.current;\n\t\tif (!renderer || !viewState) {\n\t\t\treturn;\n\t\t}\n\n\t\trenderer.setViewState(viewState);\n\t}, [viewState]);\n\n\treturn <canvas ref={canvasRef} className={className} style={mergedStyle} />;\n}\n","import { pointInAnyPreparedPolygon, prepareRoiPolygons, type RoiCoordinate, type RoiGeometry } from \"./roi-geometry\";\nimport type { WsiPointData } from \"./types\";\nimport { sanitizePointCount } from \"./utils\";\n\nexport type { RoiCoordinate };\nexport type RoiPolygon = RoiGeometry;\n\nexport function filterPointDataByPolygons(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): WsiPointData | null {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const prepared = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n const empty: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointData.fillModes instanceof Uint8Array) {\n empty.fillModes = new Uint8Array(0);\n }\n if (pointData.ids instanceof Uint32Array) {\n empty.ids = new Uint32Array(0);\n }\n return empty;\n }\n\n const count = sanitizePointCount(pointData);\n const positions = pointData.positions;\n const terms = pointData.paletteIndices;\n const fillModes = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= count ? pointData.fillModes : null;\n const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= count ? pointData.ids : null;\n\n const nextPositions = new Float32Array(count * 2);\n const nextTerms = new Uint16Array(count);\n const nextFillModes = fillModes ? new Uint8Array(count) : null;\n const nextIds = pointIds ? new Uint32Array(count) : null;\n let cursor = 0;\n\n for (let i = 0; i < count; i += 1) {\n const x = positions[i * 2];\n const y = positions[i * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = terms[i];\n if (nextFillModes) {\n nextFillModes[cursor] = fillModes![i];\n }\n if (nextIds) {\n nextIds[cursor] = pointIds![i];\n }\n cursor += 1;\n }\n\n const output: WsiPointData = {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n };\n if (nextFillModes) {\n output.fillModes = nextFillModes.subarray(0, cursor);\n }\n if (nextIds) {\n output.ids = nextIds.subarray(0, cursor);\n }\n return output;\n}\n\nexport function filterPointIndicesByPolygons(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Uint32Array {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return new Uint32Array(0);\n }\n\n const prepared = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n return new Uint32Array(0);\n }\n\n const count = sanitizePointCount(pointData);\n if (count === 0) {\n return new Uint32Array(0);\n }\n\n const positions = pointData.positions;\n const out = new Uint32Array(count);\n let cursor = 0;\n\n for (let i = 0; i < count; i += 1) {\n const x = positions[i * 2];\n const y = positions[i * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n out[cursor] = i;\n cursor += 1;\n }\n\n return out.subarray(0, cursor);\n}\n","export interface WebGpuCapabilities {\n\tsupported: boolean;\n\tadapterName?: string;\n\tfeatures: string[];\n\tlimits?: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n}\n\ninterface NavigatorGpuLike {\n\trequestAdapter: () => Promise<GpuAdapterLike | null>;\n}\n\ninterface GpuAdapterLike {\n\tinfo?: {\n\t\tdescription?: string;\n\t\tvendor?: string;\n\t};\n\tfeatures: Iterable<string>;\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t\tmaxComputeInvocationsPerWorkgroup: number;\n\t\tmaxComputeWorkgroupSizeX: number;\n\t};\n\trequestDevice: () => Promise<GpuDeviceLike>;\n}\n\ninterface GpuBufferLike {\n\tdestroy: () => void;\n\tmapAsync: (mode: number) => Promise<void>;\n\tgetMappedRange: () => ArrayBuffer;\n\tunmap: () => void;\n}\n\ninterface GpuComputePassLike {\n\tsetPipeline: (pipeline: GpuComputePipelineLike) => void;\n\tsetBindGroup: (index: number, bindGroup: unknown) => void;\n\tdispatchWorkgroups: (x: number, y?: number, z?: number) => void;\n\tend: () => void;\n}\n\ninterface GpuCommandEncoderLike {\n\tbeginComputePass: () => GpuComputePassLike;\n\tcopyBufferToBuffer: (\n\t\tsource: GpuBufferLike,\n\t\tsourceOffset: number,\n\t\tdestination: GpuBufferLike,\n\t\tdestinationOffset: number,\n\t\tsize: number,\n\t) => void;\n\tfinish: () => unknown;\n}\n\ninterface GpuQueueLike {\n\twriteBuffer: (\n\t\tbuffer: GpuBufferLike,\n\t\tbufferOffset: number,\n\t\tdata: ArrayBufferView | ArrayBufferLike,\n\t\tdataOffset?: number,\n\t\tsize?: number,\n\t) => void;\n\tsubmit: (commands: unknown[]) => void;\n}\n\ninterface GpuComputePipelineLike {\n\treadonly _brand?: \"GpuComputePipelineLike\";\n}\n\ninterface GpuBindGroupLayoutLike {\n\treadonly _brand?: \"GpuBindGroupLayoutLike\";\n}\n\ninterface GpuDeviceLike {\n\tlimits: {\n\t\tmaxStorageBufferBindingSize: number;\n\t};\n\tqueue: GpuQueueLike;\n\tcreateBindGroupLayout: (descriptor: unknown) => GpuBindGroupLayoutLike;\n\tcreatePipelineLayout: (descriptor: unknown) => unknown;\n\tcreateShaderModule: (descriptor: { code: string }) => unknown;\n\tcreateComputePipeline: (descriptor: unknown) => GpuComputePipelineLike;\n\tcreateBuffer: (descriptor: { size: number; usage: number }) => GpuBufferLike;\n\tcreateBindGroup: (descriptor: unknown) => unknown;\n\tcreateCommandEncoder: () => GpuCommandEncoderLike;\n}\n\ninterface WebGpuContext {\n\tdevice: GpuDeviceLike;\n\tpipeline: GpuComputePipelineLike;\n\tbindGroupLayout: GpuBindGroupLayoutLike;\n}\n\nlet contextPromise: Promise<WebGpuContext | null> | null = null;\n\nconst BBOX_PREFILTER_SHADER = `\nstruct Params {\n pointCount: u32,\n boundsCount: u32,\n _pad0: u32,\n _pad1: u32,\n};\n\n@group(0) @binding(0) var<storage, read> positions: array<vec2<f32>>;\n@group(0) @binding(1) var<storage, read> bounds: array<vec4<f32>>;\n@group(0) @binding(2) var<storage, read_write> outputMask: array<u32>;\n@group(0) @binding(3) var<uniform> params: Params;\n\n@compute @workgroup_size(256)\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\n let i = gid.x;\n if (i >= params.pointCount) {\n return;\n }\n\n let p = positions[i];\n var inside: u32 = 0u;\n for (var bi: u32 = 0u; bi < params.boundsCount; bi = bi + 1u) {\n let b = bounds[bi];\n if (p.x >= b.x && p.x <= b.z && p.y >= b.y && p.y <= b.w) {\n inside = 1u;\n break;\n }\n }\n outputMask[i] = inside;\n}\n`;\n\nfunction hasWebGpu(): boolean {\n\tif (typeof navigator === \"undefined\") return false;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\treturn typeof nav.gpu === \"object\" && nav.gpu !== null;\n}\n\nfunction getNavigatorGpu(): NavigatorGpuLike | null {\n\tif (!hasWebGpu()) return null;\n\tconst nav = navigator as Navigator & { gpu?: unknown };\n\tconst gpu = nav.gpu;\n\tif (!gpu || typeof gpu !== \"object\") return null;\n\tconst candidate = gpu as Partial<NavigatorGpuLike>;\n\tif (typeof candidate.requestAdapter !== \"function\") return null;\n\treturn candidate as NavigatorGpuLike;\n}\n\nconst GPU_SHADER_STAGE_COMPUTE =\n\t(globalThis as { GPUShaderStage?: { COMPUTE?: number } }).GPUShaderStage\n\t\t?.COMPUTE ?? 0x4;\nconst GPU_BUFFER_USAGE_STORAGE =\n\t(globalThis as { GPUBufferUsage?: { STORAGE?: number } }).GPUBufferUsage\n\t\t?.STORAGE ?? 0x80;\nconst GPU_BUFFER_USAGE_COPY_DST =\n\t(globalThis as { GPUBufferUsage?: { COPY_DST?: number } }).GPUBufferUsage\n\t\t?.COPY_DST ?? 0x08;\nconst GPU_BUFFER_USAGE_COPY_SRC =\n\t(globalThis as { GPUBufferUsage?: { COPY_SRC?: number } }).GPUBufferUsage\n\t\t?.COPY_SRC ?? 0x04;\nconst GPU_BUFFER_USAGE_UNIFORM =\n\t(globalThis as { GPUBufferUsage?: { UNIFORM?: number } }).GPUBufferUsage\n\t\t?.UNIFORM ?? 0x40;\nconst GPU_BUFFER_USAGE_MAP_READ =\n\t(globalThis as { GPUBufferUsage?: { MAP_READ?: number } }).GPUBufferUsage\n\t\t?.MAP_READ ?? 0x01;\nconst GPU_MAP_MODE_READ =\n\t(globalThis as { GPUMapMode?: { READ?: number } }).GPUMapMode?.READ ?? 0x01;\n\nexport async function getWebGpuCapabilities(): Promise<WebGpuCapabilities> {\n\tconst navGpu = getNavigatorGpu();\n\tif (!navGpu) {\n\t\treturn { supported: false, features: [] };\n\t}\n\tconst adapter = await navGpu.requestAdapter();\n\tif (!adapter) {\n\t\treturn { supported: false, features: [] };\n\t}\n\n\treturn {\n\t\tsupported: true,\n\t\tadapterName: adapter.info?.description ?? adapter.info?.vendor ?? \"unknown\",\n\t\tfeatures: Array.from(adapter.features),\n\t\tlimits: {\n\t\t\tmaxStorageBufferBindingSize: Number(\n\t\t\t\tadapter.limits.maxStorageBufferBindingSize,\n\t\t\t),\n\t\t\tmaxComputeInvocationsPerWorkgroup: Number(\n\t\t\t\tadapter.limits.maxComputeInvocationsPerWorkgroup,\n\t\t\t),\n\t\t\tmaxComputeWorkgroupSizeX: Number(adapter.limits.maxComputeWorkgroupSizeX),\n\t\t},\n\t};\n}\n\nasync function getContext(): Promise<WebGpuContext | null> {\n\tif (contextPromise) return contextPromise;\n\tcontextPromise = (async () => {\n\t\tconst navGpu = getNavigatorGpu();\n\t\tif (!navGpu) return null;\n\t\tconst adapter = await navGpu.requestAdapter();\n\t\tif (!adapter) return null;\n\t\tconst device = await adapter.requestDevice();\n\n\t\tconst bindGroupLayout = device.createBindGroupLayout({\n\t\t\tentries: [\n\t\t\t\t{\n\t\t\t\t\tbinding: 0,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 1,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"read-only-storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 2,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"storage\" },\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tbinding: 3,\n\t\t\t\t\tvisibility: GPU_SHADER_STAGE_COMPUTE,\n\t\t\t\t\tbuffer: { type: \"uniform\" },\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tconst pipeline = device.createComputePipeline({\n\t\t\tlayout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }),\n\t\t\tcompute: {\n\t\t\t\tmodule: device.createShaderModule({ code: BBOX_PREFILTER_SHADER }),\n\t\t\t\tentryPoint: \"main\",\n\t\t\t},\n\t\t});\n\n\t\treturn { device, pipeline, bindGroupLayout };\n\t})();\n\n\treturn contextPromise;\n}\n\nfunction align(value: number, step: number): number {\n\treturn Math.ceil(value / step) * step;\n}\n\nexport async function prefilterPointsByBoundsWebGpu(\n\tpositions: Float32Array,\n\tpointCount: number,\n\tbounds: Float32Array,\n): Promise<Uint32Array | null> {\n\tconst ctx = await getContext();\n\tif (!ctx) return null;\n\n\tconst count = Math.max(0, Math.floor(pointCount));\n\tconst boundsCount = Math.max(0, Math.floor(bounds.length / 4));\n\tif (count === 0 || boundsCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst safePointCount = Math.min(count, Math.floor(positions.length / 2));\n\tif (safePointCount === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst positionBytes = safePointCount * 2 * Float32Array.BYTES_PER_ELEMENT;\n\tconst boundsBytes = boundsCount * 4 * Float32Array.BYTES_PER_ELEMENT;\n\tconst outputBytes = safePointCount * Uint32Array.BYTES_PER_ELEMENT;\n\n\tconst limit = Number(ctx.device.limits.maxStorageBufferBindingSize);\n\tif (positionBytes > limit || boundsBytes > limit || outputBytes > limit) {\n\t\treturn null;\n\t}\n\n\tconst positionsBuffer = ctx.device.createBuffer({\n\t\tsize: align(positionBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst boundsBuffer = ctx.device.createBuffer({\n\t\tsize: align(boundsBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst outputBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_STORAGE | GPU_BUFFER_USAGE_COPY_SRC,\n\t});\n\tconst uniformBuffer = ctx.device.createBuffer({\n\t\tsize: 16,\n\t\tusage: GPU_BUFFER_USAGE_UNIFORM | GPU_BUFFER_USAGE_COPY_DST,\n\t});\n\tconst readBuffer = ctx.device.createBuffer({\n\t\tsize: align(outputBytes, 4),\n\t\tusage: GPU_BUFFER_USAGE_COPY_DST | GPU_BUFFER_USAGE_MAP_READ,\n\t});\n\n\tctx.device.queue.writeBuffer(\n\t\tpositionsBuffer,\n\t\t0,\n\t\tpositions.buffer,\n\t\tpositions.byteOffset,\n\t\tpositionBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tboundsBuffer,\n\t\t0,\n\t\tbounds.buffer,\n\t\tbounds.byteOffset,\n\t\tboundsBytes,\n\t);\n\tctx.device.queue.writeBuffer(\n\t\tuniformBuffer,\n\t\t0,\n\t\tnew Uint32Array([safePointCount, boundsCount, 0, 0]),\n\t);\n\n\tconst bindGroup = ctx.device.createBindGroup({\n\t\tlayout: ctx.bindGroupLayout,\n\t\tentries: [\n\t\t\t{ binding: 0, resource: { buffer: positionsBuffer } },\n\t\t\t{ binding: 1, resource: { buffer: boundsBuffer } },\n\t\t\t{ binding: 2, resource: { buffer: outputBuffer } },\n\t\t\t{ binding: 3, resource: { buffer: uniformBuffer } },\n\t\t],\n\t});\n\n\tconst commandEncoder = ctx.device.createCommandEncoder();\n\tconst pass = commandEncoder.beginComputePass();\n\tpass.setPipeline(ctx.pipeline);\n\tpass.setBindGroup(0, bindGroup);\n\tpass.dispatchWorkgroups(Math.ceil(safePointCount / 256));\n\tpass.end();\n\n\tcommandEncoder.copyBufferToBuffer(outputBuffer, 0, readBuffer, 0, outputBytes);\n\tctx.device.queue.submit([commandEncoder.finish()]);\n\n\tawait readBuffer.mapAsync(GPU_MAP_MODE_READ);\n\tconst mapped = readBuffer.getMappedRange();\n\tconst out = new Uint32Array(mapped.slice(0));\n\treadBuffer.unmap();\n\n\tpositionsBuffer.destroy();\n\tboundsBuffer.destroy();\n\toutputBuffer.destroy();\n\tuniformBuffer.destroy();\n\treadBuffer.destroy();\n\n\treturn out;\n}\n","import { filterPointDataByPolygons, type RoiPolygon } from \"./point-clip\";\nimport {\n pointInAnyPreparedPolygon,\n prepareRoiPolygons,\n} from \"./roi-geometry\";\nimport type { WsiPointData } from \"./types\";\nimport { nowMs, sanitizePointCount } from \"./utils\";\nimport { prefilterPointsByBoundsWebGpu } from \"./webgpu\";\n\nexport interface HybridPointClipOptions {\n bridgeToDraw?: boolean;\n}\n\nexport interface HybridPointClipResult {\n data: WsiPointData | null;\n meta: {\n mode: \"hybrid-webgpu\";\n durationMs: number;\n usedWebGpu: boolean;\n candidateCount: number;\n bridgedToDraw?: boolean;\n };\n}\n\nexport async function filterPointDataByPolygonsHybrid(\n pointData: WsiPointData | null | undefined,\n polygons: RoiPolygon[] | null | undefined,\n options: HybridPointClipOptions = {}\n): Promise<HybridPointClipResult> {\n const start = nowMs();\n const bridgeToDraw = options.bridgeToDraw === true;\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const prepared = prepareRoiPolygons(polygons ?? []);\n if (prepared.length === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointData.fillModes instanceof Uint8Array) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointData.ids instanceof Uint32Array) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const safeCount = sanitizePointCount(pointData);\n const pointFillModes = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes : null;\n const pointIds = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids : null;\n if (safeCount === 0) {\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n const bboxFlat = new Float32Array(prepared.length * 4);\n for (let i = 0; i < prepared.length; i += 1) {\n const base = i * 4;\n const polygon = prepared[i];\n bboxFlat[base] = polygon.minX;\n bboxFlat[base + 1] = polygon.minY;\n bboxFlat[base + 2] = polygon.maxX;\n bboxFlat[base + 3] = polygon.maxY;\n }\n\n let candidateMask: Uint32Array | null = null;\n let usedWebGpu = false;\n try {\n candidateMask = await prefilterPointsByBoundsWebGpu(pointData.positions, safeCount, bboxFlat);\n usedWebGpu = !!candidateMask;\n } catch {\n candidateMask = null;\n usedWebGpu = false;\n }\n\n if (!candidateMask) {\n const fallback = filterPointDataByPolygons(pointData, polygons);\n return {\n data: fallback,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: false,\n candidateCount: safeCount,\n bridgedToDraw: false,\n },\n };\n }\n\n let candidateCount = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] === 1) candidateCount += 1;\n }\n\n const candidateIndices = new Uint32Array(candidateCount);\n if (candidateCount > 0) {\n let candidateCursor = 0;\n for (let i = 0; i < safeCount; i += 1) {\n if (candidateMask[i] !== 1) continue;\n candidateIndices[candidateCursor] = i;\n candidateCursor += 1;\n }\n }\n\n if (candidateCount === 0) {\n if (bridgeToDraw) {\n const data: WsiPointData = {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: new Uint32Array(0),\n };\n if (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\n }\n if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: true,\n },\n };\n }\n\n const data: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n };\n if (pointFillModes) {\n data.fillModes = new Uint8Array(0);\n }\n if (pointIds) {\n data.ids = new Uint32Array(0);\n }\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount: 0,\n bridgedToDraw: false,\n },\n };\n }\n\n if (bridgeToDraw) {\n const drawIndices = new Uint32Array(candidateCount);\n let visibleCount = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n drawIndices[visibleCount] = pointIndex;\n visibleCount += 1;\n }\n\n const data: WsiPointData = {\n count: safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n paletteIndices: pointData.paletteIndices.subarray(0, safeCount),\n drawIndices: drawIndices.subarray(0, visibleCount),\n };\n if (pointFillModes) {\n data.fillModes = pointFillModes.subarray(0, safeCount);\n }\n if (pointIds) {\n data.ids = pointIds.subarray(0, safeCount);\n }\n\n return {\n data,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: true,\n },\n };\n }\n\n const nextPositions = new Float32Array(candidateCount * 2);\n const nextTerms = new Uint16Array(candidateCount);\n const nextFillModes = pointFillModes ? new Uint8Array(candidateCount) : null;\n const nextIds = pointIds ? new Uint32Array(candidateCount) : null;\n let cursor = 0;\n\n for (let i = 0; i < candidateCount; i += 1) {\n const pointIndex = candidateIndices[i] ?? 0;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n if (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n nextPositions[cursor * 2] = x;\n nextPositions[cursor * 2 + 1] = y;\n nextTerms[cursor] = pointData.paletteIndices[pointIndex];\n if (nextFillModes) {\n nextFillModes[cursor] = pointFillModes![pointIndex];\n }\n if (nextIds) {\n nextIds[cursor] = pointIds![pointIndex];\n }\n cursor += 1;\n }\n\n const compactData: WsiPointData = {\n count: cursor,\n positions: nextPositions.subarray(0, cursor * 2),\n paletteIndices: nextTerms.subarray(0, cursor),\n };\n if (nextFillModes) {\n compactData.fillModes = nextFillModes.subarray(0, cursor);\n }\n if (nextIds) {\n compactData.ids = nextIds.subarray(0, cursor);\n }\n\n return {\n data: compactData,\n meta: {\n mode: \"hybrid-webgpu\",\n durationMs: nowMs() - start,\n usedWebGpu: true,\n candidateCount,\n bridgedToDraw: false,\n },\n };\n}\n","export interface WorkerClientHandlers<Res extends { id: number }, Pending> {\n onResponse: (message: Res, pending: Pending) => void;\n rejectPending: (pending: Pending, error: Error) => void;\n}\n\nexport class WorkerClient<Res extends { id: number }, Pending> {\n private worker: Worker | null = null;\n private supported = true;\n private requestId = 1;\n private readonly pendingById = new Map<number, Pending>();\n\n private readonly handleMessage = (event: MessageEvent<Res>): void => {\n const message = event.data;\n if (!message) return;\n const pending = this.pendingById.get(message.id);\n if (!pending) return;\n this.pendingById.delete(message.id);\n this.handlers.onResponse(message, pending);\n };\n\n private readonly handleError = (): void => {\n this.supported = false;\n this.teardownWorker(\"worker crashed\");\n };\n\n constructor(\n private readonly createWorker: () => Worker,\n private readonly handlers: WorkerClientHandlers<Res, Pending>,\n ) {}\n\n beginRequest(pending: Pending): { id: number; worker: Worker } | null {\n const worker = this.getOrCreateWorker();\n if (!worker) return null;\n const id = this.requestId++;\n this.pendingById.set(id, pending);\n return { id, worker };\n }\n\n cancelRequest(id: number): Pending | undefined {\n const pending = this.pendingById.get(id);\n if (!pending) return undefined;\n this.pendingById.delete(id);\n return pending;\n }\n\n terminate(reason = \"worker terminated\"): void {\n this.teardownWorker(reason);\n }\n\n private getOrCreateWorker(): Worker | null {\n if (!this.supported) return null;\n if (this.worker) return this.worker;\n\n try {\n const worker = this.createWorker();\n worker.addEventListener(\"message\", this.handleMessage);\n worker.addEventListener(\"error\", this.handleError);\n this.worker = worker;\n return worker;\n } catch {\n this.supported = false;\n return null;\n }\n }\n\n private teardownWorker(reason: string): void {\n if (this.worker) {\n this.worker.removeEventListener(\"message\", this.handleMessage);\n this.worker.removeEventListener(\"error\", this.handleError);\n this.worker.terminate();\n this.worker = null;\n }\n\n const error = new Error(reason);\n for (const [, pending] of this.pendingById) {\n this.handlers.rejectPending(pending, error);\n }\n this.pendingById.clear();\n }\n}\n","import { filterPointDataByPolygons, filterPointIndicesByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { RoiClipWorkerRequest, RoiClipWorkerResponse } from \"./point-clip-worker-protocol\";\nimport type { WsiPointData } from \"./types\";\nimport { nowMs, sanitizePointCount } from \"./utils\";\nimport { WorkerClient } from \"./worker-client\";\n\nexport type PointClipMode = \"sync\" | \"worker\" | \"hybrid-webgpu\";\n\nexport interface PointClipResultMeta {\n mode: PointClipMode;\n durationMs: number;\n}\n\nexport interface PointClipResult {\n data: WsiPointData | null;\n meta: PointClipResultMeta;\n}\n\nexport interface PointClipIndexResult {\n indices: Uint32Array;\n meta: PointClipResultMeta;\n}\n\ninterface PendingDataWorkerRequest {\n kind: \"data\";\n resolve: (result: PointClipResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\ninterface PendingIndexWorkerRequest {\n kind: \"index\";\n resolve: (result: PointClipIndexResult) => void;\n reject: (reason?: unknown) => void;\n startMs: number;\n}\n\ntype PendingWorkerRequest = PendingDataWorkerRequest | PendingIndexWorkerRequest;\n\nconst workerClient = new WorkerClient<RoiClipWorkerResponse, PendingWorkerRequest>(\n () => new Worker(new URL(\"../workers/roi-clip-worker.ts\", import.meta.url), { type: \"module\" }),\n {\n onResponse: (msg, pending) => {\n if (msg.type === \"roi-clip-failure\") {\n pending.reject(new Error(msg.error || \"worker clip failed\"));\n return;\n }\n\n if (msg.type === \"roi-clip-index-success\") {\n if (pending.kind !== \"index\") {\n pending.reject(new Error(\"worker response mismatch: expected point data result\"));\n return;\n }\n const count = Math.max(0, Math.floor(msg.count));\n const indices = new Uint32Array(msg.indices).subarray(0, count);\n pending.resolve({\n indices,\n meta: {\n mode: \"worker\",\n durationMs:\n Number.isFinite(msg.durationMs)\n ? msg.durationMs\n : nowMs() - pending.startMs,\n },\n });\n return;\n }\n\n if (pending.kind !== \"data\") {\n pending.reject(new Error(\"worker response mismatch: expected index result\"));\n return;\n }\n\n const count = Math.max(0, Math.floor(msg.count));\n const positions = new Float32Array(msg.positions);\n const paletteIndices = new Uint16Array(msg.paletteIndices);\n const fillModes = msg.fillModes ? new Uint8Array(msg.fillModes) : null;\n const ids = msg.ids ? new Uint32Array(msg.ids) : null;\n const output: WsiPointData = {\n count,\n positions: positions.subarray(0, count * 2),\n paletteIndices: paletteIndices.subarray(0, count),\n };\n if (fillModes) {\n output.fillModes = fillModes.subarray(0, count);\n }\n if (ids) {\n output.ids = ids.subarray(0, count);\n }\n\n pending.resolve({\n data: output,\n meta: {\n mode: \"worker\",\n durationMs:\n Number.isFinite(msg.durationMs)\n ? msg.durationMs\n : nowMs() - pending.startMs,\n },\n });\n },\n rejectPending: (pending, error) => {\n pending.reject(error);\n },\n },\n);\n\nexport function terminateRoiClipWorker(): void {\n workerClient.terminate(\"worker terminated\");\n}\n\nexport async function filterPointDataByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n data: null,\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const safeCount = sanitizePointCount(pointData);\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const termsCopy = pointData.paletteIndices.slice(0, safeCount);\n const fillModesCopy = pointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= safeCount ? pointData.fillModes.slice(0, safeCount) : null;\n const idsCopy = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.slice(0, safeCount) : null;\n\n return new Promise<PointClipResult>((resolve, reject) => {\n const startMs = nowMs();\n const requestTicket = workerClient.beginRequest({\n kind: \"data\",\n resolve,\n reject,\n startMs,\n });\n\n if (!requestTicket) {\n resolve({\n data: filterPointDataByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - startMs },\n });\n return;\n }\n\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-request\",\n id: requestTicket.id,\n count: safeCount,\n positions: positionsCopy.buffer,\n paletteIndices: termsCopy.buffer,\n fillModes: fillModesCopy?.buffer,\n ids: idsCopy?.buffer,\n polygons: polygons ?? [],\n };\n\n const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (fillModesCopy) transfer.push(fillModesCopy.buffer);\n if (idsCopy) transfer.push(idsCopy.buffer);\n\n try {\n requestTicket.worker.postMessage(msg, transfer);\n } catch (error) {\n const canceled = workerClient.cancelRequest(requestTicket.id);\n if (canceled) {\n canceled.reject(error);\n } else {\n reject(error);\n }\n }\n });\n}\n\nexport async function filterPointIndicesByPolygonsInWorker(pointData: WsiPointData | null | undefined, polygons: RoiPolygon[] | null | undefined): Promise<PointClipIndexResult> {\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n return {\n indices: new Uint32Array(0),\n meta: { mode: \"worker\", durationMs: 0 },\n };\n }\n\n const safeCount = sanitizePointCount(pointData);\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n\n return new Promise<PointClipIndexResult>((resolve, reject) => {\n const startMs = nowMs();\n const requestTicket = workerClient.beginRequest({\n kind: \"index\",\n resolve,\n reject,\n startMs,\n });\n\n if (!requestTicket) {\n resolve({\n indices: filterPointIndicesByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - startMs },\n });\n return;\n }\n\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-index-request\",\n id: requestTicket.id,\n count: safeCount,\n positions: positionsCopy.buffer,\n polygons: polygons ?? [],\n };\n\n try {\n requestTicket.worker.postMessage(msg, [positionsCopy.buffer]);\n } catch (error) {\n const canceled = workerClient.cancelRequest(requestTicket.id);\n if (canceled) {\n canceled.reject(error);\n } else {\n reject(error);\n }\n }\n });\n}\n","export const MIN_POINT_HIT_GRID_SIZE = 24;\nexport const MAX_POINT_HIT_GRID_SIZE = 1024;\nexport const POINT_HIT_GRID_DENSITY_SCALE = 4;\nexport const HASH_EMPTY = -1;\n\nexport interface PointHitIndexBuildInput {\n count: number;\n positions: Float32Array;\n drawIndices?: Uint32Array | null;\n sourceWidth: number;\n sourceHeight: number;\n}\n\nexport interface PointHitIndexBuildResult {\n cellSize: number;\n safeCount: number;\n cellCount: number;\n hashCapacity: number;\n hashTable: Int32Array;\n cellKeys: Int32Array;\n cellOffsets: Uint32Array;\n cellLengths: Uint32Array;\n pointIndices: Uint32Array;\n}\n\nexport function cellHash(cellX: number, cellY: number, mask: number): number {\n return (((cellX * 73856093) ^ (cellY * 19349663)) >>> 0) & mask;\n}\n\nfunction resolveGridSize(sourceWidth: number, sourceHeight: number, visibleCount: number): number {\n if (sourceWidth <= 0 || sourceHeight <= 0 || visibleCount <= 0) return 256;\n const area = Math.max(1, sourceWidth * sourceHeight);\n const avgSpacing = Math.sqrt(area / Math.max(1, visibleCount));\n const raw = avgSpacing * POINT_HIT_GRID_DENSITY_SCALE;\n return Math.max(MIN_POINT_HIT_GRID_SIZE, Math.min(MAX_POINT_HIT_GRID_SIZE, raw));\n}\n\nfunction sanitizeDrawIndices(raw: Uint32Array | null | undefined, safeCount: number): Uint32Array | null {\n if (!(raw instanceof Uint32Array) || raw.length === 0) {\n return null;\n }\n\n let allValid = true;\n for (let i = 0; i < raw.length; i += 1) {\n if (raw[i] < safeCount) continue;\n allValid = false;\n break;\n }\n if (allValid) {\n return raw;\n }\n\n const filtered = new Uint32Array(raw.length);\n let cursor = 0;\n for (let i = 0; i < raw.length; i += 1) {\n if (raw[i] >= safeCount) continue;\n filtered[cursor] = raw[i];\n cursor += 1;\n }\n return cursor > 0 ? filtered.subarray(0, cursor) : null;\n}\n\nexport function buildPointHitIndex(input: PointHitIndexBuildInput): PointHitIndexBuildResult | null {\n const count = Math.max(0, Math.floor(input.count));\n const maxCountByPositions = Math.floor(input.positions.length / 2);\n const safeCount = Math.max(0, Math.min(count, maxCountByPositions));\n if (safeCount <= 0) {\n return null;\n }\n\n const drawIndices = sanitizeDrawIndices(input.drawIndices ?? null, safeCount);\n const visibleCount = drawIndices ? drawIndices.length : safeCount;\n if (visibleCount === 0) {\n return null;\n }\n\n const cellSize = resolveGridSize(input.sourceWidth, input.sourceHeight, visibleCount);\n const invCellSize = 1.0 / cellSize;\n\n const pointCellX = new Int32Array(visibleCount);\n const pointCellY = new Int32Array(visibleCount);\n let validCount = 0;\n\n if (drawIndices) {\n for (let i = 0; i < visibleCount; i += 1) {\n const pi = drawIndices[i];\n const px = input.positions[pi * 2];\n const py = input.positions[pi * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n pointCellX[validCount] = Math.floor(px * invCellSize);\n pointCellY[validCount] = Math.floor(py * invCellSize);\n validCount += 1;\n }\n } else {\n for (let i = 0; i < safeCount; i += 1) {\n const px = input.positions[i * 2];\n const py = input.positions[i * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n pointCellX[validCount] = Math.floor(px * invCellSize);\n pointCellY[validCount] = Math.floor(py * invCellSize);\n validCount += 1;\n }\n }\n\n if (validCount === 0) {\n return null;\n }\n\n let estimatedCells = Math.min(validCount, Math.max(64, validCount >>> 3));\n if (!Number.isFinite(estimatedCells) || estimatedCells <= 0) {\n estimatedCells = validCount;\n }\n\n let hashCapacity = 1;\n while (hashCapacity < estimatedCells * 2) hashCapacity <<= 1;\n let hashMask = hashCapacity - 1;\n\n let tempHashKeys = new Int32Array(hashCapacity * 2);\n let tempHashCounts = new Int32Array(hashCapacity);\n tempHashKeys.fill(0x7fffffff);\n let cellCount = 0;\n\n const pointCellSlot = new Int32Array(validCount);\n\n for (let i = 0; i < validCount; i += 1) {\n const cx = pointCellX[i];\n const cy = pointCellY[i];\n let slot = cellHash(cx, cy, hashMask);\n\n while (true) {\n const kx = tempHashKeys[slot * 2];\n if (kx === 0x7fffffff) {\n tempHashKeys[slot * 2] = cx;\n tempHashKeys[slot * 2 + 1] = cy;\n tempHashCounts[slot] = 1;\n pointCellSlot[i] = slot;\n cellCount += 1;\n\n if (cellCount * 4 > hashCapacity * 3) {\n const oldCap = hashCapacity;\n hashCapacity <<= 1;\n hashMask = hashCapacity - 1;\n\n const newKeys = new Int32Array(hashCapacity * 2);\n const newCounts = new Int32Array(hashCapacity);\n newKeys.fill(0x7fffffff);\n\n for (let s = 0; s < oldCap; s += 1) {\n if (tempHashKeys[s * 2] === 0x7fffffff) continue;\n const ocx = tempHashKeys[s * 2];\n const ocy = tempHashKeys[s * 2 + 1];\n let ns = cellHash(ocx, ocy, hashMask);\n while (newKeys[ns * 2] !== 0x7fffffff) ns = (ns + 1) & hashMask;\n newKeys[ns * 2] = ocx;\n newKeys[ns * 2 + 1] = ocy;\n newCounts[ns] = tempHashCounts[s];\n }\n\n tempHashKeys = newKeys;\n tempHashCounts = newCounts;\n\n slot = cellHash(cx, cy, hashMask);\n while (\n tempHashKeys[slot * 2] !== cx ||\n tempHashKeys[slot * 2 + 1] !== cy\n ) {\n slot = (slot + 1) & hashMask;\n }\n pointCellSlot[i] = slot;\n }\n break;\n }\n\n if (kx === cx && tempHashKeys[slot * 2 + 1] === cy) {\n tempHashCounts[slot] += 1;\n pointCellSlot[i] = slot;\n break;\n }\n\n slot = (slot + 1) & hashMask;\n }\n }\n\n const cellKeys = new Int32Array(cellCount * 2);\n const cellOffsets = new Uint32Array(cellCount);\n const cellLengths = new Uint32Array(cellCount);\n const slotToCellIndex = new Int32Array(hashCapacity);\n slotToCellIndex.fill(HASH_EMPTY);\n\n let cellIdx = 0;\n let offset = 0;\n for (let s = 0; s < hashCapacity; s += 1) {\n if (tempHashKeys[s * 2] === 0x7fffffff) continue;\n cellKeys[cellIdx * 2] = tempHashKeys[s * 2];\n cellKeys[cellIdx * 2 + 1] = tempHashKeys[s * 2 + 1];\n cellOffsets[cellIdx] = offset;\n cellLengths[cellIdx] = tempHashCounts[s];\n slotToCellIndex[s] = cellIdx;\n offset += tempHashCounts[s];\n cellIdx += 1;\n }\n\n const pointIndices = new Uint32Array(validCount);\n const fillCursor = new Uint32Array(cellCount);\n fillCursor.set(cellOffsets);\n\n if (drawIndices) {\n for (let i = 0; i < validCount; i += 1) {\n const ci = slotToCellIndex[pointCellSlot[i]];\n pointIndices[fillCursor[ci]] = drawIndices[i];\n fillCursor[ci] += 1;\n }\n } else {\n let srcIdx = 0;\n for (let i = 0; i < safeCount; i += 1) {\n const px = input.positions[i * 2];\n const py = input.positions[i * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) continue;\n const ci = slotToCellIndex[pointCellSlot[srcIdx]];\n pointIndices[fillCursor[ci]] = i;\n fillCursor[ci] += 1;\n srcIdx += 1;\n }\n }\n\n let finalCap = 1;\n while (finalCap < cellCount * 2) finalCap <<= 1;\n const finalMask = finalCap - 1;\n const hashTable = new Int32Array(finalCap);\n hashTable.fill(HASH_EMPTY);\n\n for (let i = 0; i < cellCount; i += 1) {\n const cx = cellKeys[i * 2];\n const cy = cellKeys[i * 2 + 1];\n let slot = cellHash(cx, cy, finalMask);\n while (hashTable[slot] !== HASH_EMPTY) slot = (slot + 1) & finalMask;\n hashTable[slot] = i;\n }\n\n return {\n cellSize,\n safeCount,\n cellCount,\n hashCapacity: finalCap,\n hashTable,\n cellKeys,\n cellOffsets,\n cellLengths,\n pointIndices,\n };\n}\n","import { HASH_EMPTY, buildPointHitIndex, cellHash } from \"./point-hit-index-shared\";\nimport type {\n PointHitIndexWorkerRequest,\n PointHitIndexWorkerResponse,\n PointHitIndexWorkerSuccess,\n} from \"./point-hit-index-worker-protocol\";\nimport type { WsiImageSource, WsiPointData } from \"./types\";\nimport { sanitizePointCount } from \"./utils\";\nimport { WorkerClient } from \"./worker-client\";\n\nexport interface FlatPointSpatialIndex {\n cellSize: number;\n safeCount: number;\n positions: Float32Array;\n ids: Uint32Array | null;\n hashCapacity: number;\n hashMask: number;\n hashTable: Int32Array;\n cellKeys: Int32Array;\n cellOffsets: Uint32Array;\n cellLengths: Uint32Array;\n pointIndices: Uint32Array;\n}\n\nexport function lookupCellIndex(\n index: FlatPointSpatialIndex,\n cellX: number,\n cellY: number,\n): number {\n const { hashTable, cellKeys, hashMask } = index;\n let slot = cellHash(cellX, cellY, hashMask);\n while (true) {\n const ci = hashTable[slot];\n if (ci === HASH_EMPTY) return -1;\n if (cellKeys[ci * 2] === cellX && cellKeys[ci * 2 + 1] === cellY) return ci;\n slot = (slot + 1) & hashMask;\n }\n}\n\ninterface PendingRequest {\n resolve: (result: FlatPointSpatialIndex | null) => void;\n reject: (reason?: unknown) => void;\n pointData: WsiPointData;\n}\n\nfunction buildFromResponse(msg: PointHitIndexWorkerSuccess, pointData: WsiPointData): FlatPointSpatialIndex | null {\n if (msg.safeCount <= 0 || msg.cellCount <= 0) return null;\n\n const safeCount = msg.safeCount;\n return {\n cellSize: msg.cellSize,\n safeCount,\n positions: pointData.positions.subarray(0, safeCount * 2),\n ids:\n pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount\n ? pointData.ids.subarray(0, safeCount)\n : null,\n hashCapacity: msg.hashCapacity,\n hashMask: msg.hashCapacity - 1,\n hashTable: new Int32Array(msg.hashTable),\n cellKeys: new Int32Array(msg.cellKeys),\n cellOffsets: new Uint32Array(msg.cellOffsets),\n cellLengths: new Uint32Array(msg.cellLengths),\n pointIndices: new Uint32Array(msg.pointIndices),\n };\n}\n\nconst workerClient = new WorkerClient<PointHitIndexWorkerResponse, PendingRequest>(\n () =>\n new Worker(new URL(\"../workers/point-hit-index-worker.ts\", import.meta.url), {\n type: \"module\",\n }),\n {\n onResponse: (message, pending) => {\n if (message.type === \"point-hit-index-failure\") {\n pending.reject(new Error(message.error || \"worker index build failed\"));\n return;\n }\n pending.resolve(buildFromResponse(message, pending.pointData));\n },\n rejectPending: (pending, error) => {\n pending.reject(error);\n },\n },\n);\n\nexport function terminatePointHitIndexWorker(): void {\n workerClient.terminate(\"worker terminated\");\n}\n\nfunction buildSyncFallback(\n pointData: WsiPointData,\n source: WsiImageSource | null,\n): FlatPointSpatialIndex | null {\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) return null;\n\n const positions = pointData.positions.subarray(0, safeCount * 2);\n const result = buildPointHitIndex({\n count: safeCount,\n positions,\n drawIndices:\n pointData.drawIndices instanceof Uint32Array ? pointData.drawIndices : null,\n sourceWidth: source?.width ?? 0,\n sourceHeight: source?.height ?? 0,\n });\n if (!result) return null;\n\n return {\n cellSize: result.cellSize,\n safeCount,\n positions,\n ids:\n pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount\n ? pointData.ids.subarray(0, safeCount)\n : null,\n hashCapacity: result.hashCapacity,\n hashMask: result.hashCapacity - 1,\n hashTable: result.hashTable,\n cellKeys: result.cellKeys,\n cellOffsets: result.cellOffsets,\n cellLengths: result.cellLengths,\n pointIndices: result.pointIndices,\n };\n}\n\nexport async function buildPointSpatialIndexAsync(\n pointData: WsiPointData | null | undefined,\n source: WsiImageSource | null,\n): Promise<FlatPointSpatialIndex | null> {\n if (!pointData || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) return null;\n\n return new Promise<FlatPointSpatialIndex | null>((resolve, reject) => {\n const pending: PendingRequest = {\n resolve,\n reject,\n pointData,\n };\n const requestTicket = workerClient.beginRequest(pending);\n if (!requestTicket || !requestTicket.worker) {\n resolve(buildSyncFallback(pointData, source));\n return;\n }\n\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const drawIndicesCopy =\n pointData.drawIndices instanceof Uint32Array &&\n pointData.drawIndices.length > 0\n ? pointData.drawIndices.slice()\n : undefined;\n\n const msg: PointHitIndexWorkerRequest = {\n type: \"point-hit-index-request\",\n id: requestTicket.id,\n count: safeCount,\n positions: positionsCopy.buffer,\n drawIndices: drawIndicesCopy?.buffer,\n sourceWidth: source?.width ?? 0,\n sourceHeight: source?.height ?? 0,\n };\n const transfer: Transferable[] = [positionsCopy.buffer];\n if (drawIndicesCopy) transfer.push(drawIndicesCopy.buffer);\n\n try {\n requestTicket.worker.postMessage(msg, transfer);\n } catch (error) {\n const canceled = workerClient.cancelRequest(requestTicket.id);\n if (canceled) {\n canceled.reject(error);\n } else {\n reject(error);\n }\n }\n });\n}\n","import { type PreparedRoiPolygon, pointInPreparedPolygon, prepareRoiPolygons, toRoiGeometry } from \"./roi-geometry\";\nimport type { WsiPointData, WsiRegion } from \"./types\";\n\nexport interface RoiTermCount {\n termId: string;\n paletteIndex: number;\n count: number;\n}\n\nexport interface RoiPointGroup {\n regionId: string | number;\n regionIndex: number;\n totalCount: number;\n termCounts: RoiTermCount[];\n}\n\nexport interface RoiPointGroupOptions {\n paletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n includeEmptyRegions?: boolean;\n}\n\nexport interface RoiPointGroupStats {\n groups: RoiPointGroup[];\n inputPointCount: number;\n pointsInsideAnyRegion: number;\n unmatchedPointCount: number;\n}\n\ninterface PreparedRegion {\n regionId: string | number;\n regionIndex: number;\n polygons: PreparedRoiPolygon[];\n area: number;\n}\n\nfunction prepareRegions(regions: readonly WsiRegion[]): PreparedRegion[] {\n const prepared: PreparedRegion[] = [];\n for (let i = 0; i < regions.length; i += 1) {\n const region = regions[i];\n const polygons = prepareRoiPolygons([toRoiGeometry(region?.coordinates)]);\n if (polygons.length === 0) continue;\n\n let area = 0;\n for (const polygon of polygons) {\n area += polygon.area;\n }\n\n prepared.push({\n regionId: region.id ?? i,\n regionIndex: i,\n polygons,\n area: Math.max(1e-6, area),\n });\n }\n return prepared;\n}\n\nfunction resolveTermId(paletteIndex: number, paletteIndexToTermId: RoiPointGroupOptions[\"paletteIndexToTermId\"]): string {\n if (Array.isArray(paletteIndexToTermId)) {\n const fromArray = paletteIndexToTermId[paletteIndex];\n if (typeof fromArray === \"string\" && fromArray.length > 0) return fromArray;\n }\n if (paletteIndexToTermId instanceof Map) {\n const fromMap = paletteIndexToTermId.get(paletteIndex);\n if (typeof fromMap === \"string\" && fromMap.length > 0) return fromMap;\n }\n return String(paletteIndex);\n}\n\nexport function computeRoiPointGroups(pointData: WsiPointData | null | undefined, regions: readonly WsiRegion[] | null | undefined, options: RoiPointGroupOptions = {}): RoiPointGroupStats {\n const baseCount = Math.max(\n 0,\n Math.min(\n Math.floor(pointData?.count ?? 0),\n Math.floor((pointData?.positions?.length ?? 0) / 2),\n pointData?.paletteIndices?.length ?? 0,\n pointData?.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER\n )\n );\n\n let drawIndices: Uint32Array | null = null;\n if (pointData?.drawIndices instanceof Uint32Array) {\n const source = pointData.drawIndices;\n let valid = source.length;\n for (let i = 0; i < source.length; i += 1) {\n const idx = source[i];\n if (idx < baseCount) continue;\n valid -= 1;\n }\n if (valid === source.length) {\n drawIndices = source;\n } else if (valid > 0) {\n const filtered = new Uint32Array(valid);\n let cursor = 0;\n for (let i = 0; i < source.length; i += 1) {\n const idx = source[i];\n if (idx >= baseCount) continue;\n filtered[cursor] = idx;\n cursor += 1;\n }\n drawIndices = filtered;\n } else {\n drawIndices = new Uint32Array(0);\n }\n }\n\n const inputCount = drawIndices ? drawIndices.length : baseCount;\n\n const preparedRegions = prepareRegions(regions ?? []);\n if (!pointData || inputCount === 0 || preparedRegions.length === 0) {\n return {\n groups: [],\n inputPointCount: inputCount,\n pointsInsideAnyRegion: 0,\n unmatchedPointCount: inputCount,\n };\n }\n\n const regionTermCounters = new Map<number, Map<number, number>>();\n const regionTotalCounters = new Map<number, number>();\n let insideCount = 0;\n\n for (let i = 0; i < inputCount; i += 1) {\n const pointIndex = drawIndices ? drawIndices[i] : i;\n const x = pointData.positions[pointIndex * 2];\n const y = pointData.positions[pointIndex * 2 + 1];\n let bestRegion: PreparedRegion | null = null;\n\n for (const region of preparedRegions) {\n let inside = false;\n for (const polygon of region.polygons) {\n if (!pointInPreparedPolygon(x, y, polygon)) continue;\n inside = true;\n break;\n }\n if (!inside) continue;\n if (!bestRegion || region.area < bestRegion.area) {\n bestRegion = region;\n }\n }\n\n if (!bestRegion) continue;\n insideCount += 1;\n\n const paletteIndex = pointData.paletteIndices[pointIndex] ?? 0;\n const regionTermMap = regionTermCounters.get(bestRegion.regionIndex) ?? new Map<number, number>();\n regionTermMap.set(paletteIndex, (regionTermMap.get(paletteIndex) ?? 0) + 1);\n regionTermCounters.set(bestRegion.regionIndex, regionTermMap);\n regionTotalCounters.set(bestRegion.regionIndex, (regionTotalCounters.get(bestRegion.regionIndex) ?? 0) + 1);\n }\n\n const includeEmptyRegions = options.includeEmptyRegions ?? false;\n const groups: RoiPointGroup[] = [];\n for (const region of preparedRegions) {\n const totalCount = regionTotalCounters.get(region.regionIndex) ?? 0;\n if (!includeEmptyRegions && totalCount <= 0) continue;\n const termMap = regionTermCounters.get(region.regionIndex) ?? new Map();\n const termCounts: RoiTermCount[] = Array.from(termMap.entries())\n .map(([paletteIndex, count]) => ({\n termId: resolveTermId(paletteIndex, options.paletteIndexToTermId),\n paletteIndex,\n count,\n }))\n .sort((a, b) => b.count - a.count || a.paletteIndex - b.paletteIndex);\n\n groups.push({\n regionId: region.regionId,\n regionIndex: region.regionIndex,\n totalCount,\n termCounts,\n });\n }\n\n return {\n groups,\n inputPointCount: inputCount,\n pointsInsideAnyRegion: insideCount,\n unmatchedPointCount: Math.max(0, inputCount - insideCount),\n };\n}\n","import { nowMs } from \"./utils\";\n\nexport type TileBounds = [number, number, number, number];\n\nexport interface ScheduledTile {\n\tkey: string;\n\ttier: number;\n\tx: number;\n\ty: number;\n\tbounds: TileBounds;\n\tdistance2: number;\n\turl: string;\n}\n\nexport interface TileSchedulerSnapshot {\n\tinflight: number;\n\tqueued: number;\n\taborted: number;\n\tretries: number;\n\tfailed: number;\n}\n\nexport interface TileSchedulerOptions {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n\tauthToken?: string;\n\tonTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tonTileError?: (\n\t\ttile: ScheduledTile,\n\t\terror: unknown,\n\t\tattemptCount: number,\n\t) => void;\n\tonStateChange?: (snapshot: TileSchedulerSnapshot) => void;\n}\n\ninterface QueueItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\treadyAt: number;\n}\n\ninterface InflightItem {\n\ttile: ScheduledTile;\n\tattempt: number;\n\tcontroller: AbortController;\n}\n\nfunction shouldAttachAuthHeader(url: string, authToken: string): boolean {\n\tif (!authToken) return false;\n\ttry {\n\t\tconst parsed = new URL(url, typeof window !== \"undefined\" ? window.location.href : undefined);\n\t\tconst host = parsed.hostname.toLowerCase();\n\t\tconst isAwsS3 =\n\t\t\thost.includes(\"amazonaws.com\") || host.startsWith(\"s3.\") || host.includes(\".s3.\");\n\t\tif (isAwsS3) return false;\n\t} catch {\n\t\t// Fallback to attaching auth if URL parsing fails.\n\t}\n\treturn true;\n}\n\nexport class TileScheduler {\n\tprivate readonly maxConcurrency: number;\n\tprivate readonly maxRetries: number;\n\tprivate readonly retryBaseDelayMs: number;\n\tprivate readonly retryMaxDelayMs: number;\n\tprivate readonly onTileLoad: (tile: ScheduledTile, bitmap: ImageBitmap) => void;\n\tprivate readonly onTileError?:\n\t\t| ((tile: ScheduledTile, error: unknown, attemptCount: number) => void)\n\t\t| undefined;\n\tprivate readonly onStateChange?:\n\t\t| ((snapshot: TileSchedulerSnapshot) => void)\n\t\t| undefined;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate queue: QueueItem[] = [];\n\tprivate queuedByKey = new Map<string, QueueItem>();\n\tprivate inflight = new Map<string, InflightItem>();\n\tprivate visibleKeys = new Set<string>();\n\tprivate timerId: number | null = null;\n\tprivate abortedCount = 0;\n\tprivate retryCount = 0;\n\tprivate failedCount = 0;\n\n\tconstructor(options: TileSchedulerOptions) {\n\t\tthis.maxConcurrency = Math.max(1, Math.floor(options.maxConcurrency ?? 12));\n\t\tthis.maxRetries = Math.max(0, Math.floor(options.maxRetries ?? 2));\n\t\tthis.retryBaseDelayMs = Math.max(\n\t\t\t10,\n\t\t\tMath.floor(options.retryBaseDelayMs ?? 120),\n\t\t);\n\t\tthis.retryMaxDelayMs = Math.max(\n\t\t\tthis.retryBaseDelayMs,\n\t\t\tMath.floor(options.retryMaxDelayMs ?? 1200),\n\t\t);\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.onTileLoad = options.onTileLoad;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onStateChange = options.onStateChange;\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t}\n\n\tschedule(tiles: readonly ScheduledTile[]): void {\n\t\tif (this.destroyed) return;\n\n\t\tconst nextVisibleKeys = new Set<string>();\n\t\tfor (const tile of tiles) {\n\t\t\tnextVisibleKeys.add(tile.key);\n\t\t}\n\t\tthis.visibleKeys = nextVisibleKeys;\n\n\t\tthis.dropInvisibleQueued(nextVisibleKeys);\n\t\tthis.abortInvisibleInflight(nextVisibleKeys);\n\n\t\tfor (const tile of tiles) {\n\t\t\tif (this.inflight.has(tile.key)) {\n\t\t\t\tconst inflight = this.inflight.get(tile.key);\n\t\t\t\tif (inflight) inflight.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst queued = this.queuedByKey.get(tile.key);\n\t\t\tif (queued) {\n\t\t\t\tqueued.tile = tile;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst item: QueueItem = {\n\t\t\t\ttile,\n\t\t\t\tattempt: 0,\n\t\t\t\treadyAt: nowMs(),\n\t\t\t};\n\t\t\tthis.queue.push(item);\n\t\t\tthis.queuedByKey.set(tile.key, item);\n\t\t}\n\n\t\tthis.sortQueue();\n\t\tthis.pump();\n\t\tthis.emitStateChange();\n\t}\n\n\tclear(): void {\n\t\tthis.clearPumpTimer();\n\t\tthis.visibleKeys.clear();\n\t\tthis.queue = [];\n\t\tthis.queuedByKey.clear();\n\n\t\tfor (const [, item] of this.inflight) {\n\t\t\titem.controller.abort();\n\t\t}\n\t\tthis.inflight.clear();\n\t\tthis.emitStateChange();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\t\tthis.clear();\n\t}\n\n\tgetInflightCount(): number {\n\t\treturn this.inflight.size;\n\t}\n\n\tgetSnapshot(): TileSchedulerSnapshot {\n\t\treturn {\n\t\t\tinflight: this.inflight.size,\n\t\t\tqueued: this.queue.length,\n\t\t\taborted: this.abortedCount,\n\t\t\tretries: this.retryCount,\n\t\t\tfailed: this.failedCount,\n\t\t};\n\t}\n\n\tprivate dropInvisibleQueued(visibleKeys: Set<string>): void {\n\t\tif (this.queue.length === 0) return;\n\t\tconst nextQueue: QueueItem[] = [];\n\t\tfor (const item of this.queue) {\n\t\t\tif (!visibleKeys.has(item.tile.key)) {\n\t\t\t\tthis.queuedByKey.delete(item.tile.key);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tnextQueue.push(item);\n\t\t}\n\t\tthis.queue = nextQueue;\n\t}\n\n\tprivate abortInvisibleInflight(visibleKeys: Set<string>): void {\n\t\tfor (const [key, item] of this.inflight) {\n\t\t\tif (visibleKeys.has(key)) continue;\n\t\t\tthis.inflight.delete(key);\n\t\t\tthis.abortedCount += 1;\n\t\t\titem.controller.abort();\n\t\t}\n\t}\n\n\tprivate sortQueue(): void {\n\t\tthis.queue.sort((a, b) => {\n\t\t\tif (a.readyAt !== b.readyAt) return a.readyAt - b.readyAt;\n\t\t\tif (a.tile.distance2 !== b.tile.distance2) {\n\t\t\t\treturn a.tile.distance2 - b.tile.distance2;\n\t\t\t}\n\t\t\tif (a.tile.tier !== b.tile.tier) return b.tile.tier - a.tile.tier;\n\t\t\treturn a.tile.key.localeCompare(b.tile.key);\n\t\t});\n\t}\n\n\tprivate pump(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.clearPumpTimer();\n\n\t\twhile (this.inflight.size < this.maxConcurrency) {\n\t\t\tconst next = this.takeNextReadyQueueItem();\n\t\t\tif (!next) break;\n\t\t\tthis.startFetch(next);\n\t\t}\n\n\t\tif (this.inflight.size >= this.maxConcurrency) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.queue.length === 0) return;\n\n\t\tconst earliestReadyAt = this.queue[0]?.readyAt;\n\t\tif (typeof earliestReadyAt !== \"number\") return;\n\t\tconst delay = Math.max(0, earliestReadyAt - nowMs());\n\t\tthis.timerId = window.setTimeout(() => {\n\t\t\tthis.timerId = null;\n\t\t\tthis.pump();\n\t\t}, delay);\n\t}\n\n\tprivate takeNextReadyQueueItem(): QueueItem | null {\n\t\tif (this.queue.length === 0) return null;\n\t\tconst now = nowMs();\n\t\tconst first = this.queue[0];\n\t\tif (!first || first.readyAt > now) return null;\n\n\t\tthis.queue.shift();\n\t\tthis.queuedByKey.delete(first.tile.key);\n\t\treturn first;\n\t}\n\n\tprivate startFetch(item: QueueItem): void {\n\t\tconst controller = new AbortController();\n\t\tconst inflightEntry: InflightItem = {\n\t\t\ttile: item.tile,\n\t\t\tattempt: item.attempt,\n\t\t\tcontroller,\n\t\t};\n\t\tthis.inflight.set(item.tile.key, inflightEntry);\n\t\tthis.emitStateChange();\n\n\t\tconst useAuthHeader = shouldAttachAuthHeader(item.tile.url, this.authToken);\n\t\tfetch(item.tile.url, {\n\t\t\tsignal: controller.signal,\n\t\t\theaders: useAuthHeader ? { Authorization: this.authToken } : undefined,\n\t\t})\n\t\t\t.then((response) => {\n\t\t\t\tif (!response.ok) {\n\t\t\t\t\tthrow new Error(`HTTP ${response.status}`);\n\t\t\t\t}\n\t\t\t\treturn response.blob();\n\t\t\t})\n\t\t\t.then((blob) => createImageBitmap(blob))\n\t\t\t.then((bitmap) => {\n\t\t\t\tif (this.destroyed || controller.signal.aborted) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tif (!this.visibleKeys.has(item.tile.key)) {\n\t\t\t\t\tbitmap.close();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tthis.onTileLoad(item.tile, bitmap);\n\t\t\t})\n\t\t\t.catch((error: unknown) => {\n\t\t\t\tif (controller.signal.aborted || this.destroyed) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst shouldRetry =\n\t\t\t\t\titem.attempt < this.maxRetries && this.visibleKeys.has(item.tile.key);\n\t\t\t\tif (shouldRetry) {\n\t\t\t\t\tthis.retryCount += 1;\n\t\t\t\t\tconst nextAttempt = item.attempt + 1;\n\t\t\t\t\tconst retryDelay = this.getRetryDelay(nextAttempt);\n\t\t\t\t\tconst queued: QueueItem = {\n\t\t\t\t\t\ttile: item.tile,\n\t\t\t\t\t\tattempt: nextAttempt,\n\t\t\t\t\t\treadyAt: nowMs() + retryDelay,\n\t\t\t\t\t};\n\t\t\t\t\tconst existing = this.queuedByKey.get(item.tile.key);\n\t\t\t\t\tif (existing) {\n\t\t\t\t\t\texisting.tile = queued.tile;\n\t\t\t\t\t\texisting.readyAt = Math.min(existing.readyAt, queued.readyAt);\n\t\t\t\t\t\texisting.attempt = Math.max(existing.attempt, queued.attempt);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.queue.push(queued);\n\t\t\t\t\t\tthis.queuedByKey.set(queued.tile.key, queued);\n\t\t\t\t\t}\n\t\t\t\t\tthis.sortQueue();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tthis.failedCount += 1;\n\t\t\t\tthis.onTileError?.(item.tile, error, item.attempt + 1);\n\t\t\t})\n\t\t\t.finally(() => {\n\t\t\t\tthis.inflight.delete(item.tile.key);\n\t\t\t\tthis.pump();\n\t\t\t\tthis.emitStateChange();\n\t\t\t});\n\t}\n\n\tprivate getRetryDelay(attempt: number): number {\n\t\tconst exp = Math.max(0, attempt - 1);\n\t\tconst delay = Math.min(\n\t\t\tthis.retryMaxDelayMs,\n\t\t\tthis.retryBaseDelayMs * 2 ** exp,\n\t\t);\n\t\tconst jitter = 0.85 + Math.random() * 0.3;\n\t\treturn Math.round(delay * jitter);\n\t}\n\n\tprivate clearPumpTimer(): void {\n\t\tif (this.timerId === null) return;\n\t\twindow.clearTimeout(this.timerId);\n\t\tthis.timerId = null;\n\t}\n\n\tprivate emitStateChange(): void {\n\t\tthis.onStateChange?.(this.getSnapshot());\n\t}\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\n\nexport interface RendererCanvasHandlers {\n pointerDown: (event: PointerEvent) => void;\n pointerMove: (event: PointerEvent) => void;\n pointerUp: (event: PointerEvent) => void;\n wheel: (event: WheelEvent) => void;\n doubleClick: (event: MouseEvent) => void;\n contextMenu: (event: MouseEvent) => void;\n contextLost: (event: Event) => void;\n contextRestored: (event: Event) => void;\n}\n\nexport function addRendererCanvasEventListeners(canvas: HTMLCanvasElement, handlers: RendererCanvasHandlers): void {\n canvas.addEventListener(\"pointerdown\", handlers.pointerDown);\n canvas.addEventListener(\"pointermove\", handlers.pointerMove);\n canvas.addEventListener(\"pointerup\", handlers.pointerUp);\n canvas.addEventListener(\"pointercancel\", handlers.pointerUp);\n canvas.addEventListener(\"wheel\", handlers.wheel, { passive: false });\n canvas.addEventListener(\"dblclick\", handlers.doubleClick);\n canvas.addEventListener(\"contextmenu\", handlers.contextMenu);\n canvas.addEventListener(\"webglcontextlost\", handlers.contextLost);\n canvas.addEventListener(\"webglcontextrestored\", handlers.contextRestored);\n}\n\nexport function removeRendererCanvasEventListeners(canvas: HTMLCanvasElement, handlers: RendererCanvasHandlers): void {\n canvas.removeEventListener(\"pointerdown\", handlers.pointerDown);\n canvas.removeEventListener(\"pointermove\", handlers.pointerMove);\n canvas.removeEventListener(\"pointerup\", handlers.pointerUp);\n canvas.removeEventListener(\"pointercancel\", handlers.pointerUp);\n canvas.removeEventListener(\"wheel\", handlers.wheel);\n canvas.removeEventListener(\"dblclick\", handlers.doubleClick);\n canvas.removeEventListener(\"contextmenu\", handlers.contextMenu);\n canvas.removeEventListener(\"webglcontextlost\", handlers.contextLost);\n canvas.removeEventListener(\"webglcontextrestored\", handlers.contextRestored);\n}\n\nexport function resizeCanvasViewport(canvas: HTMLCanvasElement, gl: WebGL2RenderingContext, camera: OrthoCamera): void {\n const rect = canvas.getBoundingClientRect();\n const cssW = Math.max(1, rect.width || canvas.clientWidth || 1);\n const cssH = Math.max(1, rect.height || canvas.clientHeight || 1);\n const dpr = Math.max(1, window.devicePixelRatio || 1);\n\n const pixelW = Math.max(1, Math.round(cssW * dpr));\n const pixelH = Math.max(1, Math.round(cssH * dpr));\n\n if (canvas.width !== pixelW || canvas.height !== pixelH) {\n canvas.width = pixelW;\n canvas.height = pixelH;\n }\n\n camera.setViewport(cssW, cssH);\n gl.viewport(0, 0, pixelW, pixelH);\n}\n","import type { WsiImageColorSettings } from \"./types\";\nimport { clamp } from \"./utils\";\nimport type { NormalizedImageColorSettings, PointSizeByZoom, PointSizeStop } from \"./wsi-renderer-types\";\n\nexport const DEFAULT_ROTATION_DRAG_SENSITIVITY = 0.35;\nexport const MIN_POINT_SIZE_PX = 0.5;\nexport const MAX_POINT_SIZE_PX = 256;\n\nexport const DEFAULT_POINT_SIZE_STOPS: readonly PointSizeStop[] = [\n { zoom: 1, size: 2.8 },\n { zoom: 2, size: 3.4 },\n { zoom: 3, size: 4.2 },\n { zoom: 4, size: 5.3 },\n { zoom: 5, size: 6.8 },\n { zoom: 6, size: 8.4 },\n { zoom: 7, size: 9.8 },\n { zoom: 8, size: 11.2 },\n { zoom: 9, size: 14.0 },\n { zoom: 10, size: 17.5 },\n { zoom: 11, size: 22.0 },\n { zoom: 12, size: 28.0 },\n];\n\nconst MIN_STROKE_SCALE = 0.1;\nconst MAX_STROKE_SCALE = 5.0;\nconst MIN_POINT_INNER_FILL_OPACITY = 0;\nconst MAX_POINT_INNER_FILL_OPACITY = 1;\nconst MIN_IMAGE_COLOR_INPUT = -100;\nconst MAX_IMAGE_COLOR_INPUT = 100;\nconst MAX_VIEW_TRANSITION_DURATION_MS = 2000;\n\nexport function toRadians(deg: number): number {\n return (deg * Math.PI) / 180;\n}\n\nexport function isSameArrayView(a: ArrayBufferView | null | undefined, b: ArrayBufferView | null | undefined): boolean {\n if (!a || !b) return a === b;\n return a.buffer === b.buffer && a.byteOffset === b.byteOffset && a.byteLength === b.byteLength;\n}\n\nexport function clonePointSizeStops(stops: readonly PointSizeStop[]): PointSizeStop[] {\n return stops.map(stop => ({ zoom: stop.zoom, size: stop.size }));\n}\n\nexport function normalizePointSizeStops(pointSizeByZoom: PointSizeByZoom | null | undefined): PointSizeStop[] {\n if (!pointSizeByZoom) return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\n const parsed = new Map<number, number>();\n for (const [zoomKey, rawSize] of Object.entries(pointSizeByZoom)) {\n const zoom = Number(zoomKey);\n const size = Number(rawSize);\n if (!Number.isFinite(zoom) || !Number.isFinite(size) || size <= 0) continue;\n parsed.set(zoom, size);\n }\n\n if (parsed.size === 0) {\n return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n }\n\n return Array.from(parsed.entries())\n .sort((a, b) => a[0] - b[0])\n .map(([zoom, size]) => ({ zoom, size }));\n}\n\nexport function arePointSizeStopsEqual(a: readonly PointSizeStop[], b: readonly PointSizeStop[]): boolean {\n if (a === b) return true;\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i += 1) {\n if (a[i].zoom !== b[i].zoom || a[i].size !== b[i].size) {\n return false;\n }\n }\n return true;\n}\n\nexport function resolvePointSizeByZoomStops(continuousZoom: number, stops: readonly PointSizeStop[]): number {\n if (!Number.isFinite(continuousZoom)) return stops[0]?.size ?? MIN_POINT_SIZE_PX;\n if (stops.length === 0) return MIN_POINT_SIZE_PX;\n if (stops.length === 1) return stops[0].size;\n if (continuousZoom <= stops[0].zoom) return stops[0].size;\n\n for (let i = 1; i < stops.length; i += 1) {\n const prev = stops[i - 1];\n const next = stops[i];\n if (continuousZoom > next.zoom) continue;\n const span = Math.max(1e-6, next.zoom - prev.zoom);\n const t = clamp((continuousZoom - prev.zoom) / span, 0, 1);\n return prev.size + (next.size - prev.size) * t;\n }\n\n const last = stops[stops.length - 1];\n const prev = stops[stops.length - 2];\n const span = Math.max(1e-6, last.zoom - prev.zoom);\n const slope = (last.size - prev.size) / span;\n return last.size + (continuousZoom - last.zoom) * slope;\n}\n\nexport function normalizeStrokeScale(value: number | null | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 1.0;\n return clamp(value, MIN_STROKE_SCALE, MAX_STROKE_SCALE);\n}\n\nexport function normalizePointInnerFillOpacity(value: number | null | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n return clamp(value, MIN_POINT_INNER_FILL_OPACITY, MAX_POINT_INNER_FILL_OPACITY);\n}\n\nfunction normalizeImageColorInput(value: number | null | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n return clamp(value, MIN_IMAGE_COLOR_INPUT, MAX_IMAGE_COLOR_INPUT);\n}\n\nexport function toNormalizedImageColorSettings(settings: WsiImageColorSettings | null | undefined): NormalizedImageColorSettings {\n const brightnessInput = normalizeImageColorInput(settings?.brightness);\n const contrastInput = normalizeImageColorInput(settings?.contrast);\n const saturationInput = normalizeImageColorInput(settings?.saturation);\n return {\n brightness: brightnessInput / 200,\n contrast: contrastInput / 100,\n saturation: saturationInput / 100,\n };\n}\n\nexport function linearEasing(t: number): number {\n return t;\n}\n\nexport function normalizeViewTransitionDuration(duration: number | null | undefined): number {\n if (typeof duration !== \"number\" || !Number.isFinite(duration)) return 0;\n return clamp(duration, 0, MAX_VIEW_TRANSITION_DURATION_MS);\n}\n\nexport function normalizeZoomOverride(value: number | null | undefined): number | null {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) return null;\n return Math.max(1e-6, value);\n}\n\nexport function normalizeTransitionEasing(easing: ((t: number) => number) | null | undefined): (t: number) => number {\n return typeof easing === \"function\" ? easing : linearEasing;\n}\n","import { DEFAULT_ROTATION_DRAG_SENSITIVITY, toRadians } from \"./wsi-normalize\";\nimport type { InteractionConfig, InteractionState } from \"./wsi-renderer-types\";\n\ninterface PointerMoveOptions {\n event: PointerEvent;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n config: InteractionConfig;\n camera: {\n getViewState: () => {\n zoom: number;\n offsetX: number;\n offsetY: number;\n rotationDeg: number;\n };\n setViewState: (next: Partial<{ zoom: number; offsetX: number; offsetY: number; rotationDeg: number }>) => void;\n };\n clampViewState: () => void;\n emitViewState: () => void;\n requestRender: () => void;\n}\n\ninterface PointerDownOptions {\n event: PointerEvent;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n config: InteractionConfig;\n cancelViewAnimation: () => void;\n}\n\ninterface WheelOptions {\n event: WheelEvent;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\ninterface DoubleClickOptions {\n event: MouseEvent;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\nfunction getPointerAngleRad(canvas: HTMLCanvasElement, clientX: number, clientY: number): number {\n const rect = canvas.getBoundingClientRect();\n const x = clientX - rect.left - rect.width * 0.5;\n const y = clientY - rect.top - rect.height * 0.5;\n return Math.atan2(y, x);\n}\n\nexport function cancelDrag(canvas: HTMLCanvasElement, state: InteractionState): void {\n if (state.pointerId !== null && canvas.hasPointerCapture(state.pointerId)) {\n try {\n canvas.releasePointerCapture(state.pointerId);\n } catch {\n // noop\n }\n }\n state.dragging = false;\n state.mode = \"none\";\n state.rotateLastAngleRad = null;\n state.pointerId = null;\n canvas.classList.remove(\"dragging\");\n}\n\nexport function handlePointerDown(options: PointerDownOptions): void {\n const { event, canvas, state, config, cancelViewAnimation } = options;\n const wantsRotate = config.ctrlDragRotate && (event.ctrlKey || event.metaKey);\n const allowButton = event.button === 0 || (wantsRotate && event.button === 2);\n if (!allowButton) return;\n\n cancelViewAnimation();\n if (wantsRotate) {\n event.preventDefault();\n }\n\n state.dragging = true;\n state.mode = wantsRotate ? \"rotate\" : \"pan\";\n state.pointerId = event.pointerId;\n state.lastPointerX = event.clientX;\n state.lastPointerY = event.clientY;\n state.rotateLastAngleRad = state.mode === \"rotate\" ? getPointerAngleRad(canvas, event.clientX, event.clientY) : null;\n\n canvas.classList.add(\"dragging\");\n canvas.setPointerCapture(event.pointerId);\n}\n\nexport function handlePointerMove(options: PointerMoveOptions): void {\n const { event, canvas, state, config, camera, clampViewState, emitViewState, requestRender } = options;\n if (!state.dragging || event.pointerId !== state.pointerId) return;\n\n const dx = event.clientX - state.lastPointerX;\n const dy = event.clientY - state.lastPointerY;\n state.lastPointerX = event.clientX;\n state.lastPointerY = event.clientY;\n\n if (state.mode === \"rotate\") {\n const nextAngle = getPointerAngleRad(canvas, event.clientX, event.clientY);\n const prevAngle = state.rotateLastAngleRad;\n state.rotateLastAngleRad = nextAngle;\n if (prevAngle !== null) {\n const rawDelta = nextAngle - prevAngle;\n const delta = Math.atan2(Math.sin(rawDelta), Math.cos(rawDelta));\n const sensitivityScale = DEFAULT_ROTATION_DRAG_SENSITIVITY > 0 ? config.rotationDragSensitivityDegPerPixel / DEFAULT_ROTATION_DRAG_SENSITIVITY : 1;\n const viewState = camera.getViewState();\n camera.setViewState({\n rotationDeg: viewState.rotationDeg - ((delta * 180) / Math.PI) * sensitivityScale,\n });\n }\n } else {\n const viewState = camera.getViewState();\n const zoom = Math.max(1e-6, viewState.zoom);\n const rad = toRadians(viewState.rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const worldDx = (dx * cos - dy * sin) / zoom;\n const worldDy = (dx * sin + dy * cos) / zoom;\n camera.setViewState({\n offsetX: viewState.offsetX - worldDx,\n offsetY: viewState.offsetY - worldDy,\n });\n }\n\n clampViewState();\n emitViewState();\n requestRender();\n}\n\nexport function handlePointerUp(event: PointerEvent, canvas: HTMLCanvasElement, state: InteractionState): void {\n if (event.pointerId !== state.pointerId) return;\n cancelDrag(canvas, state);\n}\n\nexport function handleWheel(options: WheelOptions): void {\n const { event, canvas, onZoomBy } = options;\n event.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const factor = event.deltaY < 0 ? 1.12 : 0.89;\n onZoomBy(factor, x, y);\n}\n\nexport function handleDoubleClick(options: DoubleClickOptions): void {\n const { event, canvas, onZoomBy } = options;\n const rect = canvas.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n onZoomBy(event.shiftKey ? 0.8 : 1.25, x, y);\n}\n\nexport function handleContextMenu(event: MouseEvent, dragging: boolean): void {\n if (dragging || event.ctrlKey || event.metaKey) {\n event.preventDefault();\n }\n}\n","import { toTileUrl } from \"./image-info\";\nimport type { ScheduledTile } from \"./tile-scheduler\";\nimport type { WsiImageSource } from \"./types\";\nimport { clamp } from \"./utils\";\nimport type { Bounds } from \"./wsi-renderer-types\";\n\ninterface CameraViewLike {\n getViewCorners: () => [readonly [number, number], readonly [number, number], readonly [number, number], readonly [number, number]];\n getViewState: () => { zoom: number };\n getCenter: () => [number, number];\n setCenter: (x: number, y: number) => void;\n}\n\nexport function getViewBounds(camera: CameraViewLike): Bounds {\n const corners = camera.getViewCorners();\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const [x, y] of corners) {\n if (x < minX) minX = x;\n if (x > maxX) maxX = x;\n if (y < minY) minY = y;\n if (y > maxY) maxY = y;\n }\n return [minX, minY, maxX, maxY];\n}\n\nexport function clampViewState(camera: CameraViewLike, source: WsiImageSource): void {\n const bounds = getViewBounds(camera);\n const visibleW = Math.max(1e-6, bounds[2] - bounds[0]);\n const visibleH = Math.max(1e-6, bounds[3] - bounds[1]);\n const marginX = visibleW * 0.2;\n const marginY = visibleH * 0.2;\n\n const [centerX, centerY] = camera.getCenter();\n const halfW = visibleW * 0.5;\n const halfH = visibleH * 0.5;\n\n const minCenterX = halfW - marginX;\n const maxCenterX = source.width - halfW + marginX;\n const minCenterY = halfH - marginY;\n const maxCenterY = source.height - halfH + marginY;\n\n const nextCenterX = minCenterX <= maxCenterX ? clamp(centerX, minCenterX, maxCenterX) : source.width * 0.5;\n const nextCenterY = minCenterY <= maxCenterY ? clamp(centerY, minCenterY, maxCenterY) : source.height * 0.5;\n\n camera.setCenter(nextCenterX, nextCenterY);\n}\n\nexport function selectTier(camera: CameraViewLike, source: WsiImageSource): number {\n const zoom = Math.max(1e-6, camera.getViewState().zoom);\n const rawTier = source.maxTierZoom + Math.log2(zoom);\n return clamp(Math.floor(rawTier), 0, source.maxTierZoom);\n}\n\nexport function intersectsBounds(a: Bounds, b: Bounds): boolean {\n return !(a[2] <= b[0] || a[0] >= b[2] || a[3] <= b[1] || a[1] >= b[3]);\n}\n\nexport function getVisibleTilesForTier(camera: CameraViewLike, source: WsiImageSource, tier: number): ScheduledTile[] {\n const viewBounds = getViewBounds(camera);\n\n const levelScale = Math.pow(2, source.maxTierZoom - tier);\n const levelWidth = Math.ceil(source.width / levelScale);\n const levelHeight = Math.ceil(source.height / levelScale);\n\n const tilesX = Math.max(1, Math.ceil(levelWidth / source.tileSize));\n const tilesY = Math.max(1, Math.ceil(levelHeight / source.tileSize));\n\n const viewMinX = viewBounds[0];\n const viewMinY = viewBounds[1];\n const viewMaxX = viewBounds[2];\n const viewMaxY = viewBounds[3];\n\n const minTileX = clamp(Math.floor(viewMinX / levelScale / source.tileSize), 0, tilesX - 1);\n const maxTileX = clamp(Math.floor((viewMaxX - 1) / levelScale / source.tileSize), 0, tilesX - 1);\n const minTileY = clamp(Math.floor(viewMinY / levelScale / source.tileSize), 0, tilesY - 1);\n const maxTileY = clamp(Math.floor((viewMaxY - 1) / levelScale / source.tileSize), 0, tilesY - 1);\n\n if (minTileX > maxTileX || minTileY > maxTileY) {\n return [];\n }\n\n const centerTileX = ((viewMinX + viewMaxX) * 0.5) / levelScale / source.tileSize;\n const centerTileY = ((viewMinY + viewMaxY) * 0.5) / levelScale / source.tileSize;\n\n const visible: ScheduledTile[] = [];\n for (let y = minTileY; y <= maxTileY; y += 1) {\n for (let x = minTileX; x <= maxTileX; x += 1) {\n const left = x * source.tileSize * levelScale;\n const top = y * source.tileSize * levelScale;\n const right = Math.min((x + 1) * source.tileSize, levelWidth) * levelScale;\n const bottom = Math.min((y + 1) * source.tileSize, levelHeight) * levelScale;\n\n const dx = x - centerTileX;\n const dy = y - centerTileY;\n visible.push({\n key: `${tier}/${x}/${y}`,\n tier,\n x,\n y,\n bounds: [left, top, right, bottom],\n distance2: dx * dx + dy * dy,\n url: toTileUrl(source, tier, x, y),\n });\n }\n }\n\n visible.sort((a, b) => a.distance2 - b.distance2);\n return visible;\n}\n\nexport function getVisibleTiles(camera: CameraViewLike, source: WsiImageSource): { tier: number; visible: ScheduledTile[] } {\n const tier = selectTier(camera, source);\n return {\n tier,\n visible: getVisibleTilesForTier(camera, source, tier),\n };\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\nimport { cancelDrag as cancelInteractionDrag, handleContextMenu, handleDoubleClick, handlePointerDown, handlePointerMove, handlePointerUp, handleWheel } from \"./wsi-interaction\";\nimport type { RendererCanvasHandlers } from \"./wsi-canvas-lifecycle\";\nimport type { InteractionState } from \"./wsi-renderer-types\";\nimport type { WsiImageSource } from \"./types\";\nimport { clampViewState } from \"./wsi-tile-visibility\";\n\ninterface BaseInteractionOptions {\n interactionLocked: boolean;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n}\n\ninterface PointerDownWithLockOptions extends BaseInteractionOptions {\n event: PointerEvent;\n ctrlDragRotate: boolean;\n rotationDragSensitivityDegPerPixel: number;\n cancelViewAnimation: () => void;\n}\n\ninterface PointerMoveWithLockOptions extends BaseInteractionOptions {\n event: PointerEvent;\n ctrlDragRotate: boolean;\n rotationDragSensitivityDegPerPixel: number;\n camera: OrthoCamera;\n source: WsiImageSource;\n emitViewState: () => void;\n requestRender: () => void;\n}\n\ninterface PointerUpWithLockOptions extends BaseInteractionOptions {\n event: PointerEvent;\n}\n\ninterface WheelWithLockOptions {\n event: WheelEvent;\n interactionLocked: boolean;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\ninterface DoubleClickWithLockOptions {\n event: MouseEvent;\n interactionLocked: boolean;\n canvas: HTMLCanvasElement;\n onZoomBy: (factor: number, x: number, y: number) => void;\n}\n\ninterface ContextMenuWithLockOptions {\n event: MouseEvent;\n canvas: HTMLCanvasElement;\n state: InteractionState;\n}\n\nexport function onPointerDownWithLock(options: PointerDownWithLockOptions): void {\n if (options.interactionLocked) return;\n handlePointerDown({\n event: options.event,\n canvas: options.canvas,\n state: options.state,\n config: {\n ctrlDragRotate: options.ctrlDragRotate,\n rotationDragSensitivityDegPerPixel: options.rotationDragSensitivityDegPerPixel,\n },\n cancelViewAnimation: options.cancelViewAnimation,\n });\n}\n\nexport function onPointerMoveWithLock(options: PointerMoveWithLockOptions): void {\n if (options.interactionLocked) return;\n handlePointerMove({\n event: options.event,\n canvas: options.canvas,\n state: options.state,\n config: {\n ctrlDragRotate: options.ctrlDragRotate,\n rotationDragSensitivityDegPerPixel: options.rotationDragSensitivityDegPerPixel,\n },\n camera: options.camera,\n clampViewState: () => clampViewState(options.camera, options.source),\n emitViewState: options.emitViewState,\n requestRender: options.requestRender,\n });\n}\n\nexport function onPointerUpWithLock(options: PointerUpWithLockOptions): void {\n if (options.interactionLocked) return;\n handlePointerUp(options.event, options.canvas, options.state);\n}\n\nexport function onWheelWithLock(options: WheelWithLockOptions): void {\n if (options.interactionLocked) {\n options.event.preventDefault();\n return;\n }\n handleWheel({\n event: options.event,\n canvas: options.canvas,\n onZoomBy: options.onZoomBy,\n });\n}\n\nexport function onDoubleClickWithLock(options: DoubleClickWithLockOptions): void {\n if (options.interactionLocked) return;\n handleDoubleClick({\n event: options.event,\n canvas: options.canvas,\n onZoomBy: options.onZoomBy,\n });\n}\n\nexport function onContextMenuWithLock(options: ContextMenuWithLockOptions): void {\n handleContextMenu(options.event, options.state.dragging);\n}\n\nexport function cancelDrag(canvas: HTMLCanvasElement, state: InteractionState): void {\n cancelInteractionDrag(canvas, state);\n}\n\nexport interface CreateRendererInputHandlersOptions {\n canvas: HTMLCanvasElement;\n state: InteractionState;\n getInteractionLocked: () => boolean;\n getCtrlDragRotate: () => boolean;\n getRotationDragSensitivityDegPerPixel: () => number;\n cancelViewAnimation: () => void;\n camera: OrthoCamera;\n source: WsiImageSource;\n emitViewState: () => void;\n requestRender: () => void;\n zoomBy: (factor: number, x: number, y: number) => void;\n}\n\nexport function createRendererInputHandlers(options: CreateRendererInputHandlersOptions): Pick<RendererCanvasHandlers, \"pointerDown\" | \"pointerMove\" | \"pointerUp\" | \"wheel\" | \"doubleClick\" | \"contextMenu\"> {\n return {\n pointerDown: (event: PointerEvent) =>\n onPointerDownWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n state: options.state,\n ctrlDragRotate: options.getCtrlDragRotate(),\n rotationDragSensitivityDegPerPixel: options.getRotationDragSensitivityDegPerPixel(),\n cancelViewAnimation: options.cancelViewAnimation,\n }),\n pointerMove: (event: PointerEvent) =>\n onPointerMoveWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n state: options.state,\n ctrlDragRotate: options.getCtrlDragRotate(),\n rotationDragSensitivityDegPerPixel: options.getRotationDragSensitivityDegPerPixel(),\n camera: options.camera,\n source: options.source,\n emitViewState: options.emitViewState,\n requestRender: options.requestRender,\n }),\n pointerUp: (event: PointerEvent) =>\n onPointerUpWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n state: options.state,\n }),\n wheel: (event: WheelEvent) =>\n onWheelWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n onZoomBy: options.zoomBy,\n }),\n doubleClick: (event: MouseEvent) =>\n onDoubleClickWithLock({\n event,\n interactionLocked: options.getInteractionLocked(),\n canvas: options.canvas,\n onZoomBy: options.zoomBy,\n }),\n contextMenu: (event: MouseEvent) =>\n onContextMenuWithLock({\n event,\n canvas: options.canvas,\n state: options.state,\n }),\n };\n}\n","import type {\n HandleTileLoadedOptions,\n TileCacheTrimOptions,\n} from \"./wsi-renderer-types\";\n\nexport function trimTileCache(options: TileCacheTrimOptions): void {\n const { gl, cache, maxCacheTiles } = options;\n if (cache.size <= maxCacheTiles) return;\n\n const entries = Array.from(cache.entries());\n entries.sort((a, b) => a[1].lastUsed - b[1].lastUsed);\n\n const removeCount = cache.size - maxCacheTiles;\n for (let i = 0; i < removeCount; i += 1) {\n const [key, value] = entries[i];\n gl.deleteTexture(value.texture);\n cache.delete(key);\n }\n}\n\nexport function createTextureFromBitmap(gl: WebGL2RenderingContext, bitmap: ImageBitmap): WebGLTexture | null {\n if (gl.isContextLost()) return null;\n\n const texture = gl.createTexture();\n if (!texture) return null;\n\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n return texture;\n}\n\nexport function handleTileLoaded(options: HandleTileLoadedOptions): void {\n const { gl, cache, tile, bitmap, frameSerial, maxCacheTiles, destroyed, contextLost, requestRender } = options;\n\n if (destroyed || contextLost || gl.isContextLost()) {\n bitmap.close();\n return;\n }\n if (cache.has(tile.key)) {\n bitmap.close();\n return;\n }\n\n const texture = createTextureFromBitmap(gl, bitmap);\n bitmap.close();\n if (!texture) return;\n\n cache.set(tile.key, {\n key: tile.key,\n texture,\n bounds: tile.bounds,\n tier: tile.tier,\n lastUsed: frameSerial,\n });\n trimTileCache({ gl, cache, maxCacheTiles });\n requestRender();\n}\n\nexport function deleteCachedTextures(gl: WebGL2RenderingContext, cache: Map<string, { texture: WebGLTexture }>): void {\n for (const [, value] of cache) {\n gl.deleteTexture(value.texture);\n }\n}\n","import type { TileScheduler } from \"./tile-scheduler\";\nimport type { CachedTile, PointProgram, TileVertexProgram } from \"./wsi-renderer-types\";\nimport { deleteCachedTextures } from \"./wsi-tile-cache\";\n\nexport interface ContextLostOptions {\n event: Event;\n destroyed: boolean;\n contextLost: boolean;\n frame: number | null;\n cancelViewAnimation: () => void;\n cancelDrag: () => void;\n tileScheduler: TileScheduler;\n cache: Map<string, CachedTile>;\n onContextLost?: () => void;\n}\n\nexport interface ContextLostResult {\n handled: boolean;\n frame: number | null;\n}\n\nexport function handleContextLost(options: ContextLostOptions): ContextLostResult {\n const { event, destroyed, contextLost, cancelViewAnimation, cancelDrag, tileScheduler, cache, onContextLost } = options;\n event.preventDefault();\n if (destroyed || contextLost) {\n return {\n handled: false,\n frame: options.frame,\n };\n }\n\n let frame = options.frame;\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n cancelViewAnimation();\n\n cancelDrag();\n tileScheduler.clear();\n cache.clear();\n onContextLost?.();\n\n return {\n handled: true,\n frame,\n };\n}\n\nexport interface DestroyRendererOptions {\n destroyed: boolean;\n frame: number | null;\n cancelViewAnimation: () => void;\n resizeObserver: ResizeObserver;\n removeCanvasEventListeners: () => void;\n cancelDrag: () => void;\n tileScheduler: TileScheduler;\n contextLost: boolean;\n gl: WebGL2RenderingContext;\n cache: Map<string, CachedTile>;\n tileProgram: TileVertexProgram;\n pointProgram: PointProgram;\n}\n\nexport interface DestroyRendererResult {\n didDestroy: boolean;\n frame: number | null;\n}\n\nexport function destroyRenderer(options: DestroyRendererOptions): DestroyRendererResult {\n if (options.destroyed) {\n return {\n didDestroy: false,\n frame: options.frame,\n };\n }\n\n let frame = options.frame;\n if (frame !== null) {\n cancelAnimationFrame(frame);\n frame = null;\n }\n options.cancelViewAnimation();\n\n options.resizeObserver.disconnect();\n options.removeCanvasEventListeners();\n options.cancelDrag();\n options.tileScheduler.destroy();\n\n if (!options.contextLost && !options.gl.isContextLost()) {\n deleteCachedTextures(options.gl, options.cache);\n options.gl.deleteBuffer(options.tileProgram.vbo);\n options.gl.deleteVertexArray(options.tileProgram.vao);\n options.gl.deleteProgram(options.tileProgram.program);\n\n options.gl.deleteBuffer(options.pointProgram.posBuffer);\n options.gl.deleteBuffer(options.pointProgram.termBuffer);\n options.gl.deleteBuffer(options.pointProgram.fillModeBuffer);\n options.gl.deleteBuffer(options.pointProgram.indexBuffer);\n options.gl.deleteTexture(options.pointProgram.paletteTexture);\n options.gl.deleteVertexArray(options.pointProgram.vao);\n options.gl.deleteProgram(options.pointProgram.program);\n }\n options.cache.clear();\n\n return {\n didDestroy: true,\n frame,\n };\n}\n","import type { WsiPointData } from \"./types\";\nimport { isSameArrayView } from \"./wsi-normalize\";\nimport type { PointProgram } from \"./wsi-renderer-types\";\n\nexport interface PointBufferRuntime {\n pointCount: number;\n usePointIndices: boolean;\n pointBuffersDirty: boolean;\n lastPointData: WsiPointData | null;\n zeroFillModes: Uint8Array<ArrayBufferLike>;\n lastPointPalette: Uint8Array<ArrayBufferLike> | null;\n pointPaletteSize: number;\n}\n\nfunction sanitizeDrawIndices(drawIndices: Uint32Array, maxExclusive: number): Uint32Array {\n if (maxExclusive <= 0 || drawIndices.length === 0) {\n return new Uint32Array(0);\n }\n\n let validCount = drawIndices.length;\n for (let i = 0; i < drawIndices.length; i += 1) {\n if (drawIndices[i] < maxExclusive) continue;\n validCount -= 1;\n }\n if (validCount === drawIndices.length) {\n return drawIndices;\n }\n if (validCount <= 0) {\n return new Uint32Array(0);\n }\n\n const filtered = new Uint32Array(validCount);\n let cursor = 0;\n for (let i = 0; i < drawIndices.length; i += 1) {\n const idx = drawIndices[i];\n if (idx >= maxExclusive) continue;\n filtered[cursor] = idx;\n cursor += 1;\n }\n return filtered;\n}\n\nfunction getZeroFillModes(zeroFillModes: Uint8Array<ArrayBufferLike>, count: number): Uint8Array<ArrayBufferLike> {\n if (count <= 0) return new Uint8Array(0);\n if (zeroFillModes.length < count) {\n return new Uint8Array(count);\n }\n return zeroFillModes.subarray(0, count);\n}\n\nexport function setPointPalette(runtime: PointBufferRuntime, gl: WebGL2RenderingContext, pointProgram: PointProgram, contextLost: boolean, colors: Uint8Array | null | undefined): PointBufferRuntime {\n if (!colors || colors.length === 0) {\n return {\n ...runtime,\n lastPointPalette: null,\n };\n }\n\n const nextPalette = new Uint8Array(colors);\n if (contextLost || gl.isContextLost()) {\n return {\n ...runtime,\n lastPointPalette: nextPalette,\n };\n }\n\n const paletteSize = Math.max(1, Math.floor(nextPalette.length / 4));\n gl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, paletteSize, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, nextPalette);\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n return {\n ...runtime,\n lastPointPalette: nextPalette,\n pointPaletteSize: paletteSize,\n };\n}\n\nexport function setPointData(runtime: PointBufferRuntime, gl: WebGL2RenderingContext, pointProgram: PointProgram, contextLost: boolean, points: WsiPointData | null | undefined): PointBufferRuntime {\n if (!points || !points.count || !points.positions || !points.paletteIndices) {\n return {\n ...runtime,\n lastPointData: null,\n pointCount: 0,\n usePointIndices: false,\n };\n }\n\n const pointFillModes = points.fillModes instanceof Uint8Array ? points.fillModes : null;\n const hasFillModes = pointFillModes !== null;\n const safeCount = Math.max(0, Math.min(points.count, Math.floor(points.positions.length / 2), points.paletteIndices.length, hasFillModes ? pointFillModes.length : Number.MAX_SAFE_INTEGER));\n const nextPositions = points.positions.subarray(0, safeCount * 2);\n const nextPaletteIndices = points.paletteIndices.subarray(0, safeCount);\n const nextFillModes = hasFillModes ? pointFillModes.subarray(0, safeCount) : undefined;\n const hasDrawIndices = points.drawIndices instanceof Uint32Array;\n const nextDrawIndices = hasDrawIndices ? sanitizeDrawIndices(points.drawIndices as Uint32Array, safeCount) : null;\n\n const prev = runtime.lastPointData;\n const prevHasFillModes = prev?.fillModes instanceof Uint8Array;\n const geometryChanged =\n runtime.pointBuffersDirty ||\n !prev ||\n prev.count !== safeCount ||\n !isSameArrayView(prev.positions, nextPositions) ||\n !isSameArrayView(prev.paletteIndices, nextPaletteIndices) ||\n prevHasFillModes !== hasFillModes ||\n (hasFillModes && (!prev?.fillModes || !isSameArrayView(prev.fillModes, nextFillModes)));\n const drawIndicesChanged = runtime.pointBuffersDirty || (hasDrawIndices && (!prev?.drawIndices || !isSameArrayView(prev.drawIndices, nextDrawIndices))) || (!hasDrawIndices && !!prev?.drawIndices);\n\n const nextRuntime: PointBufferRuntime = {\n ...runtime,\n lastPointData: {\n count: safeCount,\n positions: nextPositions,\n paletteIndices: nextPaletteIndices,\n fillModes: nextFillModes,\n drawIndices: hasDrawIndices ? (nextDrawIndices ?? undefined) : undefined,\n },\n };\n\n if (contextLost || gl.isContextLost()) {\n return nextRuntime;\n }\n\n const currentPointData = nextRuntime.lastPointData;\n if (!currentPointData) {\n return nextRuntime;\n }\n\n if (geometryChanged) {\n gl.bindBuffer(gl.ARRAY_BUFFER, pointProgram.posBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, currentPointData.positions, gl.STATIC_DRAW);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, pointProgram.termBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, currentPointData.paletteIndices, gl.STATIC_DRAW);\n\n const zeroFillModes = getZeroFillModes(nextRuntime.zeroFillModes, safeCount);\n gl.bindBuffer(gl.ARRAY_BUFFER, pointProgram.fillModeBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, currentPointData.fillModes ?? zeroFillModes, gl.STATIC_DRAW);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n nextRuntime.zeroFillModes = zeroFillModes;\n }\n\n if (hasDrawIndices && drawIndicesChanged) {\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, pointProgram.indexBuffer);\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, nextDrawIndices ?? new Uint32Array(0), gl.DYNAMIC_DRAW);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n }\n\n nextRuntime.usePointIndices = hasDrawIndices;\n nextRuntime.pointCount = hasDrawIndices ? (nextDrawIndices?.length ?? 0) : currentPointData.count;\n if (geometryChanged || drawIndicesChanged) {\n nextRuntime.pointBuffersDirty = false;\n }\n\n return nextRuntime;\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\nimport type { ScheduledTile, TileScheduler } from \"./tile-scheduler\";\nimport type { WsiImageSource } from \"./types\";\nimport type { Bounds, CachedTile, NormalizedImageColorSettings, PointProgram, TileVertexProgram } from \"./wsi-renderer-types\";\n\nexport interface RenderFrameOptions {\n gl: WebGL2RenderingContext;\n camera: OrthoCamera;\n source: WsiImageSource;\n cache: Map<string, CachedTile>;\n frameSerial: number;\n tileProgram: TileVertexProgram;\n pointProgram: PointProgram;\n imageColorSettings: NormalizedImageColorSettings;\n pointCount: number;\n usePointIndices: boolean;\n pointPaletteSize: number;\n pointStrokeScale: number;\n pointInnerFillOpacity: number;\n pointSizePx: number;\n tileScheduler: TileScheduler;\n getVisibleTiles: () => { tier: number; visible: ScheduledTile[] };\n getVisibleTilesForTier: (tier: number) => ScheduledTile[];\n getViewBounds: () => Bounds;\n intersectsBounds: (a: Bounds, b: Bounds) => boolean;\n}\n\nexport interface RenderFrameResult {\n tier: number;\n visible: number;\n rendered: number;\n points: number;\n fallback: number;\n cacheHits: number;\n cacheMisses: number;\n drawCalls: number;\n}\n\nexport function renderFrame(options: RenderFrameOptions): RenderFrameResult {\n const {\n gl,\n camera,\n source,\n cache,\n frameSerial,\n tileProgram,\n pointProgram,\n imageColorSettings,\n pointCount,\n usePointIndices,\n pointPaletteSize,\n pointStrokeScale,\n pointInnerFillOpacity,\n pointSizePx,\n tileScheduler,\n getVisibleTiles,\n getVisibleTilesForTier,\n getViewBounds,\n intersectsBounds,\n } = options;\n\n gl.clearColor(0.03, 0.06, 0.1, 1);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const { tier, visible } = getVisibleTiles();\n const viewBounds = getViewBounds();\n const visibleKeys = new Set(visible.map(tile => tile.key));\n\n gl.useProgram(tileProgram.program);\n gl.bindVertexArray(tileProgram.vao);\n gl.uniformMatrix3fv(tileProgram.uCamera, false, camera.getMatrix());\n gl.uniform1i(tileProgram.uTexture, 0);\n gl.uniform1f(tileProgram.uBrightness, imageColorSettings.brightness);\n gl.uniform1f(tileProgram.uContrast, imageColorSettings.contrast);\n gl.uniform1f(tileProgram.uSaturation, imageColorSettings.saturation);\n\n const fallbackTiles: CachedTile[] = [];\n for (const [, cached] of cache) {\n if (visibleKeys.has(cached.key)) continue;\n if (!intersectsBounds(cached.bounds, viewBounds)) continue;\n fallbackTiles.push(cached);\n }\n fallbackTiles.sort((a, b) => a.tier - b.tier);\n\n for (const cached of fallbackTiles) {\n cached.lastUsed = frameSerial;\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, cached.texture);\n gl.uniform4f(tileProgram.uBounds, cached.bounds[0], cached.bounds[1], cached.bounds[2], cached.bounds[3]);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n }\n\n let renderedTiles = 0;\n const missingTiles: ScheduledTile[] = [];\n for (const tile of visible) {\n const cached = cache.get(tile.key);\n if (!cached) {\n missingTiles.push(tile);\n continue;\n }\n cached.lastUsed = frameSerial;\n gl.activeTexture(gl.TEXTURE0);\n gl.bindTexture(gl.TEXTURE_2D, cached.texture);\n gl.uniform4f(tileProgram.uBounds, cached.bounds[0], cached.bounds[1], cached.bounds[2], cached.bounds[3]);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n renderedTiles += 1;\n }\n\n const tilesToSchedule: ScheduledTile[] = missingTiles.slice();\n const PREFETCH_DISTANCE_PENALTY = 1e6;\n const prefetchTiers: number[] = [];\n if (tier > 0) prefetchTiers.push(tier - 1);\n if (tier < source.maxTierZoom) prefetchTiers.push(tier + 1);\n for (const prefetchTier of prefetchTiers) {\n const prefetchCandidates = getVisibleTilesForTier(prefetchTier);\n for (const tile of prefetchCandidates) {\n if (cache.has(tile.key)) continue;\n tile.distance2 += PREFETCH_DISTANCE_PENALTY;\n tilesToSchedule.push(tile);\n }\n }\n tileScheduler.schedule(tilesToSchedule);\n\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.bindVertexArray(null);\n\n let renderedPoints = 0;\n if (pointCount > 0) {\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n gl.useProgram(pointProgram.program);\n gl.bindVertexArray(pointProgram.vao);\n gl.uniformMatrix3fv(pointProgram.uCamera, false, camera.getMatrix());\n gl.uniform1f(pointProgram.uPointSize, pointSizePx);\n gl.uniform1f(pointProgram.uPointStrokeScale, pointStrokeScale);\n gl.uniform1f(pointProgram.uPointInnerFillAlpha, pointInnerFillOpacity);\n gl.uniform1f(pointProgram.uPaletteSize, pointPaletteSize);\n gl.uniform1i(pointProgram.uPalette, 1);\n gl.activeTexture(gl.TEXTURE1);\n gl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n if (usePointIndices) {\n gl.drawElements(gl.POINTS, pointCount, gl.UNSIGNED_INT, 0);\n } else {\n gl.drawArrays(gl.POINTS, 0, pointCount);\n }\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.bindVertexArray(null);\n renderedPoints = pointCount;\n }\n\n return {\n tier,\n visible: visible.length,\n rendered: renderedTiles,\n points: renderedPoints,\n fallback: fallbackTiles.length,\n cacheHits: renderedTiles,\n cacheMisses: missingTiles.length,\n drawCalls: fallbackTiles.length + renderedTiles + (renderedPoints > 0 ? 1 : 0),\n };\n}\n","import { createProgram, requireUniformLocation } from \"../core/gl-utils\";\nimport type { PointProgram, TileVertexProgram } from \"./wsi-renderer-types\";\n\nexport function initTileProgram(gl: WebGL2RenderingContext): TileVertexProgram {\n const vertex = `#version 300 es\n precision highp float;\n in vec2 aUnit;\n in vec2 aUv;\n uniform mat3 uCamera;\n uniform vec4 uBounds;\n out vec2 vUv;\n void main() {\n vec2 world = vec2(\n mix(uBounds.x, uBounds.z, aUnit.x),\n mix(uBounds.y, uBounds.w, aUnit.y)\n );\n vec3 clip = uCamera * vec3(world, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n vUv = aUv;\n }`;\n\n const fragment = `#version 300 es\n precision highp float;\n in vec2 vUv;\n uniform sampler2D uTexture;\n uniform float uBrightness;\n uniform float uContrast;\n uniform float uSaturation;\n out vec4 outColor;\n void main() {\n vec4 color = texture(uTexture, vUv);\n\n color.rgb = clamp(\n (uContrast + 1.0) * color.rgb - (uContrast / 2.0),\n vec3(0.0),\n vec3(1.0)\n );\n\n float saturation = uSaturation + 1.0;\n float sr = (1.0 - saturation) * 0.2126;\n float sg = (1.0 - saturation) * 0.7152;\n float sb = (1.0 - saturation) * 0.0722;\n mat3 saturationMatrix = mat3(\n sr + saturation, sr, sr,\n sg, sg + saturation, sg,\n sb, sb, sb + saturation\n );\n color.rgb = clamp(saturationMatrix * color.rgb, vec3(0.0), vec3(1.0));\n\n color.rgb = clamp(color.rgb + uBrightness, vec3(0.0), vec3(1.0));\n outColor = color;\n }`;\n\n const program = createProgram(gl, vertex, fragment);\n const uCamera = requireUniformLocation(gl, program, \"uCamera\");\n const uBounds = requireUniformLocation(gl, program, \"uBounds\");\n const uTexture = requireUniformLocation(gl, program, \"uTexture\");\n const uBrightness = requireUniformLocation(gl, program, \"uBrightness\");\n const uContrast = requireUniformLocation(gl, program, \"uContrast\");\n const uSaturation = requireUniformLocation(gl, program, \"uSaturation\");\n\n const vao = gl.createVertexArray();\n const vbo = gl.createBuffer();\n if (!vao || !vbo) {\n throw new Error(\"buffer allocation failed\");\n }\n\n gl.bindVertexArray(vao);\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1]), gl.STATIC_DRAW);\n\n const aUnit = gl.getAttribLocation(program, \"aUnit\");\n const aUv = gl.getAttribLocation(program, \"aUv\");\n if (aUnit < 0 || aUv < 0) {\n throw new Error(\"tile attribute lookup failed\");\n }\n gl.enableVertexAttribArray(aUnit);\n gl.enableVertexAttribArray(aUv);\n gl.vertexAttribPointer(aUnit, 2, gl.FLOAT, false, 16, 0);\n gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);\n\n gl.bindVertexArray(null);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n\n return {\n program,\n vao,\n vbo,\n uCamera,\n uBounds,\n uTexture,\n uBrightness,\n uContrast,\n uSaturation,\n };\n}\n\nexport function initPointProgram(gl: WebGL2RenderingContext): PointProgram {\n const pointVertex = `#version 300 es\n precision highp float;\n in vec2 aPosition;\n in uint aTerm;\n in uint aFillMode;\n uniform mat3 uCamera;\n uniform float uPointSize;\n flat out uint vTerm;\n flat out uint vFillMode;\n void main() {\n vec3 clip = uCamera * vec3(aPosition, 1.0);\n gl_Position = vec4(clip.xy, 0.0, 1.0);\n gl_PointSize = uPointSize;\n vTerm = aTerm;\n vFillMode = aFillMode;\n }`;\n\n const pointFragment = `#version 300 es\n precision highp float;\n flat in uint vTerm;\n flat in uint vFillMode;\n uniform sampler2D uPalette;\n uniform float uPaletteSize;\n uniform float uPointSize;\n uniform float uPointStrokeScale;\n uniform float uPointInnerFillAlpha;\n out vec4 outColor;\n void main() {\n vec2 pc = gl_PointCoord * 2.0 - 1.0;\n float r = length(pc);\n if (r > 1.0) discard;\n\n float idx = clamp(float(vTerm), 0.0, max(0.0, uPaletteSize - 1.0));\n vec2 uv = vec2((idx + 0.5) / uPaletteSize, 0.5);\n vec4 color = texture(uPalette, uv);\n if (color.a <= 0.0) discard;\n\n float aa = 1.5 / max(1.0, uPointSize);\n float outerMask = 1.0 - smoothstep(1.0 - aa, 1.0 + aa, r);\n if (vFillMode != 0u) {\n float alpha = outerMask * color.a;\n if (alpha <= 0.001) discard;\n outColor = vec4(color.rgb * alpha, alpha);\n } else {\n float s = uPointStrokeScale;\n float ringWidth = clamp(3.0 * s / max(1.0, uPointSize), 0.12 * s, 0.62 * s);\n float innerRadius = 1.0 - ringWidth;\n float innerMask = smoothstep(innerRadius - aa, innerRadius + aa, r);\n float ringAlpha = outerMask * innerMask * color.a;\n float fillAlpha = outerMask * (1.0 - innerMask) * clamp(uPointInnerFillAlpha, 0.0, 1.0);\n float alpha = ringAlpha + fillAlpha;\n if (alpha <= 0.001) discard;\n // Premultiplied alpha output: inner fill is black, so it only contributes alpha.\n outColor = vec4(color.rgb * ringAlpha, alpha);\n }\n }`;\n\n const program = createProgram(gl, pointVertex, pointFragment);\n const uCamera = requireUniformLocation(gl, program, \"uCamera\");\n const uPointSize = requireUniformLocation(gl, program, \"uPointSize\");\n const uPointStrokeScale = requireUniformLocation(gl, program, \"uPointStrokeScale\");\n const uPointInnerFillAlpha = requireUniformLocation(gl, program, \"uPointInnerFillAlpha\");\n const uPalette = requireUniformLocation(gl, program, \"uPalette\");\n const uPaletteSize = requireUniformLocation(gl, program, \"uPaletteSize\");\n\n const vao = gl.createVertexArray();\n const posBuffer = gl.createBuffer();\n const termBuffer = gl.createBuffer();\n const fillModeBuffer = gl.createBuffer();\n const indexBuffer = gl.createBuffer();\n const paletteTexture = gl.createTexture();\n if (!vao || !posBuffer || !termBuffer || !fillModeBuffer || !indexBuffer || !paletteTexture) {\n throw new Error(\"point buffer allocation failed\");\n }\n\n gl.bindVertexArray(vao);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n const posLoc = gl.getAttribLocation(program, \"aPosition\");\n if (posLoc < 0) {\n throw new Error(\"point position attribute not found\");\n }\n gl.enableVertexAttribArray(posLoc);\n gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, termBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n const termLoc = gl.getAttribLocation(program, \"aTerm\");\n if (termLoc < 0) {\n throw new Error(\"point term attribute not found\");\n }\n gl.enableVertexAttribArray(termLoc);\n gl.vertexAttribIPointer(termLoc, 1, gl.UNSIGNED_SHORT, 0, 0);\n\n gl.bindBuffer(gl.ARRAY_BUFFER, fillModeBuffer);\n gl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n const fillModeLoc = gl.getAttribLocation(program, \"aFillMode\");\n if (fillModeLoc < 0) {\n throw new Error(\"point fill mode attribute not found\");\n }\n gl.enableVertexAttribArray(fillModeLoc);\n gl.vertexAttribIPointer(fillModeLoc, 1, gl.UNSIGNED_BYTE, 0, 0);\n\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\n gl.bindVertexArray(null);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n gl.bindTexture(gl.TEXTURE_2D, paletteTexture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([160, 160, 160, 255]));\n gl.bindTexture(gl.TEXTURE_2D, null);\n\n return {\n program,\n vao,\n posBuffer,\n termBuffer,\n fillModeBuffer,\n indexBuffer,\n paletteTexture,\n uCamera,\n uPointSize,\n uPointStrokeScale,\n uPointInnerFillAlpha,\n uPalette,\n uPaletteSize,\n };\n}\n","import { clamp } from \"./utils\";\nimport { nowMs } from \"./utils\";\nimport type { ViewAnimationRuntimeState, ViewAnimationStartOptions } from \"./wsi-renderer-types\";\n\nexport function cancelViewAnimation(state: ViewAnimationRuntimeState): void {\n state.animation = null;\n if (state.frame !== null) {\n cancelAnimationFrame(state.frame);\n state.frame = null;\n }\n}\n\nexport function startViewAnimation(options: ViewAnimationStartOptions): void {\n const { state, camera, target, durationMs, easing, onUpdate } = options;\n const from = camera.getViewState();\n cancelViewAnimation(state);\n state.animation = {\n startMs: nowMs(),\n durationMs: Math.max(0, durationMs),\n from,\n to: target,\n easing,\n };\n\n const step = (): void => {\n const animation = state.animation;\n if (!animation) return;\n\n const elapsed = Math.max(0, nowMs() - animation.startMs);\n const rawT = animation.durationMs <= 0 ? 1 : clamp(elapsed / animation.durationMs, 0, 1);\n let eased = rawT;\n try {\n eased = animation.easing(rawT);\n } catch {\n eased = rawT;\n }\n if (!Number.isFinite(eased)) {\n eased = rawT;\n }\n eased = clamp(eased, 0, 1);\n\n camera.setViewState({\n zoom: animation.from.zoom + (animation.to.zoom - animation.from.zoom) * eased,\n offsetX: animation.from.offsetX + (animation.to.offsetX - animation.from.offsetX) * eased,\n offsetY: animation.from.offsetY + (animation.to.offsetY - animation.from.offsetY) * eased,\n rotationDeg: animation.from.rotationDeg + (animation.to.rotationDeg - animation.from.rotationDeg) * eased,\n });\n onUpdate();\n\n if (rawT >= 1) {\n state.animation = null;\n state.frame = null;\n return;\n }\n\n state.frame = requestAnimationFrame(step);\n };\n\n state.frame = requestAnimationFrame(step);\n}\n","import type { OrthoCamera } from \"../core/ortho-camera\";\nimport type { WsiImageSource, WsiViewState } from \"./types\";\nimport { clamp } from \"./utils\";\nimport { toRadians } from \"./wsi-normalize\";\n\nexport function resolveDefaultZoomBounds(fitZoom: number): { minZoom: number; maxZoom: number } {\n const minZoom = Math.max(fitZoom * 0.5, 1e-6);\n const maxZoom = Math.max(1, fitZoom * 8);\n return {\n minZoom,\n maxZoom: Math.max(minZoom, maxZoom),\n };\n}\n\nexport function resolveZoomBounds(fitZoom: number, minZoomOverride: number | null, maxZoomOverride: number | null): { minZoom: number; maxZoom: number } {\n const defaults = resolveDefaultZoomBounds(fitZoom);\n let minZoom = minZoomOverride ?? defaults.minZoom;\n let maxZoom = maxZoomOverride ?? defaults.maxZoom;\n minZoom = Math.max(1e-6, minZoom);\n maxZoom = Math.max(1e-6, maxZoom);\n if (minZoom > maxZoom) {\n minZoom = maxZoom;\n }\n return { minZoom, maxZoom };\n}\n\nexport function resolveTargetViewState(\n camera: OrthoCamera,\n minZoom: number,\n maxZoom: number,\n next: Partial<WsiViewState>,\n clampViewState: () => void,\n): WsiViewState {\n const current = camera.getViewState();\n const candidate: WsiViewState = {\n zoom: typeof next.zoom === \"number\" && Number.isFinite(next.zoom) ? clamp(next.zoom, minZoom, maxZoom) : current.zoom,\n offsetX: typeof next.offsetX === \"number\" && Number.isFinite(next.offsetX) ? next.offsetX : current.offsetX,\n offsetY: typeof next.offsetY === \"number\" && Number.isFinite(next.offsetY) ? next.offsetY : current.offsetY,\n rotationDeg: typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg) ? next.rotationDeg : current.rotationDeg,\n };\n\n camera.setViewState(candidate);\n clampViewState();\n const target = camera.getViewState();\n camera.setViewState(current);\n return target;\n}\n\nexport function computeFitToImageTarget(\n source: WsiImageSource,\n viewportWidth: number,\n viewportHeight: number,\n minZoom: number,\n maxZoom: number,\n): { fitZoom: number; target: WsiViewState } {\n const zoom = Math.min(viewportWidth / source.width, viewportHeight / source.height);\n const safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n const clampedZoom = clamp(safeZoom, minZoom, maxZoom);\n const visibleWorldW = viewportWidth / clampedZoom;\n const visibleWorldH = viewportHeight / clampedZoom;\n\n return {\n fitZoom: safeZoom,\n target: {\n zoom: clampedZoom,\n offsetX: (source.width - visibleWorldW) * 0.5,\n offsetY: (source.height - visibleWorldH) * 0.5,\n rotationDeg: 0,\n },\n };\n}\n\nexport function computeZoomByTarget(\n camera: OrthoCamera,\n minZoom: number,\n maxZoom: number,\n factor: number,\n screenX: number,\n screenY: number,\n): Partial<WsiViewState> | null {\n const state = camera.getViewState();\n const nextZoom = clamp(state.zoom * factor, minZoom, maxZoom);\n if (nextZoom === state.zoom) return null;\n\n const [worldX, worldY] = camera.screenToWorld(screenX, screenY);\n const vp = camera.getViewportSize();\n const dx = screenX - vp.width * 0.5;\n const dy = screenY - vp.height * 0.5;\n const rad = toRadians(state.rotationDeg);\n const cos = Math.cos(rad);\n const sin = Math.sin(rad);\n const worldDx = (dx / nextZoom) * cos - (dy / nextZoom) * sin;\n const worldDy = (dx / nextZoom) * sin + (dy / nextZoom) * cos;\n const nextCenterX = worldX - worldDx;\n const nextCenterY = worldY - worldDy;\n\n return {\n zoom: nextZoom,\n offsetX: nextCenterX - vp.width / (2 * nextZoom),\n offsetY: nextCenterY - vp.height / (2 * nextZoom),\n };\n}\n","import { OrthoCamera } from \"../core/ortho-camera\";\nimport { TileScheduler } from \"./tile-scheduler\";\nimport type { WsiImageColorSettings, WsiImageSource, WsiPointData, WsiRenderStats, WsiViewState } from \"./types\";\nimport { clamp, isSameViewState, nowMs } from \"./utils\";\nimport { addRendererCanvasEventListeners, type RendererCanvasHandlers, removeRendererCanvasEventListeners, resizeCanvasViewport } from \"./wsi-canvas-lifecycle\";\nimport { cancelDrag as cancelInputDrag, createRendererInputHandlers } from \"./wsi-input-handlers\";\nimport { destroyRenderer, handleContextLost } from \"./wsi-lifecycle-ops\";\nimport {\n arePointSizeStopsEqual,\n clonePointSizeStops,\n DEFAULT_POINT_SIZE_STOPS,\n DEFAULT_ROTATION_DRAG_SENSITIVITY,\n linearEasing,\n MAX_POINT_SIZE_PX,\n MIN_POINT_SIZE_PX,\n normalizePointInnerFillOpacity,\n normalizePointSizeStops,\n normalizeStrokeScale,\n normalizeTransitionEasing,\n normalizeViewTransitionDuration,\n normalizeZoomOverride,\n resolvePointSizeByZoomStops,\n toNormalizedImageColorSettings,\n} from \"./wsi-normalize\";\nimport type { PointBufferRuntime } from \"./wsi-point-data\";\nimport { setPointData as setManagedPointData, setPointPalette as setManagedPointPalette } from \"./wsi-point-data\";\nimport { renderFrame } from \"./wsi-render-pass\";\nimport type {\n CachedTile,\n InteractionState,\n NormalizedImageColorSettings,\n PointProgram,\n PointSizeByZoom,\n PointSizeStop,\n TileVertexProgram,\n ViewAnimationRuntimeState,\n WorldPoint,\n WsiTileErrorEvent,\n WsiTileRendererOptions,\n WsiViewTransitionOptions,\n} from \"./wsi-renderer-types\";\nimport { initPointProgram, initTileProgram } from \"./wsi-shaders\";\nimport { handleTileLoaded as cacheTileLoaded } from \"./wsi-tile-cache\";\nimport {\n clampViewState as clampManagedViewState,\n getViewBounds as getManagedViewBounds,\n getVisibleTiles as getManagedVisibleTiles,\n getVisibleTilesForTier as getManagedVisibleTilesForTier,\n intersectsBounds as intersectsManagedBounds,\n} from \"./wsi-tile-visibility\";\nimport { cancelViewAnimation as cancelManagedViewAnimation, startViewAnimation } from \"./wsi-view-animation\";\nimport { computeFitToImageTarget, computeZoomByTarget, resolveTargetViewState as resolveManagedTargetViewState, resolveZoomBounds } from \"./wsi-view-ops\";\n\nexport type { PointSizeByZoom, WsiTileErrorEvent, WsiTileRendererOptions, WsiTileSchedulerConfig, WsiViewTransitionOptions } from \"./wsi-renderer-types\";\n\nexport class WsiTileRenderer {\n private readonly canvas: HTMLCanvasElement;\n private readonly source: WsiImageSource;\n private readonly gl: WebGL2RenderingContext;\n private readonly camera = new OrthoCamera();\n private readonly onViewStateChange?: (next: WsiViewState) => void;\n private readonly onStats?: (stats: WsiRenderStats) => void;\n private readonly onTileError?: (event: WsiTileErrorEvent) => void;\n private readonly onContextLost?: () => void;\n private readonly onContextRestored?: () => void;\n private readonly resizeObserver: ResizeObserver;\n private tileProgram: TileVertexProgram;\n private pointProgram: PointProgram;\n private readonly tileScheduler: TileScheduler;\n\n private authToken: string;\n private destroyed = false;\n private contextLost = false;\n private frame: number | null = null;\n private frameSerial = 0;\n private interactionState: InteractionState = {\n dragging: false,\n mode: \"none\",\n rotateLastAngleRad: null,\n pointerId: null,\n lastPointerX: 0,\n lastPointerY: 0,\n };\n private interactionLocked = false;\n private ctrlDragRotate = true;\n private rotationDragSensitivityDegPerPixel = DEFAULT_ROTATION_DRAG_SENSITIVITY;\n private maxCacheTiles: number;\n private fitZoom = 1;\n private minZoom = 1e-6;\n private maxZoom = 1;\n private minZoomOverride: number | null = null;\n private maxZoomOverride: number | null = null;\n private viewTransitionDurationMs = 0;\n private viewTransitionEasing: (t: number) => number = linearEasing;\n private viewAnimationState: ViewAnimationRuntimeState = {\n animation: null,\n frame: null,\n };\n private pointCount = 0;\n private usePointIndices = false;\n private pointBuffersDirty = true;\n private pointPaletteSize = 1;\n private pointSizeStops: PointSizeStop[] = clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n private pointStrokeScale = 1.0;\n private pointInnerFillOpacity = 0;\n private imageColorSettings: NormalizedImageColorSettings = {\n brightness: 0,\n contrast: 0,\n saturation: 0,\n };\n private lastPointData: WsiPointData | null = null;\n private lastPointPalette: Uint8Array<ArrayBufferLike> | null = null;\n private zeroFillModes: Uint8Array<ArrayBufferLike> = new Uint8Array(0);\n private cache = new Map<string, CachedTile>();\n\n private readonly boundPointerDown: (event: PointerEvent) => void;\n private readonly boundPointerMove: (event: PointerEvent) => void;\n private readonly boundPointerUp: (event: PointerEvent) => void;\n private readonly boundWheel: (event: WheelEvent) => void;\n private readonly boundDoubleClick: (event: MouseEvent) => void;\n private readonly boundContextMenu: (event: MouseEvent) => void;\n private readonly boundContextLost: (event: Event) => void;\n private readonly boundContextRestored: (event: Event) => void;\n\n private getCanvasHandlers(): RendererCanvasHandlers {\n return {\n pointerDown: this.boundPointerDown,\n pointerMove: this.boundPointerMove,\n pointerUp: this.boundPointerUp,\n wheel: this.boundWheel,\n doubleClick: this.boundDoubleClick,\n contextMenu: this.boundContextMenu,\n contextLost: this.boundContextLost,\n contextRestored: this.boundContextRestored,\n };\n }\n\n constructor(canvas: HTMLCanvasElement, source: WsiImageSource, options: WsiTileRendererOptions = {}) {\n this.canvas = canvas;\n this.source = source;\n this.onViewStateChange = options.onViewStateChange;\n this.onStats = options.onStats;\n this.onTileError = options.onTileError;\n this.onContextLost = options.onContextLost;\n this.onContextRestored = options.onContextRestored;\n this.authToken = options.authToken ?? \"\";\n this.maxCacheTiles = Math.max(32, Math.floor(options.maxCacheTiles ?? 320));\n this.ctrlDragRotate = options.ctrlDragRotate ?? true;\n this.rotationDragSensitivityDegPerPixel =\n typeof options.rotationDragSensitivityDegPerPixel === \"number\" && Number.isFinite(options.rotationDragSensitivityDegPerPixel)\n ? Math.max(0, options.rotationDragSensitivityDegPerPixel)\n : DEFAULT_ROTATION_DRAG_SENSITIVITY;\n this.pointSizeStops = normalizePointSizeStops(options.pointSizeByZoom);\n this.pointStrokeScale = normalizeStrokeScale(options.pointStrokeScale);\n this.pointInnerFillOpacity = normalizePointInnerFillOpacity(options.pointInnerFillOpacity);\n this.imageColorSettings = toNormalizedImageColorSettings(options.imageColorSettings);\n this.minZoomOverride = normalizeZoomOverride(options.minZoom);\n this.maxZoomOverride = normalizeZoomOverride(options.maxZoom);\n this.viewTransitionDurationMs = normalizeViewTransitionDuration(options.viewTransition?.duration);\n this.viewTransitionEasing = normalizeTransitionEasing(options.viewTransition?.easing);\n\n const gl = canvas.getContext(\"webgl2\", {\n alpha: false,\n antialias: false,\n depth: false,\n stencil: false,\n powerPreference: \"high-performance\",\n });\n if (!gl) {\n throw new Error(\"WebGL2 not supported\");\n }\n this.gl = gl;\n\n this.tileProgram = initTileProgram(this.gl);\n this.pointProgram = initPointProgram(this.gl);\n this.tileScheduler = new TileScheduler({\n authToken: this.authToken,\n maxConcurrency: options.tileScheduler?.maxConcurrency ?? 12,\n maxRetries: options.tileScheduler?.maxRetries ?? 2,\n retryBaseDelayMs: options.tileScheduler?.retryBaseDelayMs ?? 120,\n retryMaxDelayMs: options.tileScheduler?.retryMaxDelayMs ?? 1200,\n onTileLoad: (tile, bitmap) =>\n cacheTileLoaded({\n gl: this.gl,\n cache: this.cache,\n tile,\n bitmap,\n frameSerial: this.frameSerial,\n maxCacheTiles: this.maxCacheTiles,\n destroyed: this.destroyed,\n contextLost: this.contextLost,\n requestRender: () => this.requestRender(),\n }),\n onTileError: (tile, error, attemptCount) => {\n this.onTileError?.({ tile, error, attemptCount });\n console.warn(\"tile load failed\", tile.url, error);\n },\n });\n\n this.resizeObserver = new ResizeObserver(() => this.resize());\n this.resizeObserver.observe(canvas);\n\n const inputHandlers = createRendererInputHandlers({\n canvas: this.canvas,\n state: this.interactionState,\n getInteractionLocked: () => this.interactionLocked,\n getCtrlDragRotate: () => this.ctrlDragRotate,\n getRotationDragSensitivityDegPerPixel: () => this.rotationDragSensitivityDegPerPixel,\n cancelViewAnimation: () => this.cancelViewAnimation(),\n camera: this.camera,\n source: this.source,\n emitViewState: () => this.onViewStateChange?.(this.camera.getViewState()),\n requestRender: () => this.requestRender(),\n zoomBy: (factor, x, y) => this.zoomBy(factor, x, y),\n });\n this.boundPointerDown = inputHandlers.pointerDown;\n this.boundPointerMove = inputHandlers.pointerMove;\n this.boundPointerUp = inputHandlers.pointerUp;\n this.boundWheel = inputHandlers.wheel;\n this.boundDoubleClick = inputHandlers.doubleClick;\n this.boundContextMenu = inputHandlers.contextMenu;\n this.boundContextLost = (event: Event) => this.onWebGlContextLost(event);\n this.boundContextRestored = (event: Event) => this.onWebGlContextRestored(event);\n\n addRendererCanvasEventListeners(canvas, this.getCanvasHandlers());\n\n this.fitToImage({ duration: 0 });\n this.resize();\n }\n\n private applyZoomBounds(): void {\n const bounds = resolveZoomBounds(this.fitZoom, this.minZoomOverride, this.maxZoomOverride);\n this.minZoom = bounds.minZoom;\n this.maxZoom = bounds.maxZoom;\n }\n\n private resolveTargetViewState(next: Partial<WsiViewState>): WsiViewState {\n return resolveManagedTargetViewState(this.camera, this.minZoom, this.maxZoom, next, () => clampManagedViewState(this.camera, this.source));\n }\n\n private cancelViewAnimation(): void {\n cancelManagedViewAnimation(this.viewAnimationState);\n }\n\n private startViewAnimation(target: WsiViewState, durationMs: number, easing: (t: number) => number): void {\n startViewAnimation({\n state: this.viewAnimationState,\n camera: this.camera,\n target,\n durationMs,\n easing,\n onUpdate: () => {\n clampManagedViewState(this.camera, this.source);\n this.onViewStateChange?.(this.camera.getViewState());\n this.requestRender();\n },\n });\n }\n\n private getPointBufferRuntime(): PointBufferRuntime {\n return {\n pointCount: this.pointCount,\n usePointIndices: this.usePointIndices,\n pointBuffersDirty: this.pointBuffersDirty,\n lastPointData: this.lastPointData,\n zeroFillModes: this.zeroFillModes,\n lastPointPalette: this.lastPointPalette,\n pointPaletteSize: this.pointPaletteSize,\n };\n }\n\n private applyPointBufferRuntime(runtime: PointBufferRuntime): void {\n this.pointCount = runtime.pointCount;\n this.usePointIndices = runtime.usePointIndices;\n this.pointBuffersDirty = runtime.pointBuffersDirty;\n this.lastPointData = runtime.lastPointData;\n this.zeroFillModes = runtime.zeroFillModes;\n this.lastPointPalette = runtime.lastPointPalette;\n this.pointPaletteSize = runtime.pointPaletteSize;\n }\n\n private applyViewStateAndRender(next: WsiViewState, cancelAnimation = true): void {\n if (cancelAnimation) {\n this.cancelViewAnimation();\n }\n this.camera.setViewState(next);\n this.onViewStateChange?.(this.camera.getViewState());\n this.requestRender();\n }\n\n setAuthToken(token: string): void {\n this.authToken = String(token ?? \"\");\n this.tileScheduler.setAuthToken(this.authToken);\n }\n\n setZoomRange(minZoom: number | null | undefined, maxZoom: number | null | undefined): void {\n const nextMinOverride = normalizeZoomOverride(minZoom);\n const nextMaxOverride = normalizeZoomOverride(maxZoom);\n if (this.minZoomOverride === nextMinOverride && this.maxZoomOverride === nextMaxOverride) {\n return;\n }\n\n this.minZoomOverride = nextMinOverride;\n this.maxZoomOverride = nextMaxOverride;\n this.applyZoomBounds();\n\n const target = this.resolveTargetViewState({});\n const current = this.camera.getViewState();\n if (isSameViewState(current, target)) {\n return;\n }\n this.applyViewStateAndRender(target);\n }\n\n setViewTransition(options: WsiViewTransitionOptions | null | undefined): void {\n this.viewTransitionDurationMs = normalizeViewTransitionDuration(options?.duration);\n this.viewTransitionEasing = normalizeTransitionEasing(options?.easing);\n }\n\n setViewState(next: Partial<WsiViewState>, transition?: WsiViewTransitionOptions): void {\n const target = this.resolveTargetViewState(next);\n const current = this.camera.getViewState();\n if (isSameViewState(current, target)) return;\n\n const durationMs = normalizeViewTransitionDuration(transition?.duration ?? this.viewTransitionDurationMs);\n const easing = normalizeTransitionEasing(transition?.easing ?? this.viewTransitionEasing);\n if (durationMs <= 0) {\n this.applyViewStateAndRender(target);\n return;\n }\n\n this.startViewAnimation(target, durationMs, easing);\n }\n\n getViewState(): WsiViewState {\n return this.camera.getViewState();\n }\n\n getZoomRange(): { minZoom: number; maxZoom: number } {\n return { minZoom: this.minZoom, maxZoom: this.maxZoom };\n }\n\n setPointPalette(colors: Uint8Array | null | undefined): void {\n const nextRuntime = setManagedPointPalette(this.getPointBufferRuntime(), this.gl, this.pointProgram, this.contextLost, colors);\n this.applyPointBufferRuntime(nextRuntime);\n if (!colors || colors.length === 0) {\n return;\n }\n this.requestRender();\n }\n\n setPointData(points: WsiPointData | null | undefined): void {\n const nextRuntime = setManagedPointData(this.getPointBufferRuntime(), this.gl, this.pointProgram, this.contextLost, points);\n this.applyPointBufferRuntime(nextRuntime);\n this.requestRender();\n }\n\n setInteractionLock(locked: boolean): void {\n const next = Boolean(locked);\n if (this.interactionLocked === next) return;\n this.interactionLocked = next;\n if (next) this.cancelDrag();\n }\n\n setPointSizeByZoom(pointSizeByZoom: PointSizeByZoom | null | undefined): void {\n const nextStops = normalizePointSizeStops(pointSizeByZoom);\n if (arePointSizeStopsEqual(this.pointSizeStops, nextStops)) return;\n this.pointSizeStops = nextStops;\n this.requestRender();\n }\n\n setPointStrokeScale(scale: number | null | undefined): void {\n const next = normalizeStrokeScale(scale);\n if (this.pointStrokeScale === next) return;\n this.pointStrokeScale = next;\n this.requestRender();\n }\n\n setPointInnerFillOpacity(opacity: number | null | undefined): void {\n const next = normalizePointInnerFillOpacity(opacity);\n if (this.pointInnerFillOpacity === next) return;\n this.pointInnerFillOpacity = next;\n this.requestRender();\n }\n\n setImageColorSettings(settings: WsiImageColorSettings | null | undefined): void {\n const next = toNormalizedImageColorSettings(settings);\n const prev = this.imageColorSettings;\n if (prev.brightness === next.brightness && prev.contrast === next.contrast && prev.saturation === next.saturation) {\n return;\n }\n this.imageColorSettings = next;\n this.requestRender();\n }\n\n cancelDrag(): void {\n cancelInputDrag(this.canvas, this.interactionState);\n }\n\n screenToWorld(clientX: number, clientY: number): [number, number] {\n const rect = this.canvas.getBoundingClientRect();\n const sx = clientX - rect.left;\n const sy = clientY - rect.top;\n return this.camera.screenToWorld(sx, sy);\n }\n\n worldToScreen(worldX: number, worldY: number): [number, number] {\n return this.camera.worldToScreen(worldX, worldY);\n }\n\n setViewCenter(worldX: number, worldY: number, transition?: WsiViewTransitionOptions): void {\n if (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n const state = this.camera.getViewState();\n const zoom = Math.max(1e-6, state.zoom);\n const vp = this.camera.getViewportSize();\n this.setViewState(\n {\n offsetX: worldX - vp.width / (2 * zoom),\n offsetY: worldY - vp.height / (2 * zoom),\n },\n transition\n );\n }\n\n getViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n return this.camera.getViewCorners();\n }\n\n resetRotation(transition?: WsiViewTransitionOptions): void {\n const state = this.camera.getViewState();\n if (Math.abs(state.rotationDeg) < 1e-6) return;\n this.setViewState({ rotationDeg: 0 }, transition);\n }\n\n getPointSizeByZoom(): number {\n const zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n const continuousZoom = this.source.maxTierZoom + Math.log2(zoom);\n const size = resolvePointSizeByZoomStops(continuousZoom, this.pointSizeStops);\n return clamp(size, MIN_POINT_SIZE_PX, MAX_POINT_SIZE_PX);\n }\n\n fitToImage(transition?: WsiViewTransitionOptions): void {\n const rect = this.canvas.getBoundingClientRect();\n const vw = Math.max(1, rect.width || 1);\n const vh = Math.max(1, rect.height || 1);\n const fitTarget = computeFitToImageTarget(this.source, vw, vh, this.minZoom, this.maxZoom);\n this.fitZoom = fitTarget.fitZoom;\n this.applyZoomBounds();\n this.setViewState(fitTarget.target, transition);\n }\n\n zoomBy(factor: number, screenX: number, screenY: number, transition?: WsiViewTransitionOptions): void {\n const target = computeZoomByTarget(this.camera, this.minZoom, this.maxZoom, factor, screenX, screenY);\n if (!target) return;\n this.setViewState(target, transition);\n }\n\n render(): void {\n if (this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n const frameStartMs = this.onStats ? nowMs() : 0;\n this.frameSerial += 1;\n\n const result = renderFrame({\n gl: this.gl,\n camera: this.camera,\n source: this.source,\n cache: this.cache,\n frameSerial: this.frameSerial,\n tileProgram: this.tileProgram,\n pointProgram: this.pointProgram,\n imageColorSettings: this.imageColorSettings,\n pointCount: this.pointCount,\n usePointIndices: this.usePointIndices,\n pointPaletteSize: this.pointPaletteSize,\n pointStrokeScale: this.pointStrokeScale,\n pointInnerFillOpacity: this.pointInnerFillOpacity,\n pointSizePx: this.getPointSizeByZoom(),\n tileScheduler: this.tileScheduler,\n getVisibleTiles: () => getManagedVisibleTiles(this.camera, this.source),\n getVisibleTilesForTier: tier => getManagedVisibleTilesForTier(this.camera, this.source, tier),\n getViewBounds: () => getManagedViewBounds(this.camera),\n intersectsBounds: intersectsManagedBounds,\n });\n if (this.onStats) {\n const schedulerStats = this.tileScheduler.getSnapshot();\n this.onStats({\n tier: result.tier,\n visible: result.visible,\n rendered: result.rendered,\n points: result.points,\n fallback: result.fallback,\n cache: this.cache.size,\n inflight: schedulerStats.inflight,\n queued: schedulerStats.queued,\n retries: schedulerStats.retries,\n failed: schedulerStats.failed,\n aborted: schedulerStats.aborted,\n cacheHits: result.cacheHits,\n cacheMisses: result.cacheMisses,\n drawCalls: result.drawCalls,\n frameMs: nowMs() - frameStartMs,\n });\n }\n }\n\n requestRender(): void {\n if (this.frame !== null || this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n this.frame = requestAnimationFrame(() => {\n this.frame = null;\n this.render();\n });\n }\n\n resize(): void {\n resizeCanvasViewport(this.canvas, this.gl, this.camera);\n this.requestRender();\n }\n\n private onWebGlContextLost(event: Event): void {\n const result = handleContextLost({\n event,\n destroyed: this.destroyed,\n contextLost: this.contextLost,\n frame: this.frame,\n cancelViewAnimation: () => this.cancelViewAnimation(),\n cancelDrag: () => this.cancelDrag(),\n tileScheduler: this.tileScheduler,\n cache: this.cache,\n onContextLost: this.onContextLost,\n });\n if (!result.handled) return;\n this.frame = result.frame;\n this.contextLost = true;\n this.pointBuffersDirty = true;\n }\n\n private onWebGlContextRestored(_event: Event): void {\n if (this.destroyed) return;\n this.contextLost = false;\n this.cache.clear();\n\n this.tileProgram = initTileProgram(this.gl);\n this.pointProgram = initPointProgram(this.gl);\n this.pointBuffersDirty = true;\n\n if (this.lastPointPalette && this.lastPointPalette.length > 0) {\n this.setPointPalette(this.lastPointPalette);\n }\n if (this.lastPointData) {\n this.setPointData(this.lastPointData);\n } else {\n this.pointCount = 0;\n }\n\n this.resize();\n this.requestRender();\n this.onContextRestored?.();\n }\n\n destroy(): void {\n const result = destroyRenderer({\n destroyed: this.destroyed,\n frame: this.frame,\n cancelViewAnimation: () => this.cancelViewAnimation(),\n resizeObserver: this.resizeObserver,\n removeCanvasEventListeners: () => removeRendererCanvasEventListeners(this.canvas, this.getCanvasHandlers()),\n cancelDrag: () => this.cancelDrag(),\n tileScheduler: this.tileScheduler,\n contextLost: this.contextLost,\n gl: this.gl,\n cache: this.cache,\n tileProgram: this.tileProgram,\n pointProgram: this.pointProgram,\n });\n if (!result.didDestroy) return;\n this.destroyed = true;\n this.frame = result.frame;\n }\n}\n","import { type PreparedRoiPolygon, prepareRoiPolygons, toRoiGeometry } from \"../wsi/roi-geometry\";\nimport type { WsiRegion } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\nimport type { WsiTileRenderer } from \"../wsi/wsi-tile-renderer\";\nimport { getTopAnchorFromPolygons, measureLabelTextWidth, mergeRegionLabelStyle } from \"./draw-layer-label\";\nimport type { DrawCoordinate, RegionLabelAnchorMode, RegionLabelStyle, RegionLabelStyleResolver } from \"./draw-layer-types\";\nimport { toDrawCoordinate } from \"./draw-layer-utils\";\n\nconst REGION_CONTOUR_HIT_DISTANCE_PX = 6;\n\nexport interface PreparedRegionHit {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n polygons: PreparedRoiPolygon[];\n label: string;\n labelAnchor: DrawCoordinate | null;\n}\n\nexport function resolveRegionId(region: WsiRegion, index: number): string | number {\n return region.id ?? index;\n}\n\nfunction pointSegmentDistanceSq(px: number, py: number, ax: number, ay: number, bx: number, by: number): number {\n const abx = bx - ax;\n const aby = by - ay;\n const lengthSq = abx * abx + aby * aby;\n if (lengthSq <= 1e-12) {\n const dx = px - ax;\n const dy = py - ay;\n return dx * dx + dy * dy;\n }\n const t = clamp(((px - ax) * abx + (py - ay) * aby) / lengthSq, 0, 1);\n const nx = ax + abx * t;\n const ny = ay + aby * t;\n const dx = px - nx;\n const dy = py - ny;\n return dx * dx + dy * dy;\n}\n\nfunction isPointNearRing(x: number, y: number, ring: DrawCoordinate[], maxDistanceSq: number): boolean {\n for (let i = 1; i < ring.length; i += 1) {\n const prev = ring[i - 1];\n const next = ring[i];\n if (pointSegmentDistanceSq(x, y, prev[0], prev[1], next[0], next[1]) <= maxDistanceSq) {\n return true;\n }\n }\n return false;\n}\n\nfunction isPointNearPolygonContour(x: number, y: number, polygon: PreparedRoiPolygon, maxDistance: number): boolean {\n if (x < polygon.minX - maxDistance || x > polygon.maxX + maxDistance || y < polygon.minY - maxDistance || y > polygon.maxY + maxDistance) {\n return false;\n }\n const maxDistanceSq = maxDistance * maxDistance;\n if (isPointNearRing(x, y, polygon.outer, maxDistanceSq)) return true;\n for (const hole of polygon.holes) {\n if (isPointNearRing(x, y, hole, maxDistanceSq)) return true;\n }\n return false;\n}\n\nexport function isScreenPointInsideLabel(\n region: PreparedRegionHit,\n screenCoord: DrawCoordinate,\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n canvasWidth: number,\n canvasHeight: number,\n clampToViewport: boolean\n): boolean {\n if (!region.label || !region.labelAnchor) return false;\n\n const anchorScreen = toDrawCoordinate(renderer.worldToScreen(region.labelAnchor[0], region.labelAnchor[1]));\n if (!anchorScreen) return false;\n\n const textWidth = measureLabelTextWidth(region.label, labelStyle);\n const boxWidth = textWidth + labelStyle.paddingX * 2;\n const boxHeight = labelStyle.fontSize + labelStyle.paddingY * 2;\n\n const rawX = anchorScreen[0];\n const rawY = anchorScreen[1] - labelStyle.offsetY;\n const x = clampToViewport ? clamp(rawX, boxWidth * 0.5 + 1, canvasWidth - boxWidth * 0.5 - 1) : rawX;\n const y = clampToViewport ? clamp(rawY, boxHeight * 0.5 + 1, canvasHeight - boxHeight * 0.5 - 1) : rawY;\n const left = x - boxWidth * 0.5;\n const right = x + boxWidth * 0.5;\n const top = y - boxHeight * 0.5;\n const bottom = y + boxHeight * 0.5;\n\n return screenCoord[0] >= left && screenCoord[0] <= right && screenCoord[1] >= top && screenCoord[1] <= bottom;\n}\n\nexport function prepareRegionHits(regions: WsiRegion[], regionLabelAnchor: RegionLabelAnchorMode = \"top-center\"): PreparedRegionHit[] {\n const out: PreparedRegionHit[] = [];\n for (let i = 0; i < regions.length; i += 1) {\n const region = regions[i];\n const polygons = prepareRoiPolygons([toRoiGeometry(region?.coordinates)]);\n if (polygons.length === 0) continue;\n const label = typeof region?.label === \"string\" ? region.label.trim() : \"\";\n out.push({\n region,\n regionIndex: i,\n regionId: resolveRegionId(region, i),\n polygons,\n label,\n labelAnchor: label ? getTopAnchorFromPolygons(polygons, regionLabelAnchor) : null,\n });\n }\n return out;\n}\n\nexport function pickPreparedRegionAt(\n coord: DrawCoordinate,\n screenCoord: DrawCoordinate,\n regions: PreparedRegionHit[],\n renderer: WsiTileRenderer,\n labelStyle: RegionLabelStyle,\n labelStyleResolver: RegionLabelStyleResolver | undefined,\n labelAutoLiftOffsetPx: number,\n canvasWidth: number,\n canvasHeight: number,\n clampRegionLabelToViewport = true\n): {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n} | null {\n const x = coord[0];\n const y = coord[1];\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const labelAutoLiftOffset = Math.max(0, labelAutoLiftOffsetPx);\n const contourHitDistance = REGION_CONTOUR_HIT_DISTANCE_PX / zoom;\n for (let i = regions.length - 1; i >= 0; i -= 1) {\n const region = regions[i];\n for (const polygon of region.polygons) {\n if (!isPointNearPolygonContour(x, y, polygon, contourHitDistance)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n let dynamicLabelStyle = mergeRegionLabelStyle(\n labelStyle,\n labelStyleResolver?.({\n region: region.region,\n regionId: region.regionId,\n regionIndex: region.regionIndex,\n zoom,\n })\n );\n if (labelAutoLiftOffset > 0) {\n dynamicLabelStyle = {\n ...dynamicLabelStyle,\n offsetY: dynamicLabelStyle.offsetY + labelAutoLiftOffset,\n };\n }\n if (!isScreenPointInsideLabel(region, screenCoord, renderer, dynamicLabelStyle, canvasWidth, canvasHeight, clampRegionLabelToViewport)) continue;\n return {\n region: region.region,\n regionIndex: region.regionIndex,\n regionId: region.regionId,\n };\n }\n return null;\n}\n","import {\n type CSSProperties,\n type MutableRefObject,\n type MouseEvent as ReactMouseEvent,\n type ReactNode,\n type PointerEvent as ReactPointerEvent,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { filterPointDataByPolygons, type RoiPolygon } from \"../wsi/point-clip\";\nimport { filterPointDataByPolygonsHybrid } from \"../wsi/point-clip-hybrid\";\nimport { filterPointDataByPolygonsInWorker, type PointClipMode } from \"../wsi/point-clip-worker-client\";\nimport { buildPointSpatialIndexAsync, type FlatPointSpatialIndex, lookupCellIndex } from \"../wsi/point-hit-index-worker-client\";\nimport { type PreparedRoiPolygon, toRoiGeometry } from \"../wsi/roi-geometry\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type { WsiImageColorSettings, WsiImageSource, WsiPointData, WsiRegion, WsiRenderStats, WsiViewState } from \"../wsi/types\";\nimport { clamp } from \"../wsi/utils\";\nimport { type PointSizeByZoom, type WsiTileErrorEvent, WsiTileRenderer, type WsiViewTransitionOptions } from \"../wsi/wsi-tile-renderer\";\nimport type {\n BrushOptions,\n DrawAreaTooltipOptions,\n DrawCoordinate,\n DrawOverlayShape,\n DrawRegionCoordinates,\n DrawResult,\n DrawTool,\n PatchDrawResult,\n RegionLabelAnchorMode,\n RegionLabelStyle,\n RegionLabelStyleResolver,\n RegionStrokeStyle,\n RegionStrokeStyleResolver,\n StampOptions,\n} from \"./draw-layer\";\nimport { DrawLayer, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer\";\nimport { toDrawCoordinate } from \"./draw-layer-utils\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\nimport { type PreparedRegionHit, pickPreparedRegionAt, prepareRegionHits, resolveRegionId } from \"./wsi-region-hit-utils\";\n\nconst EMPTY_ROI_REGIONS: WsiRegion[] = [];\nconst EMPTY_ROI_POLYGONS: DrawRegionCoordinates[] = [];\nconst EMPTY_CLIPPED_POINTS: WsiPointData = {\n count: 0,\n positions: new Float32Array(0),\n paletteIndices: new Uint16Array(0),\n};\nconst POINT_HIT_RADIUS_SCALE = 0.65;\nconst MIN_POINT_HIT_RADIUS_PX = 4;\nconst REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS = 180;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\n\nexport interface RegionHoverEvent {\n region: WsiRegion | null;\n regionId: string | number | null;\n regionIndex: number;\n coordinate: DrawCoordinate | null;\n}\n\nexport interface RegionClickEvent {\n region: WsiRegion;\n regionId: string | number;\n regionIndex: number;\n coordinate: DrawCoordinate;\n}\n\nexport interface PointHitEvent {\n index: number;\n id: number | null;\n coordinate: DrawCoordinate;\n pointCoordinate: DrawCoordinate;\n}\n\nexport interface PointClickEvent extends PointHitEvent {\n button: number;\n}\n\nexport interface PointHoverEvent {\n index: number | null;\n id: number | null;\n coordinate: DrawCoordinate | null;\n pointCoordinate: DrawCoordinate | null;\n}\n\nexport interface PointClipStatsEvent {\n mode: PointClipMode;\n durationMs: number;\n inputCount: number;\n outputCount: number;\n polygonCount: number;\n usedWebGpu?: boolean;\n candidateCount?: number;\n bridgedToDraw?: boolean;\n}\n\nexport interface PointerWorldMoveEvent {\n coordinate: DrawCoordinate | null;\n clientX: number;\n clientY: number;\n insideImage: boolean;\n}\n\nexport interface WsiCustomLayerContext {\n source: WsiImageSource;\n viewState: WsiViewState;\n drawTool: DrawTool;\n interactionLock: boolean;\n worldToScreen: (worldX: number, worldY: number) => DrawCoordinate | null;\n screenToWorld: (clientX: number, clientY: number) => DrawCoordinate | null;\n requestRedraw: () => void;\n}\n\nexport interface WsiCustomLayer {\n id?: string | number;\n zIndex?: number;\n pointerEvents?: CSSProperties[\"pointerEvents\"];\n className?: string;\n style?: CSSProperties;\n render: (context: WsiCustomLayerContext) => ReactNode;\n}\n\nfunction smoothstep01(t: number): number {\n const x = clamp(t, 0, 1);\n return x * x * (3 - 2 * x);\n}\n\nexport interface OverviewMapConfig {\n show?: boolean;\n options?: Partial<OverviewMapOptions>;\n className?: string;\n style?: CSSProperties;\n}\n\nexport interface WsiViewerCanvasProps {\n source: WsiImageSource | null;\n viewState?: Partial<WsiViewState> | null;\n imageColorSettings?: WsiImageColorSettings | null;\n onViewStateChange?: (next: WsiViewState) => void;\n onStats?: (stats: WsiRenderStats) => void;\n onTileError?: (event: WsiTileErrorEvent) => void;\n onContextLost?: () => void;\n onContextRestored?: () => void;\n debugOverlay?: boolean;\n debugOverlayStyle?: CSSProperties;\n fitNonce?: number;\n rotationResetNonce?: number;\n authToken?: string;\n ctrlDragRotate?: boolean;\n pointData?: WsiPointData | null;\n pointPalette?: Uint8Array | null;\n pointSizeByZoom?: PointSizeByZoom;\n pointStrokeScale?: number;\n pointInnerFillOpacity?: number;\n minZoom?: number;\n maxZoom?: number;\n viewTransition?: WsiViewTransitionOptions;\n roiRegions?: WsiRegion[];\n roiPolygons?: DrawRegionCoordinates[];\n clipPointsToRois?: boolean;\n clipMode?: PointClipMode;\n onClipStats?: (event: PointClipStatsEvent) => void;\n onRoiPointGroups?: (stats: RoiPointGroupStats) => void;\n roiPaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n interactionLock?: boolean;\n drawTool?: DrawTool;\n stampOptions?: StampOptions;\n brushOptions?: BrushOptions;\n drawFillColor?: string;\n regionStrokeStyle?: Partial<RegionStrokeStyle>;\n regionStrokeHoverStyle?: Partial<RegionStrokeStyle>;\n regionStrokeActiveStyle?: Partial<RegionStrokeStyle>;\n patchStrokeStyle?: Partial<RegionStrokeStyle>;\n resolveRegionStrokeStyle?: RegionStrokeStyleResolver;\n resolveRegionLabelStyle?: RegionLabelStyleResolver;\n overlayShapes?: DrawOverlayShape[];\n customLayers?: WsiCustomLayer[];\n patchRegions?: WsiRegion[];\n regionLabelStyle?: Partial<RegionLabelStyle>;\n regionLabelAnchor?: RegionLabelAnchorMode;\n drawAreaTooltip?: DrawAreaTooltipOptions;\n autoLiftRegionLabelAtMaxZoom?: boolean;\n clampRegionLabelToViewport?: boolean;\n onPointerWorldMove?: (event: PointerWorldMoveEvent) => void;\n onPointHover?: (event: PointHoverEvent) => void;\n onPointClick?: (event: PointClickEvent) => void;\n onRegionHover?: (event: RegionHoverEvent) => void;\n onRegionClick?: (event: RegionClickEvent) => void;\n activeRegionId?: string | number | null;\n onActiveRegionChange?: (regionId: string | number | null) => void;\n getCellByCoordinatesRef?: MutableRefObject<((coordinate: DrawCoordinate) => PointHitEvent | null) | null>;\n onDrawComplete?: (result: DrawResult) => void;\n onPatchComplete?: (result: PatchDrawResult) => void;\n overviewMapConfig?: OverviewMapConfig;\n className?: string;\n style?: CSSProperties;\n}\n\nexport function WsiViewerCanvas({\n source,\n viewState,\n imageColorSettings = null,\n onViewStateChange,\n onStats,\n onTileError,\n onContextLost,\n onContextRestored,\n debugOverlay = false,\n debugOverlayStyle,\n fitNonce = 0,\n rotationResetNonce = 0,\n authToken = \"\",\n ctrlDragRotate = true,\n pointData = null,\n pointPalette = null,\n pointSizeByZoom,\n pointStrokeScale,\n pointInnerFillOpacity,\n minZoom,\n maxZoom,\n viewTransition,\n roiRegions,\n roiPolygons,\n clipPointsToRois = false,\n clipMode = \"worker\",\n onClipStats,\n onRoiPointGroups,\n roiPaletteIndexToTermId,\n interactionLock = false,\n drawTool = \"cursor\",\n stampOptions,\n brushOptions,\n drawFillColor,\n regionStrokeStyle,\n regionStrokeHoverStyle,\n regionStrokeActiveStyle,\n patchStrokeStyle,\n resolveRegionStrokeStyle,\n resolveRegionLabelStyle: resolveRegionLabelStyleProp,\n overlayShapes,\n customLayers,\n patchRegions,\n regionLabelStyle,\n regionLabelAnchor = \"top-center\",\n drawAreaTooltip,\n autoLiftRegionLabelAtMaxZoom = false,\n clampRegionLabelToViewport = true,\n onPointerWorldMove,\n onPointHover,\n onPointClick,\n onRegionHover,\n onRegionClick,\n activeRegionId: controlledActiveRegionId,\n onActiveRegionChange,\n getCellByCoordinatesRef,\n onDrawComplete,\n onPatchComplete,\n overviewMapConfig,\n className,\n style,\n}: WsiViewerCanvasProps): React.ReactElement {\n const showOverviewMap = overviewMapConfig?.show ?? false;\n const overviewMapOptions = overviewMapConfig?.options;\n const canvasRef = useRef<HTMLCanvasElement | null>(null);\n const rendererRef = useRef<WsiTileRenderer | null>(null);\n const drawInvalidateRef = useRef<(() => void) | null>(null);\n const overviewInvalidateRef = useRef<(() => void) | null>(null);\n const onViewStateChangeRef = useRef<typeof onViewStateChange>(onViewStateChange);\n const onStatsRef = useRef<typeof onStats>(onStats);\n const debugOverlayRef = useRef(debugOverlay);\n const [hoveredRegionId, setHoveredRegionId] = useState<string | number | null>(null);\n const [uncontrolledActiveRegionId, setUncontrolledActiveRegionId] = useState<string | number | null>(() => controlledActiveRegionId ?? null);\n const isActiveRegionControlled = controlledActiveRegionId !== undefined;\n const activeRegionId = isActiveRegionControlled ? (controlledActiveRegionId ?? null) : uncontrolledActiveRegionId;\n const [customLayerViewState, setCustomLayerViewState] = useState<WsiViewState | null>(null);\n const [debugStats, setDebugStats] = useState<WsiRenderStats | null>(null);\n const [regionLabelAutoLiftOffsetPx, setRegionLabelAutoLiftOffsetPx] = useState(0);\n const hoveredRegionIdRef = useRef<string | number | null>(null);\n const hoveredPointIndexRef = useRef<number | null>(null);\n const hoveredPointIdRef = useRef<number | null>(null);\n const regionLabelAutoLiftOffsetRef = useRef(0);\n const regionLabelAutoLiftAnimationRef = useRef<{ rafId: number | null; startMs: number; from: number; to: number }>({\n rafId: null,\n startMs: 0,\n from: 0,\n to: 0,\n });\n const clipRunIdRef = useRef(0);\n const safeRoiRegions = roiRegions ?? EMPTY_ROI_REGIONS;\n const safePatchRegions = patchRegions ?? EMPTY_ROI_REGIONS;\n const safeRoiPolygons = roiPolygons ?? EMPTY_ROI_POLYGONS;\n const shouldTrackCustomLayerViewState = (customLayers?.length ?? 0) > 0;\n\n const mergedStyle = useMemo<CSSProperties>(() => ({ position: \"relative\", width: \"100%\", height: \"100%\", ...style }), [style]);\n const mergedDebugOverlayStyle = useMemo<CSSProperties>(\n () => ({\n position: \"absolute\",\n top: 8,\n left: 8,\n zIndex: 7,\n margin: 0,\n padding: \"8px 10px\",\n maxWidth: \"min(420px, 80%)\",\n pointerEvents: \"none\",\n whiteSpace: \"pre-wrap\",\n lineHeight: 1.35,\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace\",\n fontSize: 11,\n color: \"#cde6ff\",\n background: \"rgba(6, 12, 20, 0.82)\",\n border: \"1px solid rgba(173, 216, 255, 0.28)\",\n borderRadius: 8,\n boxShadow: \"0 8px 22px rgba(0,0,0,0.35)\",\n ...debugOverlayStyle,\n }),\n [debugOverlayStyle]\n );\n\n const effectiveRoiRegions = useMemo<WsiRegion[]>(() => {\n if (safeRoiRegions.length > 0) {\n return safeRoiRegions;\n }\n if (safeRoiPolygons.length === 0) {\n return EMPTY_ROI_REGIONS;\n }\n return safeRoiPolygons.map((coordinates, index) => ({\n id: index,\n coordinates,\n }));\n }, [safeRoiRegions, safeRoiPolygons]);\n const preparedRegionHits = useMemo(() => prepareRegionHits(effectiveRoiRegions, regionLabelAnchor), [effectiveRoiRegions, regionLabelAnchor]);\n const resolvedRegionLabelStyle = useMemo(() => resolveRegionLabelStyle(regionLabelStyle), [regionLabelStyle]);\n\n const applyRegionLabelAutoLiftOffset = useCallback((next: number) => {\n const clamped = clamp(next, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n if (Math.abs(regionLabelAutoLiftOffsetRef.current - clamped) < 1e-4) return;\n regionLabelAutoLiftOffsetRef.current = clamped;\n setRegionLabelAutoLiftOffsetPx(clamped);\n }, []);\n\n const cancelRegionLabelAutoLiftAnimation = useCallback(() => {\n const animation = regionLabelAutoLiftAnimationRef.current;\n if (animation.rafId !== null) {\n cancelAnimationFrame(animation.rafId);\n animation.rafId = null;\n }\n }, []);\n\n const animateRegionLabelAutoLiftTo = useCallback(\n (target: number) => {\n const clampedTarget = clamp(target, 0, REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX);\n const animation = regionLabelAutoLiftAnimationRef.current;\n const from = regionLabelAutoLiftOffsetRef.current;\n if (Math.abs(from - clampedTarget) < 1e-4) {\n cancelRegionLabelAutoLiftAnimation();\n animation.to = clampedTarget;\n applyRegionLabelAutoLiftOffset(clampedTarget);\n return;\n }\n\n cancelRegionLabelAutoLiftAnimation();\n animation.startMs = performance.now();\n animation.from = from;\n animation.to = clampedTarget;\n\n const step = (timestamp: number) => {\n const current = regionLabelAutoLiftAnimationRef.current;\n const elapsed = Math.max(0, timestamp - current.startMs);\n const rawT = REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS <= 0 ? 1 : clamp(elapsed / REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS, 0, 1);\n const eased = smoothstep01(rawT);\n const nextValue = current.from + (current.to - current.from) * eased;\n applyRegionLabelAutoLiftOffset(nextValue);\n drawInvalidateRef.current?.();\n\n if (rawT >= 1) {\n current.rafId = null;\n applyRegionLabelAutoLiftOffset(current.to);\n return;\n }\n current.rafId = requestAnimationFrame(step);\n };\n\n animation.rafId = requestAnimationFrame(step);\n },\n [applyRegionLabelAutoLiftOffset, cancelRegionLabelAutoLiftAnimation]\n );\n\n const syncRegionLabelAutoLiftTarget = useCallback(\n (zoom: number | null | undefined) => {\n const renderer = rendererRef.current;\n if (!renderer || typeof zoom !== \"number\" || !Number.isFinite(zoom)) {\n animateRegionLabelAutoLiftTo(0);\n return;\n }\n const target = resolveRegionLabelAutoLiftOffsetPx(autoLiftRegionLabelAtMaxZoom, zoom, renderer.getZoomRange());\n animateRegionLabelAutoLiftTo(target);\n },\n [autoLiftRegionLabelAtMaxZoom, animateRegionLabelAutoLiftTo]\n );\n\n const clipPolygons = useMemo<RoiPolygon[]>(() => effectiveRoiRegions.map(region => toRoiGeometry(region.coordinates)).filter((p): p is RoiPolygon => p != null), [effectiveRoiRegions]);\n\n const [renderPointData, setRenderPointData] = useState<WsiPointData | null>(pointData);\n\n useEffect(() => {\n const runId = ++clipRunIdRef.current;\n let cancelled = false;\n\n if (!clipPointsToRois) {\n setRenderPointData(pointData);\n return () => {\n cancelled = true;\n };\n }\n\n if (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n setRenderPointData(null);\n return () => {\n cancelled = true;\n };\n }\n\n if (clipPolygons.length === 0) {\n setRenderPointData(EMPTY_CLIPPED_POINTS);\n onClipStats?.({\n mode: clipMode,\n durationMs: 0,\n inputCount: pointData.count,\n outputCount: 0,\n polygonCount: 0,\n });\n return () => {\n cancelled = true;\n };\n }\n\n const applyResult = (data: WsiPointData | null, stats: Omit<PointClipStatsEvent, \"inputCount\" | \"outputCount\" | \"polygonCount\">) => {\n if (cancelled || runId !== clipRunIdRef.current) return;\n const inputCount = pointData.count;\n const outputCount = data?.drawIndices ? data.drawIndices.length : (data?.count ?? 0);\n setRenderPointData(data);\n onClipStats?.({\n mode: stats.mode,\n durationMs: stats.durationMs,\n inputCount,\n outputCount,\n polygonCount: clipPolygons.length,\n usedWebGpu: stats.usedWebGpu,\n candidateCount: stats.candidateCount,\n bridgedToDraw: stats.bridgedToDraw,\n });\n };\n\n const run = async (): Promise<void> => {\n if (clipMode === \"sync\") {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n return;\n }\n\n if (clipMode === \"hybrid-webgpu\") {\n const result = await filterPointDataByPolygonsHybrid(pointData, clipPolygons, { bridgeToDraw: true });\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n usedWebGpu: result.meta.usedWebGpu,\n candidateCount: result.meta.candidateCount,\n bridgedToDraw: result.meta.bridgedToDraw,\n });\n return;\n }\n\n try {\n const result = await filterPointDataByPolygonsInWorker(pointData, clipPolygons);\n applyResult(result.data, {\n mode: result.meta.mode,\n durationMs: result.meta.durationMs,\n });\n } catch {\n const start = performance.now();\n const data = filterPointDataByPolygons(pointData, clipPolygons);\n applyResult(data, {\n mode: \"sync\",\n durationMs: performance.now() - start,\n });\n }\n };\n\n void run();\n return () => {\n cancelled = true;\n };\n }, [clipPointsToRois, clipMode, pointData, clipPolygons, onClipStats]);\n\n const shouldEnablePointHitTest = Boolean(onPointHover || onPointClick || getCellByCoordinatesRef);\n const [pointSpatialIndex, setPointSpatialIndex] = useState<FlatPointSpatialIndex | null>(null);\n\n useEffect(() => {\n if (!shouldEnablePointHitTest || !renderPointData) {\n setPointSpatialIndex(null);\n return;\n }\n let cancelled = false;\n\n buildPointSpatialIndexAsync(renderPointData, source).then(nextIndex => {\n if (!cancelled) setPointSpatialIndex(nextIndex);\n });\n\n return () => {\n cancelled = true;\n };\n }, [shouldEnablePointHitTest, renderPointData, source]);\n\n const getCellByCoordinates = useCallback(\n (coordinate: DrawCoordinate): PointHitEvent | null => {\n const renderer = rendererRef.current;\n if (!renderer || !pointSpatialIndex) return null;\n\n const x = Number(coordinate[0]);\n const y = Number(coordinate[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n\n const zoom = Math.max(1e-6, renderer.getViewState().zoom);\n const pointSizePx = renderer.getPointSizeByZoom();\n const hitRadiusPx = Math.max(MIN_POINT_HIT_RADIUS_PX, pointSizePx * POINT_HIT_RADIUS_SCALE);\n const hitRadiusWorld = hitRadiusPx / zoom;\n if (!Number.isFinite(hitRadiusWorld) || hitRadiusWorld <= 0) return null;\n\n const { cellSize, cellOffsets, cellLengths, pointIndices: idxBuf, positions: posBuf, safeCount } = pointSpatialIndex;\n const baseCellX = Math.floor(x / cellSize);\n const baseCellY = Math.floor(y / cellSize);\n const cellRadius = Math.max(1, Math.ceil(hitRadiusWorld / cellSize));\n const maxDist2 = hitRadiusWorld * hitRadiusWorld;\n\n let nearestIndex = -1;\n let nearestDist2 = maxDist2;\n let nearestX = 0;\n let nearestY = 0;\n\n for (let cx = baseCellX - cellRadius; cx <= baseCellX + cellRadius; cx += 1) {\n for (let cy = baseCellY - cellRadius; cy <= baseCellY + cellRadius; cy += 1) {\n const ci = lookupCellIndex(pointSpatialIndex, cx, cy);\n if (ci < 0) continue;\n\n const off = cellOffsets[ci];\n const end = off + cellLengths[ci];\n for (let i = off; i < end; i += 1) {\n const pointIndex = idxBuf[i];\n if (pointIndex >= safeCount) continue;\n\n const px = posBuf[pointIndex * 2];\n const py = posBuf[pointIndex * 2 + 1];\n const dx = px - x;\n const dy = py - y;\n const dist2 = dx * dx + dy * dy;\n if (dist2 > nearestDist2) continue;\n\n nearestDist2 = dist2;\n nearestIndex = pointIndex;\n nearestX = px;\n nearestY = py;\n }\n }\n }\n\n if (nearestIndex < 0) return null;\n const pointId = pointSpatialIndex.ids ? Number(pointSpatialIndex.ids[nearestIndex]) : null;\n return {\n index: nearestIndex,\n id: pointId,\n coordinate: [x, y],\n pointCoordinate: [nearestX, nearestY],\n };\n },\n [pointSpatialIndex]\n );\n\n const emitPointHover = useCallback(\n (hit: PointHitEvent | null, coordinate: DrawCoordinate | null) => {\n if (!onPointHover) return;\n const nextIndex = hit?.index ?? null;\n const nextId = hit?.id ?? null;\n if (hoveredPointIndexRef.current === nextIndex && hoveredPointIdRef.current === nextId) return;\n hoveredPointIndexRef.current = nextIndex;\n hoveredPointIdRef.current = nextId;\n onPointHover({\n index: nextIndex,\n id: nextId,\n coordinate,\n pointCoordinate: hit?.pointCoordinate ?? null,\n });\n },\n [onPointHover]\n );\n\n const emitPointClick = useCallback(\n (coordinate: DrawCoordinate, button: number) => {\n if (!onPointClick) return;\n const hit = getCellByCoordinates(coordinate);\n if (!hit) return;\n onPointClick({\n ...hit,\n button,\n });\n },\n [onPointClick, getCellByCoordinates]\n );\n\n useEffect(() => {\n if (!getCellByCoordinatesRef) return;\n getCellByCoordinatesRef.current = getCellByCoordinates;\n return () => {\n if (getCellByCoordinatesRef.current === getCellByCoordinates) {\n getCellByCoordinatesRef.current = null;\n }\n };\n }, [getCellByCoordinatesRef, getCellByCoordinates]);\n\n useEffect(() => {\n if (!isActiveRegionControlled) return;\n setUncontrolledActiveRegionId(controlledActiveRegionId ?? null);\n }, [isActiveRegionControlled, controlledActiveRegionId]);\n\n const commitActiveRegion = useCallback(\n (next: string | number | null) => {\n if (String(activeRegionId) === String(next)) return;\n if (!isActiveRegionControlled) {\n setUncontrolledActiveRegionId(next);\n }\n onActiveRegionChange?.(next);\n },\n [activeRegionId, isActiveRegionControlled, onActiveRegionChange]\n );\n\n useEffect(() => {\n onViewStateChangeRef.current = onViewStateChange;\n }, [onViewStateChange]);\n\n useEffect(() => {\n onStatsRef.current = onStats;\n }, [onStats]);\n\n useEffect(() => {\n debugOverlayRef.current = debugOverlay;\n if (!debugOverlay) setDebugStats(null);\n }, [debugOverlay]);\n\n useEffect(() => {\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n };\n }, [cancelRegionLabelAutoLiftAnimation]);\n\n const handleRendererStats = useCallback((stats: WsiRenderStats): void => {\n onStatsRef.current?.(stats);\n if (debugOverlayRef.current) {\n setDebugStats(stats);\n }\n }, []);\n\n const debugOverlayText = useMemo(() => {\n if (!debugStats) {\n return \"stats: waiting for first frame...\";\n }\n return [\n `tier ${debugStats.tier} | frame ${debugStats.frameMs?.toFixed(2) ?? \"-\"} ms | drawCalls ${debugStats.drawCalls ?? \"-\"}`,\n `tiles visible ${debugStats.visible} | rendered ${debugStats.rendered} | fallback ${debugStats.fallback}`,\n `cache size ${debugStats.cache} | hit ${debugStats.cacheHits ?? \"-\"} | miss ${debugStats.cacheMisses ?? \"-\"}`,\n `queue inflight ${debugStats.inflight} | queued ${debugStats.queued ?? \"-\"} | retries ${debugStats.retries ?? \"-\"} | failed ${debugStats.failed ?? \"-\"} | aborted ${debugStats.aborted ?? \"-\"}`,\n `points ${debugStats.points}`,\n ].join(\"\\n\");\n }, [debugStats]);\n\n useEffect(() => {\n const hasActive = activeRegionId === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(activeRegionId));\n if (!hasActive && activeRegionId !== null) {\n commitActiveRegion(null);\n }\n\n const currentHover = hoveredRegionIdRef.current;\n const hasHover = currentHover === null ? true : effectiveRoiRegions.some((region, index) => String(resolveRegionId(region, index)) === String(currentHover));\n\n if (!hasHover && currentHover !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n }, [effectiveRoiRegions, activeRegionId, onRegionHover, commitActiveRegion]);\n\n useEffect(() => {\n const hoveredPointIndex = hoveredPointIndexRef.current;\n if (hoveredPointIndex === null) return;\n if (pointSpatialIndex && hoveredPointIndex < pointSpatialIndex.safeCount) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [pointSpatialIndex, onPointHover]);\n\n const emitViewStateChange = useCallback(\n (next: WsiViewState): void => {\n syncRegionLabelAutoLiftTarget(next.zoom);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(next);\n }\n const callback = onViewStateChangeRef.current;\n if (callback) {\n callback(next);\n }\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n },\n [shouldTrackCustomLayerViewState, syncRegionLabelAutoLiftTarget]\n );\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [syncRegionLabelAutoLiftTarget, minZoom, maxZoom]);\n\n useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [drawTool, onRegionHover]);\n\n useEffect(() => {\n if (drawTool === \"cursor\") return;\n if (hoveredPointIndexRef.current === null) return;\n hoveredPointIndexRef.current = null;\n hoveredPointIdRef.current = null;\n onPointHover?.({\n index: null,\n id: null,\n coordinate: null,\n pointCoordinate: null,\n });\n }, [drawTool, onPointHover]);\n\n const resolveWorldCoord = useCallback((clientX: number, clientY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.screenToWorld(clientX, clientY);\n if (!Array.isArray(raw) || raw.length < 2) return null;\n const x = Number(raw[0]);\n const y = Number(raw[1]);\n if (!Number.isFinite(x) || !Number.isFinite(y)) return null;\n return [x, y];\n }, []);\n\n const resolveScreenCoord = useCallback((worldX: number, worldY: number): DrawCoordinate | null => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n const raw = renderer.worldToScreen(worldX, worldY);\n return toDrawCoordinate(raw);\n }, []);\n\n const resolveCanvasPointerSnapshot = useCallback((clientX: number, clientY: number): { screenCoord: DrawCoordinate; canvasWidth: number; canvasHeight: number } | null => {\n const canvas = canvasRef.current;\n if (!canvas) return null;\n const rect = canvas.getBoundingClientRect();\n if (!Number.isFinite(rect.width) || !Number.isFinite(rect.height) || rect.width <= 0 || rect.height <= 0) {\n return null;\n }\n const screenX = clientX - rect.left;\n const screenY = clientY - rect.top;\n if (!Number.isFinite(screenX) || !Number.isFinite(screenY)) {\n return null;\n }\n return {\n screenCoord: [screenX, screenY],\n canvasWidth: Math.max(1, rect.width),\n canvasHeight: Math.max(1, rect.height),\n };\n }, []);\n\n const pickRegionHit = useCallback(\n (coord: DrawCoordinate, screenCoord: DrawCoordinate, canvasWidth: number, canvasHeight: number) => {\n const renderer = rendererRef.current;\n if (!renderer) return null;\n return pickPreparedRegionAt(\n coord,\n screenCoord,\n preparedRegionHits,\n renderer,\n resolvedRegionLabelStyle,\n resolveRegionLabelStyleProp,\n regionLabelAutoLiftOffsetPx,\n canvasWidth,\n canvasHeight,\n clampRegionLabelToViewport\n );\n },\n [preparedRegionHits, resolvedRegionLabelStyle, resolveRegionLabelStyleProp, regionLabelAutoLiftOffsetPx, clampRegionLabelToViewport]\n );\n\n const requestCustomLayerRedraw = useCallback(() => {\n rendererRef.current?.requestRender();\n drawInvalidateRef.current?.();\n overviewInvalidateRef.current?.();\n }, []);\n\n const effectiveCustomLayerViewState = useMemo<WsiViewState | null>(() => {\n return customLayerViewState ?? rendererRef.current?.getViewState() ?? null;\n }, [customLayerViewState]);\n\n const customLayerContext = useMemo<WsiCustomLayerContext | null>(() => {\n if (!source) return null;\n const viewStateForLayer = effectiveCustomLayerViewState;\n if (!viewStateForLayer) return null;\n return {\n source,\n viewState: viewStateForLayer,\n drawTool,\n interactionLock,\n worldToScreen: resolveScreenCoord,\n screenToWorld: resolveWorldCoord,\n requestRedraw: requestCustomLayerRedraw,\n };\n }, [source, effectiveCustomLayerViewState, drawTool, interactionLock, resolveScreenCoord, resolveWorldCoord, requestCustomLayerRedraw]);\n\n const handleRegionPointerMove = useCallback(\n (event: ReactPointerEvent<HTMLDivElement>) => {\n const isCanvasEvent = event.target === canvasRef.current;\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (onPointerWorldMove) {\n const insideImage = !!coord && coord[0] >= 0 && coord[1] >= 0 && !!source && coord[0] <= source.width && coord[1] <= source.height;\n onPointerWorldMove({\n coordinate: coord,\n clientX: event.clientX,\n clientY: event.clientY,\n insideImage,\n });\n }\n\n if (drawTool !== \"cursor\") return;\n if (!isCanvasEvent) {\n emitPointHover(null, null);\n if (hoveredRegionIdRef.current !== null) {\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }\n return;\n }\n if (!coord) {\n emitPointHover(null, null);\n return;\n }\n\n if (onPointHover) {\n emitPointHover(getCellByCoordinates(coord), coord);\n }\n if (!preparedRegionHits.length) return;\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\n const nextHoverId = hit?.regionId ?? null;\n const prevHoverId = hoveredRegionIdRef.current;\n if (String(prevHoverId) === String(nextHoverId)) return;\n\n hoveredRegionIdRef.current = nextHoverId;\n setHoveredRegionId(nextHoverId);\n onRegionHover?.({\n region: hit?.region ?? null,\n regionId: nextHoverId,\n regionIndex: hit?.regionIndex ?? -1,\n coordinate: coord,\n });\n },\n [drawTool, preparedRegionHits, resolveWorldCoord, onRegionHover, onPointerWorldMove, source, emitPointHover, getCellByCoordinates, onPointHover, resolveCanvasPointerSnapshot, pickRegionHit]\n );\n\n const handleRegionPointerLeave = useCallback(() => {\n onPointerWorldMove?.({\n coordinate: null,\n clientX: -1,\n clientY: -1,\n insideImage: false,\n });\n emitPointHover(null, null);\n if (hoveredRegionIdRef.current === null) return;\n hoveredRegionIdRef.current = null;\n setHoveredRegionId(null);\n onRegionHover?.({\n region: null,\n regionId: null,\n regionIndex: -1,\n coordinate: null,\n });\n }, [onRegionHover, onPointerWorldMove, emitPointHover]);\n\n const handleRegionClick = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n\n if (!preparedRegionHits.length) {\n commitActiveRegion(null);\n return;\n }\n\n const pointerSnapshot = resolveCanvasPointerSnapshot(event.clientX, event.clientY);\n if (!pointerSnapshot) return;\n\n const hit = pickRegionHit(coord, pointerSnapshot.screenCoord, pointerSnapshot.canvasWidth, pointerSnapshot.canvasHeight);\n if (!hit) {\n commitActiveRegion(null);\n return;\n }\n\n const nextActive: string | number | null = activeRegionId !== null && String(activeRegionId) === String(hit.regionId) ? null : hit.regionId;\n commitActiveRegion(nextActive);\n onRegionClick?.({\n region: hit.region,\n regionId: hit.regionId,\n regionIndex: hit.regionIndex,\n coordinate: coord,\n });\n },\n [drawTool, preparedRegionHits, resolveWorldCoord, onRegionClick, activeRegionId, commitActiveRegion, emitPointClick, resolveCanvasPointerSnapshot, pickRegionHit]\n );\n\n const handleBrushTap = useCallback(\n (coord: DrawCoordinate): boolean => {\n if (drawTool !== \"brush\") return false;\n if (brushOptions?.clickSelectRoi !== true) return false;\n if (!preparedRegionHits.length) return false;\n\n const renderer = rendererRef.current;\n const canvas = canvasRef.current;\n if (!renderer || !canvas) return false;\n const rect = canvas.getBoundingClientRect();\n if (rect.width <= 0 || rect.height <= 0) return false;\n\n const screenCoord = toDrawCoordinate(renderer.worldToScreen(coord[0], coord[1]));\n if (!screenCoord) return false;\n const hit = pickRegionHit(coord, screenCoord, rect.width, rect.height);\n if (!hit) return false;\n\n const nextActive: string | number | null = activeRegionId !== null && String(activeRegionId) === String(hit.regionId) ? null : hit.regionId;\n commitActiveRegion(nextActive);\n onRegionClick?.({\n region: hit.region,\n regionId: hit.regionId,\n regionIndex: hit.regionIndex,\n coordinate: coord,\n });\n return true;\n },\n [drawTool, brushOptions?.clickSelectRoi, preparedRegionHits, activeRegionId, commitActiveRegion, onRegionClick, pickRegionHit]\n );\n\n const handleRegionContextMenu = useCallback(\n (event: ReactMouseEvent<HTMLDivElement>) => {\n if (!onPointClick) return;\n if (drawTool !== \"cursor\") return;\n if (event.target !== canvasRef.current) return;\n event.preventDefault();\n const coord = resolveWorldCoord(event.clientX, event.clientY);\n if (!coord) return;\n emitPointClick(coord, event.button);\n },\n [drawTool, resolveWorldCoord, emitPointClick, onPointClick]\n );\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || !source) {\n return;\n }\n\n const renderer = new WsiTileRenderer(canvas, source, {\n onViewStateChange: emitViewStateChange,\n onStats: handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n imageColorSettings,\n ctrlDragRotate,\n pointSizeByZoom,\n pointStrokeScale,\n pointInnerFillOpacity,\n minZoom,\n maxZoom,\n viewTransition,\n });\n\n rendererRef.current = renderer;\n if (viewState) {\n renderer.setViewState(viewState);\n }\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n renderer.setInteractionLock(interactionLock);\n if (shouldTrackCustomLayerViewState) {\n setCustomLayerViewState(renderer.getViewState());\n }\n\n return () => {\n cancelRegionLabelAutoLiftAnimation();\n applyRegionLabelAutoLiftOffset(0);\n renderer.destroy();\n rendererRef.current = null;\n };\n }, [\n source,\n handleRendererStats,\n onTileError,\n onContextLost,\n onContextRestored,\n authToken,\n ctrlDragRotate,\n emitViewStateChange,\n shouldTrackCustomLayerViewState,\n syncRegionLabelAutoLiftTarget,\n cancelRegionLabelAutoLiftAnimation,\n applyRegionLabelAutoLiftOffset,\n ]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !viewState) {\n return;\n }\n renderer.setViewState(viewState);\n }, [viewState]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.fitToImage();\n }, [fitNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.resetRotation();\n }, [rotationResetNonce]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer || !pointPalette) {\n return;\n }\n renderer.setPointPalette(pointPalette);\n }, [pointPalette]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setPointSizeByZoom(pointSizeByZoom);\n }, [pointSizeByZoom]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setPointStrokeScale(pointStrokeScale);\n }, [pointStrokeScale]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setPointInnerFillOpacity(pointInnerFillOpacity);\n }, [pointInnerFillOpacity]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setZoomRange(minZoom, maxZoom);\n syncRegionLabelAutoLiftTarget(renderer.getViewState().zoom);\n }, [minZoom, maxZoom, syncRegionLabelAutoLiftTarget]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setViewTransition(viewTransition);\n }, [viewTransition]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) return;\n renderer.setImageColorSettings(imageColorSettings);\n }, [imageColorSettings]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setPointData(renderPointData);\n }, [renderPointData]);\n\n useEffect(() => {\n if (!onRoiPointGroups) return;\n const sourcePoints = clipPointsToRois ? renderPointData : pointData;\n const stats = computeRoiPointGroups(sourcePoints, effectiveRoiRegions, {\n paletteIndexToTermId: roiPaletteIndexToTermId,\n includeEmptyRegions: true,\n });\n onRoiPointGroups(stats);\n }, [onRoiPointGroups, clipPointsToRois, pointData, renderPointData, effectiveRoiRegions, roiPaletteIndexToTermId]);\n\n useEffect(() => {\n const renderer = rendererRef.current;\n if (!renderer) {\n return;\n }\n renderer.setInteractionLock(interactionLock);\n }, [interactionLock]);\n\n return (\n <div\n className={className}\n style={mergedStyle}\n onPointerMove={handleRegionPointerMove}\n onPointerLeave={handleRegionPointerLeave}\n onClick={handleRegionClick}\n onContextMenu={handleRegionContextMenu}\n >\n <canvas\n ref={canvasRef}\n className=\"wsi-render-canvas\"\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: 1,\n width: \"100%\",\n height: \"100%\",\n display: \"block\",\n touchAction: \"none\",\n cursor: drawTool === \"cursor\" && hoveredRegionId !== null ? \"pointer\" : interactionLock ? \"crosshair\" : \"grab\",\n }}\n />\n {source && customLayerContext && Array.isArray(customLayers) && customLayers.length > 0\n ? customLayers.map((layer, index) => (\n <div\n key={layer.id ?? index}\n className={layer.className}\n style={{\n position: \"absolute\",\n inset: 0,\n zIndex: layer.zIndex ?? 3,\n pointerEvents: layer.pointerEvents ?? \"none\",\n ...layer.style,\n }}\n >\n {layer.render(customLayerContext)}\n </div>\n ))\n : null}\n {source ? (\n <DrawLayer\n tool={drawTool}\n enabled={drawTool !== \"cursor\"}\n imageWidth={source.width}\n imageHeight={source.height}\n imageMpp={source.mpp}\n imageZoom={source.maxTierZoom}\n stampOptions={stampOptions}\n brushOptions={brushOptions}\n drawFillColor={drawFillColor}\n projectorRef={rendererRef}\n onBrushTap={handleBrushTap}\n viewStateSignal={viewState}\n persistedRegions={effectiveRoiRegions}\n patchRegions={safePatchRegions}\n regionStrokeStyle={regionStrokeStyle}\n regionStrokeHoverStyle={regionStrokeHoverStyle}\n regionStrokeActiveStyle={regionStrokeActiveStyle}\n patchStrokeStyle={patchStrokeStyle}\n resolveRegionStrokeStyle={resolveRegionStrokeStyle}\n resolveRegionLabelStyle={resolveRegionLabelStyleProp}\n overlayShapes={overlayShapes}\n hoveredRegionId={hoveredRegionId}\n activeRegionId={activeRegionId}\n regionLabelStyle={regionLabelStyle}\n regionLabelAnchor={regionLabelAnchor}\n drawAreaTooltip={drawAreaTooltip}\n autoLiftRegionLabelAtMaxZoom={autoLiftRegionLabelAtMaxZoom}\n clampRegionLabelToViewport={clampRegionLabelToViewport}\n regionLabelAutoLiftOffsetPx={regionLabelAutoLiftOffsetPx}\n invalidateRef={drawInvalidateRef}\n onDrawComplete={onDrawComplete}\n onPatchComplete={onPatchComplete}\n />\n ) : null}\n {debugOverlay ? (\n <pre data-open-plant-debug-overlay style={mergedDebugOverlayStyle}>\n {debugOverlayText}\n </pre>\n ) : null}\n {source && showOverviewMap && (\n <OverviewMap\n source={source}\n projectorRef={rendererRef}\n authToken={authToken}\n options={overviewMapOptions}\n invalidateRef={overviewInvalidateRef}\n className={overviewMapConfig?.className}\n style={overviewMapConfig?.style}\n />\n )}\n </div>\n );\n}\n"],"names":["compileShader","gl","type","source","shader","log","createProgram","vertexSource","fragmentSource","vertexShader","fragmentShader","program","requireUniformLocation","uniformName","location","requireWebGL2","canvas","context","toRadians","deg","OrthoCamera","__publicField","width","height","next","zoom","centerX","centerY","screenX","screenY","rotationDeg","dx","dy","rad","cos","sin","worldX","worldY","rx","ry","w","h","viewWidth","viewHeight","sx","sy","tx","ty","ax","bx","ay","by","VERTEX_SHADER","FRAGMENT_SHADER","M1TileRenderer","options","vao","quadBuffer","quadVertices","unitLocation","uvLocation","stride","tiles","version","loaded","tile","viewState","response","blob","bitmap","texture","error","rect","cssWidth","cssHeight","dpr","targetWidth","targetHeight","viewport","safeZoom","visibleWorldWidth","visibleWorldHeight","offsetX","offsetY","toRoiGeometry","coords","isFiniteNumber","value","isCoordinatePair","isLinearRing","point","isPolygonRings","ring","isMultiPolygon","polygon","closeRoiRing","coordinates","out","x","y","prev","first","last","polygonSignedArea","sum","i","a","b","normalizePolygonRings","rings","normalized","closed","outerIndex","outerArea","area","normalizeRoiGeometry","geometry","pointInRing","inside","j","xi","yi","xj","yj","prepareRoiPolygons","geometries","prepared","multipolygon","outer","minX","minY","maxX","maxY","pointInPreparedPolygon","hole","pointInAnyPreparedPolygon","polygons","DEFAULT_POINT_COLOR","clamp","min","max","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","nowMs","sanitizePointCount","pointData","fillModesLength","isSameViewState","toBearerToken","trimmed","token","hexToRgba","hex","match","n","buildTermPalette","terms","palette","termToPaletteIndex","term","termId","colors","DEFAULT_MIN_RASTER_STEP","DEFAULT_MAX_RASTER_PIXELS","DEFAULT_MAX_RASTER_SIZE","DEFAULT_CIRCLE_SIDES","DEFAULT_SMOOTHING_PASSES","MAX_SMOOTHING_PASSES","MIN_RADIUS","ALPHA_THRESHOLD","sanitizePath","points","createCirclePolygon","center","radius","sides","t","closeRing","createBoundsFallback","pad","computeExpandedBounds","resolveRasterConfig","bounds","minRasterStep","maxRasterPixels","maxRasterSize","widthWorld","heightWorld","step","padding","createRasterContext","worldToRaster","config","rasterizeStrokeMask","path","p","image","buildBoundaryEdges","mask","edges","vertex","at","turnPriority","fromDir","toDir","delta","traceLoops","outgoing","entry","used","loops","startVertex","currentVertex","currentDir","loop","guard","guardLimit","candidates","bestIndex","bestPriority","edgeIndex","candidate","priority","toWorldRing","vertexLoop","id","removeCollinearVertices","epsilon","curr","cross","pointLineDistanceSquared","abx","aby","len2","simplifyRdp","tolerance","keep","tolerance2","stack","start","end","maxDist2","split","dist2","simplifyClosedRing","open","simplified","smoothClosedRingChaikin","iterations","pass","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","smoothingPasses","EMPTY_DASH","EMPTY_REGIONS","DEFAULT_REGION_STROKE_STYLE","DEFAULT_PATCH_STROKE_STYLE","REGION_INTERACTION_SHADOW_COLOR","REGION_INTERACTION_SHADOW_WIDTH","DEFAULT_REGION_LABEL_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_STYLE","DEFAULT_DRAW_AREA_TOOLTIP_OFFSET","REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX","REGION_LABEL_AUTO_LIFT_MAX_EPSILON","DEFAULT_DRAW_PREVIEW_FILL","FREEHAND_MIN_POINTS","FREEHAND_SCREEN_STEP","CIRCLE_SIDES","MIN_AREA_PX","MICRONS_PER_MM","DEFAULT_STAMP_RECTANGLE_AREA_MM2","DEFAULT_STAMP_CIRCLE_AREA_MM2","DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE","LEGACY_HPF_CIRCLE_AREA_MM2","WHEEL_ZOOM_IN_FACTOR","WHEEL_ZOOM_OUT_FACTOR","DEFAULT_BRUSH_RADIUS","DEFAULT_BRUSH_FILL_COLOR","DEFAULT_BRUSH_FILL_OPACITY","DEFAULT_BRUSH_CURSOR_COLOR","DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR","DEFAULT_BRUSH_CURSOR_LINE_WIDTH","DEFAULT_BRUSH_CURSOR_DASH","DEFAULT_BRUSH_EDGE_DETAIL","MIN_BRUSH_EDGE_DETAIL","MAX_BRUSH_EDGE_DETAIL","DEFAULT_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_EDGE_SMOOTHING","MAX_BRUSH_EDGE_SMOOTHING","MIN_BRUSH_RASTER_STEP","BRUSH_RASTER_DIAMETER_SAMPLES","BRUSH_SCREEN_STEP","clampWorld","coord","imageWidth","imageHeight","toDrawCoordinate","toCoord","polygonArea","computeBounds","tracePath","ctx","close","drawPath","strokeStyle","fill","fillColor","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isCoordinateRing","collectOverlayRings","item","normalizeOverlayRings","sourceRings","clampPositiveOrFallback","fallback","clampUnitOpacity","drawRoundedRect","r","isNestedRingCoordinates","createRectangle","projection","startScreen","endScreen","screenCorners","worldCorners","corner","world","createCircle","normalizeDrawRegionPolygons","normalizedOuter","holes","sanitizeBrushLineDash","resolveBrushEdgeDetail","resolveBrushEdgeSmoothing","resolveBrushOptions","cursorLineWidth","edgeDetail","edgeSmoothing","drawBrushStrokePreview","session","resolvedBrushOptions","screenPoints","radiusPx","drawBrushCursor","projector","cursor","screen","LABEL_MEASURE_FALLBACK_EM","LABEL_MEASURE_CACHE_LIMIT","TOP_ANCHOR_Y_TOLERANCE","sharedLabelMeasureContext","labelTextWidthCache","getLabelMeasureContext","measureLabelTextWidth","label","labelStyle","key","cached","measured","getTopAnchor","anchorMode","getTopAnchorFromPolygons","best","anchor","resolveRegionLabelStyle","px","py","fs","bw","oy","br","mergeRegionLabelStyle","resolveRegionLabelAutoLiftOffsetPx","enabled","zoomRange","minZoom","maxZoom","resolveDrawAreaTooltipStyle","fontSize","borderRadius","paddingX","paddingY","resolveTooltipCursorOffset","defaultDrawAreaTooltipFormatter","areaMm2","resolveDrawAreaTooltipOptions","format","cursorOffset","drawRegionLabel","text","canvasWidth","canvasHeight","clampToViewport","boxWidth","boxHeight","rawX","rawY","left","top","drawAreaTooltipBox","cursorScreen","drawInvertedFillMask","outerRing","holeRings","drawOverlayShapes","params","overlayShapes","imageOuterRing","worldToScreenPoints","baseStrokeStyle","onInvertedFillDebug","debugOverlay","shape","renderRings","closedRings","isStampTool","tool","resolveStampOptions","mm2ToUm2","createSquareFromCenter","halfLength","screenCenter","screenEdge","screenHL","createCircleFromCenter","buildStampCoords","stampTool","resolvedStampOptions","micronsToWorldPixels","getRectangleProjection","areaUm2","resolveRegionInteractionShadowStyle","resolveDrawPreviewFillColor","isValidPolygon","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","drawFillColor","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","resolveRegionLabelStyleProp","hoveredRegionId","activeRegionId","regionLabelStyle","drawAreaTooltip","autoLiftRegionLabelAtMaxZoom","regionLabelAnchor","clampRegionLabelToViewport","regionLabelAutoLiftOffsetPx","invalidateRef","className","canvasRef","useRef","drawPendingRef","overlayDebugSnapshotRef","lastToolRef","sessionRef","active","mergedPersistedRegions","useMemo","index","mergedPatchRegions","preparedPersistedRegions","region","preparedPatchRegions","resolvedStrokeStyle","resolvedHoverStrokeStyle","resolvedActiveStrokeStyle","resolvedPatchStrokeStyle","resolvedDrawPreviewFillColor","resolvedLabelStyle","resolvedDrawAreaTooltipOptions","mergedStyle","resizeCanvas","useCallback","localScreenToWorld","raw","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoordsCallback","buildPreviewCoords","drawOverlay","regionIndex","regionKey","state","resolved","interactionShadowStyle","screenOuter","screenHole","info","debugKey","debugSignature","preview","line","labelAutoLiftOffset","anchorWorld","anchorScreen","dynamicLabelStyle","areaCoords","areaPx","requestDraw","resetSession","preserveCursor","toWorld","event","toLocalScreen","finishSession","tapPoint","screenPath","screenPolygon","worldPolygon","handleStampAt","intent","result","appendBrushPoint","minScreenStep2","prevScreen","handlePointerDown","handlePointerMove","minWorldStep","minWorldStep2","handlePointerUp","handlePointerLeave","changed","useEffect","observer","onKeyDown","jsx","trimTrailingSlash","ensureLeadingSlash","joinImsTileRoot","tileBaseUrl","parsed","origin","normalizeImageInfo","ims","isIms","tileSize","maxTierZoom","tilePath","normalizedPath","imsTileRoot","tileUrlBuilder","tier","toTileUrl","DEFAULT_OVERVIEW_MAP_OPTIONS","strokeSymmetricDashedPolygon","dashLen","gapLen","len","from","to","sideLen","fittedLen","scale","adjDash","adjGap","toPositiveNumber","isFiniteBounds","DEFAULT_CLOSE_BUTTON_STYLE","OverviewMap","authToken","thumbnailRef","lastBoundsRef","draggingRef","rafRef","contentRect","imgW","imgH","imageAspect","boxAspect","cw","ch","margin","borderWidth","maxThumbnailTiles","backgroundColor","borderColor","viewportBorderColor","viewportBorderStyle","viewportFillColor","interactive","showThumbnail","position","onClose","closeIcon","closeButtonStyle","pos","draw","cssW","cssH","pixelW","pixelH","cx","cy","corners","safeBounds","safeCorners","isDash","right","bottom","rectW","rectH","rectCorners","toWorldFromClient","clientX","clientY","scaleX","scaleY","cxPx","cyPx","cwPx","chPx","nx","ny","recenterTo","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","dw","dh","jsxs","TileViewerCanvas","rendererRef","renderer","filterPointDataByPolygons","empty","count","positions","fillModes","pointIds","nextPositions","nextTerms","nextFillModes","nextIds","output","filterPointIndicesByPolygons","contextPromise","BBOX_PREFILTER_SHADER","hasWebGpu","nav","getNavigatorGpu","gpu","GPU_SHADER_STAGE_COMPUTE","GPU_BUFFER_USAGE_STORAGE","GPU_BUFFER_USAGE_COPY_DST","GPU_BUFFER_USAGE_COPY_SRC","GPU_BUFFER_USAGE_UNIFORM","GPU_BUFFER_USAGE_MAP_READ","GPU_MAP_MODE_READ","getWebGpuCapabilities","navGpu","adapter","getContext","device","bindGroupLayout","pipeline","align","prefilterPointsByBoundsWebGpu","pointCount","boundsCount","safePointCount","positionBytes","boundsBytes","outputBytes","limit","positionsBuffer","boundsBuffer","outputBuffer","uniformBuffer","readBuffer","bindGroup","commandEncoder","mapped","filterPointDataByPolygonsHybrid","bridgeToDraw","data","safeCount","pointFillModes","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","compactData","WorkerClient","createWorker","handlers","message","pending","worker","reason","workerClient","_documentCurrentScript","msg","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","fillModesCopy","idsCopy","resolve","reject","startMs","requestTicket","transfer","canceled","filterPointIndicesByPolygonsInWorker","MIN_POINT_HIT_GRID_SIZE","MAX_POINT_HIT_GRID_SIZE","POINT_HIT_GRID_DENSITY_SCALE","HASH_EMPTY","cellHash","cellX","cellY","resolveGridSize","sourceWidth","sourceHeight","sanitizeDrawIndices","allValid","filtered","buildPointHitIndex","input","maxCountByPositions","cellSize","invCellSize","pointCellX","pointCellY","validCount","pi","estimatedCells","hashCapacity","hashMask","tempHashKeys","tempHashCounts","cellCount","pointCellSlot","slot","kx","oldCap","newKeys","newCounts","s","ocx","ocy","ns","cellKeys","cellOffsets","cellLengths","slotToCellIndex","cellIdx","offset","pointIndices","fillCursor","ci","srcIdx","finalCap","finalMask","hashTable","lookupCellIndex","buildFromResponse","terminatePointHitIndexWorker","buildSyncFallback","buildPointSpatialIndexAsync","drawIndicesCopy","prepareRegions","regions","resolveTermId","paletteIndex","paletteIndexToTermId","fromArray","fromMap","computeRoiPointGroups","baseCount","valid","idx","inputCount","preparedRegions","regionTermCounters","regionTotalCounters","insideCount","bestRegion","regionTermMap","includeEmptyRegions","groups","totalCount","termMap","termCounts","shouldAttachAuthHeader","url","host","TileScheduler","nextVisibleKeys","inflight","queued","visibleKeys","nextQueue","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","addRendererCanvasEventListeners","removeRendererCanvasEventListeners","resizeCanvasViewport","camera","DEFAULT_ROTATION_DRAG_SENSITIVITY","MIN_POINT_SIZE_PX","MAX_POINT_SIZE_PX","DEFAULT_POINT_SIZE_STOPS","MIN_STROKE_SCALE","MAX_STROKE_SCALE","MIN_POINT_INNER_FILL_OPACITY","MAX_POINT_INNER_FILL_OPACITY","MIN_IMAGE_COLOR_INPUT","MAX_IMAGE_COLOR_INPUT","MAX_VIEW_TRANSITION_DURATION_MS","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","normalizeStrokeScale","normalizePointInnerFillOpacity","normalizeImageColorInput","toNormalizedImageColorSettings","settings","brightnessInput","contrastInput","saturationInput","linearEasing","normalizeViewTransitionDuration","duration","normalizeZoomOverride","normalizeTransitionEasing","easing","getPointerAngleRad","cancelDrag","cancelViewAnimation","wantsRotate","clampViewState","emitViewState","requestRender","nextAngle","prevAngle","rawDelta","sensitivityScale","worldDx","worldDy","handleWheel","onZoomBy","factor","handleDoubleClick","handleContextMenu","dragging","getViewBounds","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","nextCenterX","nextCenterY","selectTier","rawTier","intersectsBounds","getVisibleTilesForTier","viewBounds","viewMinX","viewMinY","viewMaxX","viewMaxY","minTileX","maxTileX","minTileY","maxTileY","centerTileX","centerTileY","visible","getVisibleTiles","onPointerDownWithLock","onPointerMoveWithLock","onPointerUpWithLock","onWheelWithLock","onDoubleClickWithLock","onContextMenuWithLock","cancelInteractionDrag","createRendererInputHandlers","trimTileCache","cache","maxCacheTiles","entries","removeCount","createTextureFromBitmap","handleTileLoaded","frameSerial","destroyed","contextLost","deleteCachedTextures","handleContextLost","tileScheduler","onContextLost","frame","destroyRenderer","maxExclusive","getZeroFillModes","zeroFillModes","setPointPalette","runtime","pointProgram","nextPalette","paletteSize","setPointData","hasFillModes","nextPaletteIndices","hasDrawIndices","nextDrawIndices","prevHasFillModes","geometryChanged","drawIndicesChanged","nextRuntime","currentPointData","renderFrame","tileProgram","imageColorSettings","usePointIndices","pointPaletteSize","pointStrokeScale","pointInnerFillOpacity","pointSizePx","fallbackTiles","renderedTiles","missingTiles","tilesToSchedule","PREFETCH_DISTANCE_PENALTY","prefetchTiers","prefetchTier","prefetchCandidates","renderedPoints","initTileProgram","uCamera","uBounds","uTexture","uBrightness","uContrast","uSaturation","vbo","aUnit","aUv","initPointProgram","uPointSize","uPointStrokeScale","uPointInnerFillAlpha","uPalette","uPaletteSize","posBuffer","termBuffer","fillModeBuffer","indexBuffer","paletteTexture","posLoc","termLoc","fillModeLoc","startViewAnimation","target","durationMs","onUpdate","animation","elapsed","rawT","eased","resolveDefaultZoomBounds","fitZoom","resolveZoomBounds","minZoomOverride","maxZoomOverride","defaults","resolveTargetViewState","current","computeFitToImageTarget","viewportWidth","viewportHeight","clampedZoom","visibleWorldW","visibleWorldH","computeZoomByTarget","nextZoom","vp","WsiTileRenderer","cacheTileLoaded","attemptCount","inputHandlers","resolveManagedTargetViewState","clampManagedViewState","cancelManagedViewAnimation","cancelAnimation","nextMinOverride","nextMaxOverride","transition","setManagedPointPalette","setManagedPointData","locked","nextStops","opacity","cancelInputDrag","vw","vh","fitTarget","frameStartMs","getManagedVisibleTiles","getManagedVisibleTilesForTier","getManagedViewBounds","intersectsManagedBounds","schedulerStats","_event","REGION_CONTOUR_HIT_DISTANCE_PX","resolveRegionId","pointSegmentDistanceSq","lengthSq","isPointNearRing","maxDistanceSq","isPointNearPolygonContour","maxDistance","isScreenPointInsideLabel","screenCoord","prepareRegionHits","pickPreparedRegionAt","labelStyleResolver","labelAutoLiftOffsetPx","contourHitDistance","EMPTY_ROI_REGIONS","EMPTY_ROI_POLYGONS","EMPTY_CLIPPED_POINTS","POINT_HIT_RADIUS_SCALE","MIN_POINT_HIT_RADIUS_PX","REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS","smoothstep01","WsiViewerCanvas","onViewStateChange","onStats","onTileError","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","viewTransition","roiRegions","roiPolygons","clipPointsToRois","clipMode","onClipStats","onRoiPointGroups","roiPaletteIndexToTermId","interactionLock","drawTool","customLayers","onPointerWorldMove","onPointHover","onPointClick","onRegionHover","onRegionClick","controlledActiveRegionId","onActiveRegionChange","getCellByCoordinatesRef","overviewMapConfig","showOverviewMap","overviewMapOptions","drawInvalidateRef","overviewInvalidateRef","onViewStateChangeRef","onStatsRef","debugOverlayRef","setHoveredRegionId","useState","uncontrolledActiveRegionId","setUncontrolledActiveRegionId","isActiveRegionControlled","customLayerViewState","setCustomLayerViewState","debugStats","setDebugStats","setRegionLabelAutoLiftOffsetPx","hoveredRegionIdRef","hoveredPointIndexRef","hoveredPointIdRef","regionLabelAutoLiftOffsetRef","regionLabelAutoLiftAnimationRef","clipRunIdRef","safeRoiRegions","safePatchRegions","safeRoiPolygons","shouldTrackCustomLayerViewState","mergedDebugOverlayStyle","effectiveRoiRegions","preparedRegionHits","resolvedRegionLabelStyle","applyRegionLabelAutoLiftOffset","clamped","cancelRegionLabelAutoLiftAnimation","animateRegionLabelAutoLiftTo","clampedTarget","timestamp","nextValue","syncRegionLabelAutoLiftTarget","clipPolygons","renderPointData","setRenderPointData","runId","applyResult","stats","outputCount","shouldEnablePointHitTest","pointSpatialIndex","setPointSpatialIndex","nextIndex","getCellByCoordinates","coordinate","hitRadiusWorld","idxBuf","posBuf","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","off","pointId","emitPointHover","hit","nextId","emitPointClick","button","commitActiveRegion","handleRendererStats","debugOverlayText","currentHover","hoveredPointIndex","emitViewStateChange","callback","resolveWorldCoord","resolveScreenCoord","resolveCanvasPointerSnapshot","pickRegionHit","requestCustomLayerRedraw","effectiveCustomLayerViewState","customLayerContext","viewStateForLayer","handleRegionPointerMove","isCanvasEvent","insideImage","pointerSnapshot","nextHoverId","prevHoverId","handleRegionPointerLeave","handleRegionClick","nextActive","handleBrushTap","handleRegionContextMenu","layer"],"mappings":"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"}
|