open-plant 1.2.21 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/README.md +129 -23
  3. package/dist/assets/point-hit-index-worker-CNFA6pZm.js +2 -0
  4. package/dist/assets/point-hit-index-worker-CNFA6pZm.js.map +1 -0
  5. package/dist/assets/roi-clip-worker-BDVQwN2T.js.map +1 -1
  6. package/dist/index.cjs +7 -7
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.js +3365 -3000
  9. package/dist/index.js.map +1 -1
  10. package/dist/types/core/ortho-camera.d.ts +7 -0
  11. package/dist/types/core/ortho-camera.d.ts.map +1 -1
  12. package/dist/types/index.d.ts +5 -0
  13. package/dist/types/index.d.ts.map +1 -1
  14. package/dist/types/react/draw-layer-brush.d.ts +9 -0
  15. package/dist/types/react/draw-layer-brush.d.ts.map +1 -0
  16. package/dist/types/react/draw-layer-label.d.ts +21 -0
  17. package/dist/types/react/draw-layer-label.d.ts.map +1 -0
  18. package/dist/types/react/draw-layer-overlay.d.ts +18 -0
  19. package/dist/types/react/draw-layer-overlay.d.ts.map +1 -0
  20. package/dist/types/react/draw-layer-stamp.d.ts +24 -0
  21. package/dist/types/react/draw-layer-stamp.d.ts.map +1 -0
  22. package/dist/types/react/draw-layer-types.d.ts +243 -0
  23. package/dist/types/react/draw-layer-types.d.ts.map +1 -0
  24. package/dist/types/react/draw-layer-utils.d.ts +30 -0
  25. package/dist/types/react/draw-layer-utils.d.ts.map +1 -0
  26. package/dist/types/react/draw-layer.d.ts +4 -187
  27. package/dist/types/react/draw-layer.d.ts.map +1 -1
  28. package/dist/types/react/wsi-region-hit-utils.d.ts +21 -0
  29. package/dist/types/react/wsi-region-hit-utils.d.ts.map +1 -0
  30. package/dist/types/react/wsi-viewer-canvas.d.ts.map +1 -1
  31. package/dist/types/workers/point-hit-index-worker.d.ts +2 -0
  32. package/dist/types/workers/point-hit-index-worker.d.ts.map +1 -0
  33. package/dist/types/wsi/brush-stroke.d.ts.map +1 -1
  34. package/dist/types/wsi/image-info.d.ts +26 -1
  35. package/dist/types/wsi/image-info.d.ts.map +1 -1
  36. package/dist/types/wsi/point-clip-hybrid.d.ts.map +1 -1
  37. package/dist/types/wsi/point-clip-worker-client.d.ts.map +1 -1
  38. package/dist/types/wsi/point-clip.d.ts +1 -1
  39. package/dist/types/wsi/point-clip.d.ts.map +1 -1
  40. package/dist/types/wsi/point-hit-index-shared.d.ts +25 -0
  41. package/dist/types/wsi/point-hit-index-shared.d.ts.map +1 -0
  42. package/dist/types/wsi/point-hit-index-worker-client.d.ts +18 -0
  43. package/dist/types/wsi/point-hit-index-worker-client.d.ts.map +1 -0
  44. package/dist/types/wsi/point-hit-index-worker-protocol.d.ts +30 -0
  45. package/dist/types/wsi/point-hit-index-worker-protocol.d.ts.map +1 -0
  46. package/dist/types/wsi/roi-geometry.d.ts +3 -0
  47. package/dist/types/wsi/roi-geometry.d.ts.map +1 -1
  48. package/dist/types/wsi/roi-term-stats.d.ts.map +1 -1
  49. package/dist/types/wsi/tile-scheduler.d.ts.map +1 -1
  50. package/dist/types/wsi/utils.d.ts +3 -2
  51. package/dist/types/wsi/utils.d.ts.map +1 -1
  52. package/dist/types/wsi/worker-client.d.ts +28 -0
  53. package/dist/types/wsi/worker-client.d.ts.map +1 -0
  54. package/dist/types/wsi/wsi-canvas-lifecycle.d.ts +15 -0
  55. package/dist/types/wsi/wsi-canvas-lifecycle.d.ts.map +1 -0
  56. package/dist/types/wsi/wsi-input-handlers.d.ts +67 -0
  57. package/dist/types/wsi/wsi-input-handlers.d.ts.map +1 -0
  58. package/dist/types/wsi/wsi-interaction.d.ts +50 -0
  59. package/dist/types/wsi/wsi-interaction.d.ts.map +1 -0
  60. package/dist/types/wsi/wsi-lifecycle-ops.d.ts +38 -0
  61. package/dist/types/wsi/wsi-lifecycle-ops.d.ts.map +1 -0
  62. package/dist/types/wsi/wsi-normalize.d.ts +19 -0
  63. package/dist/types/wsi/wsi-normalize.d.ts.map +1 -0
  64. package/dist/types/wsi/wsi-point-data.d.ts +14 -0
  65. package/dist/types/wsi/wsi-point-data.d.ts.map +1 -0
  66. package/dist/types/wsi/wsi-render-pass.d.ts +39 -0
  67. package/dist/types/wsi/wsi-render-pass.d.ts.map +1 -0
  68. package/dist/types/wsi/wsi-renderer-types.d.ts +130 -0
  69. package/dist/types/wsi/wsi-renderer-types.d.ts.map +1 -0
  70. package/dist/types/wsi/wsi-shaders.d.ts +4 -0
  71. package/dist/types/wsi/wsi-shaders.d.ts.map +1 -0
  72. package/dist/types/wsi/wsi-tile-cache.d.ts +8 -0
  73. package/dist/types/wsi/wsi-tile-cache.d.ts.map +1 -0
  74. package/dist/types/wsi/wsi-tile-renderer.d.ts +9 -69
  75. package/dist/types/wsi/wsi-tile-renderer.d.ts.map +1 -1
  76. package/dist/types/wsi/wsi-tile-visibility.d.ts +22 -0
  77. package/dist/types/wsi/wsi-tile-visibility.d.ts.map +1 -0
  78. package/dist/types/wsi/wsi-view-animation.d.ts +4 -0
  79. package/dist/types/wsi/wsi-view-animation.d.ts.map +1 -0
  80. package/dist/types/wsi/wsi-view-ops.d.ts +17 -0
  81. package/dist/types/wsi/wsi-view-ops.d.ts.map +1 -0
  82. package/package.json +1 -1
@@ -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/brush-stroke.ts","../src/wsi/roi-geometry.ts","../src/wsi/constants.ts","../src/wsi/utils.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/point-clip-worker-client.ts","../src/wsi/roi-term-stats.ts","../src/wsi/tile-scheduler.ts","../src/wsi/wsi-tile-renderer.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}\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 };\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\n getViewState(): ViewState {\n return { ...this.viewState };\n }\n\n getMatrix(): Float32Array {\n const viewWidth = this.viewportWidth / this.viewState.zoom;\n const viewHeight = this.viewportHeight / this.viewState.zoom;\n\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\n return new Float32Array([\n sx,\n 0,\n 0,\n 0,\n sy,\n 0,\n tx,\n ty,\n 1,\n ]);\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","export 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 clamp(value: number, min: number, max: number): number {\n\treturn Math.max(min, Math.min(max, value));\n}\n\nfunction closeRing(\n\tcoordinates: BrushStrokeCoordinate[],\n): BrushStrokeCoordinate[] {\n\tif (!Array.isArray(coordinates) || coordinates.length < 3) return [];\n\tconst out = coordinates.map(([x, y]) => [x, y] as BrushStrokeCoordinate);\n\tconst first = out[0];\n\tconst last = out[out.length - 1];\n\tif (!first || !last) return [];\n\tif (first[0] !== last[0] || first[1] !== last[1]) {\n\t\tout.push([first[0], first[1]]);\n\t}\n\treturn out;\n}\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 polygonSignedArea(ring: BrushStrokeCoordinate[]): number {\n\tif (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 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","export type RoiCoordinate = [number, number];\nexport type RoiLinearRing = RoiCoordinate[];\nexport type RoiPolygonRings = RoiLinearRing[];\nexport type RoiMultiPolygon = RoiPolygonRings[];\nexport type RoiGeometry = RoiLinearRing | RoiPolygonRings | RoiMultiPolygon;\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, 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 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\nexport function createProgram(\n\tgl: WebGL2RenderingContext,\n\tvertexSource: string,\n\tfragmentSource: string,\n): WebGLProgram {\n\tconst vs = gl.createShader(gl.VERTEX_SHADER);\n\tconst fs = gl.createShader(gl.FRAGMENT_SHADER);\n\tif (!vs || !fs) {\n\t\tthrow new Error(\"Shader allocation failed\");\n\t}\n\n\tgl.shaderSource(vs, vertexSource);\n\tgl.compileShader(vs);\n\tif (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {\n\t\tthrow new Error(gl.getShaderInfoLog(vs) || \"vertex compile failed\");\n\t}\n\n\tgl.shaderSource(fs, fragmentSource);\n\tgl.compileShader(fs);\n\tif (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {\n\t\tthrow new Error(gl.getShaderInfoLog(fs) || \"fragment compile failed\");\n\t}\n\n\tconst program = gl.createProgram();\n\tif (!program) {\n\t\tthrow new Error(\"Program allocation failed\");\n\t}\n\n\tgl.attachShader(program, vs);\n\tgl.attachShader(program, fs);\n\tgl.linkProgram(program);\n\n\tgl.deleteShader(vs);\n\tgl.deleteShader(fs);\n\n\tif (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n\t\tthrow new Error(gl.getProgramInfoLog(program) || \"program link failed\");\n\t}\n\n\treturn program;\n}\n","import { type CSSProperties, type MutableRefObject, type PointerEvent as ReactPointerEvent, type RefObject, useCallback, useEffect, useMemo, useRef } from \"react\";\nimport { buildBrushStrokePolygon } from \"../wsi/brush-stroke\";\nimport { normalizeRoiGeometry, type RoiGeometry } from \"../wsi/roi-geometry\";\nimport { calcScaleResolution } from \"../wsi/utils\";\n\nexport type StampDrawTool = \"stamp-rectangle\" | \"stamp-circle\" | \"stamp-rectangle-4096px\" | \"stamp-rectangle-2mm2\" | \"stamp-circle-2mm2\" | \"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 /**\n * Brush radius in HTML/CSS pixels (px).\n * This value is zoom-invariant: the on-screen brush size stays fixed.\n */\n radius: number;\n /**\n * Brush edge detail factor. Higher values create rounder/finer edges.\n * Range: 0.25 ~ 4. Default: 1.\n */\n edgeDetail?: number;\n /**\n * Post-smoothing passes for brush outline to reduce stair-stepping.\n * Range: 0 ~ 4. Default: 1.\n */\n edgeSmoothing?: number;\n /**\n * When true, a brush \"tap\" (click without drag) on ROI selects that ROI\n * instead of creating a brush stroke.\n */\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\ninterface 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\ninterface NormalizedDrawRegionPolygon {\n outer: DrawCoordinate[];\n holes: DrawCoordinate[][];\n}\n\ninterface PreparedRenderedRegion {\n region: DrawRegion;\n regionIndex: number;\n regionKey: string | number;\n polygons: NormalizedDrawRegionPolygon[];\n}\n\ninterface 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\ninterface ResolvedDrawAreaTooltipOptions {\n enabled: boolean;\n format: (areaMm2: number) => string;\n style: DrawAreaTooltipStyle;\n cursorOffsetX: number;\n cursorOffsetY: number;\n}\n\nconst DRAW_FILL = \"rgba(255, 77, 79, 0.16)\";\nconst DEFAULT_DRAW_PREVIEW_FILL = \"transparent\";\nconst FREEHAND_MIN_POINTS = 3;\nconst FREEHAND_SCREEN_STEP = 2;\nconst CIRCLE_SIDES = 96;\nconst MIN_AREA_PX = 1;\nconst EMPTY_REGIONS: DrawRegion[] = [];\nconst EMPTY_DASH: number[] = [];\nconst MICRONS_PER_MM = 1000;\nconst DEFAULT_STAMP_RECTANGLE_AREA_MM2 = 2;\nconst DEFAULT_STAMP_CIRCLE_AREA_MM2 = 2;\nconst DEFAULT_STAMP_RECTANGLE_PIXEL_SIZE = 4096;\nconst LEGACY_HPF_CIRCLE_AREA_MM2 = 0.2;\nconst WHEEL_ZOOM_IN_FACTOR = 1.12;\nconst WHEEL_ZOOM_OUT_FACTOR = 0.89;\nconst DEFAULT_BRUSH_RADIUS = 32;\nconst DEFAULT_BRUSH_FILL_COLOR = \"#000000\";\nconst DEFAULT_BRUSH_FILL_OPACITY = 0.1;\nconst DEFAULT_BRUSH_CURSOR_COLOR = \"#FFCF00\";\nconst DEFAULT_BRUSH_CURSOR_ACTIVE_COLOR = \"#FF0000\";\nconst DEFAULT_BRUSH_CURSOR_LINE_WIDTH = 1.5;\nconst DEFAULT_BRUSH_CURSOR_DASH = [2, 2];\nconst DEFAULT_BRUSH_EDGE_DETAIL = 1;\nconst MIN_BRUSH_EDGE_DETAIL = 0.25;\nconst MAX_BRUSH_EDGE_DETAIL = 4;\nconst DEFAULT_BRUSH_EDGE_SMOOTHING = 1;\nconst MIN_BRUSH_EDGE_SMOOTHING = 0;\nconst MAX_BRUSH_EDGE_SMOOTHING = 4;\nconst MIN_BRUSH_RASTER_STEP = 0.05;\nconst BRUSH_RASTER_DIAMETER_SAMPLES = 256;\nconst BRUSH_SCREEN_STEP = 1.5; // CSS px\n\nconst 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\nconst 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\nconst REGION_INTERACTION_SHADOW_COLOR = \"rgba(23, 23, 25, 0.1)\";\nconst REGION_INTERACTION_SHADOW_WIDTH = 6;\n\nconst 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\nconst 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\nconst DEFAULT_DRAW_AREA_TOOLTIP_OFFSET = {\n x: 16,\n y: -24,\n} as const;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\nconst REGION_LABEL_AUTO_LIFT_MAX_EPSILON = 1e-6;\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nexport function resolveRegionLabelAutoLiftOffsetPx(\n enabled: boolean | undefined,\n zoom: number,\n zoomRange: { minZoom: number; maxZoom: number } | null | undefined\n): 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 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\nfunction 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\nfunction 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\nfunction 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\nfunction 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\nfunction 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\nfunction 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\nfunction 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\nfunction mm2ToUm2(areaMm2: number): number {\n return areaMm2 * MICRONS_PER_MM * MICRONS_PER_MM;\n}\n\nfunction 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\nfunction 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 function closeRing(coords: DrawCoordinate[]): DrawCoordinate[] {\n if (!Array.isArray(coords) || coords.length < 3) return [];\n\n const out = coords.map(([x, y]) => [x, y] as DrawCoordinate);\n const first = out[0];\n const last = out[out.length - 1];\n if (!first || !last) return [];\n\n if (first[0] !== last[0] || first[1] !== last[1]) {\n out.push([first[0], first[1]]);\n }\n\n return out;\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\nfunction polygonArea(coords: DrawCoordinate[]): number {\n if (!Array.isArray(coords) || coords.length < 4) return 0;\n\n let sum = 0;\n for (let i = 0; i < coords.length - 1; i += 1) {\n const a = coords[i];\n const b = coords[i + 1];\n sum += a[0] * b[1] - b[0] * a[1];\n }\n\n return Math.abs(sum * 0.5);\n}\n\nfunction 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\nfunction isValidPolygon(coords: DrawCoordinate[]): boolean {\n return Array.isArray(coords) && coords.length >= 4 && polygonArea(coords) > MIN_AREA_PX;\n}\n\nfunction 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\nfunction drawPath(\n ctx: CanvasRenderingContext2D,\n points: DrawCoordinate[],\n strokeStyle: RegionStrokeStyle,\n close = false,\n fill = false,\n fillColor = DRAW_FILL\n): 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\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 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\nfunction 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\nfunction 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\nfunction isNestedRingCoordinates(coordinates: DrawOverlayCoordinates): boolean {\n const first = coordinates[0];\n return Array.isArray(first) && Array.isArray(first[0]);\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === \"number\" && Number.isFinite(value);\n}\n\nfunction isCoordinatePair(value: unknown): value is [number, number] {\n return Array.isArray(value) && value.length >= 2 && isFiniteNumber(value[0]) && isFiniteNumber(value[1]);\n}\n\nfunction 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\nfunction 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\nfunction 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 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\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\nfunction defaultDrawAreaTooltipFormatter(areaMm2: number): string {\n if (!Number.isFinite(areaMm2)) return \"0.000 mm²\";\n return `${Math.max(0, areaMm2).toFixed(3)} mm²`;\n}\n\nfunction 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\nfunction resolveRegionInteractionShadowStyle(strokeStyle: RegionStrokeStyle): 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 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\nfunction 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) > 0.5) 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\nfunction getTopAnchorFromPolygons(polygons: NormalizedDrawRegionPolygon[]): 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\nfunction normalizeDrawRegionPolygons(coordinates: DrawRegionCoordinates): NormalizedDrawRegionPolygon[] {\n const multipolygon = normalizeRoiGeometry(coordinates as RoiGeometry);\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\nfunction 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 = ctx.measureText(label).width;\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\nfunction 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 = ctx.measureText(label).width;\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\nfunction clampWorld(coord: DrawCoordinate, imageWidth: number, imageHeight: number): DrawCoordinate {\n return [clamp(coord[0], 0, imageWidth), clamp(coord[1], 0, imageHeight)];\n}\n\nfunction toCoord(value: DrawCoordinate | number[]): 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 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: DrawCoordinate[]): DrawCoordinate[] => {\n const projector = projectorRef.current;\n if (!projector || points.length === 0) return [];\n\n const out = new Array<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: DrawCoordinate): 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): DrawCoordinate | null =>\n 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 // If mpp is missing, fall back to 1um/px assumption.\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 buildStampCoords = useCallback(\n (stampTool: StampDrawTool, center: DrawCoordinate | null): DrawCoordinate[] => {\n if (!center) return [];\n\n let areaMm2 = 0;\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 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 [micronsToWorldPixels, imageWidth, imageHeight, resolvedStampOptions, getRectangleProjection]\n );\n\n const buildPreviewCoords = useCallback((): DrawCoordinate[] => {\n const session = sessionRef.current;\n if (isStampTool(tool)) {\n return buildStampCoords(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, buildStampCoords, getRectangleProjection]);\n\n const drawBrushStrokePreview = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\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 [resolvedBrushOptions]\n );\n\n const drawBrushCursor = useCallback(\n (ctx: CanvasRenderingContext2D): void => {\n const session = sessionRef.current;\n const cursor = session.cursor;\n if (!cursor) return;\n const screen =\n session.cursorScreen ??\n toCoord(projectorRef.current?.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 [projectorRef, resolvedBrushOptions]\n );\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 // Persisted ROI outlines always remain visible.\n if (preparedPersistedRegions.length > 0) {\n for (const entry of preparedPersistedRegions) {\n const { region, polygons, regionIndex, regionKey } = entry;\n const state: RegionStyleContext[\"state\"] = 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 debugOverlay = Boolean((globalThis as { __OPEN_PLANT_DEBUG_OVERLAY__?: boolean }).__OPEN_PLANT_DEBUG_OVERLAY__);\n const imageOuterRing = worldToScreenPoints(\n closeRing([\n [0, 0],\n [imageWidth, 0],\n [imageWidth, imageHeight],\n [0, imageHeight],\n ])\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) {\n const debugKey = String(shape.id ?? i);\n const debugSignature = `${imageOuterRing.length}|${closedRings.length}|${holeRings.length}|${shape.invertedFill.fillColor}`;\n if (overlayDebugSnapshotRef.current.get(debugKey) !== debugSignature) {\n overlayDebugSnapshotRef.current.set(debugKey, debugSignature);\n console.debug(\"[open-plant] invertedFill\", {\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 }\n drawInvertedFillMask(ctx, imageOuterRing, holeRings, shape.invertedFill.fillColor);\n }\n\n if (renderRings.length === 0) continue;\n const strokeStyle = mergeStrokeStyle(resolvedStrokeStyle, 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\n const preview = buildPreviewCoords();\n\n if (active) {\n if (tool === \"brush\") {\n drawBrushStrokePreview(ctx);\n drawBrushCursor(ctx);\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 // Draw labels last so they stay visually on top.\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 let text = defaultDrawAreaTooltipFormatter(areaMm2);\n try {\n text = resolvedDrawAreaTooltipOptions.format(areaMm2);\n } catch {\n text = defaultDrawAreaTooltipFormatter(areaMm2);\n }\n\n const cursor =\n session.cursorScreen ??\n (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 drawBrushStrokePreview,\n drawBrushCursor,\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 ]);\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 try {\n canvas.releasePointerCapture(session.pointerId);\n } catch {\n // noop\n }\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>): 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>): 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: 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(\n MIN_BRUSH_RASTER_STEP,\n (resolvedBrushOptions.radius * 2) / (BRUSH_RASTER_DIAMETER_SAMPLES * edgeDetail),\n );\n const screenPath =\n session.screenPoints.length > 0\n ? session.screenPoints\n : 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 DrawCoordinate[];\n const worldPolygon: 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: 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 }, [tool, onDrawComplete, resetSession, requestDraw, worldToScreenPoints, localScreenToWorld, getRectangleProjection, resolvedBrushOptions.radius, resolvedBrushOptions.edgeDetail, resolvedBrushOptions.edgeSmoothing, resolvedBrushOptions.clickSelectRoi, onBrushTap]);\n\n const handleStampAt = useCallback(\n (stampTool: StampDrawTool, center: DrawCoordinate): void => {\n const coordinates = buildStampCoords(stampTool, center);\n if (!isValidPolygon(coordinates)) return;\n const intent: DrawIntent = stampTool === \"stamp-rectangle-4096px\" ? \"patch\" : \"roi\";\n const result: 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 PatchDrawResult);\n }\n },\n [buildStampCoords, onDrawComplete, onPatchComplete]\n );\n\n const appendBrushPoint = useCallback(\n (session: DrawSession, world: DrawCoordinate, screen: 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 );\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 try {\n canvas.releasePointerCapture(event.pointerId);\n } catch {\n // noop\n }\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\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: any, 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(\"이미지 메타데이터가 불완전합니다. width/height/tileSize/path 확인 필요\");\n }\n\n const terms: WsiTerm[] = Array.isArray(raw?.terms)\n ? raw.terms.map((term: any) => ({\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 type { WsiPointData } from \"./types\";\nimport {\n\tpointInAnyPreparedPolygon,\n\tprepareRoiPolygons,\n\ttype RoiCoordinate,\n\ttype RoiGeometry,\n} from \"./roi-geometry\";\n\nexport type { RoiCoordinate };\nexport type RoiPolygon = RoiGeometry;\n\nfunction 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 filterPointDataByPolygons(\n\tpointData: WsiPointData | null | undefined,\n\tpolygons: RoiPolygon[] | null | undefined,\n): WsiPointData | null {\n\tif (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n\t\treturn null;\n\t}\n\n\tconst prepared = prepareRoiPolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\tconst empty: WsiPointData = {\n\t\t\tcount: 0,\n\t\t\tpositions: new Float32Array(0),\n\t\t\tpaletteIndices: new Uint16Array(0),\n\t\t};\n\t\tif (pointData.fillModes instanceof Uint8Array) {\n\t\t\tempty.fillModes = new Uint8Array(0);\n\t\t}\n\t\tif (pointData.ids instanceof Uint32Array) {\n\t\t\tempty.ids = new Uint32Array(0);\n\t\t}\n\t\treturn empty;\n\t}\n\n\tconst count = sanitizePointCount(pointData);\n\tconst positions = pointData.positions;\n\tconst terms = pointData.paletteIndices;\n\tconst fillModes =\n\t\tpointData.fillModes instanceof Uint8Array && pointData.fillModes.length >= count\n\t\t\t? pointData.fillModes\n\t\t\t: null;\n\tconst pointIds =\n\t\tpointData.ids instanceof Uint32Array && pointData.ids.length >= count\n\t\t\t? pointData.ids\n\t\t\t: null;\n\n\tconst nextPositions = new Float32Array(count * 2);\n\tconst nextTerms = new Uint16Array(count);\n\tconst nextFillModes = fillModes ? new Uint8Array(count) : null;\n\tconst nextIds = pointIds ? new Uint32Array(count) : null;\n\tlet cursor = 0;\n\n\tfor (let i = 0; i < count; i += 1) {\n\t\tconst x = positions[i * 2];\n\t\tconst y = positions[i * 2 + 1];\n\t\tif (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n\t\tnextPositions[cursor * 2] = x;\n\t\tnextPositions[cursor * 2 + 1] = y;\n\t\tnextTerms[cursor] = terms[i];\n\t\tif (nextFillModes) {\n\t\t\tnextFillModes[cursor] = fillModes![i];\n\t\t}\n\t\tif (nextIds) {\n\t\t\tnextIds[cursor] = pointIds![i];\n\t\t}\n\t\tcursor += 1;\n\t}\n\n\tconst output: WsiPointData = {\n\t\tcount: cursor,\n\t\tpositions: nextPositions.subarray(0, cursor * 2),\n\t\tpaletteIndices: nextTerms.subarray(0, cursor),\n\t};\n\tif (nextFillModes) {\n\t\toutput.fillModes = nextFillModes.subarray(0, cursor);\n\t}\n\tif (nextIds) {\n\t\toutput.ids = nextIds.subarray(0, cursor);\n\t}\n\treturn output;\n}\n\nexport function filterPointIndicesByPolygons(\n\tpointData: WsiPointData | null | undefined,\n\tpolygons: RoiPolygon[] | null | undefined,\n): Uint32Array {\n\tif (!pointData || !pointData.count || !pointData.positions || !pointData.paletteIndices) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst prepared = prepareRoiPolygons(polygons ?? []);\n\tif (prepared.length === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst count = sanitizePointCount(pointData);\n\tif (count === 0) {\n\t\treturn new Uint32Array(0);\n\t}\n\n\tconst positions = pointData.positions;\n\tconst out = new Uint32Array(count);\n\tlet cursor = 0;\n\n\tfor (let i = 0; i < count; i += 1) {\n\t\tconst x = positions[i * 2];\n\t\tconst y = positions[i * 2 + 1];\n\t\tif (!pointInAnyPreparedPolygon(x, y, prepared)) continue;\n\t\tout[cursor] = i;\n\t\tcursor += 1;\n\t}\n\n\treturn 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 { 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\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\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 fillModesLength =\n pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\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","import { filterPointDataByPolygons, filterPointIndicesByPolygons, type RoiPolygon } from \"./point-clip\";\nimport type { RoiClipWorkerRequest, RoiClipWorkerResponse } from \"./point-clip-worker-protocol\";\nimport type { WsiPointData } from \"./types\";\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\nlet workerInstance: Worker | null = null;\nlet workerSupported = true;\nlet requestId = 1;\nconst pendingById = new Map<number, PendingWorkerRequest>();\n\nfunction nowMs(): number {\n if (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n return performance.now();\n }\n return Date.now();\n}\n\nfunction createWorker(): Worker | null {\n if (!workerSupported) return null;\n if (workerInstance) return workerInstance;\n try {\n const worker = new Worker(new URL(\"../workers/roi-clip-worker.ts\", import.meta.url), { type: \"module\" });\n worker.addEventListener(\"message\", handleWorkerMessage);\n worker.addEventListener(\"error\", handleWorkerError);\n workerInstance = worker;\n return worker;\n } catch {\n workerSupported = false;\n return null;\n }\n}\n\nfunction handleWorkerMessage(event: MessageEvent<RoiClipWorkerResponse>): void {\n const msg = event.data;\n if (!msg) return;\n const pending = pendingById.get(msg.id);\n if (!pending) return;\n pendingById.delete(msg.id);\n\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: Number.isFinite(msg.durationMs) ? msg.durationMs : 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: Number.isFinite(msg.durationMs) ? msg.durationMs : nowMs() - pending.startMs,\n },\n });\n}\n\nfunction handleWorkerError(): void {\n workerSupported = false;\n if (workerInstance) {\n workerInstance.removeEventListener(\"message\", handleWorkerMessage);\n workerInstance.removeEventListener(\"error\", handleWorkerError);\n workerInstance.terminate();\n workerInstance = null;\n }\n for (const [, pending] of pendingById) {\n pending.reject(new Error(\"worker crashed\"));\n }\n pendingById.clear();\n}\n\nexport function terminateRoiClipWorker(): void {\n if (!workerInstance) return;\n workerInstance.removeEventListener(\"message\", handleWorkerMessage);\n workerInstance.removeEventListener(\"error\", handleWorkerError);\n workerInstance.terminate();\n workerInstance = null;\n for (const [, pending] of pendingById) {\n pending.reject(new Error(\"worker terminated\"));\n }\n pendingById.clear();\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 worker = createWorker();\n if (!worker) {\n const start = nowMs();\n return {\n data: filterPointDataByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - start },\n };\n }\n\n const fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\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 const id = requestId++;\n const startMs = nowMs();\n\n return new Promise<PointClipResult>((resolve, reject) => {\n pendingById.set(id, { kind: \"data\", resolve, reject, startMs });\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-request\",\n 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 const transfer: Transferable[] = [positionsCopy.buffer, termsCopy.buffer];\n if (fillModesCopy) {\n transfer.push(fillModesCopy.buffer);\n }\n if (idsCopy) {\n transfer.push(idsCopy.buffer);\n }\n worker.postMessage(msg, transfer);\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 worker = createWorker();\n if (!worker) {\n const start = nowMs();\n return {\n indices: filterPointIndicesByPolygons(pointData, polygons),\n meta: { mode: \"sync\", durationMs: nowMs() - start },\n };\n }\n\n const fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n const safeCount = Math.max(0, Math.min(pointData.count, Math.floor(pointData.positions.length / 2), pointData.paletteIndices.length, fillModesLength));\n const positionsCopy = pointData.positions.slice(0, safeCount * 2);\n const id = requestId++;\n const startMs = nowMs();\n\n return new Promise<PointClipIndexResult>((resolve, reject) => {\n pendingById.set(id, { kind: \"index\", resolve, reject, startMs });\n const msg: RoiClipWorkerRequest = {\n type: \"roi-clip-index-request\",\n id,\n count: safeCount,\n positions: positionsCopy.buffer,\n polygons: polygons ?? [],\n };\n worker.postMessage(msg, [positionsCopy.buffer]);\n });\n}\n","import type { WsiPointData, WsiRegion } from \"./types\";\nimport {\n\tpointInPreparedPolygon,\n\tprepareRoiPolygons,\n\ttype PreparedRoiPolygon,\n\ttype RoiGeometry,\n} from \"./roi-geometry\";\n\nexport interface RoiTermCount {\n\ttermId: string;\n\tpaletteIndex: number;\n\tcount: number;\n}\n\nexport interface RoiPointGroup {\n\tregionId: string | number;\n\tregionIndex: number;\n\ttotalCount: number;\n\ttermCounts: RoiTermCount[];\n}\n\nexport interface RoiPointGroupOptions {\n\tpaletteIndexToTermId?: ReadonlyMap<number, string> | readonly string[];\n\tincludeEmptyRegions?: boolean;\n}\n\nexport interface RoiPointGroupStats {\n\tgroups: RoiPointGroup[];\n\tinputPointCount: number;\n\tpointsInsideAnyRegion: number;\n\tunmatchedPointCount: number;\n}\n\ninterface PreparedRegion {\n\tregionId: string | number;\n\tregionIndex: number;\n\tpolygons: PreparedRoiPolygon[];\n\tarea: number;\n}\n\nfunction prepareRegions(regions: readonly WsiRegion[]): PreparedRegion[] {\n\tconst prepared: PreparedRegion[] = [];\n\tfor (let i = 0; i < regions.length; i += 1) {\n\t\tconst region = regions[i];\n\t\tconst polygons = prepareRoiPolygons([region?.coordinates as RoiGeometry | null | undefined]);\n\t\tif (polygons.length === 0) continue;\n\n\t\tlet area = 0;\n\t\tfor (const polygon of polygons) {\n\t\t\tarea += polygon.area;\n\t\t}\n\n\t\tprepared.push({\n\t\t\tregionId: region.id ?? i,\n\t\t\tregionIndex: i,\n\t\t\tpolygons,\n\t\t\tarea: Math.max(1e-6, area),\n\t\t});\n\t}\n\treturn prepared;\n}\n\nfunction resolveTermId(\n\tpaletteIndex: number,\n\tpaletteIndexToTermId: RoiPointGroupOptions[\"paletteIndexToTermId\"],\n): string {\n\tif (Array.isArray(paletteIndexToTermId)) {\n\t\tconst fromArray = paletteIndexToTermId[paletteIndex];\n\t\tif (typeof fromArray === \"string\" && fromArray.length > 0) return fromArray;\n\t}\n\tif (paletteIndexToTermId instanceof Map) {\n\t\tconst fromMap = paletteIndexToTermId.get(paletteIndex);\n\t\tif (typeof fromMap === \"string\" && fromMap.length > 0) return fromMap;\n\t}\n\treturn String(paletteIndex);\n}\n\nexport function computeRoiPointGroups(\n\tpointData: WsiPointData | null | undefined,\n\tregions: readonly WsiRegion[] | null | undefined,\n\toptions: RoiPointGroupOptions = {},\n): RoiPointGroupStats {\n\tconst baseCount = 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\tpointData?.fillModes instanceof Uint8Array\n\t\t\t\t? pointData.fillModes.length\n\t\t\t\t: Number.MAX_SAFE_INTEGER,\n\t\t),\n\t);\n\n\tlet drawIndices: Uint32Array | null = null;\n\tif (pointData?.drawIndices instanceof Uint32Array) {\n\t\tconst source = pointData.drawIndices;\n\t\tlet valid = source.length;\n\t\tfor (let i = 0; i < source.length; i += 1) {\n\t\t\tconst idx = source[i];\n\t\t\tif (idx < baseCount) continue;\n\t\t\tvalid -= 1;\n\t\t}\n\t\tif (valid === source.length) {\n\t\t\tdrawIndices = source;\n\t\t} else if (valid > 0) {\n\t\t\tconst filtered = new Uint32Array(valid);\n\t\t\tlet cursor = 0;\n\t\t\tfor (let i = 0; i < source.length; i += 1) {\n\t\t\t\tconst idx = source[i];\n\t\t\t\tif (idx >= baseCount) continue;\n\t\t\t\tfiltered[cursor] = idx;\n\t\t\t\tcursor += 1;\n\t\t\t}\n\t\t\tdrawIndices = filtered;\n\t\t} else {\n\t\t\tdrawIndices = new Uint32Array(0);\n\t\t}\n\t}\n\n\tconst inputCount = drawIndices ? drawIndices.length : baseCount;\n\n\tconst preparedRegions = prepareRegions(regions ?? []);\n\tif (!pointData || inputCount === 0 || preparedRegions.length === 0) {\n\t\treturn {\n\t\t\tgroups: [],\n\t\t\tinputPointCount: inputCount,\n\t\t\tpointsInsideAnyRegion: 0,\n\t\t\tunmatchedPointCount: inputCount,\n\t\t};\n\t}\n\n\tconst regionTermCounters = new Map<number, Map<number, number>>();\n\tconst regionTotalCounters = new Map<number, number>();\n\tlet insideCount = 0;\n\n\tfor (let i = 0; i < inputCount; i += 1) {\n\t\tconst pointIndex = drawIndices ? drawIndices[i] : i;\n\t\tconst x = pointData.positions[pointIndex * 2];\n\t\tconst y = pointData.positions[pointIndex * 2 + 1];\n\t\tlet bestRegion: PreparedRegion | null = null;\n\n\t\tfor (const region of preparedRegions) {\n\t\t\tlet inside = false;\n\t\t\tfor (const polygon of region.polygons) {\n\t\t\t\tif (!pointInPreparedPolygon(x, y, polygon)) continue;\n\t\t\t\tinside = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!inside) continue;\n\t\t\tif (!bestRegion || region.area < bestRegion.area) {\n\t\t\t\tbestRegion = region;\n\t\t\t}\n\t\t}\n\n\t\tif (!bestRegion) continue;\n\t\tinsideCount += 1;\n\n\t\tconst paletteIndex = pointData.paletteIndices[pointIndex] ?? 0;\n\t\tconst regionTermMap =\n\t\t\tregionTermCounters.get(bestRegion.regionIndex) ?? new Map<number, number>();\n\t\tregionTermMap.set(paletteIndex, (regionTermMap.get(paletteIndex) ?? 0) + 1);\n\t\tregionTermCounters.set(bestRegion.regionIndex, regionTermMap);\n\t\tregionTotalCounters.set(\n\t\t\tbestRegion.regionIndex,\n\t\t\t(regionTotalCounters.get(bestRegion.regionIndex) ?? 0) + 1,\n\t\t);\n\t}\n\n\tconst includeEmptyRegions = options.includeEmptyRegions ?? false;\n\tconst groups: RoiPointGroup[] = [];\n\tfor (const region of preparedRegions) {\n\t\tconst totalCount = regionTotalCounters.get(region.regionIndex) ?? 0;\n\t\tif (!includeEmptyRegions && totalCount <= 0) continue;\n\t\tconst termMap = regionTermCounters.get(region.regionIndex) ?? new Map();\n\t\tconst termCounts: RoiTermCount[] = Array.from(termMap.entries())\n\t\t\t.map(([paletteIndex, count]) => ({\n\t\t\t\ttermId: resolveTermId(paletteIndex, options.paletteIndexToTermId),\n\t\t\t\tpaletteIndex,\n\t\t\t\tcount,\n\t\t\t}))\n\t\t\t.sort((a, b) => b.count - a.count || a.paletteIndex - b.paletteIndex);\n\n\t\tgroups.push({\n\t\t\tregionId: region.regionId,\n\t\t\tregionIndex: region.regionIndex,\n\t\t\ttotalCount,\n\t\t\ttermCounts,\n\t\t});\n\t}\n\n\treturn {\n\t\tgroups,\n\t\tinputPointCount: inputCount,\n\t\tpointsInsideAnyRegion: insideCount,\n\t\tunmatchedPointCount: Math.max(0, inputCount - insideCount),\n\t};\n}\n","export 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 nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\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 { toTileUrl } from \"./image-info\";\nimport {\n\tTileScheduler,\n\ttype ScheduledTile,\n\ttype TileBounds,\n} from \"./tile-scheduler\";\nimport type {\n\tWsiImageColorSettings,\n\tWsiImageSource,\n\tWsiPointData,\n\tWsiRenderStats,\n\tWsiViewState,\n} from \"./types\";\nimport { clamp, createProgram } from \"./utils\";\n\ntype Bounds = TileBounds;\n\ninterface CachedTile {\n\tkey: string;\n\ttexture: WebGLTexture;\n\tbounds: Bounds;\n\ttier: number;\n\tlastUsed: number;\n}\n\ninterface TileVertexProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tvbo: WebGLBuffer;\n\tuCamera: WebGLUniformLocation;\n\tuBounds: WebGLUniformLocation;\n\tuTexture: WebGLUniformLocation;\n\tuBrightness: WebGLUniformLocation;\n\tuContrast: WebGLUniformLocation;\n\tuSaturation: WebGLUniformLocation;\n}\n\ninterface PointProgram {\n\tprogram: WebGLProgram;\n\tvao: WebGLVertexArrayObject;\n\tposBuffer: WebGLBuffer;\n\ttermBuffer: WebGLBuffer;\n\tfillModeBuffer: WebGLBuffer;\n\tindexBuffer: WebGLBuffer;\n\tpaletteTexture: WebGLTexture;\n\tuCamera: WebGLUniformLocation;\n\tuPointSize: WebGLUniformLocation;\n\tuPalette: WebGLUniformLocation;\n\tuPaletteSize: WebGLUniformLocation;\n\tuPointStrokeScale: WebGLUniformLocation;\n}\n\ninterface OrthoViewport {\n\twidth: number;\n\theight: number;\n}\n\ntype WorldPoint = [number, number];\nconst DEFAULT_ROTATION_DRAG_SENSITIVITY = 0.35;\nconst MIN_POINT_SIZE_PX = 0.5;\nconst MAX_POINT_SIZE_PX = 256;\n\ninterface PointSizeStop {\n\tzoom: number;\n\tsize: number;\n}\n\nconst DEFAULT_POINT_SIZE_STOPS: readonly PointSizeStop[] = [\n\t{ zoom: 1, size: 2.8 },\n\t{ zoom: 2, size: 3.4 },\n\t{ zoom: 3, size: 4.2 },\n\t{ zoom: 4, size: 5.3 },\n\t{ zoom: 5, size: 6.8 },\n\t{ zoom: 6, size: 8.4 },\n\t{ zoom: 7, size: 9.8 },\n\t{ zoom: 8, size: 11.2 },\n\t{ zoom: 9, size: 14.0 },\n\t{ zoom: 10, size: 17.5 },\n\t{ zoom: 11, size: 22.0 },\n\t{ zoom: 12, size: 28.0 },\n];\n\nexport type PointSizeByZoom = Readonly<Record<number, number>>;\n\nexport interface WsiViewTransitionOptions {\n\tduration?: number;\n\teasing?: (t: number) => number;\n}\n\nexport interface WsiTileSchedulerConfig {\n\tmaxConcurrency?: number;\n\tmaxRetries?: number;\n\tretryBaseDelayMs?: number;\n\tretryMaxDelayMs?: number;\n}\n\nexport interface WsiTileRendererOptions {\n\tonViewStateChange?: (next: WsiViewState) => void;\n\tonStats?: (stats: WsiRenderStats) => void;\n\tauthToken?: string;\n\timageColorSettings?: WsiImageColorSettings | null;\n\tminZoom?: number;\n\tmaxZoom?: number;\n\tviewTransition?: WsiViewTransitionOptions;\n\tpointSizeByZoom?: PointSizeByZoom;\n\tpointStrokeScale?: number;\n\tmaxCacheTiles?: number;\n\tctrlDragRotate?: boolean;\n\trotationDragSensitivityDegPerPixel?: number;\n\ttileScheduler?: WsiTileSchedulerConfig;\n\tonTileError?: (event: WsiTileErrorEvent) => void;\n\tonContextLost?: () => void;\n\tonContextRestored?: () => void;\n}\n\nexport interface WsiTileErrorEvent {\n\ttile: ScheduledTile;\n\terror: unknown;\n\tattemptCount: number;\n}\n\ninterface ViewAnimationState {\n\tstartMs: number;\n\tdurationMs: number;\n\tfrom: WsiViewState;\n\tto: WsiViewState;\n\teasing: (t: number) => number;\n}\n\nclass OrthoCamera {\n\tprivate viewportWidth = 1;\n\tprivate viewportHeight = 1;\n\tprivate viewState: WsiViewState = {\n\t\tzoom: 1,\n\t\toffsetX: 0,\n\t\toffsetY: 0,\n\t\trotationDeg: 0,\n\t};\n\n\tsetViewport(width: number, height: number): void {\n\t\tthis.viewportWidth = Math.max(1, width);\n\t\tthis.viewportHeight = Math.max(1, height);\n\t}\n\n\tgetViewport(): OrthoViewport {\n\t\treturn { width: this.viewportWidth, height: this.viewportHeight };\n\t}\n\n\tsetViewState(next: Partial<WsiViewState>): void {\n\t\tif (typeof next.zoom === \"number\") {\n\t\t\tthis.viewState.zoom = Math.max(0.0001, next.zoom);\n\t\t}\n\t\tif (typeof next.offsetX === \"number\") {\n\t\t\tthis.viewState.offsetX = next.offsetX;\n\t\t}\n\t\tif (typeof next.offsetY === \"number\") {\n\t\t\tthis.viewState.offsetY = next.offsetY;\n\t\t}\n\t\tif (typeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)) {\n\t\t\tthis.viewState.rotationDeg = next.rotationDeg;\n\t\t}\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn { ...this.viewState };\n\t}\n\n\tgetCenter(): WorldPoint {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\treturn [\n\t\t\tthis.viewState.offsetX + this.viewportWidth / (2 * zoom),\n\t\t\tthis.viewState.offsetY + this.viewportHeight / (2 * zoom),\n\t\t];\n\t}\n\n\tsetCenter(centerX: number, centerY: number): void {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\tthis.viewState.offsetX = centerX - this.viewportWidth / (2 * zoom);\n\t\tthis.viewState.offsetY = centerY - this.viewportHeight / (2 * zoom);\n\t}\n\n\tscreenToWorld(screenX: number, screenY: number): WorldPoint {\n\t\tconst state = this.viewState;\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst dx = (screenX - this.viewportWidth * 0.5) / zoom;\n\t\tconst dy = (screenY - this.viewportHeight * 0.5) / zoom;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\treturn [centerX + dx * cos - dy * sin, centerY + dx * sin + dy * cos];\n\t}\n\n\tworldToScreen(worldX: number, worldY: number): WorldPoint {\n\t\tconst state = this.viewState;\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst dx = worldX - centerX;\n\t\tconst dy = worldY - centerY;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\tconst rx = dx * cos + dy * sin;\n\t\tconst ry = -dx * sin + dy * cos;\n\t\treturn [\n\t\t\tthis.viewportWidth * 0.5 + rx * zoom,\n\t\t\tthis.viewportHeight * 0.5 + ry * zoom,\n\t\t];\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\tconst w = this.viewportWidth;\n\t\tconst h = this.viewportHeight;\n\t\treturn [\n\t\t\tthis.screenToWorld(0, 0),\n\t\t\tthis.screenToWorld(w, 0),\n\t\t\tthis.screenToWorld(w, h),\n\t\t\tthis.screenToWorld(0, h),\n\t\t];\n\t}\n\n\tgetMatrix(): Float32Array {\n\t\tconst zoom = Math.max(1e-6, this.viewState.zoom);\n\t\tconst [centerX, centerY] = this.getCenter();\n\t\tconst rad = toRadians(this.viewState.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\n\t\tconst ax = (2 * zoom * cos) / this.viewportWidth;\n\t\tconst bx = (2 * zoom * sin) / this.viewportWidth;\n\t\tconst ay = (2 * zoom * sin) / this.viewportHeight;\n\t\tconst by = (-2 * zoom * cos) / this.viewportHeight;\n\t\tconst tx = -(ax * centerX + bx * centerY);\n\t\tconst ty = -(ay * centerX + by * centerY);\n\n\t\treturn new Float32Array([ax, ay, 0, bx, by, 0, tx, ty, 1]);\n\t}\n}\n\nfunction toRadians(deg: number): number {\n\treturn (deg * Math.PI) / 180;\n}\n\nfunction nowMs(): number {\n\tif (typeof performance !== \"undefined\" && typeof performance.now === \"function\") {\n\t\treturn performance.now();\n\t}\n\treturn Date.now();\n}\n\nfunction requireUniformLocation(\n\tgl: WebGL2RenderingContext,\n\tprogram: WebGLProgram,\n\tname: string,\n): WebGLUniformLocation {\n\tconst location = gl.getUniformLocation(program, name);\n\tif (!location) {\n\t\tthrow new Error(`uniform location lookup failed: ${name}`);\n\t}\n\treturn location;\n}\n\nfunction isSameArrayView(\n\ta: ArrayBufferView | null | undefined,\n\tb: ArrayBufferView | null | undefined,\n): boolean {\n\tif (!a || !b) return a === b;\n\treturn (\n\t\ta.buffer === b.buffer &&\n\t\ta.byteOffset === b.byteOffset &&\n\t\ta.byteLength === b.byteLength\n\t);\n}\n\nfunction clonePointSizeStops(stops: readonly PointSizeStop[]): PointSizeStop[] {\n\treturn stops.map(stop => ({ zoom: stop.zoom, size: stop.size }));\n}\n\nfunction normalizePointSizeStops(pointSizeByZoom: PointSizeByZoom | null | undefined): PointSizeStop[] {\n\tif (!pointSizeByZoom) return clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\n\tconst parsed = new Map<number, number>();\n\tfor (const [zoomKey, rawSize] of Object.entries(pointSizeByZoom)) {\n\t\tconst zoom = Number(zoomKey);\n\t\tconst size = Number(rawSize);\n\t\tif (!Number.isFinite(zoom) || !Number.isFinite(size) || size <= 0) continue;\n\t\tparsed.set(zoom, size);\n\t}\n\n\tif (parsed.size === 0) {\n\t\treturn clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\t}\n\n\treturn Array.from(parsed.entries())\n\t\t.sort((a, b) => a[0] - b[0])\n\t\t.map(([zoom, size]) => ({ zoom, size }));\n}\n\nfunction arePointSizeStopsEqual(a: readonly PointSizeStop[], b: readonly PointSizeStop[]): boolean {\n\tif (a === b) return true;\n\tif (a.length !== b.length) return false;\n\tfor (let i = 0; i < a.length; i += 1) {\n\t\tif (a[i].zoom !== b[i].zoom || a[i].size !== b[i].size) {\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\nfunction resolvePointSizeByZoomStops(continuousZoom: number, stops: readonly PointSizeStop[]): number {\n\tif (!Number.isFinite(continuousZoom)) return stops[0]?.size ?? MIN_POINT_SIZE_PX;\n\tif (stops.length === 0) return MIN_POINT_SIZE_PX;\n\tif (stops.length === 1) return stops[0].size;\n\tif (continuousZoom <= stops[0].zoom) return stops[0].size;\n\n\tfor (let i = 1; i < stops.length; i += 1) {\n\t\tconst prev = stops[i - 1];\n\t\tconst next = stops[i];\n\t\tif (continuousZoom > next.zoom) continue;\n\t\tconst span = Math.max(1e-6, next.zoom - prev.zoom);\n\t\tconst t = clamp((continuousZoom - prev.zoom) / span, 0, 1);\n\t\treturn prev.size + (next.size - prev.size) * t;\n\t}\n\n\tconst last = stops[stops.length - 1];\n\tconst prev = stops[stops.length - 2];\n\tconst span = Math.max(1e-6, last.zoom - prev.zoom);\n\tconst slope = (last.size - prev.size) / span;\n\treturn last.size + (continuousZoom - last.zoom) * slope;\n}\n\nconst MIN_STROKE_SCALE = 0.1;\nconst MAX_STROKE_SCALE = 5.0;\n\nfunction normalizeStrokeScale(value: number | null | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 1.0;\n\treturn clamp(value, MIN_STROKE_SCALE, MAX_STROKE_SCALE);\n}\n\nconst MIN_IMAGE_COLOR_INPUT = -100;\nconst MAX_IMAGE_COLOR_INPUT = 100;\n\ninterface NormalizedImageColorSettings {\n\tbrightness: number;\n\tcontrast: number;\n\tsaturation: number;\n}\n\nfunction normalizeImageColorInput(value: number | null | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 0;\n\treturn clamp(value, MIN_IMAGE_COLOR_INPUT, MAX_IMAGE_COLOR_INPUT);\n}\n\nfunction toNormalizedImageColorSettings(\n\tsettings: WsiImageColorSettings | null | undefined,\n): NormalizedImageColorSettings {\n\tconst brightnessInput = normalizeImageColorInput(settings?.brightness);\n\tconst contrastInput = normalizeImageColorInput(settings?.contrast);\n\tconst saturationInput = normalizeImageColorInput(settings?.saturation);\n\treturn {\n\t\tbrightness: brightnessInput / 200,\n\t\tcontrast: contrastInput / 100,\n\t\tsaturation: saturationInput / 100,\n\t};\n}\n\nconst MAX_VIEW_TRANSITION_DURATION_MS = 2000;\n\nfunction linearEasing(t: number): number {\n\treturn t;\n}\n\nfunction normalizeViewTransitionDuration(duration: number | null | undefined): number {\n\tif (typeof duration !== \"number\" || !Number.isFinite(duration)) return 0;\n\treturn clamp(duration, 0, MAX_VIEW_TRANSITION_DURATION_MS);\n}\n\nfunction normalizeZoomOverride(value: number | null | undefined): number | null {\n\tif (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) return null;\n\treturn Math.max(1e-6, value);\n}\n\nfunction normalizeTransitionEasing(\n\teasing: ((t: number) => number) | null | undefined,\n): (t: number) => number {\n\treturn typeof easing === \"function\" ? easing : linearEasing;\n}\n\nfunction isSameViewState(a: WsiViewState, b: WsiViewState): boolean {\n\tconst epsilon = 1e-6;\n\treturn (\n\t\tMath.abs(a.zoom - b.zoom) <= epsilon &&\n\t\tMath.abs(a.offsetX - b.offsetX) <= epsilon &&\n\t\tMath.abs(a.offsetY - b.offsetY) <= epsilon &&\n\t\tMath.abs(a.rotationDeg - b.rotationDeg) <= epsilon\n\t);\n}\n\nexport class WsiTileRenderer {\n\tprivate readonly canvas: HTMLCanvasElement;\n\tprivate readonly source: WsiImageSource;\n\tprivate readonly gl: WebGL2RenderingContext;\n\tprivate readonly camera = new OrthoCamera();\n\tprivate readonly onViewStateChange?: (next: WsiViewState) => void;\n\tprivate readonly onStats?: (stats: WsiRenderStats) => void;\n\tprivate readonly onTileError?: (event: WsiTileErrorEvent) => void;\n\tprivate readonly onContextLost?: () => void;\n\tprivate readonly onContextRestored?: () => void;\n\tprivate readonly resizeObserver: ResizeObserver;\n\tprivate tileProgram: TileVertexProgram;\n\tprivate pointProgram: PointProgram;\n\tprivate readonly tileScheduler: TileScheduler;\n\n\tprivate authToken: string;\n\tprivate destroyed = false;\n\tprivate contextLost = false;\n\tprivate frame: number | null = null;\n\tprivate frameSerial = 0;\n\tprivate dragging = false;\n\tprivate interactionMode: \"none\" | \"pan\" | \"rotate\" = \"none\";\n\tprivate rotateLastAngleRad: number | null = null;\n\tprivate pointerId: number | null = null;\n\tprivate lastPointerX = 0;\n\tprivate lastPointerY = 0;\n\tprivate interactionLocked = false;\n\tprivate ctrlDragRotate = true;\n\tprivate rotationDragSensitivityDegPerPixel = 0.35;\n\tprivate maxCacheTiles: number;\n\tprivate fitZoom = 1;\n\tprivate minZoom = 1e-6;\n\tprivate maxZoom = 1;\n\tprivate minZoomOverride: number | null = null;\n\tprivate maxZoomOverride: number | null = null;\n\tprivate viewTransitionDurationMs = 0;\n\tprivate viewTransitionEasing: (t: number) => number = linearEasing;\n\tprivate viewAnimation: ViewAnimationState | null = null;\n\tprivate viewAnimationFrame: number | null = null;\n\tprivate currentTier = 0;\n\tprivate pointCount = 0;\n\tprivate usePointIndices = false;\n\tprivate pointBuffersDirty = true;\n\tprivate pointPaletteSize = 1;\n\tprivate pointSizeStops: PointSizeStop[] = clonePointSizeStops(DEFAULT_POINT_SIZE_STOPS);\n\tprivate pointStrokeScale = 1.0;\n\tprivate imageColorSettings: NormalizedImageColorSettings = {\n\t\tbrightness: 0,\n\t\tcontrast: 0,\n\t\tsaturation: 0,\n\t};\n\tprivate lastPointData: WsiPointData | null = null;\n\tprivate lastPointPalette: Uint8Array | null = null;\n\tprivate zeroFillModes = new Uint8Array(0);\n\tprivate cache = new Map<string, CachedTile>();\n\n\tprivate readonly boundPointerDown: (event: PointerEvent) => void;\n\tprivate readonly boundPointerMove: (event: PointerEvent) => void;\n\tprivate readonly boundPointerUp: (event: PointerEvent) => void;\n\tprivate readonly boundWheel: (event: WheelEvent) => void;\n\tprivate readonly boundDoubleClick: (event: MouseEvent) => void;\n\tprivate readonly boundContextMenu: (event: MouseEvent) => void;\n\tprivate readonly boundContextLost: (event: Event) => void;\n\tprivate readonly boundContextRestored: (event: Event) => void;\n\n\tconstructor(\n\t\tcanvas: HTMLCanvasElement,\n\t\tsource: WsiImageSource,\n\t\toptions: WsiTileRendererOptions = {},\n\t) {\n\t\tthis.canvas = canvas;\n\t\tthis.source = source;\n\t\tthis.onViewStateChange = options.onViewStateChange;\n\t\tthis.onStats = options.onStats;\n\t\tthis.onTileError = options.onTileError;\n\t\tthis.onContextLost = options.onContextLost;\n\t\tthis.onContextRestored = options.onContextRestored;\n\t\tthis.authToken = options.authToken ?? \"\";\n\t\tthis.maxCacheTiles = Math.max(32, Math.floor(options.maxCacheTiles ?? 320));\n\t\tthis.ctrlDragRotate = options.ctrlDragRotate ?? true;\n\t\tthis.rotationDragSensitivityDegPerPixel =\n\t\t\ttypeof options.rotationDragSensitivityDegPerPixel === \"number\" &&\n\t\t\tNumber.isFinite(options.rotationDragSensitivityDegPerPixel)\n\t\t\t\t? Math.max(0, options.rotationDragSensitivityDegPerPixel)\n\t\t\t\t: DEFAULT_ROTATION_DRAG_SENSITIVITY;\n\t\tthis.pointSizeStops = normalizePointSizeStops(options.pointSizeByZoom);\n\t\tthis.pointStrokeScale = normalizeStrokeScale(options.pointStrokeScale);\n\t\tthis.imageColorSettings = toNormalizedImageColorSettings(\n\t\t\toptions.imageColorSettings,\n\t\t);\n\t\tthis.minZoomOverride = normalizeZoomOverride(options.minZoom);\n\t\tthis.maxZoomOverride = normalizeZoomOverride(options.maxZoom);\n\t\tthis.viewTransitionDurationMs = normalizeViewTransitionDuration(options.viewTransition?.duration);\n\t\tthis.viewTransitionEasing = normalizeTransitionEasing(options.viewTransition?.easing);\n\n\t\tconst gl = canvas.getContext(\"webgl2\", {\n\t\t\talpha: false,\n\t\t\tantialias: false,\n\t\t\tdepth: false,\n\t\t\tstencil: false,\n\t\t\tpowerPreference: \"high-performance\",\n\t\t});\n\t\tif (!gl) {\n\t\t\tthrow new Error(\"WebGL2 not supported\");\n\t\t}\n\t\tthis.gl = gl;\n\n\t\tthis.tileProgram = this.initTileProgram();\n\t\tthis.pointProgram = this.initPointProgram();\n\t\tthis.tileScheduler = new TileScheduler({\n\t\t\tauthToken: this.authToken,\n\t\t\tmaxConcurrency: options.tileScheduler?.maxConcurrency ?? 12,\n\t\t\tmaxRetries: options.tileScheduler?.maxRetries ?? 2,\n\t\t\tretryBaseDelayMs: options.tileScheduler?.retryBaseDelayMs ?? 120,\n\t\t\tretryMaxDelayMs: options.tileScheduler?.retryMaxDelayMs ?? 1200,\n\t\t\tonTileLoad: (tile, bitmap) => this.handleTileLoaded(tile, bitmap),\n\t\t\tonTileError: (tile, error, attemptCount) => {\n\t\t\t\tthis.onTileError?.({ tile, error, attemptCount });\n\t\t\t\tconsole.warn(\"tile load failed\", tile.url, error);\n\t\t\t},\n\t\t});\n\n\t\tthis.resizeObserver = new ResizeObserver(() => this.resize());\n\t\tthis.resizeObserver.observe(canvas);\n\n\t\tthis.boundPointerDown = (event: PointerEvent) => this.onPointerDown(event);\n\t\tthis.boundPointerMove = (event: PointerEvent) => this.onPointerMove(event);\n\t\tthis.boundPointerUp = (event: PointerEvent) => this.onPointerUp(event);\n\t\tthis.boundWheel = (event: WheelEvent) => this.onWheel(event);\n\t\tthis.boundDoubleClick = (event: MouseEvent) => this.onDoubleClick(event);\n\t\tthis.boundContextMenu = (event: MouseEvent) => this.onContextMenu(event);\n\t\tthis.boundContextLost = (event: Event) => this.onWebGlContextLost(event);\n\t\tthis.boundContextRestored = (event: Event) =>\n\t\t\tthis.onWebGlContextRestored(event);\n\n\t\tcanvas.addEventListener(\"pointerdown\", this.boundPointerDown);\n\t\tcanvas.addEventListener(\"pointermove\", this.boundPointerMove);\n\t\tcanvas.addEventListener(\"pointerup\", this.boundPointerUp);\n\t\tcanvas.addEventListener(\"pointercancel\", this.boundPointerUp);\n\t\tcanvas.addEventListener(\"wheel\", this.boundWheel, { passive: false });\n\t\tcanvas.addEventListener(\"dblclick\", this.boundDoubleClick);\n\t\tcanvas.addEventListener(\"contextmenu\", this.boundContextMenu);\n\t\tcanvas.addEventListener(\"webglcontextlost\", this.boundContextLost);\n\t\tcanvas.addEventListener(\"webglcontextrestored\", this.boundContextRestored);\n\n\t\tthis.fitToImage({ duration: 0 });\n\t\tthis.resize();\n\t}\n\n\tprivate resolveDefaultZoomBounds(): { minZoom: number; maxZoom: number } {\n\t\tconst minZoom = Math.max(this.fitZoom * 0.5, 1e-6);\n\t\tconst maxZoom = Math.max(1, this.fitZoom * 8);\n\t\treturn {\n\t\t\tminZoom,\n\t\t\tmaxZoom: Math.max(minZoom, maxZoom),\n\t\t};\n\t}\n\n\tprivate applyZoomBounds(): void {\n\t\tconst defaults = this.resolveDefaultZoomBounds();\n\t\tlet minZoom = this.minZoomOverride ?? defaults.minZoom;\n\t\tlet maxZoom = this.maxZoomOverride ?? defaults.maxZoom;\n\t\tminZoom = Math.max(1e-6, minZoom);\n\t\tmaxZoom = Math.max(1e-6, maxZoom);\n\t\tif (minZoom > maxZoom) {\n\t\t\tminZoom = maxZoom;\n\t\t}\n\t\tthis.minZoom = minZoom;\n\t\tthis.maxZoom = maxZoom;\n\t}\n\n\tprivate resolveTargetViewState(next: Partial<WsiViewState>): WsiViewState {\n\t\tconst current = this.camera.getViewState();\n\t\tconst candidate: WsiViewState = {\n\t\t\tzoom:\n\t\t\t\ttypeof next.zoom === \"number\" && Number.isFinite(next.zoom)\n\t\t\t\t\t? clamp(next.zoom, this.minZoom, this.maxZoom)\n\t\t\t\t\t: current.zoom,\n\t\t\toffsetX:\n\t\t\t\ttypeof next.offsetX === \"number\" && Number.isFinite(next.offsetX)\n\t\t\t\t\t? next.offsetX\n\t\t\t\t\t: current.offsetX,\n\t\t\toffsetY:\n\t\t\t\ttypeof next.offsetY === \"number\" && Number.isFinite(next.offsetY)\n\t\t\t\t\t? next.offsetY\n\t\t\t\t\t: current.offsetY,\n\t\t\trotationDeg:\n\t\t\t\ttypeof next.rotationDeg === \"number\" && Number.isFinite(next.rotationDeg)\n\t\t\t\t\t? next.rotationDeg\n\t\t\t\t\t: current.rotationDeg,\n\t\t};\n\n\t\tthis.camera.setViewState(candidate);\n\t\tthis.clampViewState();\n\t\tconst target = this.camera.getViewState();\n\t\tthis.camera.setViewState(current);\n\t\treturn target;\n\t}\n\n\tprivate cancelViewAnimation(): void {\n\t\tthis.viewAnimation = null;\n\t\tif (this.viewAnimationFrame !== null) {\n\t\t\tcancelAnimationFrame(this.viewAnimationFrame);\n\t\t\tthis.viewAnimationFrame = null;\n\t\t}\n\t}\n\n\tprivate startViewAnimation(\n\t\ttarget: WsiViewState,\n\t\tdurationMs: number,\n\t\teasing: (t: number) => number,\n\t): void {\n\t\tconst from = this.camera.getViewState();\n\t\tthis.cancelViewAnimation();\n\t\tthis.viewAnimation = {\n\t\t\tstartMs: nowMs(),\n\t\t\tdurationMs: Math.max(0, durationMs),\n\t\t\tfrom,\n\t\t\tto: target,\n\t\t\teasing,\n\t\t};\n\n\t\tconst step = (): void => {\n\t\t\tconst animation = this.viewAnimation;\n\t\t\tif (!animation) return;\n\n\t\t\tconst elapsed = Math.max(0, nowMs() - animation.startMs);\n\t\t\tconst rawT =\n\t\t\t\tanimation.durationMs <= 0 ? 1 : clamp(elapsed / animation.durationMs, 0, 1);\n\t\t\tlet eased = rawT;\n\t\t\ttry {\n\t\t\t\teased = animation.easing(rawT);\n\t\t\t} catch {\n\t\t\t\teased = rawT;\n\t\t\t}\n\t\t\tif (!Number.isFinite(eased)) {\n\t\t\t\teased = rawT;\n\t\t\t}\n\t\t\teased = clamp(eased, 0, 1);\n\n\t\t\tconst nextState: WsiViewState = {\n\t\t\t\tzoom: animation.from.zoom + (animation.to.zoom - animation.from.zoom) * eased,\n\t\t\t\toffsetX:\n\t\t\t\t\tanimation.from.offsetX +\n\t\t\t\t\t(animation.to.offsetX - animation.from.offsetX) * eased,\n\t\t\t\toffsetY:\n\t\t\t\t\tanimation.from.offsetY +\n\t\t\t\t\t(animation.to.offsetY - animation.from.offsetY) * eased,\n\t\t\t\trotationDeg:\n\t\t\t\t\tanimation.from.rotationDeg +\n\t\t\t\t\t(animation.to.rotationDeg - animation.from.rotationDeg) * eased,\n\t\t\t};\n\n\t\t\tthis.camera.setViewState(nextState);\n\t\t\tthis.clampViewState();\n\t\t\tthis.emitViewState();\n\t\t\tthis.requestRender();\n\n\t\t\tif (rawT >= 1) {\n\t\t\t\tthis.viewAnimation = null;\n\t\t\t\tthis.viewAnimationFrame = null;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tthis.viewAnimationFrame = requestAnimationFrame(step);\n\t\t};\n\n\t\tthis.viewAnimationFrame = requestAnimationFrame(step);\n\t}\n\n\tsetAuthToken(token: string): void {\n\t\tthis.authToken = String(token ?? \"\");\n\t\tthis.tileScheduler.setAuthToken(this.authToken);\n\t}\n\n\tsetZoomRange(minZoom: number | null | undefined, maxZoom: number | null | undefined): void {\n\t\tconst nextMinOverride = normalizeZoomOverride(minZoom);\n\t\tconst nextMaxOverride = normalizeZoomOverride(maxZoom);\n\t\tif (\n\t\t\tthis.minZoomOverride === nextMinOverride &&\n\t\t\tthis.maxZoomOverride === nextMaxOverride\n\t\t) {\n\t\t\treturn;\n\t\t}\n\n\t\tthis.minZoomOverride = nextMinOverride;\n\t\tthis.maxZoomOverride = nextMaxOverride;\n\t\tthis.applyZoomBounds();\n\n\t\tconst target = this.resolveTargetViewState({});\n\t\tconst current = this.camera.getViewState();\n\t\tif (isSameViewState(current, target)) {\n\t\t\treturn;\n\t\t}\n\t\tthis.cancelViewAnimation();\n\t\tthis.camera.setViewState(target);\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tsetViewTransition(options: WsiViewTransitionOptions | null | undefined): void {\n\t\tthis.viewTransitionDurationMs = normalizeViewTransitionDuration(options?.duration);\n\t\tthis.viewTransitionEasing = normalizeTransitionEasing(options?.easing);\n\t}\n\n\tsetViewState(\n\t\tnext: Partial<WsiViewState>,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tconst target = this.resolveTargetViewState(next);\n\t\tconst current = this.camera.getViewState();\n\t\tif (isSameViewState(current, target)) return;\n\n\t\tconst durationMs = normalizeViewTransitionDuration(\n\t\t\ttransition?.duration ?? this.viewTransitionDurationMs,\n\t\t);\n\t\tconst easing = normalizeTransitionEasing(\n\t\t\ttransition?.easing ?? this.viewTransitionEasing,\n\t\t);\n\t\tif (durationMs <= 0) {\n\t\t\tthis.cancelViewAnimation();\n\t\t\tthis.camera.setViewState(target);\n\t\t\tthis.emitViewState();\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tthis.startViewAnimation(target, durationMs, easing);\n\t}\n\n\tgetViewState(): WsiViewState {\n\t\treturn this.camera.getViewState();\n\t}\n\n\tgetZoomRange(): { minZoom: number; maxZoom: number } {\n\t\treturn { minZoom: this.minZoom, maxZoom: this.maxZoom };\n\t}\n\n\tsetPointPalette(colors: Uint8Array | null | undefined): void {\n\t\tif (!colors || colors.length === 0) {\n\t\t\tthis.lastPointPalette = null;\n\t\t\treturn;\n\t\t}\n\t\tthis.lastPointPalette = new Uint8Array(colors);\n\t\tif (this.contextLost || this.gl.isContextLost()) return;\n\t\tconst gl = this.gl;\n\t\tconst paletteSize = Math.max(1, Math.floor(this.lastPointPalette.length / 4));\n\t\tthis.pointPaletteSize = paletteSize;\n\t\tgl.bindTexture(gl.TEXTURE_2D, this.pointProgram.paletteTexture);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tpaletteSize,\n\t\t\t1,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tthis.lastPointPalette,\n\t\t);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\tthis.requestRender();\n\t}\n\n\tsetPointData(points: WsiPointData | null | undefined): void {\n\t\tif (!points || !points.count || !points.positions || !points.paletteIndices) {\n\t\t\tthis.lastPointData = null;\n\t\t\tthis.pointCount = 0;\n\t\t\tthis.usePointIndices = false;\n\t\t\tthis.requestRender();\n\t\t\treturn;\n\t\t}\n\n\t\tconst pointFillModes =\n\t\t\tpoints.fillModes instanceof Uint8Array ? points.fillModes : null;\n\t\tconst hasFillModes = pointFillModes !== null;\n\t\tconst safeCount = Math.max(\n\t\t\t0,\n\t\t\tMath.min(\n\t\t\t\tpoints.count,\n\t\t\t\tMath.floor(points.positions.length / 2),\n\t\t\t\tpoints.paletteIndices.length,\n\t\t\t\thasFillModes ? pointFillModes.length : Number.MAX_SAFE_INTEGER,\n\t\t\t),\n\t\t);\n\t\tconst nextPositions = points.positions.subarray(0, safeCount * 2);\n\t\tconst nextPaletteIndices = points.paletteIndices.subarray(0, safeCount);\n\t\tconst nextFillModes = hasFillModes\n\t\t\t? pointFillModes.subarray(0, safeCount)\n\t\t\t: undefined;\n\t\tconst hasDrawIndices = points.drawIndices instanceof Uint32Array;\n\t\tconst nextDrawIndices = hasDrawIndices\n\t\t\t? this.sanitizeDrawIndices(points.drawIndices as Uint32Array, safeCount)\n\t\t\t: null;\n\t\tconst prev = this.lastPointData;\n\t\tconst prevHasFillModes = prev?.fillModes instanceof Uint8Array;\n\t\tlet geometryChanged =\n\t\t\tthis.pointBuffersDirty ||\n\t\t\t!prev ||\n\t\t\tprev.count !== safeCount ||\n\t\t\t!isSameArrayView(prev.positions, nextPositions) ||\n\t\t\t!isSameArrayView(prev.paletteIndices, nextPaletteIndices) ||\n\t\t\tprevHasFillModes !== hasFillModes ||\n\t\t\t(hasFillModes &&\n\t\t\t\t(!prev?.fillModes || !isSameArrayView(prev.fillModes, nextFillModes)));\n\t\tlet drawIndicesChanged =\n\t\t\tthis.pointBuffersDirty ||\n\t\t\t(hasDrawIndices &&\n\t\t\t\t(!prev?.drawIndices ||\n\t\t\t\t\t!isSameArrayView(prev.drawIndices, nextDrawIndices))) ||\n\t\t\t(!hasDrawIndices && !!prev?.drawIndices);\n\n\t\tthis.lastPointData = {\n\t\t\tcount: safeCount,\n\t\t\tpositions: nextPositions,\n\t\t\tpaletteIndices: nextPaletteIndices,\n\t\t\tfillModes: nextFillModes,\n\t\t\tdrawIndices: hasDrawIndices ? nextDrawIndices ?? undefined : undefined,\n\t\t};\n\t\tif (this.contextLost || this.gl.isContextLost()) return;\n\n\t\tconst gl = this.gl;\n\t\tif (geometryChanged) {\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.posBuffer);\n\t\t\tgl.bufferData(gl.ARRAY_BUFFER, this.lastPointData.positions, gl.STATIC_DRAW);\n\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.termBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ARRAY_BUFFER,\n\t\t\t\tthis.lastPointData.paletteIndices,\n\t\t\t\tgl.STATIC_DRAW,\n\t\t\t);\n\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, this.pointProgram.fillModeBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ARRAY_BUFFER,\n\t\t\t\tthis.lastPointData.fillModes ?? this.getZeroFillModes(safeCount),\n\t\t\t\tgl.STATIC_DRAW,\n\t\t\t);\n\t\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\t\t}\n\n\t\tif (hasDrawIndices && drawIndicesChanged) {\n\t\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.pointProgram.indexBuffer);\n\t\t\tgl.bufferData(\n\t\t\t\tgl.ELEMENT_ARRAY_BUFFER,\n\t\t\t\tnextDrawIndices ?? new Uint32Array(0),\n\t\t\t\tgl.DYNAMIC_DRAW,\n\t\t\t);\n\t\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\t\t}\n\n\t\tthis.usePointIndices = hasDrawIndices;\n\t\tthis.pointCount = hasDrawIndices\n\t\t\t? (nextDrawIndices?.length ?? 0)\n\t\t\t: this.lastPointData.count;\n\t\tif (geometryChanged || drawIndicesChanged) {\n\t\t\tthis.pointBuffersDirty = false;\n\t\t}\n\t\tthis.requestRender();\n\t}\n\n\tprivate sanitizeDrawIndices(\n\t\tdrawIndices: Uint32Array,\n\t\tmaxExclusive: number,\n\t): Uint32Array {\n\t\tif (maxExclusive <= 0 || drawIndices.length === 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\n\t\tlet validCount = drawIndices.length;\n\t\tfor (let i = 0; i < drawIndices.length; i += 1) {\n\t\t\tif (drawIndices[i] < maxExclusive) continue;\n\t\t\tvalidCount -= 1;\n\t\t}\n\t\tif (validCount === drawIndices.length) {\n\t\t\treturn drawIndices;\n\t\t}\n\t\tif (validCount <= 0) {\n\t\t\treturn new Uint32Array(0);\n\t\t}\n\n\t\tconst filtered = new Uint32Array(validCount);\n\t\tlet cursor = 0;\n\t\tfor (let i = 0; i < drawIndices.length; i += 1) {\n\t\t\tconst idx = drawIndices[i];\n\t\t\tif (idx >= maxExclusive) continue;\n\t\t\tfiltered[cursor] = idx;\n\t\t\tcursor += 1;\n\t\t}\n\t\treturn filtered;\n\t}\n\n\tprivate getZeroFillModes(count: number): Uint8Array {\n\t\tif (count <= 0) return new Uint8Array(0);\n\t\tif (this.zeroFillModes.length < count) {\n\t\t\tthis.zeroFillModes = new Uint8Array(count);\n\t\t}\n\t\treturn this.zeroFillModes.subarray(0, count);\n\t}\n\n\tsetInteractionLock(locked: boolean): void {\n\t\tconst next = Boolean(locked);\n\t\tif (this.interactionLocked === next) return;\n\t\tthis.interactionLocked = next;\n\t\tif (next) this.cancelDrag();\n\t}\n\n\tsetPointSizeByZoom(pointSizeByZoom: PointSizeByZoom | null | undefined): void {\n\t\tconst nextStops = normalizePointSizeStops(pointSizeByZoom);\n\t\tif (arePointSizeStopsEqual(this.pointSizeStops, nextStops)) return;\n\t\tthis.pointSizeStops = nextStops;\n\t\tthis.requestRender();\n\t}\n\n\tsetPointStrokeScale(scale: number | null | undefined): void {\n\t\tconst next = normalizeStrokeScale(scale);\n\t\tif (this.pointStrokeScale === next) return;\n\t\tthis.pointStrokeScale = next;\n\t\tthis.requestRender();\n\t}\n\n\tsetImageColorSettings(settings: WsiImageColorSettings | null | undefined): void {\n\t\tconst next = toNormalizedImageColorSettings(settings);\n\t\tconst prev = this.imageColorSettings;\n\t\tif (\n\t\t\tprev.brightness === next.brightness &&\n\t\t\tprev.contrast === next.contrast &&\n\t\t\tprev.saturation === next.saturation\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tthis.imageColorSettings = next;\n\t\tthis.requestRender();\n\t}\n\n\tcancelDrag(): void {\n\t\tif (this.pointerId !== null && this.canvas.hasPointerCapture(this.pointerId)) {\n\t\t\ttry {\n\t\t\t\tthis.canvas.releasePointerCapture(this.pointerId);\n\t\t\t} catch {\n\t\t\t\t// noop\n\t\t\t}\n\t\t}\n\t\tthis.dragging = false;\n\t\tthis.interactionMode = \"none\";\n\t\tthis.rotateLastAngleRad = null;\n\t\tthis.pointerId = null;\n\t\tthis.canvas.classList.remove(\"dragging\");\n\t}\n\n\tprivate getPointerAngleRad(clientX: number, clientY: number): number {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = clientX - rect.left - rect.width * 0.5;\n\t\tconst y = clientY - rect.top - rect.height * 0.5;\n\t\treturn Math.atan2(y, x);\n\t}\n\n\tscreenToWorld(clientX: number, clientY: number): [number, number] {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst sx = clientX - rect.left;\n\t\tconst sy = clientY - rect.top;\n\t\treturn this.camera.screenToWorld(sx, sy);\n\t}\n\n\tworldToScreen(worldX: number, worldY: number): [number, number] {\n\t\treturn this.camera.worldToScreen(worldX, worldY);\n\t}\n\n\tsetViewCenter(\n\t\tworldX: number,\n\t\tworldY: number,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tif (!Number.isFinite(worldX) || !Number.isFinite(worldY)) return;\n\t\tconst state = this.camera.getViewState();\n\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\tconst vp = this.camera.getViewport();\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\toffsetX: worldX - vp.width / (2 * zoom),\n\t\t\t\toffsetY: worldY - vp.height / (2 * zoom),\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tgetViewCorners(): [WorldPoint, WorldPoint, WorldPoint, WorldPoint] {\n\t\treturn this.camera.getViewCorners();\n\t}\n\n\tresetRotation(transition?: WsiViewTransitionOptions): void {\n\t\tconst state = this.camera.getViewState();\n\t\tif (Math.abs(state.rotationDeg) < 1e-6) return;\n\t\tthis.setViewState({ rotationDeg: 0 }, transition);\n\t}\n\n\tgetPointSizeByZoom(): number {\n\t\tconst zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n\t\tconst continuousZoom = this.source.maxTierZoom + Math.log2(zoom);\n\t\tconst size = resolvePointSizeByZoomStops(continuousZoom, this.pointSizeStops);\n\t\treturn clamp(size, MIN_POINT_SIZE_PX, MAX_POINT_SIZE_PX);\n\t}\n\n\tfitToImage(transition?: WsiViewTransitionOptions): void {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst vw = Math.max(1, rect.width || 1);\n\t\tconst vh = Math.max(1, rect.height || 1);\n\n\t\tconst zoom = Math.min(vw / this.source.width, vh / this.source.height);\n\t\tconst safeZoom = Number.isFinite(zoom) && zoom > 0 ? zoom : 1;\n\n\t\tthis.fitZoom = safeZoom;\n\t\tthis.applyZoomBounds();\n\t\tconst clampedZoom = clamp(safeZoom, this.minZoom, this.maxZoom);\n\t\tconst visibleWorldW = vw / clampedZoom;\n\t\tconst visibleWorldH = vh / clampedZoom;\n\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\tzoom: clampedZoom,\n\t\t\t\toffsetX: (this.source.width - visibleWorldW) * 0.5,\n\t\t\t\toffsetY: (this.source.height - visibleWorldH) * 0.5,\n\t\t\t\trotationDeg: 0,\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tzoomBy(\n\t\tfactor: number,\n\t\tscreenX: number,\n\t\tscreenY: number,\n\t\ttransition?: WsiViewTransitionOptions,\n\t): void {\n\t\tconst state = this.camera.getViewState();\n\t\tconst nextZoom = clamp(state.zoom * factor, this.minZoom, this.maxZoom);\n\t\tif (nextZoom === state.zoom) return;\n\n\t\tconst [worldX, worldY] = this.camera.screenToWorld(screenX, screenY);\n\t\tconst vp = this.camera.getViewport();\n\t\tconst dx = screenX - vp.width * 0.5;\n\t\tconst dy = screenY - vp.height * 0.5;\n\t\tconst rad = toRadians(state.rotationDeg);\n\t\tconst cos = Math.cos(rad);\n\t\tconst sin = Math.sin(rad);\n\t\tconst worldDx = (dx / nextZoom) * cos - (dy / nextZoom) * sin;\n\t\tconst worldDy = (dx / nextZoom) * sin + (dy / nextZoom) * cos;\n\t\tconst nextCenterX = worldX - worldDx;\n\t\tconst nextCenterY = worldY - worldDy;\n\n\t\tthis.setViewState(\n\t\t\t{\n\t\t\t\tzoom: nextZoom,\n\t\t\t\toffsetX: nextCenterX - vp.width / (2 * nextZoom),\n\t\t\t\toffsetY: nextCenterY - vp.height / (2 * nextZoom),\n\t\t\t},\n\t\t\ttransition,\n\t\t);\n\t}\n\n\tclampViewState(): void {\n\t\tconst bounds = this.getViewBounds();\n\t\tconst visibleW = Math.max(1e-6, bounds[2] - bounds[0]);\n\t\tconst visibleH = Math.max(1e-6, bounds[3] - bounds[1]);\n\t\tconst marginX = visibleW * 0.2;\n\t\tconst marginY = visibleH * 0.2;\n\n\t\tconst [centerX, centerY] = this.camera.getCenter();\n\t\tconst halfW = visibleW * 0.5;\n\t\tconst halfH = visibleH * 0.5;\n\n\t\tconst minCenterX = halfW - marginX;\n\t\tconst maxCenterX = this.source.width - halfW + marginX;\n\t\tconst minCenterY = halfH - marginY;\n\t\tconst maxCenterY = this.source.height - halfH + marginY;\n\n\t\tconst nextCenterX =\n\t\t\tminCenterX <= maxCenterX\n\t\t\t\t? clamp(centerX, minCenterX, maxCenterX)\n\t\t\t\t: this.source.width * 0.5;\n\t\tconst nextCenterY =\n\t\t\tminCenterY <= maxCenterY\n\t\t\t\t? clamp(centerY, minCenterY, maxCenterY)\n\t\t\t\t: this.source.height * 0.5;\n\n\t\tthis.camera.setCenter(nextCenterX, nextCenterY);\n\t}\n\n\temitViewState(): void {\n\t\tthis.onViewStateChange?.(this.camera.getViewState());\n\t}\n\n\tselectTier(): number {\n\t\tconst zoom = Math.max(1e-6, this.camera.getViewState().zoom);\n\t\tconst rawTier = this.source.maxTierZoom + Math.log2(zoom);\n\t\treturn clamp(Math.floor(rawTier), 0, this.source.maxTierZoom);\n\t}\n\n\tgetViewBounds(): Bounds {\n\t\tconst corners = this.camera.getViewCorners();\n\t\tlet minX = Infinity;\n\t\tlet minY = Infinity;\n\t\tlet maxX = -Infinity;\n\t\tlet maxY = -Infinity;\n\t\tfor (const [x, y] of corners) {\n\t\t\tif (x < minX) minX = x;\n\t\t\tif (x > maxX) maxX = x;\n\t\t\tif (y < minY) minY = y;\n\t\t\tif (y > maxY) maxY = y;\n\t\t}\n\t\treturn [minX, minY, maxX, maxY];\n\t}\n\n\tintersectsBounds(a: Bounds, b: Bounds): boolean {\n\t\treturn !(a[2] <= b[0] || a[0] >= b[2] || a[3] <= b[1] || a[1] >= b[3]);\n\t}\n\n\tgetVisibleTiles(): ScheduledTile[] {\n\t\tconst tier = this.selectTier();\n\t\tthis.currentTier = tier;\n\n\t\tconst viewBounds = this.getViewBounds();\n\n\t\tconst levelScale = Math.pow(2, this.source.maxTierZoom - tier);\n\t\tconst levelWidth = Math.ceil(this.source.width / levelScale);\n\t\tconst levelHeight = Math.ceil(this.source.height / levelScale);\n\n\t\tconst tilesX = Math.max(1, Math.ceil(levelWidth / this.source.tileSize));\n\t\tconst tilesY = Math.max(1, Math.ceil(levelHeight / this.source.tileSize));\n\n\t\tconst viewMinX = viewBounds[0];\n\t\tconst viewMinY = viewBounds[1];\n\t\tconst viewMaxX = viewBounds[2];\n\t\tconst viewMaxY = viewBounds[3];\n\n\t\tconst minTileX = clamp(\n\t\t\tMath.floor(viewMinX / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesX - 1,\n\t\t);\n\t\tconst maxTileX = clamp(\n\t\t\tMath.floor((viewMaxX - 1) / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesX - 1,\n\t\t);\n\t\tconst minTileY = clamp(\n\t\t\tMath.floor(viewMinY / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesY - 1,\n\t\t);\n\t\tconst maxTileY = clamp(\n\t\t\tMath.floor((viewMaxY - 1) / levelScale / this.source.tileSize),\n\t\t\t0,\n\t\t\ttilesY - 1,\n\t\t);\n\n\t\tif (minTileX > maxTileX || minTileY > maxTileY) {\n\t\t\treturn [];\n\t\t}\n\n\t\tconst centerTileX = (viewMinX + viewMaxX) * 0.5 / levelScale / this.source.tileSize;\n\t\tconst centerTileY = (viewMinY + viewMaxY) * 0.5 / levelScale / this.source.tileSize;\n\n\t\tconst visible: ScheduledTile[] = [];\n\t\tfor (let y = minTileY; y <= maxTileY; y += 1) {\n\t\t\tfor (let x = minTileX; x <= maxTileX; x += 1) {\n\t\t\t\tconst left = x * this.source.tileSize * levelScale;\n\t\t\t\tconst top = y * this.source.tileSize * levelScale;\n\t\t\t\tconst right = Math.min((x + 1) * this.source.tileSize, levelWidth) * levelScale;\n\t\t\t\tconst bottom = Math.min((y + 1) * this.source.tileSize, levelHeight) * levelScale;\n\n\t\t\t\tconst dx = x - centerTileX;\n\t\t\t\tconst dy = y - centerTileY;\n\t\t\t\tvisible.push({\n\t\t\t\t\tkey: `${tier}/${x}/${y}`,\n\t\t\t\t\ttier,\n\t\t\t\t\tx,\n\t\t\t\t\ty,\n\t\t\t\t\tbounds: [left, top, right, bottom],\n\t\t\t\t\tdistance2: dx * dx + dy * dy,\n\t\t\t\t\turl: toTileUrl(this.source, tier, x, y),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tvisible.sort((a, b) => a.distance2 - b.distance2);\n\t\treturn visible;\n\t}\n\n\ttrimCache(): void {\n\t\tif (this.cache.size <= this.maxCacheTiles) return;\n\n\t\tconst entries = Array.from(this.cache.entries());\n\t\tentries.sort((a, b) => a[1].lastUsed - b[1].lastUsed);\n\n\t\tconst removeCount = this.cache.size - this.maxCacheTiles;\n\t\tfor (let i = 0; i < removeCount; i += 1) {\n\t\t\tconst [key, value] = entries[i];\n\t\t\tthis.gl.deleteTexture(value.texture);\n\t\t\tthis.cache.delete(key);\n\t\t}\n\t}\n\n\trender(): void {\n\t\tif (this.destroyed || this.contextLost || this.gl.isContextLost()) return;\n\t\tconst frameStartMs = nowMs();\n\t\tthis.frameSerial += 1;\n\n\t\tconst gl = this.gl;\n\t\tconst tileProgram = this.tileProgram;\n\t\tconst pointProgram = this.pointProgram;\n\n\t\tgl.clearColor(0.03, 0.06, 0.1, 1);\n\t\tgl.clear(gl.COLOR_BUFFER_BIT);\n\n\t\tconst visible = this.getVisibleTiles();\n\t\tconst viewBounds = this.getViewBounds();\n\t\tconst visibleKeys = new Set(visible.map((tile) => tile.key));\n\n\t\tgl.useProgram(tileProgram.program);\n\t\tgl.bindVertexArray(tileProgram.vao);\n\t\tgl.uniformMatrix3fv(tileProgram.uCamera, false, this.camera.getMatrix());\n\t\tgl.uniform1i(tileProgram.uTexture, 0);\n\t\tgl.uniform1f(tileProgram.uBrightness, this.imageColorSettings.brightness);\n\t\tgl.uniform1f(tileProgram.uContrast, this.imageColorSettings.contrast);\n\t\tgl.uniform1f(tileProgram.uSaturation, this.imageColorSettings.saturation);\n\n\t\tconst fallbackTiles: CachedTile[] = [];\n\t\tfor (const [, cached] of this.cache) {\n\t\t\tif (visibleKeys.has(cached.key)) continue;\n\t\t\tif (!this.intersectsBounds(cached.bounds, viewBounds)) continue;\n\t\t\tfallbackTiles.push(cached);\n\t\t}\n\n\t\tfallbackTiles.sort((a, b) => a.tier - b.tier);\n\t\tfor (const cached of fallbackTiles) {\n\t\t\tcached.lastUsed = this.frameSerial;\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, cached.texture);\n\t\t\tgl.uniform4f(\n\t\t\t\ttileProgram.uBounds,\n\t\t\t\tcached.bounds[0],\n\t\t\t\tcached.bounds[1],\n\t\t\t\tcached.bounds[2],\n\t\t\t\tcached.bounds[3],\n\t\t\t);\n\t\t\tgl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\t\t}\n\n\t\tlet renderedTiles = 0;\n\t\tconst missingTiles: ScheduledTile[] = [];\n\t\tfor (const tile of visible) {\n\t\t\tconst cached = this.cache.get(tile.key);\n\t\t\tif (!cached) {\n\t\t\t\tmissingTiles.push(tile);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcached.lastUsed = this.frameSerial;\n\t\t\tgl.activeTexture(gl.TEXTURE0);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, cached.texture);\n\t\t\tgl.uniform4f(\n\t\t\t\ttileProgram.uBounds,\n\t\t\t\tcached.bounds[0],\n\t\t\t\tcached.bounds[1],\n\t\t\t\tcached.bounds[2],\n\t\t\t\tcached.bounds[3],\n\t\t\t);\n\t\t\tgl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n\t\t\trenderedTiles += 1;\n\t\t}\n\t\tthis.tileScheduler.schedule(missingTiles);\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\tgl.bindVertexArray(null);\n\n\t\tlet renderedPoints = 0;\n\t\tif (this.pointCount > 0) {\n\t\t\tgl.enable(gl.BLEND);\n\t\t\tgl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\t\t\tgl.useProgram(pointProgram.program);\n\t\t\tgl.bindVertexArray(pointProgram.vao);\n\t\t\tgl.uniformMatrix3fv(pointProgram.uCamera, false, this.camera.getMatrix());\n\t\t\tgl.uniform1f(pointProgram.uPointSize, this.getPointSizeByZoom());\n\t\t\tgl.uniform1f(pointProgram.uPointStrokeScale, this.pointStrokeScale);\n\t\t\tgl.uniform1f(pointProgram.uPaletteSize, this.pointPaletteSize);\n\t\t\tgl.uniform1i(pointProgram.uPalette, 1);\n\t\t\tgl.activeTexture(gl.TEXTURE1);\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, pointProgram.paletteTexture);\n\t\t\tif (this.usePointIndices) {\n\t\t\t\tgl.drawElements(gl.POINTS, this.pointCount, gl.UNSIGNED_INT, 0);\n\t\t\t} else {\n\t\t\t\tgl.drawArrays(gl.POINTS, 0, this.pointCount);\n\t\t\t}\n\t\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\t\tgl.bindVertexArray(null);\n\t\t\trenderedPoints = this.pointCount;\n\t\t}\n\n\t\tif (this.onStats) {\n\t\t\tconst schedulerStats = this.tileScheduler.getSnapshot();\n\t\t\tconst cacheHits = renderedTiles;\n\t\t\tconst cacheMisses = missingTiles.length;\n\t\t\tconst drawCalls =\n\t\t\t\tfallbackTiles.length + renderedTiles + (renderedPoints > 0 ? 1 : 0);\n\t\t\tthis.onStats({\n\t\t\t\ttier: this.currentTier,\n\t\t\t\tvisible: visible.length,\n\t\t\t\trendered: renderedTiles,\n\t\t\t\tpoints: renderedPoints,\n\t\t\t\tfallback: fallbackTiles.length,\n\t\t\t\tcache: this.cache.size,\n\t\t\t\tinflight: schedulerStats.inflight,\n\t\t\t\tqueued: schedulerStats.queued,\n\t\t\t\tretries: schedulerStats.retries,\n\t\t\t\tfailed: schedulerStats.failed,\n\t\t\t\taborted: schedulerStats.aborted,\n\t\t\t\tcacheHits,\n\t\t\t\tcacheMisses,\n\t\t\t\tdrawCalls,\n\t\t\t\tframeMs: nowMs() - frameStartMs,\n\t\t\t});\n\t\t}\n\t}\n\n\trequestRender(): void {\n\t\tif (\n\t\t\tthis.frame !== null ||\n\t\t\tthis.destroyed ||\n\t\t\tthis.contextLost ||\n\t\t\tthis.gl.isContextLost()\n\t\t)\n\t\t\treturn;\n\t\tthis.frame = requestAnimationFrame(() => {\n\t\t\tthis.frame = null;\n\t\t\tthis.render();\n\t\t});\n\t}\n\n\tresize(): void {\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst cssW = Math.max(1, rect.width || this.canvas.clientWidth || 1);\n\t\tconst cssH = Math.max(1, rect.height || this.canvas.clientHeight || 1);\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\n\t\tif (this.canvas.width !== pixelW || this.canvas.height !== pixelH) {\n\t\t\tthis.canvas.width = pixelW;\n\t\t\tthis.canvas.height = pixelH;\n\t\t}\n\n\t\tthis.camera.setViewport(cssW, cssH);\n\t\tthis.gl.viewport(0, 0, pixelW, pixelH);\n\t\tthis.requestRender();\n\t}\n\n\tonPointerDown(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tconst wantsRotate = this.ctrlDragRotate && (event.ctrlKey || event.metaKey);\n\t\tconst allowButton = event.button === 0 || (wantsRotate && event.button === 2);\n\t\tif (!allowButton) return;\n\t\tthis.cancelViewAnimation();\n\t\tif (wantsRotate) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t\tthis.dragging = true;\n\t\tthis.interactionMode =\n\t\t\twantsRotate ? \"rotate\" : \"pan\";\n\t\tthis.pointerId = event.pointerId;\n\t\tthis.lastPointerX = event.clientX;\n\t\tthis.lastPointerY = event.clientY;\n\t\tthis.rotateLastAngleRad =\n\t\t\tthis.interactionMode === \"rotate\"\n\t\t\t\t? this.getPointerAngleRad(event.clientX, event.clientY)\n\t\t\t\t: null;\n\t\tthis.canvas.classList.add(\"dragging\");\n\t\tthis.canvas.setPointerCapture(event.pointerId);\n\t}\n\n\tonPointerMove(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tif (!this.dragging || event.pointerId !== this.pointerId) return;\n\n\t\tconst dx = event.clientX - this.lastPointerX;\n\t\tconst dy = event.clientY - this.lastPointerY;\n\t\tthis.lastPointerX = event.clientX;\n\t\tthis.lastPointerY = event.clientY;\n\n\t\tif (this.interactionMode === \"rotate\") {\n\t\t\tconst nextAngle = this.getPointerAngleRad(event.clientX, event.clientY);\n\t\t\tconst prevAngle = this.rotateLastAngleRad;\n\t\t\tthis.rotateLastAngleRad = nextAngle;\n\t\t\tif (prevAngle !== null) {\n\t\t\t\tconst rawDelta = nextAngle - prevAngle;\n\t\t\t\tconst delta = Math.atan2(Math.sin(rawDelta), Math.cos(rawDelta));\n\n\t\t\t\tconst sensitivityScale =\n\t\t\t\t\tDEFAULT_ROTATION_DRAG_SENSITIVITY > 0\n\t\t\t\t\t\t? this.rotationDragSensitivityDegPerPixel /\n\t\t\t\t\t\t\tDEFAULT_ROTATION_DRAG_SENSITIVITY\n\t\t\t\t\t\t: 1;\n\t\t\t\tconst state = this.camera.getViewState();\n\t\t\t\tthis.camera.setViewState({\n\t\t\t\t\trotationDeg:\n\t\t\t\t\t\tstate.rotationDeg - ((delta * 180) / Math.PI) * sensitivityScale,\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tconst state = this.camera.getViewState();\n\t\t\tconst zoom = Math.max(1e-6, state.zoom);\n\t\t\tconst rad = toRadians(state.rotationDeg);\n\t\t\tconst cos = Math.cos(rad);\n\t\t\tconst sin = Math.sin(rad);\n\t\t\tconst worldDx = (dx * cos - dy * sin) / zoom;\n\t\t\tconst worldDy = (dx * sin + dy * cos) / zoom;\n\t\t\tthis.camera.setViewState({\n\t\t\t\toffsetX: state.offsetX - worldDx,\n\t\t\t\toffsetY: state.offsetY - worldDy,\n\t\t\t});\n\t\t}\n\n\t\tthis.clampViewState();\n\t\tthis.emitViewState();\n\t\tthis.requestRender();\n\t}\n\n\tonPointerUp(event: PointerEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tif (event.pointerId !== this.pointerId) return;\n\t\tthis.cancelDrag();\n\t}\n\n\tonWheel(event: WheelEvent): void {\n\t\tif (this.interactionLocked) {\n\t\t\tevent.preventDefault();\n\t\t\treturn;\n\t\t}\n\n\t\tevent.preventDefault();\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = event.clientX - rect.left;\n\t\tconst y = event.clientY - rect.top;\n\t\tconst factor = event.deltaY < 0 ? 1.12 : 0.89;\n\t\tthis.zoomBy(factor, x, y);\n\t}\n\n\tonDoubleClick(event: MouseEvent): void {\n\t\tif (this.interactionLocked) return;\n\t\tconst rect = this.canvas.getBoundingClientRect();\n\t\tconst x = event.clientX - rect.left;\n\t\tconst y = event.clientY - rect.top;\n\t\tthis.zoomBy(event.shiftKey ? 0.8 : 1.25, x, y);\n\t}\n\n\tonContextMenu(event: MouseEvent): void {\n\t\tif (this.dragging || event.ctrlKey || event.metaKey) {\n\t\t\tevent.preventDefault();\n\t\t}\n\t}\n\n\tprivate onWebGlContextLost(event: Event): void {\n\t\tevent.preventDefault();\n\t\tif (this.destroyed || this.contextLost) return;\n\t\tthis.contextLost = true;\n\t\tthis.pointBuffersDirty = true;\n\n\t\tif (this.frame !== null) {\n\t\t\tcancelAnimationFrame(this.frame);\n\t\t\tthis.frame = null;\n\t\t}\n\t\tthis.cancelViewAnimation();\n\n\t\tthis.cancelDrag();\n\t\tthis.tileScheduler.clear();\n\t\tthis.cache.clear();\n\t\tthis.onContextLost?.();\n\t}\n\n\tprivate onWebGlContextRestored(_event: Event): void {\n\t\tif (this.destroyed) return;\n\t\tthis.contextLost = false;\n\t\tthis.cache.clear();\n\n\t\tthis.tileProgram = this.initTileProgram();\n\t\tthis.pointProgram = this.initPointProgram();\n\t\tthis.pointBuffersDirty = true;\n\n\t\tif (this.lastPointPalette && this.lastPointPalette.length > 0) {\n\t\t\tthis.setPointPalette(this.lastPointPalette);\n\t\t}\n\t\tif (this.lastPointData) {\n\t\t\tthis.setPointData(this.lastPointData);\n\t\t} else {\n\t\t\tthis.pointCount = 0;\n\t\t}\n\n\t\tthis.resize();\n\t\tthis.requestRender();\n\t\tthis.onContextRestored?.();\n\t}\n\n\tdestroy(): void {\n\t\tif (this.destroyed) return;\n\t\tthis.destroyed = true;\n\n\t\tif (this.frame !== null) {\n\t\t\tcancelAnimationFrame(this.frame);\n\t\t\tthis.frame = null;\n\t\t}\n\t\tthis.cancelViewAnimation();\n\n\t\tthis.resizeObserver.disconnect();\n\t\tthis.canvas.removeEventListener(\"pointerdown\", this.boundPointerDown);\n\t\tthis.canvas.removeEventListener(\"pointermove\", this.boundPointerMove);\n\t\tthis.canvas.removeEventListener(\"pointerup\", this.boundPointerUp);\n\t\tthis.canvas.removeEventListener(\"pointercancel\", this.boundPointerUp);\n\t\tthis.canvas.removeEventListener(\"wheel\", this.boundWheel);\n\t\tthis.canvas.removeEventListener(\"dblclick\", this.boundDoubleClick);\n\t\tthis.canvas.removeEventListener(\"contextmenu\", this.boundContextMenu);\n\t\tthis.canvas.removeEventListener(\"webglcontextlost\", this.boundContextLost);\n\t\tthis.canvas.removeEventListener(\n\t\t\t\"webglcontextrestored\",\n\t\t\tthis.boundContextRestored,\n\t\t);\n\t\tthis.cancelDrag();\n\t\tthis.tileScheduler.destroy();\n\n\t\tif (!this.contextLost && !this.gl.isContextLost()) {\n\t\t\tfor (const [, value] of this.cache) {\n\t\t\t\tthis.gl.deleteTexture(value.texture);\n\t\t\t}\n\t\t\tthis.gl.deleteBuffer(this.tileProgram.vbo);\n\t\t\tthis.gl.deleteVertexArray(this.tileProgram.vao);\n\t\t\tthis.gl.deleteProgram(this.tileProgram.program);\n\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.posBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.termBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.fillModeBuffer);\n\t\t\tthis.gl.deleteBuffer(this.pointProgram.indexBuffer);\n\t\t\tthis.gl.deleteTexture(this.pointProgram.paletteTexture);\n\t\t\tthis.gl.deleteVertexArray(this.pointProgram.vao);\n\t\t\tthis.gl.deleteProgram(this.pointProgram.program);\n\t\t}\n\t\tthis.cache.clear();\n\t}\n\n\tprivate initTileProgram(): TileVertexProgram {\n\t\tconst gl = this.gl;\n\n\t\tconst 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\t\tconst 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\t\tconst program = createProgram(gl, vertex, fragment);\n\t\tconst uCamera = requireUniformLocation(gl, program, \"uCamera\");\n\t\tconst uBounds = requireUniformLocation(gl, program, \"uBounds\");\n\t\tconst uTexture = requireUniformLocation(gl, program, \"uTexture\");\n\t\tconst uBrightness = requireUniformLocation(gl, program, \"uBrightness\");\n\t\tconst uContrast = requireUniformLocation(gl, program, \"uContrast\");\n\t\tconst uSaturation = requireUniformLocation(gl, program, \"uSaturation\");\n\n\t\tconst vao = gl.createVertexArray();\n\t\tconst vbo = gl.createBuffer();\n\t\tif (!vao || !vbo) {\n\t\t\tthrow new Error(\"buffer allocation failed\");\n\t\t}\n\n\t\tgl.bindVertexArray(vao);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n\t\tgl.bufferData(\n\t\t\tgl.ARRAY_BUFFER,\n\t\t\tnew Float32Array([0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1]),\n\t\t\tgl.STATIC_DRAW,\n\t\t);\n\n\t\tconst aUnit = gl.getAttribLocation(program, \"aUnit\");\n\t\tconst aUv = gl.getAttribLocation(program, \"aUv\");\n\t\tif (aUnit < 0 || aUv < 0) {\n\t\t\tthrow new Error(\"tile attribute lookup failed\");\n\t\t}\n\t\tgl.enableVertexAttribArray(aUnit);\n\t\tgl.enableVertexAttribArray(aUv);\n\t\tgl.vertexAttribPointer(aUnit, 2, gl.FLOAT, false, 16, 0);\n\t\tgl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, 16, 8);\n\n\t\tgl.bindVertexArray(null);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\n\t\treturn {\n\t\t\tprogram,\n\t\t\tvao,\n\t\t\tvbo,\n\t\t\tuCamera,\n\t\t\tuBounds,\n\t\t\tuTexture,\n\t\t\tuBrightness,\n\t\t\tuContrast,\n\t\t\tuSaturation,\n\t\t};\n\t}\n\n\tprivate initPointProgram(): PointProgram {\n\t\tconst gl = this.gl;\n\n\t\tconst 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\t\tconst 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 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 float alpha = 0.0;\n if (vFillMode != 0u) {\n alpha = outerMask * color.a;\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 alpha = outerMask * innerMask * color.a;\n }\n if (alpha <= 0.001) discard;\n\n outColor = vec4(color.rgb * alpha, alpha);\n }`;\n\n\t\tconst program = createProgram(gl, pointVertex, pointFragment);\n\t\tconst uCamera = requireUniformLocation(gl, program, \"uCamera\");\n\t\tconst uPointSize = requireUniformLocation(gl, program, \"uPointSize\");\n\t\tconst uPointStrokeScale = requireUniformLocation(gl, program, \"uPointStrokeScale\");\n\t\tconst uPalette = requireUniformLocation(gl, program, \"uPalette\");\n\t\tconst uPaletteSize = requireUniformLocation(gl, program, \"uPaletteSize\");\n\n\t\tconst vao = gl.createVertexArray();\n\t\tconst posBuffer = gl.createBuffer();\n\t\tconst termBuffer = gl.createBuffer();\n\t\tconst fillModeBuffer = gl.createBuffer();\n\t\tconst indexBuffer = gl.createBuffer();\n\t\tconst paletteTexture = gl.createTexture();\n\t\tif (!vao || !posBuffer || !termBuffer || !fillModeBuffer || !indexBuffer || !paletteTexture) {\n\t\t\tthrow new Error(\"point buffer allocation failed\");\n\t\t}\n\n\t\tgl.bindVertexArray(vao);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst posLoc = gl.getAttribLocation(program, \"aPosition\");\n\t\tif (posLoc < 0) {\n\t\t\tthrow new Error(\"point position attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(posLoc);\n\t\tgl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, termBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst termLoc = gl.getAttribLocation(program, \"aTerm\");\n\t\tif (termLoc < 0) {\n\t\t\tthrow new Error(\"point term attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(termLoc);\n\t\tgl.vertexAttribIPointer(termLoc, 1, gl.UNSIGNED_SHORT, 0, 0);\n\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, fillModeBuffer);\n\t\tgl.bufferData(gl.ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\t\tconst fillModeLoc = gl.getAttribLocation(program, \"aFillMode\");\n\t\tif (fillModeLoc < 0) {\n\t\t\tthrow new Error(\"point fill mode attribute not found\");\n\t\t}\n\t\tgl.enableVertexAttribArray(fillModeLoc);\n\t\tgl.vertexAttribIPointer(fillModeLoc, 1, gl.UNSIGNED_BYTE, 0, 0);\n\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);\n\t\tgl.bufferData(gl.ELEMENT_ARRAY_BUFFER, 0, gl.DYNAMIC_DRAW);\n\n\t\tgl.bindVertexArray(null);\n\t\tgl.bindBuffer(gl.ARRAY_BUFFER, null);\n\t\tgl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, paletteTexture);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n\t\tgl.texImage2D(\n\t\t\tgl.TEXTURE_2D,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\t1,\n\t\t\t1,\n\t\t\t0,\n\t\t\tgl.RGBA,\n\t\t\tgl.UNSIGNED_BYTE,\n\t\t\tnew Uint8Array([160, 160, 160, 255]),\n\t\t);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\n\t\treturn {\n\t\t\tprogram,\n\t\t\tvao,\n\t\t\tposBuffer,\n\t\t\ttermBuffer,\n\t\t\tfillModeBuffer,\n\t\t\tindexBuffer,\n\t\t\tpaletteTexture,\n\t\t\tuCamera,\n\t\t\tuPointSize,\n\t\t\tuPointStrokeScale,\n\t\t\tuPalette,\n\t\t\tuPaletteSize,\n\t\t};\n\t}\n\n\tprivate handleTileLoaded(tile: ScheduledTile, bitmap: ImageBitmap): void {\n\t\tif (this.destroyed || this.contextLost || this.gl.isContextLost()) {\n\t\t\tbitmap.close();\n\t\t\treturn;\n\t\t}\n\t\tif (this.cache.has(tile.key)) {\n\t\t\tbitmap.close();\n\t\t\treturn;\n\t\t}\n\n\t\tconst texture = this.createTextureFromBitmap(bitmap);\n\t\tbitmap.close();\n\t\tif (!texture) return;\n\n\t\tthis.cache.set(tile.key, {\n\t\t\tkey: tile.key,\n\t\t\ttexture,\n\t\t\tbounds: tile.bounds,\n\t\t\ttier: tile.tier,\n\t\t\tlastUsed: this.frameSerial,\n\t\t});\n\t\tthis.trimCache();\n\t\tthis.requestRender();\n\t}\n\n\tprivate createTextureFromBitmap(bitmap: ImageBitmap): WebGLTexture | null {\n\t\tif (this.contextLost || this.gl.isContextLost()) return null;\n\t\tconst gl = this.gl;\n\t\tconst texture = gl.createTexture();\n\t\tif (!texture) return null;\n\n\t\tgl.bindTexture(gl.TEXTURE_2D, texture);\n\t\tgl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);\n\t\tgl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);\n\t\tgl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, bitmap);\n\t\tgl.bindTexture(gl.TEXTURE_2D, null);\n\t\treturn texture;\n\t}\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 { type PreparedRoiPolygon, prepareRoiPolygons, type RoiGeometry } from \"../wsi/roi-geometry\";\nimport { computeRoiPointGroups, type RoiPointGroupStats } from \"../wsi/roi-term-stats\";\nimport type {\n WsiImageColorSettings,\n WsiImageSource,\n WsiPointData,\n WsiRegion,\n WsiRenderStats,\n WsiViewState,\n} from \"../wsi/types\";\nimport { type PointSizeByZoom, type WsiTileErrorEvent, type WsiViewTransitionOptions, WsiTileRenderer } 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, mergeRegionLabelStyle, resolveRegionLabelAutoLiftOffsetPx, resolveRegionLabelStyle } from \"./draw-layer\";\nimport { OverviewMap, type OverviewMapOptions } from \"./overview-map\";\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 MIN_POINT_HIT_GRID_SIZE = 24;\nconst MAX_POINT_HIT_GRID_SIZE = 1024;\nconst POINT_HIT_GRID_DENSITY_SCALE = 4;\nconst REGION_CONTOUR_HIT_DISTANCE_PX = 6;\nconst TOP_ANCHOR_Y_TOLERANCE = 0.5;\nconst LABEL_MEASURE_FALLBACK_EM = 0.58;\nconst LABEL_MEASURE_CACHE_LIMIT = 4096;\nconst REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS = 180;\nconst REGION_LABEL_AUTO_LIFT_MAX_OFFSET_PX = 20;\n\nlet sharedLabelMeasureContext: CanvasRenderingContext2D | null = null;\nconst labelTextWidthCache = new Map<string, number>();\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\ninterface PointSpatialIndex {\n cellSize: number;\n safeCount: number;\n positions: Float32Array;\n ids: Uint32Array | null;\n buckets: Map<number, Map<number, number[]>>;\n}\n\ninterface PreparedRegionHit {\n region: WsiRegion;\n regionIndex: number;\n regionId: string | number;\n polygons: PreparedRoiPolygon[];\n label: string;\n labelAnchor: DrawCoordinate | null;\n}\n\nfunction sanitizePointCount(pointData: WsiPointData): number {\n const fillModesLength = pointData.fillModes instanceof Uint8Array ? pointData.fillModes.length : Number.MAX_SAFE_INTEGER;\n return Math.max(0, Math.min(Math.floor(pointData.count ?? 0), Math.floor((pointData.positions?.length ?? 0) / 2), pointData.paletteIndices?.length ?? 0, fillModesLength));\n}\n\nfunction sanitizeDrawIndices(drawIndices: Uint32Array | undefined, maxExclusive: number): Uint32Array | null {\n if (!(drawIndices instanceof Uint32Array) || maxExclusive <= 0 || drawIndices.length === 0) {\n return null;\n }\n\n let invalidFound = false;\n for (let i = 0; i < drawIndices.length; i += 1) {\n if (drawIndices[i] < maxExclusive) continue;\n invalidFound = true;\n break;\n }\n if (!invalidFound) {\n return drawIndices;\n }\n\n const out = new Uint32Array(drawIndices.length);\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 out[cursor] = idx;\n cursor += 1;\n }\n return out.subarray(0, cursor);\n}\n\nfunction resolvePointHitGridSize(source: WsiImageSource | null, visibleCount: number): number {\n if (!source || visibleCount <= 0) return 256;\n const area = Math.max(1, source.width * source.height);\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 buildPointSpatialIndex(pointData: WsiPointData | null | undefined, source: WsiImageSource | null): PointSpatialIndex | null {\n if (!pointData || !pointData.positions || !pointData.paletteIndices) {\n return null;\n }\n\n const safeCount = sanitizePointCount(pointData);\n if (safeCount <= 0) {\n return null;\n }\n\n const positions = pointData.positions.subarray(0, safeCount * 2);\n const ids = pointData.ids instanceof Uint32Array && pointData.ids.length >= safeCount ? pointData.ids.subarray(0, safeCount) : null;\n const drawIndices = sanitizeDrawIndices(pointData.drawIndices, safeCount);\n const visibleCount = drawIndices ? drawIndices.length : safeCount;\n if (visibleCount === 0) {\n return null;\n }\n\n const cellSize = resolvePointHitGridSize(source, visibleCount);\n const buckets = new Map<number, Map<number, number[]>>();\n\n const pushBucket = (pointIndex: number): void => {\n const px = positions[pointIndex * 2];\n const py = positions[pointIndex * 2 + 1];\n if (!Number.isFinite(px) || !Number.isFinite(py)) return;\n\n const cellX = Math.floor(px / cellSize);\n const cellY = Math.floor(py / cellSize);\n let column = buckets.get(cellX);\n if (!column) {\n column = new Map<number, number[]>();\n buckets.set(cellX, column);\n }\n const bucket = column.get(cellY);\n if (bucket) {\n bucket.push(pointIndex);\n } else {\n column.set(cellY, [pointIndex]);\n }\n };\n\n if (drawIndices) {\n for (let i = 0; i < drawIndices.length; i += 1) {\n pushBucket(drawIndices[i] ?? 0);\n }\n } else {\n for (let i = 0; i < safeCount; i += 1) {\n pushBucket(i);\n }\n }\n\n if (buckets.size === 0) {\n return null;\n }\n\n return {\n cellSize,\n safeCount,\n positions,\n ids,\n buckets,\n };\n}\n\nfunction resolveRegionId(region: WsiRegion, index: number): string | number {\n return region.id ?? index;\n}\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.max(min, Math.min(max, value));\n}\n\nfunction smoothstep01(t: number): number {\n const x = clamp(t, 0, 1);\n return x * x * (3 - 2 * x);\n}\n\nfunction 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\nfunction getTopAnchor(ring: DrawCoordinate[]): DrawCoordinate | null {\n if (ring.length === 0) return null;\n let minY = Infinity;\n for (const point of ring) {\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 ring) {\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 if (!Number.isFinite(minX) || !Number.isFinite(maxX)) return null;\n return [(minX + maxX) * 0.5, minY];\n}\n\nfunction getTopAnchorFromPreparedPolygons(polygons: PreparedRoiPolygon[]): 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\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\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\nfunction measureLabelTextWidth(label: string, labelStyle: RegionLabelStyle): 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\nfunction 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\nfunction 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([region?.coordinates as RoiGeometry | null | undefined]);\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 ? getTopAnchorFromPreparedPolygons(polygons) : null,\n });\n }\n return out;\n}\n\nfunction 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\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 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 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 => region.coordinates as RoiPolygon), [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 outputCount = data?.drawIndices ? data.drawIndices.length : (data?.count ?? 0);\n setRenderPointData(data);\n onClipStats?.({\n mode: stats.mode,\n durationMs: stats.durationMs,\n inputCount: pointData.count,\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 = useMemo(() => {\n if (!shouldEnablePointHitTest) return null;\n return buildPointSpatialIndex(renderPointData, source);\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 = pointSpatialIndex.cellSize;\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 const column = pointSpatialIndex.buckets.get(cx);\n if (!column) continue;\n\n for (let cy = baseCellY - cellRadius; cy <= baseCellY + cellRadius; cy += 1) {\n const bucket = column.get(cy);\n if (!bucket || bucket.length === 0) continue;\n\n for (let i = 0; i < bucket.length; i += 1) {\n const pointIndex = bucket[i];\n if (pointIndex >= pointSpatialIndex.safeCount) continue;\n\n const px = pointSpatialIndex.positions[pointIndex * 2];\n const py = pointSpatialIndex.positions[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 );\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 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 pointSizeByZoom,\n pointStrokeScale,\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.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","OrthoCamera$1","__publicField","width","height","next","viewWidth","viewHeight","sx","sy","tx","ty","VERTEX_SHADER","FRAGMENT_SHADER","M1TileRenderer","options","OrthoCamera","vao","quadBuffer","quadVertices","unitLocation","uvLocation","stride","tiles","version","loaded","tile","viewState","response","blob","bitmap","texture","error","rect","cssWidth","cssHeight","dpr","targetWidth","targetHeight","viewport","zoom","safeZoom","visibleWorldWidth","visibleWorldHeight","offsetX","offsetY","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","clamp","value","min","max","closeRing","coordinates","out","x","y","first","last","sanitizePath","points","point","prev","createCirclePolygon","center","radius","sides","ring","t","createBoundsFallback","minX","minY","maxX","maxY","pad","computeExpandedBounds","resolveRasterConfig","bounds","minRasterStep","maxRasterPixels","maxRasterSize","widthWorld","heightWorld","step","padding","createRasterContext","worldToRaster","config","rasterizeStrokeMask","path","p","i","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","polygonSignedArea","sum","a","b","removeCollinearVertices","epsilon","closed","curr","cross","pointLineDistanceSquared","abx","aby","len2","dx","dy","simplifyRdp","tolerance","keep","tolerance2","stack","start","end","maxDist2","split","dist2","simplifyClosedRing","open","simplified","smoothClosedRingChaikin","iterations","pass","clampRingToBounds","buildBrushStrokePolygon","circleSides","raster","bestRing","bestArea","area","smoothingPasses","isFiniteNumber","isCoordinatePair","isLinearRing","isPolygonRings","isMultiPolygon","polygon","closeRoiRing","normalizePolygonRings","rings","normalized","outerIndex","outerArea","normalizeRoiGeometry","geometry","pointInRing","inside","j","xi","yi","xj","yj","prepareRoiPolygons","geometries","prepared","multipolygon","outer","pointInPreparedPolygon","hole","pointInAnyPreparedPolygon","polygons","DEFAULT_POINT_COLOR","calcScaleResolution","imageMpp","imageZoom","currentZoom","mpp","z0","z1","calcScaleLength","length","unit","isSameViewState","toBearerToken","trimmed","token","hexToRgba","hex","match","n","buildTermPalette","terms","palette","termToPaletteIndex","term","termId","colors","vs","fs","DRAW_FILL","DEFAULT_DRAW_PREVIEW_FILL","FREEHAND_MIN_POINTS","FREEHAND_SCREEN_STEP","CIRCLE_SIDES","MIN_AREA_PX","EMPTY_REGIONS","EMPTY_DASH","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","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","resolveRegionLabelAutoLiftOffsetPx","enabled","zoomRange","minZoom","maxZoom","isStampTool","tool","clampPositiveOrFallback","fallback","resolveStampOptions","clampUnitOpacity","sanitizeBrushLineDash","item","resolveBrushEdgeDetail","resolveBrushEdgeSmoothing","resolveBrushOptions","cursorLineWidth","edgeDetail","edgeSmoothing","mm2ToUm2","areaMm2","createSquareFromCenter","halfLength","projection","screenCenter","screenEdge","screenHL","screenCorners","worldCorners","corner","world","createCircleFromCenter","coords","createRectangle","startScreen","endScreen","createCircle","centerX","centerY","polygonArea","computeBounds","isValidPolygon","tracePath","ctx","close","drawPath","strokeStyle","fill","fillColor","resolveDrawPreviewFillColor","resolveStrokeStyle","style","dash","shadowBlur","shadowOffsetX","shadowOffsetY","mergeStrokeStyle","base","override","isSameRegionId","isNestedRingCoordinates","isCoordinateRing","collectOverlayRings","normalizeOverlayRings","sourceRings","drawInvertedFillMask","outerRing","holeRings","resolveRegionLabelStyle","px","py","bw","oy","br","mergeRegionLabelStyle","resolveDrawAreaTooltipStyle","fontSize","borderRadius","paddingX","paddingY","resolveTooltipCursorOffset","defaultDrawAreaTooltipFormatter","resolveDrawAreaTooltipOptions","format","cursorOffset","resolveRegionInteractionShadowStyle","drawRoundedRect","r","getTopAnchor","getTopAnchorFromPolygons","best","anchor","normalizeDrawRegionPolygons","normalizedOuter","holes","drawRegionLabel","text","canvasWidth","canvasHeight","labelStyle","label","boxWidth","boxHeight","left","top","drawAreaTooltipBox","cursorScreen","clampWorld","coord","imageWidth","imageHeight","toCoord","DrawLayer","stampOptions","brushOptions","projectorRef","onBrushTap","onDrawComplete","onPatchComplete","viewStateSignal","persistedRegions","patchRegions","persistedPolygons","drawFillColor","regionStrokeStyle","regionStrokeHoverStyle","regionStrokeActiveStyle","patchStrokeStyle","resolveRegionStrokeStyle","resolveRegionLabelStyleProp","overlayShapes","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","resolvedStampOptions","resolvedBrushOptions","mergedStyle","resizeCanvas","useCallback","w","h","worldToScreenPoints","projector","localScreenToWorld","screen","raw","getRectangleProjection","rotationDeg","micronsToWorldPixels","lengthUm","mppValue","imageZoomValue","viewZoomRaw","viewZoom","continuousZoom","umPerScreenPixel","buildStampCoords","stampTool","areaUm2","buildPreviewCoords","session","drawBrushStrokePreview","screenPoints","radiusPx","drawBrushCursor","cursor","drawOverlay","regionIndex","regionKey","state","resolved","interactionShadowStyle","screenOuter","screenHole","debugOverlay","imageOuterRing","shape","renderRings","closedRings","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","screenX","screenY","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","worldX","worldY","visibleW","visibleH","drag","cancelled","levelScale","levelWidth","levelHeight","tilesX","tilesY","tileCount","requests","useAuthHeader","results","dw","dh","jsxs","TileViewerCanvas","rendererRef","renderer","sanitizePointCount","pointData","fillModesLength","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","nowMs","filterPointDataByPolygonsHybrid","bridgeToDraw","data","safeCount","pointFillModes","bboxFlat","candidateMask","usedWebGpu","candidateCount","candidateIndices","candidateCursor","drawIndices","visibleCount","pointIndex","compactData","workerInstance","workerSupported","requestId","pendingById","createWorker","worker","_documentCurrentScript","handleWorkerMessage","handleWorkerError","msg","pending","indices","paletteIndices","ids","terminateRoiClipWorker","filterPointDataByPolygonsInWorker","positionsCopy","termsCopy","fillModesCopy","idsCopy","startMs","resolve","reject","transfer","filterPointIndicesByPolygonsInWorker","prepareRegions","regions","resolveTermId","paletteIndex","paletteIndexToTermId","fromArray","fromMap","computeRoiPointGroups","baseCount","valid","filtered","idx","inputCount","preparedRegions","regionTermCounters","regionTotalCounters","insideCount","bestRegion","regionTermMap","includeEmptyRegions","groups","totalCount","termMap","termCounts","shouldAttachAuthHeader","url","host","TileScheduler","nextVisibleKeys","inflight","queued","visibleKeys","nextQueue","key","earliestReadyAt","delay","now","controller","inflightEntry","nextAttempt","retryDelay","existing","attempt","exp","jitter","DEFAULT_ROTATION_DRAG_SENSITIVITY","MIN_POINT_SIZE_PX","MAX_POINT_SIZE_PX","DEFAULT_POINT_SIZE_STOPS","rad","toRadians","cos","sin","rx","ry","ax","bx","ay","by","deg","name","isSameArrayView","clonePointSizeStops","stops","stop","normalizePointSizeStops","pointSizeByZoom","zoomKey","rawSize","size","arePointSizeStopsEqual","resolvePointSizeByZoomStops","span","slope","MIN_STROKE_SCALE","MAX_STROKE_SCALE","normalizeStrokeScale","MIN_IMAGE_COLOR_INPUT","MAX_IMAGE_COLOR_INPUT","normalizeImageColorInput","toNormalizedImageColorSettings","settings","brightnessInput","contrastInput","saturationInput","MAX_VIEW_TRANSITION_DURATION_MS","linearEasing","normalizeViewTransitionDuration","duration","normalizeZoomOverride","normalizeTransitionEasing","easing","WsiTileRenderer","attemptCount","defaults","current","target","durationMs","animation","elapsed","rawT","eased","nextState","nextMinOverride","nextMaxOverride","transition","paletteSize","hasFillModes","nextPaletteIndices","hasDrawIndices","nextDrawIndices","prevHasFillModes","geometryChanged","drawIndicesChanged","maxExclusive","validCount","locked","nextStops","vp","vw","vh","clampedZoom","visibleWorldW","visibleWorldH","factor","nextZoom","worldDx","worldDy","nextCenterX","nextCenterY","marginX","marginY","halfW","halfH","minCenterX","maxCenterX","minCenterY","maxCenterY","rawTier","viewBounds","viewMinX","viewMinY","viewMaxX","viewMaxY","minTileX","maxTileX","minTileY","maxTileY","centerTileX","centerTileY","visible","entries","removeCount","frameStartMs","tileProgram","pointProgram","fallbackTiles","cached","renderedTiles","missingTiles","renderedPoints","schedulerStats","cacheHits","cacheMisses","drawCalls","wantsRotate","nextAngle","prevAngle","rawDelta","sensitivityScale","_event","uCamera","uBounds","uTexture","uBrightness","uContrast","uSaturation","vbo","aUnit","aUv","uPointSize","uPointStrokeScale","uPalette","uPaletteSize","posBuffer","termBuffer","fillModeBuffer","indexBuffer","paletteTexture","posLoc","termLoc","fillModeLoc","EMPTY_ROI_REGIONS","EMPTY_ROI_POLYGONS","EMPTY_CLIPPED_POINTS","POINT_HIT_RADIUS_SCALE","MIN_POINT_HIT_RADIUS_PX","MIN_POINT_HIT_GRID_SIZE","MAX_POINT_HIT_GRID_SIZE","POINT_HIT_GRID_DENSITY_SCALE","REGION_CONTOUR_HIT_DISTANCE_PX","TOP_ANCHOR_Y_TOLERANCE","LABEL_MEASURE_FALLBACK_EM","LABEL_MEASURE_CACHE_LIMIT","REGION_LABEL_AUTO_LIFT_ANIMATION_DURATION_MS","sharedLabelMeasureContext","labelTextWidthCache","sanitizeDrawIndices","invalidFound","resolvePointHitGridSize","buildPointSpatialIndex","cellSize","buckets","pushBucket","cellX","cellY","column","bucket","resolveRegionId","smoothstep01","toDrawCoordinate","getTopAnchorFromPreparedPolygons","pointSegmentDistanceSq","lengthSq","isPointNearRing","maxDistanceSq","isPointNearPolygonContour","maxDistance","getLabelMeasureContext","measureLabelTextWidth","measured","isScreenPointInsideLabel","screenCoord","prepareRegionHits","pickPreparedRegionAt","labelStyleResolver","labelAutoLiftOffsetPx","contourHitDistance","WsiViewerCanvas","imageColorSettings","onViewStateChange","onStats","onTileError","onContextLost","onContextRestored","debugOverlayStyle","fitNonce","rotationResetNonce","ctrlDragRotate","pointPalette","pointStrokeScale","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","getCellByCoordinates","coordinate","pointSizePx","hitRadiusWorld","baseCellX","baseCellY","cellRadius","nearestIndex","nearestDist2","nearestX","nearestY","pointId","emitPointHover","hit","nextIndex","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,CCpEO,IAAAC,GAAA,KAAkB,CAAlB,cACGC,EAAA,qBAAgB,GAChBA,EAAA,sBAAiB,GAEjBA,EAAA,iBAAuB,CAC7B,QAAS,EACT,QAAS,EACT,KAAM,CAAA,GAGR,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,EAEpD,CAEA,cAA0B,CACxB,MAAO,CAAE,GAAG,KAAK,SAAA,CACnB,CAEA,WAA0B,CACxB,MAAMC,EAAY,KAAK,cAAgB,KAAK,UAAU,KAChDC,EAAa,KAAK,eAAiB,KAAK,UAAU,KAElDC,EAAK,EAAIF,EACTG,EAAK,GAAKF,EACVG,EAAK,GAAK,KAAK,UAAU,QAAUF,EACnCG,EAAK,EAAI,KAAK,UAAU,QAAUF,EAExC,OAAO,IAAI,aAAa,CACtBD,EACA,EACA,EACA,EACAC,EACA,EACAC,EACAC,EACA,CAAA,CACD,CACH,CACF,EC7CA,MAAMC,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,CArB3Bb,EAAA,eACAA,EAAA,WACAA,EAAA,cAAS,IAAIc,IACbd,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,OAASa,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,GAAKjB,GAAc,KAAK,MAAM,EACnC,KAAK,QAAUT,GAAc,KAAK,GAAIuB,GAAeC,EAAe,EAEpE,MAAMI,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,gBAAkB3B,GACtB,KAAK,GACL,KAAK,QACL,SAAA,EAED,KAAK,gBAAkBA,GACtB,KAAK,GACL,KAAK,QACL,SAAA,EAED,KAAK,iBAAmBA,GACvB,KAAK,GACL,KAAK,QACL,UAAA,EAGGoB,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,SAASQ,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,EAEvBC,EAAO,KAAK,IACjBD,EAAS,MAAQ,KAAK,WACtBA,EAAS,OAAS,KAAK,WAAA,EAElBE,EAAW,OAAO,SAASD,CAAI,GAAKA,EAAO,EAAIA,EAAO,EAEtDE,EAAoBH,EAAS,MAAQE,EACrCE,EAAqBJ,EAAS,OAASE,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,UAAWnB,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,CCtXA,MAAMoB,GAA0B,GAC1BC,GAA4B,IAC5BC,GAA0B,KAC1BC,GAAuB,GACvBC,GAA2B,EAC3BC,GAAuB,EACvBC,GAAa,KACbC,GAAkB,GAExB,SAASC,GAAMC,EAAeC,EAAaC,EAAqB,CAC/D,OAAO,KAAK,IAAID,EAAK,KAAK,IAAIC,EAAKF,CAAK,CAAC,CAC1C,CAEA,SAASG,GACRC,EAC0B,CAC1B,GAAI,CAAC,MAAM,QAAQA,CAAW,GAAKA,EAAY,OAAS,EAAG,MAAO,CAAA,EAClE,MAAMC,EAAMD,EAAY,IAAI,CAAC,CAACE,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAA0B,EACjEC,EAAQH,EAAI,CAAC,EACbI,EAAOJ,EAAIA,EAAI,OAAS,CAAC,EAC/B,MAAI,CAACG,GAAS,CAACC,EAAa,CAAA,IACxBD,EAAM,CAAC,IAAMC,EAAK,CAAC,GAAKD,EAAM,CAAC,IAAMC,EAAK,CAAC,IAC9CJ,EAAI,KAAK,CAACG,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAAC,EAEvBH,EACR,CAEA,SAASK,GACRC,EAC0B,CAC1B,GAAI,CAAC,MAAM,QAAQA,CAAM,GAAKA,EAAO,SAAW,EAAG,MAAO,CAAA,EAC1D,MAAMN,EAA+B,CAAA,EACrC,UAAWO,KAASD,EAAQ,CAC3B,GAAI,CAAC,MAAM,QAAQC,CAAK,GAAKA,EAAM,OAAS,EAAG,SAC/C,MAAMN,EAAI,OAAOM,EAAM,CAAC,CAAC,EACnBL,EAAI,OAAOK,EAAM,CAAC,CAAC,EACzB,GAAI,CAAC,OAAO,SAASN,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAG,SAChD,MAAMM,EAAOR,EAAIA,EAAI,OAAS,CAAC,EAC3BQ,GAAQ,KAAK,IAAIA,EAAK,CAAC,EAAIP,CAAC,EAAI,MAAQ,KAAK,IAAIO,EAAK,CAAC,EAAIN,CAAC,EAAI,MAGpEF,EAAI,KAAK,CAACC,EAAGC,CAAC,CAAC,CAChB,CACA,OAAOF,CACR,CAEA,SAASS,GACRC,EACAC,EACAC,EAC0B,CAC1B,GAAID,GAAUnB,IAAcoB,EAAQ,QAAU,CAAA,EAC9C,MAAMC,EAAgC,CAAA,EACtC,QAAS,EAAI,EAAG,GAAKD,EAAO,GAAK,EAAG,CACnC,MAAME,EAAK,EAAIF,EAAS,KAAK,GAAK,EAClCC,EAAK,KAAK,CACTH,EAAO,CAAC,EAAI,KAAK,IAAII,CAAC,EAAIH,EAC1BD,EAAO,CAAC,EAAI,KAAK,IAAII,CAAC,EAAIH,CAAA,CAC1B,CACF,CACA,OAAOb,GAAUe,CAAI,CACtB,CAEA,SAASE,GACRT,EACAK,EAC0B,CAC1B,GAAI,CAACL,EAAO,OAAQ,MAAO,CAAA,EAC3B,IAAIU,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClB,EAAGC,CAAC,IAAKI,EAChBL,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GACjBC,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GAEtB,GAAI,CAAC,OAAO,SAASc,CAAI,GAAK,CAAC,OAAO,SAASC,CAAI,EAAG,MAAO,CAAA,EAC7D,MAAMG,EAAM,KAAK,IAAIT,EAAQ,CAAC,EAC9B,OAAOb,GAAU,CAChB,CAACkB,EAAOI,EAAKH,EAAOG,CAAG,EACvB,CAACF,EAAOE,EAAKH,EAAOG,CAAG,EACvB,CAACF,EAAOE,EAAKD,EAAOC,CAAG,EACvB,CAACJ,EAAOI,EAAKD,EAAOC,CAAG,CAAA,CACvB,CACF,CAEA,SAASC,GACRf,EACAK,EACoB,CACpB,IAAIK,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClB,EAAGC,CAAC,IAAKI,EAChBL,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GACjBC,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GAEtB,MAAMkB,EAAM,KAAK,IAAIT,EAAQ,CAAC,EAC9B,MAAO,CAACK,EAAOI,EAAKH,EAAOG,EAAKF,EAAOE,EAAKD,EAAOC,CAAG,CACvD,CAEA,SAASE,GACRC,EACAZ,EACAxD,EACe,CACf,MAAMqE,EAAgB,KAAK,IAC1BtC,GACA,OAAO/B,EAAQ,aAAa,GAAK,CAAA,EAE5BsE,EAAkB,KAAK,IAC5B,MACA,KAAK,MAAMtE,EAAQ,iBAAmBgC,EAAyB,CAAA,EAE1DuC,EAAgB,KAAK,IAC1B,IACA,KAAK,MAAMvE,EAAQ,eAAiBiC,EAAuB,CAAA,EAGtDuC,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,EACVvF,EAAQ,KAAK,KAAKoF,EAAaE,CAAI,EAAIC,EAAU,EAAI,EACrDtF,EAAS,KAAK,KAAKoF,EAAcC,CAAI,EAAIC,EAAU,EAAI,EAE3D,MACCvF,EAAQmF,GACRlF,EAASkF,GACTnF,EAAQC,EAASiF,KAEjBI,GAAQ,KACRtF,EAAQ,KAAK,KAAKoF,EAAaE,CAAI,EAAIC,EAAU,EAAI,EACrDtF,EAAS,KAAK,KAAKoF,EAAcC,CAAI,EAAIC,EAAU,EAAI,EACnD,EAAAD,EAAO,KAAK,IAAIF,EAAYC,CAAW,KAA3C,CAKD,OAAArF,EAAQ,KAAK,IAAI,EAAGA,CAAK,EACzBC,EAAS,KAAK,IAAI,EAAGA,CAAM,EAEpB,CACN,KAAM+E,EAAO,CAAC,EACd,KAAMA,EAAO,CAAC,EACd,KAAAM,EACA,QAAAC,EACA,MAAAvF,EACA,OAAAC,CAAA,CAEF,CAMA,SAASuF,GACRxF,EACAC,EAC4B,CAC5B,GAAI,OAAO,gBAAoB,IAAa,CAE3C,MAAMJ,EADS,IAAI,gBAAgBG,EAAOC,CAAM,EACzB,WAAW,KAAM,CAAE,mBAAoB,GAAM,EACpE,GAAIJ,EAAS,OAAOA,CACrB,CACA,GAAI,OAAO,SAAa,IAAa,CACpC,MAAMD,EAAS,SAAS,cAAc,QAAQ,EAC9C,OAAAA,EAAO,MAAQI,EACfJ,EAAO,OAASK,EACTL,EAAO,WAAW,KAAM,CAAE,mBAAoB,GAAM,CAC5D,CACA,OAAO,IACR,CAEA,SAAS6F,GACRzB,EACA0B,EACwB,CACxB,MAAO,EACL1B,EAAM,CAAC,EAAI0B,EAAO,MAAQA,EAAO,KAAOA,EAAO,SAC/C1B,EAAM,CAAC,EAAI0B,EAAO,MAAQA,EAAO,KAAOA,EAAO,OAAA,CAElD,CAEA,SAASC,GACRC,EACAxB,EACAsB,EACa,CACb,MAAM7F,EAAU2F,GAAoBE,EAAO,MAAOA,EAAO,MAAM,EAC/D,GAAI,CAAC7F,EAAS,OAAO,IAAI,WAAW,CAAC,EAErCA,EAAQ,UAAU,EAAG,EAAG6F,EAAO,MAAOA,EAAO,MAAM,EACnD7F,EAAQ,UAAY,UACpBA,EAAQ,YAAc,UACtBA,EAAQ,QAAU,QAClBA,EAAQ,SAAW,QACnBA,EAAQ,UAAauE,EAAS,EAAKsB,EAAO,KAE1C,MAAM3B,EAAS6B,EAAK,OAAaH,GAAczB,EAAO0B,CAAM,CAAC,EAC7D,GAAI3B,EAAO,QAAU,EAAG,CACvB,MAAM8B,EAAI9B,EAAO,CAAC,EAClB,GAAI,CAAC8B,EAAG,OAAO,IAAI,WAAW,CAAC,EAC/BhG,EAAQ,UAAA,EACRA,EAAQ,IAAIgG,EAAE,CAAC,EAAGA,EAAE,CAAC,EAAGzB,EAASsB,EAAO,KAAM,EAAG,KAAK,GAAK,CAAC,EAC5D7F,EAAQ,KAAA,CACT,KAAO,CACNA,EAAQ,UAAA,EACRA,EAAQ,OAAOkE,EAAO,CAAC,EAAE,CAAC,EAAGA,EAAO,CAAC,EAAE,CAAC,CAAC,EACzC,QAAS+B,EAAI,EAAGA,EAAI/B,EAAO,OAAQ+B,GAAK,EACvCjG,EAAQ,OAAOkE,EAAO+B,CAAC,EAAE,CAAC,EAAG/B,EAAO+B,CAAC,EAAE,CAAC,CAAC,EAE1CjG,EAAQ,OAAA,CACT,CAEA,MAAMkG,EAAQlG,EAAQ,aAAa,EAAG,EAAG6F,EAAO,MAAOA,EAAO,MAAM,EAC9DjC,EAAM,IAAI,WAAWiC,EAAO,MAAQA,EAAO,MAAM,EACvD,QAASI,EAAI,EAAGA,EAAIrC,EAAI,OAAQqC,GAAK,EACpCrC,EAAIqC,CAAC,EAAIC,EAAM,KAAKD,EAAI,EAAI,CAAC,GAAK5C,GAAkB,EAAI,EAEzD,OAAOO,CACR,CAEA,SAASuC,GAAmBC,EAAkBjG,EAAeC,EAAgC,CAC5F,MAAMiG,EAAwB,CAAA,EACxB/E,EAASnB,EAAQ,EACjBmG,EAAS,CAACzC,EAAWC,IAAsBA,EAAIxC,EAASuC,EACxD0C,EAAK,CAAC1C,EAAWC,IACtBD,GAAK,GAAKC,GAAK,GAAKD,EAAI1D,GAAS2D,EAAI1D,GAAUgG,EAAKtC,EAAI3D,EAAQ0D,CAAC,EAAI,EAEtE,QAASC,EAAI,EAAGA,EAAI1D,EAAQ0D,GAAK,EAChC,QAASD,EAAI,EAAGA,EAAI1D,EAAO0D,GAAK,EAC1B0C,EAAG1C,EAAGC,CAAC,IACPyC,EAAG1C,EAAGC,EAAI,CAAC,GACfuC,EAAM,KAAK,CACV,MAAOC,EAAOzC,EAAGC,CAAC,EAClB,IAAKwC,EAAOzC,EAAI,EAAGC,CAAC,EACpB,IAAK,CAAA,CACL,EAEGyC,EAAG1C,EAAI,EAAGC,CAAC,GACfuC,EAAM,KAAK,CACV,MAAOC,EAAOzC,EAAI,EAAGC,CAAC,EACtB,IAAKwC,EAAOzC,EAAI,EAAGC,EAAI,CAAC,EACxB,IAAK,CAAA,CACL,EAEGyC,EAAG1C,EAAGC,EAAI,CAAC,GACfuC,EAAM,KAAK,CACV,MAAOC,EAAOzC,EAAI,EAAGC,EAAI,CAAC,EAC1B,IAAKwC,EAAOzC,EAAGC,EAAI,CAAC,EACpB,IAAK,CAAA,CACL,EAEGyC,EAAG1C,EAAI,EAAGC,CAAC,GACfuC,EAAM,KAAK,CACV,MAAOC,EAAOzC,EAAGC,EAAI,CAAC,EACtB,IAAKwC,EAAOzC,EAAGC,CAAC,EAChB,IAAK,CAAA,CACL,GAKJ,OAAOuC,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,MAAMhD,EAAQsC,EAAM,CAAC,EACfY,EAAclD,EAAM,MAC1B,IAAImD,EAAgBnD,EAAM,IACtBoD,EAAapD,EAAM,IACvB,MAAMqD,EAAiB,CAACrD,EAAM,MAAOA,EAAM,GAAG,EAC9CgD,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,MAAMnH,EAAOgG,EAAMmB,CAAS,EAC5BN,EAAgB7G,EAAK,IACrB8G,EAAa9G,EAAK,IAClB+G,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,EACA3H,EACA0F,EAC0B,CAC1B,MAAMvE,EAASnB,EAAQ,EACjBsE,EAAgC,CAAA,EACtC,UAAWsD,KAAMD,EAAY,CAC5B,MAAMjE,EAAIkE,EAAKzG,EACTwC,EAAI,KAAK,MAAMiE,EAAKzG,CAAM,EAChCmD,EAAK,KAAK,CACToB,EAAO,MAAQhC,EAAIgC,EAAO,SAAWA,EAAO,KAC5CA,EAAO,MAAQ/B,EAAI+B,EAAO,SAAWA,EAAO,IAAA,CAC5C,CACF,CACA,OAAOnC,GAAUe,CAAI,CACtB,CAEA,SAASuD,GAAkBvD,EAAuC,CACjE,GAAIA,EAAK,OAAS,EAAG,MAAO,GAC5B,IAAIwD,EAAM,EACV,QAAShC,EAAI,EAAGA,EAAIxB,EAAK,OAAS,EAAGwB,GAAK,EAAG,CAC5C,MAAMiC,EAAIzD,EAAKwB,CAAC,EACVkC,EAAI1D,EAAKwB,EAAI,CAAC,EACpBgC,GAAOC,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAID,EAAE,CAAC,CAChC,CACA,OAAOD,EAAM,EACd,CAEA,SAASG,GACR3D,EACA4D,EAAU,KACgB,CAC1B,MAAMC,EAAS5E,GAAUe,CAAI,EAC7B,GAAI6D,EAAO,OAAS,EAAG,OAAOA,EAC9B,MAAM1E,EAA+B,CAAC0E,EAAO,CAAC,CAAC,EAC/C,QAAS,EAAI,EAAG,EAAIA,EAAO,OAAS,EAAG,GAAK,EAAG,CAC9C,MAAMlE,EAAOR,EAAIA,EAAI,OAAS,CAAC,EACzB2E,EAAOD,EAAO,CAAC,EACfjI,EAAOiI,EAAO,EAAI,CAAC,EACnBE,GACJD,EAAK,CAAC,EAAInE,EAAK,CAAC,IAAM/D,EAAK,CAAC,EAAIkI,EAAK,CAAC,IACtCA,EAAK,CAAC,EAAInE,EAAK,CAAC,IAAM/D,EAAK,CAAC,EAAIkI,EAAK,CAAC,GACpC,KAAK,IAAIC,CAAK,GAAKH,GACvBzE,EAAI,KAAK2E,CAAI,CACd,CACA,OAAA3E,EAAI,KAAKA,EAAI,CAAC,CAAC,EACRF,GAAUE,CAAG,CACrB,CAEA,SAAS6E,GACRzC,EACAkC,EACAC,EACS,CACT,MAAMO,EAAMP,EAAE,CAAC,EAAID,EAAE,CAAC,EAChBS,EAAMR,EAAE,CAAC,EAAID,EAAE,CAAC,EAChBU,EAAOF,EAAMA,EAAMC,EAAMA,EAC/B,GAAIC,GAAQ,MAAO,CAClB,MAAMC,EAAK7C,EAAE,CAAC,EAAIkC,EAAE,CAAC,EACfY,EAAK9C,EAAE,CAAC,EAAIkC,EAAE,CAAC,EACrB,OAAOW,EAAKA,EAAKC,EAAKA,CACvB,CACA,MAAMpE,EAAIpB,KACP0C,EAAE,CAAC,EAAIkC,EAAE,CAAC,GAAKQ,GAAO1C,EAAE,CAAC,EAAIkC,EAAE,CAAC,GAAKS,GAAOC,EAC9C,EACA,CAAA,EAEK/E,EAAIqE,EAAE,CAAC,EAAIQ,EAAMhE,EACjBZ,EAAIoE,EAAE,CAAC,EAAIS,EAAMjE,EACjBmE,EAAK7C,EAAE,CAAC,EAAInC,EACZiF,EAAK9C,EAAE,CAAC,EAAIlC,EAClB,OAAO+E,EAAKA,EAAKC,EAAKA,CACvB,CAEA,SAASC,GACR7E,EACA8E,EAC0B,CAC1B,GAAI9E,EAAO,QAAU,GAAK8E,GAAa,EAAG,OAAO9E,EAAO,MAAA,EAExD,MAAM+E,EAAO,IAAI,WAAW/E,EAAO,MAAM,EACzC+E,EAAK,CAAC,EAAI,EACVA,EAAK/E,EAAO,OAAS,CAAC,EAAI,EAC1B,MAAMgF,EAAaF,EAAYA,EACzBG,EAAiC,CAAC,CAAC,EAAGjF,EAAO,OAAS,CAAC,CAAC,EAE9D,KAAOiF,EAAM,OAAS,GAAG,CACxB,MAAM9I,EAAO8I,EAAM,IAAA,EACnB,GAAI,CAAC9I,EAAM,MACX,KAAM,CAAC+I,EAAOC,CAAG,EAAIhJ,EACrB,GAAIgJ,EAAMD,GAAS,EAAG,SAEtB,IAAIE,EAAW,EACXC,EAAQ,GACZ,QAAStD,EAAImD,EAAQ,EAAGnD,EAAIoD,EAAKpD,GAAK,EAAG,CACxC,MAAMuD,EAAQf,GAAyBvE,EAAO+B,CAAC,EAAG/B,EAAOkF,CAAK,EAAGlF,EAAOmF,CAAG,CAAC,EACxEG,EAAQF,IACXA,EAAWE,EACXD,EAAQtD,EAEV,CAEIsD,GAAS,GAAKD,EAAWJ,IAC5BD,EAAKM,CAAK,EAAI,EACdJ,EAAM,KAAK,CAACC,EAAOG,CAAK,EAAG,CAACA,EAAOF,CAAG,CAAC,EAEzC,CAEA,MAAMzF,EAA+B,CAAA,EACrC,QAASqC,EAAI,EAAGA,EAAI/B,EAAO,OAAQ+B,GAAK,EACnCgD,EAAKhD,CAAC,KAAO,KAAK/B,EAAO+B,CAAC,CAAC,EAEhC,OAAOrC,CACR,CAEA,SAAS6F,GACRhF,EACAuE,EAC0B,CAC1B,MAAMV,EAAS5E,GAAUe,CAAI,EAC7B,GAAI6D,EAAO,OAAS,GAAKU,GAAa,EAAG,OAAOV,EAChD,MAAMoB,EAAOpB,EAAO,MAAM,EAAG,EAAE,EACzBqB,EAAaZ,GAAYW,EAAMV,CAAS,EAC9C,OAAIW,EAAW,OAAS,EAAUrB,EAC3B5E,GAAUiG,CAAU,CAC5B,CAEA,SAASC,GACRnF,EACAoF,EAC0B,CAC1B,IAAIjG,EAAMF,GAAUe,CAAI,EACxB,GAAIoF,GAAc,GAAKjG,EAAI,OAAS,EAAG,OAAOA,EAE9C,QAASkG,EAAO,EAAGA,EAAOD,EAAYC,GAAQ,EAAG,CAChD,MAAMJ,EAAO9F,EAAI,MAAM,EAAG,EAAE,EAC5B,GAAI8F,EAAK,OAAS,EAAG,MACrB,MAAMrJ,EAAgC,CAAA,EACtC,QAAS4F,EAAI,EAAGA,EAAIyD,EAAK,OAAQzD,GAAK,EAAG,CACxC,MAAM,EAAIyD,EAAKzD,CAAC,EACVkC,EAAIuB,GAAMzD,EAAI,GAAKyD,EAAK,MAAM,EACpCrJ,EAAK,KACJ,CAAC,EAAE,CAAC,EAAI,IAAO8H,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,CACAvE,EAAMF,GAAUrD,CAAI,CACrB,CACA,OAAOuD,CACR,CAEA,SAASmG,GACRtF,EACAU,EAC0B,CAC1B,OAAKA,EACEzB,GACNe,EAAK,IAAI,CAAC,CAACZ,EAAGC,CAAC,IAAM,CACpBR,GAAMO,EAAGsB,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,EAC7B7B,GAAMQ,EAAGqB,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,CAAA,CACJ,CAAA,EALPV,CAOrB,CAEO,SAASuF,GACfjE,EACAhF,EAC0B,CAC1B,MAAMmD,EAASD,GAAa8B,CAAI,EAC1BxB,EAAS,KAAK,IAAInB,GAAY,OAAOrC,EAAQ,MAAM,GAAK,CAAC,EAC/D,GAAImD,EAAO,SAAW,GAAK,CAAC,OAAO,SAASK,CAAM,EAAG,MAAO,CAAA,EAE5D,MAAM0F,EAAc,KAAK,IAAI,GAAI,KAAK,MAAMlJ,EAAQ,aAAekC,EAAoB,CAAC,EACxF,GAAIiB,EAAO,SAAW,EACrB,OAAO6F,GACN1F,GAAoBH,EAAO,CAAC,EAAGK,EAAQ0F,CAAW,EAClDlJ,EAAQ,UAAA,EAIV,MAAMoE,EAASF,GAAsBf,EAAQK,CAAM,EAC7C2F,EAAShF,GAAoBC,EAAQZ,EAAQxD,CAAO,EACpDqF,EAAON,GAAoB5B,EAAQK,EAAQ2F,CAAM,EACvD,GAAI,CAAC9D,EAAK,OACT,OAAO2D,GAAkBpF,GAAqBT,EAAQK,CAAM,EAAGxD,EAAQ,UAAU,EAGlF,MAAMsF,EAAQF,GAAmBC,EAAM8D,EAAO,MAAOA,EAAO,MAAM,EAC5DlD,EAAQJ,GAAWP,CAAK,EAC9B,GAAI,CAACW,EAAM,OACV,OAAO+C,GAAkBpF,GAAqBT,EAAQK,CAAM,EAAGxD,EAAQ,UAAU,EAGlF,IAAIoJ,EAAoC,CAAA,EACpCC,EAAW,EACf,UAAWhD,KAAQJ,EAAO,CACzB,MAAMvC,EAAOoD,GAAYT,EAAM8C,EAAO,MAAOA,CAAM,EAC7CG,EAAO,KAAK,IAAIrC,GAAkBvD,CAAI,CAAC,EACzC4F,GAAQD,IACZA,EAAWC,EACXF,EAAW1F,EACZ,CAEA,GAAI,CAAC0F,EAAS,OACb,OAAOJ,GAAkBpF,GAAqBT,EAAQK,CAAM,EAAGxD,EAAQ,UAAU,EAGlF,MAAMiI,EACL,OAAOjI,EAAQ,mBAAsB,UAAY,OAAO,SAASA,EAAQ,iBAAiB,EACvF,KAAK,IAAI,EAAGA,EAAQ,iBAAiB,EACrCmJ,EAAO,KAAO,GACZI,EACL,OAAOvJ,EAAQ,iBAAoB,UAAY,OAAO,SAASA,EAAQ,eAAe,EACnF,KAAK,MAAMuC,GAAMvC,EAAQ,gBAAiB,EAAGoC,EAAoB,CAAC,EAClED,GACEyG,EAAaF,GAClBG,GACCxB,GAAwB+B,EAAUD,EAAO,KAAO,IAAI,EACpDI,CAAA,EAEDtB,CAAA,EAED,OAAOe,GAAkBJ,EAAY5I,EAAQ,UAAU,CACxD,CCrkBA,SAASwJ,GAAehH,EAAiC,CACxD,OAAO,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,CAC1D,CAEA,SAASiH,GAAiBjH,EAAwC,CACjE,OACC,MAAM,QAAQA,CAAK,GACnBA,EAAM,QAAU,GAChBgH,GAAehH,EAAM,CAAC,CAAC,GACvBgH,GAAehH,EAAM,CAAC,CAAC,CAEzB,CAEA,SAASkH,GAAalH,EAAwC,CAC7D,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,GAAKA,EAAM,MAAMY,GAASqG,GAAiBrG,CAAK,CAAC,CAChG,CAEA,SAASuG,GAAenH,EAA0C,CACjE,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,GAAKA,EAAM,MAAMkB,GAAQgG,GAAahG,CAAI,CAAC,CAC1F,CAEA,SAASkG,GAAepH,EAA0C,CACjE,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,GAAKA,EAAM,MAAMqH,GAAWF,GAAeE,CAAO,CAAC,CAClG,CAEO,SAASC,GAAalH,EAAsD,CAClF,GAAI,CAAC,MAAM,QAAQA,CAAW,GAAKA,EAAY,OAAS,EAAG,MAAO,CAAA,EAClE,MAAMC,EAAqB,CAAA,EAC3B,UAAWO,KAASR,EAAa,CAChC,GAAI,CAAC,MAAM,QAAQQ,CAAK,GAAKA,EAAM,OAAS,EAAG,SAC/C,MAAMN,EAAI,OAAOM,EAAM,CAAC,CAAC,EACnBL,EAAI,OAAOK,EAAM,CAAC,CAAC,EACzB,GAAI,CAAC,OAAO,SAASN,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAG,SAChD,MAAMM,EAAOR,EAAIA,EAAI,OAAS,CAAC,EAC3BQ,GAAQA,EAAK,CAAC,IAAMP,GAAKO,EAAK,CAAC,IAAMN,GACzCF,EAAI,KAAK,CAACC,EAAGC,CAAC,CAAC,CAChB,CACA,GAAIF,EAAI,OAAS,EAAG,MAAO,CAAA,EAC3B,MAAMG,EAAQH,EAAI,CAAC,EACbI,EAAOJ,EAAIA,EAAI,OAAS,CAAC,EAC/B,OAAIG,EAAM,CAAC,IAAMC,EAAK,CAAC,GAAKD,EAAM,CAAC,IAAMC,EAAK,CAAC,IAC9CJ,EAAI,KAAK,CAACG,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAAC,EAEvBH,EAAI,QAAU,EAAIA,EAAM,CAAA,CAChC,CAEO,SAASoE,GAAkBvD,EAA6B,CAC9D,GAAI,CAAC,MAAM,QAAQA,CAAI,GAAKA,EAAK,OAAS,EAAG,MAAO,GACpD,IAAIwD,EAAM,EACV,QAAShC,EAAI,EAAGA,EAAIxB,EAAK,OAAS,EAAGwB,GAAK,EAAG,CAC5C,MAAMiC,EAAIzD,EAAKwB,CAAC,EACVkC,EAAI1D,EAAKwB,EAAI,CAAC,EACpBgC,GAAOC,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAID,EAAE,CAAC,CAChC,CACA,OAAOD,EAAM,EACd,CAEA,SAAS6C,GAAsBC,EAAyC,CACvE,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,SAAW,EAAG,MAAO,CAAA,EACxD,MAAMC,EAA8B,CAAA,EACpC,UAAWvG,KAAQsG,EAAO,CACzB,MAAMzC,EAASuC,GAAapG,CAAI,EAC5B6D,EAAO,QAAU,GAAG0C,EAAW,KAAK1C,CAAM,CAC/C,CACA,GAAI0C,EAAW,SAAW,EAAG,MAAO,CAAA,EACpC,GAAIA,EAAW,SAAW,QAAU,CAACA,EAAW,CAAC,CAAC,EAElD,IAAIC,EAAa,EACbC,EAAY,EAChB,QAASjF,EAAI,EAAGA,EAAI+E,EAAW,OAAQ/E,GAAK,EAAG,CAC9C,MAAMoE,EAAO,KAAK,IAAIrC,GAAkBgD,EAAW/E,CAAC,CAAC,CAAC,EAClDoE,GAAQa,IACZA,EAAYb,EACZY,EAAahF,EACd,CAEA,MAAMrC,EAAuB,CAACoH,EAAWC,CAAU,CAAC,EACpD,QAAShF,EAAI,EAAGA,EAAI+E,EAAW,OAAQ/E,GAAK,EACvCA,IAAMgF,GACVrH,EAAI,KAAKoH,EAAW/E,CAAC,CAAC,EAEvB,OAAOrC,CACR,CAEO,SAASuH,GAAqBC,EAA2D,CAC/F,GAAI,CAACA,EAAU,MAAO,CAAA,EAEtB,GAAIX,GAAaW,CAAQ,EAAG,CAC3B,MAAMR,EAAUE,GAAsB,CAACM,CAAQ,CAAC,EAChD,OAAOR,EAAQ,OAAS,EAAI,CAACA,CAAO,EAAI,CAAA,CACzC,CAEA,GAAIF,GAAeU,CAAQ,EAAG,CAC7B,MAAMR,EAAUE,GAAsBM,CAAQ,EAC9C,OAAOR,EAAQ,OAAS,EAAI,CAACA,CAAO,EAAI,CAAA,CACzC,CAEA,GAAID,GAAeS,CAAQ,EAAG,CAC7B,MAAMxH,EAAuB,CAAA,EAC7B,UAAWgH,KAAWQ,EAAU,CAC/B,MAAMJ,EAAaF,GAAsBF,CAAO,EAC5CI,EAAW,OAAS,GAAGpH,EAAI,KAAKoH,CAAU,CAC/C,CACA,OAAOpH,CACR,CAEA,MAAO,CAAA,CACR,CAEO,SAASyH,GAAYxH,EAAWC,EAAWW,EAA8B,CAC/E,IAAI6G,EAAS,GACb,QAAS,EAAI,EAAGC,EAAI9G,EAAK,OAAS,EAAG,EAAIA,EAAK,OAAQ8G,EAAI,EAAG,GAAK,EAAG,CACpE,MAAMC,EAAK/G,EAAK,CAAC,EAAE,CAAC,EACdgH,EAAKhH,EAAK,CAAC,EAAE,CAAC,EACdiH,EAAKjH,EAAK8G,CAAC,EAAE,CAAC,EACdI,EAAKlH,EAAK8G,CAAC,EAAE,CAAC,EAEnBE,EAAK3H,GAAM6H,EAAK7H,GAChBD,GAAM6H,EAAKF,IAAO1H,EAAI2H,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,UAAWR,KAAWmB,EAAc,CACnC,MAAMC,EAAQpB,EAAQ,CAAC,EACvB,GAAI,CAACoB,GAASA,EAAM,OAAS,EAAG,SAChC,IAAIpH,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClB,EAAGC,CAAC,IAAKkI,EAChBnI,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GACjBC,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GAEtB,GACC,CAAC,OAAO,SAASc,CAAI,GACrB,CAAC,OAAO,SAASC,CAAI,GACrB,CAAC,OAAO,SAASC,CAAI,GACrB,CAAC,OAAO,SAASC,CAAI,EAErB,SAED,IAAIsF,EAAO,KAAK,IAAIrC,GAAkBgE,CAAK,CAAC,EAC5C,QAAS/F,EAAI,EAAGA,EAAI2E,EAAQ,OAAQ3E,GAAK,EACxCoE,GAAQ,KAAK,IAAIrC,GAAkB4C,EAAQ3E,CAAC,CAAC,CAAC,EAE/C6F,EAAS,KAAK,CACb,MAAAE,EACA,MAAOpB,EAAQ,MAAM,CAAC,EACtB,KAAAhG,EACA,KAAAC,EACA,KAAAC,EACA,KAAAC,EACA,KAAM,KAAK,IAAI,KAAMsF,CAAI,CAAA,CACzB,CACF,CACD,CACA,OAAOyB,CACR,CAEO,SAASG,GACfpI,EACAC,EACA8G,EACU,CAIV,GAHI/G,EAAI+G,EAAQ,MAAQ/G,EAAI+G,EAAQ,MAAQ9G,EAAI8G,EAAQ,MAAQ9G,EAAI8G,EAAQ,MAGxE,CAACS,GAAYxH,EAAGC,EAAG8G,EAAQ,KAAK,EAAG,MAAO,GAC9C,UAAWsB,KAAQtB,EAAQ,MAC1B,GAAIS,GAAYxH,EAAGC,EAAGoI,CAAI,EAAG,MAAO,GAErC,MAAO,EACR,CAEO,SAASC,GACftI,EACAC,EACAsI,EACU,CACV,UAAWxB,KAAWwB,EACrB,GAAKH,GAAuBpI,EAAGC,EAAG8G,CAAO,EACzC,MAAO,GAER,MAAO,EACR,CCnOO,MAAMyB,GAAwD,CACpE,IAAK,IAAK,IAAK,GAChB,ECCO,SAAS/I,GAAMC,EAAeC,EAAaC,EAAqB,CACtE,OAAO,KAAK,IAAID,EAAK,KAAK,IAAIC,EAAKF,CAAK,CAAC,CAC1C,CAEO,SAAS+I,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,GACf9E,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,SAAS8E,GAAc1J,EAA0C,CACvE,MAAM2J,EAAU,OAAO3J,GAAS,EAAE,EAAE,KAAA,EACpC,GAAI,CAAC2J,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,GAAGjB,EAAmB,EAE1C,MAAMkB,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,GAAGrB,EAAmB,CAAA,EAElBsB,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,CAEO,SAAStO,GACfL,EACAM,EACAC,EACe,CACf,MAAMwO,EAAK/O,EAAG,aAAaA,EAAG,aAAa,EACrCgP,EAAKhP,EAAG,aAAaA,EAAG,eAAe,EAC7C,GAAI,CAAC+O,GAAM,CAACC,EACX,MAAM,IAAI,MAAM,0BAA0B,EAK3C,GAFAhP,EAAG,aAAa+O,EAAIzO,CAAY,EAChCN,EAAG,cAAc+O,CAAE,EACf,CAAC/O,EAAG,mBAAmB+O,EAAI/O,EAAG,cAAc,EAC/C,MAAM,IAAI,MAAMA,EAAG,iBAAiB+O,CAAE,GAAK,uBAAuB,EAKnE,GAFA/O,EAAG,aAAagP,EAAIzO,CAAc,EAClCP,EAAG,cAAcgP,CAAE,EACf,CAAChP,EAAG,mBAAmBgP,EAAIhP,EAAG,cAAc,EAC/C,MAAM,IAAI,MAAMA,EAAG,iBAAiBgP,CAAE,GAAK,yBAAyB,EAGrE,MAAMtO,EAAUV,EAAG,cAAA,EACnB,GAAI,CAACU,EACJ,MAAM,IAAI,MAAM,2BAA2B,EAU5C,GAPAV,EAAG,aAAaU,EAASqO,CAAE,EAC3B/O,EAAG,aAAaU,EAASsO,CAAE,EAC3BhP,EAAG,YAAYU,CAAO,EAEtBV,EAAG,aAAa+O,CAAE,EAClB/O,EAAG,aAAagP,CAAE,EAEd,CAAChP,EAAG,oBAAoBU,EAASV,EAAG,WAAW,EAClD,MAAM,IAAI,MAAMA,EAAG,kBAAkBU,CAAO,GAAK,qBAAqB,EAGvE,OAAOA,CACR,CCkGA,MAAMuO,GAAY,0BACZC,GAA4B,cAC5BC,GAAsB,EACtBC,GAAuB,EACvBC,GAAe,GACfC,GAAc,EACdC,GAA8B,CAAA,EAC9BC,GAAuB,CAAA,EACvBC,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,IAEpBC,GAAiD,CACrD,MAAO,UACP,MAAO,EAEP,SAAU,QACV,QAAS,QACT,YAAa,mBACb,WAAY,EACZ,cAAe,EACf,cAAe,CACjB,EAEMC,GAAgD,CACpD,MAAO,UACP,MAAO,EACP,SAAU,CAAC,GAAI,CAAC,EAChB,SAAU,QACV,QAAS,QACT,YAAa,mBACb,WAAY,EACZ,cAAe,EACf,cAAe,CACjB,EAEMC,GAAkC,wBAClCC,GAAkC,EAElCC,GAA+C,CACnD,WAAY,wEACZ,SAAU,GACV,WAAY,IACZ,UAAW,UACX,gBAAiB,UACjB,YAAa,mBACb,YAAa,EACb,SAAU,EACV,SAAU,EACV,QAAS,GACT,aAAc,CAChB,EAEMC,GAAwD,CAC5D,WAAY,wEACZ,SAAU,GACV,WAAY,IACZ,UAAW,UACX,gBAAiB,wBACjB,aAAc,EACd,SAAU,EACV,SAAU,CACZ,EAEMC,GAAmC,CACvC,EAAG,GACH,EAAG,GACL,EACMC,GAAuC,GACvCC,GAAqC,KAE3C,SAASlN,GAAMC,EAAeC,EAAaC,EAAqB,CAC9D,OAAO,KAAK,IAAID,EAAK,KAAK,IAAIC,EAAKF,CAAK,CAAC,CAC3C,CAEO,SAASkN,GACdC,EACAlO,EACAmO,EACQ,CAER,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,GAAWJ,IACrB,CAAC,OAAO,SAAShO,CAAI,EAAU,EAC5BA,GAAQqO,EAAUL,GAAqCD,GAAuC,CACvG,CAEA,SAASO,GAAYC,EAAuC,CAC1D,OACEA,IAAS,mBAAqBA,IAAS,gBAAkBA,IAAS,0BAA4BA,IAAS,wBAA0BA,IAAS,qBAAuBA,IAAS,yBAE9K,CAEA,SAASC,GAAwBzN,EAA2B0N,EAA0B,CACpF,OAAI,OAAO1N,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,GAAKA,GAAS,EAC5D0N,EAEF1N,CACT,CAEA,SAAS2N,GAAoBnQ,EAA2D,CACtF,MAAO,CACL,iBAAkBiQ,GAAwBjQ,GAAS,iBAAkB2N,EAAgC,EACrG,cAAesC,GAAwBjQ,GAAS,cAAe4N,EAA6B,EAC5F,mBAAoBqC,GAAwBjQ,GAAS,mBAAoB6N,EAAkC,CAAA,CAE/G,CAEA,SAASuC,GAAiB5N,EAA2B0N,EAA0B,CAC7E,OAAI,OAAO1N,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU0N,EAC1D3N,GAAMC,EAAO,EAAG,CAAC,CAC1B,CAEA,SAAS6N,GAAsB7N,EAAuC,CACpE,GAAI,CAAC,MAAM,QAAQA,CAAK,EAAG,OAAO+L,GAClC,MAAM1L,EAAML,EAAM,OAAO8N,GAAQ,OAAO,SAASA,CAAI,GAAKA,GAAQ,CAAC,EACnE,OAAOzN,EAAI,OAAS,EAAIA,EAAM0L,EAChC,CAEA,SAASgC,GAAuB/N,EAAmC,CACjE,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUgM,GAC1DjM,GAAMC,EAAOiM,GAAuBC,EAAqB,CAClE,CAEA,SAAS8B,GAA0BhO,EAAmC,CACpE,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAUmM,GAC1D,KAAK,MAAMpM,GAAMC,EAAOoM,GAA0BC,EAAwB,CAAC,CACpF,CAEA,SAAS4B,GAAoBzQ,EAAyD,CACpF,MAAMwD,EAASyM,GAAwBjQ,GAAS,OAAQiO,EAAoB,EACtEyC,EAAkBT,GAAwBjQ,GAAS,gBAAiBsO,EAA+B,EACnGqC,EAAaJ,GAAuBvQ,GAAS,UAAU,EACvD4Q,EAAgBJ,GAA0BxQ,GAAS,aAAa,EACtE,MAAO,CACL,OAAAwD,EACA,WAAAmN,EACA,cAAAC,EACA,eAAgB5Q,GAAS,iBAAmB,GAC5C,UAAWA,GAAS,WAAakO,GACjC,YAAakC,GAAiBpQ,GAAS,YAAamO,EAA0B,EAC9E,YAAanO,GAAS,aAAeoO,GACrC,kBAAmBpO,GAAS,mBAAqBqO,GACjD,gBAAAqC,EACA,eAAgBL,GAAsBrQ,GAAS,cAAc,CAAA,CAEjE,CAEA,SAAS6Q,GAASC,EAAyB,CACzC,OAAOA,EAAUpD,GAAiBA,EACpC,CAEA,SAASqD,GACPxN,EACAyN,EACAC,EAIkB,CAClB,GAAI,CAAC1N,GAAU,CAAC,OAAO,SAASyN,CAAU,GAAKA,GAAc,EAAG,MAAO,CAAA,EAEvE,GAAIC,EAAY,CACd,MAAMC,EAAeD,EAAW,cAAc1N,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,EAC5D4N,EAAaF,EAAW,cAAc1N,EAAO,CAAC,EAAIyN,EAAYzN,EAAO,CAAC,CAAC,EAC7E,GAAI2N,GAAgBC,EAAY,CAC9B,MAAMC,EAAW,KAAK,MAAMD,EAAW,CAAC,EAAID,EAAa,CAAC,EAAGC,EAAW,CAAC,EAAID,EAAa,CAAC,CAAC,EACtFG,EAAkC,CACtC,CAACH,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,EAEnDE,EAAiC,CAAA,EACvC,UAAWC,KAAUF,EAAe,CAClC,MAAMG,EAAQP,EAAW,cAAcM,CAAM,EAC7C,GAAI,CAACC,EAAO,MAAM,IAAI,MAAM,4BAA4B,EACxDF,EAAa,KAAKE,CAAK,CACzB,CACA,OAAO7O,GAAU2O,CAAY,CAC/B,CACF,CAEA,OAAO3O,GAAU,CACf,CAACY,EAAO,CAAC,EAAIyN,EAAYzN,EAAO,CAAC,EAAIyN,CAAU,EAC/C,CAACzN,EAAO,CAAC,EAAIyN,EAAYzN,EAAO,CAAC,EAAIyN,CAAU,EAC/C,CAACzN,EAAO,CAAC,EAAIyN,EAAYzN,EAAO,CAAC,EAAIyN,CAAU,EAC/C,CAACzN,EAAO,CAAC,EAAIyN,EAAYzN,EAAO,CAAC,EAAIyN,CAAU,CAAA,CAChD,CACH,CAEA,SAASS,GAAuBlO,EAA+BC,EAAgBC,EAAQ6J,GAAgC,CACrH,GAAI,CAAC/J,GAAU,CAAC,OAAO,SAASC,CAAM,GAAKA,GAAU,EAAG,MAAO,CAAA,EAE/D,MAAMkO,EAA2B,CAAA,EACjC,QAAS,EAAI,EAAG,GAAKjO,EAAO,GAAK,EAAG,CAClC,MAAME,EAAK,EAAIF,EAAS,KAAK,GAAK,EAClCiO,EAAO,KAAK,CAACnO,EAAO,CAAC,EAAI,KAAK,IAAII,CAAC,EAAIH,EAAQD,EAAO,CAAC,EAAI,KAAK,IAAII,CAAC,EAAIH,CAAM,CAAC,CAClF,CAEA,OAAOb,GAAU+O,CAAM,CACzB,CAEO,SAAS/O,GAAU+O,EAA4C,CACpE,GAAI,CAAC,MAAM,QAAQA,CAAM,GAAKA,EAAO,OAAS,EAAG,MAAO,CAAA,EAExD,MAAM7O,EAAM6O,EAAO,IAAI,CAAC,CAAC5O,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,EACrDC,EAAQH,EAAI,CAAC,EACbI,EAAOJ,EAAIA,EAAI,OAAS,CAAC,EAC/B,MAAI,CAACG,GAAS,CAACC,EAAa,CAAA,IAExBD,EAAM,CAAC,IAAMC,EAAK,CAAC,GAAKD,EAAM,CAAC,IAAMC,EAAK,CAAC,IAC7CJ,EAAI,KAAK,CAACG,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAAC,EAGxBH,EACT,CAEO,SAAS8O,GACdtJ,EACAC,EACA2I,EAIkB,CAClB,GAAI,CAAC5I,GAAS,CAACC,QAAY,CAAA,EAE3B,GAAI2I,EAAY,CACd,MAAMW,EAAcX,EAAW,cAAc5I,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EACzDwJ,EAAYZ,EAAW,cAAc3I,EAAI,CAAC,EAAGA,EAAI,CAAC,CAAC,EAEzD,GAAIsJ,GAAeC,EAAW,CAC5B,MAAMR,EAAkC,CACtC,CAACO,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,EAEzBP,EAAiC,CAAA,EACvC,UAAWC,KAAUF,EAAe,CAClC,MAAMG,EAAQP,EAAW,cAAcM,CAAM,EAC7C,GAAI,CAACC,EAAO,OAAOG,GAAgBtJ,EAAOC,CAAG,EAC7CgJ,EAAa,KAAKE,CAAK,CACzB,CACA,OAAO7O,GAAU2O,CAAY,CAC/B,CACF,CAEA,OAAO3O,GAAU,CACf,CAAC0F,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,SAASwJ,GAAazJ,EAA8BC,EAA4B7E,EAAQ6J,GAAgC,CAC7H,GAAI,CAACjF,GAAS,CAACC,QAAY,CAAA,EAE3B,MAAMyJ,GAAW1J,EAAM,CAAC,EAAIC,EAAI,CAAC,GAAK,GAChC0J,GAAW3J,EAAM,CAAC,EAAIC,EAAI,CAAC,GAAK,GAChC9E,EAAS,KAAK,MAAM8E,EAAI,CAAC,EAAID,EAAM,CAAC,EAAGC,EAAI,CAAC,EAAID,EAAM,CAAC,CAAC,EAAI,GAClE,GAAI7E,EAAS,EAAG,MAAO,CAAA,EAEvB,MAAMkO,EAA2B,CAAA,EACjC,QAASxM,EAAI,EAAGA,GAAKzB,EAAOyB,GAAK,EAAG,CAClC,MAAMvB,EAAKuB,EAAIzB,EAAS,KAAK,GAAK,EAClCiO,EAAO,KAAK,CAACK,EAAU,KAAK,IAAIpO,CAAC,EAAIH,EAAQwO,EAAU,KAAK,IAAIrO,CAAC,EAAIH,CAAM,CAAC,CAC9E,CAEA,OAAOb,GAAU+O,CAAM,CACzB,CAEA,SAASO,GAAYP,EAAkC,CACrD,GAAI,CAAC,MAAM,QAAQA,CAAM,GAAKA,EAAO,OAAS,EAAG,MAAO,GAExD,IAAIxK,EAAM,EACV,QAAShC,EAAI,EAAGA,EAAIwM,EAAO,OAAS,EAAGxM,GAAK,EAAG,CAC7C,MAAMiC,EAAIuK,EAAOxM,CAAC,EACZkC,EAAIsK,EAAOxM,EAAI,CAAC,EACtBgC,GAAOC,EAAE,CAAC,EAAIC,EAAE,CAAC,EAAIA,EAAE,CAAC,EAAID,EAAE,CAAC,CACjC,CAEA,OAAO,KAAK,IAAID,EAAM,EAAG,CAC3B,CAEA,SAASgL,GAAcR,EAAsC,CAC3D,GAAI,CAAC,MAAM,QAAQA,CAAM,GAAKA,EAAO,SAAW,EAAG,MAAO,CAAC,EAAG,EAAG,EAAG,CAAC,EAErE,IAAI7N,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KAEX,SAAW,CAAClB,EAAGC,CAAC,IAAK2O,EACf5O,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GACjBC,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GAGvB,MAAO,CAACc,EAAMC,EAAMC,EAAMC,CAAI,CAChC,CAEA,SAASmO,GAAeT,EAAmC,CACzD,OAAO,MAAM,QAAQA,CAAM,GAAKA,EAAO,QAAU,GAAKO,GAAYP,CAAM,EAAInE,EAC9E,CAEA,SAAS6E,GAAUC,EAA+BlP,EAA0BmP,EAAQ,GAAa,CAC/F,GAAInP,EAAO,SAAW,EAEtB,CAAAkP,EAAI,OAAOlP,EAAO,CAAC,EAAE,CAAC,EAAGA,EAAO,CAAC,EAAE,CAAC,CAAC,EACrC,QAAS+B,EAAI,EAAGA,EAAI/B,EAAO,OAAQ+B,GAAK,EACtCmN,EAAI,OAAOlP,EAAO+B,CAAC,EAAE,CAAC,EAAG/B,EAAO+B,CAAC,EAAE,CAAC,CAAC,EAGnCoN,GACFD,EAAI,UAAA,EAER,CAEA,SAASE,GACPF,EACAlP,EACAqP,EACAF,EAAQ,GACRG,EAAO,GACPC,EAAYxF,GACN,CACF/J,EAAO,SAAW,IAEtBkP,EAAI,UAAA,EACJD,GAAUC,EAAKlP,EAAQmP,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,YAAY5E,EAAU,EAC1B4E,EAAI,YAAc,mBAClBA,EAAI,WAAa,EACjBA,EAAI,cAAgB,EACpBA,EAAI,cAAgB,EACtB,CAEA,SAASM,GAA4BnQ,EAAmC,CACtE,GAAI,OAAOA,GAAU,SAAU,OAAO2K,GACtC,MAAM7N,EAAOkD,EAAM,KAAA,EACnB,OAAOlD,EAAK,OAAS,EAAIA,EAAO6N,EAClC,CAEA,SAASyF,GAAmBC,EAAkE,CAC5F,MAAMC,EAAO,MAAM,QAAQD,GAAO,QAAQ,EAAIA,EAAM,SAAS,OAAOrQ,GAAS,OAAO,SAASA,CAAK,GAAKA,GAAS,CAAC,EAAIiL,GAC/GrO,EAAQ,OAAOyT,GAAO,OAAU,UAAY,OAAO,SAASA,EAAM,KAAK,EAAI,KAAK,IAAI,EAAGA,EAAM,KAAK,EAAI5D,GAA4B,MAClI8D,EAAa,OAAOF,GAAO,YAAe,UAAY,OAAO,SAASA,EAAM,UAAU,EAAI,KAAK,IAAI,EAAGA,EAAM,UAAU,EAAI5D,GAA4B,WACtJ+D,EAAgB,OAAOH,GAAO,eAAkB,UAAY,OAAO,SAASA,EAAM,aAAa,EAAIA,EAAM,cAAgB5D,GAA4B,cACrJgE,EAAgB,OAAOJ,GAAO,eAAkB,UAAY,OAAO,SAASA,EAAM,aAAa,EAAIA,EAAM,cAAgB5D,GAA4B,cAC3J,MAAO,CACL,MAAO4D,GAAO,OAAS5D,GAA4B,MACnD,MAAA7P,EACA,SAAU0T,EAAK,OAASA,EAAOrF,GAC/B,SAAUoF,GAAO,UAAY5D,GAA4B,SACzD,QAAS4D,GAAO,SAAW5D,GAA4B,QACvD,YAAa4D,GAAO,aAAe5D,GAA4B,YAC/D,WAAA8D,EACA,cAAAC,EACA,cAAAC,CAAA,CAEJ,CAEA,SAASC,GAAiBC,EAAyBC,EAAqE,CACtH,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,CAEA,SAASE,GAAelM,EAAuCC,EAAgD,CAC7G,OAAID,GAAM,MAA2BC,IAAM,MAAQA,IAAM,OAChD,GAEF,OAAOD,CAAC,IAAM,OAAOC,CAAC,CAC/B,CAEA,SAASkM,GAAwB1Q,EAA8C,CAC7E,MAAMI,EAAQJ,EAAY,CAAC,EAC3B,OAAO,MAAM,QAAQI,CAAK,GAAK,MAAM,QAAQA,EAAM,CAAC,CAAC,CACvD,CAEA,SAASwG,GAAehH,EAAiC,CACvD,OAAO,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,CAC3D,CAEA,SAASiH,GAAiBjH,EAA2C,CACnE,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,QAAU,GAAKgH,GAAehH,EAAM,CAAC,CAAC,GAAKgH,GAAehH,EAAM,CAAC,CAAC,CACzG,CAEA,SAAS+Q,GAAiB/Q,EAA2C,CACnE,OAAO,MAAM,QAAQA,CAAK,GAAKA,EAAM,QAAU,GAAKA,EAAM,MAAMY,GAASqG,GAAiBrG,CAAK,CAAC,CAClG,CAEA,SAASoQ,GAAoBhR,EAAgBK,EAA+B,CAC1E,GAAI,GAAC,MAAM,QAAQL,CAAK,GAAKA,EAAM,SAAW,GAC9C,IAAI+Q,GAAiB/Q,CAAK,EAAG,CAC3BK,EAAI,KAAKL,EAAM,IAAI,CAAC,CAACM,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,CAAC,EACxD,MACF,CACA,UAAWuN,KAAQ9N,EACjBgR,GAAoBlD,EAAMzN,CAAG,EAEjC,CAEA,SAAS4Q,GAAsB7Q,EAAqC0P,EAAoC,CACtG,MAAMoB,EAAkC,CAAA,EACxCF,GAAoB5Q,EAAa8Q,CAAW,EAC5C,MAAM7Q,EAA0B,CAAA,EAChC,UAAWa,KAAQgQ,EAAa,CAC9B,GAAIhQ,EAAK,OAAS,EAAG,SACrB,MAAMuG,EAAaqI,EAAQ3P,GAAUe,CAAI,EAAIA,EACzCuG,EAAW,SAAWqI,EAAQ,EAAI,IACpCzP,EAAI,KAAKoH,CAAU,CAEvB,CACA,OAAOpH,CACT,CAEA,SAAS8Q,GAAqBtB,EAA+BuB,EAA6BC,EAA+BnB,EAAyB,CAChJ,GAAI,EAAAkB,EAAU,OAAS,GAAKC,EAAU,SAAW,GACjD,CAAAxB,EAAI,KAAA,EACJA,EAAI,UAAA,EACJD,GAAUC,EAAKuB,EAAW,EAAI,EAC9B,UAAWlQ,KAAQmQ,EACbnQ,EAAK,OAAS,GAClB0O,GAAUC,EAAK3O,EAAM,EAAI,EAE3B2O,EAAI,UAAYK,EAChBL,EAAI,KAAK,SAAS,EAClBA,EAAI,QAAA,EACN,CAEO,SAASyB,GAAwBjB,EAAgE,CACtG,MAAMkB,EAAK,OAAOlB,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIxD,GAA2B,SACvI2E,EAAK,OAAOnB,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIxD,GAA2B,SACvIpC,EAAK,OAAO4F,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIxD,GAA2B,SACvI4E,EAAK,OAAOpB,GAAO,aAAgB,UAAY,OAAO,SAASA,EAAM,WAAW,EAAI,KAAK,IAAI,EAAGA,EAAM,WAAW,EAAIxD,GAA2B,YAChJ6E,EAAK,OAAOrB,GAAO,SAAY,UAAY,OAAO,SAASA,EAAM,OAAO,EAAIA,EAAM,QAAUxD,GAA2B,QACvH8E,EAAK,OAAOtB,GAAO,cAAiB,UAAY,OAAO,SAASA,EAAM,YAAY,EAAI,KAAK,IAAI,EAAGA,EAAM,YAAY,EAAIxD,GAA2B,aACzJ,MAAO,CACL,WAAYwD,GAAO,YAAcxD,GAA2B,WAC5D,SAAUpC,EACV,WAAY4F,GAAO,YAAcxD,GAA2B,WAC5D,UAAWwD,GAAO,WAAaxD,GAA2B,UAC1D,gBAAiBwD,GAAO,iBAAmBxD,GAA2B,gBACtE,YAAawD,GAAO,aAAexD,GAA2B,YAC9D,YAAa4E,EACb,SAAUF,EACV,SAAUC,EACV,QAASE,EACT,aAAcC,CAAA,CAElB,CAEO,SAASC,GAAsBjB,EAAwBC,EAA0E,CACtI,OAAKA,EACEU,GAAwB,CAC7B,WAAYV,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,CAEA,SAASkB,GAA4BxB,EAAwE,CAC3G,MAAMyB,EAAW,OAAOzB,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIvD,GAAgC,SAClJiF,EAAe,OAAO1B,GAAO,cAAiB,UAAY,OAAO,SAASA,EAAM,YAAY,EAAI,KAAK,IAAI,EAAGA,EAAM,YAAY,EAAIvD,GAAgC,aAClKkF,EAAW,OAAO3B,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIvD,GAAgC,SAClJmF,EAAW,OAAO5B,GAAO,UAAa,UAAY,OAAO,SAASA,EAAM,QAAQ,EAAI,KAAK,IAAI,EAAGA,EAAM,QAAQ,EAAIvD,GAAgC,SACxJ,MAAO,CACL,WAAYuD,GAAO,YAAcvD,GAAgC,WACjE,SAAAgF,EACA,WAAYzB,GAAO,YAAcvD,GAAgC,WACjE,UAAWuD,GAAO,WAAavD,GAAgC,UAC/D,gBAAiBuD,GAAO,iBAAmBvD,GAAgC,gBAC3E,aAAAiF,EACA,SAAAC,EACA,SAAAC,CAAA,CAEJ,CAEA,SAASC,GAA2BlS,EAAyE,CAC3G,MAAMM,EAAI,OAAON,GAAO,GAAM,UAAY,OAAO,SAASA,EAAM,CAAC,EAAIA,EAAM,EAAI+M,GAAiC,EAC1GxM,EAAI,OAAOP,GAAO,GAAM,UAAY,OAAO,SAASA,EAAM,CAAC,EAAIA,EAAM,EAAI+M,GAAiC,EAChH,MAAO,CAAE,EAAAzM,EAAG,EAAAC,CAAA,CACd,CAEA,SAAS4R,GAAgC7D,EAAyB,CAChE,OAAK,OAAO,SAASA,CAAO,EACrB,GAAG,KAAK,IAAI,EAAGA,CAAO,EAAE,QAAQ,CAAC,CAAC,OADH,WAExC,CAEA,SAAS8D,GAA8B5U,EAA6E,CAClH,MAAM6U,EAAS,OAAO7U,GAAS,QAAW,WAAaA,EAAQ,OAAS2U,GAClEG,EAAeJ,GAA2B1U,GAAS,YAAY,EACrE,MAAO,CACL,QAASA,GAAS,UAAY,GAC9B,OAAA6U,EACA,MAAOR,GAA4BrU,GAAS,KAAK,EACjD,cAAe8U,EAAa,EAC5B,cAAeA,EAAa,CAAA,CAEhC,CAEA,SAASC,GAAoCvC,EAAmD,CAC9F,MAAO,CACL,MAAOrD,GACP,MAAOC,GACP,SAAU3B,GACV,SAAU+E,EAAY,SACtB,QAASA,EAAY,QACrB,YAAa,mBACb,WAAY,EACZ,cAAe,EACf,cAAe,CAAA,CAEnB,CAEA,SAASwC,GAAgB3C,EAA+BvP,EAAWC,EAAW3D,EAAeC,EAAgBmE,EAAsB,CACjI,MAAMyR,EAAI,KAAK,IAAI,EAAG,KAAK,IAAIzR,EAAQpE,EAAQ,GAAKC,EAAS,EAAG,CAAC,EACjEgT,EAAI,UAAA,EACJA,EAAI,OAAOvP,EAAImS,EAAGlS,CAAC,EACnBsP,EAAI,OAAOvP,EAAI1D,EAAQ6V,EAAGlS,CAAC,EAC3BsP,EAAI,iBAAiBvP,EAAI1D,EAAO2D,EAAGD,EAAI1D,EAAO2D,EAAIkS,CAAC,EACnD5C,EAAI,OAAOvP,EAAI1D,EAAO2D,EAAI1D,EAAS4V,CAAC,EACpC5C,EAAI,iBAAiBvP,EAAI1D,EAAO2D,EAAI1D,EAAQyD,EAAI1D,EAAQ6V,EAAGlS,EAAI1D,CAAM,EACrEgT,EAAI,OAAOvP,EAAImS,EAAGlS,EAAI1D,CAAM,EAC5BgT,EAAI,iBAAiBvP,EAAGC,EAAI1D,EAAQyD,EAAGC,EAAI1D,EAAS4V,CAAC,EACrD5C,EAAI,OAAOvP,EAAGC,EAAIkS,CAAC,EACnB5C,EAAI,iBAAiBvP,EAAGC,EAAGD,EAAImS,EAAGlS,CAAC,EACnCsP,EAAI,UAAA,CACN,CAEA,SAAS6C,GAAaxD,EAAiD,CACrE,GAAI,CAACA,EAAO,OAAQ,OAAO,KAE3B,IAAI5N,EAAO,IACX,UAAWV,KAASsO,EACdtO,EAAM,CAAC,EAAIU,IAAMA,EAAOV,EAAM,CAAC,GAErC,GAAI,CAAC,OAAO,SAASU,CAAI,EAAG,OAAO,KAEnC,IAAID,EAAO,IACPE,EAAO,KACX,UAAWX,KAASsO,EACd,KAAK,IAAItO,EAAM,CAAC,EAAIU,CAAI,EAAI,KAC5BV,EAAM,CAAC,EAAIS,IAAMA,EAAOT,EAAM,CAAC,GAC/BA,EAAM,CAAC,EAAIW,IAAMA,EAAOX,EAAM,CAAC,IAGrC,MAAI,CAAC,OAAO,SAASS,CAAI,GAAK,CAAC,OAAO,SAASE,CAAI,EAAU,KACtD,EAAEF,EAAOE,GAAQ,GAAKD,CAAI,CACnC,CAEA,SAASqR,GAAyB9J,EAAgE,CAChG,IAAI+J,EAA8B,KAClC,UAAWvL,KAAWwB,EAAU,CAC9B,MAAMgK,EAASH,GAAarL,EAAQ,KAAK,EACpCwL,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,CAEA,SAASE,GAA4B1S,EAAmE,CACtG,MAAMoI,EAAeZ,GAAqBxH,CAA0B,EACpE,GAAIoI,EAAa,SAAW,EAAG,MAAO,CAAA,EAEtC,MAAMnI,EAAqC,CAAA,EAC3C,UAAWgH,KAAWmB,EAAc,CAClC,MAAMC,EAAQpB,EAAQ,CAAC,EACvB,GAAI,CAACoB,GAASA,EAAM,OAAS,EAAG,SAChC,MAAMsK,EAAkBtK,EAAM,IAAI,CAAC,CAACnI,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,EAChEyS,EAA4B,CAAA,EAClC,QAAStQ,EAAI,EAAGA,EAAI2E,EAAQ,OAAQ3E,GAAK,EAAG,CAC1C,MAAMiG,EAAOtB,EAAQ3E,CAAC,EAClB,CAACiG,GAAQA,EAAK,OAAS,GAC3BqK,EAAM,KAAKrK,EAAK,IAAI,CAAC,CAACrI,EAAGC,CAAC,IAAM,CAACD,EAAGC,CAAC,CAAmB,CAAC,CAC3D,CACAF,EAAI,KAAK,CACP,MAAO0S,EACP,MAAAC,CAAA,CACD,CACH,CACA,OAAO3S,CACT,CAEA,SAAS4S,GAAgBpD,EAA+BqD,EAAcL,EAAwBM,EAAqBC,EAAsBC,EAAoC,CAC3K,MAAMC,EAAQJ,EAAK,KAAA,EACnB,GAAI,CAACI,EAAO,OAEZzD,EAAI,KAAA,EACJA,EAAI,KAAO,GAAGwD,EAAW,UAAU,IAAIA,EAAW,QAAQ,MAAMA,EAAW,UAAU,GACrFxD,EAAI,UAAY,SAChBA,EAAI,aAAe,SAGnB,MAAM0D,EADY1D,EAAI,YAAYyD,CAAK,EAAE,MACZD,EAAW,SAAW,EAC7CG,EAAYH,EAAW,SAAWA,EAAW,SAAW,EAExD/S,EAAIP,GAAM8S,EAAO,CAAC,EAAGU,EAAW,GAAM,EAAGJ,EAAcI,EAAW,GAAM,CAAC,EACzEhT,EAAIR,GAAM8S,EAAO,CAAC,EAAIQ,EAAW,QAASG,EAAY,GAAM,EAAGJ,EAAeI,EAAY,GAAM,CAAC,EACjGC,EAAOnT,EAAIiT,EAAW,GACtBG,EAAMnT,EAAIiT,EAAY,GAE5B3D,EAAI,UAAYwD,EAAW,gBAC3BxD,EAAI,YAAcwD,EAAW,YAC7BxD,EAAI,UAAYwD,EAAW,YAC3Bb,GAAgB3C,EAAK4D,EAAMC,EAAKH,EAAUC,EAAWH,EAAW,YAAY,EAC5ExD,EAAI,KAAA,EACAwD,EAAW,YAAc,GAC3BxD,EAAI,OAAA,EAGNA,EAAI,UAAYwD,EAAW,UAC3BxD,EAAI,SAASyD,EAAOhT,EAAGC,EAAI,EAAG,EAC9BsP,EAAI,QAAA,CACN,CAEA,SAAS8D,GACP9D,EACAqD,EACAU,EACAT,EACAC,EACA/C,EACAhR,EACAC,EACM,CACN,MAAMgU,EAAQJ,EAAK,KAAA,EACnB,GAAI,CAACI,EAAO,OAEZzD,EAAI,KAAA,EACJA,EAAI,KAAO,GAAGQ,EAAM,UAAU,IAAIA,EAAM,QAAQ,MAAMA,EAAM,UAAU,GACtER,EAAI,UAAY,SAChBA,EAAI,aAAe,SAGnB,MAAM0D,EADY1D,EAAI,YAAYyD,CAAK,EAAE,MACZjD,EAAM,SAAW,EACxCmD,EAAYnD,EAAM,SAAWA,EAAM,SAAW,EAE9C/P,EAAIP,GAAM6T,EAAa,CAAC,EAAIvU,EAASkU,EAAW,GAAM,EAAGJ,EAAcI,EAAW,GAAM,CAAC,EACzFhT,EAAIR,GAAM6T,EAAa,CAAC,EAAItU,EAASkU,EAAY,GAAM,EAAGJ,EAAeI,EAAY,GAAM,CAAC,EAC5FC,EAAOnT,EAAIiT,EAAW,GACtBG,EAAMnT,EAAIiT,EAAY,GAE5B3D,EAAI,UAAYQ,EAAM,gBACtBmC,GAAgB3C,EAAK4D,EAAMC,EAAKH,EAAUC,EAAWnD,EAAM,YAAY,EACvER,EAAI,KAAA,EAEJA,EAAI,UAAYQ,EAAM,UACtBR,EAAI,SAASyD,EAAOhT,EAAGC,EAAI,EAAG,EAC9BsP,EAAI,QAAA,CACN,CAEA,SAASgE,GAAWC,EAAuBC,EAAoBC,EAAqC,CAClG,MAAO,CAACjU,GAAM+T,EAAM,CAAC,EAAG,EAAGC,CAAU,EAAGhU,GAAM+T,EAAM,CAAC,EAAG,EAAGE,CAAW,CAAC,CACzE,CAEA,SAASC,GAAQjU,EAAyD,CACxE,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,EAAG,OAAO,KACtD,MAAMM,EAAI,OAAON,EAAM,CAAC,CAAC,EACnBO,EAAI,OAAOP,EAAM,CAAC,CAAC,EACzB,MAAI,CAAC,OAAO,SAASM,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,CAEO,SAAS2T,GAAU,CACxB,KAAA1G,EACA,WAAAuG,EACA,YAAAC,EACA,SAAAhL,EACA,UAAAC,EACA,aAAAkL,EACA,aAAAC,EACA,aAAAC,EACA,WAAAC,EACA,eAAAC,EACA,gBAAAC,EACA,QAAArH,EACA,gBAAAsH,EACA,iBAAAC,EACA,aAAAC,EACA,kBAAAC,EACA,cAAAC,EACA,kBAAAC,EACA,uBAAAC,EACA,wBAAAC,EACA,iBAAAC,EACA,yBAAAC,EACA,wBAAyBC,EACzB,cAAAC,EACA,gBAAAC,GAAkB,KAClB,eAAAC,GAAiB,KACjB,iBAAAC,GACA,gBAAAC,GACA,6BAAAC,GAA+B,GAC/B,4BAAAC,GACA,cAAAC,GACA,UAAAC,GACA,MAAAvF,EACF,EAAuC,CACrC,MAAMwF,EAAYC,EAAAA,OAAiC,IAAI,EACjDC,GAAiBD,EAAAA,OAAO,EAAK,EAC7BE,GAA0BF,EAAAA,OAA4B,IAAI,GAAK,EAC/DG,GAAcH,EAAAA,OAAiBtI,CAAI,EACnC0I,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,GAAShJ,GAAWK,IAAS,SAC7B4I,EAAyBC,EAAAA,QAAsB,IAC/C3B,GAAoBA,EAAiB,OAAS,EACzCA,EAEL,CAACE,GAAqBA,EAAkB,SAAW,EAC9C5J,GAEF4J,EAAkB,IAAI,CAACxU,EAAakW,KAAW,CACpD,GAAIA,EACJ,YAAAlW,CAAA,EACA,EACD,CAACsU,EAAkBE,CAAiB,CAAC,EAClC2B,EAAqBF,EAAAA,QAAsB,IAAM1B,GAAgB3J,GAAe,CAAC2J,CAAY,CAAC,EAC9F6B,EAA2BH,EAAAA,QAAkC,IAAM,CACvE,MAAMhW,EAAgC,CAAA,EACtC,QAASqC,EAAI,EAAGA,EAAI0T,EAAuB,OAAQ1T,GAAK,EAAG,CACzD,MAAM+T,EAASL,EAAuB1T,CAAC,EACjCmG,EAAWiK,GAA4B2D,EAAO,WAAW,EAC3D5N,EAAS,SAAW,GACxBxI,EAAI,KAAK,CACP,OAAAoW,EACA,YAAa/T,EACb,UAAW+T,EAAO,IAAM/T,EACxB,SAAAmG,CAAA,CACD,CACH,CACA,OAAOxI,CACT,EAAG,CAAC+V,CAAsB,CAAC,EACrBM,EAAuBL,EAAAA,QAAkC,IAAM,CACnE,MAAMhW,EAAgC,CAAA,EACtC,QAASqC,EAAI,EAAGA,EAAI6T,EAAmB,OAAQ7T,GAAK,EAAG,CACrD,MAAM+T,EAASF,EAAmB7T,CAAC,EAC7BmG,EAAWiK,GAA4B2D,EAAO,WAAW,EAC3D5N,EAAS,SAAW,GACxBxI,EAAI,KAAK,CACP,OAAAoW,EACA,YAAa/T,EACb,UAAW+T,EAAO,IAAM/T,EACxB,SAAAmG,CAAA,CACD,CACH,CACA,OAAOxI,CACT,EAAG,CAACkW,CAAkB,CAAC,EAEjBI,EAAsBN,EAAAA,QAAQ,IAAMjG,GAAmB0E,CAAiB,EAAG,CAACA,CAAiB,CAAC,EAC9F8B,GAA2BP,UAAQ,IAAM3F,GAAiBiG,EAAqB5B,CAAsB,EAAG,CAAC4B,EAAqB5B,CAAsB,CAAC,EACrJ8B,GAA4BR,UAAQ,IAAM3F,GAAiBiG,EAAqB3B,CAAuB,EAAG,CAAC2B,EAAqB3B,CAAuB,CAAC,EACxJ8B,EAA2BT,EAAAA,QAAQ,IAAM3F,GAAiBhE,GAA4BuI,CAAgB,EAAG,CAACA,CAAgB,CAAC,EAC3H8B,EAA+BV,EAAAA,QAAQ,IAAMlG,GAA4B0E,CAAa,EAAG,CAACA,CAAa,CAAC,EAExGmC,GAAqBX,EAAAA,QAAQ,IAAM/E,GAAwBiE,EAAgB,EAAG,CAACA,EAAgB,CAAC,EAChG0B,GAAiCZ,EAAAA,QAAQ,IAAMjE,GAA8BoD,EAAe,EAAG,CAACA,EAAe,CAAC,EAChH0B,EAAuBb,EAAAA,QAAQ,IAAM1I,GAAoBwG,CAAY,EAAG,CAACA,CAAY,CAAC,EACtFgD,EAAuBd,EAAAA,QAAQ,IAAMpI,GAAoBmG,CAAY,EAAG,CAACA,CAAY,CAAC,EAEtFgD,GAAcf,EAAAA,QAClB,KAAO,CACL,SAAU,WACV,MAAO,EACP,OAAQ,EACR,MAAO,OACP,OAAQ,OACR,QAAS,QACT,YAAa,OACb,cAAeF,GAAS,OAAS,OACjC,OAAQA,GAAU3I,IAAS,QAAU,OAAS,YAAe,UAC7D,GAAG6C,EAAA,GAEL,CAAC8F,GAAQ3I,EAAM6C,EAAK,CAAA,EAGhBgH,GAAeC,EAAAA,YAAY,IAAM,CACrC,MAAM9a,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAEb,MAAMkC,EAAOlC,EAAO,sBAAA,EACdqC,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAC9C0Y,EAAI,KAAK,IAAI,EAAG,KAAK,MAAM7Y,EAAK,MAAQG,CAAG,CAAC,EAC5C2Y,EAAI,KAAK,IAAI,EAAG,KAAK,MAAM9Y,EAAK,OAASG,CAAG,CAAC,GAE/CrC,EAAO,QAAU+a,GAAK/a,EAAO,SAAWgb,KAC1Chb,EAAO,MAAQ+a,EACf/a,EAAO,OAASgb,EAEpB,EAAG,CAAA,CAAE,EAECC,EAAsBH,EAAAA,YACzB3W,GAA+C,CAC9C,MAAM+W,EAAYrD,EAAa,QAC/B,GAAI,CAACqD,GAAa/W,EAAO,SAAW,QAAU,CAAA,EAE9C,MAAMN,EAAM,IAAI,MAAsBM,EAAO,MAAM,EACnD,QAAS+B,EAAI,EAAGA,EAAI/B,EAAO,OAAQ+B,GAAK,EAAG,CACzC,MAAMoR,EAAQG,GAAQyD,EAAU,cAAc/W,EAAO+B,CAAC,EAAE,CAAC,EAAG/B,EAAO+B,CAAC,EAAE,CAAC,CAAC,CAAC,EACzE,GAAI,CAACoR,EAAO,MAAO,CAAA,EACnBzT,EAAIqC,CAAC,EAAIoR,CACX,CACA,OAAOzT,CACT,EACA,CAACgU,CAAY,CAAA,EAGTsD,GAAqBL,EAAAA,YACxBM,GAAkD,CACjD,MAAMF,EAAYrD,EAAa,QACzB7X,EAASqZ,EAAU,QACzB,GAAI,CAAC6B,GAAa,CAAClb,EAAQ,OAAO,KAClC,MAAMkC,EAAOlC,EAAO,sBAAA,EACdqb,EAAM5D,GAAQyD,EAAU,cAAchZ,EAAK,KAAOkZ,EAAO,CAAC,EAAGlZ,EAAK,IAAMkZ,EAAO,CAAC,CAAC,CAAC,EACxF,OAAKC,EACEhE,GAAWgE,EAAK9D,EAAYC,CAAW,EAD7B,IAEnB,EACA,CAACK,EAAcN,EAAYC,CAAW,CAAA,EAGlC8D,GAAyBR,EAAAA,YAAY,IAAM,CAC/C,MAAMI,EAAYrD,EAAa,QACzB0D,EAAcL,GAAW,eAAA,EAAiB,aAAe,EAC/D,GAAI,OAAK,IAAIK,EAAc,GAAG,EAAI,KAAQ,CAACL,GAE3C,MAAO,CACL,cAAe,CAACpX,EAAWC,IACzB0T,GAAQyD,EAAU,cAAcpX,EAAGC,CAAC,CAAC,EACvC,cAAeoX,EAAA,CAEnB,EAAG,CAACtD,EAAcsD,EAAkB,CAAC,EAE/BK,GAAuBV,EAAAA,YAC1BW,GAA6B,CAC5B,GAAI,CAAC,OAAO,SAASA,CAAQ,GAAKA,GAAY,EAAG,MAAO,GAGxD,MAAMC,EAAW,OAAOlP,GAAa,UAAY,OAAO,SAASA,CAAQ,GAAKA,EAAW,EAAIA,EAAW,EAClGmP,EAAiB,OAAOlP,GAAc,UAAY,OAAO,SAASA,CAAS,EAAIA,EAAY,EAC3FmP,EAAc/D,EAAa,SAAS,eAAA,EAAiB,KACrDgE,EAAW,OAAOD,GAAgB,UAAY,OAAO,SAASA,CAAW,GAAKA,EAAc,EAAIA,EAAc,EAC9GE,EAAiBH,EAAiB,KAAK,KAAKE,CAAQ,EACpDE,EAAmB,KAAK,IAAI,KAAMxP,GAAoBmP,EAAUC,EAAgBG,CAAc,CAAC,EAErG,OADqBL,EAAWM,EACVF,CACxB,EACA,CAACrP,EAAUC,EAAWoL,CAAY,CAAA,EAG9BmE,GAAmBlB,EAAAA,YACvB,CAACmB,EAA0B1X,IAAoD,CAC7E,GAAI,CAACA,EAAQ,MAAO,CAAA,EAEpB,IAAIuN,EAAU,EACd,GAAImK,IAAc,yBAA0B,CAC1C,MAAMjK,EAAa0I,EAAqB,mBAAqB,GAC7D,OAAO3I,GAAuBxN,EAAQyN,EAAYsJ,GAAA,CAAwB,EAAE,IAAIlX,GAASiT,GAAWjT,EAAOmT,EAAYC,CAAW,CAAC,CACrI,CAOA,GALIyE,IAAc,mBAAqBA,IAAc,uBACnDnK,EAAUmK,IAAc,uBAAyBtN,GAAmC+L,EAAqB,kBAChGuB,IAAc,gBAAkBA,IAAc,qBAAuBA,IAAc,6BAC5FnK,EAAUmK,IAAc,0BAA4BnN,GAA6BmN,IAAc,oBAAsBrN,GAAgC8L,EAAqB,eAExK,CAAC,OAAO,SAAS5I,CAAO,GAAKA,GAAW,QAAU,CAAA,EAEtD,MAAMoK,EAAUrK,GAASC,CAAO,EAChC,IAAIY,EAA2B,CAAA,EAC/B,GAAIuJ,IAAc,mBAAqBA,IAAc,uBAAwB,CAC3E,MAAMjK,EAAawJ,GAAqB,KAAK,KAAKU,CAAO,EAAI,EAAG,EAChExJ,EAASX,GAAuBxN,EAAQyN,EAAYsJ,GAAA,CAAwB,CAC9E,SAAWW,IAAc,gBAAkBA,IAAc,qBAAuBA,IAAc,0BAA2B,CACvH,MAAMzX,EAASgX,GAAqB,KAAK,KAAKU,EAAU,KAAK,EAAE,CAAC,EAChExJ,EAASD,GAAuBlO,EAAQC,CAAM,CAChD,CAEA,OAAKkO,EAAO,OACLA,EAAO,IAAItO,GAASiT,GAAWjT,EAAOmT,EAAYC,CAAW,CAAC,EAD1C,CAAA,CAE7B,EACA,CAACgE,GAAsBjE,EAAYC,EAAakD,EAAsBY,EAAsB,CAAA,EAGxFa,GAAqBrB,EAAAA,YAAY,IAAwB,CAC7D,MAAMsB,EAAU1C,GAAW,QAC3B,OAAI3I,GAAYC,CAAI,EACXgL,GAAiBhL,EAAMoL,EAAQ,WAAW,EAE/CpL,IAAS,QACJ,CAAA,EAEJoL,EAAQ,UAETpL,IAAS,WACJoL,EAAQ,OAEbpL,IAAS,YACJ2B,GAAgByJ,EAAQ,MAAOA,EAAQ,QAASd,IAAwB,EAE7EtK,IAAS,WACJ8B,GAAasJ,EAAQ,MAAOA,EAAQ,OAAO,EAG7C,CAAA,EAZwB,CAAA,CAajC,EAAG,CAACpL,EAAMgL,GAAkBV,EAAsB,CAAC,EAE7Ce,GAAyBvB,EAAAA,YAC5BzH,GAAwC,CACvC,MAAM+I,EAAU1C,GAAW,QAC3B,GAAI,CAAC0C,EAAQ,WAAaA,EAAQ,aAAa,SAAW,EAAG,OAC7D,MAAME,EAAeF,EAAQ,aAC7B,GAAIE,EAAa,SAAW,EAAG,OAC/B,MAAMC,EAAW5B,EAAqB,OACtC,GAAI,GAAC,OAAO,SAAS4B,CAAQ,GAAKA,GAAY,GAS9C,IAPAlJ,EAAI,KAAA,EACJA,EAAI,YAAcsH,EAAqB,YACvCtH,EAAI,UAAYsH,EAAqB,UACrCtH,EAAI,YAAcsH,EAAqB,UACvCtH,EAAI,QAAU,QACdA,EAAI,SAAW,QACfA,EAAI,UAAYkJ,EAAW,EACvBD,EAAa,SAAW,EAC1BjJ,EAAI,UAAA,EACJA,EAAI,IAAIiJ,EAAa,CAAC,EAAE,CAAC,EAAGA,EAAa,CAAC,EAAE,CAAC,EAAGC,EAAU,EAAG,KAAK,GAAK,CAAC,EACxElJ,EAAI,KAAA,MACC,CACLA,EAAI,UAAA,EACJA,EAAI,OAAOiJ,EAAa,CAAC,EAAE,CAAC,EAAGA,EAAa,CAAC,EAAE,CAAC,CAAC,EACjD,QAASpW,EAAI,EAAGA,EAAIoW,EAAa,OAAQpW,GAAK,EAC5CmN,EAAI,OAAOiJ,EAAapW,CAAC,EAAE,CAAC,EAAGoW,EAAapW,CAAC,EAAE,CAAC,CAAC,EAEnDmN,EAAI,OAAA,CACN,CACAA,EAAI,QAAA,EACN,EACA,CAACsH,CAAoB,CAAA,EAGjB6B,EAAkB1B,EAAAA,YACrBzH,GAAwC,CACvC,MAAM+I,EAAU1C,GAAW,QACrB+C,EAASL,EAAQ,OACvB,GAAI,CAACK,EAAQ,OACb,MAAMrB,EACJgB,EAAQ,cACR3E,GAAQI,EAAa,SAAS,cAAc4E,EAAO,CAAC,EAAGA,EAAO,CAAC,CAAC,GAAK,CAAA,CAAE,EACzE,GAAI,CAACrB,EAAQ,OACb,MAAMmB,EAAW5B,EAAqB,OAClC,CAAC,OAAO,SAAS4B,CAAQ,GAAKA,GAAY,IAE9ClJ,EAAI,KAAA,EACJA,EAAI,UAAA,EACJA,EAAI,IAAI+H,EAAO,CAAC,EAAGA,EAAO,CAAC,EAAGmB,EAAU,EAAG,KAAK,GAAK,CAAC,EACtDlJ,EAAI,YAAc+I,EAAQ,UAAYzB,EAAqB,kBAAoBA,EAAqB,YACpGtH,EAAI,UAAYsH,EAAqB,gBACrCtH,EAAI,YAAYsH,EAAqB,cAAc,EACnDtH,EAAI,OAAA,EACJA,EAAI,YAAY5E,EAAU,EAC1B4E,EAAI,QAAA,EACN,EACA,CAACwE,EAAc8C,CAAoB,CAAA,EAG/B+B,GAAc5B,EAAAA,YAAY,IAAM,CACpCD,GAAA,EAEA,MAAM7a,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAEb,MAAMqT,EAAMrT,EAAO,WAAW,IAAI,EAClC,GAAI,CAACqT,EAAK,OAEV,MAAMhR,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAC9CsU,EAAc3W,EAAO,MAAQqC,EAC7BuU,EAAe5W,EAAO,OAASqC,EAMrC,GALAgR,EAAI,aAAa,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EACjCA,EAAI,UAAU,EAAG,EAAGrT,EAAO,MAAOA,EAAO,MAAM,EAC/CqT,EAAI,aAAahR,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,EAGjC2X,EAAyB,OAAS,EACpC,UAAWjT,KAASiT,EAA0B,CAC5C,KAAM,CAAE,OAAAC,GAAQ,SAAA5N,EAAU,YAAAsQ,EAAa,UAAAC,IAAc7V,EAC/C8V,GAAqCxI,GAAeyE,GAAgB8D,EAAS,EAAI,SAAWvI,GAAewE,GAAiB+D,EAAS,EAAI,QAAU,UACzJ,IAAIpJ,GAAcqJ,KAAU,SAAWxC,GAA4BwC,KAAU,QAAUzC,GAA2BD,EAElH,GAAIzB,EAA0B,CAC5B,MAAMoE,GAAWpE,EAAyB,CACxC,OAAAuB,GACA,SAAU2C,GACV,YAAAD,EACA,MAAAE,EAAA,CACD,EACDrJ,GAAcU,GAAiBV,GAAasJ,IAAY,MAAS,CACnE,CACA,MAAMC,GAAyBF,KAAU,UAAY,KAAO9G,GAAoCvC,EAAW,EAE3G,UAAW3I,MAAWwB,EAAU,CAC9B,MAAM2Q,GAAc/B,EAAoBpQ,GAAQ,KAAK,EACjDmS,GAAY,QAAU,IACpBD,IACFxJ,GAASF,EAAK2J,GAAaD,GAAwB,GAAM,EAAK,EAEhExJ,GAASF,EAAK2J,GAAaxJ,GAAa,GAAM,EAAK,GAErD,UAAWrH,MAAQtB,GAAQ,MAAO,CAChC,MAAMoS,GAAahC,EAAoB9O,EAAI,EACvC8Q,GAAW,QAAU,IACnBF,IACFxJ,GAASF,EAAK4J,GAAYF,GAAwB,GAAM,EAAK,EAE/DxJ,GAASF,EAAK4J,GAAYzJ,GAAa,GAAM,EAAK,EAEtD,CACF,CACF,CAGF,GAAI0G,EAAqB,OAAS,EAChC,UAAWnT,KAASmT,EAClB,UAAWrP,MAAW9D,EAAM,SAAU,CACpC,MAAMiW,EAAc/B,EAAoBpQ,GAAQ,KAAK,EACjDmS,EAAY,QAAU,GACxBzJ,GAASF,EAAK2J,EAAa1C,EAA0B,GAAM,EAAK,EAElE,UAAWnO,KAAQtB,GAAQ,MAAO,CAChC,MAAMoS,GAAahC,EAAoB9O,CAAI,EACvC8Q,GAAW,QAAU,GACvB1J,GAASF,EAAK4J,GAAY3C,EAA0B,GAAM,EAAK,CAEnE,CACF,CAIJ,GAAI,MAAM,QAAQ1B,CAAa,GAAKA,EAAc,OAAS,EAAG,CAC5D,MAAMsE,EAAe,EAAS,WAA0D,6BAClFC,GAAiBlC,EACrBtX,GAAU,CACR,CAAC,EAAG,CAAC,EACL,CAAC4T,EAAY,CAAC,EACd,CAACA,EAAYC,CAAW,EACxB,CAAC,EAAGA,CAAW,CAAA,CAChB,CAAA,EAEH,QAAStR,EAAI,EAAGA,EAAI0S,EAAc,OAAQ1S,GAAK,EAAG,CAChD,MAAMkX,EAAQxE,EAAc1S,CAAC,EAC7B,GAAI,CAACkX,GAAO,aAAa,QAAUA,EAAM,UAAY,GAAO,SAE5D,MAAM7U,GAAS6U,EAAM,QAAU9I,GAAwB8I,EAAM,WAAW,EAClEC,GAAc5I,GAAsB2I,EAAM,YAAa7U,EAAM,EAEnE,GAAI6U,EAAM,cAAc,UAAW,CACjC,MAAMvI,GAAgC,CAAA,EAChCyI,GAAc7I,GAAsB2I,EAAM,YAAa,EAAI,EACjE,UAAW1Y,MAAQ4Y,GAAa,CAC9B,MAAMlC,GAASH,EAAoBvW,EAAI,EACnC0W,GAAO,QAAU,GACnBvG,GAAU,KAAKuG,EAAM,CAEzB,CACA,GAAI8B,EAAc,CAChB,MAAMK,GAAW,OAAOH,EAAM,IAAMlX,CAAC,EAC/BsX,GAAiB,GAAGL,GAAe,MAAM,IAAIG,GAAY,MAAM,IAAIzI,GAAU,MAAM,IAAIuI,EAAM,aAAa,SAAS,GACrH5D,GAAwB,QAAQ,IAAI+D,EAAQ,IAAMC,KACpDhE,GAAwB,QAAQ,IAAI+D,GAAUC,EAAc,EAC5D,QAAQ,MAAM,4BAA6B,CACzC,GAAIJ,EAAM,IAAMlX,EAChB,gBAAiBiX,GAAe,OAChC,gBAAiBG,GAAY,OAC7B,cAAezI,GAAU,OACzB,UAAWuI,EAAM,aAAa,SAAA,CAC/B,EAEL,CACAzI,GAAqBtB,EAAK8J,GAAgBtI,GAAWuI,EAAM,aAAa,SAAS,CACnF,CAEA,GAAIC,GAAY,SAAW,EAAG,SAC9B,MAAM7J,GAAcU,GAAiBiG,EAAqBiD,EAAM,QAAUA,EAAM,WAAW,EAC3F,UAAW1Y,MAAQ2Y,GAAa,CAC9B,MAAMjC,GAASH,EAAoBvW,EAAI,EACnC0W,GAAO,OAAS,GACpB7H,GAASF,EAAK+H,GAAQ5H,GAAajL,GAAQ6U,EAAM,MAAQ,EAAK,CAChE,CACF,CACF,CAEA,MAAMK,EAAUtB,GAAA,EAEhB,GAAIxC,IACF,GAAI3I,IAAS,QACXqL,GAAuBhJ,CAAG,EAC1BmJ,EAAgBnJ,CAAG,UACVoK,EAAQ,OAAS,EAC1B,GAAIzM,IAAS,WAAY,CACvB,MAAM0M,EAAOzC,EAAoBwC,CAAO,EACpCC,EAAK,QAAU,GACjBnK,GAASF,EAAKqK,EAAMvD,EAAqB,GAAO,EAAK,EAEnDuD,EAAK,QAAU,GACjBnK,GAASF,EAAK4H,EAAoBtX,GAAU8Z,CAAO,CAAC,EAAGtD,EAAqB,GAAM,GAAMI,CAA4B,CAExH,KAAO,CACL,MAAM1P,EAAUoQ,EAAoBwC,CAAO,EACvC5S,EAAQ,QAAU,GACpB0I,GAASF,EAAKxI,EAASsP,EAAqB,GAAM,GAAMI,CAA4B,CAExF,EAKJ,GAAIP,EAAyB,OAAS,EAAG,CACvC,MAAMvX,EAAO,KAAK,IAAI,KAAMoV,EAAa,SAAS,eAAA,EAAiB,MAAQ,CAAC,EACtE8F,GACJ,OAAOzE,IAAgC,UAAY,OAAO,SAASA,EAA2B,EAC1F,KAAK,IAAI,EAAGA,EAA2B,EACvCxI,GAAmCuI,GAA8BxW,EAAMoV,EAAa,SAAS,gBAAgB,EACnH,UAAW9Q,KAASiT,EAA0B,CAC5C,GAAI,CAACjT,EAAM,OAAO,MAAO,SACzB,MAAM6W,EAAczH,GAAyBpP,EAAM,QAAQ,EAC3D,GAAI,CAAC6W,EAAa,SAClB,MAAMC,GAAepG,GAAQI,EAAa,SAAS,cAAc+F,EAAY,CAAC,EAAGA,EAAY,CAAC,CAAC,GAAK,CAAA,CAAE,EACtG,GAAI,CAACC,GAAc,SACnB,IAAIC,GAAoB1I,GACtBoF,GACA7B,IAA8B,CAC5B,OAAQ5R,EAAM,OACd,SAAUA,EAAM,UAChB,YAAaA,EAAM,YACnB,KAAAtE,CAAA,CACD,CAAA,EAECkb,GAAsB,IACxBG,GAAoB,CAClB,GAAGA,GACH,QAASA,GAAkB,QAAUH,EAAA,GAGzClH,GAAgBpD,EAAKtM,EAAM,OAAO,MAAO8W,GAAclH,EAAaC,EAAckH,EAAiB,CACrG,CACF,CAEA,GAAIrD,GAA+B,SAAWd,KAAW3I,IAAS,YAAcA,IAAS,aAAeA,IAAS,YAAa,CAC5H,MAAMoL,EAAU1C,GAAW,QAC3B,GAAI0C,EAAQ,UAAW,CACrB,MAAM2B,GAAa/M,IAAS,WAAarN,GAAU8Z,CAAO,EAAIA,EAC9D,GAAIM,GAAW,QAAU,EAAG,CAC1B,MAAMC,EAAS/K,GAAY8K,EAAU,EAC/BpR,EAAM,OAAOH,GAAa,UAAY,OAAO,SAASA,CAAQ,GAAKA,EAAW,EAAIA,EAAW,EAC7FsF,GAAUnF,EAAM,EAAKqR,EAASrR,EAAMA,GAAQ+B,GAAiBA,IAAkB,EACrF,IAAIgI,GAAOf,GAAgC7D,EAAO,EAClD,GAAI,CACF4E,GAAO+D,GAA+B,OAAO3I,EAAO,CACtD,MAAQ,CACN4E,GAAOf,GAAgC7D,EAAO,CAChD,CAEA,MAAM2K,GACJL,EAAQ,eACPA,EAAQ,QAAU3E,GAAQI,EAAa,SAAS,cAAcuE,EAAQ,QAAQ,CAAC,EAAGA,EAAQ,QAAQ,CAAC,CAAC,GAAK,EAAE,EAAI,MAC9GK,IACFtF,GACE9D,EACAqD,GACA+F,GACA9F,EACAC,EACA6D,GAA+B,MAC/BA,GAA+B,cAC/BA,GAA+B,aAAA,CAGrC,CACF,CACF,CACF,EAAG,CACDd,GACA3I,EACAmL,GACAE,GACAG,EACA3B,GACAI,EACA1D,EACAC,EACAK,EACAmC,EACApB,EACAC,GACAC,GACAqB,EACAC,GACAC,GACAE,EACAL,EACAI,EACA5B,EACAC,EACA6B,GACAC,GACAxB,GACAC,GACA1M,CAAA,CACD,EAEKyR,EAAcnD,EAAAA,YAAY,IAAM,CAChCvB,GAAe,UACnBA,GAAe,QAAU,GACzB,sBAAsB,IAAM,CAC1BA,GAAe,QAAU,GACzBmD,GAAA,CACF,CAAC,EACH,EAAG,CAACA,EAAW,CAAC,EAEVwB,GAAepD,EAAAA,YAAY,CAACqD,EAAiB,KAAU,CAC3D,MAAM/B,EAAU1C,GAAW,QACrB1Z,EAASqZ,EAAU,QAEzB,GAAIrZ,GAAUoc,EAAQ,YAAc,MAAQpc,EAAO,kBAAkBoc,EAAQ,SAAS,EACpF,GAAI,CACFpc,EAAO,sBAAsBoc,EAAQ,SAAS,CAChD,MAAQ,CAER,CAGFA,EAAQ,UAAY,GACpBA,EAAQ,UAAY,KACpBA,EAAQ,MAAQ,KAChBA,EAAQ,QAAU,KAClBA,EAAQ,OAAS,CAAA,EACjBA,EAAQ,aAAe,CAAA,EACvBA,EAAQ,YAAc,KACjB+B,IACH/B,EAAQ,OAAS,KACjBA,EAAQ,aAAe,KAE3B,EAAG,CAAA,CAAE,EAECgC,GAAUtD,EAAAA,YACbuD,GAAuE,CACtE,MAAMnD,EAAYrD,EAAa,QAC/B,GAAI,CAACqD,GAAa3D,GAAc,GAAKC,GAAe,EAAG,OAAO,KAE9D,MAAM6D,EAAM5D,GAAQyD,EAAU,cAAcmD,EAAM,QAASA,EAAM,OAAO,CAAC,EACzE,OAAKhD,EACEhE,GAAWgE,EAAK9D,EAAYC,CAAW,EAD7B,IAEnB,EACA,CAACK,EAAcN,EAAYC,CAAW,CAAA,EAGlC8G,GAAgBxD,cAAauD,GAAuE,CACxG,MAAMre,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAAO,KACpB,MAAMkC,EAAOlC,EAAO,sBAAA,EACd8D,EAAIP,GAAM8a,EAAM,QAAUnc,EAAK,KAAM,EAAGA,EAAK,KAAK,EAClD6B,EAAIR,GAAM8a,EAAM,QAAUnc,EAAK,IAAK,EAAGA,EAAK,MAAM,EACxD,MAAI,CAAC,OAAO,SAAS4B,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,EAAG,CAAA,CAAE,EAECwa,GAAgBzD,EAAAA,YAAY,IAAM,CACtC,MAAMsB,EAAU1C,GAAW,QAC3B,GAAI,CAAC0C,EAAQ,UAAW,CACtB8B,GAAa,EAAI,EACjBD,EAAA,EACA,MACF,CAEA,IAAIra,EAAgC,CAAA,EACpC,GAAIoN,IAAS,WACPoL,EAAQ,OAAO,QAAUhO,KAC3BxK,EAAcD,GAAUyY,EAAQ,MAAM,WAE/BpL,IAAS,YAClBpN,EAAc+O,GAAgByJ,EAAQ,MAAOA,EAAQ,QAASd,IAAwB,UAC7EtK,IAAS,WAClBpN,EAAckP,GAAasJ,EAAQ,MAAOA,EAAQ,OAAO,UAChDpL,IAAS,QAAS,CAC3B,MAAMwN,EAAWpC,EAAQ,OAAOA,EAAQ,OAAO,OAAS,CAAC,GAAKA,EAAQ,SAAWA,EAAQ,MACzF,GAAIzB,EAAqB,gBAAkB6D,GAAYpC,EAAQ,OAAO,QAAU,GAAKtE,IAAa0G,CAAQ,EAAG,CAC3GN,GAAa,EAAI,EACjBD,EAAA,EACA,MACF,CACA,MAAMtM,EAAagJ,EAAqB,WAClCtV,EAAgB,KAAK,IACzByK,GACC6K,EAAqB,OAAS,GAAM5K,GAAgC4B,EAAA,EAEjE8M,EACJrC,EAAQ,aAAa,OAAS,EAC1BA,EAAQ,aACRnB,EAAoBmB,EAAQ,MAAM,EAClCsC,EAAgBzU,GAAwBwU,EAAY,CACxD,OAAQ9D,EAAqB,OAC7B,cAAAtV,EACA,YAAa,KAAK,IAAI,GAAI,KAAK,MAAM,GAAKsM,CAAU,CAAC,EACrD,kBAAmBtM,EAAgB,IACnC,gBAAiBsV,EAAqB,aAAA,CACvC,EACKgE,GAAiC,CAAA,EACvC,UAAWva,KAASsa,EAAe,CACjC,MAAMlM,EAAQ2I,GAAmB/W,CAAK,EACjCoO,GACLmM,GAAa,KAAKnM,CAAK,CACzB,CACA5O,EAAcD,GAAUgb,EAAY,CACtC,EAEK3N,IAAS,YAAcA,IAAS,aAAeA,IAAS,YAAcA,IAAS,UAAYmC,GAAevP,CAAW,GAAKmU,GAE7HA,EAAe,CACb,KAAA/G,EACA,OAHyBA,IAAS,QAAU,QAAU,MAItD,YAAApN,EACA,KAAMsP,GAActP,CAAW,EAC/B,OAAQqP,GAAYrP,CAAW,CAAA,CAChC,EAGHsa,GAAa,EAAI,EACjBD,EAAA,CACF,EAAG,CAACjN,EAAM+G,EAAgBmG,GAAcD,EAAahD,EAAqBE,GAAoBG,GAAwBX,EAAqB,OAAQA,EAAqB,WAAYA,EAAqB,cAAeA,EAAqB,eAAgB7C,CAAU,CAAC,EAElQ8G,GAAgB9D,EAAAA,YACpB,CAACmB,EAA0B1X,IAAiC,CAC1D,MAAMX,EAAcoY,GAAiBC,EAAW1X,CAAM,EACtD,GAAI,CAAC4O,GAAevP,CAAW,EAAG,OAClC,MAAMib,EAAqB5C,IAAc,yBAA2B,QAAU,MACxE6C,EAAqB,CACzB,KAAM7C,EACN,OAAA4C,EACA,YAAAjb,EACA,KAAMsP,GAActP,CAAW,EAC/B,OAAQqP,GAAYrP,CAAW,CAAA,EAEjCmU,IAAiB+G,CAAM,EACnBD,IAAW,SAAW7G,GACxBA,EAAgB8G,CAAyB,CAE7C,EACA,CAAC9C,GAAkBjE,EAAgBC,CAAe,CAAA,EAG9C+G,GAAmBjE,EAAAA,YACvB,CAACsB,EAAsB5J,EAAuB4I,IAAiC,CAC7E,MAAM4D,EAAiBhP,GAAoBA,GACrCiP,EAAa7C,EAAQ,aAAaA,EAAQ,aAAa,OAAS,CAAC,EACvE,GAAI,CAAC6C,EAAY,CACf7C,EAAQ,OAAO,KAAK5J,CAAK,EACzB4J,EAAQ,aAAa,KAAKhB,CAAM,EAChCgB,EAAQ,QAAU5J,EAClB,MACF,CACA,MAAM1J,EAAKsS,EAAO,CAAC,EAAI6D,EAAW,CAAC,EAC7BlW,EAAKqS,EAAO,CAAC,EAAI6D,EAAW,CAAC,EAC/BnW,EAAKA,EAAKC,EAAKA,GAAMiW,GACvB5C,EAAQ,OAAO,KAAK5J,CAAK,EACzB4J,EAAQ,aAAa,KAAKhB,CAAM,IAEhCgB,EAAQ,OAAOA,EAAQ,OAAO,OAAS,CAAC,EAAI5J,EAC5C4J,EAAQ,aAAaA,EAAQ,aAAa,OAAS,CAAC,EAAIhB,GAE1DgB,EAAQ,QAAU5J,CACpB,EACA,CAAA,CAAC,EAGG0M,GAAoBpE,EAAAA,YACvBuD,GAAgD,CAG/C,GAFI,CAAC1E,IACD3I,IAAS,UACTqN,EAAM,SAAW,EAAG,OAExB,MAAM7L,EAAQ4L,GAAQC,CAAK,EAC3B,GAAI,CAAC7L,EAAO,OACZ,MAAM4I,EAASkD,GAAcD,CAAK,EAClC,GAAI,CAACjD,EAAQ,OAKb,GAHAiD,EAAM,eAAA,EACNA,EAAM,gBAAA,EAEFtN,GAAYC,CAAI,EAAG,CACrB,MAAMoL,EAAU1C,GAAW,QAC3B0C,EAAQ,YAAc5J,EACtBoM,GAAc5N,EAAMwB,CAAK,EACzByL,EAAA,EACA,MACF,CAEA,MAAMje,EAASqZ,EAAU,QACrBrZ,GACFA,EAAO,kBAAkBqe,EAAM,SAAS,EAG1C,MAAMjC,EAAU1C,GAAW,QAC3B0C,EAAQ,UAAY,GACpBA,EAAQ,UAAYiC,EAAM,UAC1BjC,EAAQ,MAAQ5J,EAChB4J,EAAQ,QAAU5J,EAClB4J,EAAQ,OAAS5J,EACjB4J,EAAQ,aAAehB,EACvBgB,EAAQ,OAASpL,IAAS,YAAcA,IAAS,QAAU,CAACwB,CAAK,EAAI,CAAA,EACrE4J,EAAQ,aAAepL,IAAS,QAAU,CAACoK,CAAM,EAAI,CAAA,EACrD6C,EAAA,CACF,EACA,CAACtE,GAAQ3I,EAAMoN,GAASE,GAAeM,GAAeX,CAAW,CAAA,EAG7DkB,GAAoBrE,EAAAA,YACvBuD,GAAgD,CAE/C,GADI,CAAC1E,IACD3I,IAAS,SAAU,OAEvB,MAAMwB,EAAQ4L,GAAQC,CAAK,EAC3B,GAAI,CAAC7L,EAAO,OACZ,MAAM4I,EAASkD,GAAcD,CAAK,EAClC,GAAI,CAACjD,EAAQ,OAEb,MAAMgB,EAAU1C,GAAW,QAI3B,GAHA0C,EAAQ,OAAS5J,EACjB4J,EAAQ,aAAehB,EAEnBrK,GAAYC,CAAI,EAAG,CACrBoL,EAAQ,YAAc5J,EACtB6L,EAAM,eAAA,EACNA,EAAM,gBAAA,EACNJ,EAAA,EACA,MACF,CAEA,GAAIjN,IAAS,QAAS,CACpB,GAAI,CAACoL,EAAQ,WAAaA,EAAQ,YAAciC,EAAM,UAAW,CAC/DJ,EAAA,EACA,MACF,CACAI,EAAM,eAAA,EACNA,EAAM,gBAAA,EACNU,GAAiB3C,EAAS5J,EAAO4I,CAAM,EACvC6C,EAAA,EACA,MACF,CAEA,GAAI,GAAC7B,EAAQ,WAAaA,EAAQ,YAAciC,EAAM,WAMtD,IAHAA,EAAM,eAAA,EACNA,EAAM,gBAAA,EAEFrN,IAAS,WAAY,CACvB,MAAMkK,EAAYrD,EAAa,QACzBpV,EAAO,KAAK,IAAI,KAAMyY,GAAW,eAAA,EAAiB,MAAQ,CAAC,EAC3DkE,EAAe/Q,GAAuB5L,EACtC4c,GAAgBD,EAAeA,EAC/B/a,EAAO+X,EAAQ,OAAOA,EAAQ,OAAO,OAAS,CAAC,EAErD,GAAI,CAAC/X,EACH+X,EAAQ,OAAO,KAAK5J,CAAK,MACpB,CACL,MAAM1J,EAAK0J,EAAM,CAAC,EAAInO,EAAK,CAAC,EACtB0E,GAAKyJ,EAAM,CAAC,EAAInO,EAAK,CAAC,EACxByE,EAAKA,EAAKC,GAAKA,IAAMsW,IACvBjD,EAAQ,OAAO,KAAK5J,CAAK,CAE7B,CACF,MACE4J,EAAQ,QAAU5J,EAGpByL,EAAA,EACF,EACA,CAACtE,GAAQ3I,EAAMoN,GAASE,GAAeL,EAAapG,EAAckH,EAAgB,CAAA,EAG9EO,GAAkBxE,EAAAA,YACrBuD,GAAgD,CAC/C,MAAMjC,EAAU1C,GAAW,QAC3B,GAAI,CAAC0C,EAAQ,WAAaA,EAAQ,YAAciC,EAAM,UAAW,OAEjEA,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,MAAM7L,EAAQ4L,GAAQC,CAAK,EACrBjD,EAASkD,GAAcD,CAAK,EAC9B7L,IACF4J,EAAQ,OAAS5J,EACb4I,IACFgB,EAAQ,aAAehB,GAErBpK,IAAS,QACPoK,GACF2D,GAAiB3C,EAAS5J,EAAO4I,CAAM,EAGzCgB,EAAQ,QAAU5J,GAGtB,MAAMxS,EAASqZ,EAAU,QACzB,GAAIrZ,GAAUA,EAAO,kBAAkBqe,EAAM,SAAS,EACpD,GAAI,CACFre,EAAO,sBAAsBqe,EAAM,SAAS,CAC9C,MAAQ,CAER,CAGFE,GAAA,CACF,EACA,CAACA,GAAeH,GAASE,GAAetN,EAAM+N,EAAgB,CAAA,EAG1DQ,GAAqBzE,EAAAA,YAAY,IAAM,CAC3C,MAAMsB,EAAU1C,GAAW,QAC3B,IAAI8F,EAAU,GACVxO,IAAS,SAAW,CAACoL,EAAQ,WAAaA,EAAQ,SACpDA,EAAQ,OAAS,KACjBA,EAAQ,aAAe,KACvBoD,EAAU,IAERzO,GAAYC,CAAI,GAAKoL,EAAQ,cAC/BA,EAAQ,YAAc,KACtBoD,EAAU,IAERA,GACFvB,EAAA,CAEJ,EAAG,CAACjN,EAAMiN,CAAW,CAAC,EAEtBwB,OAAAA,EAAAA,UAAU,IAAM,CACd5E,GAAA,EACAoD,EAAA,EAEA,MAAMje,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAEb,MAAM0f,EAAW,IAAI,eAAe,IAAM,CACxC7E,GAAA,EACAoD,EAAA,CACF,CAAC,EACD,OAAAyB,EAAS,QAAQ1f,CAAM,EAEhB,IAAM,CACX0f,EAAS,WAAA,CACX,CACF,EAAG,CAAC7E,GAAcoD,CAAW,CAAC,EAE9BwB,EAAAA,UAAU,IAAM,CACT9F,IACHuE,GAAA,EAEFD,EAAA,CACF,EAAG,CAACtE,GAAQsE,EAAaC,EAAY,CAAC,EAEtCuB,EAAAA,UAAU,IAAM,CACVhG,GAAY,UAAYzI,IAG5ByI,GAAY,QAAUzI,EACtBkN,GAAA,EACAD,EAAA,EACF,EAAG,CAACjN,EAAMkN,GAAcD,CAAW,CAAC,EAEpCwB,EAAAA,UAAU,IAAM,CACdxB,EAAA,CACF,EAAG,CAAChG,EAAiB2B,EAAwBhB,EAAeqF,CAAW,CAAC,EAExEwB,EAAAA,UAAU,IAAM,CACd,GAAKtG,GACL,OAAAA,GAAc,QAAU8E,EACjB,IAAM,CACP9E,GAAc,UAAY8E,IAC5B9E,GAAc,QAAU,KAE5B,CACF,EAAG,CAACA,GAAe8E,CAAW,CAAC,EAE/BwB,EAAAA,UAAU,IAAM,CACd,GAAI,CAAC9F,GAAQ,OAEb,MAAMgG,EAAatB,GAA+B,CAC5CA,EAAM,MAAQ,WAClBH,GAAA,EACAD,EAAA,EACF,EAEA,cAAO,iBAAiB,UAAW0B,CAAS,EACrC,IAAM,CACX,OAAO,oBAAoB,UAAWA,CAAS,CACjD,CACF,EAAG,CAAChG,GAAQuE,GAAcD,CAAW,CAAC,EAGpC2B,GAAAA,IAAC,SAAA,CACC,IAAKvG,EACL,UAAAD,GACA,MAAOwB,GACP,cAAesE,GACf,cAAeC,GACf,YAAaG,GACb,gBAAiBA,GACjB,eAAgBC,GAChB,cAAelB,GAAS,CAClB1E,MAAc,eAAA,CACpB,EACA,QAAS0E,GAAS,CAChB,GAAI,CAAC1E,GAAQ,OACb,MAAM3Z,EAASqZ,EAAU,QACnB6B,EAAYrD,EAAa,QAC/B,GAAI,CAAC7X,GAAU,OAAOkb,GAAW,QAAW,WAAY,OACxDmD,EAAM,eAAA,EACNA,EAAM,gBAAA,EACN,MAAMnc,EAAOlC,EAAO,sBAAA,EACd6f,EAAUxB,EAAM,QAAUnc,EAAK,KAC/B4d,EAAUzB,EAAM,QAAUnc,EAAK,IACrCgZ,EAAU,OAAOmD,EAAM,OAAS,EAAItP,GAAuBC,GAAuB6Q,EAASC,CAAO,EAClG7B,EAAA,CACF,CAAA,CAAA,CAGN,CC/4DA,SAAS8B,GAAkBvc,EAAuB,CAChD,OAAO,OAAOA,GAAS,EAAE,EAAE,QAAQ,OAAQ,EAAE,CAC/C,CAEA,SAASwc,GAAmBxc,EAAuB,CACjD,MAAM6X,EAAM,OAAO7X,GAAS,EAAE,EAC9B,OAAO6X,EAAI,WAAW,GAAG,EAAIA,EAAM,IAAIA,CAAG,EAC5C,CAEA,SAAS4E,GAAgBC,EAA6B,CACpD,MAAM/L,EAAO4L,GAAkBG,CAAW,EAC1C,GAAI,CAAC/L,EAAM,MAAO,GAGlB,GAAI,mBAAmB,KAAKA,CAAI,EAAG,OAAOA,EAE1C,IAAIgM,EAAqB,KACzB,GAAI,CACFA,EAAS,IAAI,IAAIhM,CAAI,CACvB,MAAQ,CACNgM,EAAS,IACX,CAEA,GAAIA,EAAQ,CACV,MAAMC,EAAS,GAAGD,EAAO,QAAQ,KAAKA,EAAO,IAAI,GAC3Cna,EAAO+Z,GAAkBI,EAAO,UAAY,EAAE,EAIpD,MAAI,UAAU,KAAKna,CAAI,EAAU,GAAGoa,CAAM,GAAGpa,CAAI,GAC7C,YAAY,KAAKA,CAAI,EAAU,GAAGoa,CAAM,GAAGpa,CAAI,GAC5C,GAAGoa,CAAM,GAAGpa,CAAI,QACzB,CAGA,MAAI,UAAU,KAAKmO,CAAI,EAAU,OAC7B,YAAY,KAAKA,CAAI,EAAU,GAAGA,CAAI,GACnC,GAAGA,CAAI,QAChB,CAEO,SAASkM,GAAmBhF,EAAU6E,EAAqC,CAChF,MAAMI,EAAMjF,GAAK,SAAW,CAAA,EACtBkF,EAAQ,CAAC,CAAClF,GAAK,QAEfjb,EAAQ,OAAOkgB,EAAI,OAASjF,GAAK,OAAS,CAAC,EAC3Chb,EAAS,OAAOigB,EAAI,QAAUjF,GAAK,QAAU,CAAC,EAC9CmF,EAAW,OAAOF,EAAI,UAAYjF,GAAK,UAAY,CAAC,EACpDoF,EAAc,OAAOH,EAAI,MAAQjF,GAAK,MAAQ,CAAC,EAC/CqF,EAAW,OAAOJ,EAAI,MAAQjF,GAAK,MAAQ,EAAE,EAC7C1O,EAAM,OAAO2T,EAAI,KAAOjF,GAAK,KAAO,CAAC,EAE3C,GAAI,CAACjb,GAAS,CAACC,GAAU,CAACmgB,GAAY,CAACE,EACrC,MAAM,IAAI,MAAM,qDAAqD,EAGvE,MAAMhT,EAAmB,MAAM,QAAQ2N,GAAK,KAAK,EAC7CA,EAAI,MAAM,IAAKxN,IAAe,CAC5B,OAAQ,OAAOA,GAAM,QAAU,EAAE,EACjC,SAAU,OAAOA,GAAM,UAAY,EAAE,EACrC,UAAW,OAAOA,GAAM,WAAa,EAAE,CAAA,EACvC,EACF,CAAA,EAEE8S,EAAiBX,GAAmBU,CAAQ,EAC5CE,EAAcX,GAAgBC,CAAW,EACzCW,EAAiBN,EAAQ,CAACO,EAAchd,EAAWC,IAAsB,GAAG6c,CAAW,GAAGD,CAAc,IAAIG,CAAI,IAAI/c,CAAC,IAAID,CAAC,QAAU,OAE1I,MAAO,CACL,GAAIuX,GAAK,KAAO,UAChB,KAAMA,GAAK,MAAQ,UACnB,MAAAjb,EACA,OAAAC,EACA,IAAK,OAAO,SAASsM,CAAG,GAAKA,EAAM,EAAIA,EAAM,OAC7C,SAAA6T,EACA,YAAa,OAAO,SAASC,CAAW,EAAI,KAAK,IAAI,EAAG,KAAK,MAAMA,CAAW,CAAC,EAAI,EACnF,SAAAC,EACA,YAAAR,EACA,MAAAxS,EACA,eAAAmT,CAAA,CAEJ,CAEO,SAASE,GAAU5hB,EAA6E2hB,EAAchd,EAAWC,EAAmB,CACjJ,GAAI5E,EAAO,eACT,OAAOA,EAAO,eAAe2hB,EAAMhd,EAAGC,CAAC,EAEzC,MAAM4c,EAAiBX,GAAmB7gB,EAAO,QAAQ,EACzD,MAAO,GAAGA,EAAO,WAAW,GAAGwhB,CAAc,IAAIG,CAAI,IAAI/c,CAAC,IAAID,CAAC,OACjE,CC3BA,MAAMkd,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,GACR5N,EACAlP,EACA+c,EACAC,EACO,CACP,MAAMC,EAAMjd,EAAO,OACnB,GAAIid,IAAQ,EAGZ,SAASlb,EAAI,EAAGA,EAAIkb,EAAKlb,GAAK,EAAG,CAChC,MAAMmb,EAAOld,EAAO+B,CAAC,EACfob,EAAKnd,GAAQ+B,EAAI,GAAKkb,CAAG,EACzBG,EAAU,KAAK,MAAMD,EAAG,CAAC,EAAID,EAAK,CAAC,EAAGC,EAAG,CAAC,EAAID,EAAK,CAAC,CAAC,EAC3D,GAAIE,EAAU,KAAM,SAEpB,MAAM/T,EAAI,KAAK,IAAI,EAAG,KAAK,OAAO+T,EAAUJ,IAAWD,EAAUC,EAAO,CAAC,EACnEK,EAAYhU,EAAI0T,GAAW1T,EAAI,GAAK2T,EACpCM,EAAQF,EAAU,KAAK,IAAI,KAAMC,CAAS,EAC1CE,EAAUR,EAAUO,EACpBE,EAASR,EAASM,EAExBpO,EAAI,UAAA,EACJA,EAAI,OAAOgO,EAAK,CAAC,EAAGA,EAAK,CAAC,CAAC,EAC3BhO,EAAI,OAAOiO,EAAG,CAAC,EAAGA,EAAG,CAAC,CAAC,EACvBjO,EAAI,YAAY,CAACqO,EAASC,CAAM,CAAC,EACjCtO,EAAI,eAAiB,EACrBA,EAAI,OAAA,CACL,CAEAA,EAAI,YAAY,EAAE,EAClBA,EAAI,eAAiB,EACtB,CAEA,SAASuO,GACRpe,EACA0N,EACAzN,EAAM,EACG,CACT,OAAI,OAAOD,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU0N,EAC1D,KAAK,IAAIzN,EAAKD,CAAK,CAC3B,CAEA,SAASqe,GAAezc,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,MAAM0c,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,OAAA5iB,EACA,aAAA0Y,EACA,UAAAmK,EAAY,GACZ,QAAAhhB,EACA,cAAAmY,EACA,UAAAC,EACA,MAAAvF,CACD,EAAyC,CACxC,MAAMwF,EAAYC,EAAAA,OAAiC,IAAI,EACjD2I,EAAe3I,EAAAA,OAAiC,IAAI,EACpD4I,EAAgB5I,EAAAA,OAAsB,IAAI,EAC1C6I,EAAc7I,EAAAA,OAAsD,CACzE,OAAQ,GACR,UAAW,IAAA,CACX,EACK8I,EAAS9I,EAAAA,OAAsB,IAAI,EACnCC,EAAiBD,EAAAA,OAAO,EAAK,EAE7BlZ,EAAQwhB,GACb5gB,GAAS,MACTggB,GAA6B,MAC7B,EAAA,EAEK3gB,EAASuhB,GACd5gB,GAAS,OACTggB,GAA6B,OAC7B,EAAA,EAGKqB,EAAcxI,EAAAA,QAAQ,IAAM,CACjC,MAAMyI,EAAO,KAAK,IAAI,EAAGnjB,EAAO,KAAK,EAC/BojB,EAAO,KAAK,IAAI,EAAGpjB,EAAO,MAAM,EAChCqjB,EAAcF,EAAOC,EACrBE,EAAYriB,EAAQC,EAE1B,IAAIqiB,EACAC,GACJ,OAAIH,EAAcC,GACjBC,EAAKtiB,EACLuiB,GAAKviB,EAAQoiB,IAEbG,GAAKtiB,EACLqiB,EAAKriB,EAASmiB,GAGR,CACN,GAAIpiB,EAAQsiB,GAAM,EAClB,GAAIriB,EAASsiB,IAAM,EACnB,EAAGD,EACH,EAAGC,EAAA,CAEL,EAAG,CAACxjB,EAAO,MAAOA,EAAO,OAAQiB,EAAOC,CAAM,CAAC,EACzCuiB,EAAShB,GACd5gB,GAAS,OACTggB,GAA6B,OAC7B,CAAA,EAEKzL,EAAeqM,GACpB5gB,GAAS,aACTggB,GAA6B,aAC7B,CAAA,EAEK6B,EAAcjB,GACnB5gB,GAAS,YACTggB,GAA6B,YAC7B,CAAA,EAEK8B,EAAoB,KAAK,IAC9B,EACA,KAAK,MACJlB,GACC5gB,GAAS,kBACTggB,GAA6B,kBAC7B,CAAA,CACD,CACD,EAGK+B,EACL/hB,GAAS,iBAAmBggB,GAA6B,gBACpDgC,EACLhiB,GAAS,aAAeggB,GAA6B,YAChDiC,EACLjiB,GAAS,qBACTggB,GAA6B,oBACxBkC,EACLliB,GAAS,sBAAwB,UAAYA,GAAS,sBAAwB,OAC3EA,EAAQ,oBACRggB,GAA6B,oBAC3BmC,GACLniB,GAAS,mBACTggB,GAA6B,kBACxBoC,GACLpiB,GAAS,aAAeggB,GAA6B,YAChDqC,GACLriB,GAAS,eAAiBggB,GAA6B,cAClDsC,GACLtiB,GAAS,UAAYggB,GAA6B,SAC7CuC,GAAUviB,GAAS,QACnBwiB,GAAYxiB,GAAS,UACrByiB,GAAmBziB,GAAS,iBAE5B4Z,GAAcf,EAAAA,QAAuB,IAAM,CAChD,MAAM6J,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,MAAAtjB,EACA,OAAAC,EACA,aAAAkV,EACA,SAAU,SACV,OAAQ,EACR,cAAe6N,GAAc,OAAS,OACtC,YAAa,OACb,UAAW,iCACX,GAAGvP,CAAA,CAEL,EAAG,CAAC+O,EAAQU,GAAUljB,EAAOC,EAAQkV,EAAc6N,GAAavP,CAAK,CAAC,EAEhE8P,GAAO7I,EAAAA,YAAY,IAAM,CAC9B,MAAM9a,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAEb,MAAMqT,EAAMrT,EAAO,WAAW,IAAI,EAClC,GAAI,CAACqT,EAAK,OAEV,MAAMuQ,EAAOxjB,EACPyjB,EAAOxjB,EACPgC,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAE9CyhB,GAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOvhB,CAAG,CAAC,EAC3C0hB,GAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOxhB,CAAG,CAAC,GAC7CrC,EAAO,QAAU8jB,IAAU9jB,EAAO,SAAW+jB,MAChD/jB,EAAO,MAAQ8jB,GACf9jB,EAAO,OAAS+jB,IAGjB1Q,EAAI,aAAa,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,EACjCA,EAAI,UAAU,EAAG,EAAGrT,EAAO,MAAOA,EAAO,MAAM,EAC/CqT,EAAI,aAAahR,EAAK,EAAG,EAAGA,EAAK,EAAG,CAAC,EAErCgR,EAAI,UAAY0P,EAChB1P,EAAI,SAAS,EAAG,EAAGuQ,EAAMC,CAAI,EAE7B,KAAM,CAAE,EAAGG,EAAI,EAAGC,EAAI,EAAGvB,GAAI,EAAGC,EAAA,EAAON,EAEjC5E,EAAUwE,EAAa,QACzBxE,GACHpK,EAAI,UAAUoK,EAASuG,EAAIC,EAAIvB,GAAIC,EAAE,EAGtCtP,EAAI,YAAc2P,EAClB3P,EAAI,UAAYwP,EAChBxP,EAAI,WACHwP,EAAc,GACdA,EAAc,GACde,EAAOf,EACPgB,EAAOhB,CAAA,EAGR,MAAM3H,EAAYrD,EAAa,QACzBzS,GAAS8V,GAAW,gBAAA,EACpBgJ,GAAUhJ,GAAW,iBAAA,EACrBiJ,EAAatC,GAAezc,EAAM,EACrCA,GACAyc,GAAeK,EAAc,OAAO,EACnCA,EAAc,QACd,KACJ,GAAI,CAACiC,EAAY,OACjBjC,EAAc,QAAUiC,EAExB,MAAM1jB,GAAKiiB,GAAK,KAAK,IAAI,EAAGvjB,EAAO,KAAK,EAClCuB,GAAKiiB,GAAK,KAAK,IAAI,EAAGxjB,EAAO,MAAM,EAEnCilB,GACL,MAAM,QAAQF,EAAO,GACrBA,GAAQ,QAAU,GAClBA,GAAQ,MACN9f,IACA,MAAM,QAAQA,EAAK,GACnBA,GAAM,QAAU,GAChB,OAAO,SAASA,GAAM,CAAC,CAAC,GACxB,OAAO,SAASA,GAAM,CAAC,CAAC,CAAA,EAEtB8f,GACD,KAEEG,GAASnB,IAAwB,OAEvC,GAAIkB,GAAa,CAChB,MAAM/R,GAAyC+R,GAAY,IACzDhgB,IAAU,CAAC4f,EAAK5f,GAAM,CAAC,EAAI3D,GAAIwjB,EAAK7f,GAAM,CAAC,EAAI1D,EAAE,CAAA,EAGnD2S,EAAI,KAAA,EACJA,EAAI,UAAA,EACJA,EAAI,KAAK2Q,EAAIC,EAAIvB,GAAIC,EAAE,EACvBtP,EAAI,KAAA,EAEJA,EAAI,UAAA,EACJ,QAASnN,GAAI,EAAGA,GAAImM,GAAc,OAAQnM,IAAK,EAC1CA,KAAM,EAAGmN,EAAI,OAAOhB,GAAcnM,EAAC,EAAE,CAAC,EAAGmM,GAAcnM,EAAC,EAAE,CAAC,CAAC,EAC3DmN,EAAI,OAAOhB,GAAcnM,EAAC,EAAE,CAAC,EAAGmM,GAAcnM,EAAC,EAAE,CAAC,CAAC,EAEzDmN,EAAI,UAAA,EACJA,EAAI,UAAY8P,GAChB9P,EAAI,KAAA,EAEJA,EAAI,YAAc4P,EAClB5P,EAAI,UAAY,KACZgR,GACHpD,GAA6B5N,EAAKhB,GAAe,EAAG,CAAC,EAErDgB,EAAI,OAAA,EAGLA,EAAI,QAAA,EACJ,MACD,CAEA,MAAM4D,GAAO1T,GAAMygB,EAAKG,EAAW,CAAC,EAAI1jB,GAAIujB,EAAIA,EAAKtB,EAAE,EACjDxL,GAAM3T,GAAM0gB,EAAKE,EAAW,CAAC,EAAIzjB,GAAIujB,EAAIA,EAAKtB,EAAE,EAChD2B,EAAQ/gB,GAAMygB,EAAKG,EAAW,CAAC,EAAI1jB,GAAIujB,EAAIA,EAAKtB,EAAE,EAClD6B,GAAShhB,GAAM0gB,EAAKE,EAAW,CAAC,EAAIzjB,GAAIujB,EAAIA,EAAKtB,EAAE,EACnD6B,EAAQ,KAAK,IAAI,EAAGF,EAAQrN,EAAI,EAChCwN,GAAQ,KAAK,IAAI,EAAGF,GAASrN,EAAG,EAOtC,GALA7D,EAAI,UAAY8P,GAChB9P,EAAI,SAAS4D,GAAMC,GAAKsN,EAAOC,EAAK,EAEpCpR,EAAI,YAAc4P,EAClB5P,EAAI,UAAY,KACZgR,GAAQ,CACX,MAAMK,GAAuC,CAC5C,CAACzN,GAAO,GAAKC,GAAM,EAAG,EACtB,CAACD,GAAO,GAAM,KAAK,IAAI,EAAGuN,EAAQ,CAAC,EAAGtN,GAAM,EAAG,EAC/C,CAACD,GAAO,GAAM,KAAK,IAAI,EAAGuN,EAAQ,CAAC,EAAGtN,GAAM,GAAM,KAAK,IAAI,EAAGuN,GAAQ,CAAC,CAAC,EACxE,CAACxN,GAAO,GAAKC,GAAM,GAAM,KAAK,IAAI,EAAGuN,GAAQ,CAAC,CAAC,CAAA,EAEhDxD,GAA6B5N,EAAKqR,GAAa,EAAG,CAAC,CACpD,MACCrR,EAAI,WACH4D,GAAO,GACPC,GAAM,GACN,KAAK,IAAI,EAAGsN,EAAQ,CAAC,EACrB,KAAK,IAAI,EAAGC,GAAQ,CAAC,CAAA,CAGxB,EAAG,CACFrkB,EACAC,EACAgiB,EACAU,EACAC,EACAH,EACAhL,EACA1Y,EAAO,MACPA,EAAO,OACPgkB,GACAF,EACAC,CAAA,CACA,EAEKjF,EAAcnD,EAAAA,YAAY,IAAM,CACjCvB,EAAe,UACnBA,EAAe,QAAU,GACzB6I,EAAO,QAAU,sBAAsB,IAAM,CAC5C7I,EAAe,QAAU,GACzB6I,EAAO,QAAU,KACjBuB,GAAA,CACD,CAAC,EACF,EAAG,CAACA,EAAI,CAAC,EAEHgB,GAAoB7J,EAAAA,YACzB,CAAC8J,EAAiBC,IAA6C,CAC9D,MAAM7kB,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAAO,KAEpB,MAAMkC,EAAOlC,EAAO,sBAAA,EACpB,GAAI,CAACkC,EAAK,OAAS,CAACA,EAAK,OAAQ,OAAO,KAExC,MAAM4iB,EAAS5iB,EAAK,MAAQ9B,EACtB2kB,GAAS7iB,EAAK,OAAS7B,EACvB2kB,GAAO3C,EAAY,EAAIyC,EACvBG,EAAO5C,EAAY,EAAI0C,GACvBG,EAAO7C,EAAY,EAAIyC,EACvBK,GAAO9C,EAAY,EAAI0C,GAEvBK,GAAK7hB,IAAOqhB,EAAU1iB,EAAK,KAAO8iB,IAAQE,EAAM,EAAG,CAAC,EACpDG,EAAK9hB,IAAOshB,EAAU3iB,EAAK,IAAM+iB,GAAQE,GAAM,EAAG,CAAC,EACzD,MAAO,CAACC,GAAKjmB,EAAO,MAAOkmB,EAAKlmB,EAAO,MAAM,CAC9C,EACA,CAACA,EAAO,MAAOA,EAAO,OAAQiB,EAAOC,EAAQgiB,CAAW,CAAA,EAGnDiD,GAAaxK,EAAAA,YAClB,CAACyK,EAAgBC,IAAmB,CACnC,MAAMtK,EAAYrD,EAAa,QAC/B,GAAI,CAACqD,EAAW,OAEhB,GAAIA,EAAU,cAAe,CAC5BA,EAAU,cAAcqK,EAAQC,CAAM,EACtCvH,EAAA,EACA,MACD,CAEA,MAAM7Y,EAAS8V,EAAU,gBAAA,EACnBiJ,EAAatC,GAAezc,CAAM,EACrCA,EACAyc,GAAeK,EAAc,OAAO,EACnCA,EAAc,QACd,KACJ,GAAI,CAACiC,EAAY,OAEjB,MAAMsB,GAAW,KAAK,IAAI,KAAMtB,EAAW,CAAC,EAAIA,EAAW,CAAC,CAAC,EACvDuB,GAAW,KAAK,IAAI,KAAMvB,EAAW,CAAC,EAAIA,EAAW,CAAC,CAAC,EAE7DjJ,EAAU,aAAa,CACtB,QAASqK,EAASE,GAAW,GAC7B,QAASD,EAASE,GAAW,EAAA,CAC7B,EACDzH,EAAA,CACD,EACA,CAACpG,EAAcoG,CAAW,CAAA,EAGrBiB,GAAoBpE,EAAAA,YACxBuD,GAAgD,CAEhD,GADI,CAAC+E,IACD/E,EAAM,SAAW,EAAG,OAExB,MAAMre,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EAAQ,OAEb,MAAMwS,EAAQmS,GAAkBtG,EAAM,QAASA,EAAM,OAAO,EACvD7L,IAEL6L,EAAM,eAAA,EACNA,EAAM,gBAAA,EAENre,EAAO,kBAAkBqe,EAAM,SAAS,EACxC8D,EAAY,QAAU,CAAE,OAAQ,GAAM,UAAW9D,EAAM,SAAA,EACvDiH,GAAW9S,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC9B,EACA,CAAC4Q,GAAauB,GAAmBW,EAAU,CAAA,EAGtCnG,GAAoBrE,EAAAA,YACxBuD,GAAgD,CAChD,MAAMsH,EAAOxD,EAAY,QACzB,GAAI,CAACwD,EAAK,QAAUA,EAAK,YAActH,EAAM,UAAW,OAExD,MAAM7L,EAAQmS,GAAkBtG,EAAM,QAASA,EAAM,OAAO,EACvD7L,IAEL6L,EAAM,eAAA,EACNA,EAAM,gBAAA,EACNiH,GAAW9S,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAC9B,EACA,CAACmS,GAAmBW,EAAU,CAAA,EAGzBhG,GAAkBxE,EAAAA,YACtBuD,GAAgD,CAChD,MAAMsH,EAAOxD,EAAY,QACzB,GAAI,CAACwD,EAAK,QAAUA,EAAK,YAActH,EAAM,UAAW,OAExD,MAAMre,EAASqZ,EAAU,QACzB,GAAIrZ,GAAUA,EAAO,kBAAkBqe,EAAM,SAAS,EACrD,GAAI,CACHre,EAAO,sBAAsBqe,EAAM,SAAS,CAC7C,MAAQ,CAER,CAGD8D,EAAY,QAAU,CAAE,OAAQ,GAAO,UAAW,IAAA,EAClDlE,EAAA,CACD,EACA,CAACA,CAAW,CAAA,EAGbwB,OAAAA,EAAAA,UAAU,IAAM,CACf,IAAImG,EAAY,GAChB3D,EAAa,QAAU,KACvBhE,EAAA,EAEA,MAAM6C,EAAO,EACP+E,EAAa,IAAM1mB,EAAO,YAAc2hB,GACxCgF,EAAa,KAAK,KAAK3mB,EAAO,MAAQ0mB,CAAU,EAChDE,EAAc,KAAK,KAAK5mB,EAAO,OAAS0mB,CAAU,EAClDG,GAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAa3mB,EAAO,QAAQ,CAAC,EAC5D8mB,GAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAc5mB,EAAO,QAAQ,CAAC,EAC7D+mB,EAAYF,GAASC,GAE3B,GAAI,CAAC5C,IAAiB6C,EAAYpD,EACjC,OAGD,MAAMrF,EAAU,SAAS,cAAc,QAAQ,EAC/CA,EAAQ,MAAQ,KAAK,IAAI,EAAG,KAAK,MAAM4E,EAAY,CAAC,CAAC,EACrD5E,EAAQ,OAAS,KAAK,IAAI,EAAG,KAAK,MAAM4E,EAAY,CAAC,CAAC,EACtD,MAAMhP,GAAMoK,EAAQ,WAAW,IAAI,EACnC,GAAI,CAACpK,GACJ,OAGDA,GAAI,UAAY0P,EAChB1P,GAAI,SAAS,EAAG,EAAGoK,EAAQ,MAAOA,EAAQ,MAAM,EAEhD,MAAM0I,GAGD,CAAA,EAEL,QAASpiB,EAAI,EAAGA,EAAIkiB,GAAQliB,GAAK,EAChC,QAASD,EAAI,EAAGA,EAAIkiB,GAAQliB,GAAK,EAAG,CACnC,MAAMmT,GAAOnT,EAAI3E,EAAO,SAAW0mB,EAC7B3O,GAAMnT,EAAI5E,EAAO,SAAW0mB,EAC5BvB,EACL,KAAK,KAAKxgB,EAAI,GAAK3E,EAAO,SAAU2mB,CAAU,EAAID,EAC7CtB,GACL,KAAK,KAAKxgB,EAAI,GAAK5E,EAAO,SAAU4mB,CAAW,EAAIF,EACpDM,GAAS,KAAK,CACb,IAAKpF,GAAU5hB,EAAQ2hB,EAAMhd,EAAGC,CAAC,EACjC,OAAQ,CAACkT,GAAMC,GAAKoN,EAAOC,EAAM,CAAA,CACjC,CACF,CAGD,OAAK,QAAQ,WACZ4B,GAAS,IAAI,MAAOxkB,GAAS,CAC5B,MAAMykB,EAAgB,CAAC,CAACpE,EAClBngB,GAAW,MAAM,MAAMF,EAAK,IAAK,CACtC,QAASykB,EAAgB,CAAE,cAAepE,GAAc,MAAA,CACxD,EACD,GAAI,CAACngB,GAAS,GACb,MAAM,IAAI,MAAM,QAAQA,GAAS,MAAM,EAAE,EAE1C,MAAME,GAAS,MAAM,kBAAkB,MAAMF,GAAS,MAAM,EAC5D,MAAO,CAAE,KAAAF,EAAM,OAAAI,EAAA,CAChB,CAAC,CAAA,EACA,KAAMskB,GAAY,CACnB,GAAIT,EAAW,CACd,UAAW9G,MAAUuH,EAChBvH,GAAO,SAAW,aACrBA,GAAO,MAAM,OAAO,MAAA,EAGtB,MACD,CAEA,MAAMre,EAAKgd,EAAQ,MAAQ,KAAK,IAAI,EAAGte,EAAO,KAAK,EAC7CuB,GAAK+c,EAAQ,OAAS,KAAK,IAAI,EAAGte,EAAO,MAAM,EACrD,UAAW2f,MAAUuH,EAAS,CAC7B,GAAIvH,GAAO,SAAW,YAAa,SACnC,KAAM,CACL,KAAM,CAAE,OAAA1Z,CAAA,EACR,OAAArD,EAAA,EACG+c,GAAO,MACLhW,GAAK1D,EAAO,CAAC,EAAI3E,EACjBsI,GAAK3D,EAAO,CAAC,EAAI1E,GACjB4lB,GAAK,KAAK,IAAI,GAAIlhB,EAAO,CAAC,EAAIA,EAAO,CAAC,GAAK3E,CAAE,EAC7C8lB,GAAK,KAAK,IAAI,GAAInhB,EAAO,CAAC,EAAIA,EAAO,CAAC,GAAK1E,EAAE,EACnD2S,GAAI,UAAUtR,GAAQ+G,GAAIC,GAAIud,GAAIC,EAAE,EACpCxkB,GAAO,MAAA,CACR,CAEAkgB,EAAa,QAAUxE,EACvBQ,EAAA,CACD,CAAC,EAEM,IAAM,CACZ2H,EAAY,EACb,CACD,EAAG,CACFzmB,EACA6iB,EACAK,EACAU,EACAM,GACAP,EACA7E,CAAA,CACA,EAEDwB,EAAAA,UAAU,IAAM,CACfxB,EAAA,CACD,EAAG,CAACA,CAAW,CAAC,EAEhBwB,EAAAA,UAAU,IAAM,CACf,GAAKtG,EACL,OAAAA,EAAc,QAAU8E,EACjB,IAAM,CACR9E,EAAc,UAAY8E,IAC7B9E,EAAc,QAAU,KAE1B,CACD,EAAG,CAACA,EAAe8E,CAAW,CAAC,EAE/BwB,EAAAA,UACC,IAAM,IAAM,CACX0C,EAAY,QAAU,CAAE,OAAQ,GAAO,UAAW,IAAA,EAC9CC,EAAO,UAAY,OACtB,qBAAqBA,EAAO,OAAO,EACnCA,EAAO,QAAU,MAElB7I,EAAe,QAAU,EAC1B,EACA,CAAA,CAAC,EAIDiN,GAAAA,KAAC,MAAA,CAAI,UAAApN,EAAsB,MAAOwB,GACjC,SAAA,CAAAgF,GAAAA,IAAC,SAAA,CACA,IAAKvG,EACL,MAAO,CACN,MAAO,OACP,OAAQ,OACR,QAAS,QACT,aAAc,SAAA,EAEf,cAAe6F,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,EAEAkF,IACA3D,GAAAA,IAAC,SAAA,CACA,KAAK,SACL,aAAW,oBACX,QAAUvB,GAAU,CACnBA,EAAM,gBAAA,EACNkF,GAAA,CACD,EACA,MAAOE,GACJ,CAAC,GAAGA,IACJ,CAAE,GAAG3B,EAAA,EAGP,SAAA0B,IAAa,GAAA,CAAA,CACf,EAEF,CAEF,CCzrBO,SAASiD,GAAiB,CAChC,WAAAlP,EACA,YAAAC,EACA,MAAAhW,EACA,UAAAI,EACA,UAAAwX,EACA,MAAAvF,CACD,EAA8C,CAC7C,MAAMwF,EAAYC,EAAAA,OAAiC,IAAI,EACjDoN,EAAcpN,EAAAA,OAA8B,IAAI,EAChDsB,EAAcf,EAAAA,QACnB,KAAO,CAAE,MAAO,OAAQ,OAAQ,OAAQ,QAAS,QAAS,GAAGhG,IAC7D,CAACA,CAAK,CAAA,EAGP4L,OAAAA,EAAAA,UAAU,IAAM,CACf,MAAMzf,EAASqZ,EAAU,QACzB,GAAI,CAACrZ,EACJ,OAGD,MAAM2mB,EAAW,IAAI5lB,GAAe,CACnC,OAAAf,EACA,WAAAuX,EACA,YAAAC,EACA,iBAAkB5V,CAAA,CAClB,EAED,OAAA8kB,EAAY,QAAUC,EACjBA,EAAS,SAASnlB,CAAK,EAErB,IAAM,CACZmlB,EAAS,QAAA,EACTD,EAAY,QAAU,IACvB,CACD,EAAG,CAACnP,EAAYC,CAAW,CAAC,EAE5BiI,EAAAA,UAAU,IAAM,CACf,MAAMkH,EAAWD,EAAY,QACxBC,GAIAA,EAAS,SAASnlB,CAAK,CAC7B,EAAG,CAACA,CAAK,CAAC,EAEVie,EAAAA,UAAU,IAAM,CACf,MAAMkH,EAAWD,EAAY,QACzB,CAACC,GAAY,CAAC/kB,GAIlB+kB,EAAS,aAAa/kB,CAAS,CAChC,EAAG,CAACA,CAAS,CAAC,SAEN,SAAA,CAAO,IAAKyX,EAAW,UAAAD,EAAsB,MAAOwB,EAAa,CAC1E,CC3DA,SAASgM,GAAmBC,EAAiC,CAC5D,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,GACfF,EACAxa,EACsB,CACtB,GAAI,CAACwa,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACxE,OAAO,KAGR,MAAM9a,EAAWF,GAAmBQ,GAAY,EAAE,EAClD,GAAIN,EAAS,SAAW,EAAG,CAC1B,MAAMib,EAAsB,CAC3B,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAElC,OAAIH,EAAU,qBAAqB,aAClCG,EAAM,UAAY,IAAI,WAAW,CAAC,GAE/BH,EAAU,eAAe,cAC5BG,EAAM,IAAM,IAAI,YAAY,CAAC,GAEvBA,CACR,CAEA,MAAMC,EAAQL,GAAmBC,CAAS,EACpCK,EAAYL,EAAU,UACtBnZ,EAAQmZ,EAAU,eAClBM,EACLN,EAAU,qBAAqB,YAAcA,EAAU,UAAU,QAAUI,EACxEJ,EAAU,UACV,KACEO,EACLP,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUI,EAC7DJ,EAAU,IACV,KAEEQ,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,IAAIxK,EAAS,EAEb,QAASvW,EAAI,EAAGA,EAAI+gB,EAAO/gB,GAAK,EAAG,CAClC,MAAMpC,EAAIojB,EAAUhhB,EAAI,CAAC,EACnBnC,EAAImjB,EAAUhhB,EAAI,EAAI,CAAC,EACxBkG,GAA0BtI,EAAGC,EAAGgI,CAAQ,IAC7Csb,EAAc5K,EAAS,CAAC,EAAI3Y,EAC5BujB,EAAc5K,EAAS,EAAI,CAAC,EAAI1Y,EAChCujB,EAAU7K,CAAM,EAAI/O,EAAMxH,CAAC,EACvBqhB,IACHA,EAAc9K,CAAM,EAAI0K,EAAWjhB,CAAC,GAEjCshB,IACHA,EAAQ/K,CAAM,EAAI2K,EAAUlhB,CAAC,GAE9BuW,GAAU,EACX,CAEA,MAAMgL,EAAuB,CAC5B,MAAOhL,EACP,UAAW4K,EAAc,SAAS,EAAG5K,EAAS,CAAC,EAC/C,eAAgB6K,EAAU,SAAS,EAAG7K,CAAM,CAAA,EAE7C,OAAI8K,IACHE,EAAO,UAAYF,EAAc,SAAS,EAAG9K,CAAM,GAEhD+K,IACHC,EAAO,IAAMD,EAAQ,SAAS,EAAG/K,CAAM,GAEjCgL,CACR,CAEO,SAASC,GACfb,EACAxa,EACc,CACd,GAAI,CAACwa,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACxE,OAAO,IAAI,YAAY,CAAC,EAGzB,MAAM9a,EAAWF,GAAmBQ,GAAY,EAAE,EAClD,GAAIN,EAAS,SAAW,EACvB,OAAO,IAAI,YAAY,CAAC,EAGzB,MAAMkb,EAAQL,GAAmBC,CAAS,EAC1C,GAAII,IAAU,EACb,OAAO,IAAI,YAAY,CAAC,EAGzB,MAAMC,EAAYL,EAAU,UACtBhjB,EAAM,IAAI,YAAYojB,CAAK,EACjC,IAAIxK,EAAS,EAEb,QAASvW,EAAI,EAAGA,EAAI+gB,EAAO/gB,GAAK,EAAG,CAClC,MAAMpC,EAAIojB,EAAUhhB,EAAI,CAAC,EACnBnC,EAAImjB,EAAUhhB,EAAI,EAAI,CAAC,EACxBkG,GAA0BtI,EAAGC,EAAGgI,CAAQ,IAC7ClI,EAAI4Y,CAAM,EAAIvW,EACduW,GAAU,EACX,CAEA,OAAO5Y,EAAI,SAAS,EAAG4Y,CAAM,CAC9B,CCpCA,IAAIkL,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,MAAMpgB,EAAYogB,EAClB,OAAI,OAAOpgB,EAAU,gBAAmB,WAAmB,KACpDA,CACR,CAEA,MAAMqgB,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,GAAMvlB,EAAekC,EAAsB,CACnD,OAAO,KAAK,KAAKlC,EAAQkC,CAAI,EAAIA,CAClC,CAEA,eAAsBsjB,GACrB9B,EACA+B,EACA7jB,EAC8B,CAC9B,MAAMiO,EAAM,MAAMsV,GAAA,EAClB,GAAI,CAACtV,EAAK,OAAO,KAEjB,MAAM4T,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMgC,CAAU,CAAC,EAC1CC,EAAc,KAAK,IAAI,EAAG,KAAK,MAAM9jB,EAAO,OAAS,CAAC,CAAC,EAC7D,GAAI6hB,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,OAAOlW,EAAI,OAAO,OAAO,2BAA2B,EAClE,GAAI+V,EAAgBG,GAASF,EAAcE,GAASD,EAAcC,EACjE,OAAO,KAGR,MAAMC,EAAkBnW,EAAI,OAAO,aAAa,CAC/C,KAAM0V,GAAMK,EAAe,CAAC,EAC5B,MAAOlB,GAA2BC,EAAA,CAClC,EACKsB,EAAepW,EAAI,OAAO,aAAa,CAC5C,KAAM0V,GAAMM,EAAa,CAAC,EAC1B,MAAOnB,GAA2BC,EAAA,CAClC,EACKuB,EAAerW,EAAI,OAAO,aAAa,CAC5C,KAAM0V,GAAMO,EAAa,CAAC,EAC1B,MAAOpB,GAA2BE,EAAA,CAClC,EACKuB,EAAgBtW,EAAI,OAAO,aAAa,CAC7C,KAAM,GACN,MAAOgV,GAA2BF,EAAA,CAClC,EACKyB,EAAavW,EAAI,OAAO,aAAa,CAC1C,KAAM0V,GAAMO,EAAa,CAAC,EAC1B,MAAOnB,GAA4BG,EAAA,CACnC,EAEDjV,EAAI,OAAO,MAAM,YAChBmW,EACA,EACAtC,EAAU,OACVA,EAAU,WACVkC,CAAA,EAED/V,EAAI,OAAO,MAAM,YAChBoW,EACA,EACArkB,EAAO,OACPA,EAAO,WACPikB,CAAA,EAEDhW,EAAI,OAAO,MAAM,YAChBsW,EACA,EACA,IAAI,YAAY,CAACR,EAAgBD,EAAa,EAAG,CAAC,CAAC,CAAA,EAGpD,MAAMW,EAAYxW,EAAI,OAAO,gBAAgB,CAC5C,OAAQA,EAAI,gBACZ,QAAS,CACR,CAAE,QAAS,EAAG,SAAU,CAAE,OAAQmW,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,EAAiBzW,EAAI,OAAO,qBAAA,EAC5BtJ,EAAO+f,EAAe,iBAAA,EAC5B/f,EAAK,YAAYsJ,EAAI,QAAQ,EAC7BtJ,EAAK,aAAa,EAAG8f,CAAS,EAC9B9f,EAAK,mBAAmB,KAAK,KAAKof,EAAiB,GAAG,CAAC,EACvDpf,EAAK,IAAA,EAEL+f,EAAe,mBAAmBJ,EAAc,EAAGE,EAAY,EAAGN,CAAW,EAC7EjW,EAAI,OAAO,MAAM,OAAO,CAACyW,EAAe,OAAA,CAAQ,CAAC,EAEjD,MAAMF,EAAW,SAASrB,EAAiB,EAC3C,MAAMwB,EAASH,EAAW,eAAA,EACpB/lB,EAAM,IAAI,YAAYkmB,EAAO,MAAM,CAAC,CAAC,EAC3C,OAAAH,EAAW,MAAA,EAEXJ,EAAgB,QAAA,EAChBC,EAAa,QAAA,EACbC,EAAa,QAAA,EACbC,EAAc,QAAA,EACdC,EAAW,QAAA,EAEJ/lB,CACR,CClUA,SAASmmB,IAAgB,CACvB,OAAI,OAAO,YAAgB,KAAe,OAAO,YAAY,KAAQ,WAC5D,YAAY,IAAA,EAEd,KAAK,IAAA,CACd,CAEA,eAAsBC,GACpBpD,EACAxa,EACArL,EAAkC,CAAA,EACF,CAChC,MAAMqI,EAAQ2gB,GAAA,EACRE,EAAelpB,EAAQ,eAAiB,GAC9C,GAAI,CAAC6lB,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,MAAO,CACL,KAAM,KACN,KAAM,CACJ,KAAM,gBACN,WAAYmD,KAAU3gB,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,EAIJ,MAAM0C,EAAWF,GAAmBQ,GAAY,EAAE,EAClD,GAAIN,EAAS,SAAW,EAAG,CACzB,MAAMoe,EAAqB,CACzB,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAEnC,OAAItD,EAAU,qBAAqB,aACjCsD,EAAK,UAAY,IAAI,WAAW,CAAC,GAE/BtD,EAAU,eAAe,cAC3BsD,EAAK,IAAM,IAAI,YAAY,CAAC,GAEvB,CACL,KAAAA,EACA,KAAM,CACJ,KAAM,gBACN,WAAYH,KAAU3gB,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMyd,EACJD,EAAU,qBAAqB,WAAaA,EAAU,UAAU,OAAS,OAAO,iBAC5EuD,EAAY,KAAK,IAAI,EAAG,KAAK,IAAIvD,EAAU,MAAO,KAAK,MAAMA,EAAU,UAAU,OAAS,CAAC,EAAGA,EAAU,eAAe,OAAQC,CAAe,CAAC,EAC/IuD,EAAiBxD,EAAU,qBAAqB,YAAcA,EAAU,UAAU,QAAUuD,EAAYvD,EAAU,UAAY,KAC9HO,EAAWP,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUuD,EAAYvD,EAAU,IAAM,KAC7G,GAAIuD,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/B/C,IACF+C,EAAK,IAAM,IAAI,YAAY,CAAC,GAEvB,CACL,KAAAA,EACA,KAAM,CACJ,KAAM,gBACN,WAAYH,KAAU3gB,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMihB,EAAW,IAAI,aAAave,EAAS,OAAS,CAAC,EACrD,QAAS7F,EAAI,EAAGA,EAAI6F,EAAS,OAAQ7F,GAAK,EAAG,CAC3C,MAAMiO,EAAOjO,EAAI,EACX2E,EAAUkB,EAAS7F,CAAC,EAC1BokB,EAASnW,CAAI,EAAItJ,EAAQ,KACzByf,EAASnW,EAAO,CAAC,EAAItJ,EAAQ,KAC7Byf,EAASnW,EAAO,CAAC,EAAItJ,EAAQ,KAC7Byf,EAASnW,EAAO,CAAC,EAAItJ,EAAQ,IAC/B,CAEA,IAAI0f,EAAoC,KACpCC,EAAa,GACjB,GAAI,CACFD,EAAgB,MAAMvB,GAA8BnC,EAAU,UAAWuD,EAAWE,CAAQ,EAC5FE,EAAa,CAAC,CAACD,CACjB,MAAQ,CACNA,EAAgB,KAChBC,EAAa,EACf,CAEA,GAAI,CAACD,EAEH,MAAO,CACL,KAFexD,GAA0BF,EAAWxa,CAAQ,EAG5D,KAAM,CACJ,KAAM,gBACN,WAAY2d,KAAU3gB,EACtB,WAAY,GACZ,eAAgB+gB,EAChB,cAAe,EAAA,CACjB,EAIJ,IAAIK,EAAiB,EACrB,QAASvkB,EAAI,EAAGA,EAAIkkB,EAAWlkB,GAAK,EAC9BqkB,EAAcrkB,CAAC,IAAM,IAAGukB,GAAkB,GAGhD,MAAMC,EAAmB,IAAI,YAAYD,CAAc,EACvD,GAAIA,EAAiB,EAAG,CACtB,IAAIE,EAAkB,EACtB,QAASzkB,EAAI,EAAGA,EAAIkkB,EAAWlkB,GAAK,EAC9BqkB,EAAcrkB,CAAC,IAAM,IACzBwkB,EAAiBC,CAAe,EAAIzkB,EACpCykB,GAAmB,EAEvB,CAEA,GAAIF,IAAmB,EAAG,CACxB,GAAIP,EAAc,CAChB,MAAMC,EAAqB,CACzB,MAAOC,EACP,UAAWvD,EAAU,UAAU,SAAS,EAAGuD,EAAY,CAAC,EACxD,eAAgBvD,EAAU,eAAe,SAAS,EAAGuD,CAAS,EAC9D,YAAa,IAAI,YAAY,CAAC,CAAA,EAEhC,OAAIC,IACFF,EAAK,UAAYE,EAAe,SAAS,EAAGD,CAAS,GAEnDhD,IACF+C,EAAK,IAAM/C,EAAS,SAAS,EAAGgD,CAAS,GAEpC,CACL,KAAAD,EACA,KAAM,CACJ,KAAM,gBACN,WAAYH,KAAU3gB,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAM8gB,EAAqB,CACzB,MAAO,EACP,UAAW,IAAI,aAAa,CAAC,EAC7B,eAAgB,IAAI,YAAY,CAAC,CAAA,EAEnC,OAAIE,IACFF,EAAK,UAAY,IAAI,WAAW,CAAC,GAE/B/C,IACF+C,EAAK,IAAM,IAAI,YAAY,CAAC,GAEvB,CACL,KAAAA,EACA,KAAM,CACJ,KAAM,gBACN,WAAYH,KAAU3gB,EACtB,WAAY,GACZ,eAAgB,EAChB,cAAe,EAAA,CACjB,CAEJ,CAEA,GAAI6gB,EAAc,CAChB,MAAMU,EAAc,IAAI,YAAYH,CAAc,EAClD,IAAII,EAAe,EAEnB,QAAS3kB,GAAI,EAAGA,GAAIukB,EAAgBvkB,IAAK,EAAG,CAC1C,MAAM4kB,GAAaJ,EAAiBxkB,EAAC,GAAK,EACpCpC,GAAI+iB,EAAU,UAAUiE,GAAa,CAAC,EACtC/mB,GAAI8iB,EAAU,UAAUiE,GAAa,EAAI,CAAC,EAC3C1e,GAA0BtI,GAAGC,GAAGgI,CAAQ,IAC7C6e,EAAYC,CAAY,EAAIC,GAC5BD,GAAgB,EAClB,CAEA,MAAMV,EAAqB,CACzB,MAAOC,EACP,UAAWvD,EAAU,UAAU,SAAS,EAAGuD,EAAY,CAAC,EACxD,eAAgBvD,EAAU,eAAe,SAAS,EAAGuD,CAAS,EAC9D,YAAaQ,EAAY,SAAS,EAAGC,CAAY,CAAA,EAEnD,OAAIR,IACFF,EAAK,UAAYE,EAAe,SAAS,EAAGD,CAAS,GAEnDhD,IACF+C,EAAK,IAAM/C,EAAS,SAAS,EAAGgD,CAAS,GAGpC,CACL,KAAAD,EACA,KAAM,CACJ,KAAM,gBACN,WAAYH,KAAU3gB,EACtB,WAAY,GACZ,eAAAohB,EACA,cAAe,EAAA,CACjB,CAEJ,CAEA,MAAMpD,EAAgB,IAAI,aAAaoD,EAAiB,CAAC,EACnDnD,EAAY,IAAI,YAAYmD,CAAc,EAC1ClD,EAAgB8C,EAAiB,IAAI,WAAWI,CAAc,EAAI,KAClEjD,EAAUJ,EAAW,IAAI,YAAYqD,CAAc,EAAI,KAC7D,IAAIhO,EAAS,EAEb,QAASvW,EAAI,EAAGA,EAAIukB,EAAgBvkB,GAAK,EAAG,CAC1C,MAAM4kB,EAAaJ,EAAiBxkB,CAAC,GAAK,EACpCpC,EAAI+iB,EAAU,UAAUiE,EAAa,CAAC,EACtC/mB,GAAI8iB,EAAU,UAAUiE,EAAa,EAAI,CAAC,EAC3C1e,GAA0BtI,EAAGC,GAAGgI,CAAQ,IAC7Csb,EAAc5K,EAAS,CAAC,EAAI3Y,EAC5BujB,EAAc5K,EAAS,EAAI,CAAC,EAAI1Y,GAChCujB,EAAU7K,CAAM,EAAIoK,EAAU,eAAeiE,CAAU,EACnDvD,IACFA,EAAc9K,CAAM,EAAI4N,EAAgBS,CAAU,GAEhDtD,IACFA,EAAQ/K,CAAM,EAAI2K,EAAU0D,CAAU,GAExCrO,GAAU,EACZ,CAEA,MAAMsO,EAA4B,CAChC,MAAOtO,EACP,UAAW4K,EAAc,SAAS,EAAG5K,EAAS,CAAC,EAC/C,eAAgB6K,EAAU,SAAS,EAAG7K,CAAM,CAAA,EAE9C,OAAI8K,IACFwD,EAAY,UAAYxD,EAAc,SAAS,EAAG9K,CAAM,GAEtD+K,IACFuD,EAAY,IAAMvD,EAAQ,SAAS,EAAG/K,CAAM,GAGvC,CACL,KAAMsO,EACN,KAAM,CACJ,KAAM,gBACN,WAAYf,KAAU3gB,EACtB,WAAY,GACZ,eAAAohB,EACA,cAAe,EAAA,CACjB,CAEJ,CCxPA,IAAIO,GAAgC,KAChCC,GAAkB,GAClBC,GAAY,EAChB,MAAMC,OAAkB,IAExB,SAASnB,IAAgB,CACvB,OAAI,OAAO,YAAgB,KAAe,OAAO,YAAY,KAAQ,WAC5D,YAAY,IAAA,EAEd,KAAK,IAAA,CACd,CAEA,SAASoB,IAA8B,CACrC,GAAI,CAACH,GAAiB,OAAO,KAC7B,GAAID,GAAgB,OAAOA,GAC3B,GAAI,CACF,MAAMK,EAAS,IAAI,OAAO,IAAA,IAAA,6RAAA,OAAA,SAAA,IAAA,QAAA,KAAA,EAAA,cAAA,UAAA,EAAA,KAAAC,IAAAA,GAAA,QAAA,YAAA,IAAA,UAAAA,GAAA,KAAA,IAAA,IAAA,YAAA,SAAA,OAAA,EAAA,IAAA,EAA2D,CAAE,KAAM,SAAU,EACvG,OAAAD,EAAO,iBAAiB,UAAWE,EAAmB,EACtDF,EAAO,iBAAiB,QAASG,EAAiB,EAClDR,GAAiBK,EACVA,CACT,MAAQ,CACN,OAAAJ,GAAkB,GACX,IACT,CACF,CAEA,SAASM,GAAoBlN,EAAkD,CAC7E,MAAMoN,EAAMpN,EAAM,KAClB,GAAI,CAACoN,EAAK,OACV,MAAMC,EAAUP,GAAY,IAAIM,EAAI,EAAE,EACtC,GAAI,CAACC,EAAS,OAGd,GAFAP,GAAY,OAAOM,EAAI,EAAE,EAErBA,EAAI,OAAS,mBAAoB,CACnCC,EAAQ,OAAO,IAAI,MAAMD,EAAI,OAAS,oBAAoB,CAAC,EAC3D,MACF,CAEA,GAAIA,EAAI,OAAS,yBAA0B,CACzC,GAAIC,EAAQ,OAAS,QAAS,CAC5BA,EAAQ,OAAO,IAAI,MAAM,sDAAsD,CAAC,EAChF,MACF,CACA,MAAMzE,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMwE,EAAI,KAAK,CAAC,EACzCE,EAAU,IAAI,YAAYF,EAAI,OAAO,EAAE,SAAS,EAAGxE,CAAK,EAC9DyE,EAAQ,QAAQ,CACd,QAAAC,EACA,KAAM,CACJ,KAAM,SACN,WAAY,OAAO,SAASF,EAAI,UAAU,EAAIA,EAAI,WAAazB,GAAA,EAAU0B,EAAQ,OAAA,CACnF,CACD,EACD,MACF,CAEA,GAAIA,EAAQ,OAAS,OAAQ,CAC3BA,EAAQ,OAAO,IAAI,MAAM,iDAAiD,CAAC,EAC3E,MACF,CAEA,MAAMzE,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAMwE,EAAI,KAAK,CAAC,EACzCvE,EAAY,IAAI,aAAauE,EAAI,SAAS,EAC1CG,EAAiB,IAAI,YAAYH,EAAI,cAAc,EACnDtE,EAAYsE,EAAI,UAAY,IAAI,WAAWA,EAAI,SAAS,EAAI,KAC5DI,EAAMJ,EAAI,IAAM,IAAI,YAAYA,EAAI,GAAG,EAAI,KAC3ChE,EAAuB,CAC3B,MAAAR,EACA,UAAWC,EAAU,SAAS,EAAGD,EAAQ,CAAC,EAC1C,eAAgB2E,EAAe,SAAS,EAAG3E,CAAK,CAAA,EAE9CE,IACFM,EAAO,UAAYN,EAAU,SAAS,EAAGF,CAAK,GAE5C4E,IACFpE,EAAO,IAAMoE,EAAI,SAAS,EAAG5E,CAAK,GAGpCyE,EAAQ,QAAQ,CACd,KAAMjE,EACN,KAAM,CACJ,KAAM,SACN,WAAY,OAAO,SAASgE,EAAI,UAAU,EAAIA,EAAI,WAAazB,GAAA,EAAU0B,EAAQ,OAAA,CACnF,CACD,CACH,CAEA,SAASF,IAA0B,CACjCP,GAAkB,GACdD,KACFA,GAAe,oBAAoB,UAAWO,EAAmB,EACjEP,GAAe,oBAAoB,QAASQ,EAAiB,EAC7DR,GAAe,UAAA,EACfA,GAAiB,MAEnB,SAAW,CAAA,CAAGU,CAAO,IAAKP,GACxBO,EAAQ,OAAO,IAAI,MAAM,gBAAgB,CAAC,EAE5CP,GAAY,MAAA,CACd,CAEO,SAASW,IAA+B,CAC7C,GAAKd,GACL,CAAAA,GAAe,oBAAoB,UAAWO,EAAmB,EACjEP,GAAe,oBAAoB,QAASQ,EAAiB,EAC7DR,GAAe,UAAA,EACfA,GAAiB,KACjB,SAAW,CAAA,CAAGU,CAAO,IAAKP,GACxBO,EAAQ,OAAO,IAAI,MAAM,mBAAmB,CAAC,EAE/CP,GAAY,MAAA,EACd,CAEA,eAAsBY,GAAkClF,EAA4Cxa,EAAqE,CACvK,GAAI,CAACwa,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,MAAO,CACL,KAAM,KACN,KAAM,CAAE,KAAM,SAAU,WAAY,CAAA,CAAE,EAI1C,MAAMwE,EAASD,GAAA,EACf,GAAI,CAACC,EAAQ,CACX,MAAMhiB,EAAQ2gB,GAAA,EACd,MAAO,CACL,KAAMjD,GAA0BF,EAAWxa,CAAQ,EACnD,KAAM,CAAE,KAAM,OAAQ,WAAY2d,GAAA,EAAU3gB,CAAA,CAAM,CAEtD,CAEA,MAAMyd,EAAkBD,EAAU,qBAAqB,WAAaA,EAAU,UAAU,OAAS,OAAO,iBAClGuD,EAAY,KAAK,IAAI,EAAG,KAAK,IAAIvD,EAAU,MAAO,KAAK,MAAMA,EAAU,UAAU,OAAS,CAAC,EAAGA,EAAU,eAAe,OAAQC,CAAe,CAAC,EAC/IkF,EAAgBnF,EAAU,UAAU,MAAM,EAAGuD,EAAY,CAAC,EAC1D6B,EAAYpF,EAAU,eAAe,MAAM,EAAGuD,CAAS,EACvD8B,EAAgBrF,EAAU,qBAAqB,YAAcA,EAAU,UAAU,QAAUuD,EAAYvD,EAAU,UAAU,MAAM,EAAGuD,CAAS,EAAI,KACjJ+B,EAAUtF,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUuD,EAAYvD,EAAU,IAAI,MAAM,EAAGuD,CAAS,EAAI,KAC1HpiB,EAAKkjB,KACLkB,EAAUpC,GAAA,EAEhB,OAAO,IAAI,QAAyB,CAACqC,EAASC,IAAW,CACvDnB,GAAY,IAAInjB,EAAI,CAAE,KAAM,OAAQ,QAAAqkB,EAAS,OAAAC,EAAQ,QAAAF,EAAS,EAC9D,MAAMX,EAA4B,CAChC,KAAM,mBACN,GAAAzjB,EACA,MAAOoiB,EACP,UAAW4B,EAAc,OACzB,eAAgBC,EAAU,OAC1B,UAAWC,GAAe,OAC1B,IAAKC,GAAS,OACd,SAAU9f,GAAY,CAAA,CAAC,EAEnBkgB,EAA2B,CAACP,EAAc,OAAQC,EAAU,MAAM,EACpEC,GACFK,EAAS,KAAKL,EAAc,MAAM,EAEhCC,GACFI,EAAS,KAAKJ,EAAQ,MAAM,EAE9Bd,EAAO,YAAYI,EAAKc,CAAQ,CAClC,CAAC,CACH,CAEA,eAAsBC,GAAqC3F,EAA4Cxa,EAA0E,CAC/K,GAAI,CAACwa,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,MAAMwE,EAASD,GAAA,EACf,GAAI,CAACC,EAAQ,CACX,MAAMhiB,EAAQ2gB,GAAA,EACd,MAAO,CACL,QAAStC,GAA6Bb,EAAWxa,CAAQ,EACzD,KAAM,CAAE,KAAM,OAAQ,WAAY2d,GAAA,EAAU3gB,CAAA,CAAM,CAEtD,CAEA,MAAMyd,EAAkBD,EAAU,qBAAqB,WAAaA,EAAU,UAAU,OAAS,OAAO,iBAClGuD,EAAY,KAAK,IAAI,EAAG,KAAK,IAAIvD,EAAU,MAAO,KAAK,MAAMA,EAAU,UAAU,OAAS,CAAC,EAAGA,EAAU,eAAe,OAAQC,CAAe,CAAC,EAC/IkF,EAAgBnF,EAAU,UAAU,MAAM,EAAGuD,EAAY,CAAC,EAC1DpiB,EAAKkjB,KACLkB,EAAUpC,GAAA,EAEhB,OAAO,IAAI,QAA8B,CAACqC,EAASC,IAAW,CAC5DnB,GAAY,IAAInjB,EAAI,CAAE,KAAM,QAAS,QAAAqkB,EAAS,OAAAC,EAAQ,QAAAF,EAAS,EAC/D,MAAMX,EAA4B,CAChC,KAAM,yBACN,GAAAzjB,EACA,MAAOoiB,EACP,UAAW4B,EAAc,OACzB,SAAU3f,GAAY,CAAA,CAAC,EAEzBgf,EAAO,YAAYI,EAAK,CAACO,EAAc,MAAM,CAAC,CAChD,CAAC,CACH,CCjMA,SAASS,GAAeC,EAAiD,CACxE,MAAM3gB,EAA6B,CAAA,EACnC,QAAS7F,EAAI,EAAGA,EAAIwmB,EAAQ,OAAQxmB,GAAK,EAAG,CAC3C,MAAM+T,EAASyS,EAAQxmB,CAAC,EAClBmG,EAAWR,GAAmB,CAACoO,GAAQ,WAA6C,CAAC,EAC3F,GAAI5N,EAAS,SAAW,EAAG,SAE3B,IAAI/B,EAAO,EACX,UAAWO,KAAWwB,EACrB/B,GAAQO,EAAQ,KAGjBkB,EAAS,KAAK,CACb,SAAUkO,EAAO,IAAM/T,EACvB,YAAaA,EACb,SAAAmG,EACA,KAAM,KAAK,IAAI,KAAM/B,CAAI,CAAA,CACzB,CACF,CACA,OAAOyB,CACR,CAEA,SAAS4gB,GACRC,EACAC,EACS,CACT,GAAI,MAAM,QAAQA,CAAoB,EAAG,CACxC,MAAMC,EAAYD,EAAqBD,CAAY,EACnD,GAAI,OAAOE,GAAc,UAAYA,EAAU,OAAS,EAAG,OAAOA,CACnE,CACA,GAAID,aAAgC,IAAK,CACxC,MAAME,EAAUF,EAAqB,IAAID,CAAY,EACrD,GAAI,OAAOG,GAAY,UAAYA,EAAQ,OAAS,EAAG,OAAOA,CAC/D,CACA,OAAO,OAAOH,CAAY,CAC3B,CAEO,SAASI,GACfnG,EACA6F,EACA1rB,EAAgC,CAAA,EACX,CACrB,MAAMisB,EAAY,KAAK,IACtB,EACA,KAAK,IACJ,KAAK,MAAMpG,GAAW,OAAS,CAAC,EAChC,KAAK,OAAOA,GAAW,WAAW,QAAU,GAAK,CAAC,EAClDA,GAAW,gBAAgB,QAAU,EACrCA,GAAW,qBAAqB,WAC7BA,EAAU,UAAU,OACpB,OAAO,gBAAA,CACX,EAGD,IAAI+D,EAAkC,KACtC,GAAI/D,GAAW,uBAAuB,YAAa,CAClD,MAAM1nB,EAAS0nB,EAAU,YACzB,IAAIqG,EAAQ/tB,EAAO,OACnB,QAAS+G,EAAI,EAAGA,EAAI/G,EAAO,OAAQ+G,GAAK,EAC3B/G,EAAO+G,CAAC,EACV+mB,IACVC,GAAS,GAEV,GAAIA,IAAU/tB,EAAO,OACpByrB,EAAczrB,UACJ+tB,EAAQ,EAAG,CACrB,MAAMC,EAAW,IAAI,YAAYD,CAAK,EACtC,IAAIzQ,EAAS,EACb,QAASvW,EAAI,EAAGA,EAAI/G,EAAO,OAAQ+G,GAAK,EAAG,CAC1C,MAAMknB,EAAMjuB,EAAO+G,CAAC,EAChBknB,GAAOH,IACXE,EAAS1Q,CAAM,EAAI2Q,EACnB3Q,GAAU,EACX,CACAmO,EAAcuC,CACf,MACCvC,EAAc,IAAI,YAAY,CAAC,CAEjC,CAEA,MAAMyC,EAAazC,EAAcA,EAAY,OAASqC,EAEhDK,EAAkBb,GAAeC,GAAW,EAAE,EACpD,GAAI,CAAC7F,GAAawG,IAAe,GAAKC,EAAgB,SAAW,EAChE,MAAO,CACN,OAAQ,CAAA,EACR,gBAAiBD,EACjB,sBAAuB,EACvB,oBAAqBA,CAAA,EAIvB,MAAME,MAAyB,IACzBC,MAA0B,IAChC,IAAIC,EAAc,EAElB,QAASvnB,EAAI,EAAGA,EAAImnB,EAAYnnB,GAAK,EAAG,CACvC,MAAM4kB,EAAaF,EAAcA,EAAY1kB,CAAC,EAAIA,EAC5CpC,EAAI+iB,EAAU,UAAUiE,EAAa,CAAC,EACtC/mB,EAAI8iB,EAAU,UAAUiE,EAAa,EAAI,CAAC,EAChD,IAAI4C,EAAoC,KAExC,UAAWzT,KAAUqT,EAAiB,CACrC,IAAI/hB,EAAS,GACb,UAAWV,KAAWoP,EAAO,SAC5B,GAAK/N,GAAuBpI,EAAGC,EAAG8G,CAAO,EACzC,CAAAU,EAAS,GACT,MAEIA,IACD,CAACmiB,GAAczT,EAAO,KAAOyT,EAAW,QAC3CA,EAAazT,EAEf,CAEA,GAAI,CAACyT,EAAY,SACjBD,GAAe,EAEf,MAAMb,EAAe/F,EAAU,eAAeiE,CAAU,GAAK,EACvD6C,EACLJ,EAAmB,IAAIG,EAAW,WAAW,OAAS,IACvDC,EAAc,IAAIf,GAAee,EAAc,IAAIf,CAAY,GAAK,GAAK,CAAC,EAC1EW,EAAmB,IAAIG,EAAW,YAAaC,CAAa,EAC5DH,EAAoB,IACnBE,EAAW,aACVF,EAAoB,IAAIE,EAAW,WAAW,GAAK,GAAK,CAAA,CAE3D,CAEA,MAAME,EAAsB5sB,EAAQ,qBAAuB,GACrD6sB,EAA0B,CAAA,EAChC,UAAW5T,KAAUqT,EAAiB,CACrC,MAAMQ,EAAaN,EAAoB,IAAIvT,EAAO,WAAW,GAAK,EAClE,GAAI,CAAC2T,GAAuBE,GAAc,EAAG,SAC7C,MAAMC,EAAUR,EAAmB,IAAItT,EAAO,WAAW,OAAS,IAC5D+T,EAA6B,MAAM,KAAKD,EAAQ,SAAS,EAC7D,IAAI,CAAC,CAACnB,EAAc3F,CAAK,KAAO,CAChC,OAAQ0F,GAAcC,EAAc5rB,EAAQ,oBAAoB,EAChE,aAAA4rB,EACA,MAAA3F,CAAA,EACC,EACD,KAAK,CAAC9e,EAAGC,IAAMA,EAAE,MAAQD,EAAE,OAASA,EAAE,aAAeC,EAAE,YAAY,EAErEylB,EAAO,KAAK,CACX,SAAU5T,EAAO,SACjB,YAAaA,EAAO,YACpB,WAAA6T,EACA,WAAAE,CAAA,CACA,CACF,CAEA,MAAO,CACN,OAAAH,EACA,gBAAiBR,EACjB,sBAAuBI,EACvB,oBAAqB,KAAK,IAAI,EAAGJ,EAAaI,CAAW,CAAA,CAE3D,CCtJA,SAASzD,IAAgB,CACxB,OAAI,OAAO,YAAgB,KAAe,OAAO,YAAY,KAAQ,WAC7D,YAAY,IAAA,EAEb,KAAK,IAAA,CACb,CAEA,SAASiE,GAAuBC,EAAalM,EAA4B,CACxE,GAAI,CAACA,EAAW,MAAO,GACvB,GAAI,CAEH,MAAMmM,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,YAAYptB,EAA+B,CAvB1Bb,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,MAAMa,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,aAAaoM,EAAqB,CACjC,KAAK,UAAY,OAAOA,GAAS,EAAE,CACpC,CAEA,SAAS5L,EAAuC,CAC/C,GAAI,KAAK,UAAW,OAEpB,MAAM6sB,MAAsB,IAC5B,UAAW1sB,KAAQH,EAClB6sB,EAAgB,IAAI1sB,EAAK,GAAG,EAE7B,KAAK,YAAc0sB,EAEnB,KAAK,oBAAoBA,CAAe,EACxC,KAAK,uBAAuBA,CAAe,EAE3C,UAAW1sB,KAAQH,EAAO,CACzB,GAAI,KAAK,SAAS,IAAIG,EAAK,GAAG,EAAG,CAChC,MAAM2sB,EAAW,KAAK,SAAS,IAAI3sB,EAAK,GAAG,EACvC2sB,MAAmB,KAAO3sB,GAC9B,QACD,CAEA,MAAM4sB,EAAS,KAAK,YAAY,IAAI5sB,EAAK,GAAG,EAC5C,GAAI4sB,EAAQ,CACXA,EAAO,KAAO5sB,EACd,QACD,CAEA,MAAM2P,EAAkB,CACvB,KAAA3P,EACA,QAAS,EACT,QAASqoB,GAAA,CAAM,EAEhB,KAAK,MAAM,KAAK1Y,CAAI,EACpB,KAAK,YAAY,IAAI3P,EAAK,IAAK2P,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,oBAAoBkd,EAAgC,CAC3D,GAAI,KAAK,MAAM,SAAW,EAAG,OAC7B,MAAMC,EAAyB,CAAA,EAC/B,UAAWnd,KAAQ,KAAK,MAAO,CAC9B,GAAI,CAACkd,EAAY,IAAIld,EAAK,KAAK,GAAG,EAAG,CACpC,KAAK,YAAY,OAAOA,EAAK,KAAK,GAAG,EACrC,QACD,CACAmd,EAAU,KAAKnd,CAAI,CACpB,CACA,KAAK,MAAQmd,CACd,CAEQ,uBAAuBD,EAAgC,CAC9D,SAAW,CAACE,EAAKpd,CAAI,IAAK,KAAK,SAC1Bkd,EAAY,IAAIE,CAAG,IACvB,KAAK,SAAS,OAAOA,CAAG,EACxB,KAAK,cAAgB,EACrBpd,EAAK,WAAW,MAAA,EAElB,CAEQ,WAAkB,CACzB,KAAK,MAAM,KAAK,CAACnJ,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,MAAM9H,EAAO,KAAK,uBAAA,EAClB,GAAI,CAACA,EAAM,MACX,KAAK,WAAWA,CAAI,CACrB,CAMA,GAJI,KAAK,SAAS,MAAQ,KAAK,gBAI3B,KAAK,MAAM,SAAW,EAAG,OAE7B,MAAMquB,EAAkB,KAAK,MAAM,CAAC,GAAG,QACvC,GAAI,OAAOA,GAAoB,SAAU,OACzC,MAAMC,EAAQ,KAAK,IAAI,EAAGD,EAAkB3E,IAAO,EACnD,KAAK,QAAU,OAAO,WAAW,IAAM,CACtC,KAAK,QAAU,KACf,KAAK,KAAA,CACN,EAAG4E,CAAK,CACT,CAEQ,wBAA2C,CAClD,GAAI,KAAK,MAAM,SAAW,EAAG,OAAO,KACpC,MAAMC,EAAM7E,GAAA,EACNhmB,EAAQ,KAAK,MAAM,CAAC,EAC1B,MAAI,CAACA,GAASA,EAAM,QAAU6qB,EAAY,MAE1C,KAAK,MAAM,MAAA,EACX,KAAK,YAAY,OAAO7qB,EAAM,KAAK,GAAG,EAC/BA,EACR,CAEQ,WAAWsN,EAAuB,CACzC,MAAMwd,EAAa,IAAI,gBACjBC,EAA8B,CACnC,KAAMzd,EAAK,KACX,QAASA,EAAK,QACd,WAAAwd,CAAA,EAED,KAAK,SAAS,IAAIxd,EAAK,KAAK,IAAKyd,CAAa,EAC9C,KAAK,gBAAA,EAEL,MAAM3I,EAAgB6H,GAAuB3c,EAAK,KAAK,IAAK,KAAK,SAAS,EAC1E,MAAMA,EAAK,KAAK,IAAK,CACpB,OAAQwd,EAAW,OACnB,QAAS1I,EAAgB,CAAE,cAAe,KAAK,WAAc,MAAA,CAC7D,EACC,KAAMvkB,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,WAAa+sB,EAAW,OAAO,QAAS,CAChD/sB,EAAO,MAAA,EACP,MACD,CACA,GAAI,CAAC,KAAK,YAAY,IAAIuP,EAAK,KAAK,GAAG,EAAG,CACzCvP,EAAO,MAAA,EACP,MACD,CACA,KAAK,WAAWuP,EAAK,KAAMvP,CAAM,CAClC,CAAC,EACA,MAAOE,GAAmB,CAC1B,GAAI6sB,EAAW,OAAO,SAAW,KAAK,UACrC,OAKD,GADCxd,EAAK,QAAU,KAAK,YAAc,KAAK,YAAY,IAAIA,EAAK,KAAK,GAAG,EACpD,CAChB,KAAK,YAAc,EACnB,MAAM0d,EAAc1d,EAAK,QAAU,EAC7B2d,EAAa,KAAK,cAAcD,CAAW,EAC3CT,EAAoB,CACzB,KAAMjd,EAAK,KACX,QAAS0d,EACT,QAAShF,KAAUiF,CAAA,EAEdC,EAAW,KAAK,YAAY,IAAI5d,EAAK,KAAK,GAAG,EAC/C4d,GACHA,EAAS,KAAOX,EAAO,KACvBW,EAAS,QAAU,KAAK,IAAIA,EAAS,QAASX,EAAO,OAAO,EAC5DW,EAAS,QAAU,KAAK,IAAIA,EAAS,QAASX,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,cAAcjd,EAAK,KAAMrP,EAAOqP,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,cAAc6d,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,CC/RA,MAAMC,GAAoC,IACpCC,GAAoB,GACpBC,GAAoB,IAOpBC,GAAqD,CAC1D,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,CACnB,EAiDA,MAAMxuB,EAAY,CAAlB,cACSd,EAAA,qBAAgB,GAChBA,EAAA,sBAAiB,GACjBA,EAAA,iBAA0B,CACjC,KAAM,EACN,QAAS,EACT,QAAS,EACT,YAAa,CAAA,GAGd,YAAYC,EAAeC,EAAsB,CAChD,KAAK,cAAgB,KAAK,IAAI,EAAGD,CAAK,EACtC,KAAK,eAAiB,KAAK,IAAI,EAAGC,CAAM,CACzC,CAEA,aAA6B,CAC5B,MAAO,CAAE,MAAO,KAAK,cAAe,OAAQ,KAAK,cAAA,CAClD,CAEA,aAAaC,EAAmC,CAC3C,OAAOA,EAAK,MAAS,WACxB,KAAK,UAAU,KAAO,KAAK,IAAI,KAAQA,EAAK,IAAI,GAE7C,OAAOA,EAAK,SAAY,WAC3B,KAAK,UAAU,QAAUA,EAAK,SAE3B,OAAOA,EAAK,SAAY,WAC3B,KAAK,UAAU,QAAUA,EAAK,SAE3B,OAAOA,EAAK,aAAgB,UAAY,OAAO,SAASA,EAAK,WAAW,IAC3E,KAAK,UAAU,YAAcA,EAAK,YAEpC,CAEA,cAA6B,CAC5B,MAAO,CAAE,GAAG,KAAK,SAAA,CAClB,CAEA,WAAwB,CACvB,MAAMmC,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EAC/C,MAAO,CACN,KAAK,UAAU,QAAU,KAAK,eAAiB,EAAIA,GACnD,KAAK,UAAU,QAAU,KAAK,gBAAkB,EAAIA,EAAA,CAEtD,CAEA,UAAUsQ,EAAiBC,EAAuB,CACjD,MAAMvQ,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EAC/C,KAAK,UAAU,QAAUsQ,EAAU,KAAK,eAAiB,EAAItQ,GAC7D,KAAK,UAAU,QAAUuQ,EAAU,KAAK,gBAAkB,EAAIvQ,EAC/D,CAEA,cAAcod,EAAiBC,EAA6B,CAC3D,MAAMjD,EAAQ,KAAK,UACbpa,EAAO,KAAK,IAAI,KAAMoa,EAAM,IAAI,EAChC,CAAC9J,EAASC,CAAO,EAAI,KAAK,UAAA,EAC1BlK,GAAM+W,EAAU,KAAK,cAAgB,IAAOpd,EAC5CsG,GAAM+W,EAAU,KAAK,eAAiB,IAAOrd,EAC7CitB,EAAMC,GAAU9S,EAAM,WAAW,EACjC+S,EAAM,KAAK,IAAIF,CAAG,EAClBG,EAAM,KAAK,IAAIH,CAAG,EACxB,MAAO,CAAC3c,EAAUjK,EAAK8mB,EAAM7mB,EAAK8mB,EAAK7c,EAAUlK,EAAK+mB,EAAM9mB,EAAK6mB,CAAG,CACrE,CAEA,cAAcrK,EAAgBC,EAA4B,CACzD,MAAM3I,EAAQ,KAAK,UACbpa,EAAO,KAAK,IAAI,KAAMoa,EAAM,IAAI,EAChC,CAAC9J,EAASC,CAAO,EAAI,KAAK,UAAA,EAC1BlK,EAAKyc,EAASxS,EACdhK,EAAKyc,EAASxS,EACd0c,EAAMC,GAAU9S,EAAM,WAAW,EACjC+S,EAAM,KAAK,IAAIF,CAAG,EAClBG,EAAM,KAAK,IAAIH,CAAG,EAClBI,EAAKhnB,EAAK8mB,EAAM7mB,EAAK8mB,EACrBE,EAAK,CAACjnB,EAAK+mB,EAAM9mB,EAAK6mB,EAC5B,MAAO,CACN,KAAK,cAAgB,GAAME,EAAKrtB,EAChC,KAAK,eAAiB,GAAMstB,EAAKttB,CAAA,CAEnC,CAEA,gBAAmE,CAClE,MAAMsY,EAAI,KAAK,cACTC,EAAI,KAAK,eACf,MAAO,CACN,KAAK,cAAc,EAAG,CAAC,EACvB,KAAK,cAAcD,EAAG,CAAC,EACvB,KAAK,cAAcA,EAAGC,CAAC,EACvB,KAAK,cAAc,EAAGA,CAAC,CAAA,CAEzB,CAEA,WAA0B,CACzB,MAAMvY,EAAO,KAAK,IAAI,KAAM,KAAK,UAAU,IAAI,EACzC,CAACsQ,EAASC,CAAO,EAAI,KAAK,UAAA,EAC1B0c,EAAMC,GAAU,KAAK,UAAU,WAAW,EAC1CC,EAAM,KAAK,IAAIF,CAAG,EAClBG,EAAM,KAAK,IAAIH,CAAG,EAElBM,EAAM,EAAIvtB,EAAOmtB,EAAO,KAAK,cAC7BK,EAAM,EAAIxtB,EAAOotB,EAAO,KAAK,cAC7BK,EAAM,EAAIztB,EAAOotB,EAAO,KAAK,eAC7BM,EAAM,GAAK1tB,EAAOmtB,EAAO,KAAK,eAC9BjvB,EAAK,EAAEqvB,EAAKjd,EAAUkd,EAAKjd,GAC3BpS,EAAK,EAAEsvB,EAAKnd,EAAUod,EAAKnd,GAEjC,OAAO,IAAI,aAAa,CAACgd,EAAIE,EAAI,EAAGD,EAAIE,EAAI,EAAGxvB,EAAIC,EAAI,CAAC,CAAC,CAC1D,CACD,CAEA,SAAS+uB,GAAUS,EAAqB,CACvC,OAAQA,EAAM,KAAK,GAAM,GAC1B,CAEA,SAASpG,IAAgB,CACxB,OAAI,OAAO,YAAgB,KAAe,OAAO,YAAY,KAAQ,WAC7D,YAAY,IAAA,EAEb,KAAK,IAAA,CACb,CAEA,SAASpqB,GACRX,EACAU,EACA0wB,EACuB,CACvB,MAAMvwB,EAAWb,EAAG,mBAAmBU,EAAS0wB,CAAI,EACpD,GAAI,CAACvwB,EACJ,MAAM,IAAI,MAAM,mCAAmCuwB,CAAI,EAAE,EAE1D,OAAOvwB,CACR,CAEA,SAASwwB,GACRnoB,EACAC,EACU,CACV,MAAI,CAACD,GAAK,CAACC,EAAUD,IAAMC,EAE1BD,EAAE,SAAWC,EAAE,QACfD,EAAE,aAAeC,EAAE,YACnBD,EAAE,aAAeC,EAAE,UAErB,CAEA,SAASmoB,GAAoBC,EAAkD,CAC9E,OAAOA,EAAM,IAAIC,IAAS,CAAE,KAAMA,EAAK,KAAM,KAAMA,EAAK,IAAA,EAAO,CAChE,CAEA,SAASC,GAAwBC,EAAsE,CACtG,GAAI,CAACA,EAAiB,OAAOJ,GAAoBd,EAAwB,EAEzE,MAAMtP,MAAa,IACnB,SAAW,CAACyQ,EAASC,CAAO,IAAK,OAAO,QAAQF,CAAe,EAAG,CACjE,MAAMluB,EAAO,OAAOmuB,CAAO,EACrBE,EAAO,OAAOD,CAAO,EACvB,CAAC,OAAO,SAASpuB,CAAI,GAAK,CAAC,OAAO,SAASquB,CAAI,GAAKA,GAAQ,GAChE3Q,EAAO,IAAI1d,EAAMquB,CAAI,CACtB,CAEA,OAAI3Q,EAAO,OAAS,EACZoQ,GAAoBd,EAAwB,EAG7C,MAAM,KAAKtP,EAAO,QAAA,CAAS,EAChC,KAAK,CAAChY,EAAGC,IAAMD,EAAE,CAAC,EAAIC,EAAE,CAAC,CAAC,EAC1B,IAAI,CAAC,CAAC3F,EAAMquB,CAAI,KAAO,CAAE,KAAAruB,EAAM,KAAAquB,CAAA,EAAO,CACzC,CAEA,SAASC,GAAuB5oB,EAA6BC,EAAsC,CAClG,GAAID,IAAMC,EAAG,MAAO,GACpB,GAAID,EAAE,SAAWC,EAAE,OAAQ,MAAO,GAClC,QAASlC,EAAI,EAAGA,EAAIiC,EAAE,OAAQjC,GAAK,EAClC,GAAIiC,EAAEjC,CAAC,EAAE,OAASkC,EAAElC,CAAC,EAAE,MAAQiC,EAAEjC,CAAC,EAAE,OAASkC,EAAElC,CAAC,EAAE,KACjD,MAAO,GAGT,MAAO,EACR,CAEA,SAAS8qB,GAA4BlV,EAAwB0U,EAAyC,CACrG,GAAI,CAAC,OAAO,SAAS1U,CAAc,EAAG,OAAO0U,EAAM,CAAC,GAAG,MAAQjB,GAC/D,GAAIiB,EAAM,SAAW,EAAG,OAAOjB,GAE/B,GADIiB,EAAM,SAAW,GACjB1U,GAAkB0U,EAAM,CAAC,EAAE,KAAM,OAAOA,EAAM,CAAC,EAAE,KAErD,QAAStqB,EAAI,EAAGA,EAAIsqB,EAAM,OAAQtqB,GAAK,EAAG,CACzC,MAAM7B,EAAOmsB,EAAMtqB,EAAI,CAAC,EAClB5F,EAAOkwB,EAAMtqB,CAAC,EACpB,GAAI4V,EAAiBxb,EAAK,KAAM,SAChC,MAAM2wB,EAAO,KAAK,IAAI,KAAM3wB,EAAK,KAAO+D,EAAK,IAAI,EAC3CM,EAAIpB,IAAOuY,EAAiBzX,EAAK,MAAQ4sB,EAAM,EAAG,CAAC,EACzD,OAAO5sB,EAAK,MAAQ/D,EAAK,KAAO+D,EAAK,MAAQM,CAC9C,CAEA,MAAMV,EAAOusB,EAAMA,EAAM,OAAS,CAAC,EAC7BnsB,EAAOmsB,EAAMA,EAAM,OAAS,CAAC,EAC7BS,EAAO,KAAK,IAAI,KAAMhtB,EAAK,KAAOI,EAAK,IAAI,EAC3C6sB,GAASjtB,EAAK,KAAOI,EAAK,MAAQ4sB,EACxC,OAAOhtB,EAAK,MAAQ6X,EAAiB7X,EAAK,MAAQitB,CACnD,CAEA,MAAMC,GAAmB,GACnBC,GAAmB,EAEzB,SAASC,GAAqB7tB,EAA0C,CACvE,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU,EAC1DD,GAAMC,EAAO2tB,GAAkBC,EAAgB,CACvD,CAEA,MAAME,GAAwB,KACxBC,GAAwB,IAQ9B,SAASC,GAAyBhuB,EAA0C,CAC3E,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,EAAU,EAC1DD,GAAMC,EAAO8tB,GAAuBC,EAAqB,CACjE,CAEA,SAASE,GACRC,EAC+B,CAC/B,MAAMC,EAAkBH,GAAyBE,GAAU,UAAU,EAC/DE,EAAgBJ,GAAyBE,GAAU,QAAQ,EAC3DG,EAAkBL,GAAyBE,GAAU,UAAU,EACrE,MAAO,CACN,WAAYC,EAAkB,IAC9B,SAAUC,EAAgB,IAC1B,WAAYC,EAAkB,GAAA,CAEhC,CAEA,MAAMC,GAAkC,IAExC,SAASC,GAAaptB,EAAmB,CACxC,OAAOA,CACR,CAEA,SAASqtB,GAAgCC,EAA6C,CACrF,OAAI,OAAOA,GAAa,UAAY,CAAC,OAAO,SAASA,CAAQ,EAAU,EAChE1uB,GAAM0uB,EAAU,EAAGH,EAA+B,CAC1D,CAEA,SAASI,GAAsB1uB,EAAiD,CAC/E,OAAI,OAAOA,GAAU,UAAY,CAAC,OAAO,SAASA,CAAK,GAAKA,GAAS,EAAU,KACxE,KAAK,IAAI,KAAMA,CAAK,CAC5B,CAEA,SAAS2uB,GACRC,EACwB,CACxB,OAAO,OAAOA,GAAW,WAAaA,EAASL,EAChD,CAEA,SAAS9kB,GAAgB9E,EAAiBC,EAA0B,CAEnE,OACC,KAAK,IAAID,EAAE,KAAOC,EAAE,IAAI,GAAK,MAC7B,KAAK,IAAID,EAAE,QAAUC,EAAE,OAAO,GAAK,MACnC,KAAK,IAAID,EAAE,QAAUC,EAAE,OAAO,GAAK,MACnC,KAAK,IAAID,EAAE,YAAcC,EAAE,WAAW,GAAK,IAE7C,CAEO,MAAMiqB,EAAgB,CAiE5B,YACCryB,EACAb,EACA6B,EAAkC,CAAA,EACjC,CApEeb,EAAA,eACAA,EAAA,eACAA,EAAA,WACAA,EAAA,cAAS,IAAIc,IACbd,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,gBAAW,IACXA,EAAA,uBAA6C,QAC7CA,EAAA,0BAAoC,MACpCA,EAAA,iBAA2B,MAC3BA,EAAA,oBAAe,GACfA,EAAA,oBAAe,GACfA,EAAA,yBAAoB,IACpBA,EAAA,sBAAiB,IACjBA,EAAA,0CAAqC,KACrCA,EAAA,sBACAA,EAAA,eAAU,GACVA,EAAA,eAAU,MACVA,EAAA,eAAU,GACVA,EAAA,uBAAiC,MACjCA,EAAA,uBAAiC,MACjCA,EAAA,gCAA2B,GAC3BA,EAAA,4BAA8C4xB,IAC9C5xB,EAAA,qBAA2C,MAC3CA,EAAA,0BAAoC,MACpCA,EAAA,mBAAc,GACdA,EAAA,kBAAa,GACbA,EAAA,uBAAkB,IAClBA,EAAA,yBAAoB,IACpBA,EAAA,wBAAmB,GACnBA,EAAA,sBAAkCowB,GAAoBd,EAAwB,GAC9EtvB,EAAA,wBAAmB,GACnBA,EAAA,0BAAmD,CAC1D,WAAY,EACZ,SAAU,EACV,WAAY,CAAA,GAELA,EAAA,qBAAqC,MACrCA,EAAA,wBAAsC,MACtCA,EAAA,qBAAgB,IAAI,WAAW,CAAC,GAChCA,EAAA,iBAAY,KAEHA,EAAA,yBACAA,EAAA,yBACAA,EAAA,uBACAA,EAAA,mBACAA,EAAA,yBACAA,EAAA,yBACAA,EAAA,yBACAA,EAAA,6BAOhB,KAAK,OAASH,EACd,KAAK,OAASb,EACd,KAAK,kBAAoB6B,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,mCACJ,OAAOA,EAAQ,oCAAuC,UACtD,OAAO,SAASA,EAAQ,kCAAkC,EACvD,KAAK,IAAI,EAAGA,EAAQ,kCAAkC,EACtDsuB,GACJ,KAAK,eAAiBoB,GAAwB1vB,EAAQ,eAAe,EACrE,KAAK,iBAAmBqwB,GAAqBrwB,EAAQ,gBAAgB,EACrE,KAAK,mBAAqBywB,GACzBzwB,EAAQ,kBAAA,EAET,KAAK,gBAAkBkxB,GAAsBlxB,EAAQ,OAAO,EAC5D,KAAK,gBAAkBkxB,GAAsBlxB,EAAQ,OAAO,EAC5D,KAAK,yBAA2BgxB,GAAgChxB,EAAQ,gBAAgB,QAAQ,EAChG,KAAK,qBAAuBmxB,GAA0BnxB,EAAQ,gBAAgB,MAAM,EAEpF,MAAM/B,EAAKe,EAAO,WAAW,SAAU,CACtC,MAAO,GACP,UAAW,GACX,MAAO,GACP,QAAS,GACT,gBAAiB,kBAAA,CACjB,EACD,GAAI,CAACf,EACJ,MAAM,IAAI,MAAM,sBAAsB,EAEvC,KAAK,GAAKA,EAEV,KAAK,YAAc,KAAK,gBAAA,EACxB,KAAK,aAAe,KAAK,iBAAA,EACzB,KAAK,cAAgB,IAAImvB,GAAc,CACtC,UAAW,KAAK,UAChB,eAAgBptB,EAAQ,eAAe,gBAAkB,GACzD,WAAYA,EAAQ,eAAe,YAAc,EACjD,iBAAkBA,EAAQ,eAAe,kBAAoB,IAC7D,gBAAiBA,EAAQ,eAAe,iBAAmB,KAC3D,WAAY,CAACW,EAAMI,IAAW,KAAK,iBAAiBJ,EAAMI,CAAM,EAChE,YAAa,CAACJ,EAAMM,EAAOqwB,IAAiB,CAC3C,KAAK,cAAc,CAAE,KAAA3wB,EAAM,MAAAM,EAAO,aAAAqwB,EAAc,EAChD,QAAQ,KAAK,mBAAoB3wB,EAAK,IAAKM,CAAK,CACjD,CAAA,CACA,EAED,KAAK,eAAiB,IAAI,eAAe,IAAM,KAAK,QAAQ,EAC5D,KAAK,eAAe,QAAQjC,CAAM,EAElC,KAAK,iBAAoBqe,GAAwB,KAAK,cAAcA,CAAK,EACzE,KAAK,iBAAoBA,GAAwB,KAAK,cAAcA,CAAK,EACzE,KAAK,eAAkBA,GAAwB,KAAK,YAAYA,CAAK,EACrE,KAAK,WAAcA,GAAsB,KAAK,QAAQA,CAAK,EAC3D,KAAK,iBAAoBA,GAAsB,KAAK,cAAcA,CAAK,EACvE,KAAK,iBAAoBA,GAAsB,KAAK,cAAcA,CAAK,EACvE,KAAK,iBAAoBA,GAAiB,KAAK,mBAAmBA,CAAK,EACvE,KAAK,qBAAwBA,GAC5B,KAAK,uBAAuBA,CAAK,EAElCre,EAAO,iBAAiB,cAAe,KAAK,gBAAgB,EAC5DA,EAAO,iBAAiB,cAAe,KAAK,gBAAgB,EAC5DA,EAAO,iBAAiB,YAAa,KAAK,cAAc,EACxDA,EAAO,iBAAiB,gBAAiB,KAAK,cAAc,EAC5DA,EAAO,iBAAiB,QAAS,KAAK,WAAY,CAAE,QAAS,GAAO,EACpEA,EAAO,iBAAiB,WAAY,KAAK,gBAAgB,EACzDA,EAAO,iBAAiB,cAAe,KAAK,gBAAgB,EAC5DA,EAAO,iBAAiB,mBAAoB,KAAK,gBAAgB,EACjEA,EAAO,iBAAiB,uBAAwB,KAAK,oBAAoB,EAEzE,KAAK,WAAW,CAAE,SAAU,CAAA,CAAG,EAC/B,KAAK,OAAA,CACN,CAEQ,0BAAiE,CACxE,MAAM6Q,EAAU,KAAK,IAAI,KAAK,QAAU,GAAK,IAAI,EAC3CC,EAAU,KAAK,IAAI,EAAG,KAAK,QAAU,CAAC,EAC5C,MAAO,CACN,QAAAD,EACA,QAAS,KAAK,IAAIA,EAASC,CAAO,CAAA,CAEpC,CAEQ,iBAAwB,CAC/B,MAAMyhB,EAAW,KAAK,yBAAA,EACtB,IAAI1hB,EAAU,KAAK,iBAAmB0hB,EAAS,QAC3CzhB,EAAU,KAAK,iBAAmByhB,EAAS,QAC/C1hB,EAAU,KAAK,IAAI,KAAMA,CAAO,EAChCC,EAAU,KAAK,IAAI,KAAMA,CAAO,EAC5BD,EAAUC,IACbD,EAAUC,GAEX,KAAK,QAAUD,EACf,KAAK,QAAUC,CAChB,CAEQ,uBAAuBxQ,EAA2C,CACzE,MAAMkyB,EAAU,KAAK,OAAO,aAAA,EACtB5qB,EAA0B,CAC/B,KACC,OAAOtH,EAAK,MAAS,UAAY,OAAO,SAASA,EAAK,IAAI,EACvDiD,GAAMjD,EAAK,KAAM,KAAK,QAAS,KAAK,OAAO,EAC3CkyB,EAAQ,KACZ,QACC,OAAOlyB,EAAK,SAAY,UAAY,OAAO,SAASA,EAAK,OAAO,EAC7DA,EAAK,QACLkyB,EAAQ,QACZ,QACC,OAAOlyB,EAAK,SAAY,UAAY,OAAO,SAASA,EAAK,OAAO,EAC7DA,EAAK,QACLkyB,EAAQ,QACZ,YACC,OAAOlyB,EAAK,aAAgB,UAAY,OAAO,SAASA,EAAK,WAAW,EACrEA,EAAK,YACLkyB,EAAQ,WAAA,EAGb,KAAK,OAAO,aAAa5qB,CAAS,EAClC,KAAK,eAAA,EACL,MAAM6qB,EAAS,KAAK,OAAO,aAAA,EAC3B,YAAK,OAAO,aAAaD,CAAO,EACzBC,CACR,CAEQ,qBAA4B,CACnC,KAAK,cAAgB,KACjB,KAAK,qBAAuB,OAC/B,qBAAqB,KAAK,kBAAkB,EAC5C,KAAK,mBAAqB,KAE5B,CAEQ,mBACPA,EACAC,EACAN,EACO,CACP,MAAM/Q,EAAO,KAAK,OAAO,aAAA,EACzB,KAAK,oBAAA,EACL,KAAK,cAAgB,CACpB,QAAS2I,GAAA,EACT,WAAY,KAAK,IAAI,EAAG0I,CAAU,EAClC,KAAArR,EACA,GAAIoR,EACJ,OAAAL,CAAA,EAGD,MAAM1sB,EAAO,IAAY,CACxB,MAAMitB,EAAY,KAAK,cACvB,GAAI,CAACA,EAAW,OAEhB,MAAMC,EAAU,KAAK,IAAI,EAAG5I,GAAA,EAAU2I,EAAU,OAAO,EACjDE,EACLF,EAAU,YAAc,EAAI,EAAIpvB,GAAMqvB,EAAUD,EAAU,WAAY,EAAG,CAAC,EAC3E,IAAIG,EAAQD,EACZ,GAAI,CACHC,EAAQH,EAAU,OAAOE,CAAI,CAC9B,MAAQ,CACPC,EAAQD,CACT,CACK,OAAO,SAASC,CAAK,IACzBA,EAAQD,GAETC,EAAQvvB,GAAMuvB,EAAO,EAAG,CAAC,EAEzB,MAAMC,EAA0B,CAC/B,KAAMJ,EAAU,KAAK,MAAQA,EAAU,GAAG,KAAOA,EAAU,KAAK,MAAQG,EACxE,QACCH,EAAU,KAAK,SACdA,EAAU,GAAG,QAAUA,EAAU,KAAK,SAAWG,EACnD,QACCH,EAAU,KAAK,SACdA,EAAU,GAAG,QAAUA,EAAU,KAAK,SAAWG,EACnD,YACCH,EAAU,KAAK,aACdA,EAAU,GAAG,YAAcA,EAAU,KAAK,aAAeG,CAAA,EAQ5D,GALA,KAAK,OAAO,aAAaC,CAAS,EAClC,KAAK,eAAA,EACL,KAAK,cAAA,EACL,KAAK,cAAA,EAEDF,GAAQ,EAAG,CACd,KAAK,cAAgB,KACrB,KAAK,mBAAqB,KAC1B,MACD,CAEA,KAAK,mBAAqB,sBAAsBntB,CAAI,CACrD,EAEA,KAAK,mBAAqB,sBAAsBA,CAAI,CACrD,CAEA,aAAa0H,EAAqB,CACjC,KAAK,UAAY,OAAOA,GAAS,EAAE,EACnC,KAAK,cAAc,aAAa,KAAK,SAAS,CAC/C,CAEA,aAAayD,EAAoCC,EAA0C,CAC1F,MAAMkiB,EAAkBd,GAAsBrhB,CAAO,EAC/CoiB,EAAkBf,GAAsBphB,CAAO,EACrD,GACC,KAAK,kBAAoBkiB,GACzB,KAAK,kBAAoBC,EAEzB,OAGD,KAAK,gBAAkBD,EACvB,KAAK,gBAAkBC,EACvB,KAAK,gBAAA,EAEL,MAAMR,EAAS,KAAK,uBAAuB,EAAE,EACvCD,EAAU,KAAK,OAAO,aAAA,EACxBvlB,GAAgBulB,EAASC,CAAM,IAGnC,KAAK,oBAAA,EACL,KAAK,OAAO,aAAaA,CAAM,EAC/B,KAAK,cAAA,EACL,KAAK,cAAA,EACN,CAEA,kBAAkBzxB,EAA4D,CAC7E,KAAK,yBAA2BgxB,GAAgChxB,GAAS,QAAQ,EACjF,KAAK,qBAAuBmxB,GAA0BnxB,GAAS,MAAM,CACtE,CAEA,aACCV,EACA4yB,EACO,CACP,MAAMT,EAAS,KAAK,uBAAuBnyB,CAAI,EACzCkyB,EAAU,KAAK,OAAO,aAAA,EAC5B,GAAIvlB,GAAgBulB,EAASC,CAAM,EAAG,OAEtC,MAAMC,EAAaV,GAClBkB,GAAY,UAAY,KAAK,wBAAA,EAExBd,EAASD,GACde,GAAY,QAAU,KAAK,oBAAA,EAE5B,GAAIR,GAAc,EAAG,CACpB,KAAK,oBAAA,EACL,KAAK,OAAO,aAAaD,CAAM,EAC/B,KAAK,cAAA,EACL,KAAK,cAAA,EACL,MACD,CAEA,KAAK,mBAAmBA,EAAQC,EAAYN,CAAM,CACnD,CAEA,cAA6B,CAC5B,OAAO,KAAK,OAAO,aAAA,CACpB,CAEA,cAAqD,CACpD,MAAO,CAAE,QAAS,KAAK,QAAS,QAAS,KAAK,OAAA,CAC/C,CAEA,gBAAgBrkB,EAA6C,CAC5D,GAAI,CAACA,GAAUA,EAAO,SAAW,EAAG,CACnC,KAAK,iBAAmB,KACxB,MACD,CAEA,GADA,KAAK,iBAAmB,IAAI,WAAWA,CAAM,EACzC,KAAK,aAAe,KAAK,GAAG,gBAAiB,OACjD,MAAM9O,EAAK,KAAK,GACVk0B,EAAc,KAAK,IAAI,EAAG,KAAK,MAAM,KAAK,iBAAiB,OAAS,CAAC,CAAC,EAC5E,KAAK,iBAAmBA,EACxBl0B,EAAG,YAAYA,EAAG,WAAY,KAAK,aAAa,cAAc,EAC9DA,EAAG,WACFA,EAAG,WACH,EACAA,EAAG,KACHk0B,EACA,EACA,EACAl0B,EAAG,KACHA,EAAG,cACH,KAAK,gBAAA,EAENA,EAAG,YAAYA,EAAG,WAAY,IAAI,EAClC,KAAK,cAAA,CACN,CAEA,aAAakF,EAA+C,CAC3D,GAAI,CAACA,GAAU,CAACA,EAAO,OAAS,CAACA,EAAO,WAAa,CAACA,EAAO,eAAgB,CAC5E,KAAK,cAAgB,KACrB,KAAK,WAAa,EAClB,KAAK,gBAAkB,GACvB,KAAK,cAAA,EACL,MACD,CAEA,MAAMkmB,EACLlmB,EAAO,qBAAqB,WAAaA,EAAO,UAAY,KACvDivB,EAAe/I,IAAmB,KAClCD,EAAY,KAAK,IACtB,EACA,KAAK,IACJjmB,EAAO,MACP,KAAK,MAAMA,EAAO,UAAU,OAAS,CAAC,EACtCA,EAAO,eAAe,OACtBivB,EAAe/I,EAAe,OAAS,OAAO,gBAAA,CAC/C,EAEKhD,EAAgBljB,EAAO,UAAU,SAAS,EAAGimB,EAAY,CAAC,EAC1DiJ,EAAqBlvB,EAAO,eAAe,SAAS,EAAGimB,CAAS,EAChE7C,EAAgB6L,EACnB/I,EAAe,SAAS,EAAGD,CAAS,EACpC,OACGkJ,EAAiBnvB,EAAO,uBAAuB,YAC/CovB,EAAkBD,EACrB,KAAK,oBAAoBnvB,EAAO,YAA4BimB,CAAS,EACrE,KACG/lB,EAAO,KAAK,cACZmvB,EAAmBnvB,GAAM,qBAAqB,WACpD,IAAIovB,EACH,KAAK,mBACL,CAACpvB,GACDA,EAAK,QAAU+lB,GACf,CAACkG,GAAgBjsB,EAAK,UAAWgjB,CAAa,GAC9C,CAACiJ,GAAgBjsB,EAAK,eAAgBgvB,CAAkB,GACxDG,IAAqBJ,GACpBA,IACC,CAAC/uB,GAAM,WAAa,CAACisB,GAAgBjsB,EAAK,UAAWkjB,CAAa,GACjEmM,EACH,KAAK,mBACJJ,IACC,CAACjvB,GAAM,aACP,CAACisB,GAAgBjsB,EAAK,YAAakvB,CAAe,IACnD,CAACD,GAAkB,CAAC,CAACjvB,GAAM,YAS7B,GAPA,KAAK,cAAgB,CACpB,MAAO+lB,EACP,UAAW/C,EACX,eAAgBgM,EAChB,UAAW9L,EACX,YAAa+L,EAAiBC,GAAmB,OAAY,MAAA,EAE1D,KAAK,aAAe,KAAK,GAAG,gBAAiB,OAEjD,MAAMt0B,EAAK,KAAK,GACZw0B,IACHx0B,EAAG,WAAWA,EAAG,aAAc,KAAK,aAAa,SAAS,EAC1DA,EAAG,WAAWA,EAAG,aAAc,KAAK,cAAc,UAAWA,EAAG,WAAW,EAE3EA,EAAG,WAAWA,EAAG,aAAc,KAAK,aAAa,UAAU,EAC3DA,EAAG,WACFA,EAAG,aACH,KAAK,cAAc,eACnBA,EAAG,WAAA,EAGJA,EAAG,WAAWA,EAAG,aAAc,KAAK,aAAa,cAAc,EAC/DA,EAAG,WACFA,EAAG,aACH,KAAK,cAAc,WAAa,KAAK,iBAAiBmrB,CAAS,EAC/DnrB,EAAG,WAAA,EAEJA,EAAG,WAAWA,EAAG,aAAc,IAAI,GAGhCq0B,GAAkBI,IACrBz0B,EAAG,WAAWA,EAAG,qBAAsB,KAAK,aAAa,WAAW,EACpEA,EAAG,WACFA,EAAG,qBACHs0B,GAAmB,IAAI,YAAY,CAAC,EACpCt0B,EAAG,YAAA,EAEJA,EAAG,WAAWA,EAAG,qBAAsB,IAAI,GAG5C,KAAK,gBAAkBq0B,EACvB,KAAK,WAAaA,EACdC,GAAiB,QAAU,EAC5B,KAAK,cAAc,OAClBE,GAAmBC,KACtB,KAAK,kBAAoB,IAE1B,KAAK,cAAA,CACN,CAEQ,oBACP9I,EACA+I,EACc,CACd,GAAIA,GAAgB,GAAK/I,EAAY,SAAW,EAC/C,OAAO,IAAI,YAAY,CAAC,EAGzB,IAAIgJ,EAAahJ,EAAY,OAC7B,QAAS1kB,EAAI,EAAGA,EAAI0kB,EAAY,OAAQ1kB,GAAK,EACxC0kB,EAAY1kB,CAAC,EAAIytB,IACrBC,GAAc,GAEf,GAAIA,IAAehJ,EAAY,OAC9B,OAAOA,EAER,GAAIgJ,GAAc,EACjB,OAAO,IAAI,YAAY,CAAC,EAGzB,MAAMzG,EAAW,IAAI,YAAYyG,CAAU,EAC3C,IAAInX,EAAS,EACb,QAASvW,EAAI,EAAGA,EAAI0kB,EAAY,OAAQ1kB,GAAK,EAAG,CAC/C,MAAMknB,EAAMxC,EAAY1kB,CAAC,EACrBknB,GAAOuG,IACXxG,EAAS1Q,CAAM,EAAI2Q,EACnB3Q,GAAU,EACX,CACA,OAAO0Q,CACR,CAEQ,iBAAiBlG,EAA2B,CACnD,OAAIA,GAAS,EAAU,IAAI,WAAW,CAAC,GACnC,KAAK,cAAc,OAASA,IAC/B,KAAK,cAAgB,IAAI,WAAWA,CAAK,GAEnC,KAAK,cAAc,SAAS,EAAGA,CAAK,EAC5C,CAEA,mBAAmB4M,EAAuB,CACzC,MAAMvzB,EAAO,EAAQuzB,EACjB,KAAK,oBAAsBvzB,IAC/B,KAAK,kBAAoBA,EACrBA,QAAW,WAAA,EAChB,CAEA,mBAAmBqwB,EAA2D,CAC7E,MAAMmD,EAAYpD,GAAwBC,CAAe,EACrDI,GAAuB,KAAK,eAAgB+C,CAAS,IACzD,KAAK,eAAiBA,EACtB,KAAK,cAAA,EACN,CAEA,oBAAoBrS,EAAwC,CAC3D,MAAMnhB,EAAO+wB,GAAqB5P,CAAK,EACnC,KAAK,mBAAqBnhB,IAC9B,KAAK,iBAAmBA,EACxB,KAAK,cAAA,EACN,CAEA,sBAAsBoxB,EAA0D,CAC/E,MAAMpxB,EAAOmxB,GAA+BC,CAAQ,EAC9CrtB,EAAO,KAAK,mBAEjBA,EAAK,aAAe/D,EAAK,YACzB+D,EAAK,WAAa/D,EAAK,UACvB+D,EAAK,aAAe/D,EAAK,aAI1B,KAAK,mBAAqBA,EAC1B,KAAK,cAAA,EACN,CAEA,YAAmB,CAClB,GAAI,KAAK,YAAc,MAAQ,KAAK,OAAO,kBAAkB,KAAK,SAAS,EAC1E,GAAI,CACH,KAAK,OAAO,sBAAsB,KAAK,SAAS,CACjD,MAAQ,CAER,CAED,KAAK,SAAW,GAChB,KAAK,gBAAkB,OACvB,KAAK,mBAAqB,KAC1B,KAAK,UAAY,KACjB,KAAK,OAAO,UAAU,OAAO,UAAU,CACxC,CAEQ,mBAAmBskB,EAAiBC,EAAyB,CACpE,MAAM3iB,EAAO,KAAK,OAAO,sBAAA,EACnB4B,EAAI8gB,EAAU1iB,EAAK,KAAOA,EAAK,MAAQ,GACvC6B,EAAI8gB,EAAU3iB,EAAK,IAAMA,EAAK,OAAS,GAC7C,OAAO,KAAK,MAAM6B,EAAGD,CAAC,CACvB,CAEA,cAAc8gB,EAAiBC,EAAmC,CACjE,MAAM3iB,EAAO,KAAK,OAAO,sBAAA,EACnBzB,EAAKmkB,EAAU1iB,EAAK,KACpBxB,EAAKmkB,EAAU3iB,EAAK,IAC1B,OAAO,KAAK,OAAO,cAAczB,EAAIC,CAAE,CACxC,CAEA,cAAc6kB,EAAgBC,EAAkC,CAC/D,OAAO,KAAK,OAAO,cAAcD,EAAQC,CAAM,CAChD,CAEA,cACCD,EACAC,EACA0N,EACO,CACP,GAAI,CAAC,OAAO,SAAS3N,CAAM,GAAK,CAAC,OAAO,SAASC,CAAM,EAAG,OAC1D,MAAM3I,EAAQ,KAAK,OAAO,aAAA,EACpBpa,EAAO,KAAK,IAAI,KAAMoa,EAAM,IAAI,EAChCkX,EAAK,KAAK,OAAO,YAAA,EACvB,KAAK,aACJ,CACC,QAASxO,EAASwO,EAAG,OAAS,EAAItxB,GAClC,QAAS+iB,EAASuO,EAAG,QAAU,EAAItxB,EAAA,EAEpCywB,CAAA,CAEF,CAEA,gBAAmE,CAClE,OAAO,KAAK,OAAO,eAAA,CACpB,CAEA,cAAcA,EAA6C,CAC1D,MAAMrW,EAAQ,KAAK,OAAO,aAAA,EACtB,KAAK,IAAIA,EAAM,WAAW,EAAI,MAClC,KAAK,aAAa,CAAE,YAAa,CAAA,EAAKqW,CAAU,CACjD,CAEA,oBAA6B,CAC5B,MAAMzwB,EAAO,KAAK,IAAI,KAAM,KAAK,OAAO,aAAA,EAAe,IAAI,EACrDqZ,EAAiB,KAAK,OAAO,YAAc,KAAK,KAAKrZ,CAAI,EACzDquB,EAAOE,GAA4BlV,EAAgB,KAAK,cAAc,EAC5E,OAAOvY,GAAMutB,EAAMvB,GAAmBC,EAAiB,CACxD,CAEA,WAAW0D,EAA6C,CACvD,MAAMhxB,EAAO,KAAK,OAAO,sBAAA,EACnB8xB,EAAK,KAAK,IAAI,EAAG9xB,EAAK,OAAS,CAAC,EAChC+xB,EAAK,KAAK,IAAI,EAAG/xB,EAAK,QAAU,CAAC,EAEjCO,EAAO,KAAK,IAAIuxB,EAAK,KAAK,OAAO,MAAOC,EAAK,KAAK,OAAO,MAAM,EAC/DvxB,EAAW,OAAO,SAASD,CAAI,GAAKA,EAAO,EAAIA,EAAO,EAE5D,KAAK,QAAUC,EACf,KAAK,gBAAA,EACL,MAAMwxB,EAAc3wB,GAAMb,EAAU,KAAK,QAAS,KAAK,OAAO,EACxDyxB,EAAgBH,EAAKE,EACrBE,EAAgBH,EAAKC,EAE3B,KAAK,aACJ,CACC,KAAMA,EACN,SAAU,KAAK,OAAO,MAAQC,GAAiB,GAC/C,SAAU,KAAK,OAAO,OAASC,GAAiB,GAChD,YAAa,CAAA,EAEdlB,CAAA,CAEF,CAEA,OACCmB,EACAxU,EACAC,EACAoT,EACO,CACP,MAAMrW,EAAQ,KAAK,OAAO,aAAA,EACpByX,EAAW/wB,GAAMsZ,EAAM,KAAOwX,EAAQ,KAAK,QAAS,KAAK,OAAO,EACtE,GAAIC,IAAazX,EAAM,KAAM,OAE7B,KAAM,CAAC0I,EAAQC,CAAM,EAAI,KAAK,OAAO,cAAc3F,EAASC,CAAO,EAC7DiU,EAAK,KAAK,OAAO,YAAA,EACjBjrB,EAAK+W,EAAUkU,EAAG,MAAQ,GAC1BhrB,EAAK+W,EAAUiU,EAAG,OAAS,GAC3BrE,EAAMC,GAAU9S,EAAM,WAAW,EACjC+S,EAAM,KAAK,IAAIF,CAAG,EAClBG,EAAM,KAAK,IAAIH,CAAG,EAClB6E,EAAWzrB,EAAKwrB,EAAY1E,EAAO7mB,EAAKurB,EAAYzE,EACpD2E,EAAW1rB,EAAKwrB,EAAYzE,EAAO9mB,EAAKurB,EAAY1E,EACpD6E,EAAclP,EAASgP,EACvBG,EAAclP,EAASgP,EAE7B,KAAK,aACJ,CACC,KAAMF,EACN,QAASG,EAAcV,EAAG,OAAS,EAAIO,GACvC,QAASI,EAAcX,EAAG,QAAU,EAAIO,EAAA,EAEzCpB,CAAA,CAEF,CAEA,gBAAuB,CACtB,MAAM9tB,EAAS,KAAK,cAAA,EACdqgB,EAAW,KAAK,IAAI,KAAMrgB,EAAO,CAAC,EAAIA,EAAO,CAAC,CAAC,EAC/CsgB,EAAW,KAAK,IAAI,KAAMtgB,EAAO,CAAC,EAAIA,EAAO,CAAC,CAAC,EAC/CuvB,EAAUlP,EAAW,GACrBmP,EAAUlP,EAAW,GAErB,CAAC3S,EAASC,CAAO,EAAI,KAAK,OAAO,UAAA,EACjC6hB,EAAQpP,EAAW,GACnBqP,EAAQpP,EAAW,GAEnBqP,EAAaF,EAAQF,EACrBK,EAAa,KAAK,OAAO,MAAQH,EAAQF,EACzCM,EAAaH,EAAQF,EACrBM,EAAa,KAAK,OAAO,OAASJ,EAAQF,EAE1CH,EACLM,GAAcC,EACXzxB,GAAMwP,EAASgiB,EAAYC,CAAU,EACrC,KAAK,OAAO,MAAQ,GAClBN,EACLO,GAAcC,EACX3xB,GAAMyP,EAASiiB,EAAYC,CAAU,EACrC,KAAK,OAAO,OAAS,GAEzB,KAAK,OAAO,UAAUT,EAAaC,CAAW,CAC/C,CAEA,eAAsB,CACrB,KAAK,oBAAoB,KAAK,OAAO,aAAA,CAAc,CACpD,CAEA,YAAqB,CACpB,MAAMjyB,EAAO,KAAK,IAAI,KAAM,KAAK,OAAO,aAAA,EAAe,IAAI,EACrD0yB,EAAU,KAAK,OAAO,YAAc,KAAK,KAAK1yB,CAAI,EACxD,OAAOc,GAAM,KAAK,MAAM4xB,CAAO,EAAG,EAAG,KAAK,OAAO,WAAW,CAC7D,CAEA,eAAwB,CACvB,MAAMjR,EAAU,KAAK,OAAO,eAAA,EAC5B,IAAIrf,EAAO,IACPC,EAAO,IACPC,EAAO,KACPC,EAAO,KACX,SAAW,CAAClB,EAAGC,CAAC,IAAKmgB,EAChBpgB,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GACjBC,EAAIe,IAAMA,EAAOf,GACjBA,EAAIiB,IAAMA,EAAOjB,GAEtB,MAAO,CAACc,EAAMC,EAAMC,EAAMC,CAAI,CAC/B,CAEA,iBAAiBmD,EAAWC,EAAoB,CAC/C,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,EACrE,CAEA,iBAAmC,CAClC,MAAM0Y,EAAO,KAAK,WAAA,EAClB,KAAK,YAAcA,EAEnB,MAAMsU,EAAa,KAAK,cAAA,EAElBvP,EAAa,KAAK,IAAI,EAAG,KAAK,OAAO,YAAc/E,CAAI,EACvDgF,EAAa,KAAK,KAAK,KAAK,OAAO,MAAQD,CAAU,EACrDE,EAAc,KAAK,KAAK,KAAK,OAAO,OAASF,CAAU,EAEvDG,EAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAa,KAAK,OAAO,QAAQ,CAAC,EACjEG,EAAS,KAAK,IAAI,EAAG,KAAK,KAAKF,EAAc,KAAK,OAAO,QAAQ,CAAC,EAElEsP,EAAWD,EAAW,CAAC,EACvBE,EAAWF,EAAW,CAAC,EACvBG,EAAWH,EAAW,CAAC,EACvBI,EAAWJ,EAAW,CAAC,EAEvBK,EAAWlyB,GAChB,KAAK,MAAM8xB,EAAWxP,EAAa,KAAK,OAAO,QAAQ,EACvD,EACAG,EAAS,CAAA,EAEJ0P,EAAWnyB,GAChB,KAAK,OAAOgyB,EAAW,GAAK1P,EAAa,KAAK,OAAO,QAAQ,EAC7D,EACAG,EAAS,CAAA,EAEJ2P,EAAWpyB,GAChB,KAAK,MAAM+xB,EAAWzP,EAAa,KAAK,OAAO,QAAQ,EACvD,EACAI,EAAS,CAAA,EAEJ2P,EAAWryB,GAChB,KAAK,OAAOiyB,EAAW,GAAK3P,EAAa,KAAK,OAAO,QAAQ,EAC7D,EACAI,EAAS,CAAA,EAGV,GAAIwP,EAAWC,GAAYC,EAAWC,EACrC,MAAO,CAAA,EAGR,MAAMC,GAAeR,EAAWE,GAAY,GAAM1P,EAAa,KAAK,OAAO,SACrEiQ,GAAeR,EAAWE,GAAY,GAAM3P,EAAa,KAAK,OAAO,SAErEkQ,EAA2B,CAAA,EACjC,QAAShyB,EAAI4xB,EAAU5xB,GAAK6xB,EAAU7xB,GAAK,EAC1C,QAASD,EAAI2xB,EAAU3xB,GAAK4xB,EAAU5xB,GAAK,EAAG,CAC7C,MAAMmT,EAAOnT,EAAI,KAAK,OAAO,SAAW+hB,EAClC3O,EAAMnT,EAAI,KAAK,OAAO,SAAW8hB,EACjCvB,EAAQ,KAAK,KAAKxgB,EAAI,GAAK,KAAK,OAAO,SAAUgiB,CAAU,EAAID,EAC/DtB,GAAS,KAAK,KAAKxgB,EAAI,GAAK,KAAK,OAAO,SAAUgiB,CAAW,EAAIF,EAEjE/c,GAAKhF,EAAI+xB,EACT9sB,GAAKhF,EAAI+xB,EACfC,EAAQ,KAAK,CACZ,IAAK,GAAGjV,CAAI,IAAIhd,CAAC,IAAIC,CAAC,GACtB,KAAA+c,EACA,EAAAhd,EACA,EAAAC,EACA,OAAQ,CAACkT,EAAMC,EAAKoN,EAAOC,EAAM,EACjC,UAAWzb,GAAKA,GAAKC,GAAKA,GAC1B,IAAKgY,GAAU,KAAK,OAAQD,EAAMhd,EAAGC,CAAC,CAAA,CACtC,CACF,CAGD,OAAAgyB,EAAQ,KAAK,CAAC5tB,EAAGC,IAAMD,EAAE,UAAYC,EAAE,SAAS,EACzC2tB,CACR,CAEA,WAAkB,CACjB,GAAI,KAAK,MAAM,MAAQ,KAAK,cAAe,OAE3C,MAAMC,EAAU,MAAM,KAAK,KAAK,MAAM,SAAS,EAC/CA,EAAQ,KAAK,CAAC7tB,EAAGC,IAAMD,EAAE,CAAC,EAAE,SAAWC,EAAE,CAAC,EAAE,QAAQ,EAEpD,MAAM6tB,EAAc,KAAK,MAAM,KAAO,KAAK,cAC3C,QAAS/vB,EAAI,EAAGA,EAAI+vB,EAAa/vB,GAAK,EAAG,CACxC,KAAM,CAACwoB,EAAKlrB,CAAK,EAAIwyB,EAAQ9vB,CAAC,EAC9B,KAAK,GAAG,cAAc1C,EAAM,OAAO,EACnC,KAAK,MAAM,OAAOkrB,CAAG,CACtB,CACD,CAEA,QAAe,CACd,GAAI,KAAK,WAAa,KAAK,aAAe,KAAK,GAAG,gBAAiB,OACnE,MAAMwH,EAAelM,GAAA,EACrB,KAAK,aAAe,EAEpB,MAAM/qB,EAAK,KAAK,GACVk3B,EAAc,KAAK,YACnBC,EAAe,KAAK,aAE1Bn3B,EAAG,WAAW,IAAM,IAAM,GAAK,CAAC,EAChCA,EAAG,MAAMA,EAAG,gBAAgB,EAE5B,MAAM82B,EAAU,KAAK,gBAAA,EACfX,EAAa,KAAK,cAAA,EAClB5G,EAAc,IAAI,IAAIuH,EAAQ,IAAKp0B,GAASA,EAAK,GAAG,CAAC,EAE3D1C,EAAG,WAAWk3B,EAAY,OAAO,EACjCl3B,EAAG,gBAAgBk3B,EAAY,GAAG,EAClCl3B,EAAG,iBAAiBk3B,EAAY,QAAS,GAAO,KAAK,OAAO,WAAW,EACvEl3B,EAAG,UAAUk3B,EAAY,SAAU,CAAC,EACpCl3B,EAAG,UAAUk3B,EAAY,YAAa,KAAK,mBAAmB,UAAU,EACxEl3B,EAAG,UAAUk3B,EAAY,UAAW,KAAK,mBAAmB,QAAQ,EACpEl3B,EAAG,UAAUk3B,EAAY,YAAa,KAAK,mBAAmB,UAAU,EAExE,MAAME,EAA8B,CAAA,EACpC,SAAW,CAAA,CAAGC,CAAM,IAAK,KAAK,MACzB9H,EAAY,IAAI8H,EAAO,GAAG,GACzB,KAAK,iBAAiBA,EAAO,OAAQlB,CAAU,GACpDiB,EAAc,KAAKC,CAAM,EAG1BD,EAAc,KAAK,CAACluB,EAAGC,IAAMD,EAAE,KAAOC,EAAE,IAAI,EAC5C,UAAWkuB,KAAUD,EACpBC,EAAO,SAAW,KAAK,YACvBr3B,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,WAAYq3B,EAAO,OAAO,EAC5Cr3B,EAAG,UACFk3B,EAAY,QACZG,EAAO,OAAO,CAAC,EACfA,EAAO,OAAO,CAAC,EACfA,EAAO,OAAO,CAAC,EACfA,EAAO,OAAO,CAAC,CAAA,EAEhBr3B,EAAG,WAAWA,EAAG,eAAgB,EAAG,CAAC,EAGtC,IAAIs3B,EAAgB,EACpB,MAAMC,EAAgC,CAAA,EACtC,UAAW70B,KAAQo0B,EAAS,CAC3B,MAAMO,EAAS,KAAK,MAAM,IAAI30B,EAAK,GAAG,EACtC,GAAI,CAAC20B,EAAQ,CACZE,EAAa,KAAK70B,CAAI,EACtB,QACD,CACA20B,EAAO,SAAW,KAAK,YACvBr3B,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,WAAYq3B,EAAO,OAAO,EAC5Cr3B,EAAG,UACFk3B,EAAY,QACZG,EAAO,OAAO,CAAC,EACfA,EAAO,OAAO,CAAC,EACfA,EAAO,OAAO,CAAC,EACfA,EAAO,OAAO,CAAC,CAAA,EAEhBr3B,EAAG,WAAWA,EAAG,eAAgB,EAAG,CAAC,EACrCs3B,GAAiB,CAClB,CACA,KAAK,cAAc,SAASC,CAAY,EAExCv3B,EAAG,YAAYA,EAAG,WAAY,IAAI,EAClCA,EAAG,gBAAgB,IAAI,EAEvB,IAAIw3B,EAAiB,EAuBrB,GAtBI,KAAK,WAAa,IACrBx3B,EAAG,OAAOA,EAAG,KAAK,EAClBA,EAAG,UAAUA,EAAG,IAAKA,EAAG,mBAAmB,EAC3CA,EAAG,WAAWm3B,EAAa,OAAO,EAClCn3B,EAAG,gBAAgBm3B,EAAa,GAAG,EACnCn3B,EAAG,iBAAiBm3B,EAAa,QAAS,GAAO,KAAK,OAAO,WAAW,EACxEn3B,EAAG,UAAUm3B,EAAa,WAAY,KAAK,oBAAoB,EAC/Dn3B,EAAG,UAAUm3B,EAAa,kBAAmB,KAAK,gBAAgB,EAClEn3B,EAAG,UAAUm3B,EAAa,aAAc,KAAK,gBAAgB,EAC7Dn3B,EAAG,UAAUm3B,EAAa,SAAU,CAAC,EACrCn3B,EAAG,cAAcA,EAAG,QAAQ,EAC5BA,EAAG,YAAYA,EAAG,WAAYm3B,EAAa,cAAc,EACrD,KAAK,gBACRn3B,EAAG,aAAaA,EAAG,OAAQ,KAAK,WAAYA,EAAG,aAAc,CAAC,EAE9DA,EAAG,WAAWA,EAAG,OAAQ,EAAG,KAAK,UAAU,EAE5CA,EAAG,YAAYA,EAAG,WAAY,IAAI,EAClCA,EAAG,gBAAgB,IAAI,EACvBw3B,EAAiB,KAAK,YAGnB,KAAK,QAAS,CACjB,MAAMC,EAAiB,KAAK,cAAc,YAAA,EACpCC,EAAYJ,EACZK,EAAcJ,EAAa,OAC3BK,EACLR,EAAc,OAASE,GAAiBE,EAAiB,EAAI,EAAI,GAClE,KAAK,QAAQ,CACZ,KAAM,KAAK,YACX,QAASV,EAAQ,OACjB,SAAUQ,EACV,OAAQE,EACR,SAAUJ,EAAc,OACxB,MAAO,KAAK,MAAM,KAClB,SAAUK,EAAe,SACzB,OAAQA,EAAe,OACvB,QAASA,EAAe,QACxB,OAAQA,EAAe,OACvB,QAASA,EAAe,QACxB,UAAAC,EACA,YAAAC,EACA,UAAAC,EACA,QAAS7M,KAAUkM,CAAA,CACnB,CACF,CACD,CAEA,eAAsB,CAEpB,KAAK,QAAU,MACf,KAAK,WACL,KAAK,aACL,KAAK,GAAG,cAAA,IAGT,KAAK,MAAQ,sBAAsB,IAAM,CACxC,KAAK,MAAQ,KACb,KAAK,OAAA,CACN,CAAC,EACF,CAEA,QAAe,CACd,MAAMh0B,EAAO,KAAK,OAAO,sBAAA,EACnB0hB,EAAO,KAAK,IAAI,EAAG1hB,EAAK,OAAS,KAAK,OAAO,aAAe,CAAC,EAC7D2hB,EAAO,KAAK,IAAI,EAAG3hB,EAAK,QAAU,KAAK,OAAO,cAAgB,CAAC,EAC/DG,EAAM,KAAK,IAAI,EAAG,OAAO,kBAAoB,CAAC,EAE9CyhB,EAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOvhB,CAAG,CAAC,EAC3C0hB,EAAS,KAAK,IAAI,EAAG,KAAK,MAAMF,EAAOxhB,CAAG,CAAC,GAE7C,KAAK,OAAO,QAAUyhB,GAAU,KAAK,OAAO,SAAWC,KAC1D,KAAK,OAAO,MAAQD,EACpB,KAAK,OAAO,OAASC,GAGtB,KAAK,OAAO,YAAYH,EAAMC,CAAI,EAClC,KAAK,GAAG,SAAS,EAAG,EAAGC,EAAQC,CAAM,EACrC,KAAK,cAAA,CACN,CAEA,cAAc1F,EAA2B,CACxC,GAAI,KAAK,kBAAmB,OAC5B,MAAMyY,EAAc,KAAK,iBAAmBzY,EAAM,SAAWA,EAAM,UAC/CA,EAAM,SAAW,GAAMyY,GAAezY,EAAM,SAAW,KAE3E,KAAK,oBAAA,EACDyY,GACHzY,EAAM,eAAA,EAEP,KAAK,SAAW,GAChB,KAAK,gBACJyY,EAAc,SAAW,MAC1B,KAAK,UAAYzY,EAAM,UACvB,KAAK,aAAeA,EAAM,QAC1B,KAAK,aAAeA,EAAM,QAC1B,KAAK,mBACJ,KAAK,kBAAoB,SACtB,KAAK,mBAAmBA,EAAM,QAASA,EAAM,OAAO,EACpD,KACJ,KAAK,OAAO,UAAU,IAAI,UAAU,EACpC,KAAK,OAAO,kBAAkBA,EAAM,SAAS,EAC9C,CAEA,cAAcA,EAA2B,CAExC,GADI,KAAK,mBACL,CAAC,KAAK,UAAYA,EAAM,YAAc,KAAK,UAAW,OAE1D,MAAMvV,EAAKuV,EAAM,QAAU,KAAK,aAC1BtV,EAAKsV,EAAM,QAAU,KAAK,aAIhC,GAHA,KAAK,aAAeA,EAAM,QAC1B,KAAK,aAAeA,EAAM,QAEtB,KAAK,kBAAoB,SAAU,CACtC,MAAM0Y,EAAY,KAAK,mBAAmB1Y,EAAM,QAASA,EAAM,OAAO,EAChE2Y,EAAY,KAAK,mBAEvB,GADA,KAAK,mBAAqBD,EACtBC,IAAc,KAAM,CACvB,MAAMC,EAAWF,EAAYC,EACvBpwB,EAAQ,KAAK,MAAM,KAAK,IAAIqwB,CAAQ,EAAG,KAAK,IAAIA,CAAQ,CAAC,EAEzDC,EAEF,KAAK,mCACN5H,GAEGzS,EAAQ,KAAK,OAAO,aAAA,EAC1B,KAAK,OAAO,aAAa,CACxB,YACCA,EAAM,YAAgBjW,EAAQ,IAAO,KAAK,GAAMswB,CAAA,CACjD,CACF,CACD,KAAO,CACN,MAAMra,EAAQ,KAAK,OAAO,aAAA,EACpBpa,EAAO,KAAK,IAAI,KAAMoa,EAAM,IAAI,EAChC6S,EAAMC,GAAU9S,EAAM,WAAW,EACjC+S,EAAM,KAAK,IAAIF,CAAG,EAClBG,EAAM,KAAK,IAAIH,CAAG,EAClB6E,GAAWzrB,EAAK8mB,EAAM7mB,EAAK8mB,GAAOptB,EAClC+xB,GAAW1rB,EAAK+mB,EAAM9mB,EAAK6mB,GAAOntB,EACxC,KAAK,OAAO,aAAa,CACxB,QAASoa,EAAM,QAAU0X,EACzB,QAAS1X,EAAM,QAAU2X,CAAA,CACzB,CACF,CAEA,KAAK,eAAA,EACL,KAAK,cAAA,EACL,KAAK,cAAA,CACN,CAEA,YAAYnW,EAA2B,CAClC,KAAK,mBACLA,EAAM,YAAc,KAAK,WAC7B,KAAK,WAAA,CACN,CAEA,QAAQA,EAAyB,CAChC,GAAI,KAAK,kBAAmB,CAC3BA,EAAM,eAAA,EACN,MACD,CAEAA,EAAM,eAAA,EACN,MAAMnc,EAAO,KAAK,OAAO,sBAAA,EACnB4B,EAAIua,EAAM,QAAUnc,EAAK,KACzB6B,EAAIsa,EAAM,QAAUnc,EAAK,IACzBmyB,EAAShW,EAAM,OAAS,EAAI,KAAO,IACzC,KAAK,OAAOgW,EAAQvwB,EAAGC,CAAC,CACzB,CAEA,cAAcsa,EAAyB,CACtC,GAAI,KAAK,kBAAmB,OAC5B,MAAMnc,EAAO,KAAK,OAAO,sBAAA,EACnB4B,EAAIua,EAAM,QAAUnc,EAAK,KACzB6B,EAAIsa,EAAM,QAAUnc,EAAK,IAC/B,KAAK,OAAOmc,EAAM,SAAW,GAAM,KAAMva,EAAGC,CAAC,CAC9C,CAEA,cAAcsa,EAAyB,EAClC,KAAK,UAAYA,EAAM,SAAWA,EAAM,UAC3CA,EAAM,eAAA,CAER,CAEQ,mBAAmBA,EAAoB,CAC9CA,EAAM,eAAA,EACF,OAAK,WAAa,KAAK,eAC3B,KAAK,YAAc,GACnB,KAAK,kBAAoB,GAErB,KAAK,QAAU,OAClB,qBAAqB,KAAK,KAAK,EAC/B,KAAK,MAAQ,MAEd,KAAK,oBAAA,EAEL,KAAK,WAAA,EACL,KAAK,cAAc,MAAA,EACnB,KAAK,MAAM,MAAA,EACX,KAAK,gBAAA,EACN,CAEQ,uBAAuB8Y,EAAqB,CAC/C,KAAK,YACT,KAAK,YAAc,GACnB,KAAK,MAAM,MAAA,EAEX,KAAK,YAAc,KAAK,gBAAA,EACxB,KAAK,aAAe,KAAK,iBAAA,EACzB,KAAK,kBAAoB,GAErB,KAAK,kBAAoB,KAAK,iBAAiB,OAAS,GAC3D,KAAK,gBAAgB,KAAK,gBAAgB,EAEvC,KAAK,cACR,KAAK,aAAa,KAAK,aAAa,EAEpC,KAAK,WAAa,EAGnB,KAAK,OAAA,EACL,KAAK,cAAA,EACL,KAAK,oBAAA,EACN,CAEA,SAAgB,CACf,GAAI,MAAK,UAyBT,IAxBA,KAAK,UAAY,GAEb,KAAK,QAAU,OAClB,qBAAqB,KAAK,KAAK,EAC/B,KAAK,MAAQ,MAEd,KAAK,oBAAA,EAEL,KAAK,eAAe,WAAA,EACpB,KAAK,OAAO,oBAAoB,cAAe,KAAK,gBAAgB,EACpE,KAAK,OAAO,oBAAoB,cAAe,KAAK,gBAAgB,EACpE,KAAK,OAAO,oBAAoB,YAAa,KAAK,cAAc,EAChE,KAAK,OAAO,oBAAoB,gBAAiB,KAAK,cAAc,EACpE,KAAK,OAAO,oBAAoB,QAAS,KAAK,UAAU,EACxD,KAAK,OAAO,oBAAoB,WAAY,KAAK,gBAAgB,EACjE,KAAK,OAAO,oBAAoB,cAAe,KAAK,gBAAgB,EACpE,KAAK,OAAO,oBAAoB,mBAAoB,KAAK,gBAAgB,EACzE,KAAK,OAAO,oBACX,uBACA,KAAK,oBAAA,EAEN,KAAK,WAAA,EACL,KAAK,cAAc,QAAA,EAEf,CAAC,KAAK,aAAe,CAAC,KAAK,GAAG,gBAAiB,CAClD,SAAW,CAAA,CAAG3zB,CAAK,IAAK,KAAK,MAC5B,KAAK,GAAG,cAAcA,EAAM,OAAO,EAEpC,KAAK,GAAG,aAAa,KAAK,YAAY,GAAG,EACzC,KAAK,GAAG,kBAAkB,KAAK,YAAY,GAAG,EAC9C,KAAK,GAAG,cAAc,KAAK,YAAY,OAAO,EAE9C,KAAK,GAAG,aAAa,KAAK,aAAa,SAAS,EAChD,KAAK,GAAG,aAAa,KAAK,aAAa,UAAU,EACjD,KAAK,GAAG,aAAa,KAAK,aAAa,cAAc,EACrD,KAAK,GAAG,aAAa,KAAK,aAAa,WAAW,EAClD,KAAK,GAAG,cAAc,KAAK,aAAa,cAAc,EACtD,KAAK,GAAG,kBAAkB,KAAK,aAAa,GAAG,EAC/C,KAAK,GAAG,cAAc,KAAK,aAAa,OAAO,CAChD,CACA,KAAK,MAAM,MAAA,EACZ,CAEQ,iBAAqC,CAC5C,MAAMvE,EAAK,KAAK,GAmDVU,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,EAC5Cm4B,EAAUx3B,GAAuBX,EAAIU,EAAS,SAAS,EACvD03B,EAAUz3B,GAAuBX,EAAIU,EAAS,SAAS,EACvD23B,EAAW13B,GAAuBX,EAAIU,EAAS,UAAU,EACzD43B,EAAc33B,GAAuBX,EAAIU,EAAS,aAAa,EAC/D63B,EAAY53B,GAAuBX,EAAIU,EAAS,WAAW,EAC3D83B,EAAc73B,GAAuBX,EAAIU,EAAS,aAAa,EAE/DuB,EAAMjC,EAAG,kBAAA,EACTy4B,EAAMz4B,EAAG,aAAA,EACf,GAAI,CAACiC,GAAO,CAACw2B,EACZ,MAAM,IAAI,MAAM,0BAA0B,EAG3Cz4B,EAAG,gBAAgBiC,CAAG,EACtBjC,EAAG,WAAWA,EAAG,aAAcy4B,CAAG,EAClCz4B,EAAG,WACFA,EAAG,aACH,IAAI,aAAa,CAAC,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,CAAC,CAAC,EACjEA,EAAG,WAAA,EAGJ,MAAM04B,EAAQ14B,EAAG,kBAAkBU,EAAS,OAAO,EAC7Ci4B,EAAM34B,EAAG,kBAAkBU,EAAS,KAAK,EAC/C,GAAIg4B,EAAQ,GAAKC,EAAM,EACtB,MAAM,IAAI,MAAM,8BAA8B,EAE/C,OAAA34B,EAAG,wBAAwB04B,CAAK,EAChC14B,EAAG,wBAAwB24B,CAAG,EAC9B34B,EAAG,oBAAoB04B,EAAO,EAAG14B,EAAG,MAAO,GAAO,GAAI,CAAC,EACvDA,EAAG,oBAAoB24B,EAAK,EAAG34B,EAAG,MAAO,GAAO,GAAI,CAAC,EAErDA,EAAG,gBAAgB,IAAI,EACvBA,EAAG,WAAWA,EAAG,aAAc,IAAI,EAE5B,CACN,QAAAU,EACA,IAAAuB,EACA,IAAAw2B,EACA,QAAAN,EACA,QAAAC,EACA,SAAAC,EACA,YAAAC,EACA,UAAAC,EACA,YAAAC,CAAA,CAEF,CAEQ,kBAAiC,CACxC,MAAMx4B,EAAK,KAAK,GAuDVU,EAAUL,GAAcL,EArDV;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,MAoCsC,EACtDm4B,EAAUx3B,GAAuBX,EAAIU,EAAS,SAAS,EACvDk4B,EAAaj4B,GAAuBX,EAAIU,EAAS,YAAY,EAC7Dm4B,EAAoBl4B,GAAuBX,EAAIU,EAAS,mBAAmB,EAC3Eo4B,EAAWn4B,GAAuBX,EAAIU,EAAS,UAAU,EACzDq4B,EAAep4B,GAAuBX,EAAIU,EAAS,cAAc,EAEjEuB,EAAMjC,EAAG,kBAAA,EACTg5B,EAAYh5B,EAAG,aAAA,EACfi5B,EAAaj5B,EAAG,aAAA,EAChBk5B,EAAiBl5B,EAAG,aAAA,EACpBm5B,EAAcn5B,EAAG,aAAA,EACjBo5B,EAAiBp5B,EAAG,cAAA,EAC1B,GAAI,CAACiC,GAAO,CAAC+2B,GAAa,CAACC,GAAc,CAACC,GAAkB,CAACC,GAAe,CAACC,EAC5E,MAAM,IAAI,MAAM,gCAAgC,EAGjDp5B,EAAG,gBAAgBiC,CAAG,EAEtBjC,EAAG,WAAWA,EAAG,aAAcg5B,CAAS,EACxCh5B,EAAG,WAAWA,EAAG,aAAc,EAAGA,EAAG,YAAY,EACjD,MAAMq5B,EAASr5B,EAAG,kBAAkBU,EAAS,WAAW,EACxD,GAAI24B,EAAS,EACZ,MAAM,IAAI,MAAM,oCAAoC,EAErDr5B,EAAG,wBAAwBq5B,CAAM,EACjCr5B,EAAG,oBAAoBq5B,EAAQ,EAAGr5B,EAAG,MAAO,GAAO,EAAG,CAAC,EAEvDA,EAAG,WAAWA,EAAG,aAAci5B,CAAU,EACzCj5B,EAAG,WAAWA,EAAG,aAAc,EAAGA,EAAG,YAAY,EACjD,MAAMs5B,EAAUt5B,EAAG,kBAAkBU,EAAS,OAAO,EACrD,GAAI44B,EAAU,EACb,MAAM,IAAI,MAAM,gCAAgC,EAEjDt5B,EAAG,wBAAwBs5B,CAAO,EAClCt5B,EAAG,qBAAqBs5B,EAAS,EAAGt5B,EAAG,eAAgB,EAAG,CAAC,EAE3DA,EAAG,WAAWA,EAAG,aAAck5B,CAAc,EAC7Cl5B,EAAG,WAAWA,EAAG,aAAc,EAAGA,EAAG,YAAY,EACjD,MAAMu5B,EAAcv5B,EAAG,kBAAkBU,EAAS,WAAW,EAC7D,GAAI64B,EAAc,EACjB,MAAM,IAAI,MAAM,qCAAqC,EAEtD,OAAAv5B,EAAG,wBAAwBu5B,CAAW,EACtCv5B,EAAG,qBAAqBu5B,EAAa,EAAGv5B,EAAG,cAAe,EAAG,CAAC,EAE9DA,EAAG,WAAWA,EAAG,qBAAsBm5B,CAAW,EAClDn5B,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,WAAYo5B,CAAc,EAC5Cp5B,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,WACFA,EAAG,WACH,EACAA,EAAG,KACH,EACA,EACA,EACAA,EAAG,KACHA,EAAG,cACH,IAAI,WAAW,CAAC,IAAK,IAAK,IAAK,GAAG,CAAC,CAAA,EAEpCA,EAAG,YAAYA,EAAG,WAAY,IAAI,EAE3B,CACN,QAAAU,EACA,IAAAuB,EACA,UAAA+2B,EACA,WAAAC,EACA,eAAAC,EACA,YAAAC,EACA,eAAAC,EACA,QAAAjB,EACA,WAAAS,EACA,kBAAAC,EACA,SAAAC,EACA,aAAAC,CAAA,CAEF,CAEQ,iBAAiBr2B,EAAqBI,EAA2B,CACxE,GAAI,KAAK,WAAa,KAAK,aAAe,KAAK,GAAG,gBAAiB,CAClEA,EAAO,MAAA,EACP,MACD,CACA,GAAI,KAAK,MAAM,IAAIJ,EAAK,GAAG,EAAG,CAC7BI,EAAO,MAAA,EACP,MACD,CAEA,MAAMC,EAAU,KAAK,wBAAwBD,CAAM,EACnDA,EAAO,MAAA,EACFC,IAEL,KAAK,MAAM,IAAIL,EAAK,IAAK,CACxB,IAAKA,EAAK,IACV,QAAAK,EACA,OAAQL,EAAK,OACb,KAAMA,EAAK,KACX,SAAU,KAAK,WAAA,CACf,EACD,KAAK,UAAA,EACL,KAAK,cAAA,EACN,CAEQ,wBAAwBI,EAA0C,CACzE,GAAI,KAAK,aAAe,KAAK,GAAG,cAAA,EAAiB,OAAO,KACxD,MAAM9C,EAAK,KAAK,GACV+C,EAAU/C,EAAG,cAAA,EACnB,OAAK+C,GAEL/C,EAAG,YAAYA,EAAG,WAAY+C,CAAO,EACrC/C,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,cAAe8C,CAAM,EAC1E9C,EAAG,YAAYA,EAAG,WAAY,IAAI,EAC3B+C,GAVc,IAWtB,CACD,CC1vDA,MAAMy2B,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,GAA0B,GAC1BC,GAA0B,KAC1BC,GAA+B,EAC/BC,GAAiC,EACjCC,GAAyB,GACzBC,GAA4B,IAC5BC,GAA4B,KAC5BC,GAA+C,IAC/C7oB,GAAuC,GAE7C,IAAI8oB,GAA6D,KACjE,MAAMC,OAA0B,IAwFhC,SAAS3S,GAAmBC,EAAiC,CAC3D,MAAMC,EAAkBD,EAAU,qBAAqB,WAAaA,EAAU,UAAU,OAAS,OAAO,iBACxG,OAAO,KAAK,IAAI,EAAG,KAAK,IAAI,KAAK,MAAMA,EAAU,OAAS,CAAC,EAAG,KAAK,OAAOA,EAAU,WAAW,QAAU,GAAK,CAAC,EAAGA,EAAU,gBAAgB,QAAU,EAAGC,CAAe,CAAC,CAC3K,CAEA,SAAS0S,GAAoB5O,EAAsC+I,EAA0C,CAC3G,GAAI,EAAE/I,aAAuB,cAAgB+I,GAAgB,GAAK/I,EAAY,SAAW,EACvF,OAAO,KAGT,IAAI6O,EAAe,GACnB,QAASvzB,EAAI,EAAGA,EAAI0kB,EAAY,OAAQ1kB,GAAK,EAC3C,GAAI,EAAA0kB,EAAY1kB,CAAC,EAAIytB,GACrB,CAAA8F,EAAe,GACf,MAEF,GAAI,CAACA,EACH,OAAO7O,EAGT,MAAM/mB,EAAM,IAAI,YAAY+mB,EAAY,MAAM,EAC9C,IAAInO,EAAS,EACb,QAASvW,EAAI,EAAGA,EAAI0kB,EAAY,OAAQ1kB,GAAK,EAAG,CAC9C,MAAMknB,EAAMxC,EAAY1kB,CAAC,EACrBknB,GAAOuG,IACX9vB,EAAI4Y,CAAM,EAAI2Q,EACd3Q,GAAU,EACZ,CACA,OAAO5Y,EAAI,SAAS,EAAG4Y,CAAM,CAC/B,CAEA,SAASid,GAAwBv6B,EAA+B0rB,EAA8B,CAC5F,GAAI,CAAC1rB,GAAU0rB,GAAgB,EAAG,MAAO,KACzC,MAAMvgB,EAAO,KAAK,IAAI,EAAGnL,EAAO,MAAQA,EAAO,MAAM,EAE/Ckc,EADa,KAAK,KAAK/Q,EAAO,KAAK,IAAI,EAAGugB,CAAY,CAAC,EACpCmO,GACzB,OAAO,KAAK,IAAIF,GAAyB,KAAK,IAAIC,GAAyB1d,CAAG,CAAC,CACjF,CAEA,SAASse,GAAuB9S,EAA4C1nB,EAAyD,CACnI,GAAI,CAAC0nB,GAAa,CAACA,EAAU,WAAa,CAACA,EAAU,eACnD,OAAO,KAGT,MAAMuD,EAAYxD,GAAmBC,CAAS,EAC9C,GAAIuD,GAAa,EACf,OAAO,KAGT,MAAMlD,EAAYL,EAAU,UAAU,SAAS,EAAGuD,EAAY,CAAC,EACzDyB,EAAMhF,EAAU,eAAe,aAAeA,EAAU,IAAI,QAAUuD,EAAYvD,EAAU,IAAI,SAAS,EAAGuD,CAAS,EAAI,KACzHQ,EAAc4O,GAAoB3S,EAAU,YAAauD,CAAS,EAClES,EAAeD,EAAcA,EAAY,OAASR,EACxD,GAAIS,IAAiB,EACnB,OAAO,KAGT,MAAM+O,EAAWF,GAAwBv6B,EAAQ0rB,CAAY,EACvDgP,MAAc,IAEdC,EAAchP,GAA6B,CAC/C,MAAM/V,EAAKmS,EAAU4D,EAAa,CAAC,EAC7B9V,EAAKkS,EAAU4D,EAAa,EAAI,CAAC,EACvC,GAAI,CAAC,OAAO,SAAS/V,CAAE,GAAK,CAAC,OAAO,SAASC,CAAE,EAAG,OAElD,MAAM+kB,EAAQ,KAAK,MAAMhlB,EAAK6kB,CAAQ,EAChCI,EAAQ,KAAK,MAAMhlB,EAAK4kB,CAAQ,EACtC,IAAIK,EAASJ,EAAQ,IAAIE,CAAK,EACzBE,IACHA,MAAa,IACbJ,EAAQ,IAAIE,EAAOE,CAAM,GAE3B,MAAMC,EAASD,EAAO,IAAID,CAAK,EAC3BE,EACFA,EAAO,KAAKpP,CAAU,EAEtBmP,EAAO,IAAID,EAAO,CAAClP,CAAU,CAAC,CAElC,EAEA,GAAIF,EACF,QAAS1kB,EAAI,EAAGA,EAAI0kB,EAAY,OAAQ1kB,GAAK,EAC3C4zB,EAAWlP,EAAY1kB,CAAC,GAAK,CAAC,MAGhC,SAASA,EAAI,EAAGA,EAAIkkB,EAAWlkB,GAAK,EAClC4zB,EAAW5zB,CAAC,EAIhB,OAAI2zB,EAAQ,OAAS,EACZ,KAGF,CACL,SAAAD,EACA,UAAAxP,EACA,UAAAlD,EACA,IAAA2E,EACA,QAAAgO,CAAA,CAEJ,CAEA,SAASM,GAAgBlgB,EAAmBH,EAAgC,CAC1E,OAAOG,EAAO,IAAMH,CACtB,CAEA,SAASvW,GAAMC,EAAeC,EAAaC,EAAqB,CAC9D,OAAO,KAAK,IAAID,EAAK,KAAK,IAAIC,EAAKF,CAAK,CAAC,CAC3C,CAEA,SAAS42B,GAAaz1B,EAAmB,CACvC,MAAMb,EAAIP,GAAMoB,EAAG,EAAG,CAAC,EACvB,OAAOb,EAAIA,GAAK,EAAI,EAAIA,EAC1B,CAEA,SAASu2B,GAAiB72B,EAAuC,CAC/D,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,OAAS,EAAG,OAAO,KACtD,MAAMM,EAAI,OAAON,EAAM,CAAC,CAAC,EACnBO,EAAI,OAAOP,EAAM,CAAC,CAAC,EACzB,MAAI,CAAC,OAAO,SAASM,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,CAEA,SAASmS,GAAaxR,EAA+C,CACnE,GAAIA,EAAK,SAAW,EAAG,OAAO,KAC9B,IAAII,EAAO,IACX,UAAWV,KAASM,EACdN,EAAM,CAAC,EAAIU,IAAMA,EAAOV,EAAM,CAAC,GAErC,GAAI,CAAC,OAAO,SAASU,CAAI,EAAG,OAAO,KAEnC,IAAID,EAAO,IACPE,EAAO,KACX,UAAWX,KAASM,EACd,KAAK,IAAIN,EAAM,CAAC,EAAIU,CAAI,EAAIo0B,KAC5B90B,EAAM,CAAC,EAAIS,IAAMA,EAAOT,EAAM,CAAC,GAC/BA,EAAM,CAAC,EAAIW,IAAMA,EAAOX,EAAM,CAAC,IAErC,MAAI,CAAC,OAAO,SAASS,CAAI,GAAK,CAAC,OAAO,SAASE,CAAI,EAAU,KACtD,EAAEF,EAAOE,GAAQ,GAAKD,CAAI,CACnC,CAEA,SAASw1B,GAAiCjuB,EAAuD,CAC/F,IAAI+J,EAA8B,KAClC,UAAWvL,KAAWwB,EAAU,CAC9B,MAAMgK,EAASH,GAAarL,EAAQ,KAAK,EACpCwL,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,CAEA,SAASmkB,GAAuBxlB,EAAYC,EAAYgb,EAAYE,EAAYD,EAAYE,EAAoB,CAC9G,MAAMxnB,EAAMsnB,EAAKD,EACXpnB,EAAMunB,EAAKD,EACXsK,EAAW7xB,EAAMA,EAAMC,EAAMA,EACnC,GAAI4xB,GAAY,MAAO,CACrB,MAAM1xB,EAAKiM,EAAKib,EACVjnB,EAAKiM,EAAKkb,EAChB,OAAOpnB,EAAKA,EAAKC,EAAKA,CACxB,CACA,MAAMpE,EAAIpB,KAAQwR,EAAKib,GAAMrnB,GAAOqM,EAAKkb,GAAMtnB,GAAO4xB,EAAU,EAAG,CAAC,EAC9DpV,EAAK4K,EAAKrnB,EAAMhE,EAChB0gB,EAAK6K,EAAKtnB,EAAMjE,EAChBmE,EAAKiM,EAAKqQ,EACVrc,EAAKiM,EAAKqQ,EAChB,OAAOvc,EAAKA,EAAKC,EAAKA,CACxB,CAEA,SAAS0xB,GAAgB32B,EAAWC,EAAWW,EAAwBg2B,EAAgC,CACrG,QAAS,EAAI,EAAG,EAAIh2B,EAAK,OAAQ,GAAK,EAAG,CACvC,MAAML,EAAOK,EAAK,EAAI,CAAC,EACjBpE,EAAOoE,EAAK,CAAC,EACnB,GAAI61B,GAAuBz2B,EAAGC,EAAGM,EAAK,CAAC,EAAGA,EAAK,CAAC,EAAG/D,EAAK,CAAC,EAAGA,EAAK,CAAC,CAAC,GAAKo6B,EACtE,MAAO,EAEX,CACA,MAAO,EACT,CAEA,SAASC,GAA0B72B,EAAWC,EAAW8G,EAA6B+vB,EAA8B,CAClH,GAAI92B,EAAI+G,EAAQ,KAAO+vB,GAAe92B,EAAI+G,EAAQ,KAAO+vB,GAAe72B,EAAI8G,EAAQ,KAAO+vB,GAAe72B,EAAI8G,EAAQ,KAAO+vB,EAC3H,MAAO,GAET,MAAMF,EAAgBE,EAAcA,EACpC,GAAIH,GAAgB32B,EAAGC,EAAG8G,EAAQ,MAAO6vB,CAAa,EAAG,MAAO,GAChE,UAAWvuB,KAAQtB,EAAQ,MACzB,GAAI4vB,GAAgB32B,EAAGC,EAAGoI,EAAMuuB,CAAa,EAAG,MAAO,GAEzD,MAAO,EACT,CAEA,SAASG,IAA0D,CACjE,GAAIvB,GAA2B,OAAOA,GACtC,GAAI,OAAO,SAAa,IAAa,OAAO,KAE5C,MAAMjmB,EADS,SAAS,cAAc,QAAQ,EAC3B,WAAW,IAAI,EAClC,OAAKA,GACLimB,GAA4BjmB,EACrBimB,IAFU,IAGnB,CAEA,SAASwB,GAAsBhkB,EAAeD,EAAsC,CAClF,MAAM6X,EAAM,GAAG7X,EAAW,UAAU,IAAIA,EAAW,QAAQ,IAAIA,EAAW,UAAU,IAAIC,CAAK,GACvFwf,EAASiD,GAAoB,IAAI7K,CAAG,EAC1C,GAAI4H,IAAW,OAAW,OAAOA,EAEjC,MAAMplB,EAAW4F,EAAM,OAASD,EAAW,SAAWsiB,GAChD9lB,EAAMwnB,GAAA,EACZ,IAAIz6B,EAAQ8Q,EACZ,GAAImC,EAAK,CACPA,EAAI,KAAO,GAAGwD,EAAW,UAAU,IAAIA,EAAW,QAAQ,MAAMA,EAAW,UAAU,GACrF,MAAMkkB,EAAW1nB,EAAI,YAAYyD,CAAK,EAAE,MACpC,OAAO,SAASikB,CAAQ,GAAKA,GAAY,IAC3C36B,EAAQ26B,EAEZ,CAEA,OAAIxB,GAAoB,KAAOH,IAC7BG,GAAoB,MAAA,EAEtBA,GAAoB,IAAI7K,EAAKtuB,CAAK,EAC3BA,CACT,CAEA,SAAS46B,GACP/gB,EACAghB,EACAtU,EACA9P,EACAF,EACAC,EACS,CACT,GAAI,CAACqD,EAAO,OAAS,CAACA,EAAO,YAAa,MAAO,GAEjD,MAAM4D,EAAewc,GAAiB1T,EAAS,cAAc1M,EAAO,YAAY,CAAC,EAAGA,EAAO,YAAY,CAAC,CAAC,CAAC,EAC1G,GAAI,CAAC4D,EAAc,MAAO,GAG1B,MAAM9G,EADY+jB,GAAsB7gB,EAAO,MAAOpD,CAAU,EACnCA,EAAW,SAAW,EAC7CG,EAAYH,EAAW,SAAWA,EAAW,SAAW,EAExD/S,EAAIP,GAAMsa,EAAa,CAAC,EAAG9G,EAAW,GAAM,EAAGJ,EAAcI,EAAW,GAAM,CAAC,EAC/EhT,EAAIR,GAAMsa,EAAa,CAAC,EAAIhH,EAAW,QAASG,EAAY,GAAM,EAAGJ,EAAeI,EAAY,GAAM,CAAC,EACvGC,EAAOnT,EAAIiT,EAAW,GACtBuN,EAAQxgB,EAAIiT,EAAW,GACvBG,EAAMnT,EAAIiT,EAAY,GACtBuN,EAASxgB,EAAIiT,EAAY,GAE/B,OAAOikB,EAAY,CAAC,GAAKhkB,GAAQgkB,EAAY,CAAC,GAAK3W,GAAS2W,EAAY,CAAC,GAAK/jB,GAAO+jB,EAAY,CAAC,GAAK1W,CACzG,CAEA,SAAS2W,GAAkBxO,EAA2C,CACpE,MAAM7oB,EAA2B,CAAA,EACjC,QAASqC,EAAI,EAAGA,EAAIwmB,EAAQ,OAAQxmB,GAAK,EAAG,CAC1C,MAAM+T,EAASyS,EAAQxmB,CAAC,EAClBmG,EAAWR,GAAmB,CAACoO,GAAQ,WAA6C,CAAC,EAC3F,GAAI5N,EAAS,SAAW,EAAG,SAC3B,MAAMyK,EAAQ,OAAOmD,GAAQ,OAAU,SAAWA,EAAO,MAAM,OAAS,GACxEpW,EAAI,KAAK,CACP,OAAAoW,EACA,YAAa/T,EACb,SAAUi0B,GAAgBlgB,EAAQ/T,CAAC,EACnC,SAAAmG,EACA,MAAAyK,EACA,YAAaA,EAAQwjB,GAAiCjuB,CAAQ,EAAI,IAAA,CACnE,CACH,CACA,OAAOxI,CACT,CAEA,SAASs3B,GACP7jB,EACA2jB,EACAvO,EACA/F,EACA9P,EACAukB,EACAC,EACA1kB,EACAC,EAKO,CACP,MAAM9S,EAAIwT,EAAM,CAAC,EACXvT,EAAIuT,EAAM,CAAC,EACX7U,EAAO,KAAK,IAAI,KAAMkkB,EAAS,aAAA,EAAe,IAAI,EAClDhJ,EAAsB,KAAK,IAAI,EAAG0d,CAAqB,EACvDC,EAAqBrC,GAAiCx2B,EAC5D,QAASyD,EAAIwmB,EAAQ,OAAS,EAAGxmB,GAAK,EAAGA,GAAK,EAAG,CAC/C,MAAM+T,EAASyS,EAAQxmB,CAAC,EACxB,UAAW2E,KAAWoP,EAAO,SAC3B,GAAK0gB,GAA0B72B,EAAGC,EAAG8G,EAASywB,CAAkB,EAChE,MAAO,CACL,OAAQrhB,EAAO,OACf,YAAaA,EAAO,YACpB,SAAUA,EAAO,QAAA,EAGrB,IAAI6D,EAAoB1I,GACtByB,EACAukB,IAAqB,CACnB,OAAQnhB,EAAO,OACf,SAAUA,EAAO,SACjB,YAAaA,EAAO,YACpB,KAAAxX,CAAA,CACD,CAAA,EAQH,GANIkb,EAAsB,IACxBG,EAAoB,CAClB,GAAGA,EACH,QAASA,EAAkB,QAAUH,CAAA,GAGrC,EAACqd,GAAyB/gB,EAAQghB,EAAatU,EAAU7I,EAAmBnH,EAAaC,CAAY,EACzG,MAAO,CACL,OAAQqD,EAAO,OACf,YAAaA,EAAO,YACpB,SAAUA,EAAO,QAAA,CAErB,CACA,OAAO,IACT,CAsEO,SAASshB,GAAgB,CAC9B,OAAAp8B,EACA,UAAAyC,EACA,mBAAA45B,EAAqB,KACrB,kBAAAC,EACA,QAAAC,EACA,YAAAC,EACA,cAAAC,EACA,kBAAAC,EACA,aAAA3e,EAAe,GACf,kBAAA4e,EACA,SAAAC,EAAW,EACX,mBAAAC,EAAqB,EACrB,UAAAha,EAAY,GACZ,eAAAia,EAAiB,GACjB,UAAApV,EAAY,KACZ,aAAAqV,EAAe,KACf,gBAAAvL,EACA,iBAAAwL,EACA,QAAAtrB,EACA,QAAAC,EACA,eAAAsrB,EACA,WAAAC,EACA,YAAAC,EACA,iBAAAC,EAAmB,GACnB,SAAAC,GAAW,SACX,YAAAC,GACA,iBAAAC,GACA,wBAAAC,GACA,gBAAAC,GAAkB,GAClB,SAAAC,GAAW,SACX,aAAAllB,GACA,aAAAC,GACA,cAAAS,GACA,kBAAAC,EACA,uBAAAC,GACA,wBAAAC,GACA,iBAAAC,GACA,yBAAAC,GACA,wBAAyBC,GACzB,cAAAC,EACA,aAAAkkB,EACA,aAAA3kB,EACA,iBAAAY,EACA,gBAAAC,EACA,6BAAAC,GAA+B,GAC/B,mBAAA8jB,GACA,aAAAC,EACA,aAAAC,EACA,cAAAC,GACA,cAAAC,GACA,eAAgBC,EAChB,qBAAAC,EACA,wBAAAC,GACA,eAAAvlB,GACA,gBAAAC,EACA,kBAAAulB,GACA,UAAAnkB,GACA,MAAAvF,EACF,EAA6C,CAC3C,MAAM2pB,GAAkBD,IAAmB,MAAQ,GAC7CE,GAAqBF,IAAmB,QACxClkB,GAAYC,EAAAA,OAAiC,IAAI,EACjDoN,EAAcpN,EAAAA,OAA+B,IAAI,EACjDokB,GAAoBpkB,EAAAA,OAA4B,IAAI,EACpDqkB,EAAwBrkB,EAAAA,OAA4B,IAAI,EACxDskB,GAAuBtkB,EAAAA,OAAiCmiB,CAAiB,EACzEoC,GAAavkB,EAAAA,OAAuBoiB,CAAO,EAC3CoC,GAAkBxkB,EAAAA,OAAO4D,CAAY,EACrC,CAACrE,GAAiBklB,EAAkB,EAAIC,EAAAA,SAAiC,IAAI,EAC7E,CAACC,GAA4BC,EAA6B,EAAIF,EAAAA,SAAiC,IAAMZ,GAA4B,IAAI,EACrIe,GAA2Bf,IAA6B,OACxDtkB,GAAiBqlB,GAA4Bf,GAA4B,KAAQa,GACjF,CAACG,GAAsBC,CAAuB,EAAIL,EAAAA,SAA8B,IAAI,EACpF,CAACM,EAAYC,CAAa,EAAIP,EAAAA,SAAgC,IAAI,EAClE,CAAC9kB,EAA6BslB,CAA8B,EAAIR,EAAAA,SAAS,CAAC,EAC1ES,EAAqBnlB,EAAAA,OAA+B,IAAI,EACxDolB,EAAuBplB,EAAAA,OAAsB,IAAI,EACjDqlB,GAAoBrlB,EAAAA,OAAsB,IAAI,EAC9CslB,EAA+BtlB,EAAAA,OAAO,CAAC,EACvCulB,EAAkCvlB,EAAAA,OAA4E,CAClH,MAAO,KACP,QAAS,EACT,KAAM,EACN,GAAI,CAAA,CACL,EACKwlB,GAAexlB,EAAAA,OAAO,CAAC,EACvBylB,GAAiB1C,GAAc5D,GAC/BuG,GAAmB7mB,GAAgBsgB,GACnCwG,GAAkB3C,GAAe5D,GACjCwG,IAAmCpC,GAAc,QAAU,GAAK,EAEhEliB,GAAcf,EAAAA,QAAuB,KAAO,CAAE,SAAU,WAAY,MAAO,OAAQ,OAAQ,OAAQ,GAAGhG,EAAA,GAAU,CAACA,EAAK,CAAC,EACvHsrB,GAA0BtlB,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,GAAGiiB,CAAA,GAEL,CAACA,CAAiB,CAAA,EAGdsD,GAAsBvlB,EAAAA,QAAqB,IAC3CklB,GAAe,OAAS,EACnBA,GAELE,GAAgB,SAAW,EACtBxG,GAEFwG,GAAgB,IAAI,CAACr7B,EAAakW,KAAW,CAClD,GAAIA,EACJ,YAAAlW,CAAA,EACA,EACD,CAACm7B,GAAgBE,EAAe,CAAC,EAC9BI,GAAqBxlB,EAAAA,QAAQ,IAAMqhB,GAAkBkE,EAAmB,EAAG,CAACA,EAAmB,CAAC,EAChGE,GAA2BzlB,EAAAA,QAAQ,IAAM/E,GAAwBiE,CAAgB,EAAG,CAACA,CAAgB,CAAC,EAEtGwmB,GAAiCzkB,cAAaxa,GAAiB,CACnE,MAAMk/B,EAAUj8B,GAAMjD,EAAM,EAAGkQ,EAAoC,EAC/D,KAAK,IAAIouB,EAA6B,QAAUY,CAAO,EAAI,OAC/DZ,EAA6B,QAAUY,EACvChB,EAA+BgB,CAAO,EACxC,EAAG,CAAA,CAAE,EAECC,GAAqC3kB,EAAAA,YAAY,IAAM,CAC3D,MAAM6X,EAAYkM,EAAgC,QAC9ClM,EAAU,QAAU,OACtB,qBAAqBA,EAAU,KAAK,EACpCA,EAAU,MAAQ,KAEtB,EAAG,CAAA,CAAE,EAEC+M,GAA+B5kB,EAAAA,YAClC2X,GAAmB,CAClB,MAAMkN,EAAgBp8B,GAAMkvB,EAAQ,EAAGjiB,EAAoC,EACrEmiB,EAAYkM,EAAgC,QAC5Cxd,EAAOud,EAA6B,QAC1C,GAAI,KAAK,IAAIvd,EAAOse,CAAa,EAAI,KAAM,CACzCF,GAAA,EACA9M,EAAU,GAAKgN,EACfJ,GAA+BI,CAAa,EAC5C,MACF,CAEAF,GAAA,EACA9M,EAAU,QAAU,YAAY,IAAA,EAChCA,EAAU,KAAOtR,EACjBsR,EAAU,GAAKgN,EAEf,MAAMj6B,EAAQk6B,GAAsB,CAClC,MAAMpN,GAAUqM,EAAgC,QAC1CjM,GAAU,KAAK,IAAI,EAAGgN,EAAYpN,GAAQ,OAAO,EACjDK,GAA+DtvB,GAAMqvB,GAAUyG,GAA8C,EAAG,CAAC,EACjIvG,GAAQsH,GAAavH,EAAI,EACzBgN,GAAYrN,GAAQ,MAAQA,GAAQ,GAAKA,GAAQ,MAAQM,GAI/D,GAHAyM,GAA+BM,EAAS,EACxCnC,GAAkB,UAAA,EAEd7K,IAAQ,EAAG,CACbL,GAAQ,MAAQ,KAChB+M,GAA+B/M,GAAQ,EAAE,EACzC,MACF,CACAA,GAAQ,MAAQ,sBAAsB9sB,CAAI,CAC5C,EAEAitB,EAAU,MAAQ,sBAAsBjtB,CAAI,CAC9C,EACA,CAAC65B,GAAgCE,EAAkC,CAAA,EAG/DK,GAAgChlB,EAAAA,YACnCrY,GAAoC,CACnC,MAAMkkB,EAAWD,EAAY,QAC7B,GAAI,CAACC,GAAY,OAAOlkB,GAAS,UAAY,CAAC,OAAO,SAASA,CAAI,EAAG,CACnEi9B,GAA6B,CAAC,EAC9B,MACF,CACA,MAAMjN,EAAS/hB,GAAmCuI,GAA8BxW,EAAMkkB,EAAS,cAAc,EAC7G+Y,GAA6BjN,CAAM,CACrC,EACA,CAACxZ,GAA8BymB,EAA4B,CAAA,EAGvDK,GAAelmB,EAAAA,QAAsB,IAAMulB,GAAoB,IAAInlB,GAAUA,EAAO,WAAyB,EAAG,CAACmlB,EAAmB,CAAC,EAErI,CAACY,GAAiBC,EAAkB,EAAIjC,EAAAA,SAA8BnX,CAAS,EAErFpH,EAAAA,UAAU,IAAM,CACd,MAAMygB,EAAQ,EAAEpB,GAAa,QAC7B,IAAIlZ,EAAY,GAEhB,GAAI,CAAC2W,EACH,OAAA0D,GAAmBpZ,CAAS,EACrB,IAAM,CACXjB,EAAY,EACd,EAGF,GAAI,CAACiB,GAAa,CAACA,EAAU,OAAS,CAACA,EAAU,WAAa,CAACA,EAAU,eACvE,OAAAoZ,GAAmB,IAAI,EAChB,IAAM,CACXra,EAAY,EACd,EAGF,GAAIma,GAAa,SAAW,EAC1B,OAAAE,GAAmBtH,EAAoB,EACvC8D,KAAc,CACZ,KAAMD,GACN,WAAY,EACZ,WAAY3V,EAAU,MACtB,YAAa,EACb,aAAc,CAAA,CACf,EACM,IAAM,CACXjB,EAAY,EACd,EAGF,MAAMua,EAAc,CAAChW,EAA2BiW,IAAoF,CAClI,GAAIxa,GAAasa,IAAUpB,GAAa,QAAS,OACjD,MAAMuB,GAAclW,GAAM,YAAcA,EAAK,YAAY,OAAUA,GAAM,OAAS,EAClF8V,GAAmB9V,CAAI,EACvBsS,KAAc,CACZ,KAAM2D,EAAM,KACZ,WAAYA,EAAM,WAClB,WAAYvZ,EAAU,MACtB,YAAAwZ,GACA,aAAcN,GAAa,OAC3B,WAAYK,EAAM,WAClB,eAAgBA,EAAM,eACtB,cAAeA,EAAM,aAAA,CACtB,CACH,EAyCA,OAvCY,SAA2B,CACrC,GAAI5D,KAAa,OAAQ,CACvB,MAAMnzB,EAAQ,YAAY,IAAA,EACpB8gB,EAAOpD,GAA0BF,EAAWkZ,EAAY,EAC9DI,EAAYhW,EAAM,CAChB,KAAM,OACN,WAAY,YAAY,MAAQ9gB,CAAA,CACjC,EACD,MACF,CAEA,GAAImzB,KAAa,gBAAiB,CAChC,MAAM1d,EAAS,MAAMmL,GAAgCpD,EAAWkZ,GAAc,CAAE,aAAc,GAAM,EACpGI,EAAYrhB,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,MAAMiN,GAAkClF,EAAWkZ,EAAY,EAC9EI,EAAYrhB,EAAO,KAAM,CACvB,KAAMA,EAAO,KAAK,KAClB,WAAYA,EAAO,KAAK,UAAA,CACzB,CACH,MAAQ,CACN,MAAMzV,EAAQ,YAAY,IAAA,EACpB8gB,EAAOpD,GAA0BF,EAAWkZ,EAAY,EAC9DI,EAAYhW,EAAM,CAChB,KAAM,OACN,WAAY,YAAY,MAAQ9gB,CAAA,CACjC,CACH,CACF,GAEK,EACE,IAAM,CACXuc,EAAY,EACd,CACF,EAAG,CAAC2W,EAAkBC,GAAU3V,EAAWkZ,GAActD,EAAW,CAAC,EAErE,MAAM6D,GAA2B,GAAQtD,GAAgBC,GAAgBK,IACnEiD,GAAoB1mB,EAAAA,QAAQ,IAC3BymB,GACE3G,GAAuBqG,GAAiB7gC,CAAM,EADf,KAErC,CAACmhC,GAA0BN,GAAiB7gC,CAAM,CAAC,EAEhDqhC,GAAuB1lB,EAAAA,YAC1B2lB,GAAqD,CACpD,MAAM9Z,EAAWD,EAAY,QAC7B,GAAI,CAACC,GAAY,CAAC4Z,GAAmB,OAAO,KAE5C,MAAMz8B,EAAI,OAAO28B,EAAW,CAAC,CAAC,EACxB18B,EAAI,OAAO08B,EAAW,CAAC,CAAC,EAC9B,GAAI,CAAC,OAAO,SAAS38B,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAG,OAAO,KAEvD,MAAMtB,EAAO,KAAK,IAAI,KAAMkkB,EAAS,aAAA,EAAe,IAAI,EAClD+Z,EAAc/Z,EAAS,mBAAA,EAEvBga,GADc,KAAK,IAAI9H,GAAyB6H,EAAc9H,EAAsB,EACrDn2B,EACrC,GAAI,CAAC,OAAO,SAASk+B,EAAc,GAAKA,IAAkB,EAAG,OAAO,KAEpE,MAAM/G,GAAW2G,GAAkB,SAC7BK,GAAY,KAAK,MAAM98B,EAAI81B,EAAQ,EACnCiH,GAAY,KAAK,MAAM98B,EAAI61B,EAAQ,EACnCkH,GAAa,KAAK,IAAI,EAAG,KAAK,KAAKH,GAAiB/G,EAAQ,CAAC,EAC7DrwB,GAAWo3B,GAAiBA,GAElC,IAAII,GAAe,GACfC,GAAez3B,GACf03B,GAAW,EACXC,GAAW,EAEf,QAASld,GAAK4c,GAAYE,GAAY9c,IAAM4c,GAAYE,GAAY9c,IAAM,EAAG,CAC3E,MAAMiW,GAASsG,GAAkB,QAAQ,IAAIvc,EAAE,EAC/C,GAAKiW,GAEL,QAAShW,GAAK4c,GAAYC,GAAY7c,IAAM4c,GAAYC,GAAY7c,IAAM,EAAG,CAC3E,MAAMiW,GAASD,GAAO,IAAIhW,EAAE,EAC5B,GAAI,GAACiW,IAAUA,GAAO,SAAW,GAEjC,QAASh0B,GAAI,EAAGA,GAAIg0B,GAAO,OAAQh0B,IAAK,EAAG,CACzC,MAAM4kB,GAAaoP,GAAOh0B,EAAC,EAC3B,GAAI4kB,IAAcyV,GAAkB,UAAW,SAE/C,MAAMxrB,GAAKwrB,GAAkB,UAAUzV,GAAa,CAAC,EAC/C9V,GAAKurB,GAAkB,UAAUzV,GAAa,EAAI,CAAC,EACnDhiB,GAAKiM,GAAKjR,EACViF,GAAKiM,GAAKjR,EACV0F,GAAQX,GAAKA,GAAKC,GAAKA,GACzBU,GAAQu3B,KAEZA,GAAev3B,GACfs3B,GAAejW,GACfmW,GAAWlsB,GACXmsB,GAAWlsB,GACb,CACF,CACF,CAEA,GAAI+rB,GAAe,EAAG,OAAO,KAC7B,MAAMI,GAAUZ,GAAkB,IAAM,OAAOA,GAAkB,IAAIQ,EAAY,CAAC,EAAI,KACtF,MAAO,CACL,MAAOA,GACP,GAAII,GACJ,WAAY,CAACr9B,EAAGC,CAAC,EACjB,gBAAiB,CAACk9B,GAAUC,EAAQ,CAAA,CAExC,EACA,CAACX,EAAiB,CAAA,EAGda,GAAiBtmB,EAAAA,YACrB,CAACumB,EAA2BZ,IAAsC,CAChE,GAAI,CAACzD,EAAc,OACnB,MAAMsE,EAAYD,GAAK,OAAS,KAC1BE,EAASF,GAAK,IAAM,KACtB3C,EAAqB,UAAY4C,GAAa3C,GAAkB,UAAY4C,IAChF7C,EAAqB,QAAU4C,EAC/B3C,GAAkB,QAAU4C,EAC5BvE,EAAa,CACX,MAAOsE,EACP,GAAIC,EACJ,WAAAd,EACA,gBAAiBY,GAAK,iBAAmB,IAAA,CAC1C,EACH,EACA,CAACrE,CAAY,CAAA,EAGTwE,GAAiB1mB,EAAAA,YACrB,CAAC2lB,EAA4BgB,IAAmB,CAC9C,GAAI,CAACxE,EAAc,OACnB,MAAMoE,EAAMb,GAAqBC,CAAU,EACtCY,GACLpE,EAAa,CACX,GAAGoE,EACH,OAAAI,CAAA,CACD,CACH,EACA,CAACxE,EAAcuD,EAAoB,CAAA,EAGrC/gB,EAAAA,UAAU,IAAM,CACd,GAAK6d,GACL,OAAAA,GAAwB,QAAUkD,GAC3B,IAAM,CACPlD,GAAwB,UAAYkD,KACtClD,GAAwB,QAAU,KAEtC,CACF,EAAG,CAACA,GAAyBkD,EAAoB,CAAC,EAElD/gB,EAAAA,UAAU,IAAM,CACT0e,IACLD,GAA8Bd,GAA4B,IAAI,CAChE,EAAG,CAACe,GAA0Bf,CAAwB,CAAC,EAEvD,MAAMsE,GAAqB5mB,EAAAA,YACxBxa,GAAiC,CAC5B,OAAOwY,EAAc,IAAM,OAAOxY,CAAI,IACrC69B,IACHD,GAA8B59B,CAAI,EAEpC+8B,IAAuB/8B,CAAI,EAC7B,EACA,CAACwY,GAAgBqlB,GAA0Bd,CAAoB,CAAA,EAGjE5d,EAAAA,UAAU,IAAM,CACdme,GAAqB,QAAUnC,CACjC,EAAG,CAACA,CAAiB,CAAC,EAEtBhc,EAAAA,UAAU,IAAM,CACdoe,GAAW,QAAUnC,CACvB,EAAG,CAACA,CAAO,CAAC,EAEZjc,EAAAA,UAAU,IAAM,CACdqe,GAAgB,QAAU5gB,EACrBA,GAAcqhB,EAAc,IAAI,CACvC,EAAG,CAACrhB,CAAY,CAAC,EAEjBuC,EAAAA,UAAU,IACD,IAAM,CACXggB,GAAA,CACF,EACC,CAACA,EAAkC,CAAC,EAEvC,MAAMkC,GAAsB7mB,cAAaslB,GAAgC,CACvEvC,GAAW,UAAUuC,CAAK,EACtBtC,GAAgB,SAClBS,EAAc6B,CAAK,CAEvB,EAAG,CAAA,CAAE,EAECwB,GAAmB/nB,EAAAA,QAAQ,IAC1BykB,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,EAEf7e,EAAAA,UAAU,IAAM,CAEV,EADc3G,KAAmB,KAAO,GAAOsmB,GAAoB,KAAK,CAACnlB,EAAQH,IAAU,OAAOqgB,GAAgBlgB,EAAQH,CAAK,CAAC,IAAM,OAAOhB,EAAc,CAAC,IAC9IA,KAAmB,MACnC4oB,GAAmB,IAAI,EAGzB,MAAMG,EAAepD,EAAmB,QAGpC,EAFaoD,IAAiB,KAAO,GAAOzC,GAAoB,KAAK,CAACnlB,EAAQH,IAAU,OAAOqgB,GAAgBlgB,EAAQH,CAAK,CAAC,IAAM,OAAO+nB,CAAY,CAAC,IAE1IA,IAAiB,OAChCpD,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,EAEL,EAAG,CAACkC,GAAqBtmB,GAAgBokB,GAAewE,EAAkB,CAAC,EAE3EjiB,EAAAA,UAAU,IAAM,CACd,MAAMqiB,EAAoBpD,EAAqB,QAC3CoD,IAAsB,OACtBvB,IAAqBuB,EAAoBvB,GAAkB,YAC/D7B,EAAqB,QAAU,KAC/BC,GAAkB,QAAU,KAC5B3B,IAAe,CACb,MAAO,KACP,GAAI,KACJ,WAAY,KACZ,gBAAiB,IAAA,CAClB,GACH,EAAG,CAACuD,GAAmBvD,CAAY,CAAC,EAEpC,MAAM+E,GAAsBjnB,EAAAA,YACzBxa,GAA6B,CAC5Bw/B,GAA8Bx/B,EAAK,IAAI,EACnC4+B,IACFb,EAAwB/9B,CAAI,EAE9B,MAAM0hC,EAAWpE,GAAqB,QAClCoE,GACFA,EAAS1hC,CAAI,EAEfo9B,GAAkB,UAAA,EAClBC,EAAsB,UAAA,CACxB,EACA,CAACuB,GAAiCY,EAA6B,CAAA,EAGjErgB,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GACLmZ,GAA8BnZ,EAAS,aAAA,EAAe,IAAI,CAC5D,EAAG,CAACmZ,GAA+BjvB,EAASC,CAAO,CAAC,EAEpD2O,EAAAA,UAAU,IAAM,CACVod,KAAa,UACb4B,EAAmB,UAAY,OACnCA,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,EACH,EAAG,CAACL,GAAUK,EAAa,CAAC,EAE5Bzd,EAAAA,UAAU,IAAM,CACVod,KAAa,UACb6B,EAAqB,UAAY,OACrCA,EAAqB,QAAU,KAC/BC,GAAkB,QAAU,KAC5B3B,IAAe,CACb,MAAO,KACP,GAAI,KACJ,WAAY,KACZ,gBAAiB,IAAA,CAClB,EACH,EAAG,CAACH,GAAUG,CAAY,CAAC,EAE3B,MAAMiF,GAAoBnnB,EAAAA,YAAY,CAAC8J,EAAiBC,IAA2C,CACjG,MAAM8B,EAAWD,EAAY,QAC7B,GAAI,CAACC,EAAU,OAAO,KACtB,MAAMtL,EAAMsL,EAAS,cAAc/B,EAASC,CAAO,EACnD,GAAI,CAAC,MAAM,QAAQxJ,CAAG,GAAKA,EAAI,OAAS,EAAG,OAAO,KAClD,MAAMvX,EAAI,OAAOuX,EAAI,CAAC,CAAC,EACjBtX,EAAI,OAAOsX,EAAI,CAAC,CAAC,EACvB,MAAI,CAAC,OAAO,SAASvX,CAAC,GAAK,CAAC,OAAO,SAASC,CAAC,EAAU,KAChD,CAACD,EAAGC,CAAC,CACd,EAAG,CAAA,CAAE,EAECm+B,GAAqBpnB,EAAAA,YAAY,CAACyK,EAAgBC,IAA0C,CAChG,MAAMmB,EAAWD,EAAY,QAC7B,GAAI,CAACC,EAAU,OAAO,KACtB,MAAMtL,EAAMsL,EAAS,cAAcpB,EAAQC,CAAM,EACjD,OAAO6U,GAAiBhf,CAAG,CAC7B,EAAG,CAAA,CAAE,EAEC8mB,GAA+BrnB,EAAAA,YAAY,CAAC8J,EAAiBC,IAAuG,CACxK,MAAM7kB,EAASqZ,GAAU,QACzB,GAAI,CAACrZ,EAAQ,OAAO,KACpB,MAAMkC,EAAOlC,EAAO,sBAAA,EACpB,GAAI,CAAC,OAAO,SAASkC,EAAK,KAAK,GAAK,CAAC,OAAO,SAASA,EAAK,MAAM,GAAKA,EAAK,OAAS,GAAKA,EAAK,QAAU,EACrG,OAAO,KAET,MAAM2d,EAAU+E,EAAU1iB,EAAK,KACzB4d,EAAU+E,EAAU3iB,EAAK,IAC/B,MAAI,CAAC,OAAO,SAAS2d,CAAO,GAAK,CAAC,OAAO,SAASC,CAAO,EAChD,KAEF,CACL,YAAa,CAACD,EAASC,CAAO,EAC9B,YAAa,KAAK,IAAI,EAAG5d,EAAK,KAAK,EACnC,aAAc,KAAK,IAAI,EAAGA,EAAK,MAAM,CAAA,CAEzC,EAAG,CAAA,CAAE,EAECkgC,GAAgBtnB,EAAAA,YACpB,CAACxD,EAAuB2jB,EAA6BtkB,EAAqBC,IAAyB,CACjG,MAAM+P,EAAWD,EAAY,QAC7B,OAAKC,EACEwU,GACL7jB,EACA2jB,EACAoE,GACA1Y,EACA2Y,GACA3mB,GACAO,EACAvC,EACAC,CAAA,EAVoB,IAYxB,EACA,CAACyoB,GAAoBC,GAA0B3mB,GAA6BO,CAA2B,CAAA,EAGnGmpB,GAA2BvnB,EAAAA,YAAY,IAAM,CACjD4L,EAAY,SAAS,cAAA,EACrBgX,GAAkB,UAAA,EAClBC,EAAsB,UAAA,CACxB,EAAG,CAAA,CAAE,EAEC2E,GAAgCzoB,EAAAA,QAA6B,IAC1DukB,IAAwB1X,EAAY,SAAS,aAAA,GAAkB,KACrE,CAAC0X,EAAoB,CAAC,EAEnBmE,GAAqB1oB,EAAAA,QAAsC,IAAM,CACrE,GAAI,CAAC1a,EAAQ,OAAO,KACpB,MAAMqjC,EAAoBF,GAC1B,OAAKE,EACE,CACL,OAAArjC,EACA,UAAWqjC,EACX,SAAA3F,GACA,gBAAAD,GACA,cAAesF,GACf,cAAeD,GACf,cAAeI,EAAA,EARc,IAUjC,EAAG,CAACljC,EAAQmjC,GAA+BzF,GAAUD,GAAiBsF,GAAoBD,GAAmBI,EAAwB,CAAC,EAEhII,GAA0B3nB,EAAAA,YAC7BuD,GAA6C,CAC5C,MAAMqkB,EAAgBrkB,EAAM,SAAWhF,GAAU,QAC3C/B,EAAQ2qB,GAAkB5jB,EAAM,QAASA,EAAM,OAAO,EAC5D,GAAI0e,GAAoB,CACtB,MAAM4F,GAAc,CAAC,CAACrrB,GAASA,EAAM,CAAC,GAAK,GAAKA,EAAM,CAAC,GAAK,GAAK,CAAC,CAACnY,GAAUmY,EAAM,CAAC,GAAKnY,EAAO,OAASmY,EAAM,CAAC,GAAKnY,EAAO,OAC5H49B,GAAmB,CACjB,WAAYzlB,EACZ,QAAS+G,EAAM,QACf,QAASA,EAAM,QACf,YAAAskB,EAAA,CACD,CACH,CAEA,GAAI9F,KAAa,SAAU,OAC3B,GAAI,CAAC6F,EAAe,CAClBtB,GAAe,KAAM,IAAI,EACrB3C,EAAmB,UAAY,OACjCA,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,GAEH,MACF,CACA,GAAI,CAAC5lB,EAAO,CACV8pB,GAAe,KAAM,IAAI,EACzB,MACF,CAKA,GAHIpE,GACFoE,GAAeZ,GAAqBlpB,CAAK,EAAGA,CAAK,EAE/C,CAAC+nB,GAAmB,OAAQ,OAEhC,MAAMuD,EAAkBT,GAA6B9jB,EAAM,QAASA,EAAM,OAAO,EACjF,GAAI,CAACukB,EAAiB,OAEtB,MAAMvB,EAAMe,GAAc9qB,EAAOsrB,EAAgB,YAAaA,EAAgB,YAAaA,EAAgB,YAAY,EACjHC,EAAcxB,GAAK,UAAY,KAC/ByB,GAAcrE,EAAmB,QACnC,OAAOqE,EAAW,IAAM,OAAOD,CAAW,IAE9CpE,EAAmB,QAAUoE,EAC7B9E,GAAmB8E,CAAW,EAC9B3F,KAAgB,CACd,OAAQmE,GAAK,QAAU,KACvB,SAAUwB,EACV,YAAaxB,GAAK,aAAe,GACjC,WAAY/pB,CAAA,CACb,EACH,EACA,CAACulB,GAAUwC,GAAoB4C,GAAmB/E,GAAeH,GAAoB59B,EAAQiiC,GAAgBZ,GAAsBxD,EAAcmF,GAA8BC,EAAa,CAAA,EAGxLW,GAA2BjoB,EAAAA,YAAY,IAAM,CACjDiiB,KAAqB,CACnB,WAAY,KACZ,QAAS,GACT,QAAS,GACT,YAAa,EAAA,CACd,EACDqE,GAAe,KAAM,IAAI,EACrB3C,EAAmB,UAAY,OACnCA,EAAmB,QAAU,KAC7BV,GAAmB,IAAI,EACvBb,KAAgB,CACd,OAAQ,KACR,SAAU,KACV,YAAa,GACb,WAAY,IAAA,CACb,EACH,EAAG,CAACA,GAAeH,GAAoBqE,EAAc,CAAC,EAEhD4B,GAAoBloB,EAAAA,YACvBuD,GAA2C,CAE1C,GADIwe,KAAa,UACbxe,EAAM,SAAWhF,GAAU,QAAS,OAExC,MAAM/B,EAAQ2qB,GAAkB5jB,EAAM,QAASA,EAAM,OAAO,EAC5D,GAAI,CAAC/G,EAAO,OAGZ,GAFAkqB,GAAelqB,EAAO+G,EAAM,MAAM,EAE9B,CAACghB,GAAmB,OAAQ,CAC9BqC,GAAmB,IAAI,EACvB,MACF,CAEA,MAAMkB,EAAkBT,GAA6B9jB,EAAM,QAASA,EAAM,OAAO,EACjF,GAAI,CAACukB,EAAiB,OAEtB,MAAMvB,EAAMe,GAAc9qB,EAAOsrB,EAAgB,YAAaA,EAAgB,YAAaA,EAAgB,YAAY,EACvH,GAAI,CAACvB,EAAK,CACRK,GAAmB,IAAI,EACvB,MACF,CAEA,MAAMuB,EAAqCnqB,KAAmB,MAAQ,OAAOA,EAAc,IAAM,OAAOuoB,EAAI,QAAQ,EAAI,KAAOA,EAAI,SACnIK,GAAmBuB,CAAU,EAC7B9F,KAAgB,CACd,OAAQkE,EAAI,OACZ,SAAUA,EAAI,SACd,YAAaA,EAAI,YACjB,WAAY/pB,CAAA,CACb,CACH,EACA,CAACulB,GAAUwC,GAAoB4C,GAAmB9E,GAAerkB,GAAgB4oB,GAAoBF,GAAgBW,GAA8BC,EAAa,CAAA,EAG5Jc,GAAiBpoB,EAAAA,YACpBxD,GAAmC,CAGlC,GAFIulB,KAAa,SACbjlB,IAAc,iBAAmB,IACjC,CAACynB,GAAmB,OAAQ,MAAO,GAEvC,MAAM1Y,EAAWD,EAAY,QACvB1mB,EAASqZ,GAAU,QACzB,GAAI,CAACsN,GAAY,CAAC3mB,EAAQ,MAAO,GACjC,MAAMkC,EAAOlC,EAAO,sBAAA,EACpB,GAAIkC,EAAK,OAAS,GAAKA,EAAK,QAAU,EAAG,MAAO,GAEhD,MAAM+4B,EAAcZ,GAAiB1T,EAAS,cAAcrP,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAAC,EAC/E,GAAI,CAAC2jB,EAAa,MAAO,GACzB,MAAMoG,EAAMe,GAAc9qB,EAAO2jB,EAAa/4B,EAAK,MAAOA,EAAK,MAAM,EACrE,GAAI,CAACm/B,EAAK,MAAO,GAEjB,MAAM4B,GAAqCnqB,KAAmB,MAAQ,OAAOA,EAAc,IAAM,OAAOuoB,EAAI,QAAQ,EAAI,KAAOA,EAAI,SACnI,OAAAK,GAAmBuB,EAAU,EAC7B9F,KAAgB,CACd,OAAQkE,EAAI,OACZ,SAAUA,EAAI,SACd,YAAaA,EAAI,YACjB,WAAY/pB,CAAA,CACb,EACM,EACT,EACA,CAACulB,GAAUjlB,IAAc,eAAgBynB,GAAoBvmB,GAAgB4oB,GAAoBvE,GAAeiF,EAAa,CAAA,EAGzHe,GAA0BroB,EAAAA,YAC7BuD,GAA2C,CAG1C,GAFI,CAAC4e,GACDJ,KAAa,UACbxe,EAAM,SAAWhF,GAAU,QAAS,OACxCgF,EAAM,eAAA,EACN,MAAM/G,EAAQ2qB,GAAkB5jB,EAAM,QAASA,EAAM,OAAO,EACvD/G,GACLkqB,GAAelqB,EAAO+G,EAAM,MAAM,CACpC,EACA,CAACwe,GAAUoF,GAAmBT,GAAgBvE,CAAY,CAAA,EAG5Dxd,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAMzf,EAASqZ,GAAU,QACzB,GAAI,CAACrZ,GAAU,CAACb,EACd,OAGF,MAAMwnB,EAAW,IAAI0L,GAAgBryB,EAAQb,EAAQ,CACnD,kBAAmB4iC,GACnB,QAASJ,GACT,YAAAhG,EACA,cAAAC,EACA,kBAAAC,EACA,UAAA7Z,EACA,mBAAAwZ,EACA,eAAAS,EACA,gBAAAtL,EACA,iBAAAwL,EACA,QAAAtrB,EACA,QAAAC,EACA,eAAAsrB,CAAA,CACD,EAED,OAAA1V,EAAY,QAAUC,EAClB/kB,GACF+kB,EAAS,aAAa/kB,CAAS,EAEjCk+B,GAA8BnZ,EAAS,aAAA,EAAe,IAAI,EAC1DA,EAAS,mBAAmBiW,EAAe,EACvCsC,IACFb,EAAwB1X,EAAS,cAAc,EAG1C,IAAM,CACX8Y,GAAA,EACAF,GAA+B,CAAC,EAChC5Y,EAAS,QAAA,EACTD,EAAY,QAAU,IACxB,CACF,EAAG,CACDvnB,EACAwiC,GACAhG,EACAC,EACAC,EACA7Z,EACAia,EACAtL,EACAwL,EACA4F,GACA7C,GACAY,GACAL,GACAF,EAAA,CACD,EAED9f,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACzB,CAACC,GAAY,CAAC/kB,GAGlB+kB,EAAS,aAAa/kB,CAAS,CACjC,EAAG,CAACA,CAAS,CAAC,EAEd6d,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GAGLA,EAAS,WAAA,CACX,EAAG,CAACoV,CAAQ,CAAC,EAEbtc,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GACLA,EAAS,cAAA,CACX,EAAG,CAACqV,CAAkB,CAAC,EAEvBvc,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACzB,CAACC,GAAY,CAACuV,GAGlBvV,EAAS,gBAAgBuV,CAAY,CACvC,EAAG,CAACA,CAAY,CAAC,EAEjBzc,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GAGLA,EAAS,mBAAmBgK,CAAe,CAC7C,EAAG,CAACA,CAAe,CAAC,EAEpBlR,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GACLA,EAAS,oBAAoBwV,CAAgB,CAC/C,EAAG,CAACA,CAAgB,CAAC,EAErB1c,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,IACLA,EAAS,aAAa9V,EAASC,CAAO,EACtCgvB,GAA8BnZ,EAAS,aAAA,EAAe,IAAI,EAC5D,EAAG,CAAC9V,EAASC,EAASgvB,EAA6B,CAAC,EAEpDrgB,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GACLA,EAAS,kBAAkByV,CAAc,CAC3C,EAAG,CAACA,CAAc,CAAC,EAEnB3c,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GACLA,EAAS,sBAAsB6U,CAAkB,CACnD,EAAG,CAACA,CAAkB,CAAC,EAEvB/b,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GAGLA,EAAS,aAAaqZ,EAAe,CACvC,EAAG,CAACA,EAAe,CAAC,EAEpBvgB,EAAAA,UAAU,IAAM,CACd,GAAI,CAACid,GAAkB,OAEvB,MAAM0D,EAAQpT,GADOuP,EAAmByD,GAAkBnZ,EACRuY,GAAqB,CACrE,qBAAsBzC,GACtB,oBAAqB,EAAA,CACtB,EACDD,GAAiB0D,CAAK,CACxB,EAAG,CAAC1D,GAAkBH,EAAkB1V,EAAWmZ,GAAiBZ,GAAqBzC,EAAuB,CAAC,EAEjHld,EAAAA,UAAU,IAAM,CACd,MAAMkH,EAAWD,EAAY,QACxBC,GAGLA,EAAS,mBAAmBiW,EAAe,CAC7C,EAAG,CAACA,EAAe,CAAC,EAGlBpW,GAAAA,KAAC,MAAA,CACC,UAAApN,GACA,MAAOwB,GACP,cAAe6nB,GACf,eAAgBM,GAChB,QAASC,GACT,cAAeG,GAEf,SAAA,CAAAvjB,GAAAA,IAAC,SAAA,CACC,IAAKvG,GACL,UAAU,oBACV,MAAO,CACL,SAAU,WACV,MAAO,EACP,OAAQ,EACR,MAAO,OACP,OAAQ,OACR,QAAS,QACT,YAAa,OACb,OAAQwjB,KAAa,UAAYhkB,KAAoB,KAAO,UAAY+jB,GAAkB,YAAc,MAAA,CAC1G,CAAA,EAEDz9B,GAAUojC,IAAsB,MAAM,QAAQzF,CAAY,GAAKA,EAAa,OAAS,EAClFA,EAAa,IAAI,CAACsG,EAAOtpB,IACvB8F,GAAAA,IAAC,MAAA,CAEC,UAAWwjB,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,IAAMtpB,CAAA,CAYpB,EACD,KACH3a,EACCygB,GAAAA,IAAClI,GAAA,CACC,KAAMmlB,GACN,QAASA,KAAa,SACtB,WAAY19B,EAAO,MACnB,YAAaA,EAAO,OACpB,SAAUA,EAAO,IACjB,UAAWA,EAAO,YAClB,aAAAwY,GACA,aAAAC,GACA,cAAAS,GACA,aAAcqO,EACd,WAAYwc,GACZ,gBAAiBthC,EACjB,iBAAkBw9B,GAClB,aAAcJ,GACd,kBAAA1mB,EACA,uBAAAC,GACA,wBAAAC,GACA,iBAAAC,GACA,yBAAAC,GACA,wBAAyBC,GACzB,cAAAC,EACA,gBAAAC,GACA,eAAAC,GACA,iBAAAC,EACA,gBAAAC,EACA,6BAAAC,GACA,4BAAAC,EACA,cAAewkB,GACf,eAAA3lB,GACA,gBAAAC,CAAA,CAAA,EAEA,KACHkF,SACE,MAAA,CAAI,gCAA6B,GAAC,MAAOiiB,GACvC,YACH,EACE,KACHhgC,GAAUq+B,IACT5d,GAAAA,IAACmC,GAAA,CACC,OAAA5iB,EACA,aAAcunB,EACd,UAAA1E,EACA,QAASyb,GACT,cAAeE,EACf,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 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_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\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 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 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.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 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 float alpha = 0.0;\n if (vFillMode != 0u) {\n alpha = outerMask * color.a;\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 alpha = outerMask * innerMask * color.a;\n }\n if (alpha <= 0.001) discard;\n\n outColor = vec4(color.rgb * alpha, alpha);\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 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 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 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 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.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 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 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 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 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 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 pointSizeByZoom,\n pointStrokeScale,\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.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_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","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","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","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","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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"}