@treewyrm/freelancer-webgl2 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["scaled","turnTo","GREY","MODES","rotate","FORMAT","STRIDE_FLOATS","placement","MODES","UNIFORMS","ORIGIN","byte","fragment","CORNERS","STRIDE","wrapOf","f","WHITE","BLACK","ORIGIN","f","sub","f","RAND_UNIT","TWO_PI","bits","f","sub","scaled","byte","f","TWO_PI","FORMAT","STRIDE","BLACK","f","DEGREES","rotationOf","f","RAND_UNIT","DEGREES","f","FORMAT","STRIDE","BLACK","byte","f","PI","FORMAT","STRIDE","BLACK","byte","RAND_UNIT","TWO_PI","f","FORMAT","STRIDE","BLACK","WHITE","byte","add","sub","scaled","reaches","f","byte","FORMAT","STRIDE","BLACK","WHITE","FORMAT","STRIDE","f","BYTE_TO_UNIT","unit","add","quad","f","RAND_UNIT","byte","scale","length","cross","rotate","f","FORMAT","STRIDE","BLACK","byte","dot","scale","interpolate","scale","FAR","f","BLACK","f","BLACK","FORMAT","STRIDE","ORDER","f","FORMAT","STRIDE","BLACK","f","WHITE","BLACK","f","end","f","FORMAT","STRIDE","BLACK","clampOne","RAND_UNIT","f","RAND_UNIT","f","byte","f","FORMAT","STRIDE","BLACK","TWO_PI","byte","f","f","PI","FORMAT","STRIDE","BLACK","f","RAND_UNIT","f","f","f","f","f","f","f"],"sources":["../src/gl/context.ts","../src/gl/program.ts","../src/texture/playback.ts","../src/alchemy/transform.ts","../src/alchemy/effect.ts","../src/alchemy/draw.ts","../src/mesh/plan.ts","../src/scene/hierarchy.ts","../src/deformable/level.ts","../src/deformable/skin.ts","../src/material/fog.ts","../src/material/dcdt.ts","../src/alchemy/curves.ts","../src/alchemy/program.ts","../src/material/screen.ts","../src/mesh/mesh.ts","../src/texture/texture.ts","../src/texture/upload.ts","../src/scene/render.ts","../src/material/map.ts","../src/scene/camera.ts","../src/scene/uv-animation.ts","../src/scene/level.ts","../src/scene/frame.ts","../src/scene/extent.ts","../src/scene/zone-segment.ts","../src/scene/retail.ts","../src/scene/nebula.ts","../src/scene/effect-view.ts","../src/scene/ring.ts","../src/scene/asteroids.ts","../src/scene/flare.ts","../src/scene/overlay.ts","../src/scene/exterior.ts","../src/scene/star.ts","../src/scene/hitbox.ts","../src/scene/corona.ts","../src/scene/immediate.ts","../src/scene/beam.ts","../src/scene/tractor.ts","../src/scene/sheets.ts","../src/scene/light.ts","../src/scene/space.ts","../src/scene/flashlight.ts","../src/scene/shadow.ts","../src/scene/room.ts","../src/scene/dust.ts","../src/scene/billboards.ts","../src/scene/dynamic.ts","../src/scene/lightning.ts","../src/scene/tunnel.ts","../src/scene/placed.ts","../src/scene/band.ts","../src/scene/clouds.ts","../src/alchemy/nodes.ts","../src/alchemy/tree.ts","../src/mesh/sphere.ts","../src/scene/sphere.ts","../src/thorn/curve.ts","../src/thorn/sound.ts","../src/thorn/frame.ts","../src/thorn/light.ts","../src/thorn/events.ts","../src/thorn/path.ts","../src/thorn/room.ts","../src/thorn/playback.ts","../src/thorn/script.ts","../src/thorn/view.ts","../src/thorn/sequence.ts","../src/thorn/character.ts","../src/thorn/index.ts","../src/deformable/player.ts","../src/deformable/mixer.ts"],"sourcesContent":["/** Acquires a WebGL2 context, or throws: the renderer has no fallback for its absence. */\nexport const createContext = (\n canvas: HTMLCanvasElement | OffscreenCanvas,\n options?: WebGLContextAttributes,\n): WebGL2RenderingContext => {\n const gl = canvas.getContext('webgl2', options) as WebGL2RenderingContext | null\n if (!gl) throw new Error('WebGL2 is not available')\n return gl\n}\n","/** A linked program and its uniform locations. `null` is GL's own: optimized out by the driver. */\nexport interface Program<U extends string = string> {\n handle: WebGLProgram\n uniforms: Record<U, WebGLUniformLocation | null>\n}\n\nconst compile = (gl: WebGL2RenderingContext, type: GLenum, source: string): WebGLShader => {\n const shader = gl.createShader(type)\n if (!shader) throw new Error('Cannot create shader')\n\n gl.shaderSource(shader, source)\n gl.compileShader(shader)\n\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n const log = gl.getShaderInfoLog(shader)\n\n gl.deleteShader(shader)\n throw new Error(`Shader compilation failed: ${log}`)\n }\n\n return shader\n}\n\n/** Compiles and links GLSL ES 3.00 sources, looking up the named uniforms once. */\nexport const createProgram = <U extends string = never>(\n gl: WebGL2RenderingContext,\n vertexSource: string,\n fragmentSource: string,\n uniforms: readonly U[] = [],\n): Program<U> => {\n const vertex = compile(gl, gl.VERTEX_SHADER, vertexSource)\n let fragment: WebGLShader\n\n try {\n fragment = compile(gl, gl.FRAGMENT_SHADER, fragmentSource)\n } catch (error) {\n gl.deleteShader(vertex)\n throw error\n }\n\n const handle = gl.createProgram()\n\n gl.attachShader(handle, vertex)\n gl.attachShader(handle, fragment)\n gl.linkProgram(handle)\n\n // Flagged for deletion only: GL keeps them until the program is gone.\n gl.deleteShader(vertex)\n gl.deleteShader(fragment)\n\n if (!gl.getProgramParameter(handle, gl.LINK_STATUS)) {\n const log = gl.getProgramInfoLog(handle)\n\n gl.deleteProgram(handle)\n throw new Error(`Program link failed: ${log}`)\n }\n\n const locations = {} as Record<U, WebGLUniformLocation | null>\n for (const name of uniforms) locations[name] = gl.getUniformLocation(handle, name)\n\n return { handle, uniforms: locations }\n}\n","/** Which frame an animated texture shows: `TextureLibrary`'s playback, as a function of its clock. Pure. */\nimport type { AnimatedTexture, Texture, TextureEntry } from '@treewyrm/freelancer/texture'\n\n/** `SetWrapMode`'s 0 and 1. Ping-pong, 2, has no retail caller. */\nexport type PlaybackWrap = 'clamp' | 'loop'\n\n/**\n * The frame a playback shows `elapsed` seconds after it began: `FUN_06ebe660`, then `FUN_06ebe8c0`'s\n * `floor(fmod(rate * seconds, count))`. Retail sums each tick into the clock, and this takes the sum.\n * A negative rate gives a frame below 0, which retail reads out of bounds.\n */\nexport const playbackFrame = (\n { frames, rate }: AnimatedTexture,\n elapsed: number,\n wrap: PlaybackWrap,\n): number => {\n const count = frames.length\n // A single frame is never advanced, and a rate within the epsilon leaves the duration 0, which\n // reads frame 0 either way: a clamp to 0, or a NaN that `ftol` turns to 0.\n if (count <= 1) return 0\n\n const fps = Math.fround(rate)\n if (!(Math.abs(fps) > 1e-5)) return 0\n\n // `PlaybackDuration`: just short of the last frame's end, so a clamp holds on it.\n const duration = count / fps - 1e-6\n const seconds = Math.fround(\n wrap === 'loop' ? elapsed % duration : Math.max(0, Math.min(elapsed, duration)),\n )\n\n // `+ 0`, as a negative rate's clamp gives -0.\n return Math.floor((fps * seconds) % count) + 0\n}\n\n/** A frame's atlas: the sibling entry `<name>_<index>` its frame names, as `LoadTextureRecord` loads them. */\nexport const frameAtlas = (\n animation: AnimatedTexture,\n frame: number,\n texture: (name: string) => TextureEntry | undefined,\n): { name: string; entry: Texture } | undefined => {\n const at = animation.frames[frame]\n if (!at) return undefined\n\n const name = `${animation.name}_${at.index}`\n const entry = texture(name)\n\n return entry && entry.type !== 'cube' && entry.type !== 'animated' ? { name, entry } : undefined\n}\n","/** A node's matrices, as `alchemy.dll` builds them. */\nimport { transformAt, transformMatrix, type AnimatedTransform } from '@treewyrm/freelancer/alchemy'\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\n\n/** The local matrix at a moment, or `undefined` for the common header with no curves. */\nexport const localMatrix = (\n transform: AnimatedTransform | undefined,\n sparam: number,\n time: number,\n): Matrix4 | undefined => {\n if (!transform?.curves) return undefined\n return transformMatrix(transformAt(transform, sparam, time))\n}\n\n/** `x86math.dll` `0x6f71380`: never fails. At `|det| ≤ 1e-8` the adjugate goes unscaled, so a zero scale still runs. */\nexport const frameInverse = (world: Matrix4): Matrix4 => {\n const { x: a, y: b, z: c, w: t } = world\n const r0 = { x: b.y * c.z - b.z * c.y, y: b.z * c.x - b.x * c.z, z: b.x * c.y - b.y * c.x }\n const r1 = { x: c.y * a.z - c.z * a.y, y: c.z * a.x - c.x * a.z, z: c.x * a.y - c.y * a.x }\n const r2 = { x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x }\n const det = a.x * r0.x + a.y * r0.y + a.z * r0.z\n const k = Math.abs(det) > 1e-8 ? 1 / det : 1\n\n return {\n x: { x: r0.x * k, y: r1.x * k, z: r2.x * k, w: 0 },\n y: { x: r0.y * k, y: r1.y * k, z: r2.y * k, w: 0 },\n z: { x: r0.z * k, y: r1.z * k, z: r2.z * k, w: 0 },\n w: {\n x: -(r0.x * t.x + r0.y * t.y + r0.z * t.z) * k,\n y: -(r1.x * t.x + r1.y * t.y + r1.z * t.z) * k,\n z: -(r2.x * t.x + r2.y * t.y + r2.z * t.z) * k,\n w: 1,\n },\n }\n}\n\n/** `Mᵀ · (p − t)`, 3DMathEngine `+0x3c`: the transpose, so a scaled frame's result stays scaled. */\nexport const transposeInto = (matrix: Matrix4, point: Vector3): Vector3 => {\n const dx = point.x - matrix.w.x\n const dy = point.y - matrix.w.y\n const dz = point.z - matrix.w.z\n\n return {\n x: matrix.x.x * dx + matrix.x.y * dy + matrix.x.z * dz,\n y: matrix.y.x * dx + matrix.y.y * dy + matrix.y.z * dz,\n z: matrix.z.x * dx + matrix.z.y * dy + matrix.z.z * dz,\n }\n}\n","/**\n * One effect running, advanced by host-supplied time. Retail keeps its nodes in a tree and walks it each\n * frame (`0x6201810`): each node updates in turn, and one past its life dies with all that hangs from\n * it. The picture depends on that order, so this keeps the same tree: an appearance updates before the\n * sibling fields it reads, so it sees them a frame late, and a sub-effect's nodes hang off its spawner.\n */\nimport {\n curveAt,\n floatAt,\n type AnimatedCurve,\n type AnimatedFloat,\n} from '@treewyrm/freelancer/alchemy'\nimport { Matrix3, Matrix4, Quat, type Vector3, type Vector4 } from '@treewyrm/freelancer/math'\nimport type { Appearance, Emitter, Field, NodeDescriptor, ParticleAppearance } from './nodes.js'\nimport { frameInverse, localMatrix, transposeInto } from './transform.js'\nimport type { EffectLookup, EffectNode, EffectScene } from './tree.js'\n\n/** A lane's record, in floats. Position and velocity are in the appearance's frame, at `BORN`. */\nexport const RECORD = 16\nexport const POSITION = 0\nexport const VELOCITY = 3\n/** The lane's clock, less its epoch, when the record was last written. */\nexport const BORN = 6\nexport const AGE = 7\nexport const LIFE = 8\n/** A perp's roll reference (`0x6235db0`). */\nexport const AXIS = 9\nexport const SERIAL = 12\n\n/** How many of a kind the game's pool holds, from `dacom.ini`. A full one evicts its oldest. */\nexport type PoolSizes = Readonly<Record<Appearance['kind'], number>>\n\nexport const RETAIL_POOLS: PoolSizes = {\n 'basic-appearance': 1000,\n 'rect-appearance': 400,\n 'perp-appearance': 250,\n // Not retail's: its `0` crashes the game, and 1000 runs (`effect_oriented`). So a mod has set this.\n 'oriented-appearance': 1000,\n 'beam-appearance': 680,\n 'dust-appearance': 250,\n 'mesh-appearance': 500,\n 'particle-appearance': 100,\n}\n\n/** Where evictions are counted, and the random stream. Effects sharing one compete as in the game. */\nexport interface EffectPools {\n sizes: PoolSizes\n held: Map<Appearance['kind'], Set<AppearanceNode>>\n serial: number\n rngState: number\n rngCount: number\n}\n\nexport const createPools = (seed = 0, sizes: PoolSizes = RETAIL_POOLS): EffectPools => ({\n sizes,\n held: new Map(),\n serial: 0,\n rngState: seed | 0,\n rngCount: 0,\n})\n\n/** `0x623f1f0`: one of 256 values, 0 and 1 included. */\nconst random = (pools: EffectPools): number => {\n const state = pools.rngState\n const mixed = (((state & 0xff) << 8) ^ (state & 0xff00)) | ((pools.rngCount ^ state) & 0xff)\n const bit = ((state >>> 14) & 1) ^ (state & 1)\n\n pools.rngCount = (pools.rngCount + 1) | 0\n pools.rngState = (bit + mixed * 2) | 0\n\n const next = pools.rngState\n\n return Math.fround(((next & 0xff) ^ ((next >>> 8) & 0xff)) * Math.fround(1 / 255))\n}\n\nconst FLOAT = new Float32Array(1)\nconst INT = new Int32Array(FLOAT.buffer)\n\n/** The fast inverse square root with one Newton step, as the emitter and turbulence take it. */\nconst inverseLength = (squared: number): number => {\n FLOAT[0] = squared\n INT[0] = 0x5f3759df - (INT[0]! >> 1)\n\n const guess = FLOAT[0]!\n\n return (1.5 - 0.5 * squared * guess * guess) * guess\n}\n\nconst curve = (c: AnimatedCurve | undefined, sparam: number, time: number, fallback: number) =>\n c ? curveAt(c, sparam, time) : fallback\n\n// The 3×3 part of `m` times a vector (columns x, y, z), translation dropped.\nconst scaled = (m: Matrix4, { x, y, z }: Vector3): Vector3 => ({\n x: m.x.x * x + m.y.x * y + m.z.x * z,\n y: m.x.y * x + m.y.y * y + m.z.y * z,\n z: m.x.z * x + m.y.z * y + m.z.z * z,\n})\n\ninterface RunContext {\n pools: EffectPools\n lookup?: EffectLookup\n sparam: number\n lod: number\n}\n\ninterface EffectRun {\n context: RunContext\n scene: EffectScene\n nodes: RunNode[]\n top: RunNode[]\n root?: RunNode\n}\n\nexport interface RunNode {\n run: EffectRun\n index: number\n key: number\n descriptor?: NodeDescriptor\n parent?: RunNode\n children: RunNode[]\n age: number\n lifeSpan: number\n /** Marked by `+0x5c`: it no longer updates or draws. */\n dead: boolean\n world: Matrix4\n /** `+0xc(1, M)`: `parent · override · local`, how a cutscene's placement reaches its node. */\n override?: Matrix4\n /**\n * `+0xc(0, M)`: the node's world for the next compose, outright, its parent and its own transform\n * left out (`alchemy!0x624012a`, `0x62401b1`). How every in-flight effect is placed.\n */\n placed?: Matrix4\n update: (dt: number) => boolean\n died?: () => void\n}\n\n/** What a field holds between its update and an appearance reading it. */\ntype FieldState =\n | { kind: 'gravity-field'; change: number }\n | { kind: 'air-field'; magnitude: number; blend: number }\n | { kind: 'turbulence-field'; magnitude: number; blend: number }\n | {\n kind: 'radial-field'\n magnitude: number\n inverseRadius: number\n attenuation?: AnimatedFloat\n blend: number\n }\n | { kind: 'collide-field'; reflectivity: number; dt: number }\n | { kind: 'dust-field'; radius: number }\n | { kind: 'beam-field' }\n\nexport interface FieldNode extends RunNode {\n state: FieldState\n}\n\n/** A run of a lane's records, in emission order, with the holes a ballistic lane leaves. */\nexport interface Lane {\n records: Float32Array\n capacity: number\n /** Up to here is gone. */\n tail: number\n head: number\n count: number\n /** Pushed each step, so `born == clock` and the vertex stage reads records as they stand. */\n stepped: boolean\n /** Seconds since it last rebased, so a float stays exact. Only `clock - BORN` means anything. */\n clock: number\n /** Bumped when records already uploaded change. */\n version: number\n /** Births, whose parity is the beam's texture mirror. */\n births: number\n}\n\nconst LANE_MIN = 16\n\nconst createLane = (stepped: boolean): Lane => ({\n records: new Float32Array(LANE_MIN * RECORD),\n capacity: LANE_MIN,\n tail: 0,\n head: 0,\n count: 0,\n stepped,\n clock: 0,\n version: 0,\n births: 0,\n})\n\nconst aliveAt = (lane: Lane, o: number): boolean =>\n lane.records[o + AGE]! + (lane.clock - lane.records[o + BORN]!) <= lane.records[o + LIFE]!\n\n/** A ballistic particle is its birth record, and floats keep its age exact for about this long. */\nconst REBASE = 16\n\nconst rebase = (lane: Lane) => {\n const { records, clock } = lane\n if (clock < REBASE) return\n for (let i = lane.tail; i < lane.head; i++) records[i * RECORD + BORN]! -= clock\n lane.clock = 0\n lane.version++\n}\n\nexport interface ParticleRecord {\n state: Float32Array\n lifeRun: EffectRun\n deathRun?: EffectRun\n blend: Vector4\n}\n\nexport interface AppearanceNode extends RunNode {\n descriptor: Appearance\n /** How many emitters feed it (`+0xb0`): none, and nothing held, and it's done. */\n refs: number\n fields: FieldNode[]\n lane?: Lane\n records?: ParticleRecord[]\n}\n\nconst held = (node: AppearanceNode) => node.lane?.count ?? node.records?.length ?? 0\n\nconst QUARTER_Z = Quat.axisAngle({ axis: { x: 0, y: 0, z: 1 }, angle: -Math.PI / 2 })\n\n/** `0x622ff00`: the turn taking +Y onto a velocity. */\nconst turnTo = (velocity: Vector3): Vector4 => {\n const length = Math.hypot(velocity.x, velocity.y, velocity.z)\n if (!(length > 0)) return Quat.identity\n\n const d = { x: velocity.x / length, y: velocity.y / length, z: velocity.z / length }\n\n // Off the Y axis: about Y × d by acos(d.y). Near it that axis degenerates, so +Y is first turned to\n // +X by `QUARTER_Z`, then +X onto d about X × d.\n if (Math.abs(d.y) < 0.99) {\n const s = Math.hypot(d.z, d.x)\n\n return Quat.axisAngle({ axis: { x: d.z / s, y: 0, z: -d.x / s }, angle: Math.acos(d.y) })\n }\n\n const s = Math.hypot(d.z, d.y)\n const first = Quat.axisAngle({\n axis: s > 0 ? { x: 0, y: -d.z / s, z: d.y / s } : { x: 0, y: 0, z: 1 },\n angle: Math.acos(Math.max(-1, Math.min(1, d.x))),\n })\n\n return Quat.multiply(first, QUARTER_Z)\n}\n\nconst insertChild = (parent: RunNode | undefined, top: RunNode[], node: RunNode) => {\n const list = parent ? parent.children : top\n // After the last whose key isn't greater, so ties keep entry order (`0x6201e00`).\n let at = list.length\n\n while (at > 0 && list[at - 1]!.key > node.key) at--\n list.splice(at, 0, node)\n}\n\n/** Depth first: children before the node, each marked and its emitter's ref given back. */\nconst kill = (node: RunNode) => {\n if (node.dead) return\n for (const child of node.children) kill(child)\n node.children = []\n node.dead = true\n node.died?.()\n}\n\nconst detach = (node: RunNode, top: RunNode[]) => {\n const list = node.parent ? node.parent.children : top\n const at = list.indexOf(node)\n if (at >= 0) list.splice(at, 1)\n}\n\n/** `Slot11(7)`: nothing lives in it but its control root. */\n/** `+0x2c(7)`: no live node but the root, what a sub-effect is held to. */\nconst runFinished = (run: EffectRun) => run.nodes.every((one) => one.dead || one === run.root)\n\n/** `+0x2c(4)`: no live appearance, emitters, fields and folders notwithstanding. */\nconst appearancesDone = (run: EffectRun) =>\n run.nodes.every((one) => one.dead || one.descriptor?.category !== 'appearance')\n\n/** `Slot13(1)`: its emitters go, and what they made lives out. */\nconst stopRun = (run: EffectRun, top: RunNode[]) => {\n for (const node of run.nodes) {\n if (node.descriptor?.category !== 'emitter' || node.dead) continue\n kill(node)\n detach(node, top)\n }\n}\n\nexport interface AdvanceOptions {\n /** The outer key of every animated property. 0 when absent, as the game's engine-less effects. */\n sparam?: number\n /** `[EffectLOD]`'s key. 1 when absent, what the game shows close up. */\n lod?: number\n /** Where the host has the effect: reaches its control root, or else every top-level node. */\n placement?: Matrix4\n /**\n * How {@link placement} lands. `world`, every in-flight effect's (`ParticleEffect`,\n * `Freelancer!0x4f8baa`), replaces the node's world outright, so a rootless effect's top-level\n * transform is never applied. `override`, a cutscene's (`Thorn_Psys`), is `parent · M · local`.\n */\n placing?: 'world' | 'override'\n /** The camera's world to view, which the dust's streak and fade read. */\n view?: Matrix4\n}\n\nconst applyField = (field: FieldNode, frame: Matrix4, world: Matrix4) => {\n const { state } = field\n\n switch (state.kind) {\n case 'gravity-field': {\n const change = scaled(frame, { x: 0, y: -state.change, z: 0 })\n\n return (s: Float32Array, o: number) => {\n s[o + VELOCITY]! += change.x\n s[o + VELOCITY + 1]! += change.y\n s[o + VELOCITY + 2]! += change.z\n }\n }\n case 'air-field': {\n const target = scaled(frame, { x: 0, y: state.magnitude, z: 0 })\n const { blend } = state\n\n // Per component v += (target − v) × blend, the easing turbulence and radial repeat.\n return (s: Float32Array, o: number) => {\n s[o + VELOCITY] = s[o + VELOCITY]! + (target.x - s[o + VELOCITY]!) * blend\n s[o + VELOCITY + 1] = s[o + VELOCITY + 1]! + (target.y - s[o + VELOCITY + 1]!) * blend\n s[o + VELOCITY + 2] = s[o + VELOCITY + 2]! + (target.z - s[o + VELOCITY + 2]!) * blend\n }\n }\n case 'turbulence-field': {\n const pools = field.run.context.pools\n const { magnitude, blend } = state\n\n // `0x623e370`: three draws, y, x, z, and a fourth for strength. Not a noise field.\n return (s: Float32Array, o: number) => {\n const y = 2 * (random(pools) - 0.5)\n const x = 2 * (random(pools) - 0.5)\n const z = 2 * (random(pools) - 0.5)\n const n = inverseLength(Math.fround(x * x + y * y + z * z))\n const push = random(pools) * magnitude\n\n s[o + VELOCITY] = s[o + VELOCITY]! + (x * n * push - s[o + VELOCITY]!) * blend\n s[o + VELOCITY + 1] = s[o + VELOCITY + 1]! + (y * n * push - s[o + VELOCITY + 1]!) * blend\n s[o + VELOCITY + 2] = s[o + VELOCITY + 2]! + (z * n * push - s[o + VELOCITY + 2]!) * blend\n }\n }\n case 'radial-field': {\n const origin = frame.w\n const { magnitude, inverseRadius, attenuation, blend } = state\n const { sparam } = field.run.context\n\n // `0x6236610`: the displacement isn't normalized, and nothing is cut off at the radius.\n return (s: Float32Array, o: number) => {\n const dx = s[o]! - origin.x\n const dy = s[o + 1]! - origin.y\n const dz = s[o + 2]! - origin.z\n const x = Math.min(1, Math.hypot(dx, dy, dz) * inverseRadius)\n const k = magnitude * (attenuation ? floatAt(attenuation, sparam, x) : 1)\n\n s[o + VELOCITY] = s[o + VELOCITY]! + (dx * k - s[o + VELOCITY]!) * blend\n s[o + VELOCITY + 1] = s[o + VELOCITY + 1]! + (dy * k - s[o + VELOCITY + 1]!) * blend\n s[o + VELOCITY + 2] = s[o + VELOCITY + 2]! + (dz * k - s[o + VELOCITY + 2]!) * blend\n }\n }\n case 'collide-field': {\n const axis = scaled(frame, { x: 0, y: 1, z: 0 })\n const inverse = 1 / Math.hypot(axis.x, axis.y, axis.z)\n const n = { x: axis.x * inverse, y: axis.y * inverse, z: axis.z * inverse }\n const point = Matrix4.transformPoint({ x: 1, y: 0, z: 1 }, frame)\n const { reflectivity, dt } = state\n\n // `0x621a0e0`: unbounded, and it acts only on a five-unit skin behind the plane.\n return (s: Float32Array, o: number) => {\n const v = o + VELOCITY\n const start =\n (s[o]! + 5 * n.x - point.x) * n.x +\n (s[o + 1]! + 5 * n.y - point.y) * n.y +\n (s[o + 2]! + 5 * n.z - point.z) * n.z\n if (start < 0) return\n\n const sx = s[v]! * dt\n const sy = s[v + 1]! * dt\n const sz = s[v + 2]! * dt\n const along = sx * n.x + sy * n.y + sz * n.z\n if (along < 0) return\n\n const end =\n (s[o]! + sx - point.x) * n.x +\n (s[o + 1]! + sy - point.y) * n.y +\n (s[o + 2]! + sz - point.z) * n.z\n if (end > 0) return\n\n // Signed plane distances of the skin-offset start and the step's end; t is the crossing fraction.\n const t = start / (start - end)\n const fromX = s[o]! + 5 * n.x\n const fromY = s[o + 1]! + 5 * n.y\n const fromZ = s[o + 2]! + 5 * n.z\n\n s[o] = fromX + t * (s[o]! + sx - fromX)\n s[o + 1] = fromY + t * (s[o + 1]! + sy - fromY)\n s[o + 2] = fromZ + t * (s[o + 2]! + sz - fromZ)\n\n // The position stands even when the speed is too small to reflect (`0x621a32f`).\n const speed = Math.hypot(s[v]!, s[v + 1]!, s[v + 2]!)\n if (!(speed > 0.001)) return\n\n const dot = 2 * (s[v]! * n.x + s[v + 1]! * n.y + s[v + 2]! * n.z)\n const rx = reflectivity * (s[v]! - dot * n.x)\n const ry = reflectivity * (s[v + 1]! - dot * n.y)\n const rz = reflectivity * (s[v + 2]! - dot * n.z)\n const back = (1 - t) * dt\n\n s[v] = rx\n s[v + 1] = ry\n s[v + 2] = rz\n s[o]! -= back * rx\n s[o + 1]! -= back * ry\n s[o + 2]! -= back * rz\n }\n }\n case 'dust-field': {\n const { radius } = state\n const squared = Math.fround(radius * radius)\n\n // `0x6212c90`: the field's world, not `frame`, and it writes the age. A zero radius kills all.\n return (s: Float32Array, o: number) => {\n const q = transposeInto(world, { x: s[o]!, y: s[o + 1]!, z: s[o + 2]! })\n const d = q.x * q.x + q.y * q.y + q.z * q.z\n\n if (d > squared) {\n s[o + AGE] = 3.4028234663852886e38\n return\n }\n\n // Age is 10 × fade × (z + r) / 2r, so depth through the sphere stands in for age; behind\n // the centre, the outer fifth of r² fades out.\n let fade = 1\n const band = squared * 0.8\n if (q.z < 0 && d > band) fade = 1 - (d - band) / (squared - band)\n s[o + AGE] = (1 - (radius - q.z) / (radius + radius)) * fade * 10\n }\n }\n case 'beam-field':\n return undefined\n }\n}\n\n/** Every live field acting on an appearance's records, in link order (`0x6218780`). */\nconst applyFields = (\n node: AppearanceNode,\n each: (apply: (s: Float32Array, o: number) => void) => void,\n) => {\n node.fields = node.fields.filter((field) => !field.dead)\n if (!node.fields.length) return\n\n const inverse = frameInverse(node.world)\n\n for (const field of node.fields) {\n const apply = applyField(field, Matrix4.multiply(inverse, field.world), field.world)\n if (apply) each(apply)\n }\n}\n\n/** Takes a list appearance's record for this birth, evicting the pool's oldest when it's full. */\nconst claim = ({ pools }: RunContext, node: AppearanceNode) => {\n const { kind } = node.descriptor\n let set = pools.held.get(kind)\n\n if (!set) {\n set = new Set()\n pools.held.set(kind, set)\n }\n\n set.add(node)\n\n let total = 0\n for (const one of set) total += held(one)\n if (total < pools.sizes[kind]) return\n\n let oldest: AppearanceNode | undefined\n let serial = Infinity\n\n for (const one of set) {\n const first = oldestSerial(one)\n\n if (first < serial) {\n serial = first\n oldest = one\n }\n }\n\n if (oldest) evict(oldest)\n}\n\nconst oldestSerial = ({ lane, records }: AppearanceNode): number => {\n if (records) return records[0]?.state[SERIAL] ?? Infinity\n if (!lane) return Infinity\n\n for (let i = lane.tail; i < lane.head; i++) {\n const o = i * RECORD\n if (aliveAt(lane, o)) return lane.records[o + SERIAL]!\n }\n\n return Infinity\n}\n\nconst evict = (node: AppearanceNode) => {\n const { lane, records } = node\n\n if (records) {\n const record = records.shift()\n\n if (record) {\n killRun(record.lifeRun, node)\n if (record.deathRun) killRun(record.deathRun, node)\n }\n\n return\n }\n\n if (!lane) return\n\n for (let i = lane.tail; i < lane.head; i++) {\n const o = i * RECORD\n if (!aliveAt(lane, o)) continue\n lane.records[o + LIFE] = -1\n lane.count--\n lane.version++\n return\n }\n}\n\nconst killRun = (run: EffectRun, parent: AppearanceNode) => {\n for (const node of run.top) {\n kill(node)\n\n const at = parent.children.indexOf(node)\n if (at >= 0) parent.children.splice(at, 1)\n }\n}\n\nconst appendRecord = (\n lane: Lane,\n six: Vector3[],\n age: number,\n life: number,\n axis: Vector3,\n serial: number,\n) => {\n if (lane.head >= lane.capacity) repack(lane)\n\n const o = lane.head++ * RECORD\n const r = lane.records\n\n r[o] = six[0]!.x\n r[o + 1] = six[0]!.y\n r[o + 2] = six[0]!.z\n r[o + VELOCITY] = six[1]!.x\n r[o + VELOCITY + 1] = six[1]!.y\n r[o + VELOCITY + 2] = six[1]!.z\n r[o + BORN] = lane.clock\n r[o + AGE] = age\n r[o + LIFE] = life\n r[o + AXIS] = axis.x\n r[o + AXIS + 1] = axis.y\n r[o + AXIS + 2] = axis.z\n r[o + SERIAL] = serial\n lane.count++\n lane.births++\n}\n\n/** Drops the holes, never reordering, and grows if it's still more than half full. */\nconst repack = (lane: Lane) => {\n const { records } = lane\n const room = Math.max(LANE_MIN, lane.count * 2)\n const into = room === lane.capacity ? records : new Float32Array(room * RECORD)\n let write = 0\n\n for (let read = lane.tail; read < lane.head; read++) {\n const o = read * RECORD\n if (!aliveAt(lane, o)) continue\n\n if (into !== records || write !== read)\n into.set(records.subarray(o, o + RECORD), write * RECORD)\n\n write++\n }\n\n lane.records = into\n lane.capacity = room\n lane.tail = 0\n lane.head = write\n lane.version++\n}\n\n/** A perp's roll starts at +X, or +Z when it leaves along +X (`0x6235e15`). */\nconst perpSeed = ({ x, y, z }: Vector3): Vector3 =>\n (x - 1) ** 2 <= 1e-6 && y * y <= 1e-6 && z * z <= 1e-6\n ? { x: 0, y: 0, z: 1 }\n : { x: 1, y: 0, z: 0 }\n\nconst NO_AXIS: Vector3 = { x: 1, y: 0, z: 0 }\n\n/** A perp lane's roll, re-derived from the last: the axis across the velocity (`0x6233330`). */\nconst carryAxis = (s: Float32Array, o: number) => {\n let vx = s[o + VELOCITY]!\n let vy = s[o + VELOCITY + 1]!\n let vz = s[o + VELOCITY + 2]!\n const ax = s[o + AXIS]!\n const ay = s[o + AXIS + 1]!\n const az = s[o + AXIS + 2]!\n const squared = Math.fround(vx * vx + vy * vy + vz * vz)\n const length = squared * inverseLength(squared)\n\n if (length > 1e-6) {\n vx /= length\n vy /= length\n vz /= length\n } else if (ax * ax <= 1e-8 && (1 - ay) * (1 - ay) <= 1e-8 && az * az <= 1e-8) {\n vx = 1\n vy = vz = 0\n } else {\n vx = vz = 0\n vy = 1\n }\n\n // n = a × v, and the new axis is v × n normalised: a with its part along v removed.\n const nx = vz * ay - vy * az\n const ny = az * vx - vz * ax\n const nz = vy * ax - ay * vx\n const i = inverseLength(Math.fround(nx * nx + ny * ny + nz * nz))\n\n s[o + AXIS] = vy * nz * i - vz * ny * i\n s[o + AXIS + 1] = vz * nx * i - vx * nz * i\n s[o + AXIS + 2] = vx * ny * i - vy * nx * i\n}\n\nexport class EffectInstance {\n readonly top: RunNode[] = []\n readonly context: RunContext\n /** Seconds, the effect's clock, which is also its top nodes' age. */\n time = 0\n /** `view` as given to the last advance, and the one before, for the dust. */\n view?: Matrix4\n previousView?: Matrix4\n lastStep = 0\n cameraTravel = 0\n previousTravel = Number.NaN\n readonly #run: EffectRun\n\n constructor(\n scene: EffectScene,\n { lookup, pools }: { lookup?: EffectLookup; pools?: EffectPools } = {},\n ) {\n this.context = { pools: pools ?? createPools(), lookup, sparam: 0, lod: 1 }\n this.#run = this.#start(scene, undefined)\n }\n\n /**\n * No live appearance: what the game asks before dropping an effect (`+0x2c(4)`,\n * `Freelancer!0x4f8a88`). An emitter, field or folder still alive doesn't keep it.\n */\n get finished(): boolean {\n return appearancesDone(this.#run)\n }\n\n /** Its emitters stop, and what they made lives out (`+0x34(1)`, `0x4f84d0`). */\n stop(): void {\n stopRun(this.#run, this.top)\n }\n\n /**\n * Gone: every node dies at once, and what it held leaves the pools, as the game releases the Alchemy\n * instance of an effect it destroys. One dropped without this keeps its share of the pools, and\n * every later birth counts it.\n */\n release(): void {\n for (const node of this.top) kill(node)\n this.top.length = 0\n }\n\n /**\n * Every live particle, in sub-effects too: which appearance holds it, its age and span, and where it\n * stands and heads in the world, as the sprite's vertex stage carries a record to now.\n */\n eachParticle(\n visit: (\n node: EffectNode,\n age: number,\n life: number,\n position: Vector3,\n velocity: Vector3,\n ) => void,\n ): void {\n const walk = (node: RunNode) => {\n if (node.dead) return\n\n const { lane, records } = node as AppearanceNode\n const entry = node.run.scene.nodes[node.index]!\n const { world } = node\n\n const place = (\n state: Float32Array,\n o: number,\n elapsed: number,\n age: number,\n life: number,\n ) => {\n const v = {\n x: state[o + VELOCITY]!,\n y: state[o + VELOCITY + 1]!,\n z: state[o + VELOCITY + 2]!,\n }\n const p = {\n x: state[o + POSITION]! + v.x * elapsed,\n y: state[o + POSITION + 1]! + v.y * elapsed,\n z: state[o + POSITION + 2]! + v.z * elapsed,\n }\n\n visit(\n entry,\n age,\n life,\n Matrix4.transformPoint(p, world),\n Matrix4.transformDirection(v, world),\n )\n }\n\n if (lane)\n for (let i = lane.tail; i < lane.head; i++) {\n const o = i * RECORD\n if (!aliveAt(lane, o)) continue\n\n const elapsed = lane.clock - lane.records[o + BORN]!\n\n place(lane.records, o, elapsed, lane.records[o + AGE]! + elapsed, lane.records[o + LIFE]!)\n }\n\n // A life effect's particle is moved on the CPU each step (`#placeLife`), so it stands as kept.\n if (records)\n for (const { state } of records)\n if (state[AGE]! <= state[LIFE]!) place(state, 0, 0, state[AGE]!, state[LIFE]!)\n\n for (const child of node.children) walk(child)\n }\n for (const node of this.top) walk(node)\n }\n\n /** One of the game's frames, at the step the host chooses (`0x4f8a20`). */\n advance(\n dt: number,\n { sparam, lod, placement, placing = 'world', view }: AdvanceOptions = {},\n ): void {\n const { context, top } = this\n if (sparam !== undefined) context.sparam = sparam\n if (lod !== undefined) context.lod = lod\n this.time += dt\n this.previousView = this.view\n this.view = view\n this.lastStep = dt\n\n if (view && this.previousView) {\n // The camera's travel in the world: the view's translation back through its rotation.\n const here = frameInverse(view).w\n const last = frameInverse(this.previousView).w\n\n this.previousTravel = this.cameraTravel\n this.cameraTravel = Math.hypot(here.x - last.x, here.y - last.y, here.z - last.z)\n }\n\n if (placement) {\n const { root } = this.#run\n const key = placing === 'world' ? 'placed' : 'override'\n\n if (root) root[key] = placement\n else for (const node of this.#run.top) node[key] = placement\n }\n\n for (const node of top.slice()) this.#compose(node, Matrix4.identity)\n for (const node of top.slice()) this.#walk(node, dt, top)\n }\n\n #compose(node: RunNode, parent: Matrix4): void {\n if (node.dead) return\n\n const { sparam } = this.context\n const { descriptor } = node\n if (descriptor?.kind === 'particle-appearance') this.#startDeaths(node as AppearanceNode)\n\n if (node.placed) {\n // Flag 8: this compose keeps the world it was handed and clears the flag.\n node.world = node.placed\n node.placed = undefined\n } else {\n const local = localMatrix(descriptor?.transform, sparam, node.age)\n const placed = node.override ? Matrix4.multiply(parent, node.override) : parent\n\n node.world = local ? Matrix4.multiply(placed, local) : placed\n }\n\n for (const child of node.children.slice()) this.#compose(child, node.world)\n }\n\n /** `0x6201810`. A node that says it's done dies here, with all that hangs from it. */\n #walk(node: RunNode, dt: number, top: RunNode[]): void {\n if (node.dead) return\n\n if (node.update(dt)) {\n kill(node)\n detach(node, top)\n return\n }\n\n for (const child of node.children.slice()) this.#walk(child, dt, top)\n }\n\n /** Builds a run's nodes, links them in entry order, then applies its `Pair` records in order. */\n #start(scene: EffectScene, parent: AppearanceNode | undefined): EffectRun {\n const run: EffectRun = { context: this.context, scene, nodes: [], top: [] }\n\n scene.nodes.forEach((entry, index) => {\n const node: RunNode = {\n run,\n index,\n key: entry.key,\n descriptor: entry.descriptor,\n parent: undefined,\n children: [],\n age: 0,\n // Reported, and inert rather than a clock that kills what hangs from it.\n lifeSpan: entry.descriptor?.lifeSpan ?? Infinity,\n dead: false,\n world: Matrix4.identity,\n update: () => false,\n }\n\n run.nodes.push(node)\n })\n\n // A flagged entry takes the longest lifespan below it, 0 with none (`0x621f526`). Top level first.\n const order = [...scene.top, ...scene.nodes.keys()].filter((v, i, a) => a.indexOf(v) === i)\n\n for (const index of order) {\n const entry = scene.nodes[index]!\n if (entry.descriptor?.category !== 'folder') continue\n\n const longest = (of: number): number =>\n scene.nodes[of]!.children.reduce(\n (most, child) => Math.max(most, run.nodes[child]!.lifeSpan, longest(child)),\n 0,\n )\n\n run.nodes[index]!.lifeSpan = longest(index)\n }\n\n scene.nodes.forEach((entry, index) => {\n const node = run.nodes[index]!\n\n node.parent = entry.parent >= 0 ? run.nodes[entry.parent] : parent\n this.#behave(node)\n })\n for (const node of run.nodes) insertChild(node.parent, this.top, node)\n run.top = scene.top.map((index) => run.nodes[index]!)\n if (scene.root !== undefined) run.root = run.nodes[scene.root]\n scene.nodes.forEach((entry, index) => {\n const node = run.nodes[index]!\n\n for (const target of entry.targets) {\n const other = run.nodes[target]!\n\n if (node.descriptor?.category === 'emitter') this.#associate(node, other)\n else if (\n node.descriptor?.category === 'appearance' &&\n other.descriptor?.category === 'field'\n )\n (node as AppearanceNode).fields.push(other as FieldNode)\n }\n })\n return run\n }\n\n /** An emitter has one slot (`+0x98`), so a later link replaces it, and the old count stays. */\n #associate(node: RunNode, other: RunNode): void {\n const emitter = node as EmitterNode\n\n if (other.descriptor?.category !== 'appearance') {\n emitter.target = undefined\n return\n }\n\n emitter.target = other as AppearanceNode\n emitter.fresh = true\n emitter.target.refs++\n }\n\n #behave(node: RunNode): void {\n const { descriptor } = node\n\n switch (descriptor?.category) {\n case 'emitter':\n return this.#behaveEmitter(node as EmitterNode, descriptor)\n case 'appearance':\n return this.#behaveAppearance(node as AppearanceNode, descriptor)\n case 'field':\n return this.#behaveField(node as FieldNode, descriptor)\n default:\n node.update = (dt) => {\n node.age += dt\n return node.age > node.lifeSpan\n }\n }\n }\n\n #behaveField(node: FieldNode, descriptor: Field): void {\n node.state = { kind: 'beam-field' }\n\n const { context } = this\n const blendOf = (approach: number, dt: number) => Math.min(1, dt * approach * 4)\n\n node.update = (dt) => {\n node.age += dt\n\n const at = (c: AnimatedCurve | undefined, fallback: number) =>\n curve(c, context.sparam, node.age, fallback)\n\n switch (descriptor.kind) {\n case 'gravity-field':\n node.state = { kind: descriptor.kind, change: at(descriptor.gravity, 9.8) * dt }\n break\n case 'air-field':\n node.state = {\n kind: descriptor.kind,\n magnitude: at(descriptor.magnitude, 1),\n blend: blendOf(at(descriptor.approach, 1), dt),\n }\n break\n case 'turbulence-field':\n node.state = {\n kind: descriptor.kind,\n magnitude: at(descriptor.magnitude, 10),\n blend: blendOf(at(descriptor.approach, 1), dt),\n }\n break\n case 'radial-field':\n node.state = {\n kind: descriptor.kind,\n magnitude: at(descriptor.magnitude, 10),\n inverseRadius: 1 / Math.max(at(descriptor.radius, 50), 0.001),\n attenuation: descriptor.attenuation,\n blend: blendOf(at(descriptor.approach, 0.3), dt),\n }\n break\n case 'collide-field':\n node.state = {\n kind: descriptor.kind,\n reflectivity: at(descriptor.reflectivity, 0.7),\n dt,\n }\n break\n case 'dust-field':\n node.state = { kind: descriptor.kind, radius: at(descriptor.maxRadius, 60.1) }\n break\n case 'beam-field':\n break\n }\n\n return node.age > node.lifeSpan\n }\n }\n\n #behaveAppearance(node: AppearanceNode, descriptor: Appearance): void {\n node.refs = 0\n node.fields = []\n node.died = () => {\n this.context.pools.held.get(descriptor.kind)?.delete(node)\n }\n\n if (descriptor.kind === 'particle-appearance') {\n node.records = []\n node.update = (dt) => this.#updateSpawner(node, descriptor, dt)\n return\n }\n\n const entry = node.run.scene.nodes[node.index]!\n\n const stepped = entry.targets.some((target) => {\n const linked = node.run.scene.nodes[target]!.descriptor\n\n return linked?.category === 'field' && linked.kind !== 'beam-field'\n })\n\n const lane = createLane(stepped)\n\n node.lane = lane\n\n const perp = descriptor.kind === 'perp-appearance'\n\n node.update = (dt) => {\n node.age += dt\n\n const empty = node.refs === 0 && lane.count === 0\n\n if (lane.stepped) this.#stepLane(node, lane, dt, perp)\n else {\n lane.clock += dt\n rebase(lane)\n\n let count = 0\n const { head } = lane\n for (let i = lane.tail; i < head; i++) if (aliveAt(lane, i * RECORD)) count++\n lane.count = count\n while (lane.tail < head && !aliveAt(lane, lane.tail * RECORD)) lane.tail++\n }\n\n // It never checks its own clock: an appearance's `Node_LifeSpan` alone doesn't stop it (`0x6216441`).\n return empty\n }\n }\n\n /** The list appearance's update: fields over every record, then age and move (`0x62188c0`). */\n #stepLane(node: AppearanceNode, lane: Lane, dt: number, perp: boolean): void {\n const { records } = lane\n\n applyFields(node, (apply) => {\n for (let i = 0; i < lane.head; i++) apply(records, i * RECORD)\n })\n\n // One pass: age, drop the dead, slide survivors down to `write` in order, then move them.\n let write = 0\n\n for (let read = 0; read < lane.head; read++) {\n const o = read * RECORD\n const age = records[o + AGE]! + dt\n if (age > records[o + LIFE]!) continue\n\n const w = write * RECORD\n if (w !== o) records.copyWithin(w, o, o + RECORD)\n records[w + AGE] = age\n records[w] = records[w]! + records[w + VELOCITY]! * dt\n records[w + 1] = records[w + 1]! + records[w + VELOCITY + 1]! * dt\n records[w + 2] = records[w + 2]! + records[w + VELOCITY + 2]! * dt\n if (perp) carryAxis(records, w)\n write++\n }\n\n lane.head = write\n lane.count = write\n for (let i = 0; i < write; i++) records[i * RECORD + BORN] = lane.clock\n lane.version++\n }\n\n #updateSpawner(node: AppearanceNode, descriptor: ParticleAppearance, dt: number): boolean {\n node.age += dt\n\n const records = node.records!\n const empty = node.refs === 0 && records.length === 0\n\n applyFields(node, (apply) => {\n for (const { state } of records) if (state[AGE]! < state[LIFE]!) apply(state, 0)\n })\n\n let write = 0\n\n for (const record of records) {\n const { state } = record\n\n if (state[AGE]! <= state[LIFE]!) {\n state[AGE]! += dt\n\n if (!(state[AGE]! > state[LIFE]!)) this.#placeLife(descriptor, record, dt)\n else if (!runFinished(record.lifeRun)) stopRun(record.lifeRun, node.children)\n\n records[write++] = record\n continue\n }\n\n if (\n !runFinished(record.lifeRun) ||\n (record.deathRun !== undefined && !runFinished(record.deathRun))\n ) {\n records[write++] = record\n continue\n }\n\n killRun(record.lifeRun, node)\n if (record.deathRun) killRun(record.deathRun, node)\n }\n\n records.length = write\n return empty\n }\n\n /** `0x622ff00`: moves a particle, and hands its life effect `[R | p]`. */\n #placeLife(descriptor: ParticleAppearance, record: ParticleRecord, dt: number): void {\n const { state } = record\n\n state[0]! += state[VELOCITY]! * dt\n state[1]! += state[VELOCITY + 1]! * dt\n state[2]! += state[VELOCITY + 2]! * dt\n\n const position = { x: state[0]!, y: state[1]!, z: state[2]! }\n let placed = Matrix4.translation(position)\n\n if (descriptor.useDynamicRotation) {\n const velocity = { x: state[VELOCITY]!, y: state[VELOCITY + 1]!, z: state[VELOCITY + 2]! }\n let turn = turnTo(velocity)\n\n if (descriptor.smoothRotation) {\n const speed = Math.hypot(velocity.x, velocity.y, velocity.z)\n let blend = speed * dt\n\n if (!(speed >= 0.5)) {\n turn = Quat.identity\n blend = dt + 0.01\n }\n\n record.blend = Quat.slerp(record.blend, turn, Math.min(blend, 1))\n turn = record.blend\n }\n\n placed = Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(turn), position)\n }\n\n this.#place(record.lifeRun, placed)\n }\n\n #place(run: EffectRun, placed: Matrix4): void {\n if (run.root) run.root.override = placed\n else for (const node of run.top) node.override = placed\n }\n\n /** `0x622fcf0`: a death effect starts where its particle stands, unturned, in the next compose. */\n #startDeaths(node: AppearanceNode): void {\n const descriptor = node.descriptor as ParticleAppearance\n if (!descriptor.deathName) return\n\n for (const record of node.records!) {\n const { state } = record\n if (record.deathRun || !(state[AGE]! > state[LIFE]!)) continue\n\n const scene = this.context.lookup?.(descriptor.deathName)\n if (!scene) continue\n record.deathRun = this.#start(scene, node)\n this.#place(\n record.deathRun,\n Matrix4.translation({ x: state[0]!, y: state[1]!, z: state[2]! }),\n )\n }\n }\n\n /** A birth handed over from an emitter (`+0xbc`), through the pool. */\n #spawn(\n node: AppearanceNode,\n position: Vector3,\n velocity: Vector3,\n age: number,\n life: number,\n ): void {\n const { descriptor } = node\n const { context } = this\n\n claim(context, node)\n\n const serial = context.pools.serial++\n\n if (descriptor.kind === 'particle-appearance') {\n // No name, or one no library defines, and no particle is born (`0x622f6fc`, `0x622f742`).\n const scene = descriptor.lifeName ? context.lookup?.(descriptor.lifeName) : undefined\n if (!scene) return\n\n const state = new Float32Array(RECORD)\n\n state.set([position.x, position.y, position.z, velocity.x, velocity.y, velocity.z])\n state[AGE] = age\n state[LIFE] = life\n state[SERIAL] = serial\n\n const lifeRun = this.#start(scene, node)\n const record: ParticleRecord = { state, lifeRun, blend: Quat.identity }\n\n node.records!.push(record)\n this.#placeLife(descriptor, record, 0)\n return\n }\n\n const axis = descriptor.kind === 'perp-appearance' ? perpSeed(velocity) : NO_AXIS\n\n appendRecord(node.lane!, [position, velocity], age, life, axis, serial)\n }\n\n #behaveEmitter(node: EmitterNode, descriptor: Emitter): void {\n node.fresh = true\n node.last = 0\n node.carry = 0\n node.previous = { x: 0, y: 0, z: 0 }\n node.died = () => {\n if (node.target) node.target.refs--\n }\n\n const { context } = this\n const emit = this.#emitter(node, descriptor)\n\n // `0x6245bf0`.\n node.update = (dt) => {\n node.age += dt\n\n const expired = node.age > node.lifeSpan\n const target = node.target\n if (!target) return expired\n\n if (target.dead) {\n node.target = undefined\n return expired\n }\n\n emit(target, context.sparam, node.age)\n return expired\n }\n }\n\n #emitter(node: EmitterNode, descriptor: Emitter) {\n const { context } = this\n\n return (target: AppearanceNode, sparam: number, t: number) => {\n const at = (c: AnimatedCurve | undefined, fallback: number) => curve(c, sparam, t, fallback)\n const pressure = at(descriptor.pressure, 10)\n const lifeSpan = at(descriptor.initLifeSpan, 2)\n const frequency = at(descriptor.frequency, 100)\n const elapsed = t - node.last\n let count = Math.trunc(elapsed * frequency)\n const here = node.world.w\n\n if (node.fresh) {\n node.fresh = false\n count += Math.trunc(descriptor.initialParticles)\n node.previous = { x: here.x, y: here.y, z: here.z }\n }\n\n for (const { key, value } of descriptor.emitCount?.keyframes[0]?.keyframes ?? []) {\n if (key < node.last) continue\n if (key > t) break\n count = Math.trunc(count + value.x)\n }\n\n const lod = descriptor.lodCurve ? floatAt(descriptor.lodCurve, sparam, context.lod) : 1\n const sum = lod * count + node.carry\n const total = Math.trunc(sum)\n\n node.carry = sum - total\n\n if (!total) {\n if (!frequency) node.last = t\n return\n }\n\n const path = transposeInto(node.world, node.previous)\n\n node.previous = { x: here.x, y: here.y, z: here.z }\n\n // The whole path lends the velocity; only its share per birth spaces them (`0x6245fa0`).\n const share = elapsed > 0 ? -at(descriptor.velocityApproach, 0) / elapsed : 0\n const bias = { x: path.x * share, y: path.y * share, z: path.z * share }\n\n if (target.parent === node.parent) path.x = path.y = path.z = 0\n\n const room = at(descriptor.maxParticles, 10000) - held(target)\n let births = room < total ? Math.trunc(room) : total\n // This library's rule, not read: a birth with no life would last until the next update at most.\n if (!(lifeSpan > 0)) births = 0\n\n const frame = Matrix4.multiply(frameInverse(target.world), node.world)\n\n // Births spread back across the step: the n-th is `age` old, already `v × age` along its heading\n // and `path × back` along the emitter's travel; `frame` takes emitter space to the target's.\n for (let n = 1; n <= births; n++) {\n const back = 1 - n / total\n const age = elapsed * back\n const { point, direction } = this.#shape(descriptor, sparam, t)\n const vx = direction.x * pressure\n const vy = direction.y * pressure\n const vz = direction.z * pressure\n const position = Matrix4.transformPoint(\n {\n x: point.x + vx * age + path.x * back,\n y: point.y + vy * age + path.y * back,\n z: point.z + vz * age + path.z * back,\n },\n frame,\n )\n const velocity = scaled(frame, { x: vx + bias.x, y: vy + bias.y, z: vz + bias.z })\n\n this.#spawn(target, position, velocity, age, lifeSpan)\n }\n\n node.last = t\n }\n }\n\n /** A unit vector off +Y by a random angle in `min`..`max` degrees, at a random azimuth, z negated. */\n #spread(min: number, max: number): Vector3 {\n const { pools } = this.context\n const phi = random(pools) * 2 * Math.PI\n const theta = (min + random(pools) * (max - min)) * (Math.PI / 180)\n const sin = Math.sin(theta)\n\n return { x: Math.cos(phi) * sin, y: Math.cos(theta), z: -Math.sin(phi) * sin }\n }\n\n /** Where a particle appears and which way it leaves, random draws in the DLL's order, about +Y. */\n #shape(descriptor: Emitter, sparam: number, t: number) {\n const { pools } = this.context\n const at = (c: AnimatedCurve | undefined, fallback: number) => curve(c, sparam, t, fallback)\n\n switch (descriptor.kind) {\n // `0x621d430`: half-extents, height drawn first, and a heading independent of the point.\n case 'cube-emitter': {\n const direction = this.#spread(at(descriptor.minSpread, 0), at(descriptor.maxSpread, 15))\n const y = 2 * (random(pools) - 0.5) * at(descriptor.height, 5)\n const x = 2 * (random(pools) - 0.5) * at(descriptor.width, 5)\n const z = 2 * (random(pools) - 0.5) * at(descriptor.depth, 5)\n\n return { point: { x, y, z }, direction }\n }\n // `0x623bd60`: a point of the cube normalized, so it leans towards the diagonals.\n case 'sphere-emitter': {\n const b = 2 * (random(pools) - 0.5)\n const a = 2 * (random(pools) - 0.5)\n const c = 2 * (random(pools) - 0.5)\n const i = inverseLength(Math.fround(a * a + b * b + c * c))\n const direction = { x: a * i, y: b * i, z: c * i }\n const min = at(descriptor.minRadius, 0)\n const radius = min + random(pools) * (at(descriptor.maxRadius, 1) - min)\n\n return {\n point: { x: direction.x * radius, y: direction.y * radius, z: direction.z * radius },\n direction,\n }\n }\n // `0x621ba90`.\n case 'cone-emitter': {\n const direction = this.#spread(at(descriptor.minSpread, 0), at(descriptor.maxSpread, 0))\n const min = at(descriptor.minRadius, 0)\n const radius = min + random(pools) * (at(descriptor.maxRadius, 1) - min)\n\n return {\n point: { x: direction.x * radius, y: direction.y * radius, z: direction.z * radius },\n direction,\n }\n }\n }\n }\n}\n\ninterface EmitterNode extends RunNode {\n target?: AppearanceNode\n /** Adds `InitialParticles` once, and takes where it stands now (`0x6245cd9`). */\n fresh: boolean\n last: number\n carry: number\n previous: Vector3\n}\n","/** An effect's appearances as draws, in the game's order (`0x6201910`). Pure, no GL. */\nimport {\n curveAt,\n floatAt,\n colorAt,\n type AnimatedColor,\n type AnimatedFloat,\n type Blending,\n} from '@treewyrm/freelancer/alchemy'\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture, TextureEntry } from '@treewyrm/freelancer/texture'\nimport { frameAtlas, playbackFrame } from '#/texture/playback.js'\nimport type { AppearanceNode, EffectInstance, FieldNode, Lane, RunNode } from './effect.js'\nimport { AGE, BORN, LIFE, POSITION, RECORD } from './effect.js'\nimport type { UVRect } from './curves.js'\nimport type { EffectNode } from './tree.js'\nimport type { Appearance, BeamAppearance, OrientedAppearance, Sprite } from './nodes.js'\nimport { frameInverse, localMatrix } from './transform.js'\n\nexport const FACING_CAMERA = 0\nexport const FACING_TRAVEL = 1\nexport const FACING_PERPENDICULAR = 2\nexport const FACING_NODE = 3\nexport const FACING_DUST = 4\n\nexport const SHAPE_QUAD = 0\nexport const SHAPE_TRIANGLE = 1\nexport const SHAPE_TRI_TEXTURE = 2\n\nexport const KIND_BASIC = 0\nexport const KIND_PERP = 1\nexport const KIND_RECT = 2\nexport const KIND_DUST = 3\nexport const KIND_ORIENTED = 4\n\nexport interface EffectDrawCommon {\n /** The appearance, as its file names it. */\n node: EffectNode\n /** The appearance's world, as last composed: the game draws with it unadvanced. */\n world: Matrix4\n texture?: { name: string; entry: Texture }\n blend?: Blending\n}\n\n/** The lists a sprite reads, keyed in the vertex stage by each particle's age. */\nexport interface SpriteLists {\n kind: number\n color?: AnimatedColor\n alpha?: AnimatedFloat\n a?: AnimatedFloat\n b?: AnimatedFloat\n c?: AnimatedFloat\n roll?: AnimatedFloat\n frame?: AnimatedFloat\n}\n\nexport interface SpriteDraw extends EffectDrawCommon {\n type: 'sprite'\n lane: Lane\n /** Its clock now: what `BORN` is read against. */\n time: number\n sparam: number\n /** `Appearance_LODCurve` at the host's key, on every extent but the dust's. */\n extent: number\n facing: number\n shape: number\n blur: boolean\n centered: boolean\n fade: boolean\n lists: SpriteLists\n /** The atlas frames a particle's own clock picks among. */\n frames: readonly UVRect[]\n /** Which of them a particle's -1 picks: the playback's. 0 when absent. */\n currentFrame?: number\n /** The camera, in the appearance's frame. */\n eye: Vector3\n dust?: { previous: Matrix4; step: number; fade: number }\n}\n\n/** Interleaved `position, colour, uv` triangles, already in the appearance's frame: a beam, or what the vertex stage can't key. */\nexport interface TriangleDraw extends EffectDrawCommon {\n type: 'triangles'\n vertices: Float32Array\n count: number\n}\n\nexport type EffectDraw = SpriteDraw | TriangleDraw\n\nconst GREY: Vector3 = { x: 0.8, y: 0.8, z: 0.8 }\n\nconst FULL: UVRect = { u1: 0, v1: 0, u2: 1, v2: 1 }\n\nconst rectOf = (rect: UVRect, { flipU, flipV }: Sprite): UVRect => ({\n u1: flipU ? rect.u2 : rect.u1,\n u2: flipU ? rect.u1 : rect.u2,\n v1: flipV ? rect.v2 : rect.v1,\n v2: flipV ? rect.v1 : rect.v2,\n})\n\n/**\n * A sprite's texture and frames: `FFxTextureWrapper`, whose playback is the appearance's own and\n * clamps (`Resolve`). `UseCommonTexFrame` picks a frame by the node's clock, and its atlas and rect\n * come with it. Otherwise each particle picks a rect, all of them on the atlas the playback is at,\n * advanced by every update but a beam's (`Texture_.Advance`), so by the node's age.\n */\nconst spriteTexture = (\n descriptor: Sprite,\n node: RunNode,\n sparam: number,\n texture: (name: string) => TextureEntry | undefined,\n unsupported: Set<string>,\n advanced: boolean,\n): {\n texture?: { name: string; entry: Texture }\n frames: readonly UVRect[]\n /** The frame a particle's `-1` reads. */\n current?: number\n} => {\n const name = descriptor.texture\n const plain = { frames: [rectOf(FULL, descriptor)] }\n if (!name) return plain\n\n const entry = texture(name)\n\n if (!entry) {\n unsupported.add(`texture ${name}`)\n return plain\n }\n\n if (entry.type === 'cube') return plain\n if (entry.type !== 'animated') return { ...plain, texture: { name, entry } }\n if (!entry.frames.length) return plain\n\n const count = entry.frames.length\n const current =\n advanced && !descriptor.useCommonTexFrame ? playbackFrame(entry, node.age, 'clamp') : 0\n\n const at = (frame: number) => {\n const bound = frameAtlas(entry, frame, texture)\n if (!bound) unsupported.add(`texture ${entry.name}`)\n return bound\n }\n\n if (descriptor.useCommonTexFrame) {\n const position = descriptor.commonTexFrame\n ? curveAt(descriptor.commonTexFrame, sparam, node.age)\n : 0\n const frame = count === 1 ? 0 : pickFrame(Math.trunc(position * (count - 1)), count, current)\n\n return { texture: at(frame), frames: [rectOf(entry.frames[frame]!, descriptor)] }\n }\n\n return {\n texture: at(current),\n frames: entry.frames.map((frame) => rectOf(frame, descriptor)),\n current,\n }\n}\n\n/** `GetFrame`'s choice (`FUN_06ebe7f0`): -1 is the current frame, and anything else outside is the last. */\nexport const pickFrame = (frame: number, count: number, current: number): number =>\n frame === -1 ? current : frame < 0 || frame >= count ? count - 1 : frame\n\nconst listsOf = (descriptor: Appearance): SpriteLists | undefined => {\n switch (descriptor.kind) {\n case 'basic-appearance':\n return {\n kind: KIND_BASIC,\n color: descriptor.color,\n alpha: descriptor.alpha,\n a: descriptor.size,\n b: descriptor.aspect,\n roll: descriptor.rotate,\n frame: descriptor.texFrame,\n }\n case 'perp-appearance':\n return {\n kind: KIND_PERP,\n color: descriptor.color,\n alpha: descriptor.alpha,\n a: descriptor.size,\n frame: descriptor.texFrame,\n }\n case 'rect-appearance':\n return {\n kind: KIND_RECT,\n color: descriptor.color,\n alpha: descriptor.alpha,\n a: descriptor.width,\n b: descriptor.length,\n c: descriptor.scale,\n frame: descriptor.texFrame,\n }\n case 'dust-appearance':\n return {\n kind: KIND_DUST,\n color: descriptor.color,\n alpha: descriptor.alpha,\n a: descriptor.size,\n }\n case 'oriented-appearance':\n return {\n kind: KIND_ORIENTED,\n color: descriptor.color,\n alpha: descriptor.alpha,\n a: descriptor.width,\n b: descriptor.height,\n c: descriptor.scale,\n frame: descriptor.texFrame,\n }\n default:\n return undefined\n }\n}\n\n/** The camera's speed fades all of the dust: none at rest, full at 100, none at 1,200 (`0x620fcb0`). */\nexport const dustFade = (travel: number, previous: number, step: number): number => {\n const speed = travel / step\n let fade =\n speed < 100 ? 1 - (1 - speed / 100) ** 2 : speed < 1200 ? 1 - ((speed - 100) / 1100) ** 2 : 0\n // Kept when the previous travel is unknown, as the routine's compare falls through on a NaN.\n const jerk = Math.abs(previous - travel)\n if (jerk > 20) fade = jerk < 35 ? fade * (1 - (jerk - 20) / 15) : 0\n return fade\n}\n\nconst FLOATS = 9\n\n/** `_ftol(c × 255)`, keeping the low byte, as the vertex colour packs it (`0x620610d`). */\nconst packed = (c: number) => (Math.trunc(c * 255) & 0xff) / 255\n\ninterface BeamPoint {\n x: number\n y: number\n z: number\n half: number\n r: number\n g: number\n b: number\n a: number\n mirrored: boolean\n}\n\n/**\n * A beam's chain, newest first, opened on each point into a cross along the camera's axes. Built here,\n * as the game does, since every point is read and most are skipped or shifted (`0x6205720`).\n */\nconst beamVertices = (\n node: AppearanceNode,\n descriptor: BeamAppearance,\n instance: EffectInstance,\n rect: UVRect,\n axes: readonly [Vector3, Vector3],\n): { vertices: Float32Array; count: number } | undefined => {\n const lane = node.lane!\n const { sparam, lod } = instance.context\n const extent = descriptor.lodCurve ? floatAt(descriptor.lodCurve, sparam, lod) : 1\n const live: number[] = []\n\n for (let i = lane.head - 1; i >= lane.tail; i--) {\n const o = i * RECORD\n const age = lane.records[o + AGE]! + (lane.clock - lane.records[o + BORN]!)\n if (age <= lane.records[o + LIFE]!) live.push(i)\n }\n\n if (!live.length) return undefined\n\n // The i-th newest live point now: birth position plus velocity (floats 3..5) × time since birth.\n const position = (i: number): Vector3 => {\n const o = live[i]! * RECORD\n const elapsed = lane.clock - lane.records[o + BORN]!\n\n return {\n x: lane.records[o + POSITION]! + lane.records[o + 3]! * elapsed,\n y: lane.records[o + POSITION + 1]! + lane.records[o + 4]! * elapsed,\n z: lane.records[o + POSITION + 2]! + lane.records[o + 5]! * elapsed,\n }\n }\n\n const ageOf = (i: number) => {\n const o = live[i]! * RECORD\n\n return lane.records[o + AGE]! + (lane.clock - lane.records[o + BORN]!)\n }\n\n const keyOf = (i: number) => {\n const life = lane.records[live[i]! * RECORD + LIFE]!\n\n return life > 0 ? Math.min(1, Math.max(0, ageOf(i) / life)) : 0\n }\n\n const points: BeamPoint[] = []\n const toggle = lane.births % 2\n\n const emit = (i: number, { x, y, z }: Vector3) => {\n const key = keyOf(i)\n const width =\n (descriptor.width ? floatAt(descriptor.width, sparam, key) : 1) *\n (descriptor.scale ? floatAt(descriptor.scale, sparam, key) : 1) *\n extent\n const { x: r, y: g, z: b } = descriptor.color ? colorAt(descriptor.color, sparam, key) : GREY\n const a = descriptor.alpha ? floatAt(descriptor.alpha, sparam, key) : 1\n\n points.push({\n x,\n y,\n z,\n half: width / 2,\n r,\n g,\n b,\n a: packed(a),\n mirrored: (points.length & 1) === toggle,\n })\n }\n\n const near = (a: Vector3, b: Vector3) =>\n (a.x - b.x) ** 2 + (a.y - b.y) ** 2 + (a.z - b.z) ** 2 <= 0.01\n\n // An `FLBeamField` it links is the head, wherever it stands.\n let anchor: Vector3 | undefined\n const inverse = frameInverse(node.world)\n\n for (const field of node.fields as FieldNode[])\n if (!field.dead && field.descriptor?.kind === 'beam-field') {\n anchor = Matrix4.transformPoint(field.world.w, inverse)\n break\n }\n\n let head: Vector3 | undefined\n\n if (anchor && !near(anchor, position(0))) head = anchor\n else if (live.length < 2) return undefined\n else if (!descriptor.disablePlaceHolder) {\n // Where a particle of age zero would be, from the two newest. Bunched, or a burst's two of one age, none.\n const p0 = position(0)\n const p1 = position(1)\n const r = ageOf(0) / (ageOf(1) - ageOf(0))\n\n if (!near(p0, p1) && Number.isFinite(r))\n head = {\n x: p0.x - (p1.x - p0.x) * r,\n y: p0.y - (p1.y - p0.y) * r,\n z: p0.z - (p1.z - p0.z) * r,\n }\n }\n\n // Without `DupeFirstParticle`, positions lag one point behind properties, and the oldest's is dropped.\n const shifted = head !== undefined && !descriptor.dupeFirstParticle\n\n if (head) emit(0, head)\n\n let last = head\n\n if (!shifted) {\n last = position(0)\n emit(0, last)\n }\n\n for (let i = 1; i < live.length; i++) {\n const at = position(shifted ? i - 1 : i)\n if (last && near(at, last)) continue\n emit(i, at)\n last = at\n }\n\n if (points.length < 2) return undefined\n\n const fan = descriptor.quadTexture\n const perSegment = (fan ? 12 : 6) * 2\n const vertices = new Float32Array((points.length - 1) * perSegment * FLOATS)\n let v = 0\n\n const write = (point: BeamPoint, axis: Vector3, side: number) => {\n vertices.set(\n [\n point.x + axis.x * point.half * side,\n point.y + axis.y * point.half * side,\n point.z + axis.z * point.half * side,\n point.r,\n point.g,\n point.b,\n point.a,\n side < 0 ? rect.u1 : rect.u2,\n point.mirrored ? rect.v1 : rect.v2,\n ],\n v,\n )\n v += FLOATS\n }\n\n // The centre takes UV (0.5, 0.5) literally, whatever the frame, and the far end's colour.\n const centre = (a: BeamPoint, b: BeamPoint) => {\n vertices.set(\n [(a.x + b.x) / 2, (a.y + b.y) / 2, (a.z + b.z) / 2, b.r, b.g, b.b, b.a, 0.5, 0.5],\n v,\n )\n v += FLOATS\n }\n\n // Per point pair and axis: a quad as two triangles, or with `QuadTexture` four round the midpoint.\n for (const axis of axes)\n for (let i = 0; i + 1 < points.length; i++) {\n const a = points[i]!\n const b = points[i + 1]!\n\n if (fan) {\n write(a, axis, -1)\n write(a, axis, 1)\n centre(a, b)\n write(a, axis, 1)\n write(b, axis, 1)\n centre(a, b)\n write(b, axis, 1)\n write(b, axis, -1)\n centre(a, b)\n write(b, axis, -1)\n write(a, axis, -1)\n centre(a, b)\n } else {\n write(a, axis, -1)\n write(a, axis, 1)\n write(b, axis, -1)\n write(a, axis, 1)\n write(b, axis, 1)\n write(b, axis, -1)\n }\n }\n\n return { vertices, count: v / FLOATS }\n}\n\n/**\n * Oriented sprites whose `MeshApp_ParticleTransform` has curves: each corner along that matrix's columns,\n * about the particle plus its translation (`0x622c6dd`). Nine Hermite curves per particle are the CPU's.\n */\nconst orientedVertices = (\n node: AppearanceNode,\n descriptor: OrientedAppearance,\n instance: EffectInstance,\n rect: UVRect,\n eye: Vector3,\n): { vertices: Float32Array; count: number } | undefined => {\n const lane = node.lane!\n const { sparam, lod } = instance.context\n const extent = descriptor.lodCurve ? floatAt(descriptor.lodCurve, sparam, lod) : 1\n const out: number[] = []\n const list = (property: AnimatedFloat | undefined, key: number) =>\n property ? floatAt(property, sparam, key) : 1\n\n for (let i = lane.tail; i < lane.head; i++) {\n const o = i * RECORD\n const elapsed = lane.clock - lane.records[o + BORN]!\n const age = lane.records[o + AGE]! + elapsed\n const life = lane.records[o + LIFE]!\n if (age > life) continue\n\n const key = life > 0 ? Math.min(1, Math.max(0, age / life)) : 0\n let alpha = list(descriptor.alpha, key)\n const scale = list(descriptor.scale, key) * extent\n if (alpha === 0 || scale < 1e-11) continue\n\n const matrix = localMatrix(descriptor.particleTransform, sparam, key) ?? Matrix4.identity\n const p = {\n x: lane.records[o]! + lane.records[o + 3]! * elapsed + matrix.w.x,\n y: lane.records[o + 1]! + lane.records[o + 4]! * elapsed + matrix.w.y,\n z: lane.records[o + 2]! + lane.records[o + 5]! * elapsed + matrix.w.z,\n }\n const width = list(descriptor.width, key) * scale\n const height = list(descriptor.height, key) * scale\n\n if (descriptor.viewingAngleFade) {\n // n = x × y, the face normal. c = 1 − |cos(eye, n)|, so alpha falls as the face turns edge-on:\n // full to c = 0.866025, then ((0.984808 − c) / 0.118783)², gone past 0.984808.\n const a = matrix.x\n const b = matrix.y\n const n = { x: a.y * b.z - a.z * b.y, y: a.z * b.x - a.x * b.z, z: a.x * b.y - a.y * b.x }\n const e = { x: eye.x - p.x, y: eye.y - p.y, z: eye.z - p.z }\n const length = Math.hypot(e.x, e.y, e.z)\n const c = 1 - Math.abs(length > 1e-6 ? (e.x * n.x + e.y * n.y + e.z * n.z) / length : n.y)\n if (c > 0.984808) continue\n if (c > 0.866025) alpha *= ((0.984808 - c) * 8.41876) ** 2\n if (alpha === 0) continue\n }\n\n const { x: r, y: g, z: b } = descriptor.color ? colorAt(descriptor.color, sparam, key) : GREY\n const corner = (cx: number, cy: number) =>\n out.push(\n p.x + matrix.x.x * width * cx + matrix.y.x * height * cy,\n p.y + matrix.x.y * width * cx + matrix.y.y * height * cy,\n p.z + matrix.x.z * width * cx + matrix.y.z * height * cy,\n r,\n g,\n b,\n packed(alpha),\n cx < 0 ? rect.u1 : rect.u2,\n cy > 0 ? rect.v1 : rect.v2,\n )\n\n corner(-1, 1)\n corner(1, 1)\n corner(1, -1)\n corner(-1, 1)\n corner(1, -1)\n corner(-1, -1)\n }\n\n return out.length ? { vertices: new Float32Array(out), count: out.length / FLOATS } : undefined\n}\n\nexport const collectEffect = (\n instance: EffectInstance,\n view: Matrix4,\n texture: (name: string) => TextureEntry | undefined,\n draws: EffectDraw[],\n unsupported: Set<string>,\n visible?: (node: EffectNode) => boolean,\n): void => {\n const { sparam, lod } = instance.context\n const camera = frameInverse(view)\n\n const visit = (node: RunNode) => {\n if (node.dead) return\n\n const shown = !visible || visible(node.run.scene.nodes[node.index]!)\n if (shown && node.descriptor?.category === 'appearance') appear(node as AppearanceNode)\n // What a hidden particle appearance started is its picture, and what's under it in the file isn't.\n for (const child of node.children) if (shown || child.run === node.run) visit(child)\n }\n\n const appear = (node: AppearanceNode) => {\n const { descriptor } = node\n if (descriptor.kind === 'particle-appearance') return\n\n if (descriptor.kind === 'mesh-appearance') {\n // The game's factory fails on every one of these and crashes on spawn (`0x6224ed9`).\n unsupported.add(`FxMeshAppearance ${descriptor.name}`)\n return\n }\n\n const lane = node.lane!\n if (!lane.count) return\n\n const {\n texture: bound,\n frames,\n current,\n } = spriteTexture(\n descriptor,\n node,\n sparam,\n texture,\n unsupported,\n descriptor.kind !== 'beam-appearance',\n )\n const common = {\n node: node.run.scene.nodes[node.index]!,\n world: node.world,\n texture: bound,\n blend: descriptor.blend,\n }\n\n if (descriptor.kind === 'beam-appearance') {\n // `S · W`'s first two columns, added in the frame, so `W` reaches them twice (`0x620592d`).\n const axes = Matrix4.multiply(camera, node.world)\n const beam = beamVertices(node, descriptor, instance, frames[0] ?? FULL, [axes.x, axes.y])\n if (beam) draws.push({ ...common, type: 'triangles', ...beam })\n return\n }\n\n if (descriptor.kind === 'oriented-appearance' && descriptor.particleTransform?.curves) {\n const eye = Matrix4.transformPoint(camera.w, frameInverse(node.world))\n const quads = orientedVertices(node, descriptor, instance, frames[0] ?? FULL, eye)\n if (quads) draws.push({ ...common, type: 'triangles', ...quads })\n return\n }\n\n const lists = listsOf(descriptor)\n if (!lists) return\n\n const extent =\n descriptor.kind === 'dust-appearance' || !descriptor.lodCurve\n ? 1\n : floatAt(descriptor.lodCurve, sparam, lod)\n // The basic routine's one test on it, before any particle (`0x62165ca`).\n if (descriptor.kind === 'basic-appearance' && extent === 0) return\n\n const previous = instance.previousView\n const dust =\n descriptor.kind === 'dust-appearance'\n ? previous && instance.lastStep > 0\n ? {\n previous: Matrix4.multiply(previous, node.world),\n step: instance.lastStep,\n fade: dustFade(instance.cameraTravel, instance.previousTravel, instance.lastStep),\n }\n : undefined\n : undefined\n if (descriptor.kind === 'dust-appearance' && !dust) return\n\n const eye = Matrix4.transformPoint(camera.w, frameInverse(node.world))\n const basic = descriptor.kind === 'basic-appearance'\n\n draws.push({\n ...common,\n type: 'sprite',\n lane,\n time: lane.clock,\n sparam,\n extent,\n facing: basic\n ? FACING_CAMERA\n : descriptor.kind === 'rect-appearance'\n ? FACING_TRAVEL\n : descriptor.kind === 'perp-appearance'\n ? FACING_PERPENDICULAR\n : descriptor.kind === 'dust-appearance'\n ? FACING_DUST\n : FACING_NODE,\n // `QuadTexture` alone picks the routine (`0x6217720`).\n shape:\n !basic || descriptor.quadTexture\n ? SHAPE_QUAD\n : descriptor.triTexture\n ? SHAPE_TRI_TEXTURE\n : SHAPE_TRIANGLE,\n blur:\n (basic && descriptor.quadTexture && descriptor.motionBlur) ||\n (descriptor.kind === 'rect-appearance' && descriptor.motionBlur),\n centered: descriptor.kind === 'rect-appearance' && descriptor.centerOnPos,\n fade: 'viewingAngleFade' in descriptor && descriptor.viewingAngleFade,\n lists,\n frames,\n // Within the list, whatever a negative rate reached, as its atlas has already gone unbound.\n ...(current ? { currentFrame: Math.min(Math.max(current, 0), frames.length - 1) } : {}),\n eye,\n dust,\n })\n }\n\n for (const node of instance.top) visit(node)\n}\n","/** What a VMesh becomes on the GPU. Pure, no GL. */\nimport {\n getMapCount,\n getMeshDraw,\n Primitive,\n vertexByteLength,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\n\n/** Fixed attribute locations, so every program fits every mesh. */\nexport const ATTRIBUTE_LOCATIONS = {\n position: 0,\n normal: 1,\n diffuse: 2,\n uv0: 3,\n uv1: 4,\n boneIndex: 5,\n boneWeight: 6,\n} as const\n\nexport type AttributeName = keyof typeof ATTRIBUTE_LOCATIONS\n\nexport interface VertexAttribute {\n name: AttributeName\n size: number\n /** `D3DCOLOR` bytes, B G R A: a shader reading `diffuse` wants `.bgra`. */\n normalizedBytes: boolean\n offset: number\n}\n\nexport interface VertexLayout {\n stride: number\n attributes: VertexAttribute[]\n}\n\n/** The FVF's layout: position, normal, point size, diffuse, specular, then UV sets. */\nexport const vertexLayout = (format: VertexFormat): VertexLayout => {\n const attributes: VertexAttribute[] = []\n let offset = 0\n\n // Floats take 4 bytes a component, `D3DCOLOR` one; `offset` runs on in the FVF's fixed order.\n const add = (name: AttributeName, size: number, normalizedBytes = false) => {\n attributes.push({ name, size, normalizedBytes, offset })\n offset += normalizedBytes ? size : size * 4\n }\n\n if (format & VertexFormat.Position) add('position', 3)\n if (format & VertexFormat.Normal) add('normal', 3)\n // Neither occurs in retail, and no material reads them, but they take up room in the stride.\n if (format & VertexFormat.PointSize) offset += 4\n if (format & VertexFormat.Diffuse) add('diffuse', 4, true)\n if (format & VertexFormat.Specular) offset += 4\n\n const maps = getMapCount(format)\n\n for (let map = 0; map < maps; map++) {\n if (map < 2) add(map === 0 ? 'uv0' : 'uv1', 2)\n else offset += 8\n }\n\n return { stride: vertexByteLength(format), attributes }\n}\n\nconst MODES: Partial<Record<Primitive, GLenum>> = {\n [Primitive.PointList]: 0,\n [Primitive.LineList]: 1,\n [Primitive.LineStrip]: 3,\n [Primitive.TriangleList]: 4,\n [Primitive.TriangleStrip]: 5,\n [Primitive.TriangleFan]: 6,\n}\n\n/** The `drawElements` mode: the game passes the primitive through unexamined. */\nexport const drawMode = (primitive: Primitive): GLenum => {\n const mode = MODES[primitive]\n if (mode === undefined) throw new RangeError(`Mesh has no primitive type: ${primitive}`)\n return mode\n}\n\nexport interface GroupDraw {\n /** CRC of the material name. */\n materialId: number\n /** Into the reference's index buffer. */\n byteOffset: number\n count: number\n}\n\nexport interface ReferencePlan {\n /** Absolute vertices, since WebGL2 has no base vertex parameter. */\n indices: Uint16Array\n groups: GroupDraw[]\n}\n\n/**\n * A reference's indices made absolute, one buffer per reference. Retail keeps `ref.vertexStart` as\n * `BaseVertexIndex`, with `group.vertexStart` already added to its indices (`li_elite`, draw 7).\n */\nexport const planReference = (data: VMeshData, reference: VMeshRef): ReferencePlan => {\n const draws = [...getMeshDraw(data, reference)]\n const indices = new Uint16Array(\n draws.reduce((total, { elementCount }) => total + elementCount, 0),\n )\n const groups: GroupDraw[] = []\n\n let written = 0\n\n for (const { materialId, startIndex, elementCount, baseVertex } of draws) {\n groups.push({\n materialId,\n byteOffset: written * Uint16Array.BYTES_PER_ELEMENT,\n count: elementCount,\n })\n\n for (let at = 0; at < elementCount; at++)\n indices[written++] = data.indices[startIndex + at]! + baseVertex\n }\n\n return { indices, groups }\n}\n","/** A compound model's parts in the scene, and what attaches to them. */\nimport {\n getJointMatrix,\n type CompoundNode,\n type Hardpoint,\n type Joint,\n type JointState,\n} from '@treewyrm/freelancer/compound'\nimport { Matrix3, Matrix4, Vector3 } from '@treewyrm/freelancer/math'\n\n/**\n * Every part's world transform: `W_child = W_parent · L_child`, the root at `model`. A joint with no\n * state stands at rest. Parts are keyed by identity.\n */\nexport const partTransforms = <T>(\n root: CompoundNode<T>,\n model: Matrix4,\n stateOf?: (part: CompoundNode<T>) => JointState | undefined,\n): Map<CompoundNode<T>, Matrix4> => {\n const transforms = new Map<CompoundNode<T>, Matrix4>()\n\n const visit = (part: CompoundNode<T>, parent: Matrix4) => {\n const world = part.joint\n ? Matrix4.multiply(parent, getJointMatrix(part.joint, stateOf?.(part)))\n : parent\n\n transforms.set(part, world)\n for (const child of part.children) visit(child, world)\n }\n\n visit(root, model)\n return transforms\n}\n\n// `0x6294265`: a float 2π, which a range is compared against in double.\nconst FULL_TURN = Math.fround(2 * Math.PI)\nconst HALF_TURN = Math.fround(Math.PI)\n// `DAT_0639c9e0`, the step `WrapLimitRange` takes. Its upper bound is 360, in degrees.\nconst WRAP_STEP = 6.2831854820251465\n\n/** `WrapLimitRange`: a range under a full turn, wrapped into [0, 360) by steps of 2π. */\nconst wrapRange = (range: number): number => {\n while (range < 0) range += WRAP_STEP\n while (range >= 360) range -= WRAP_STEP\n return range\n}\n\n/** A revolute hardpoint's range, and its limits opened to ±π at a full turn or more. */\nconst limitsOf = ({ min, max }: { min: number; max: number }) => {\n const range = max - min\n\n return range >= FULL_TURN\n ? { range, min: -HALF_TURN, max: HALF_TURN }\n : { range: wrapRange(range), min, max }\n}\n\n/** Retail's `A · B`, row-major, for two `Matrix3`s whose triples are rows (RENDERER.md). */\nconst product = (a: Matrix3, b: Matrix3): Matrix3 => Matrix3.multiply(b, a)\n\n/** Retail's `M · v`: `Matrix3.transform` applies the transpose. */\nconst rotate = (v: Vector3, m: Matrix3): Vector3 => Matrix3.transform(v, Matrix3.transpose(m))\n\n/**\n * The joint that hangs `child`'s hardpoint on `parent`'s, as attached equipment is connected\n * (`ConnectAttachedHardpoints`, `0x62940c0`, then `HardpointConnect`, `EngBase` `IHardpoint` slot 6).\n * Two revolute hardpoints make a revolute joint limited by the narrower range. Otherwise the child's\n * type decides: a fixed one lands its point and frame on the parent's, a revolute one turns about its\n * own axis within its own limits. A revolute joint's orientation is the parent's times the child's,\n * untransposed as retail has it; no reference attaches a child whose frame isn't the identity.\n */\nexport const attachJoint = (parent: Hardpoint, child: Hardpoint): Joint => {\n const parentAt = parent.position ?? Vector3.zero\n const childAt = child.position ?? Vector3.zero\n\n if (child.type === 'fixed') {\n const orientation = product(parent.orientation, Matrix3.transpose(child.orientation))\n const position = Vector3.subtract(parentAt, rotate(childAt, orientation))\n\n return { type: 'fixed', position, orientation }\n }\n\n const orientation = product(parent.orientation, child.orientation)\n const axis = rotate(child.axis, orientation)\n const joint = {\n type: 'revolute',\n position: parentAt,\n offset: childAt,\n orientation,\n axis,\n } as const\n if (parent.type !== 'revolute') return { ...joint, min: child.min, max: child.max }\n\n const outer = limitsOf(parent)\n const inner = limitsOf(child)\n const { min, max } = outer.range < inner.range ? outer : inner\n\n return { ...joint, min, max }\n}\n","/** Which level a character's part draws: `FCharacterObject::PickLods`, over `[DetailSwitchTable]`. Pure. */\nimport type { Level } from '@treewyrm/freelancer/deformable'\n\n/** A `bodyparts.ini` group's table: `switch = percent, distance` rows, the percent descending. */\nexport interface SwitchTable {\n rows: readonly (readonly [percent: number, distance: number])[]\n /** Degrees, the whole angle. `RETAIL_SWITCH_FOVX` when the section writes none. */\n fovx?: number\n}\n\n/** What a `[DetailSwitchTable]` with no `fovx` reads. A mod patching it passes its own as `fovx`. */\nexport const RETAIL_SWITCH_FOVX = 40\n\n/** `DetailSwitchTable::get_switch_distance`: linear between rows, clamped at both ends. */\nexport const switchDistance = ({ rows }: SwitchTable, percent: number): number => {\n const first = rows[0]!\n const last = rows.at(-1)!\n\n if (percent >= first[0]) return first[1]\n if (percent <= last[0]) return last[1]\n\n for (let at = 0; at + 1 < rows.length; at++) {\n const [a, b] = [rows[at]!, rows[at + 1]!]\n\n if (a[0] >= percent && b[0] <= percent)\n return ((percent - a[0]) * (b[1] - a[1])) / (b[0] - a[0]) + a[1]\n }\n\n return 1\n}\n\nconst tanDegrees = (degrees: number): number => Math.tan((degrees * Math.PI) / 180)\n\n/** `adjust_distance`: a narrow lens counts as closer, against the table's own. `fovh` is half the angle. */\nexport const adjustedDistance = (\n { fovx = RETAIL_SWITCH_FOVX }: SwitchTable,\n distance: number,\n fovh: number,\n): number => (tanDegrees(fovh) / tanDegrees(fovx / 2)) * distance\n\n/** The first level whose distance reaches this one, or none past the table's far cutoff. */\nexport const costumeLevel = (\n levels: readonly Level[],\n table: SwitchTable,\n distance: number,\n fovh: number,\n): number | undefined => {\n const adjusted = adjustedDistance(table, distance, fovh)\n\n const level = levels.findIndex(({ fraction }, at) => {\n // The last level's own distance is written over with the table's at 0 (`0x443de1`).\n const reach = switchDistance(table, at === levels.length - 1 ? 0 : fraction * 100)\n\n return !(reach < adjusted)\n })\n\n return level < 0 ? undefined : level\n}\n","/** A `.dfm` detail level as a mesh and its bone table: `FMeshArchetype::Skin`, in `Deformable2`. Pure, no GL. */\nimport { getResourceId } from '@treewyrm/freelancer'\nimport type { CompoundNode, Hardpoint, JointState } from '@treewyrm/freelancer/compound'\nimport {\n getBoneModel,\n type Bone,\n type DeformableModel,\n type Level,\n type UVBone,\n} from '@treewyrm/freelancer/deformable'\nimport { Matrix4 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n type VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport type { Camera } from '#/scene/camera.js'\nimport { partTransforms } from '#/scene/hierarchy.js'\nimport type { DrawSkin, PlacedPart } from '#/scene/frame.js'\nimport { costumeLevel, type SwitchTable } from './level.js'\n\n/** The game's table holds this many, and nothing checks it (`0x65f3898`). Retail's largest is 86. */\nexport const MAX_BONES = 150\n\nexport const INFLUENCE_FLOATS = 8\n\n// As retail's vertex buffer: position, normal and UV0, which is all `deformable2.dll` reads.\nconst FORMAT = 0x112 as VertexFormat\nconst STRIDE_FLOATS = 8\nconst MOST_BLENDED = 4\n\nexport interface SkinMesh {\n mesh: VMeshData\n reference: VMeshRef\n /** Four bone indices, then four weights, per vertex. */\n influences: Float32Array\n}\n\n/** `ExpandTristrip` (`0x65f7d70`), which every strip goes through at load: what has no area goes. */\nconst expanded = (indices: Uint16Array): number[] => {\n const out: number[] = []\n\n for (let at = 0; at + 2 < indices.length; at++) {\n const [a, b, c] = [indices[at]!, indices[at + 1]!, indices[at + 2]!]\n if (a === b || b === c || a === c) continue\n\n // A strip's winding alternates, so odd triangles swap their last two to stay one way.\n if (at % 2 === 0) out.push(a, b, c)\n else out.push(a, c, b)\n }\n\n return out\n}\n\nconst buildSkin = ({ geometry, groups }: Level, bones: number): SkinMesh => {\n const { indices: elements, points, normals, uv0, boneCount, boneIds, boneWeights } = geometry\n const count = elements.length\n if (count > 0x10000) throw new RangeError(`${count} elements, past a 16-bit index`)\n\n // The slices are cumulative from `Point_bone_count`: `Point_bone_first` is never read (`0x65f8239`).\n const starts = new Uint32Array(boneCount.length)\n\n for (let point = 1; point < starts.length; point++)\n starts[point] = starts[point - 1]! + boneCount[point - 1]!\n\n const vertices = new Float32Array(count * STRIDE_FLOATS)\n const influences = new Float32Array(count * INFLUENCE_FLOATS)\n const min = { x: Infinity, y: Infinity, z: Infinity }\n const max = { x: -Infinity, y: -Infinity, z: -Infinity }\n\n // Each element becomes its own vertex: position, normal and influences read by point, UV by `uv0.indices`.\n for (let element = 0; element < count; element++) {\n const point = elements[element]!\n const coordinate = uv0.indices[element]!\n const at = element * STRIDE_FLOATS\n const [x, y, z] = [\n points[point * 3] ?? 0,\n points[point * 3 + 1] ?? 0,\n points[point * 3 + 2] ?? 0,\n ]\n\n vertices.set(\n [\n x,\n y,\n z,\n normals[point * 3] ?? 0,\n normals[point * 3 + 1] ?? 0,\n normals[point * 3 + 2] ?? 0,\n uv0.coordinates[coordinate * 2] ?? 0,\n uv0.coordinates[coordinate * 2 + 1] ?? 0,\n ],\n at,\n )\n min.x = Math.min(min.x, x)\n min.y = Math.min(min.y, y)\n min.z = Math.min(min.z, z)\n max.x = Math.max(max.x, x)\n max.y = Math.max(max.y, y)\n max.z = Math.max(max.z, z)\n\n // `Skin`: one influence ignores its weight, and five or more keep the first at its own.\n const declared = boneCount[point] ?? 0\n const used = declared > MOST_BLENDED ? 1 : declared\n const first = starts[point] ?? 0\n const out = element * INFLUENCE_FLOATS\n\n for (let slot = 0; slot < used; slot++) {\n const id = boneIds[first + slot] ?? 0\n if (id >= bones) throw new RangeError(`Bone id ${id} past a table of ${bones}`)\n influences[out + slot] = id\n influences[out + MOST_BLENDED + slot] = declared === 1 ? 1 : (boneWeights[first + slot] ?? 0)\n }\n\n // A point with none is in no bone's list, so never re-skinned: it keeps its stored position\n // under the root's world (decomp \\`BuildBoneVertexLists\\`). No weight at all says so to the shader.\n }\n\n // `DrawFaceGroup` skips an empty group.\n const drawn = groups.filter(({ indices }) => indices.length > 0)\n const lists = drawn.map(({ indices, primitive }) =>\n primitive === 'list' ? [...indices] : expanded(indices),\n )\n const radius = Math.hypot(max.x - min.x, max.y - min.y, max.z - min.z) / 2\n const center = { x: (min.x + max.x) / 2, y: (min.y + max.y) / 2, z: (min.z + max.z) / 2 }\n const indices = new Uint16Array(lists.flat())\n\n for (const index of indices)\n if (index >= count) throw new RangeError(`Face group index ${index} past ${count} elements`)\n\n return {\n mesh: {\n name: 'skin',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: drawn.map(({ material }, at) => ({\n materialId: getResourceId(material),\n vertexStart: 0,\n vertexEnd: count - 1,\n elementCount: lists[at]!.length,\n padding: 0,\n })),\n indices,\n vertices: new Uint8Array(vertices.buffer),\n },\n reference: {\n meshId: 0,\n vertexStart: 0,\n vertexCount: count,\n indexStart: 0,\n indexCount: indices.length,\n groupStart: 0,\n groupCount: drawn.length,\n boundingBox: { min, max },\n boundingSphere: { center, radius },\n },\n influences,\n }\n}\n\nconst skins = new WeakMap<Level, SkinMesh>()\n\n/** The same object for the same level, so a renderer's buffers are shared between characters. */\nexport const skinMesh = (level: Level, bones: number): SkinMesh => {\n let skin = skins.get(level)\n\n if (!skin) {\n skin = buildSkin(level, bones)\n skins.set(level, skin)\n }\n\n return skin\n}\n\n/**\n * `K = W(root)⁻¹ · W(bone) · B`, `B` being `Bone to root` as stored (`Skin`). A slot with no world keeps\n * the identity, as one past the bound cursor does in retail.\n */\nexport const boneTable = (\n bones: readonly Bone[],\n worlds: readonly (Matrix4 | undefined)[],\n root: Matrix4,\n): Float32Array => {\n if (bones.length > MAX_BONES) throw new RangeError(`${bones.length} bones, past ${MAX_BONES}`)\n\n const table = new Float32Array(bones.length * 16)\n const inverse = Matrix4.invert(root)\n\n bones.forEach(({ orientation, position }, index) => {\n const world = worlds[index]\n const matrix = world\n ? Matrix4.multiply(\n Matrix4.multiply(inverse, world),\n Matrix4.fromRotationTranslation(orientation, position),\n )\n : Matrix4.identity\n\n Matrix4.toArray(matrix, table, index * 16)\n })\n return table\n}\n\nexport interface SkinOptions {\n /** Pinned, clamped to what a part has. The top one when there's neither this nor `lod`. */\n level?: number\n /** Each part's level as the game chooses it, `tables` in part order. */\n lod?: { camera: Camera; tables: readonly SwitchTable[] }\n /**\n * A level at or past this draws rigid, at bind. A costume's default is the builder's, by slot:\n * the body none, a head or hand 2 (\\`0x443b60\\`). It goes by position, the first part taken as the\n * body, so a costume with no body passes its own, or its head skins every level.\n */\n skinnedLevels?: readonly number[]\n jointState?: (bone: CompoundNode<Bone>) => JointState | undefined\n /**\n * The skin as modelled, ignoring the joints. `chain` is the default and what the game draws: its\n * joints' rest plus `jointState`. On a body that rest is another pose entirely, which it only ever\n * shows under a script, so a viewer with none playing wants `bind` (library `DEFORMABLE.md`).\n */\n pose?: 'chain' | 'bind'\n}\n\n// `EyeUvClampPair`: below this on both axes, the stage's transform stays off.\nconst EYE_DEAD_ZONE = 1e-4\n\n/**\n * What `FEyeMaterial::Bind` slides the eye's texture by: the bone's Z axis in its parent's frame. The\n * decomp writes it to the wrong cells of the matrix, and `character_eyes` has it in the third row.\n */\nconst eyeOffset = (\n { scaleU, scaleV, minU, maxU, minV, maxV, distance }: UVBone,\n world: Matrix4 | undefined,\n parent: Matrix4 | undefined,\n): [number, number] | undefined => {\n if (!world) return undefined\n\n const { x, y, z } = world.z\n const axes = parent ?? Matrix4.identity\n const across = axes.x.x * x + axes.x.y * y + axes.x.z * z\n const along = axes.y.x * x + axes.y.y * y + axes.y.z * z\n const [u, v] = [scaleU * across * distance, scaleV * along * distance]\n if (Math.abs(u) <= EYE_DEAD_ZONE && Math.abs(v) <= EYE_DEAD_ZONE) return undefined\n return [Math.min(maxU, Math.max(minU, u)), Math.min(maxV, Math.max(minV, v))]\n}\n\nconst CHILD_SKINNED_LEVELS = 2\n\nconst placement = ({\n orientation,\n position,\n}: Pick<Hardpoint, 'orientation' | 'position'>): Matrix4 =>\n Matrix4.fromRotationTranslation(orientation, position)\n\nexport interface SkinPose {\n /** Each bone's world, by its place in the table. A slot with none keeps the identity. */\n worlds: readonly (Matrix4 | undefined)[]\n /** The part's root bone's world, which the mesh is drawn with. */\n root: Matrix4\n /** Each bone's parent, by the same place, which an eye's offset is read against. */\n parents?: readonly (number | undefined)[]\n /** `Flag70` off: every bone the identity (`0x65f6cc6`), so the level draws at bind. */\n rigid?: boolean\n}\n\n/** One level of a part, for a host that poses and joins its own bones. `placeCostume` is the other way in. */\nexport const poseSkin = (\n level: Level,\n bones: readonly Bone[],\n { worlds, root, parents, rigid = false }: SkinPose,\n): PlacedPart => {\n const { mesh, reference, influences } = skinMesh(level, bones.length)\n const skin: DrawSkin = { influences, bones: boneTable(bones, rigid ? [] : worlds, root) }\n // Only the first UV bone drives, and only eye groups read it (`0x65f75ca`).\n const { uvBone } = level.geometry\n const parent = uvBone && parents?.[uvBone.bone]\n const offset =\n uvBone &&\n eyeOffset(uvBone, worlds[uvBone.bone], parent === undefined ? undefined : worlds[parent])\n\n return { reference, mesh, world: root, skin, ...(offset ? { eyeOffset: offset } : {}) }\n}\n\n/**\n * Every bone's world in a costume, by part and by its place in the part's table; nothing for a part\n * with no root. The skeletons join by shared hardpoint name (`0x65f3540`, library `COSTUME.md`):\n * walking every bone, the first with a name holds it, and a later one with no parent links to it.\n * That's a part's root, placing the part, or a detached bone, placing one seam.\n */\nexport const costumeWorlds = (\n models: readonly DeformableModel[],\n transform: Matrix4,\n { jointState, pose = 'chain' }: Pick<SkinOptions, 'jointState' | 'pose'> = {},\n): (Matrix4[] | undefined)[] => {\n const holders = new Map<string, { world: Matrix4; hardpoint: Matrix4 }>()\n\n // Seats a hardpoint on the holder's: holder world · holder hardpoint · inverse of this hardpoint.\n const linked = (name: string, hardpoint: Hardpoint): Matrix4 | undefined => {\n const holder = holders.get(name.toLowerCase())\n\n return (\n holder &&\n Matrix4.multiply(\n Matrix4.multiply(holder.world, holder.hardpoint),\n Matrix4.invert(placement(hardpoint)),\n )\n )\n }\n\n return models.map((model, at) => {\n const root = getBoneModel(model)\n if (!root) return undefined\n\n // A root links by the first of its names already held. No other can join it to a second.\n const place = root.part.hardpoints.flatMap((hardpoint) => {\n const world = linked(hardpoint.name, hardpoint)\n\n return world ? [world] : []\n })[0]\n\n const transforms = partTransforms(root, place ?? transform, jointState)\n\n const worlds: (Matrix4 | undefined)[] = []\n for (const [node, world] of transforms) worlds[node.index] = world\n\n // The modelled pose is the host's to ask for: a head's and hand's chain already is theirs.\n if (pose === 'bind' && at === 0)\n for (const [node] of transforms)\n worlds[node.index] = Matrix4.multiply(transform, Matrix4.invert(placement(node.part)))\n\n // Everything stops at the last bone a part claims (`0x65f5a52`), so past it a slot keeps the identity.\n const cursor = model.bones.reduce(\n (last, { name }, index) => (name === undefined ? last : index + 1),\n 0,\n )\n\n for (let index = 0; index < cursor; index++) {\n const bone = model.bones[index]!\n\n for (const hardpoint of bone.hardpoints) {\n const name = hardpoint.name.toLowerCase()\n const world = worlds[index]\n\n if (holders.has(name)) {\n // The engine refuses a link to a bone with a parent, so only a detached one takes it here.\n if (!world) worlds[index] = linked(name, hardpoint)\n }\n // The first with a name holds it, seated or not: the walk runs before the destroy pass, so a\n // detached bone with no seat still holds at the identity it keeps (\\`0x65f35b4\\`).\n else\n holders.set(name, { world: world ?? Matrix4.identity, hardpoint: placement(hardpoint) })\n }\n\n // A seam nothing seats is destroyed, and its record keeps the identity (`0x65f3d49`).\n worlds[index] ??= Matrix4.identity\n }\n\n return worlds as Matrix4[]\n })\n}\n\n/**\n * A character's parts, body first, each drawn with its root's world and skinned relative to it, its\n * bones joined as {@link costumeWorlds} joins them. A part with no root or level is skipped.\n */\nexport const placeCostume = (\n models: readonly DeformableModel[],\n transform: Matrix4,\n { level, lod, skinnedLevels, jointState, pose = 'chain' }: SkinOptions = {},\n): PlacedPart[] => {\n const all = costumeWorlds(models, transform, { ...(jointState && { jointState }), pose })\n const parts: PlacedPart[] = []\n\n models.forEach((model, at) => {\n const root = getBoneModel(model)\n const worlds = all[at]\n const table = lod?.tables[at]\n const chosenAt =\n level === undefined && lod && table\n ? costumeLevel(\n model.levels,\n table,\n Math.hypot(\n lod.camera.position.x - transform.w.x,\n lod.camera.position.y - transform.w.y,\n lod.camera.position.z - transform.w.z,\n ),\n lod.camera.fovh,\n )\n : Math.min(level ?? 0, model.levels.length - 1)\n const chosen = chosenAt === undefined ? undefined : model.levels[chosenAt]\n\n // Past its far cutoff a part draws nothing, and its bones still hold for those after it.\n if (!root || !worlds || !chosen) return\n\n const parents: (number | undefined)[] = []\n\n const walk = (node: typeof root) => {\n for (const child of node.children) {\n parents[child.index] = node.index\n walk(child)\n }\n }\n\n walk(root)\n parts.push(\n poseSkin(chosen, model.bones, {\n worlds,\n // Slot 0 is the root: the skinning inverse and the draw's world (\\`0x65f6c00\\`).\n root: worlds[0] ?? Matrix4.identity,\n parents,\n // `BuildCharacterDeformable` (`0x443b60`): the body has no limit, and the others skin levels 0\n // and 1.\n rigid: chosenAt! >= (skinnedLevels?.[at] ?? (at === 0 ? Infinity : CHILD_SKINNED_LEVELS)),\n }),\n )\n })\n return parts\n}\n\n/** One model, as a costume of one part. */\nexport const placeSkin = (\n model: DeformableModel,\n transform: Matrix4,\n options: SkinOptions = {},\n): PlacedPart | undefined => placeCostume([model], transform, options)[0]\n","/**\n * D3D8's table fog on W, per pixel, which `FogApplyColorAndRange` picks on any device with W-fog and\n * T&L (`FDirectX8`'s ability 13). Shared by every program a fogged draw goes through.\n */\nimport type { Fog } from '#/scene/nebula.js'\n\nexport const FOG_UNIFORMS = ['fogMode', 'fogColor', 'fogRange', 'fogDensity'] as const\n\n/** Declares the uniforms, and `fogged`, which blends a colour into the fog by this pixel's W. */\nexport const FOG_GLSL = `\n// 0 off, then D3DFOGMODE's 1 exp, 2 exp2 and 3 linear.\nuniform int fogMode;\nuniform vec3 fogColor;\n// Start and end, which only linear fog reads.\nuniform vec2 fogRange;\nuniform float fogDensity;\n\nvec3 fogged(vec3 color) {\n if (fogMode == 0) return color;\n // W is eye depth. How finely the hardware's fog factor steps is uncaptured.\n float w = 1.0 / gl_FragCoord.w;\n float d = fogDensity * w;\n float f = fogMode == 1 ? exp(-d)\n : fogMode == 2 ? exp(-d * d)\n : (fogRange.y - w) / (fogRange.y - fogRange.x);\n return mix(fogColor, color, clamp(f, 0.0, 1.0));\n}`\n\ntype FogUniforms = Record<(typeof FOG_UNIFORMS)[number], WebGLUniformLocation | null>\n\nconst MODES = { exp: 1, exp2: 2, linear: 3 } as const\n\nexport const setFog = (gl: WebGL2RenderingContext, uniforms: FogUniforms, fog?: Fog): void => {\n gl.uniform1i(uniforms.fogMode, fog ? MODES[fog.mode ?? 'linear'] : 0)\n if (!fog) return\n gl.uniform3f(uniforms.fogColor, fog.color.x, fog.color.y, fog.color.z)\n gl.uniform2f(uniforms.fogRange, fog.start, fog.end)\n gl.uniform1f(uniforms.fogDensity, fog.density ?? 0)\n}\n","/**\n * `DcDt` and its kin: D3D8's fixed-function lighting per vertex, then its texture stages.\n * Sources: `src/Shading/Material.cpp`, `FMaterialImpl::BindEnvMap`; the arithmetic is D3D8's own.\n */\nimport { Matrix4 } from '@treewyrm/freelancer/math'\nimport { createProgram, type Program } from '#/gl/program.js'\nimport { ATTRIBUTE_LOCATIONS } from '#/mesh/plan.js'\nimport { MAX_BONES } from '#/deformable/skin.js'\nimport type { Draw, Frame, SceneLight } from '#/scene/frame.js'\nimport { FOG_GLSL, FOG_UNIFORMS, setFog } from './fog.js'\n\n/** Retail lights a model with at most four (library `THORN.md`, `lt_grp`). */\nexport const MAX_LIGHTS = 4\n\n// `D3DTOP_ADD` for `DcDtEt` (`0x6ed1724`), `D3DTOP_MODULATE2X` for `BtDetailMapMaterial` (`0x6ed14dc`).\nconst SECOND_STAGE = { none: 0, add: 1, modulate2x: 2 } as const\n\nconst ALPHA_FUNCTION = { always: 0, greater: 1, less: 2 } as const\n\nconst VERTEX = `#version 300 es\nlayout(location = ${ATTRIBUTE_LOCATIONS.position}) in vec3 position;\nlayout(location = ${ATTRIBUTE_LOCATIONS.normal}) in vec3 normal;\nlayout(location = ${ATTRIBUTE_LOCATIONS.diffuse}) in vec4 diffuse;\nlayout(location = ${ATTRIBUTE_LOCATIONS.uv0}) in vec2 uv0;\nlayout(location = ${ATTRIBUTE_LOCATIONS.uv1}) in vec2 uv1;\nlayout(location = ${ATTRIBUTE_LOCATIONS.boneIndex}) in vec4 boneIndex;\nlayout(location = ${ATTRIBUTE_LOCATIONS.boneWeight}) in vec4 boneWeight;\n\nlayout(std140) uniform Bones {\n mat4 bones[${MAX_BONES}];\n};\nuniform bool skinned;\n\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\n\nuniform vec3 sceneAmbient;\nuniform vec3 materialAmbient;\nuniform vec4 materialDiffuse;\nuniform vec3 materialEmissive;\nuniform int lightCount;\nuniform vec3 lightColor[${MAX_LIGHTS}];\nuniform vec3 lightDirection[${MAX_LIGHTS}];\n// A point light's world position, with w 1. A directional light has w 0.\nuniform vec4 lightPosition[${MAX_LIGHTS}];\nuniform float lightRange[${MAX_LIGHTS}];\nuniform vec3 lightAttenuation[${MAX_LIGHTS}];\n// A spot's cos(theta / 2), cos(phi / 2) and falloff. A falloff of 0 is no spot.\nuniform vec3 lightSpot[${MAX_LIGHTS}];\nuniform vec3 lightAmbient[${MAX_LIGHTS}];\n\nuniform bool colorVertex;\nuniform bool nomad;\nuniform bool unlit;\nuniform float normalSign;\nuniform bool normalizeNormals;\nuniform bool reflecting;\nuniform int uvSet;\nuniform int secondUvSet;\nuniform float secondTile;\n// Towards the camera and the horizon's cosine, then \\`u\\`'s gain and the row.\nuniform bool atmosphere;\nuniform vec4 atmosphereView;\nuniform vec2 atmosphereFade;\n// Offset, then scale, on stage 0 alone.\nuniform vec4 uvTransform;\n\nout vec4 lit;\nout vec2 uv;\nout vec2 secondUv;\nout vec3 reflection;\n\n// The fast inverse root and one Newton step, which always lands a little short of unit length\n// (\\`deformable2!0x65f6fc3\\`–\\`0x65f7031\\`).\nvec3 renormalized(vec3 v) {\n float squared = dot(v, v);\n float guess = uintBitsToFloat(0x5f3759dfu - (floatBitsToUint(squared) >> 1));\n return v * ((1.5 - 0.5 * squared * guess * guess) * guess);\n}\n\nvoid main() {\n mat4 modelView = view * world;\n vec3 place = position;\n vec3 facing = normal;\n // What FMeshArchetype::Skin writes to locked memory when a bone moves. A lone influence is not\n // renormalized, and a blend is.\n // A point with no influence is in no bone's list, and keeps its stored position.\n if (skinned && boneWeight != vec4(0.0)) {\n mat4 skin = bones[int(boneIndex.x)] * boneWeight.x + bones[int(boneIndex.y)] * boneWeight.y\n + bones[int(boneIndex.z)] * boneWeight.z + bones[int(boneIndex.w)] * boneWeight.w;\n place = (skin * vec4(position, 1.0)).xyz;\n facing = (skin * vec4(normal, 0.0)).xyz;\n if (boneWeight != vec4(1.0, 0.0, 0.0, 0.0)) facing = renormalized(facing);\n }\n vec4 eyePosition = modelView * vec4(place, 1.0);\n gl_Position = projection * eyePosition;\n uv = (uvSet == 1 ? uv1 : uv0) * uvTransform.zw + uvTransform.xy;\n secondUv = (secondUvSet == 1 ? uv1 : uv0) * secondTile;\n\n // What \\`SubmitAtmosphereLock\\` writes to locked memory each frame, from the vertex's own normal.\n if (atmosphere) {\n float facing = dot(atmosphereView.xyz, normal);\n float u = facing < atmosphereView.w ? 0.0 : (facing - atmosphereView.w) / (1.0 - atmosphereView.w) * atmosphereFade.x;\n uv = vec2(u, atmosphereFade.y);\n }\n\n // What \\`NomadWriteVert\\` writes to locked memory each frame: white at the draw's alpha, and a ramp\n // coordinate from one camera axis per draw, carried into object space by the transpose alone.\n if (nomad) {\n lit = vec4(1.0, 1.0, 1.0, materialDiffuse.a);\n vec3 axis = transpose(mat3(modelView)) * vec3(0.0, 0.0, -1.0);\n // \\`SubmitNomadGeometry\\` has \\`1 - fmod(clock, 5) / 5\\`, but every caller of the material's update\n // passes a delta of 0 (\\`Freelancer.exe\\`, \\`0x41af28\\` and on), so the clock stays at 0 and this at 1.\n secondUv = vec2((dot(axis, normal) + 1.0) * 0.5, 1.0);\n reflection = vec3(0.0);\n return;\n }\n\n // A normal goes through the inverse transpose, and keeps its length unless asked otherwise.\n vec3 eyeNormal = transpose(inverse(mat3(modelView))) * (facing * normalSign);\n if (normalizeNormals) eyeNormal = normalize(eyeNormal);\n\n // D3DMCS_COLOR1 under COLORVERTEX (\\`BindMaterialAndContext\\`; captured source states, \\`li_elite\\`).\n // Those states also take ambient from COLOR2, which no retail mesh has. What D3D8 reads then is\n // uncaptured, so the material's ambient here is a reading to check. 22 mesh groups depend on it.\n vec4 source = colorVertex ? diffuse.bgra : materialDiffuse;\n\n vec3 sum = materialEmissive + materialAmbient * sceneAmbient;\n for (int i = 0; i < lightCount; i++) {\n vec3 toLight = -normalize(mat3(view) * lightDirection[i]);\n float attenuation = 1.0;\n // D3D8's point light: nothing past its range, and \\`1 / (a0 + a1 d + a2 d²)\\` within it.\n if (lightPosition[i].w > 0.5) {\n vec3 offset = (view * vec4(lightPosition[i].xyz, 1.0)).xyz - eyePosition.xyz;\n float d = length(offset);\n if (d > lightRange[i]) continue;\n toLight = offset / d;\n vec3 a = lightAttenuation[i];\n attenuation = 1.0 / (a.x + a.y * d + a.z * d * d);\n // D3D8's spot: rho against the inner and outer cones' half-angle cosines.\n vec3 spot = lightSpot[i];\n if (spot.z > 0.0) {\n float rho = dot(normalize(mat3(view) * lightDirection[i]), -toLight);\n if (rho <= spot.y) continue;\n if (rho <= spot.x) attenuation *= pow((rho - spot.y) / (spot.x - spot.y), spot.z);\n }\n }\n // D3D8 adds each light's own ambient whichever way the surface faces. Specular is never on:\n // nothing sets SPECULARENABLE (\\`ShadingInternal.h\\` names it; RP8's default is 0).\n sum += materialAmbient * lightAmbient[i] * attenuation;\n sum += source.rgb * lightColor[i] * attenuation * max(dot(eyeNormal, toLight), 0.0);\n }\n // Saturated here, per vertex, before it is interpolated or meets a texture.\n lit = clamp(vec4(sum, source.a), 0.0, 1.0);\n if (unlit) lit = colorVertex ? diffuse.bgra : vec4(1.0, 1.0, 1.0, materialDiffuse.a);\n\n // D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR with LOCALVIEWER on, in D3D's Z-flipped camera space.\n reflection = vec3(0.0);\n if (reflecting) {\n vec3 toEye = normalize(-eyePosition.xyz);\n vec3 r = 2.0 * dot(toEye, eyeNormal) * eyeNormal - toEye;\n reflection = vec3(r.xy, -r.z);\n }\n}`\n\nconst FRAGMENT = `#version 300 es\nprecision highp float;\n\nuniform bool textured;\nuniform sampler2D diffuseMap;\nuniform bool reflecting;\nuniform samplerCube environmentMap;\nuniform float alphaReference;\nuniform int alphaFunction;\nuniform int secondStage;\nuniform bool secondTextured;\nuniform sampler2D secondMap;\n${FOG_GLSL}\n\nin vec4 lit;\nin vec2 uv;\nin vec2 secondUv;\nin vec3 reflection;\nout vec4 color;\n\nvoid main() {\n // An empty stage reads as white: glass has no texture, and still shows its colour.\n color = textured ? clamp(texture(diffuseMap, uv) * lit, 0.0, 1.0) : lit;\n\n // Stage 1, which saturates like any stage.\n if (secondStage != ${SECOND_STAGE.none} && secondTextured) {\n vec4 second = texture(secondMap, secondUv);\n color.rgb = secondStage == ${SECOND_STAGE.add} ? color.rgb + second.rgb : 2.0 * second.rgb * color.rgb;\n color = clamp(vec4(color.rgb, second.a * color.a), 0.0, 1.0);\n }\n\n if (reflecting) {\n vec4 cube = texture(environmentMap, reflection);\n color = vec4(clamp(2.0 * cube.rgb * color.rgb, 0.0, 1.0), clamp(cube.a * color.a, 0.0, 1.0));\n }\n\n // After the stages, before blending, and never on alpha.\n color.rgb = fogged(color.rgb);\n\n // On the 8-bit value.\n float alpha8 = floor(color.a * 255.0 + 0.5);\n if (alphaFunction == ${ALPHA_FUNCTION.greater} && !(alpha8 > alphaReference)) discard;\n if (alphaFunction == ${ALPHA_FUNCTION.less} && !(alpha8 < alphaReference)) discard;\n}`\n\nconst UNIFORMS = [\n 'world',\n 'view',\n 'projection',\n 'sceneAmbient',\n 'materialAmbient',\n 'materialDiffuse',\n 'materialEmissive',\n 'lightCount',\n 'lightColor',\n 'lightDirection',\n 'lightPosition',\n 'lightRange',\n 'lightAttenuation',\n 'lightSpot',\n 'lightAmbient',\n 'colorVertex',\n 'nomad',\n 'unlit',\n 'normalSign',\n 'normalizeNormals',\n 'reflecting',\n 'uvSet',\n 'uvTransform',\n 'secondUvSet',\n 'secondTile',\n 'atmosphere',\n 'atmosphereView',\n 'atmosphereFade',\n 'alphaFunction',\n 'skinned',\n 'secondStage',\n 'secondTextured',\n 'secondMap',\n 'textured',\n 'diffuseMap',\n 'environmentMap',\n 'alphaReference',\n ...FOG_UNIFORMS,\n] as const\n\nexport type DcDtProgram = Program<(typeof UNIFORMS)[number]> & { boneBuffer: WebGLBuffer }\n\n/** The `Bones` block's binding point, which needs a buffer whether or not this draw skins. */\nexport const BONES_BINDING = 0\n\nexport const DIFFUSE_UNIT = 0\nexport const ENVIRONMENT_UNIT = 1\nexport const SECOND_UNIT = 2\n\nexport const createDcDtProgram = (gl: WebGL2RenderingContext): DcDtProgram => {\n const program = createProgram(gl, VERTEX, FRAGMENT, UNIFORMS)\n\n gl.useProgram(program.handle)\n gl.uniform1i(program.uniforms.diffuseMap, DIFFUSE_UNIT)\n gl.uniform1i(program.uniforms.environmentMap, ENVIRONMENT_UNIT)\n gl.uniform1i(program.uniforms.secondMap, SECOND_UNIT)\n\n gl.uniformBlockBinding(\n program.handle,\n gl.getUniformBlockIndex(program.handle, 'Bones'),\n BONES_BINDING,\n )\n\n const boneBuffer = gl.createBuffer()\n\n gl.bindBuffer(gl.UNIFORM_BUFFER, boneBuffer)\n gl.bufferData(gl.UNIFORM_BUFFER, MAX_BONES * 64, gl.DYNAMIC_DRAW)\n gl.bindBuffer(gl.UNIFORM_BUFFER, null)\n gl.bindBufferBase(gl.UNIFORM_BUFFER, BONES_BINDING, boneBuffer)\n return { ...program, boneBuffer }\n}\n\nconst vectors = (values: { x: number; y: number; z: number }[]): Float32Array =>\n new Float32Array(values.flatMap(({ x, y, z }) => [x, y, z]))\n\n/** What stays the same through a frame. The program must be in use. */\nexport const setFrameUniforms = (\n gl: WebGL2RenderingContext,\n { uniforms }: DcDtProgram,\n { view, projection, ambient, lights }: Frame,\n): void => {\n if (lights.length > MAX_LIGHTS) throw new RangeError(`More than ${MAX_LIGHTS} lights`)\n gl.uniformMatrix4fv(uniforms.view, false, Matrix4.toArray(view))\n gl.uniformMatrix4fv(uniforms.projection, false, Matrix4.toArray(projection))\n gl.uniform3f(uniforms.sceneAmbient, ambient.x, ambient.y, ambient.z)\n setLights(gl, uniforms, lights)\n}\n\nconst ORIGIN = { x: 0, y: 0, z: 0 }\n\n/** A frame's lights, or one draw's in their place. */\nexport const setLights = (\n gl: WebGL2RenderingContext,\n uniforms: DcDtProgram['uniforms'],\n lights: readonly SceneLight[],\n): void => {\n if (lights.length > MAX_LIGHTS) throw new RangeError(`More than ${MAX_LIGHTS} lights`)\n gl.uniform1i(uniforms.lightCount, lights.length)\n if (!lights.length) return\n gl.uniform3fv(uniforms.lightColor, vectors(lights.map(({ color }) => color)))\n gl.uniform3fv(uniforms.lightDirection, vectors(lights.map(({ direction }) => direction)))\n gl.uniform4fv(\n uniforms.lightPosition,\n new Float32Array(\n lights.flatMap(({ position }) => {\n const { x, y, z } = position ?? ORIGIN\n\n return [x, y, z, position ? 1 : 0]\n }),\n ),\n )\n gl.uniform1fv(uniforms.lightRange, new Float32Array(lights.map(({ range }) => range ?? 0)))\n gl.uniform3fv(\n uniforms.lightAttenuation,\n vectors(lights.map(({ attenuation }) => attenuation ?? ORIGIN)),\n )\n gl.uniform3fv(uniforms.lightAmbient, vectors(lights.map(({ ambient }) => ambient ?? ORIGIN)))\n // The cosines of half of each cone, and the falloff. A zero falloff marks no spot.\n gl.uniform3fv(\n uniforms.lightSpot,\n new Float32Array(\n lights.flatMap(({ spot }) =>\n spot ? [Math.cos(spot.theta / 2), Math.cos(spot.phi / 2), spot.falloff] : [0, 0, 0],\n ),\n ),\n )\n}\n\n/** What one draw changes. The textures themselves are the caller's to bind. */\nexport const setDrawUniforms = (\n gl: WebGL2RenderingContext,\n { uniforms }: DcDtProgram,\n draw: Pick<\n Draw,\n | 'world'\n | 'diffuse'\n | 'ambient'\n | 'emissive'\n | 'colorVertex'\n | 'nomad'\n | 'unlit'\n | 'sceneAmbient'\n | 'negateNormals'\n | 'normalizeNormals'\n | 'alphaReference'\n | 'alphaFunction'\n | 'atmosphere'\n | 'skin'\n | 'texture'\n | 'environment'\n | 'second'\n | 'uvTransform'\n | 'fog'\n >,\n): void => {\n gl.uniformMatrix4fv(uniforms.world, false, Matrix4.toArray(draw.world))\n setFog(gl, uniforms, draw.fog)\n gl.uniform4fv(uniforms.materialDiffuse, draw.diffuse)\n gl.uniform3f(uniforms.materialAmbient, draw.ambient.x, draw.ambient.y, draw.ambient.z)\n gl.uniform3f(uniforms.materialEmissive, draw.emissive.x, draw.emissive.y, draw.emissive.z)\n\n if (draw.sceneAmbient) {\n const { x, y, z } = draw.sceneAmbient\n\n gl.uniform3f(uniforms.sceneAmbient, x, y, z)\n }\n\n gl.uniform1i(uniforms.colorVertex, draw.colorVertex ? 1 : 0)\n gl.uniform1i(uniforms.nomad, draw.nomad ? 1 : 0)\n gl.uniform1i(uniforms.unlit, draw.unlit ? 1 : 0)\n gl.uniform1f(uniforms.normalSign, draw.negateNormals ? -1 : 1)\n gl.uniform1i(uniforms.normalizeNormals, draw.normalizeNormals ? 1 : 0)\n gl.uniform1f(uniforms.alphaReference, draw.alphaReference)\n gl.uniform1i(uniforms.alphaFunction, ALPHA_FUNCTION[draw.alphaFunction])\n gl.uniform1i(uniforms.skinned, draw.skin ? 1 : 0)\n gl.uniform1i(uniforms.atmosphere, draw.atmosphere ? 1 : 0)\n\n if (draw.atmosphere) {\n const { direction, threshold, gain, v } = draw.atmosphere\n\n gl.uniform4f(uniforms.atmosphereView, direction.x, direction.y, direction.z, threshold)\n gl.uniform2f(uniforms.atmosphereFade, gain, v)\n }\n\n gl.uniform1i(uniforms.textured, draw.texture ? 1 : 0)\n gl.uniform1i(uniforms.uvSet, draw.texture?.uvSet ?? 0)\n\n const { offset, scale } = draw.uvTransform ?? { offset: [0, 0], scale: [1, 1] }\n\n gl.uniform4f(uniforms.uvTransform, offset[0]!, offset[1]!, scale[0]!, scale[1]!)\n gl.uniform1i(uniforms.reflecting, draw.environment ? 1 : 0)\n gl.uniform1i(uniforms.secondStage, SECOND_STAGE[draw.second?.operation ?? 'none'])\n gl.uniform1i(uniforms.secondTextured, draw.second?.texture ? 1 : 0)\n gl.uniform1i(uniforms.secondUvSet, draw.second?.texture?.uvSet ?? 0)\n gl.uniform1f(uniforms.secondTile, draw.second?.tile ?? 1)\n}\n","/** An appearance's eased lists as texels, and GLSL reading them, rule for rule as the library's evaluator. */\nimport {\n sparamLevel,\n type AnimatedColor,\n type AnimatedFloat,\n type EaseAnimation,\n type FloatKeyframe,\n type VectorKeyframe,\n} from '@treewyrm/freelancer/alchemy'\nimport type { Vector3 } from '@treewyrm/freelancer/math'\n\nexport interface UVRect {\n u1: number\n v1: number\n u2: number\n v2: number\n}\n\nexport const TABLE_WIDTH = 1024\n\n/** The two lists around `sparam`, how far between them, and their easing. */\nexport type Slot = readonly [lower: number, upper: number, span: number, easing: number]\n\nconst constantSlot = (offset: number): Slot => [offset, offset, 0, 1]\n\n/** `_ftol(c × 255)` per channel, spilling as the packed word does. */\nconst byte = (c: number): number => (c * 255) | 0\n\n/** Whole lists rather than baked ones: baking lost 10% of alpha at the 99th percentile. */\nexport class CurveTable {\n texels = new Float32Array(TABLE_WIDTH * 4)\n length = 0\n version = 0\n #floats = new WeakMap<EaseAnimation<FloatKeyframe>, number>()\n #colors = new WeakMap<EaseAnimation<VectorKeyframe>, number>()\n #frames = new Map<string, number>()\n #constants = new Map<number, number>()\n #colorConstants = new Map<string, number>()\n\n #reserve(texels: number): number {\n const offset = this.length\n const needed = (offset + texels) * 4\n\n if (needed > this.texels.length) {\n let size = this.texels.length\n\n while (size < needed) size *= 2\n\n const grown = new Float32Array(size)\n\n grown.set(this.texels)\n this.texels = grown\n }\n\n this.length += texels\n this.version++\n return offset\n }\n\n float(list: EaseAnimation<FloatKeyframe>): number {\n const known = this.#floats.get(list)\n if (known !== undefined) return known\n\n const { keyframes, easing } = list\n const offset = this.#reserve(1 + Math.ceil(keyframes.length / 2))\n const t = this.texels\n\n // A header texel `[count, easing, 0, 0]`, then two `(key, value)` pairs per texel.\n t.set([keyframes.length, easing, 0, 0], offset * 4)\n\n for (const [n, { key, value }] of keyframes.entries()) {\n const at = (offset + 1) * 4 + n * 2\n\n t[at] = key\n t[at + 1] = value\n }\n\n this.#floats.set(list, offset)\n return offset\n }\n\n color(list: EaseAnimation<VectorKeyframe>): number {\n const known = this.#colors.get(list)\n if (known !== undefined) return known\n\n const { keyframes, easing } = list\n const offset = this.#reserve(1 + keyframes.length)\n const t = this.texels\n\n t.set([keyframes.length, easing, 1, 0], offset * 4)\n\n for (const [n, { key, value }] of keyframes.entries()) {\n // Packed `0xXXYYZZ` by OR, so a channel over 1 spills into its neighbour, then split to bytes.\n const word = (((byte(value.y) | (byte(value.x) << 8)) << 8) | byte(value.z)) >>> 0\n\n t.set([key, (word >>> 16) & 0xff, (word >>> 8) & 0xff, word & 0xff], (offset + 1 + n) * 4)\n }\n\n this.#colors.set(list, offset)\n return offset\n }\n\n constant(value: number): number {\n const known = this.#constants.get(value)\n if (known !== undefined) return known\n\n const offset = this.float({ easing: 1, keyframes: [{ key: 0, value }] })\n\n this.#constants.set(value, offset)\n return offset\n }\n\n /** The rects, after a header of their count and the frame a `-1` picks. */\n frames(rects: readonly UVRect[], current = 0): number {\n const name = `${current}:${rects.map(({ u1, v1, u2, v2 }) => `${u1},${v1},${u2},${v2}`).join(';')}`\n const known = this.#frames.get(name)\n if (known !== undefined) return known\n\n const offset = this.#reserve(1 + rects.length)\n\n this.texels.set([rects.length, current, 0, 0], offset * 4)\n\n for (const [n, { u1, v1, u2, v2 }] of rects.entries())\n this.texels.set([u1, v1, u2, v2], (offset + 1 + n) * 4)\n\n this.#frames.set(name, offset)\n return offset\n }\n\n floatSlot(property: AnimatedFloat | undefined, sparam: number, fallback: number): Slot {\n if (!property) return constantSlot(this.constant(fallback))\n\n const level = sparamLevel(property, sparam)\n if (!level) return constantSlot(this.constant(0))\n return [this.float(level.lower), this.float(level.upper), level.span, level.easing]\n }\n\n colorSlot(property: AnimatedColor | undefined, sparam: number, fallback: Vector3): Slot {\n const level = property && sparamLevel(property, sparam)\n if (level) return [this.color(level.lower), this.color(level.upper), level.span, level.easing]\n\n const value = property ? { x: 0, y: 0, z: 0 } : fallback\n const name = `${value.x},${value.y},${value.z}`\n let offset = this.#colorConstants.get(name)\n\n if (offset === undefined) {\n offset = this.color({ easing: 1, keyframes: [{ key: 0, value }] })\n this.#colorConstants.set(name, offset)\n }\n\n return constantSlot(offset)\n }\n}\n\nexport const curvesSource = /* glsl */ `\nuniform highp sampler2D u_curves;\n\nvec4 curveTexel(int i) {\n return texelFetch(u_curves, ivec2(i % ${TABLE_WIDTH}, i / ${TABLE_WIDTH}), 0);\n}\n\nfloat easeWeight(int type, bool rising, float t) {\n if (type == 0) return 0.0;\n if (type == 2) return t * t;\n if (type == 3) return t * (2.0 - t);\n if (type == 4) return t * t * (3.0 - 2.0 * t);\n if (type == 5) return rising ? t * t : t * (2.0 - t);\n if (type == 6) return rising ? t * (2.0 - t) : t * t;\n return t;\n}\n\nfloat easeValue(int type, float a, float b, float t) {\n if (a == b || type == 0) return a;\n float w = easeWeight(type, a < b, t);\n return a * (1.0 - w) + b * w;\n}\n\nvec2 floatKey(int header, int n) {\n vec4 texel = curveTexel(header + 1 + n / 2);\n return n % 2 == 0 ? texel.xy : texel.zw;\n}\n\nfloat floatList(int header, float key) {\n vec4 head = curveTexel(header);\n int count = int(head.x);\n if (count == 0) return 0.0;\n vec2 last = floatKey(header, count - 1);\n if (key >= last.x) return last.y;\n // Brackets key by start and end: end is the first key at or past it, start < 0 before the first.\n int start = -1;\n int end = 0;\n for (int n = 0; n < count; n++) {\n end = n;\n if (key <= floatKey(header, n).x && (start < 0 || floatKey(header, n).x > floatKey(header, start).x)) break;\n start = n;\n }\n vec2 a = floatKey(header, start < 0 ? end : start);\n vec2 b = floatKey(header, end);\n float span = start < 0 ? 0.0 : clamp((key - a.x) / (b.x - a.x), 0.0, 1.0);\n return easeValue(int(head.y), a.y, b.y, span);\n}\n\nconst float BYTE = 1.0 / 255.0;\n\nvec3 colorList(int header, float key) {\n vec4 head = curveTexel(header);\n int count = int(head.x);\n if (count == 0) return vec3(0.0);\n vec4 last = curveTexel(header + count);\n if (key >= last.x) return last.yzw * BYTE;\n int start = -1;\n int end = 0;\n for (int n = 0; n < count; n++) {\n end = n;\n if (key <= curveTexel(header + 1 + n).x && (start < 0 || curveTexel(header + 1 + n).x > curveTexel(header + 1 + start).x)) break;\n start = n;\n }\n vec4 from = curveTexel(header + 1 + (start < 0 ? end : start));\n vec4 to = curveTexel(header + 1 + end);\n ivec3 a = ivec3(from.yzw);\n int easing = int(head.y);\n if (easing == 0) return vec3(a) * BYTE;\n ivec3 b = ivec3(to.yzw);\n float span = start < 0 ? 0.0 : clamp((key - from.x) / (to.x - from.x), 0.0, 1.0);\n bool rising = a.x * 65536 + a.y * 256 + a.z < b.x * 65536 + b.y * 256 + b.z;\n // 8-bit fixed-point lerp per channel: a + ((b - a) * w >> 8), w in 0..255, wrapped to a byte.\n int w = int(easeWeight(easing, rising, span) * 255.0);\n return vec3((a + (((b - a) * w) >> 8)) & 0xff) * BYTE;\n}\n\nfloat slotFloat(vec4 slot, float key) {\n int lower = int(slot.x);\n int upper = int(slot.y);\n float a = floatList(lower, key);\n if (lower == upper) return a;\n return easeValue(int(slot.w), a, floatList(upper, key), slot.z);\n}\n\nvec3 slotColor(vec4 slot, float key) {\n int lower = int(slot.x);\n int upper = int(slot.y);\n vec3 a = colorList(lower, key);\n if (lower == upper) return a;\n int type = int(slot.w);\n if (type == 0) return a;\n vec3 b = colorList(upper, key);\n float f = easeWeight(type, a.x + a.y + a.z < b.x + b.y + b.z, slot.z);\n return a * (1.0 - f) + b * f;\n}\n\n// _ftol(position × (count − 1)), then GetFrame's choice (FUN_06ebe7f0): -1 is the playback's\n// current frame, and anything else outside is the last.\nvec4 frameRect(int header, float position) {\n vec4 head = curveTexel(header);\n int count = int(head.x);\n int index = int(position * float(count - 1));\n if (index == -1) index = int(head.y);\n else if (index < 0 || index >= count) index = count - 1;\n return curveTexel(header + 1 + index);\n}\n`\n","/** The GL of an effect: a sprite program whose vertex stage carries each record to now, and beams. */\nimport { BlendingMode, type Blending } from '@treewyrm/freelancer/alchemy'\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport { createProgram, type Program } from '#/gl/program.js'\nimport { DIFFUSE_UNIT } from '#/material/dcdt.js'\nimport { FOG_GLSL, FOG_UNIFORMS, setFog } from '#/material/fog.js'\nimport type { Fog } from '#/scene/nebula.js'\nimport { CurveTable, curvesSource, TABLE_WIDTH } from './curves.js'\nimport type { EffectDraw, SpriteDraw } from './draw.js'\nimport type { EffectNode } from './tree.js'\nimport {\n FACING_CAMERA,\n FACING_DUST,\n FACING_PERPENDICULAR,\n FACING_TRAVEL,\n KIND_BASIC,\n KIND_DUST,\n KIND_PERP,\n KIND_RECT,\n SHAPE_QUAD,\n SHAPE_TRI_TEXTURE,\n} from './draw.js'\nimport { RECORD, type Lane } from './effect.js'\n\nconst GREY: Vector3 = { x: 0.8, y: 0.8, z: 0.8 }\n\nconst SPRITE_UNIFORMS = [\n 'u_projection',\n 'u_modelView',\n 'u_time',\n 'u_kind',\n 'u_facing',\n 'u_shape',\n 'u_blur',\n 'u_centered',\n 'u_fade',\n 'u_extent',\n 'u_eye',\n 'u_previous',\n 'u_step',\n 'u_dustFade',\n 'u_color',\n 'u_alpha',\n 'u_slotA',\n 'u_slotB',\n 'u_slotC',\n 'u_roll',\n 'u_frame',\n 'u_frames',\n 'u_curves',\n 'u_texture',\n 'u_hasTexture',\n 'u_wire',\n 'u_wireOutline',\n 'u_wireAxisX',\n 'u_wireAxisY',\n 'u_wireNormal',\n 'u_wireAlpha',\n ...FOG_UNIFORMS,\n] as const\n\n// A frame's line rules, in the wire template's third column. The quad's template has two, so 0.\nconst RULE_OUTLINE = 0\nconst RULE_AXIS_X = 1\nconst RULE_AXIS_Y = 2\nconst RULE_NORMAL = 3\n\nconst LOCATION = { corner: 0, position: 1, velocity: 2, time: 3, axis: 4 } as const\n\nconst spriteVertex = /* glsl */ `#version 300 es\nprecision highp float;\nprecision highp int;\n\n// The corner, and under \\`u_wire\\` the line's rule.\nlayout(location = ${LOCATION.corner}) in vec3 a_corner;\nlayout(location = ${LOCATION.position}) in vec3 a_position;\nlayout(location = ${LOCATION.velocity}) in vec3 a_velocity;\n// BORN, AGE, LIFE.\nlayout(location = ${LOCATION.time}) in vec3 a_time;\nlayout(location = ${LOCATION.axis}) in vec3 a_axis;\n\nuniform mat4 u_projection;\nuniform mat4 u_modelView;\nuniform float u_time;\nuniform int u_kind;\nuniform int u_facing;\nuniform int u_shape;\nuniform bool u_blur;\nuniform bool u_centered;\nuniform bool u_fade;\nuniform float u_extent;\nuniform vec3 u_eye;\nuniform mat4 u_previous;\nuniform float u_step;\nuniform float u_dustFade;\nuniform vec4 u_color;\nuniform vec4 u_alpha;\nuniform vec4 u_slotA;\nuniform vec4 u_slotB;\nuniform vec4 u_slotC;\nuniform vec4 u_roll;\nuniform vec4 u_frame;\nuniform int u_frames;\n// A host's frame of each sprite, through the same corners: not the game's.\nuniform bool u_wire;\nuniform vec3 u_wireOutline;\nuniform vec3 u_wireAxisX;\nuniform vec3 u_wireAxisY;\nuniform vec3 u_wireNormal;\nuniform float u_wireAlpha;\n\nout vec2 v_uv;\nout vec4 v_color;\n${curvesSource}\n\nconst float SQRT3 = 1.7320508;\nconst float TINY = 1e-6;\n\n// The DLL's normalize: the fast inverse square root with one Newton step, up to 0.2% short.\nfloat inverseLength(float squared) {\n float guess = uintBitsToFloat(0x5f3759dfu - (floatBitsToUint(squared) >> 1));\n return (1.5 - 0.5 * squared * guess * guess) * guess;\n}\n\nvec3 unit(vec3 v) {\n return v * inverseLength(dot(v, v));\n}\n\n// A direction, or the one it falls back on under 1e-6 of length.\nvec3 unitOr(vec3 v, vec3 fallback) {\n float squared = dot(v, v);\n float inverse = inverseLength(squared);\n float len = squared * inverse;\n return len <= TINY ? fallback : v / len;\n}\n\n// 0x6238ecb: under 30° of end-on it falls, and under 10° it's gone.\nfloat fadeOf(float c) {\n if (c > 0.984808) return -1.0;\n if (c <= 0.866025) return 1.0;\n float f = (0.984808 - c) * 8.41876;\n return f * f;\n}\n\nvoid main() {\n float elapsed = u_time - a_time.x;\n float age = a_time.y + elapsed;\n float life = a_time.z;\n bool skip = age > life;\n vec3 p = a_position + a_velocity * elapsed;\n vec3 v = a_velocity;\n\n float key = clamp(life > 0.0 ? age / life : 0.0, 0.0, 1.0);\n vec3 tint = slotColor(u_color, key);\n float alpha = slotFloat(u_alpha, key);\n float slotA = slotFloat(u_slotA, key);\n float slotB = slotFloat(u_slotB, key);\n float slotC = slotFloat(u_slotC, key);\n float frame = slotFloat(u_frame, key);\n float roll = 0.0;\n float halfX;\n float halfY;\n\n // Each routine's own skips, after the LOD and on the sign.\n if (u_kind == ${KIND_BASIC}) {\n skip = skip || !(alpha >= 0.01);\n halfX = slotA * u_extent * slotB;\n halfY = slotA * u_extent;\n roll = slotFloat(u_roll, key);\n } else if (u_kind == ${KIND_PERP}) {\n halfX = halfY = slotA * u_extent * 0.5;\n skip = skip || !(halfX > TINY) || !(alpha > TINY);\n } else if (u_kind == ${KIND_RECT}) {\n float k = slotC * u_extent;\n halfX = slotA * k / 2.0;\n halfY = slotB * k / 2.0;\n skip = skip || !(slotB * k > TINY) || !(halfX > TINY) || !(alpha > 1e-4);\n } else if (u_kind == ${KIND_DUST}) {\n halfX = halfY = slotA * 0.5;\n frame = 0.0;\n } else {\n float k = slotC * u_extent;\n skip = skip || k < 1e-11 || alpha == 0.0;\n halfX = slotA * k;\n halfY = slotB * k;\n }\n\n vec4 rect = u_frames < 0 ? vec4(0.0, 0.0, 1.0, 1.0) : frameRect(u_frames, frame);\n float cx = a_corner.x;\n float cy = a_corner.y;\n // (-1, 1) is (u1, v1) and (1, -1) is (u2, v2).\n vec2 through = vec2(cx < 0.0 ? 0.0 : 1.0, cy > 0.0 ? 0.0 : 1.0);\n vec4 clip;\n // The frame's normal, from its centre, in view space or in the appearance's.\n vec3 wireCentre = p;\n vec3 wireNormal = vec3(0.0);\n bool wireView = false;\n\n if (u_facing == ${FACING_CAMERA} || u_facing == ${FACING_DUST}) {\n // Built in the view plane: an appearance's scale moves these and never resizes them.\n vec3 c = (u_modelView * vec4(p, 1.0)).xyz;\n vec2 corner;\n float depth = c.z;\n wireCentre = c;\n wireNormal = vec3(0.0, 0.0, 1.0);\n wireView = true;\n\n if (u_facing == ${FACING_CAMERA}) {\n float cosine = cos(roll);\n float sine = sin(roll);\n vec2 x = vec2(cosine, -sine);\n vec2 y = vec2(sine, cosine);\n\n // Equilateral triangle round the circle of radius halfY: apex 2 halfY up, base at (+-sqrt3, -1) halfY.\n if (u_shape != ${SHAPE_QUAD}) {\n bool mapped = u_shape == ${SHAPE_TRI_TEXTURE};\n if (cx < 0.0 && cy > 0.0) {\n corner = c.xy + y * (2.0 * halfY);\n through = mapped ? vec2(0.0, 1.0) : vec2(0.5, 0.0);\n } else if (cy > 0.0) {\n corner = c.xy + x * (SQRT3 * halfY) - y * halfY;\n through = vec2(1.0, 1.0);\n } else {\n corner = c.xy - x * (SQRT3 * halfY) - y * halfY;\n through = mapped ? vec2(0.0, 0.0) : vec2(0.0, 1.0);\n }\n } else if (u_blur) {\n // 0x62168a4: from a thirtieth of a second back to here, along the motion across the view.\n vec3 velocity = mat3(u_modelView) * v;\n vec3 w = unit(cross(cross(c, velocity), c));\n vec2 tail = c.xy - w.xy * (dot(velocity, w) / 30.0);\n vec2 along = w.xy * halfY;\n vec2 across = vec2(-w.y, w.x) * halfX;\n corner = (cy > 0.0 ? tail - along : c.xy + along) - across * cx;\n } else {\n corner = c.xy + x * (halfX * cx) + y * (halfY * cy);\n }\n } else {\n // 0x620fcb0: a kite along how far it moved across the view since the last frame.\n vec3 q = (u_previous * vec4(p - v * u_step, 1.0)).xyz;\n vec3 d = c - q;\n vec3 w = unit(cross(cross(c, d), c));\n float s = 0.0175 * dot(d, w) / u_step;\n if (s < 0.025) w = vec3(0.0, 1.0, 0.0);\n vec3 along = w * (min(s, 100.0) + halfY);\n vec2 side = vec2(-w.y, w.x) * halfY;\n alpha *= u_dustFade;\n skip = skip || c.z > -1.0 || q.z > -1.0 || !(alpha > 0.01);\n vec3 view;\n if (cx < 0.0 && cy > 0.0) {\n view = vec3(c.xy - side, c.z);\n through = vec2(0.0, 0.0);\n } else if (cx > 0.0 && cy < 0.0) {\n view = vec3(c.xy + side, c.z);\n through = vec2(1.0, 1.0);\n } else if (cy > 0.0) {\n view = c + along * 0.65;\n through = vec2(0.0, 1.0);\n } else {\n view = c - along / 0.65;\n through = vec2(1.0, 0.0);\n }\n corner = view.xy;\n depth = view.z;\n }\n clip = u_projection * vec4(corner, depth, 1.0);\n } else {\n // Built in the appearance's frame, so its scale reaches the quad.\n vec3 local;\n float c;\n float least = 0.0;\n\n if (u_facing == ${FACING_TRAVEL}) {\n // 0x6238a70: along the velocity in space, turned about it to face the eye.\n vec3 d = unitOr(v, vec3(0.0, 1.0, 0.0));\n // The fast inverse root's length, as the direction's (\\`0x6238d44\\`–\\`0x6238d98\\`).\n float speed = dot(v, v) * inverseLength(dot(v, v));\n vec3 e = p - u_eye;\n vec3 side = cross(d, e);\n float l = length(side);\n skip = skip || !(l > TINY);\n side = l > 0.0 ? side / l : vec3(1.0, 0.0, 0.0);\n // \\`0x3d08850a\\`, not the basic streak's: about a thirtieth of a second of travel.\n float len = 2.0 * halfY + (u_blur ? speed * 0.03333 : 0.0);\n vec3 front = u_centered ? p + d * (0.5 * len) : p + d * len;\n vec3 back = u_centered ? p - d * (0.5 * len) : p;\n local = (cy > 0.0 ? front : back) - side * (halfX * cx);\n c = abs(dot(d, unitOr(e, vec3(0.0, 1.0, 0.0))));\n least = 1e-4;\n wireCentre = back;\n wireNormal = cross(d, side);\n } else {\n vec3 x;\n vec3 y;\n vec3 n;\n if (u_facing == ${FACING_PERPENDICULAR}) {\n // 0x6233330: the velocity normal to it, and the roll the seed's projection across it.\n float squared = dot(v, v);\n bool still = squared * inverseLength(squared) <= TINY;\n bool onY = all(lessThanEqual(abs(a_axis - vec3(0.0, 1.0, 0.0)), vec3(1e-4)));\n // Divided by its fast length, then crossed, so the extents run up to 0.2% short (\\`effect_sprites\\`).\n n = still ? (onY ? vec3(1.0, 0.0, 0.0) : vec3(0.0, 1.0, 0.0)) : v / (squared * inverseLength(squared));\n vec3 across = unit(cross(a_axis, n));\n x = cross(n, across);\n y = -across;\n least = TINY;\n } else {\n x = vec3(1.0, 0.0, 0.0);\n y = vec3(0.0, 1.0, 0.0);\n n = vec3(0.0, 0.0, 1.0);\n }\n local = p + x * (halfX * cx) + y * (halfY * cy);\n // 1 minus the eye ray's |cos| to the normal: it nears 1 as the face turns edge-on.\n c = 1.0 - abs(dot(unitOr(u_eye - p, vec3(0.0, 1.0, 0.0)), n));\n wireNormal = n;\n }\n if (u_fade) {\n float f = fadeOf(c);\n if (f < 0.0) skip = true;\n else alpha *= f;\n if (!(alpha > least)) skip = true;\n }\n clip = u_projection * (u_modelView * vec4(local, 1.0));\n }\n\n v_uv = vec2(mix(rect.x, rect.z, through.x), mix(rect.y, rect.w, through.y));\n // The vertex colour: into the top byte with no clamp, so it wraps.\n v_color = vec4(tint, mod(trunc(alpha * 255.0), 256.0) / 255.0);\n\n if (u_wire) {\n int rule = int(a_corner.z + 0.5);\n if (rule == ${RULE_NORMAL}) {\n // As long as the mean of the half extents, so it reads against the quad it stands on.\n vec3 tip = wireCentre + wireNormal * (cx * 0.5 * (halfX + halfY));\n clip = u_projection * (wireView ? vec4(tip, 1.0) : u_modelView * vec4(tip, 1.0));\n }\n v_color = vec4(\n rule == ${RULE_AXIS_X} ? u_wireAxisX\n : rule == ${RULE_AXIS_Y} ? u_wireAxisY\n : rule == ${RULE_NORMAL} ? u_wireNormal\n : u_wireOutline,\n u_wireAlpha);\n }\n\n // A skipped instance goes outside the clip volume (x, y, z > w), so it draws nothing.\n gl_Position = skip ? vec4(2.0, 2.0, 2.0, 1.0) : clip;\n}\n`\n\nconst beamVertex = /* glsl */ `#version 300 es\nprecision highp float;\n\nlayout(location = 0) in vec3 a_position;\nlayout(location = 1) in vec4 a_color;\nlayout(location = 2) in vec2 a_uv;\n\nuniform mat4 u_projection;\nuniform mat4 u_modelView;\n\nout vec2 v_uv;\nout vec4 v_color;\n\nvoid main() {\n v_uv = a_uv;\n v_color = a_color;\n gl_Position = u_projection * (u_modelView * vec4(a_position, 1.0));\n}\n`\n\n// Modulated by the texture when there's one. 21 retail appearances name none, and draw flat.\nconst fragment = /* glsl */ `#version 300 es\nprecision highp float;\n\nin vec2 v_uv;\nin vec4 v_color;\n\nuniform sampler2D u_texture;\nuniform bool u_hasTexture;\n${FOG_GLSL}\n\nout vec4 fragColor;\n\nvoid main() {\n fragColor = u_hasTexture ? v_color * texture(u_texture, v_uv) : v_color;\n fragColor.rgb = fogged(fragColor.rgb);\n // D3DRS_ALPHAREF 0, GREATER (\\`effect_sprites\\`), compared at 8 bits.\n if (!(floor(fragColor.a * 255.0 + 0.5) > 0.0)) discard;\n}\n`\n\nconst BEAM_UNIFORMS = [\n 'u_projection',\n 'u_modelView',\n 'u_texture',\n 'u_hasTexture',\n ...FOG_UNIFORMS,\n] as const\n\n// A triangle to a line: no culling, so the winding means nothing.\n// prettier-ignore\nconst CORNERS = new Float32Array([\n -1, 1, 1, 1, 1, -1,\n -1, 1, 1, -1, -1, -1,\n])\n\n// A line pair to a line: the outline edge by edge, then centre to edge for each axis and the normal.\n// A triangle's two lower corners meet, so its third edge is a point.\n// prettier-ignore\nconst WIRE = new Float32Array([\n -1, 1, RULE_OUTLINE, 1, 1, RULE_OUTLINE,\n 1, 1, RULE_OUTLINE, 1, -1, RULE_OUTLINE,\n 1, -1, RULE_OUTLINE, -1, -1, RULE_OUTLINE,\n -1, -1, RULE_OUTLINE, -1, 1, RULE_OUTLINE,\n 0, 0, RULE_AXIS_X, 1, 0, RULE_AXIS_X,\n 0, 0, RULE_AXIS_Y, 0, 1, RULE_AXIS_Y,\n 0, 0, RULE_NORMAL, 1, 0, RULE_NORMAL,\n])\n\nconst WIRE_VERTICES = WIRE.length / 3\n\nconst TEXTURE_UNIT = DIFFUSE_UNIT\nconst CURVES_UNIT = 3\n\nconst factor = (gl: WebGL2RenderingContext, mode: BlendingMode): number | undefined => {\n switch (mode) {\n case BlendingMode.Zero:\n return gl.ZERO\n case BlendingMode.One:\n return gl.ONE\n case BlendingMode.SourceColor:\n return gl.SRC_COLOR\n case BlendingMode.InverseSourceColor:\n return gl.ONE_MINUS_SRC_COLOR\n case BlendingMode.SourceAlpha:\n return gl.SRC_ALPHA\n case BlendingMode.InverseSourceAlpha:\n return gl.ONE_MINUS_SRC_ALPHA\n case BlendingMode.DestinationAlpha:\n return gl.DST_ALPHA\n case BlendingMode.InverseDestinationAlpha:\n return gl.ONE_MINUS_DST_ALPHA\n case BlendingMode.DestinationColor:\n return gl.DST_COLOR\n case BlendingMode.InverseDestinationColor:\n return gl.ONE_MINUS_DST_COLOR\n case BlendingMode.SourceAlphaSAT:\n return gl.SRC_ALPHA_SATURATE\n default:\n return undefined\n }\n}\n\n/**\n * The two render states, straight from the node (`0x6217760`). Absent is `{5, 2}`. **Uncaptured:** a\n * present `None`, 0, is no D3D value, so what the driver does is unknown (22 retail nodes); and a\n * both-mode as a destination, which D3D rejects (one node), is read as the plain factor.\n */\nexport const blendFactors = (gl: WebGL2RenderingContext, blend?: Blending): [number, number] => {\n const fallback: [number, number] = [gl.SRC_ALPHA, gl.ONE]\n if (!blend || blend.source === BlendingMode.None) return fallback\n if (blend.source === BlendingMode.BothSourceAlpha) return [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA]\n\n if (blend.source === BlendingMode.BothInverseSourceAlpha)\n return [gl.ONE_MINUS_SRC_ALPHA, gl.SRC_ALPHA]\n\n const source = factor(gl, blend.source) ?? fallback[0]\n if (blend.target === BlendingMode.BothInverseSourceAlpha) return [source, gl.ONE_MINUS_SRC_ALPHA]\n if (blend.target === BlendingMode.BothSourceAlpha) return [source, gl.SRC_ALPHA]\n return [source, factor(gl, blend.target) ?? fallback[1]]\n}\n\ninterface LaneBuffers {\n buffer: WebGLBuffer\n array: WebGLVertexArrayObject\n capacity: number\n version: number\n uploaded: number\n bound: number\n}\n\nexport interface EffectContext {\n gl: WebGL2RenderingContext\n view: Matrix4\n projection: Matrix4\n bindTexture: (draw: EffectDraw) => boolean\n fog?: Fog\n /** `less` when absent. */\n depthFunc?: 'less' | 'lequal'\n}\n\nexport type Rgb = readonly [number, number, number]\n\n/** How a host's frames of the sprites look: none of it is the game's. */\nexport interface SpriteFrameStyle {\n /** An appearance's outline; none leaves its sprites unframed. */\n outline: (node: EffectNode) => Rgb | undefined\n axisX: Rgb\n axisY: Rgb\n normal: Rgb\n alpha: number\n}\n\nexport interface EffectRenderer {\n draw: (draws: readonly EffectDraw[], context: EffectContext) => void\n /**\n * Each sprite's frame as lines: its outline, its two axes and its normal, through the corners the\n * draw would have. Under the depth test and function as found, blended, with no depth writes.\n * A beam or a triangle list has none.\n */\n outline: (\n draws: readonly EffectDraw[],\n context: Pick<EffectContext, 'gl' | 'view' | 'projection'> & { style: SpriteFrameStyle },\n ) => void\n /** Frees the lanes no draw or outline named since the last call: once a frame, after both. */\n prune: () => void\n dispose: () => void\n}\n\nexport const createEffectRenderer = (gl: WebGL2RenderingContext): EffectRenderer => {\n let sprite: Program<(typeof SPRITE_UNIFORMS)[number]> | undefined\n let beam: Program<(typeof BEAM_UNIFORMS)[number]> | undefined\n let template: WebGLBuffer | undefined\n let wire: WebGLBuffer | undefined\n let beamBuffer: WebGLBuffer | undefined\n let beamArray: WebGLVertexArrayObject | undefined\n let curveTexture: WebGLTexture | undefined\n let curveVersion = -1\n const table = new CurveTable()\n let lanes = new Map<Lane, LaneBuffers>()\n let named = new Set<Lane>()\n\n const point = (entry: LaneBuffers, lane: Lane) => {\n if (entry.bound === lane.tail) return\n entry.bound = lane.tail\n\n // The 64-byte record is read in place: byte 0 position, 12 velocity, 24 BORN/AGE/LIFE, 36 axis.\n const stride = RECORD * 4\n const base = lane.tail * stride\n\n gl.bindBuffer(gl.ARRAY_BUFFER, entry.buffer)\n gl.vertexAttribPointer(LOCATION.position, 3, gl.FLOAT, false, stride, base)\n gl.vertexAttribPointer(LOCATION.velocity, 3, gl.FLOAT, false, stride, base + 12)\n gl.vertexAttribPointer(LOCATION.time, 3, gl.FLOAT, false, stride, base + 24)\n gl.vertexAttribPointer(LOCATION.axis, 3, gl.FLOAT, false, stride, base + 36)\n }\n\n const laneOf = (lane: Lane): LaneBuffers => {\n named.add(lane)\n\n let entry = lanes.get(lane)\n\n if (!entry) {\n entry = {\n buffer: gl.createBuffer(),\n array: gl.createVertexArray(),\n capacity: 0,\n version: -1,\n uploaded: 0,\n bound: -1,\n }\n lanes.set(lane, entry)\n gl.bindVertexArray(entry.array)\n gl.bindBuffer(gl.ARRAY_BUFFER, template!)\n gl.enableVertexAttribArray(LOCATION.corner)\n gl.vertexAttribPointer(LOCATION.corner, 2, gl.FLOAT, false, 0, 0)\n\n for (const location of [LOCATION.position, LOCATION.velocity, LOCATION.time, LOCATION.axis]) {\n gl.enableVertexAttribArray(location)\n gl.vertexAttribDivisor(location, 1)\n }\n }\n\n gl.bindVertexArray(entry.array)\n gl.bindBuffer(gl.ARRAY_BUFFER, entry.buffer)\n\n // Only births go up, unless a record it already has changed.\n if (entry.capacity !== lane.capacity) {\n gl.bufferData(gl.ARRAY_BUFFER, lane.records, gl.DYNAMIC_DRAW)\n entry.capacity = lane.capacity\n entry.bound = -1\n } else if (entry.version !== lane.version) {\n gl.bufferSubData(gl.ARRAY_BUFFER, 0, lane.records, 0, lane.head * RECORD)\n } else if (entry.uploaded < lane.head) {\n const from = entry.uploaded * RECORD\n\n // `from` counts floats: bytes (×4) into the buffer, elements into `lane.records`.\n gl.bufferSubData(gl.ARRAY_BUFFER, from * 4, lane.records, from, lane.head * RECORD - from)\n }\n\n entry.version = lane.version\n entry.uploaded = lane.head\n point(entry, lane)\n return entry\n }\n\n const bindCurves = () => {\n gl.activeTexture(gl.TEXTURE0 + CURVES_UNIT)\n curveTexture ??= gl.createTexture()\n gl.bindTexture(gl.TEXTURE_2D, curveTexture)\n\n if (curveVersion !== table.version) {\n const rows = Math.max(1, Math.ceil(table.length / TABLE_WIDTH))\n\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(\n gl.TEXTURE_2D,\n 0,\n gl.RGBA32F,\n TABLE_WIDTH,\n rows,\n 0,\n gl.RGBA,\n gl.FLOAT,\n table.texels.subarray(0, rows * TABLE_WIDTH * 4),\n )\n curveVersion = table.version\n }\n\n gl.activeTexture(gl.TEXTURE0 + TEXTURE_UNIT)\n }\n\n const spriteUniforms = (draw: SpriteDraw, view: Matrix4, projection: Matrix4) => {\n const { uniforms } = sprite!\n const { lists, sparam } = draw\n const slot = (location: WebGLUniformLocation | null, s: readonly number[]) =>\n gl.uniform4f(location, s[0]!, s[1]!, s[2]!, s[3]!)\n const float = (list: typeof lists.alpha, fallback: number) =>\n table.floatSlot(list, sparam, fallback)\n\n slot(uniforms.u_color, table.colorSlot(lists.color, sparam, GREY))\n slot(uniforms.u_alpha, float(lists.alpha, 1))\n slot(uniforms.u_slotA, float(lists.a, 1))\n slot(uniforms.u_slotB, float(lists.b, 1))\n slot(uniforms.u_slotC, float(lists.c, 1))\n slot(uniforms.u_roll, float(lists.roll, 0))\n slot(uniforms.u_frame, float(lists.frame, 0))\n gl.uniform1i(\n uniforms.u_frames,\n draw.frames.length > 1 || draw.texture ? table.frames(draw.frames, draw.currentFrame) : -1,\n )\n gl.uniform1i(uniforms.u_kind, lists.kind)\n gl.uniform1i(uniforms.u_facing, draw.facing)\n gl.uniform1i(uniforms.u_shape, draw.shape)\n gl.uniform1i(uniforms.u_blur, draw.blur ? 1 : 0)\n gl.uniform1i(uniforms.u_centered, draw.centered ? 1 : 0)\n gl.uniform1i(uniforms.u_fade, draw.fade ? 1 : 0)\n gl.uniform1f(uniforms.u_extent, draw.extent)\n gl.uniform1f(uniforms.u_time, draw.time)\n gl.uniform3f(uniforms.u_eye, draw.eye.x, draw.eye.y, draw.eye.z)\n gl.uniformMatrix4fv(uniforms.u_projection, false, Matrix4.toArray(projection))\n gl.uniformMatrix4fv(\n uniforms.u_modelView,\n false,\n Matrix4.toArray(Matrix4.multiply(view, draw.world)),\n )\n\n if (draw.dust) {\n gl.uniformMatrix4fv(uniforms.u_previous, false, Matrix4.toArray(draw.dust.previous))\n gl.uniform1f(uniforms.u_step, draw.dust.step)\n gl.uniform1f(uniforms.u_dustFade, draw.dust.fade)\n }\n }\n\n const prepare = () => {\n sprite ??= createProgram(gl, spriteVertex, fragment, SPRITE_UNIFORMS)\n beam ??= createProgram(gl, beamVertex, fragment, BEAM_UNIFORMS)\n\n if (!template) {\n template = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, template)\n gl.bufferData(gl.ARRAY_BUFFER, CORNERS, gl.STATIC_DRAW)\n }\n }\n\n // Encoded first: the texture must hold every list before any sprite reads one.\n const encode = (draws: readonly EffectDraw[]) => {\n for (const each of draws)\n if (each.type === 'sprite') {\n const { lists, sparam } = each\n\n table.colorSlot(lists.color, sparam, GREY)\n\n for (const [list, fallback] of [\n [lists.alpha, 1],\n [lists.a, 1],\n [lists.b, 1],\n [lists.c, 1],\n [lists.roll, 0],\n [lists.frame, 0],\n ] as const)\n table.floatSlot(list, sparam, fallback)\n\n if (each.frames.length > 1 || each.texture) table.frames(each.frames, each.currentFrame)\n }\n\n bindCurves()\n }\n\n const unbind = () => {\n gl.bindVertexArray(null)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n gl.activeTexture(gl.TEXTURE0 + CURVES_UNIT)\n gl.bindTexture(gl.TEXTURE_2D, null)\n gl.activeTexture(gl.TEXTURE0)\n gl.depthMask(true)\n }\n\n const draw = (\n draws: readonly EffectDraw[],\n { view, projection, bindTexture, fog, depthFunc = 'less' }: EffectContext,\n ): void => {\n if (!draws.length) return\n prepare()\n if (!sprite || !beam) return\n\n // `0x62019e0`: lighting off, no Z writes, no culling, blending on. The fog is the frame's.\n for (const program of [sprite, beam]) {\n gl.useProgram(program.handle)\n setFog(gl, program.uniforms, fog)\n }\n\n gl.disable(gl.CULL_FACE)\n gl.enable(gl.BLEND)\n gl.depthMask(false)\n gl.depthFunc(depthFunc === 'lequal' ? gl.LEQUAL : gl.LESS)\n gl.useProgram(sprite.handle)\n gl.uniform1i(sprite.uniforms.u_wire, 0)\n\n encode(draws)\n\n for (const each of draws) {\n const [source, destination] = blendFactors(gl, each.blend)\n\n // Retail's target has no alpha to keep (`li_elite`).\n gl.blendFuncSeparate(source, destination, gl.ZERO, gl.ONE)\n\n const hasTexture = bindTexture(each)\n\n if (each.type === 'sprite') {\n gl.useProgram(sprite.handle)\n gl.uniform1i(sprite.uniforms.u_texture, TEXTURE_UNIT)\n gl.uniform1i(sprite.uniforms.u_curves, CURVES_UNIT)\n gl.uniform1i(sprite.uniforms.u_hasTexture, hasTexture ? 1 : 0)\n spriteUniforms(each, view, projection)\n\n const { lane } = each\n\n laneOf(lane)\n gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, lane.head - lane.tail)\n continue\n }\n\n gl.useProgram(beam.handle)\n gl.uniform1i(beam.uniforms.u_texture, TEXTURE_UNIT)\n gl.uniform1i(beam.uniforms.u_hasTexture, hasTexture ? 1 : 0)\n gl.uniformMatrix4fv(beam.uniforms.u_projection, false, Matrix4.toArray(projection))\n gl.uniformMatrix4fv(\n beam.uniforms.u_modelView,\n false,\n Matrix4.toArray(Matrix4.multiply(view, each.world)),\n )\n beamBuffer ??= gl.createBuffer()\n\n if (!beamArray) {\n beamArray = gl.createVertexArray()\n gl.bindVertexArray(beamArray)\n gl.bindBuffer(gl.ARRAY_BUFFER, beamBuffer)\n // Nine floats a vertex, as `beamVertices` writes them: position at 0, colour at 12, UV at 28.\n gl.enableVertexAttribArray(0)\n gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 36, 0)\n gl.enableVertexAttribArray(1)\n gl.vertexAttribPointer(1, 4, gl.FLOAT, false, 36, 12)\n gl.enableVertexAttribArray(2)\n gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 36, 28)\n }\n\n gl.bindVertexArray(beamArray)\n gl.bindBuffer(gl.ARRAY_BUFFER, beamBuffer)\n gl.bufferData(gl.ARRAY_BUFFER, each.vertices, gl.STREAM_DRAW)\n gl.drawArrays(gl.TRIANGLES, 0, each.count)\n }\n\n unbind()\n }\n\n const outline: EffectRenderer['outline'] = (draws, { view, projection, style }) => {\n const sprites = draws.filter((each): each is SpriteDraw => each.type === 'sprite')\n if (!sprites.length) return\n prepare()\n if (!sprite) return\n\n if (!wire) {\n wire = gl.createBuffer()\n gl.bindBuffer(gl.ARRAY_BUFFER, wire)\n gl.bufferData(gl.ARRAY_BUFFER, WIRE, gl.STATIC_DRAW)\n }\n\n const { uniforms } = sprite\n const rgb = (location: WebGLUniformLocation | null, [r, g, b]: Rgb) =>\n gl.uniform3f(location, r, g, b)\n\n gl.useProgram(sprite.handle)\n setFog(gl, uniforms, undefined)\n gl.uniform1i(uniforms.u_wire, 1)\n gl.uniform1i(uniforms.u_hasTexture, 0)\n gl.uniform1i(uniforms.u_curves, CURVES_UNIT)\n rgb(uniforms.u_wireAxisX, style.axisX)\n rgb(uniforms.u_wireAxisY, style.axisY)\n rgb(uniforms.u_wireNormal, style.normal)\n gl.uniform1f(uniforms.u_wireAlpha, style.alpha)\n gl.disable(gl.CULL_FACE)\n gl.enable(gl.BLEND)\n gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)\n gl.depthMask(false)\n\n encode(sprites)\n\n for (const each of sprites) {\n const color = style.outline(each.node)\n if (!color) continue\n rgb(uniforms.u_wireOutline, color)\n spriteUniforms(each, view, projection)\n\n const { lane } = each\n\n laneOf(lane)\n // The lane's array, with the wire template in the quad's place for this draw.\n gl.bindBuffer(gl.ARRAY_BUFFER, wire)\n gl.vertexAttribPointer(LOCATION.corner, 3, gl.FLOAT, false, 0, 0)\n gl.drawArraysInstanced(gl.LINES, 0, WIRE_VERTICES, lane.head - lane.tail)\n gl.bindBuffer(gl.ARRAY_BUFFER, template!)\n gl.vertexAttribPointer(LOCATION.corner, 2, gl.FLOAT, false, 0, 0)\n }\n\n gl.uniform1i(uniforms.u_wire, 0)\n unbind()\n }\n\n // A lane nothing named this frame is gone, or empty, and its effect may be too.\n const prune = () => {\n for (const [lane, entry] of lanes)\n if (!named.has(lane)) {\n gl.deleteBuffer(entry.buffer)\n gl.deleteVertexArray(entry.array)\n lanes.delete(lane)\n }\n\n named = new Set()\n }\n\n const dispose = () => {\n for (const entry of lanes.values()) {\n gl.deleteBuffer(entry.buffer)\n gl.deleteVertexArray(entry.array)\n }\n\n lanes = new Map()\n if (sprite) gl.deleteProgram(sprite.handle)\n if (beam) gl.deleteProgram(beam.handle)\n if (template) gl.deleteBuffer(template)\n if (wire) gl.deleteBuffer(wire)\n if (beamBuffer) gl.deleteBuffer(beamBuffer)\n if (beamArray) gl.deleteVertexArray(beamArray)\n if (curveTexture) gl.deleteTexture(curveTexture)\n sprite = beam = undefined\n template = wire = beamBuffer = beamArray = curveTexture = undefined\n named = new Set()\n }\n\n return { draw, outline, prune, dispose }\n}\n","/**\n * Screen quads: pre-transformed D3D vertices (`XYZRHW | DIFFUSE | TEX1`, FVF `0x1c4`), as\n * `ScreenQuadFlush` (`src/freelancer/Client/screen_quad_state.cpp`) draws a batch. Texture times the\n * vertex's colour, added and unlit, and fogged as the frame left it: the flush never touches\n * `FOGENABLE`, and `SpaceEffectsDrawFrame` runs it under the effects' table fog in a nebula\n * (`SpaceObjDrawPass`, `0x51c741`), which goes by W, `1 / rhw`. Fogged quads are uncaptured.\n */\nimport { createProgram, type Program } from '#/gl/program.js'\nimport { FOG_GLSL, FOG_UNIFORMS, setFog } from './fog.js'\nimport type { Fog } from '#/scene/nebula.js'\nimport type { ScreenQuad } from '#/scene/flare.js'\nimport type { ScreenQuadBatch } from '#/scene/frame.js'\nimport { DIFFUSE_UNIT } from './dcdt.js'\n\nconst UNIFORMS = ['u_viewport', 'u_texture', ...FOG_UNIFORMS] as const\n\nconst vertex = /* glsl */ `#version 300 es\nprecision highp float;\n\n// X and Y in D3D pixels, Z, and 1 / w.\nlayout(location = 0) in vec4 a_position;\nlayout(location = 1) in vec4 a_color;\nlayout(location = 2) in vec2 a_uv;\n\nuniform vec2 u_viewport;\n\nout vec2 v_uv;\nout vec4 v_color;\n\nvoid main() {\n v_uv = a_uv;\n v_color = a_color;\n // D3D8 centres a pixel on its integer coordinate, GL half a pixel on, and Y runs down.\n vec2 window = vec2(a_position.x + 0.5, u_viewport.y - a_position.y - 0.5);\n vec3 ndc = vec3(window / u_viewport * 2.0 - 1.0, a_position.z * 2.0 - 1.0);\n // Dividing by rhw gives clip = (ndc * w, w): GL's divide returns ndc, and gl_FragCoord.w is rhw.\n gl_Position = vec4(ndc, 1.0) / a_position.w;\n}\n`\n\nconst fragment = /* glsl */ `#version 300 es\nprecision highp float;\n\nin vec2 v_uv;\nin vec4 v_color;\n\nuniform sampler2D u_texture;\n${FOG_GLSL}\n\nout vec4 fragColor;\n\nvoid main() {\n fragColor = v_color * texture(u_texture, v_uv);\n // The effects before leave D3DRS_ALPHAREF 0, GREATER on (\\`space_order\\`'s draw 130).\n if (!(floor(fragColor.a * 255.0 + 0.5) > 0.0)) discard;\n fragColor.rgb = fogged(fragColor.rgb);\n}\n`\n\n// Floats a vertex: X, Y, Z, 1 / w, then U and V; its colour follows as four bytes.\nconst FLOATS = 6\nconst STRIDE = FLOATS * 4 + 4\n\n/** `FlushOneBatch`'s corners for a record: (x0, y0), (x0, y1), (x1, y1), (x1, y0). */\nconst writeQuads = (quads: readonly ScreenQuad[]): ArrayBuffer => {\n const buffer = new ArrayBuffer(quads.length * 4 * STRIDE)\n const floats = new Float32Array(buffer)\n const bytes = new Uint8Array(buffer)\n\n quads.forEach(({ x0, y0, x1, y1, z, rhw, u0, v0, u1, v1, color }, n) => {\n const corners = [\n [x0, y0, u0, v0],\n [x0, y1, u0, v1],\n [x1, y1, u1, v1],\n [x1, y0, u1, v0],\n ] as const\n\n corners.forEach(([x, y, u, v], corner) => {\n // `at` is the vertex's byte offset: its floats start at `at / 4`, its colour bytes at `at + 24`.\n const at = (n * 4 + corner) * STRIDE\n\n floats.set([x, y, z, rhw, u, v], at / 4)\n // `0xAARRGGBB` as R, G, B, A.\n bytes.set([(color >>> 16) & 0xff, (color >>> 8) & 0xff, color & 0xff, color >>> 24], at + 24)\n })\n })\n return buffer\n}\n\n/** Two triangles a quad: `{b, b+1, b+2, b, b+2, b+3}`. */\nconst indicesFor = (count: number): Uint16Array => {\n const indices = new Uint16Array(count * 6)\n\n for (let quad = 0; quad < count; quad++)\n indices.set(\n [0, 1, 2, 0, 2, 3].map((offset) => quad * 4 + offset),\n quad * 6,\n )\n\n return indices\n}\n\nexport interface ScreenQuadRenderer {\n /** Draws each batch with its texture bound by `bindTexture` to `DIFFUSE_UNIT`, under `fog`. */\n draw: (\n batches: readonly ScreenQuadBatch[],\n viewport: { width: number; height: number },\n bindTexture: (batch: ScreenQuadBatch) => void,\n fog?: Fog,\n ) => void\n dispose: () => void\n}\n\nexport const createScreenQuadRenderer = (gl: WebGL2RenderingContext): ScreenQuadRenderer => {\n const program: Program<(typeof UNIFORMS)[number]> = createProgram(gl, vertex, fragment, UNIFORMS)\n const vertices = gl.createBuffer()\n const indices = gl.createBuffer()\n const array = gl.createVertexArray()\n\n gl.bindVertexArray(array)\n gl.bindBuffer(gl.ARRAY_BUFFER, vertices)\n gl.enableVertexAttribArray(0)\n gl.vertexAttribPointer(0, 4, gl.FLOAT, false, STRIDE, 0)\n gl.enableVertexAttribArray(1)\n gl.vertexAttribPointer(1, 4, gl.UNSIGNED_BYTE, true, STRIDE, 24)\n gl.enableVertexAttribArray(2)\n gl.vertexAttribPointer(2, 2, gl.FLOAT, false, STRIDE, 16)\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices)\n gl.bindVertexArray(null)\n\n const draw: ScreenQuadRenderer['draw'] = (batches, { width, height }, bindTexture, fog) => {\n gl.useProgram(program.handle)\n gl.uniform2f(program.uniforms.u_viewport, width, height)\n gl.uniform1i(program.uniforms.u_texture, DIFFUSE_UNIT)\n setFog(gl, program.uniforms, fog)\n // `SpaceEffectsDrawFrame` around the flush: LEQUAL, no depth writes; `ScreenQuadFlush` turns\n // culling off, and a batch blends ONE, ONE.\n gl.enable(gl.DEPTH_TEST)\n gl.depthFunc(gl.LEQUAL)\n gl.depthMask(false)\n gl.disable(gl.CULL_FACE)\n gl.enable(gl.BLEND)\n gl.blendFuncSeparate(gl.ONE, gl.ONE, gl.ZERO, gl.ONE)\n gl.bindVertexArray(array)\n\n for (const batch of batches) {\n if (!batch.quads.length) continue\n bindTexture(batch)\n gl.bindBuffer(gl.ARRAY_BUFFER, vertices)\n gl.bufferData(gl.ARRAY_BUFFER, writeQuads(batch.quads), gl.STREAM_DRAW)\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indicesFor(batch.quads.length), gl.STREAM_DRAW)\n gl.drawElements(gl.TRIANGLES, batch.quads.length * 6, gl.UNSIGNED_SHORT, 0)\n }\n\n gl.bindVertexArray(null)\n }\n\n const dispose = () => {\n gl.deleteProgram(program.handle)\n gl.deleteBuffer(vertices)\n gl.deleteBuffer(indices)\n gl.deleteVertexArray(array)\n }\n\n return { draw, dispose }\n}\n","/** GL buffers and vertex arrays for a VMesh. */\nimport type { VMeshData } from '@treewyrm/freelancer/vmesh'\nimport { ATTRIBUTE_LOCATIONS, vertexLayout, type ReferencePlan } from './plan.js'\n\nexport const createVertexBuffer = (gl: WebGL2RenderingContext, data: VMeshData): WebGLBuffer => {\n const buffer = gl.createBuffer()\n\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer)\n gl.bufferData(gl.ARRAY_BUFFER, data.vertices, gl.STATIC_DRAW)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n return buffer\n}\n\nexport interface ReferenceArray {\n array: WebGLVertexArrayObject\n elements: WebGLBuffer\n}\n\n/** A vertex array over a mesh's shared vertices and one reference's own indices. */\nexport const createReferenceArray = (\n gl: WebGL2RenderingContext,\n data: VMeshData,\n vertices: WebGLBuffer,\n { indices }: ReferencePlan,\n): ReferenceArray => {\n const { stride, attributes } = vertexLayout(data.format)\n const array = gl.createVertexArray()\n\n gl.bindVertexArray(array)\n gl.bindBuffer(gl.ARRAY_BUFFER, vertices)\n\n for (const { name, size, normalizedBytes, offset } of attributes) {\n const location = ATTRIBUTE_LOCATIONS[name]\n\n gl.enableVertexAttribArray(location)\n gl.vertexAttribPointer(\n location,\n size,\n normalizedBytes ? gl.UNSIGNED_BYTE : gl.FLOAT,\n normalizedBytes,\n stride,\n offset,\n )\n }\n\n const elements = gl.createBuffer()\n\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elements)\n gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW)\n\n gl.bindVertexArray(null)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null)\n return { array, elements }\n}\n","/** GL textures and samplers. */\nimport type { TextureLayout, TextureUpload } from './upload.js'\n\ninterface Format {\n internal: GLenum\n format?: GLenum\n type?: GLenum\n}\n\n// Raw GL enums: S3TC RGBA, RGB565, RGB5_A1, RGBA8. A compressed layout has no `format` or `type`.\nconst FORMATS: Record<TextureLayout, Format> = {\n // Always the RGBA variants: DXT1 selects punch-through per block.\n dxt1: { internal: 0x83f1 },\n dxt3: { internal: 0x83f2 },\n dxt5: { internal: 0x83f3 },\n rgb565: { internal: 0x8d62, format: 0x1907, type: 0x8363 },\n rgb5a1: { internal: 0x8057, format: 0x1908, type: 0x8034 },\n rgba8: { internal: 0x8058, format: 0x1908, type: 0x1401 },\n}\n\n/** Creates a texture of exactly the planned levels, so a short chain is still complete. */\nexport const createTexture = (\n gl: WebGL2RenderingContext,\n { target, layout, width, height, faces }: TextureUpload,\n): WebGLTexture => {\n const { internal, format, type } = FORMATS[layout]\n\n if (format === undefined && !gl.getExtension('WEBGL_compressed_texture_s3tc'))\n throw new Error('WEBGL_compressed_texture_s3tc is not available')\n\n const bind = target === 'cube' ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D\n const texture = gl.createTexture()\n\n gl.bindTexture(bind, texture)\n gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1)\n gl.texStorage2D(bind, faces[0]!.length, internal, width, height)\n\n faces.forEach((levels, face) => {\n const destination = target === 'cube' ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + face : gl.TEXTURE_2D\n\n levels.forEach((pixels, level) => {\n const w = Math.max(1, width >> level)\n const h = Math.max(1, height >> level)\n\n if (format === undefined)\n gl.compressedTexSubImage2D(destination, level, 0, 0, w, h, internal, pixels)\n else gl.texSubImage2D(destination, level, 0, 0, w, h, format, type!, pixels)\n })\n })\n\n gl.bindTexture(bind, null)\n return texture\n}\n\nexport type TextureFilter = 'nearest' | 'linear'\nexport type TextureWrap = 'repeat' | 'mirror' | 'clamp'\n\nexport interface SamplerState {\n magnify: TextureFilter\n minify: TextureFilter\n /** Between mip levels. */\n mipmap: TextureFilter\n wrapU: TextureWrap\n wrapV: TextureWrap\n}\n\n/** Retail's on hull stages: bilinear within a level, none between (`li_elite`, and `G_RenderMipFilter`). */\nexport const DEFAULT_SAMPLER: SamplerState = {\n magnify: 'linear',\n minify: 'linear',\n mipmap: 'nearest',\n wrapU: 'repeat',\n wrapV: 'repeat',\n}\n\nconst wrapOf = (gl: WebGL2RenderingContext, wrap: TextureWrap): GLenum =>\n wrap === 'repeat' ? gl.REPEAT : wrap === 'mirror' ? gl.MIRRORED_REPEAT : gl.CLAMP_TO_EDGE\n\n// The in-level and between-level filters folded into GL's one combined min-filter enum.\nconst minifyOf = (gl: WebGL2RenderingContext, { minify, mipmap }: SamplerState): GLenum => {\n if (minify === 'nearest')\n return mipmap === 'nearest' ? gl.NEAREST_MIPMAP_NEAREST : gl.NEAREST_MIPMAP_LINEAR\n\n return mipmap === 'nearest' ? gl.LINEAR_MIPMAP_NEAREST : gl.LINEAR_MIPMAP_LINEAR\n}\n\nexport const createSampler = (gl: WebGL2RenderingContext, state: SamplerState): WebGLSampler => {\n const sampler = gl.createSampler()\n\n gl.samplerParameteri(\n sampler,\n gl.TEXTURE_MAG_FILTER,\n state.magnify === 'linear' ? gl.LINEAR : gl.NEAREST,\n )\n gl.samplerParameteri(sampler, gl.TEXTURE_MIN_FILTER, minifyOf(gl, state))\n gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_S, wrapOf(gl, state.wrapU))\n gl.samplerParameteri(sampler, gl.TEXTURE_WRAP_T, wrapOf(gl, state.wrapV))\n return sampler\n}\n","/** What a library texture becomes on the GPU: the same texels retail's device held. Pure, no GL. */\nimport type { CubeTexture, Texture } from '@treewyrm/freelancer/texture'\n\nexport type TextureLayout = 'dxt1' | 'dxt3' | 'dxt5' | 'rgb565' | 'rgb5a1' | 'rgba8'\n\nexport interface TextureUpload {\n target: '2d' | 'cube'\n layout: TextureLayout\n width: number\n height: number\n /** By face, then by level. A flat texture has one face. 16-bit layouts hold `Uint16Array`s. */\n faces: (Uint8Array | Uint16Array)[][]\n}\n\nconst toLittleEndian16 = (bytes: Uint8Array): Uint16Array => {\n const output = new Uint16Array(bytes.length >> 1)\n for (let at = 0; at < output.length; at++) output[at] = bytes[at * 2]! | (bytes[at * 2 + 1]! << 8)\n return output\n}\n\n/** To `bits` by rounding, as D3DX loads a surface. Truncating fails retail's hashes on large levels. */\nconst narrow = (value: number, bits: number): number => {\n const top = (1 << bits) - 1\n\n return Math.floor((value * top) / 255 + 0.5)\n}\n\n/**\n * A Targa without alpha reaches retail's device as R5G6B5 (`DAOT`; captures, format 23). Hashes pin\n * this for colour-mapped and 24-bit chains.\n */\nconst rgbToRgb565 = (level: Uint8Array): Uint16Array => {\n const output = new Uint16Array(level.length / 3)\n\n for (let at = 0; at < output.length; at++)\n output[at] =\n (narrow(level[at * 3]!, 5) << 11) |\n (narrow(level[at * 3 + 1]!, 6) << 5) |\n narrow(level[at * 3 + 2]!, 5)\n\n return output\n}\n\n/**\n * A 16-bit Targa is X1R5G5B5 to retail whatever its attribute bits (`GetTgaSourceFormat`,\n * `src/Shading/TextureLibrary.cpp`), so R5G6B5 as the rest, green widened by repeating its top bit.\n * Hashes pin it on all seven levels of `code_beam` (`beam_shots`, `src/reference/beams.test.ts`).\n * One with its attribute bit set is uncaptured, and none is in retail.\n */\nconst xrgb1555ToRgb565 = (level: Uint8Array): Uint16Array =>\n toLittleEndian16(level).map((pixel) => {\n const green = (pixel >> 5) & 0x1f\n\n // Red moves up one bit, green gains its top bit as a new low bit, blue stays.\n return ((pixel & 0x7c00) << 1) | (((green << 1) | (green >> 4)) << 5) | (pixel & 0x1f)\n })\n\n/** D3D's A1R5G5B5 has alpha on top, GL's RGB5_A1 at the bottom. */\nconst argb1555ToRgba5551 = (level: Uint8Array): Uint16Array =>\n toLittleEndian16(level).map((pixel) => ((pixel << 1) & 0xffff) | (pixel >> 15))\n\n/** X1R5G5B5 as RGB5_A1, opaque: the same 5-bit channels the device would sample. */\nconst xrgb1555ToRgba5551 = (level: Uint8Array): Uint16Array =>\n toLittleEndian16(level).map((pixel) => ((pixel << 1) & 0xffff) | 1)\n\nconst swapRedBlue = (level: Uint8Array): Uint8Array => {\n const output = level.slice()\n\n for (let at = 0; at < level.length; at += 4) {\n output[at] = level[at + 2]!\n output[at + 2] = level[at]!\n }\n\n return output\n}\n\nconst bgrToRgba = (level: Uint8Array): Uint8Array => {\n const output = new Uint8Array((level.length / 3) * 4)\n\n for (let at = 0; at < level.length / 3; at++) {\n output[at * 4] = level[at * 3 + 2]!\n output[at * 4 + 1] = level[at * 3 + 1]!\n output[at * 4 + 2] = level[at * 3]!\n output[at * 4 + 3] = 0xff\n }\n\n return output\n}\n\n/** Reverses rows: `shading.dll` does so for a top-left Targa (`DecodeTgaTexture`). No capture yet. */\nconst reverseRows = (level: Uint8Array, height: number): Uint8Array => {\n const row = level.length / height\n const output = new Uint8Array(level.length)\n\n for (let y = 0; y < height; y++)\n output.set(level.subarray(y * row, (y + 1) * row), (height - 1 - y) * row)\n\n return output\n}\n\nconst flatLayout = ({ format, storage }: Texture): TextureLayout => {\n switch (format) {\n case 'dxt1':\n case 'dxt3':\n case 'dxt5':\n return format\n case 'rgb16_565':\n return 'rgb565'\n case 'rgb16_555':\n // No retail surface is X1R5G5B5. Held as stored is a guess: D3DX may convert it.\n return storage === 'targa' ? 'rgb565' : 'rgb5a1'\n case 'rgba16_5551':\n return storage === 'targa' ? 'rgb565' : 'rgb5a1'\n case 'rgba32_8888':\n return 'rgba8'\n case 'rgb24_888':\n // Two DDS surfaces in `FX/rtc_scene02_e.txm`. Uncaptured, so their device format is a guess.\n return storage === 'targa' ? 'rgb565' : 'rgba8'\n default:\n throw new RangeError(`No retail texture uses ${format}`)\n }\n}\n\nconst flatLevel = (texture: Texture, level: Uint8Array, at: number) => {\n const { format, storage, flip, height } = texture\n\n if (storage === 'targa') {\n // The library has already put a 24- or 32-bit Targa in RGB order.\n const rows = flip ? reverseRows(level, Math.max(1, height >> at)) : level\n\n switch (format) {\n case 'rgb24_888':\n return rgbToRgb565(rows)\n case 'rgb16_555':\n case 'rgba16_5551':\n return xrgb1555ToRgb565(rows)\n default:\n return rows\n }\n }\n\n // A surface is as stored, whatever its header's origin says.\n switch (format) {\n case 'rgb16_565':\n return toLittleEndian16(level)\n case 'rgb16_555':\n return xrgb1555ToRgba5551(level)\n case 'rgba16_5551':\n return argb1555ToRgba5551(level)\n case 'rgba32_8888':\n return swapRedBlue(level)\n case 'rgb24_888':\n return bgrToRgba(level)\n default:\n return level\n }\n}\n\n/** One level down by a 2x2 box, rounded: matches every generated level of retail's two cubes. */\nconst halve = (level: Uint8Array, size: number): Uint8Array => {\n const half = size >> 1\n const output = new Uint8Array(half * half * 4)\n\n for (let y = 0; y < half; y++)\n for (let x = 0; x < half; x++)\n for (let channel = 0; channel < 4; channel++) {\n const texel = (row: number, column: number) => level[(row * size + column) * 4 + channel]!\n const sum =\n texel(y * 2, x * 2) +\n texel(y * 2, x * 2 + 1) +\n texel(y * 2 + 1, x * 2) +\n texel(y * 2 + 1, x * 2 + 1)\n\n output[(y * half + x) * 4 + channel] = (sum + 2) >> 2\n }\n\n return output\n}\n\n/** The rest of a cube's chain: the file holds one level, and D3DX loads it with a full chain. */\nconst cubeChain = (levels: Uint8Array[], width: number): Uint8Array[] => {\n const chain = levels.map(swapRedBlue)\n\n // `size` is the edge of the last level held; each pass appends the next one down to 1x1.\n for (let size = width >> (chain.length - 1); size > 1; size >>= 1)\n chain.push(halve(chain.at(-1)!, size))\n\n return chain\n}\n\n/** What to upload for a texture. Animated entries have no pixels of their own, so don't come here. */\nexport const planUpload = (texture: Texture | CubeTexture): TextureUpload => {\n const { width, height } = texture\n\n if (texture.type === 'cube') {\n if (texture.format !== 'rgba32_8888') throw new RangeError(`No cube uses ${texture.format}`)\n return {\n target: 'cube',\n layout: 'rgba8',\n width,\n height,\n faces: texture.faces.map((levels) => cubeChain(levels, width)),\n }\n }\n\n return {\n target: '2d',\n layout: flatLayout(texture),\n width,\n height,\n faces: [texture.levels.map((level, at) => flatLevel(texture, level, at))],\n }\n}\n","/** Executes a frame. All the GL of a game frame lives here, and it owns what it creates. */\nimport { Matrix4 } from '@treewyrm/freelancer/math'\nimport type { CubeTexture, Texture } from '@treewyrm/freelancer/texture'\nimport type { VMeshData, VMeshRef } from '@treewyrm/freelancer/vmesh'\nimport { collectEffect, type EffectDraw } from '#/alchemy/draw.js'\nimport {\n createEffectRenderer,\n type EffectRenderer,\n type SpriteFrameStyle,\n} from '#/alchemy/program.js'\nimport { INFLUENCE_FLOATS } from '#/deformable/skin.js'\nimport {\n BONES_BINDING,\n createDcDtProgram,\n DIFFUSE_UNIT,\n ENVIRONMENT_UNIT,\n SECOND_UNIT,\n setDrawUniforms,\n setFrameUniforms,\n setLights,\n type DcDtProgram,\n} from '#/material/dcdt.js'\nimport { createScreenQuadRenderer, type ScreenQuadRenderer } from '#/material/screen.js'\nimport { createReferenceArray, createVertexBuffer, type ReferenceArray } from '#/mesh/mesh.js'\nimport { ATTRIBUTE_LOCATIONS, drawMode, planReference } from '#/mesh/plan.js'\nimport {\n createSampler,\n createTexture,\n DEFAULT_SAMPLER,\n type SamplerState,\n} from '#/texture/texture.js'\nimport { planUpload } from '#/texture/upload.js'\nimport type { Draw, Frame, HookName, SceneEffect } from './frame.js'\n\nconst WHOLE_DEPTH: readonly [number, number] = [0, 1]\nconst EFFECT_SAMPLER: SamplerState = { ...DEFAULT_SAMPLER, wrapU: 'clamp', wrapV: 'clamp' }\n\nexport interface HookContext {\n gl: WebGL2RenderingContext\n frame: Frame\n /** With D3D's pixel shift, so a host's lines land on the pixels the ship did. */\n viewProjection: Matrix4\n /**\n * Frames each sprite of these effects as this frame's camera has them, whether or not the frame\n * draws them: an outline, two axes and a normal, under the depth state the hook has set.\n */\n outlineEffects: (effects: readonly SceneEffect[], style: SpriteFrameStyle) => void\n}\n\n/**\n * The host's own drawing. It finds the depth buffer the game path left, with no vertex array or\n * sampler object bound, and may change any GL state: the renderer sets its own again after each hook,\n * so nothing leaks into the game path.\n */\nexport type FrameHooks = Partial<Record<HookName, (context: HookContext) => void>>\n\n/** A rectangle of the target in pixels, from its bottom left as GL counts. */\nexport interface ViewportRect {\n x: number\n y: number\n width: number\n height: number\n}\n\nexport interface RenderOptions {\n /**\n * Where the picture goes, as D3D's viewport: drawn and cleared there alone, the rest of the target\n * left as it was. The letterbox's picture, `(0, bar, w, h − 2·bar)`, with the scene's `aspect` its\n * own (THN-HOST.md, the letterbox). The whole target when absent.\n */\n viewport?: ViewportRect\n}\n\nexport interface Renderer {\n /** Draws, and answers false if there is no context to draw with for now. */\n render: (frame: Frame, hooks?: FrameHooks, options?: RenderOptions) => boolean\n /** Frees what depends on an edited mesh or texture. The next frame uses it afresh. */\n invalidate: (asset: VMeshData | Texture | CubeTexture) => void\n /** Frees everything, and the renderer with it. */\n dispose: () => void\n}\n\ninterface MeshResources {\n vertices: WebGLBuffer\n influences?: WebGLBuffer\n references: Map<VMeshRef, ReferenceArray>\n}\n\n/**\n * Takes a context, and keeps only GPU handles keyed on what the host's frames hold. So a lost context\n * needs nothing from the host but the next frame, whose data rebuilds them.\n */\nexport const createRenderer = (gl: WebGL2RenderingContext): Renderer => {\n let program: DcDtProgram | undefined\n let effects: EffectRenderer | undefined\n let quads: ScreenQuadRenderer | undefined\n let meshes = new Map<VMeshData, MeshResources>()\n let textures = new Map<Texture | CubeTexture, WebGLTexture>()\n let samplers = new Map<string, WebGLSampler>()\n let disposed = false\n\n const forget = () => {\n program = undefined\n effects = undefined\n quads = undefined\n meshes = new Map()\n textures = new Map()\n samplers = new Map()\n }\n\n // Without this default a lost context never comes back.\n const onLost = (event: Event) => event.preventDefault()\n const onRestored = () => forget()\n\n gl.canvas.addEventListener('webglcontextlost', onLost)\n gl.canvas.addEventListener('webglcontextrestored', onRestored)\n\n const freeMesh = ({ vertices, influences, references }: MeshResources) => {\n gl.deleteBuffer(vertices)\n if (influences) gl.deleteBuffer(influences)\n\n for (const { array, elements } of references.values()) {\n gl.deleteVertexArray(array)\n gl.deleteBuffer(elements)\n }\n }\n\n const arrayOf = (\n mesh: VMeshData,\n reference: VMeshRef,\n influences?: Float32Array,\n ): WebGLVertexArrayObject => {\n let resources = meshes.get(mesh)\n\n if (!resources) {\n resources = { vertices: createVertexBuffer(gl, mesh), references: new Map() }\n meshes.set(mesh, resources)\n }\n\n let array = resources.references.get(reference)\n\n if (!array) {\n array = createReferenceArray(gl, mesh, resources.vertices, planReference(mesh, reference))\n\n if (influences) {\n resources.influences ??= gl.createBuffer()\n gl.bindVertexArray(array.array)\n gl.bindBuffer(gl.ARRAY_BUFFER, resources.influences)\n gl.bufferData(gl.ARRAY_BUFFER, influences, gl.STATIC_DRAW)\n\n // Per vertex, 8 floats: four bone indices at byte 0, then their four weights at 16.\n const stride = INFLUENCE_FLOATS * 4\n\n gl.enableVertexAttribArray(ATTRIBUTE_LOCATIONS.boneIndex)\n gl.vertexAttribPointer(ATTRIBUTE_LOCATIONS.boneIndex, 4, gl.FLOAT, false, stride, 0)\n gl.enableVertexAttribArray(ATTRIBUTE_LOCATIONS.boneWeight)\n gl.vertexAttribPointer(ATTRIBUTE_LOCATIONS.boneWeight, 4, gl.FLOAT, false, stride, 16)\n gl.bindVertexArray(null)\n gl.bindBuffer(gl.ARRAY_BUFFER, null)\n }\n\n resources.references.set(reference, array)\n }\n\n return array.array\n }\n\n const textureOf = (entry: Texture | CubeTexture): WebGLTexture => {\n let texture = textures.get(entry)\n\n if (!texture) {\n texture = createTexture(gl, planUpload(entry))\n textures.set(entry, texture)\n }\n\n return texture\n }\n\n const samplerOf = (state: SamplerState): WebGLSampler => {\n const key = JSON.stringify(state)\n let sampler = samplers.get(key)\n\n if (!sampler) {\n sampler = createSampler(gl, state)\n samplers.set(key, sampler)\n }\n\n return sampler\n }\n\n const render = (\n frame: Frame,\n hooks: FrameHooks = {},\n { viewport }: RenderOptions = {},\n ): boolean => {\n if (disposed) throw new Error('This renderer has been disposed')\n if (gl.isContextLost()) return false\n program ??= createDcDtProgram(gl)\n\n const active = program\n\n const target: WebGLFramebuffer | null = gl.getParameter(gl.FRAMEBUFFER_BINDING)\n const [left, bottom, width, height]: [number, number, number, number] = viewport\n ? [viewport.x, viewport.y, viewport.width, viewport.height]\n : target\n ? [0, 0, gl.getParameter(gl.VIEWPORT)[2], gl.getParameter(gl.VIEWPORT)[3]]\n : [0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight]\n\n // D3D8's `Clear` with no rectangles clears the viewport alone.\n const clear = (mask: number) => {\n if (viewport) {\n gl.enable(gl.SCISSOR_TEST)\n gl.scissor(left, bottom, width, height)\n }\n gl.clear(mask)\n gl.disable(gl.SCISSOR_TEST)\n }\n\n // D3D8 samples pixels at integer coordinates, GL at half. Measured: without this shift, mean\n // difference from retail's `li_elite_turned` is 8.55 of 255, against 1.55 with it.\n const shift = Matrix4.translation({ x: 1 / width, y: -1 / height, z: 0 })\n const projection = Matrix4.multiply(shift, frame.projection)\n const viewProjection = Matrix4.multiply(projection, frame.view)\n\n const applyState = () => {\n gl.bindFramebuffer(gl.FRAMEBUFFER, target)\n gl.viewport(left, bottom, width, height)\n gl.useProgram(active.handle)\n gl.bindBufferBase(gl.UNIFORM_BUFFER, BONES_BINDING, active.boneBuffer)\n setFrameUniforms(gl, active, { ...frame, projection })\n\n // Retail's device: DITHERENABLE 0, D3DCMP_LESS, and a target with no alpha to keep (`li_elite`).\n gl.disable(gl.DITHER)\n gl.disable(gl.SCISSOR_TEST)\n gl.disable(gl.STENCIL_TEST)\n gl.disable(gl.SAMPLE_COVERAGE)\n gl.disable(gl.SAMPLE_ALPHA_TO_COVERAGE)\n gl.disable(gl.POLYGON_OFFSET_FILL)\n gl.disable(gl.RASTERIZER_DISCARD)\n gl.enable(gl.DEPTH_TEST)\n gl.depthFunc(gl.LESS)\n gl.depthMask(true)\n gl.depthRange(0, 1)\n gl.colorMask(true, true, true, true)\n // What a UV set the mesh hasn't got reads (`bands_one_uv`), whatever a hook left here.\n gl.vertexAttrib2f(ATTRIBUTE_LOCATIONS.uv0, 0, 0)\n gl.vertexAttrib2f(ATTRIBUTE_LOCATIONS.uv1, 0, 0)\n gl.vertexAttrib3f(ATTRIBUTE_LOCATIONS.normal, 0, 0, 0)\n gl.enable(gl.CULL_FACE)\n gl.frontFace(gl.CCW)\n gl.blendEquation(gl.FUNC_ADD)\n gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ZERO, gl.ONE)\n }\n\n // A sampler object outranks a texture's own parameters, so one left bound would change a host's.\n const release = () => {\n gl.bindVertexArray(null)\n gl.bindSampler(DIFFUSE_UNIT, null)\n gl.bindSampler(ENVIRONMENT_UNIT, null)\n gl.bindSampler(SECOND_UNIT, null)\n }\n\n const outlineEffects = (shown: readonly SceneEffect[], style: SpriteFrameStyle) => {\n const draws: EffectDraw[] = []\n\n for (const { instance, texture, visible } of shown)\n collectEffect(instance, frame.view, texture, draws, new Set(), visible)\n\n effects ??= createEffectRenderer(gl)\n effects.outline(draws, { gl, view: frame.view, projection, style })\n }\n\n const runHooks = (before: number, only?: (name: HookName) => boolean) => {\n for (const hook of frame.hooks) {\n const run =\n hook.before === before && (only?.(hook.name) ?? true) ? hooks[hook.name] : undefined\n if (!run) continue\n release()\n run({ gl, frame, viewProjection, outlineEffects })\n applyState()\n }\n }\n\n applyState()\n\n const { x, y, z } = frame.background\n\n gl.clearColor(x, y, z, 1)\n gl.clearDepth(1)\n clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)\n\n let previousAmbient = false\n let ownLights = false\n let uploaded: Float32Array | undefined\n const spent = new Set<VMeshData>()\n\n const drawOne = (draw: Draw) => {\n if (draw.transient) spent.add(draw.mesh)\n setDrawUniforms(gl, active, draw)\n\n const [nearDepth, farDepth] = draw.depthRange ?? WHOLE_DEPTH\n\n gl.depthRange(nearDepth!, farDepth!)\n\n if (draw.cull === 'none') gl.disable(gl.CULL_FACE)\n else {\n gl.enable(gl.CULL_FACE)\n gl.cullFace(draw.cull === 'back' ? gl.BACK : gl.FRONT)\n }\n\n gl.depthMask(draw.depthWrite)\n gl.depthFunc({ less: gl.LESS, lequal: gl.LEQUAL, always: gl.ALWAYS }[draw.depthFunc])\n\n if (draw.depthBias) {\n gl.enable(gl.POLYGON_OFFSET_FILL)\n gl.polygonOffset(0, -draw.depthBias)\n } else gl.disable(gl.POLYGON_OFFSET_FILL)\n\n // A draw's own ambient lasts only for that draw.\n if (previousAmbient && !draw.sceneAmbient) {\n const { x, y, z } = frame.ambient\n\n gl.uniform3f(active.uniforms.sceneAmbient, x, y, z)\n }\n\n previousAmbient = draw.sceneAmbient !== undefined\n\n // A draw's own lights last only for that draw, as its ambient does.\n if (draw.lightless) gl.uniform1i(active.uniforms.lightCount, 0)\n else if (draw.lights) setLights(gl, active.uniforms, draw.lights)\n else if (ownLights) setLights(gl, active.uniforms, frame.lights)\n else gl.uniform1i(active.uniforms.lightCount, frame.lights.length)\n\n if (draw.lights) ownLights = true\n else if (!draw.lightless) ownLights = false\n\n gl.uniformMatrix4fv(\n active.uniforms.projection,\n false,\n Matrix4.toArray(draw.projection ? Matrix4.multiply(shift, draw.projection) : projection),\n )\n\n if (draw.blend) {\n gl.enable(gl.BLEND)\n\n const [source, destination] = {\n alpha: [gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA],\n add: [gl.ONE, gl.ONE],\n alphaAdd: [gl.SRC_ALPHA, gl.ONE],\n multiply: [gl.DST_COLOR, gl.ZERO],\n screen: [gl.ONE, gl.ONE_MINUS_SRC_COLOR],\n premultiplied: [gl.ONE, gl.ONE_MINUS_SRC_ALPHA],\n }[draw.blendMode]\n\n gl.blendFuncSeparate(source!, destination!, gl.ZERO, gl.ONE)\n } else gl.disable(gl.BLEND)\n\n gl.activeTexture(gl.TEXTURE0 + DIFFUSE_UNIT)\n gl.bindTexture(gl.TEXTURE_2D, draw.texture ? textureOf(draw.texture.entry) : null)\n gl.bindSampler(DIFFUSE_UNIT, samplerOf(draw.texture?.sampler ?? DEFAULT_SAMPLER))\n\n gl.activeTexture(gl.TEXTURE0 + ENVIRONMENT_UNIT)\n gl.bindTexture(\n gl.TEXTURE_CUBE_MAP,\n draw.environmentTexture ? textureOf(draw.environmentTexture) : null,\n )\n gl.bindSampler(ENVIRONMENT_UNIT, samplerOf(DEFAULT_SAMPLER))\n\n const second = draw.second?.texture\n\n gl.activeTexture(gl.TEXTURE0 + SECOND_UNIT)\n gl.bindTexture(gl.TEXTURE_2D, second ? textureOf(second.entry) : null)\n gl.bindSampler(SECOND_UNIT, samplerOf(second?.sampler ?? DEFAULT_SAMPLER))\n\n if (draw.skin && draw.skin.bones !== uploaded) {\n gl.bindBuffer(gl.UNIFORM_BUFFER, active.boneBuffer)\n gl.bufferSubData(gl.UNIFORM_BUFFER, 0, draw.skin.bones)\n gl.bindBuffer(gl.UNIFORM_BUFFER, null)\n uploaded = draw.skin.bones\n }\n\n gl.bindVertexArray(arrayOf(draw.mesh, draw.reference, draw.skin?.influences))\n gl.drawElements(drawMode(draw.mesh.primitive), draw.count, gl.UNSIGNED_SHORT, draw.byteOffset)\n }\n\n frame.draws.forEach((draw, at) => {\n runHooks(at)\n drawOne(draw)\n })\n // Nothing after the draws takes a bias.\n gl.disable(gl.POLYGON_OFFSET_FILL)\n\n runHooks(frame.draws.length, (name) => name !== 'end')\n\n if (frame.effects.length) {\n effects ??= createEffectRenderer(gl)\n effects.draw(frame.effects, {\n gl,\n view: frame.view,\n projection,\n fog: frame.effectFog,\n depthFunc: frame.effectDepthFunc,\n bindTexture: ({ texture }) => {\n gl.activeTexture(gl.TEXTURE0 + DIFFUSE_UNIT)\n gl.bindTexture(gl.TEXTURE_2D, texture ? textureOf(texture.entry) : null)\n // Alchemy's begin-draw clamps (`src/alchemy/alchemy_alchemy.cpp`), and `effect_sprites` shows it.\n gl.bindSampler(DIFFUSE_UNIT, samplerOf(EFFECT_SAMPLER))\n return texture !== undefined\n },\n })\n applyState()\n }\n\n if (frame.tractors?.length || frame.beams) {\n // The effects' renderer has had the program, so only `applyState` knows what's bound.\n applyState()\n previousAmbient = false\n ownLights = false\n frame.tractors?.forEach(drawOne)\n if (frame.beams) drawOne(frame.beams)\n applyState()\n }\n\n if (frame.screenQuads?.length) {\n quads ??= createScreenQuadRenderer(gl)\n quads.draw(\n frame.screenQuads,\n { width, height },\n ({ texture }) => {\n gl.activeTexture(gl.TEXTURE0 + DIFFUSE_UNIT)\n gl.bindTexture(gl.TEXTURE_2D, textureOf(texture))\n // `ScreenQuadFlush` clamps stage 0 (`space_order`'s draw 130, `ADDRESSU` 3).\n gl.bindSampler(DIFFUSE_UNIT, samplerOf(EFFECT_SAMPLER))\n },\n frame.effectFog,\n )\n applyState()\n }\n\n // `applyState` has put the frame's ambient and lights back.\n previousAmbient = false\n ownLights = false\n\n if (frame.clearDepth) {\n // A hook or the host's own may have left a mask, as `gl.clear` obeys it.\n gl.depthMask(true)\n clear(gl.DEPTH_BUFFER_BIT)\n }\n\n frame.afterEffects?.forEach(drawOne)\n gl.depthRange(0, 1)\n runHooks(frame.draws.length, (name) => name === 'end')\n effects?.prune()\n\n if (frame.atEnd?.length) {\n applyState()\n previousAmbient = false\n ownLights = false\n frame.atEnd.forEach(drawOne)\n gl.depthRange(0, 1)\n }\n\n release()\n\n for (const mesh of spent) {\n const resources = meshes.get(mesh)\n if (resources) freeMesh(resources)\n meshes.delete(mesh)\n }\n\n return true\n }\n\n const invalidate = (asset: VMeshData | Texture | CubeTexture) => {\n if ('vertices' in asset) {\n const resources = meshes.get(asset)\n if (resources) freeMesh(resources)\n meshes.delete(asset)\n return\n }\n\n const texture = textures.get(asset)\n if (texture) gl.deleteTexture(texture)\n textures.delete(asset)\n }\n\n const dispose = () => {\n if (disposed) return\n disposed = true\n gl.canvas.removeEventListener('webglcontextlost', onLost)\n gl.canvas.removeEventListener('webglcontextrestored', onRestored)\n\n if (!gl.isContextLost()) {\n for (const resources of meshes.values()) freeMesh(resources)\n for (const texture of textures.values()) gl.deleteTexture(texture)\n for (const sampler of samplers.values()) gl.deleteSampler(sampler)\n effects?.dispose()\n quads?.dispose()\n\n if (program) {\n gl.deleteProgram(program.handle)\n gl.deleteBuffer(program.boneBuffer)\n }\n }\n\n forget()\n }\n\n return { render, invalidate, dispose }\n}\n","/** Which class a material is shaded as: `[MaterialMap]` in `EXE/dacom.ini`, then what is registered. */\nimport type { Material } from '@treewyrm/freelancer/material'\n\nexport interface MaterialMapRule {\n on: 'name' | 'type'\n pattern: RegExp\n to: string\n}\n\nconst type = (pattern: RegExp, to: string): MaterialMapRule => ({ on: 'type', pattern, to })\nconst name = (pattern: RegExp, to: string): MaterialMapRule => ({ on: 'name', pattern, to })\n\n/**\n * Retail's section, in file order. `shading.dll` matches with Spencer's regular expressions, which\n * search rather than anchor (`0x6ed0540`), and these patterns mean the same in JavaScript. So a type\n * rule's plain text matches anywhere in the type. A host with a mod's `dacom.ini` passes its own rules\n * as `SceneModel.materialMap`: JavaScript's patterns are a superset, and how a mod's unusual pattern\n * differs under Spencer's engine is unmeasured.\n */\nexport const MATERIAL_MAP: readonly MaterialMapRule[] = [\n type(/EcEtOcOt/, 'DcDtOcOt'),\n type(/DcDtEcEt/, 'DcDtEt'),\n name(/^alpha_mask.*/, 'DcDt'),\n name(/^alpha_mask.*2side/, 'DcDtTwo'),\n name(/^detailmap_.*/, 'BtDetailMapMaterial'),\n name(/^tlr_material$/, 'NebulaTwo'),\n name(/^tlr_energy$/, 'NebulaTwo'),\n name(/^nomad.*$/, 'NomadMaterialNoBendy'),\n name(/^n-texture.*$/, 'NomadMaterialNoBendy'),\n name(/^ui_.*/, 'HUDIconMaterial'),\n name(/^exclusion_.*/, 'ExclusionZoneMaterial'),\n name(/^c_glass$/, 'HighGlassMaterial'),\n name(/^cv_glass$/, 'HighGlassMaterial'),\n name(/^b_glass$/, 'HighGlassMaterial'),\n name(/^k_glass$/, 'HighGlassMaterial'),\n name(/^l_glass$/, 'HighGlassMaterial'),\n name(/^r_glass$/, 'HighGlassMaterial'),\n name(/^planet.*_glass$/, 'GFGlassMaterial'),\n name(/^bw_glass$/, 'HighGlassMaterial'),\n name(/^o_glass$/, 'HighGlassMaterial'),\n name(/^anim_hud.*$/, 'HUDAnimMaterial'),\n name(/^sea_anim.*$/, 'PlanetWaterMaterial'),\n name(/^null$/, 'NullMaterial'),\n]\n\n// `deformable2.dll` adds this itself, in no `dacom.ini` (`BindEyeMaterials`, `0x65fdfbb`). So it reaches\n// rigid models too, 14 retail materials of them. That it outranks the file's is read as it being added\n// later, and nothing retail tells the two apart. As a pattern it means `ey`, then any number of `e`.\nconst EYE_RULE = /^eye*/\n\n// `FMaterialLibrary::CreateAfterMap` (`0x6ec9aa0`) copies both into 64 bytes.\nconst FIELD_LENGTH = 63\n\n/**\n * The type a material is created as. Each rule is added at the front, so the last listed wins\n * (`FMaterialLibrary::AddMapRule`, `RemapType`). Only the name is lowercased (`_strlwr`, `0x6ec9afa`).\n */\nexport const mapMaterialType = (\n { name, type }: Pick<Material, 'name' | 'type'>,\n rules: readonly MaterialMapRule[] = MATERIAL_MAP,\n): string => {\n const lowered = name.slice(0, FIELD_LENGTH).toLowerCase()\n const original = type.slice(0, FIELD_LENGTH)\n\n if (EYE_RULE.test(lowered)) return 'EyeMaterial'\n\n for (let at = rules.length - 1; at >= 0; at--) {\n const rule = rules[at]!\n if (rule.pattern.test(rule.on === 'name' ? lowered : original)) return rule.to\n }\n\n return original\n}\n\n/** The factories of `shading.dll` (`src/Shading/Shading.cpp`), `flmaterials.dll` and `deformable2.dll`. Case matters. */\nexport const REGISTERED_TYPES: ReadonlySet<string> = new Set([\n 'DcDt',\n 'DcDtEc',\n 'DcDtOcOt',\n 'DcDtEcOcOt',\n 'DcDtTwo',\n 'DcDtEcTwo',\n 'DcDtOcOtTwo',\n 'DcDtEcOcOtTwo',\n 'DcDtEt',\n 'EcEt',\n 'EcEtTwo',\n 'AtmosphereMaterial',\n 'Nebula',\n 'NebulaTwo',\n 'NullMaterial',\n 'LightMap',\n 'DetailMapMaterial',\n 'DetailMap2Dm1Msk2PassMaterial',\n 'IllumDetailMapMaterial',\n 'Masked2DetailMapMaterial',\n 'BtDetailMapMaterial',\n 'BtDetailMapTwoMaterial',\n 'NomadMaterial',\n 'NomadMaterialNoBendy',\n 'HUDIconMaterial',\n 'HUDAnimMaterial',\n 'ColorizeMaterial',\n 'CloakMaterial',\n 'WireMaterial',\n 'WireMaterial2',\n 'ExclusionZoneMaterial',\n 'GlassMaterial',\n 'HighGlassMaterial',\n 'GFGlassMaterial',\n 'EnvMapMaterial',\n 'BackdropMaterial',\n 'StarsphereMaterial',\n 'ShadowMaterial',\n 'EngineGlowMaterial',\n 'VisibleCounterMaterial',\n 'PlanetWaterMaterial',\n 'EyeMaterial',\n])\n","/** A camera as the game holds one, to GL matrices. */\nimport { Matrix3, Matrix4, Vector3 } from '@treewyrm/freelancer/math'\n\nexport interface Camera {\n position: Vector3\n /** Rows, as `./thn/scene` reads a THN `orient`. Looks down local -Z, with +Y up (`0x5568b0`). */\n orientation: Matrix3\n /** Half the horizontal field of view, in degrees (`RoomCameraSetHalfFovX`). */\n fovh: number\n near: number\n far: number\n}\n\n/** `Mᵀ(p - position)`, the game's own right-handed view space (`0x40ff50`). */\nexport const viewMatrix = ({ position, orientation }: Camera): Matrix4 =>\n Matrix4.invert(Matrix4.fromRotationTranslation(orientation, position))\n\n/** A viewport's size in pixels. */\nexport interface Viewport {\n width: number\n height: number\n}\n\nconst f = Math.fround\n\n/**\n * `FRoomCamera::ClassifySphere`'s rank 2 (`0x55687a`): `π (R / z)²` times its pixel scales, under one\n * pixel. `HalfWidth` is `(width - 1) / 2`, as `Rect_to_ViewRect`'s edges are inclusive, and its Y\n * tangent is X's over `width / height` (`RoomCameraConstruct`, `FUN_00556280`).\n */\nexport const underPixel = (\n z: number,\n radius: number,\n fovh: number,\n { width, height }: Viewport,\n): boolean => {\n // `0x556868`: a centre on the eye's plane isn't sized.\n if (!(Math.abs(z) >= 0.0001)) return false\n\n const tanX = f(Math.tan((fovh + fovh) * (Math.PI / 360)))\n const tanY = f(tanX / (width / height))\n const xScale = f(f((width - 1) * 0.5) / tanX)\n const yScale = f(-(f((height - 1) * 0.5) / tanY))\n const q = -(radius / z)\n\n return yScale * xScale * q * q * f(-Math.PI) < 1\n}\n\n/**\n * `ClassifySphere` (`FSpaceCamera`, `0x40ffe0`) for a sphere in view space: 1 is outside, 3 crosses a\n * plane, 4 is wholly inside. With a viewport, a room camera's (`FRoomCamera`, `0x556780`), whose\n * rank 2 is a sphere in view that covers under a pixel; no caller draws it.\n */\nexport function classifySphere(\n center: Vector3,\n radius: number,\n camera: Camera,\n aspect: number,\n): 1 | 3 | 4\n\nexport function classifySphere(\n center: Vector3,\n radius: number,\n camera: Camera,\n aspect: number,\n viewport?: Viewport,\n): 1 | 2 | 3 | 4\n\nexport function classifySphere(\n { x, y, z }: Vector3,\n radius: number,\n { fovh, near, far }: Camera,\n aspect: number,\n viewport?: Viewport,\n): 1 | 2 | 3 | 4 {\n const nearEdge = -z - radius\n const farEdge = radius - z\n if (farEdge < near || nearEdge > far) return 1\n\n // Signed distance to the side plane nearest the centre, positive outside (-Z is ahead, so z < 0\n // in view): past `radius` is outside, past -`radius` is wholly inside.\n const tanX = Math.tan((fovh * Math.PI) / 180)\n const tanY = tanX / aspect\n const distanceX = (Math.abs(x) + tanX * z) / Math.hypot(1, tanX)\n const distanceY = (Math.abs(y) + tanY * z) / Math.hypot(1, tanY)\n if (distanceX > radius || distanceY > radius) return 1\n if (viewport && underPixel(z, radius, fovh, viewport)) return 2\n return nearEdge < near || farEdge > far || distanceX > -radius || distanceY > -radius ? 3 : 4\n}\n\n/** Whether a sphere in view space can reach the frustum. */\nexport const sphereInFrustum = (\n center: Vector3,\n radius: number,\n camera: Camera,\n aspect: number,\n viewport?: Viewport,\n): boolean => classifySphere(center, radius, camera, aspect, viewport) >= 3\n\n/**\n * RP8 flips view Z and applies a left-handed D3D projection (`FDirectX8::SetPerspective`). For a GL\n * clip space that comes to this plain right-handed perspective: no axis is negated, and z / w maps\n * onto the same window depth as D3D's. `hvaspect` never reaches the screen, so aspect is the viewport's.\n */\nexport const projectionMatrix = ({ fovh, near, far }: Camera, aspect: number): Matrix4 =>\n // `fovh` is half the horizontal angle, in degrees.\n Matrix4.perspectiveRH(2 * Math.atan(Math.tan((fovh * Math.PI) / 180) / aspect), aspect, near, far)\n","/** A material's UV transform at a moment: `shading.dll`'s animation instance, as data. */\nimport type { MaterialAnim } from '@treewyrm/freelancer/rigid'\n\n/** `uv * scale + offset`, on stage 0 alone (`0x6ec7330`, `rp8.dll` \\`0x6d0fdd2\\`). */\nexport interface UvTransform {\n offset: [number, number]\n scale: [number, number]\n}\n\n/**\n * `FImaInstance::Tick` and `FillUvMatrix`: a segment's duration is its own length, and the walk moves\n * on only strictly past it, wrapping always, as nothing reads `MAFlags`. A segment starts at the last\n * one's key, or four zeros, and its velocities are rates. Stored scales are displacements from 1.\n */\nexport const sampleUvAnimation = ({ segments }: MaterialAnim, time: number): UvTransform => {\n const total = segments.reduce((sum, { duration }) => sum + duration, 0)\n if (!segments.length || !(total > 0)) return { offset: [0, 0], scale: [1, 1] }\n\n let elapsed = Math.max(0, time) % total\n // A clock landing exactly on the wrap has run one whole loop, and reads the last segment's end.\n if (elapsed === 0 && time > 0) elapsed = total\n\n let at = 0\n\n // Skips whole segments until `elapsed` is the time within the current one.\n while (at < segments.length - 1 && elapsed > segments[at]!.duration) {\n elapsed -= segments[at]!.duration\n at++\n }\n\n const { start, velocity } = segments[at]!\n\n return {\n offset: [\n start.uOffset + velocity.uOffset * elapsed,\n start.vOffset + velocity.vOffset * elapsed,\n ],\n scale: [\n 1 + start.uScale + velocity.uScale * elapsed,\n 1 + start.vScale + velocity.vScale * elapsed,\n ],\n }\n}\n","/** Which detail level a part draws: `rendcomp.dll`'s selector, and an archetype's INI over `Switch2`. */\nimport { Matrix4 } from '@treewyrm/freelancer/math'\nimport type { MeshSource } from '@treewyrm/freelancer/rigid'\nimport type { VMeshPart } from '@treewyrm/freelancer/vmesh'\nimport { viewMatrix, type Camera } from './camera.js'\n\n/** One level-of-detail list an archetype writes: its own `LODranges`, or a `[LOD]` block's. */\nexport interface LodList {\n /** The part a `[LOD]` block is for, by name. Absent on the section's own list. */\n obj?: string\n /** As written, at most eight. */\n ranges: readonly number[]\n /** `MinSpecLOD`: the levels low detail skips. 1 when absent, but 0 under three ranges. */\n minSpecLod?: number\n}\n\n/** The `level_of_detail` option, 0 to 1. At 0.75, the default here, it changes nothing. */\nexport interface LodDetail {\n detail?: number\n}\n\n// `Freelancer-original.exe` `0x5c7410`, about tan 35°, which an INI value is multiplied by as it is\n// written, and `0x5c7478`, past which the far clamp holds a range.\nconst RANGE_SCALE = 0.700208\nconst FAR_CUTOFF = 15000\n\n/** `ApplyLevelOfDetail` (`0x5b4560`): low detail below 0.75, and the scale the far clamp tests. */\nexport const lodScale = (detail: number): { low: boolean; scale: number } => {\n const low = detail < 0.75\n const scale = low ? detail * (4 / 3) * 0.5 + 0.5 : (detail - 0.75) * 4 + 1\n\n return { low, scale: Math.fround(scale) }\n}\n\n/**\n * `ApplyArchLodRanges` (`0x401ed0`) for one part with `count` levels: each level's end, in the INI's\n * unit, from the first list with no `obj` or with its name, and the largest range it walked. The\n * levels low detail skips end at 0; the walk stops at a negative range. Nothing when no list matches.\n */\nconst walkRanges = (\n count: number,\n name: string,\n lists: readonly LodList[],\n detail: number,\n): { ends: (number | undefined)[]; largest: number } | undefined => {\n if (count === 0) return undefined\n\n const folded = name.toLowerCase()\n const list = lists.find(({ obj }) => obj === undefined || obj.toLowerCase() === folded)\n if (!list) return undefined\n\n const { low, scale } = lodScale(detail)\n // Past what's written, the terminator: -1.\n const range = (at: number) => list.ranges[at] ?? -1\n const ends: (number | undefined)[] = Array.from({ length: count }, () => undefined)\n\n // The cap is the first list's, whichever matched.\n const head = lists[0]!\n const minSpec = head.minSpecLod ?? (head.ranges.length < 3 ? 0 : 1)\n const cap = low ? Math.min(minSpec, count) : 0\n let applied = 0\n\n for (; applied < cap; applied++) {\n if (range(applied + 1) < 0) break\n ends[applied] = 0\n }\n\n if (applied >= count) return { ends, largest: -1 }\n\n // At high detail a near list's far ranges are held at 15000, its level added.\n const farClamp = range(count) < FAR_CUTOFF && scale * range(count) > FAR_CUTOFF\n let largest = Math.max(-1, range(applied))\n\n for (let level = applied; level < count; level++) {\n let end = range(level + 1)\n if (!(end >= 0)) break\n if (farClamp && end * scale > FAR_CUTOFF) end = level + FAR_CUTOFF\n largest = Math.max(largest, Math.fround(end))\n ends[level] = Math.fround(RANGE_SCALE * end)\n }\n\n return { ends, largest }\n}\n\nconst levelCount = (source: MeshSource): number =>\n source.type === 'vmeshpart' ? 1 : (source.ranges ?? [0, NaN]).length - 1\n\n/**\n * The archetype's `LodPick` (`ComputeLodPickThis`, `0x4021b0`): the largest range any part's list\n * walked, past which the object draws nothing. -1 when none did. A single model's part is `Root`.\n */\nexport const lodRange = (\n parts: readonly { source: MeshSource; name: string }[],\n lists: readonly LodList[],\n { detail = 0.75 }: LodDetail = {},\n): number => {\n let largest = -1\n\n for (const { source, name } of parts) {\n const walked = walkRanges(levelCount(source), name, lists, detail)\n if (walked) largest = Math.max(largest, walked.largest)\n }\n\n return largest\n}\n\n// A bare `VMeshPart` is one level (`0x6c33fe0`).\nconst BARE = [0, 1e6]\n\n/**\n * Each level's end, in `Switch2`'s unit. The first list with no `obj` or with this part's name\n * overwrites the model's own entry by entry, as far as it reaches and no further (`0x401ed0`), and a\n * negative value ends it. With no `Switch2` the game's floats are uninitialised: `NaN`, which no metric\n * reaches. `lists` are in matching order, `[LOD]` blocks first.\n */\nexport const levelEnds = (\n source: MeshSource,\n name: string,\n lists: readonly LodList[] = [],\n { detail = 0.75 }: LodDetail = {},\n): number[] => {\n const switches = source.type === 'vmeshpart' ? BARE : (source.ranges ?? [0, NaN])\n const ends = switches.slice(1)\n const walked = walkRanges(ends.length, name, lists, detail)\n\n return walked ? ends.map((end, at) => walked.ends[at] ?? end) : ends\n}\n\n/**\n * `LodSetPick` (`0x6c32040`): the first level whose end reaches the metric. Only ends are read, so a\n * level ending under the one before it is never chosen. Past the last, the part draws nothing.\n */\nexport const levelAt = (\n source: MeshSource,\n metric: number,\n ends: readonly number[],\n): VMeshPart | undefined => {\n const level = ends.findIndex((end) => end >= metric)\n if (level < 0) return undefined\n return source.type === 'vmeshpart' ? source : source.levels[level]\n}\n\nexport const largestAxis = ({ x, y, z }: Matrix4): number =>\n Math.max(Math.hypot(x.x, x.y, x.z), Math.hypot(y.x, y.y, y.z), Math.hypot(z.x, z.y, z.z)) || 1\n\n/**\n * `FRenderManager::RenderInstance`: view depth of the part's centre, not its distance, times\n * tan(fovx½), over the largest axis of the matrix given to the draw. So it widens with the view. The\n * centre being the top level's bounding sphere is inferred (`IEngine +0x88`). Threshold is 1 in a room\n * (`room_control.cpp`); space's isn't read yet.\n */\nexport const levelMetric = (\n source: MeshSource,\n part: Matrix4,\n transform: Matrix4,\n camera: Camera,\n): number => {\n const first = source.type === 'vmeshpart' ? source : source.levels[0]\n const centre = first?.reference.boundingSphere.center ?? { x: 0, y: 0, z: 0 }\n const { z } = Matrix4.transformPoint(centre, Matrix4.multiply(viewMatrix(camera), part))\n\n return (Math.abs(z) * Math.tan((camera.fovh * Math.PI) / 180)) / largestAxis(transform)\n}\n","/** A frame as data: what is drawn, in what order, in GL terms. Pure, no GL. */\nimport type { CompoundNode, JointState } from '@treewyrm/freelancer/compound'\nimport {\n getAddress,\n DEFAULT_NOMAD_TEXTURE_NAME,\n getMapIndex,\n TextureAddress,\n type Material,\n type TextureReference,\n} from '@treewyrm/freelancer/material'\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n getMaterialAnim,\n type MaterialAnimLibrary,\n type RigidModel,\n type RigidPart,\n} from '@treewyrm/freelancer/rigid'\nimport type { CubeTexture, Texture, TextureEntry } from '@treewyrm/freelancer/texture'\nimport {\n getMeshDraw,\n vertexByteLength,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { collectEffect, type EffectDraw } from '#/alchemy/draw.js'\nimport type { EffectInstance } from '#/alchemy/effect.js'\nimport type { EffectNode } from '#/alchemy/tree.js'\nimport { mapMaterialType, REGISTERED_TYPES, type MaterialMapRule } from '#/material/map.js'\nimport { frameAtlas, playbackFrame } from '#/texture/playback.js'\nimport { DEFAULT_SAMPLER, type SamplerState, type TextureWrap } from '#/texture/texture.js'\nimport {\n projectionMatrix,\n sphereInFrustum,\n viewMatrix,\n type Camera,\n type Viewport,\n} from './camera.js'\nimport { partTransforms } from './hierarchy.js'\nimport { sampleUvAnimation, type UvTransform } from './uv-animation.js'\nimport { largestAxis, levelAt, levelEnds, levelMetric, type LodList } from './level.js'\nimport type { ScreenQuad } from './flare.js'\nimport type { Fog } from './nebula.js'\n\nexport interface SceneLight {\n color: Vector3\n /** World space, the way the light shines. A point light's is unused. */\n direction: Vector3\n /** In world space, which makes it a point light: D3D8's, with no light past `range`. */\n position?: Vector3\n range?: number\n /** Constant, linear and quadratic, of the distance. */\n attenuation?: Vector3\n /** With a position, a spot along `direction`: D3D8's angles, inner and outer, in radians. */\n spot?: Spot\n /**\n * `D3DLIGHT8`'s `Ambient`, which D3D8 adds as the material's ambient times it, attenuated and in\n * the cone, whichever way the surface faces. A THN light's; a system's is black.\n */\n ambient?: Vector3\n}\n\n/** `D3DLIGHT8`'s `Theta`, `Phi` and `Falloff`: full angles in radians, no light outside `phi`. */\nexport interface Spot {\n theta: number\n phi: number\n falloff: number\n}\n\n/** What a skinned mesh adds: `skinMesh`'s influences and `boneTable`'s matrices, column-major. */\nexport interface DrawSkin {\n influences: Float32Array\n bones: Float32Array\n}\n\n/** One piece of geometry where the host has posed it, at the detail level it chose. */\nexport interface PlacedPart {\n reference: VMeshRef\n world: Matrix4\n /** A generated mesh, which no library holds: a sphere's patch. */\n mesh?: VMeshData\n /** Over each group's own, as a sphere's face names its material and its patch can't. */\n materialId?: number\n /** That material's name, as the file writes it, for a report: an id can't be read back. */\n materialName?: string\n skin?: DrawSkin\n /** Added to an `EyeMaterial` group's UVs, as its eye bone turns. */\n eyeOffset?: [number, number]\n /** What the engine tells a sphere's shell of its size. Anything else reads 1 (`Field20` unset). */\n extent?: number\n}\n\nexport interface SceneModel {\n parts: PlacedPart[]\n mesh: (id: number) => VMeshData | undefined\n material: (id: number) => Material | undefined\n texture: (name: string) => TextureEntry | undefined\n /** The archetype's `envmap_material`: the model does not say. Absent means no reflection. */\n environment?: string\n /** 0 to 1, the engine's per-object value that nomad surfaces and `cloaked` read. 1 when absent. */\n fade?: number\n /** Drawn through `CloakMaterial`, which the host decides: the game spares nomad archetypes. */\n cloaked?: boolean\n /** UV animations, found by material name as the game does. */\n materialAnimations?: MaterialAnimLibrary\n /** `[MaterialMap]` from the host's own `dacom.ini`, in file order. Retail's when absent. */\n materialMap?: readonly MaterialMapRule[]\n /**\n * Drawn through `StarsphereMaterial`: at the camera, turned with the view alone, under white ambient\n * and no lights. Or `BackdropMaterial`, where the camera stands, on planes of its own. Both ignore\n * depth. The host orders models, so a sky goes first.\n */\n sky?: 'starsphere' | 'backdrop'\n /**\n * The instance's user data, which HUD icons and exclusion zones read: over `Ac` and `Oc`. The engine\n * sets it, so without it they use the material's own.\n */\n instance?: { ambient: Vector3; alpha: number }\n}\n\nexport interface PlaceOptions {\n /** Choose each part's level as the game does, from this camera. Unless `level` pins one. */\n camera?: Camera\n /** The archetype's level-of-detail lists, in matching order, over the model's own `Switch2`. */\n lod?: readonly LodList[]\n /** The `level_of_detail` option, 0 to 1, which the lists answer to. 0.75 changes nothing. */\n detail?: number\n /** Pins a level, clamped to what a part has. The top one when there is no `camera` either. */\n level?: number\n /** A part left out draws nothing, and its children still do. */\n visible?: (part: CompoundNode<RigidPart>) => boolean\n jointState?: (part: CompoundNode<RigidPart>) => JointState | undefined\n}\n\n/** A running effect, advanced by the host, and where its textures come from. */\nexport interface SceneEffect {\n instance: EffectInstance\n texture: (name: string) => TextureEntry | undefined\n /** An appearance left out isn't drawn, and still runs: a way of looking. Every one when absent. */\n visible?: (node: EffectNode) => boolean\n}\n\nexport interface Scene {\n camera: Camera\n /** Width over height of the viewport. */\n aspect: number\n /** 0 to 1. */\n ambient: Vector3\n lights: SceneLight[]\n models: SceneModel[]\n /** 0 to 1. Black when absent, which is what the menu clears to. */\n background?: Vector3\n /**\n * Seconds, the host's clock, for material UV and texture animation. 0 when absent. Retail starts a\n * material's texture playback when it loads (`FMaterial::Setup`), so 0 is when the models loaded.\n */\n time?: number\n /** After the models, in the order given. `collectSpaceFrame` has the game's order. */\n effects?: readonly SceneEffect[]\n /** Over `RETAIL_FRAME_LIMITS`, for a mod that patches them. */\n limits?: Partial<FrameLimits>\n}\n\n/** What the material and appearance DLLs hardcode, and a mod can patch. */\nexport interface FrameLimits {\n /** The least alpha glass draws at, whatever its `Oc` (`FMaterialImpl::BindGlass`). */\n glassLeastAlpha: number\n /** A backdrop's own near and far planes (`FFLAppearanceBase::DrawBackdrop`, `BindArg`'s first flag). */\n backdropNear: number\n backdropFar: number\n}\n\nexport const RETAIL_FRAME_LIMITS: Readonly<FrameLimits> = {\n glassLeastAlpha: 0.8,\n backdropNear: 1,\n backdropFar: 200000,\n}\n\nexport interface DrawTexture {\n name: string\n entry: Texture | CubeTexture\n sampler: SamplerState\n /** Which of the mesh's UV sets it samples. */\n uvSet: number\n}\n\n/**\n * Texture stage 1, in the classes that use it. With no texture the rig's picture is as if the stage were\n * off (`bands`), so that's what draws, though a real D3D8 driver may read it as white: see VALIDATION.md.\n */\nexport interface DrawStage {\n operation: 'add' | 'modulate2x'\n texture?: DrawTexture\n /** A planet mask's `diag(tile, tile)` texture matrix, on UV0 (`SetDetailTileTransform`). */\n tile?: number\n}\n\n/** What `SubmitAtmosphereLock` needs for each vertex's UV, the rest being the same for a draw. */\nexport interface DrawAtmosphere {\n /** Towards the camera, in the object's space. */\n direction: Vector3\n /** The cosine of the horizon, where `u` starts. */\n threshold: number\n /** `u` where the vertex faces the camera. */\n gain: number\n /** The row of the fade texture, the whole draw's. */\n v: number\n}\n\n/**\n * Source and destination: `SRCALPHA / INVSRCALPHA`, `ONE / ONE`, `SRCALPHA / ONE`, `DESTCOLOR / ZERO`,\n * `ONE / INVSRCCOLOR`, `ONE / INVSRCALPHA`.\n */\nexport type BlendMode = 'alpha' | 'add' | 'alphaAdd' | 'multiply' | 'screen' | 'premultiplied'\n\nexport interface Draw {\n mesh: VMeshData\n reference: VMeshRef\n /** The mesh was built for this frame alone: the renderer frees it once the frame's drawn. */\n transient?: boolean\n /** Into the reference's planned index buffer. */\n byteOffset: number\n count: number\n world: Matrix4\n\n materialName: string\n diffuse: [number, number, number, number]\n ambient: Vector3\n emissive: Vector3\n /** The mesh has vertex colours, which take the place of `diffuse`. */\n colorVertex: boolean\n /** Unlit white at `diffuse`'s alpha, and stage 1 reads the nomad ramp. */\n nomad: boolean\n texture?: DrawTexture\n /** A cube, reflected in camera space, as `2 × cube × colour`. */\n environment?: string\n environmentTexture?: CubeTexture\n second?: DrawStage\n uvTransform?: UvTransform\n\n cull: 'back' | 'front' | 'none'\n depthWrite: boolean\n /** `D3DCMP_LESS` for most. `always` is `ZENABLE 0`, a sky's or the far list's: the same pixels. */\n depthFunc: 'less' | 'lequal' | 'always'\n /** Scene ambient in place of the frame's, for this draw. */\n sceneAmbient?: Vector3\n /** The frame's lights don't reach it. */\n lightless?: boolean\n /** In place of the frame's, for this draw: space lights each object by its own. */\n lights?: SceneLight[]\n /** In place of the frame's, for this draw. */\n projection?: Matrix4\n /** `D3DVIEWPORT8`'s `MinZ` and `MaxZ`, for this draw: `[0, 1]` when absent. */\n depthRange?: readonly [number, number]\n /**\n * D3D8's `ZBIAS`, 0 to 16, pulling it toward the camera: a room's shadow's 4. How far a level\n * moves depth is the driver's; here one level is one unit of `polygonOffset`: uncaptured.\n */\n depthBias?: number\n /** D3D's table fog, on depth: a nebula's, for what it holds (`StarSysApplyObjectLighting`). */\n fog?: Fog\n negateNormals: boolean\n normalizeNormals: boolean\n blend: boolean\n /** `alpha` unless a class sets its own (`bands`). */\n blendMode: BlendMode\n /** Lighting off: white, or the vertex colour, at `diffuse`'s alpha. */\n unlit: boolean\n /** Compared with this, of 255: `D3DRS_ALPHAFUNC`, or `always` with the test off. */\n alphaReference: number\n alphaFunction: 'greater' | 'less' | 'always'\n atmosphere?: DrawAtmosphere\n skin?: DrawSkin\n}\n\n/**\n * Where a host's own drawing goes. `begin` is after the clear, `opaque` before the first blended draw,\n * and `end` after everything. None of them changes the game's order.\n */\nexport type HookName = 'begin' | 'opaque' | 'end'\n\nexport interface FrameHook {\n name: HookName\n /** Index of the draw it goes in front of, so the length of `draws` is after the last. */\n before: number\n}\n\nexport interface ScreenQuadBatch {\n texture: Texture\n quads: ScreenQuad[]\n}\n\nexport interface Frame {\n background: Vector3\n hooks: FrameHook[]\n view: Matrix4\n projection: Matrix4\n ambient: Vector3\n lights: SceneLight[]\n draws: Draw[]\n /** Each appearance of each effect, after `draws`, in the game's tree order. */\n effects: EffectDraw[]\n /** Over every effect, as `SpaceObjDrawPass` sets it in a nebula. */\n effectFog?: Fog\n /** `less` when absent, as the menu's effects capture it; space's are `lequal`. */\n effectDepthFunc?: 'less' | 'lequal'\n /** Each tractor's lines, after the effects, in the walk's own bucket (`EFT_TRACTORBEAM`). */\n tractors?: Draw[]\n /** Every shot of the frame, once the effects are walked (`EffectVertexBatchFlush`). */\n beams?: Draw\n /**\n * Screen quads, after the effects, in D3D's pixels: added, the texture times each quad's colour,\n * `lequal` without writing depth (`ScreenQuadFlush` in `SpaceEffectsDrawFrame`), under\n * `effectFog` by `1 / rhw`. Each batch is one texture's.\n */\n screenQuads?: ScreenQuadBatch[]\n /**\n * Clear depth before `afterEffects`: from the cockpit, with the HUD on or the cockpit showing\n * (`FirstPersonCameraSceneDraw`, `0x518463`). None of what's already drawn can then hide what's next.\n */\n clearDepth?: boolean\n /**\n * Drawn after the screen quads, before the `end` hook: a sun's corona, which the game draws once\n * its effects are done (`ScaleEnvironmentEffects`, `0x51c7d4`), and from the cockpit, its mesh.\n */\n afterEffects?: Draw[]\n /**\n * After the `end` hook: what the cockpit's mesh queued with the effects option off, which the\n * game's batcher draws only as the scene ends, past the HUD and every sun's flare (`EndSceneHalf`).\n */\n atEnd?: Draw[]\n /** What didn't draw as authored: materials M3 is to cover, and any mesh or texture not found. */\n unsupported: string[]\n /** Materials of a type no DLL registers. They draw nothing in retail either. */\n unregistered: string[]\n}\n\ntype MaterialClass =\n | 'single'\n | 'singleTwo'\n | 'glass'\n | 'emission'\n | 'detail'\n | 'detailTwo'\n | 'nomad'\n | 'hudIcon'\n | 'hudAnim'\n | 'exclusion'\n | 'water'\n | 'emissive'\n | 'lightMap'\n | 'glow'\n | 'nebula'\n | 'detailMap'\n | 'masked'\n | 'illum'\n | 'atmosphere'\n\n// What M3 has built so far. Other registered types are reported, not drawn. The eight single-pass\n// names share one bind and submit (`kMaterialTypes`, `src/Shading/Material.cpp`), and `Ec` and `OcOt`\n// are properties: the latter only batches.\nconst CLASSES: Readonly<Record<string, MaterialClass>> = {\n DcDt: 'single',\n DcDtEc: 'single',\n DcDtOcOt: 'single',\n DcDtEcOcOt: 'single',\n DcDtTwo: 'singleTwo',\n DcDtEcTwo: 'singleTwo',\n DcDtOcOtTwo: 'singleTwo',\n DcDtEcOcOtTwo: 'singleTwo',\n DcDtEt: 'emission',\n BtDetailMapMaterial: 'detail',\n BtDetailMapTwoMaterial: 'detailTwo',\n EcEt: 'emissive',\n EcEtTwo: 'emissive',\n LightMap: 'lightMap',\n EngineGlowMaterial: 'glow',\n Nebula: 'nebula',\n NebulaTwo: 'nebula',\n HUDIconMaterial: 'hudIcon',\n HUDAnimMaterial: 'hudAnim',\n ExclusionZoneMaterial: 'exclusion',\n PlanetWaterMaterial: 'water',\n // One class for the two names: the clock that sets them apart is read by nothing (`0x66f88bd`).\n NomadMaterial: 'nomad',\n NomadMaterialNoBendy: 'nomad',\n // One class for the three names (`flmaterials.dll`).\n HighGlassMaterial: 'glass',\n GlassMaterial: 'glass',\n GFGlassMaterial: 'glass',\n // `FEyeMaterial::Bind` and `UpdateTranslucency` come to the same states, leaving stage 1 off. Its other\n // part, the eye bone's offset, is written where a 2D coordinate never reads it: see VALIDATION.md.\n EyeMaterial: 'single',\n DetailMapMaterial: 'detailMap',\n // Only which masks they read sets these two apart.\n DetailMap2Dm1Msk2PassMaterial: 'masked',\n Masked2DetailMapMaterial: 'masked',\n IllumDetailMapMaterial: 'illum',\n AtmosphereMaterial: 'atmosphere',\n}\n\n/** Whether `collectFrame` draws this type, the one `[MaterialMap]` gives. */\nexport const isBuiltType = (type: string): boolean => type in CLASSES\n\nconst wrapOf = (address: TextureAddress): TextureWrap => {\n if (address === TextureAddress.Wrap) return 'repeat'\n if (address === TextureAddress.Mirror) return 'mirror'\n if (address === TextureAddress.Clamp) return 'clamp'\n throw new RangeError('WebGL2 has no border address mode, and retail uses none')\n}\n\nconst drawTexture = ({ flags }: TextureReference, { name, entry }: Bound): DrawTexture => ({\n name,\n entry,\n sampler: {\n ...DEFAULT_SAMPLER,\n wrapU: wrapOf(getAddress(flags, 'u')),\n wrapV: wrapOf(getAddress(flags, 'v')),\n },\n // Kept even for a set the mesh hasn't got, as 52 retail draws ask: that reads (0, 0) (`bands_one_uv`).\n uvSet: getMapIndex(flags),\n})\n\n/**\n * One alpha bit is cut, more is blended (`FMaterial` after `PixelFormatAlphaBits`). An animated\n * texture neither: `Setup` reads the format from a handle it resolves only for a single frame.\n */\nconst alphaBits = (entry: TextureEntry | undefined): number => {\n if (!entry || entry.type === 'animated') return 0\n\n switch (entry.format) {\n case 'dxt1':\n case 'rgba16_5551':\n return 1\n // `A4R4G4B4`'s row of the format table (`shading!0x6ed5230`).\n case 'rgba16_4444':\n return 4\n case 'dxt3':\n case 'dxt5':\n case 'rgba32_8888':\n return 8\n default:\n return 0\n }\n}\n\n// `[RenderPipeline]`'s device-wide reference, and the one `FMaterial::SubmitAlphaTest` sets.\nconst DEVICE_ALPHA_REFERENCE = 0\nconst CUT_ALPHA_REFERENCE = 0x80\n\nconst WHITE: Vector3 = { x: 1, y: 1, z: 1 }\n\n// These declare no `Dc`, so the material block stays white (`bands`).\nconst FIXED_COLOUR: ReadonlySet<MaterialClass> = new Set(['emissive', 'lightMap', 'nebula'])\n\n// `bands`: what a `EngineGlowMaterial` with no `Ec` draws with. Whether `Ec` can replace it is read.\nconst ENGINE_GLOW: Vector3 = { x: 0.75, y: 0.7, z: 0.7 }\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\ntype Pass = Pick<\n Draw,\n 'cull' | 'negateNormals' | 'normalizeNormals' | 'blend' | 'alphaReference' | 'environment'\n> & {\n alpha?: number\n depthWrite?: boolean\n depthFunc?: 'less' | 'lequal'\n blendMode?: BlendMode\n alphaFunction?: Draw['alphaFunction']\n unlit?: boolean\n /** Stage 1, for the classes whose passes differ in it. `null` turns it off. */\n mask?: { slot: TextureReference | undefined; tile: number } | null\n}\n\nconst NO_ENVIRONMENT: Pick<Pass, 'normalizeNormals'> = { normalizeNormals: false }\n\n// `BindEnvMap` also turns these on for the draw it adds a stage to.\nconst withEnvironment = (\n name: string | undefined,\n): Pick<Pass, 'normalizeNormals' | 'environment'> =>\n name ? { normalizeNormals: true, environment: name } : NO_ENVIRONMENT\n\n/**\n * `[BatchedMaterials] Type = .*OcOt`. A batched material takes bin 1 if it blends and bin 0 if not\n * (`0x6eb4133`). Bin 1 waits for the flush, past the end of the environment override, so it has neither\n * its stage nor its normalized normals (`ku_dragon`). Bin 0 submits at once (`0x6ec9589`) and binds\n * again over the stage. No environment-mapped ship has that, so it stands as read, and uncaptured.\n */\nconst BATCHED = /.*OcOt/\n\n/**\n * `BindCloak` binds the material as usual, so its texture stays, then sets alpha to the object's value\n * times the material's, and a blend table on that alpha alone. Below 1 there's no cut either\n * (`Flag64_`, `0x400`). A cloaked object passes this in place of `EnvMapMaterial`, so nothing reflects\n * (`0x539a87`). A batched material binds again at submit, undoing the alpha, so it only loses the\n * reflection. Read from `flmaterials.dll`, uncaptured: only flight has a cloak.\n */\nconst cloak = (\n pass: Pass,\n kind: MaterialClass,\n type: string,\n material: Material,\n fade: number,\n): Pass => {\n const plain: Pass = { ...pass, normalizeNormals: false }\n\n delete plain.environment\n if (BATCHED.test(type)) return plain\n\n const alpha = (pass.alpha ?? material.opacity ?? 1) * fade\n // Glass sets its own blend for each pass as it draws.\n if (kind === 'glass') return { ...plain, alpha }\n return alpha < 1\n ? { ...plain, alpha, blend: true, alphaReference: DEVICE_ALPHA_REFERENCE }\n : { ...plain, alpha, blend: false }\n}\n\n// Truncated to the byte `SubmitNomadGeometry` writes, after the smoothstep of `NomadFadeFromValue`.\nconst nomadAlpha = (fade: number): number => {\n const delta = Math.min(Math.max(1 - fade, 0), 1)\n\n return Math.trunc((1 - (3 - 2 * delta) * delta * delta) * 255) / 255\n}\n\n// `TileRate`'s default in each planet class's property schema.\nconst DEFAULT_TILE = 4\n\n// `Scale`'s default in the atmosphere's property schema.\nexport const DEFAULT_SHELL_SCALE = 1.025\n\n/**\n * The planet surfaces (`src/Shading/Material.cpp`, `FMaterial::Submit`), whose state `bands_planet`\n * captured. Pass A is opaque, with its stage 1 on UV0 through a tile matrix, and B blends over it. An\n * environment map turns on normalized normals on the two-pass classes, and has no stage free. These\n * assume `[PerfOptions]`' multipass record on, as a retail install has it.\n */\nconst planetPasses = (\n kind: 'detailMap' | 'masked' | 'illum',\n type: string,\n material: Material,\n model: SceneModel,\n): Pass[] => {\n const shared = {\n cull: 'back' as const,\n negateNormals: false,\n alpha: 1,\n normalizeNormals: model.environment !== undefined,\n }\n\n if (kind === 'detailMap')\n return [\n {\n ...shared,\n normalizeNormals: false,\n blend: false,\n alphaReference: DEVICE_ALPHA_REFERENCE,\n mask: { slot: material.maskTexture, tile: material.tileRate ?? DEFAULT_TILE },\n },\n ]\n\n // `DetailMap2Dm1Msk2PassMaterial` reads `Dm1` and `TileRate` for A, and B leaves stage 1 off.\n const single = type === 'DetailMap2Dm1Msk2PassMaterial'\n const first = single\n ? { slot: material.maskTexture1, tile: material.tileRate ?? DEFAULT_TILE }\n : { slot: material.maskTexture0, tile: material.tileRate0 ?? DEFAULT_TILE }\n const second = single\n ? null\n : { slot: material.maskTexture1, tile: material.tileRate1 ?? DEFAULT_TILE }\n const over = {\n ...shared,\n blend: true,\n alphaReference: 1,\n depthFunc: 'lequal',\n mask: second,\n } as const\n\n if (kind === 'illum')\n return [\n // The test off, so a texel at zero alpha still draws, and B unlit: the night side's lights.\n {\n ...shared,\n blend: false,\n alphaReference: DEVICE_ALPHA_REFERENCE,\n alphaFunction: 'always',\n mask: first,\n },\n { ...over, depthWrite: false, unlit: true },\n ]\n\n return [\n { ...shared, blend: false, alphaReference: 0xfe, alphaFunction: 'less', mask: first },\n over,\n ]\n}\n\nconst passesOf = (\n kind: MaterialClass,\n type: string,\n material: Material,\n model: SceneModel,\n { glassLeastAlpha }: FrameLimits,\n): Pass[] => {\n if (kind === 'detailMap' || kind === 'masked' || kind === 'illum')\n return planetPasses(kind, type, material, model)\n\n // `GAtmosphereRs`, and `SubmitAtmosphereLock`'s depth. Stage 1 stays free for a reflection (`bands_planet`).\n if (kind === 'atmosphere')\n return [\n {\n cull: 'back',\n negateNormals: false,\n blend: true,\n alphaReference: DEVICE_ALPHA_REFERENCE,\n alpha: 1,\n depthWrite: false,\n depthFunc: 'lequal',\n ...withEnvironment(model.environment),\n },\n ]\n\n // The fixed classes, whose tables `bands` captured. Each leaves stage 1 free. Two names draw twice.\n if (kind === 'emissive' || kind === 'lightMap' || kind === 'glow' || kind === 'nebula') {\n const front: Pass = {\n cull: 'back',\n negateNormals: false,\n blend: kind !== 'glow',\n alphaReference: DEVICE_ALPHA_REFERENCE,\n alpha: 1,\n ...(kind === 'emissive' ? { blendMode: 'add' as const } : {}),\n ...(kind === 'nebula' ? { blendMode: 'alphaAdd' as const } : {}),\n // `Submit`'s temporary `ZFUNC` 4.\n ...(kind === 'lightMap'\n ? { blendMode: 'multiply' as const, depthFunc: 'lequal' as const }\n : {}),\n ...withEnvironment(model.environment),\n }\n\n return type.endsWith('Two')\n ? [front, { ...front, cull: 'front', negateNormals: true }]\n : [front]\n }\n\n if (kind === 'hudIcon' || kind === 'hudAnim' || kind === 'exclusion' || kind === 'water') {\n const entry = material.diffuseTexture && model.texture(material.diffuseTexture.name)\n // `+0x64`, set at load: its own `Oc` below 1, or a `Dt` format with more than one alpha bit.\n const translucent = (material.opacity ?? 1) < 1 || alphaBits(entry) > 1\n // HUDIcon and ExclusionZone write the engine's alpha over `Oc` (`flmaterials!0x66f80f8`).\n const override = kind === 'hudIcon' || kind === 'exclusion' ? model.instance?.alpha : undefined\n const alpha = override ?? material.opacity\n\n return [\n {\n // None sets an alpha test, and all leave stage 1 free for a reflection. `kExclusionRs` always\n // blends; HUDIcon when the override is below 1 or `+0x64` is set (`0x66f8133`), so its own\n // translucency holds whatever the override says; the others by `+0x64` alone.\n cull: 'back',\n negateNormals: false,\n blend: kind === 'exclusion' || translucent || (override ?? 1) < 1,\n alphaReference: DEVICE_ALPHA_REFERENCE,\n ...(alpha === undefined ? {} : { alpha }),\n // `SubmitPlanetWaterGeometry`.\n ...(kind === 'water' ? { depthWrite: false, depthFunc: 'lequal' as const } : {}),\n ...withEnvironment(model.environment),\n },\n ]\n }\n\n if (kind === 'nomad')\n return [\n {\n // `kNomadRs`, then `SubmitNomadGeometry`. Stage 1 is taken, so no reflection.\n cull: 'none',\n depthWrite: false,\n negateNormals: false,\n blend: true,\n alphaReference: DEVICE_ALPHA_REFERENCE,\n // The object's value is one slot, and an environment override keeps a pointer to its cube's\n // name there (`SetAppearanceInstanceValue`). Read as a float it's near 0, and so is the fade:\n // retail's surface is invisible on an environment-mapped object (`bands`). A cloaked object\n // doesn't pass that override, so keeps its fade.\n alpha: model.environment && !model.cloaked ? 0 : nomadAlpha(model.fade ?? 1),\n ...NO_ENVIRONMENT,\n },\n ]\n\n const opacity = material.opacity ?? 1\n\n if (kind === 'glass') {\n // `SubmitGlassGeometry`: inner faces opaque, then outer faces blended. Only those reflect.\n const alpha = Math.max(opacity, glassLeastAlpha)\n const shared = { negateNormals: false, alphaReference: DEVICE_ALPHA_REFERENCE, alpha }\n\n return [\n { ...shared, cull: 'front', blend: false, ...NO_ENVIRONMENT },\n {\n ...shared,\n cull: 'back',\n blend: true,\n ...withEnvironment(model.environment && 'envmapglass'),\n },\n ]\n }\n\n if (kind === 'emission' || kind === 'detail' || kind === 'detailTwo') {\n // Neither ever blends or cuts (`0x6ed16cc`, `0x6ed1484`). `BindEnvMap` needs stage 1 free: `DcDtEt`\n // without an `Et` leaves it so, and `BtDetailMapMaterial` always takes it (`0x6eb5100`).\n const free = kind === 'emission' && !material.emissionTexture\n const front: Pass = {\n cull: 'back',\n negateNormals: false,\n blend: false,\n alphaReference: DEVICE_ALPHA_REFERENCE,\n ...(free ? withEnvironment(model.environment) : NO_ENVIRONMENT),\n }\n // `DcDtEt` loads only `Dc`, `Dt` and `Et` (`0x6eb60b0`), so its opacity stays 1.\n if (kind === 'emission') front.alpha = 1\n return kind === 'detailTwo'\n ? [front, { ...front, cull: 'front', negateNormals: true }]\n : [front]\n }\n\n const entry = material.diffuseTexture && model.texture(material.diffuseTexture.name)\n const bits = alphaBits(entry)\n const blend = opacity < 1 || bits > 1\n const front: Pass = {\n cull: 'back',\n negateNormals: false,\n blend,\n // An `Oc` below 1 leaves before the format is read, so it isn't cut (`0x6eb6d63`).\n alphaReference: opacity >= 1 && bits === 1 ? CUT_ALPHA_REFERENCE : DEVICE_ALPHA_REFERENCE,\n ...(!BATCHED.test(type)\n ? withEnvironment(model.environment)\n : { normalizeNormals: !blend && model.environment !== undefined }),\n }\n if (kind === 'single') return [front]\n\n // `FMaterial::SubmitDcDtTwoSecondPass`: reversed, normals negated, outside the alpha test's scope.\n return [\n front,\n { ...front, cull: 'front', negateNormals: true, alphaReference: DEVICE_ALPHA_REFERENCE },\n ]\n}\n\nconst referenceOf = (\n part: RigidPart,\n name: string,\n world: Matrix4,\n transform: Matrix4,\n { level, camera, lod, detail }: PlaceOptions,\n): VMeshRef | undefined => {\n if (part.type !== 'rigid' || !part.part) return undefined\n\n const source = part.part\n\n if (level === undefined && camera)\n return levelAt(\n source,\n levelMetric(source, world, transform, camera),\n levelEnds(source, name, lod, { detail }),\n )?.reference\n\n if (source.type !== 'multilevel') return source.reference\n return source.levels[Math.min(level ?? 0, source.levels.length - 1)]?.reference\n}\n\n/** A compound model's parts, depth first (`li_elite`), for a host that doesn't pose its own. */\nexport const placeParts = (\n root: RigidModel,\n transform: Matrix4,\n options: PlaceOptions = {},\n): PlacedPart[] => {\n // A `.3db` is one part, with no hierarchy to walk. The game matches it as `Root`.\n if (root.type !== 'compound') {\n const reference = referenceOf(root, 'Root', transform, transform, options)\n\n return reference ? [{ reference, world: transform }] : []\n }\n\n const parts: PlacedPart[] = []\n\n for (const [node, world] of partTransforms(root, transform, options.jointState)) {\n if (options.visible && !options.visible(node)) continue\n\n const reference = referenceOf(node.part, node.name, world, transform, options)\n if (reference) parts.push({ reference, world })\n }\n\n return parts\n}\n\n/** A texture as bound: an animated one's is its frame's atlas, under that atlas's name. */\ninterface Bound {\n name: string\n entry: Texture | CubeTexture\n}\n\ntype Resolve = (name: string) => Bound | undefined\n\n/**\n * A slot's texture, reporting what the library doesn't hold. An animated one loops from load\n * (`TickAllPlayback`), and only its atlas is bound: `ResolveTextures` writes the frame's rect beside\n * the handle, and nothing reads it.\n */\nconst entryOf = (\n name: string,\n model: SceneModel,\n unsupported: Set<string>,\n time: number,\n): Bound | undefined => {\n const entry = model.texture(name)\n if (entry && entry.type !== 'animated') return { name, entry }\n\n const atlas = entry && frameAtlas(entry, playbackFrame(entry, time, 'loop'), model.texture)\n if (atlas) return atlas\n unsupported.add(`texture ${name}`)\n return undefined\n}\n\n// `nt_name`'s default (`FlmNomadParamsBase`), which wraps both ways.\nconst NOMAD_RAMP: TextureReference = { name: DEFAULT_NOMAD_TEXTURE_NAME, flags: 0x40 }\n\n/** A planet mask: an empty slot draws as an empty stage, and one not found drops the stage. */\nconst maskStage = (\n { slot, tile }: { slot: TextureReference | undefined; tile: number },\n resolve: Resolve,\n): DrawStage | undefined => {\n if (!slot) return { operation: 'modulate2x', tile }\n\n const entry = resolve(slot.name)\n if (!entry) return undefined\n return { operation: 'modulate2x', tile, texture: { ...drawTexture(slot, entry), uvSet: 0 } }\n}\n\nconst SHELL_FLOOR = 1e-7\n\n/**\n * `SubmitAtmosphereLock`'s values for a draw, from the camera in the unscaled object's space. Each\n * face has its own space, and retail reads its patch's normals, so this holds for the turned face.\n */\nconst atmosphereOf = (\n material: Material,\n world: Matrix4,\n view: Matrix4,\n radius: number,\n): { atmosphere: DrawAtmosphere; scale: number } => {\n const scale = material.scale ?? DEFAULT_SHELL_SCALE\n const fade = material.fade ?? 1\n // Defaults from its property schema.\n const alpha = material.alpha ?? 0.75\n const camera = Matrix4.transformPoint(\n { x: 0, y: 0, z: 0 },\n Matrix4.invert(Matrix4.multiply(view, world)),\n )\n // `factor` is the camera's height over the surface against the shell's thickness (0 at the\n // surface, toward 1 far off); its cube sets `gain`, and `v` rises to `1 - alpha` by half of it.\n const length = Math.hypot(camera.x, camera.y, camera.z) || SHELL_FLOOR\n const shell = (scale - 1) * (radius / scale)\n const distance = length - radius\n const factor = distance / ((shell > 0 ? shell : SHELL_FLOOR) + distance)\n const cubed = factor * factor * factor\n\n return {\n scale,\n atmosphere: {\n direction: { x: camera.x / length, y: camera.y / length, z: camera.z / length },\n threshold: radius / length,\n gain: fade * cubed,\n v: cubed < 0.5 ? 2 * (1 - alpha) * cubed : 1 - alpha,\n },\n }\n}\n\nconst secondStage = (\n kind: MaterialClass,\n { emissionTexture, detailTexture, nomadTexture }: Material,\n mesh: VMeshData,\n resolve: Resolve,\n): DrawStage | undefined => {\n if (kind === 'nomad') {\n // No retail material names its own. Stage 1 reads the second set `NomadWriteVert` generates.\n const slot = nomadTexture ?? NOMAD_RAMP\n const entry = resolve(slot.name)\n if (!entry) return undefined\n return { operation: 'add', texture: { ...drawTexture(slot, entry), uvSet: 1 } }\n }\n\n // Without an `Et`, `DcDtEt` disables the stage. `BtDetailMapMaterial` applies it regardless, and so\n // doubles without a `Bt`: two retail materials, uncaptured.\n if (kind === 'emission' && !emissionTexture) return undefined\n if (kind !== 'emission' && kind !== 'detail' && kind !== 'detailTwo') return undefined\n\n const operation = kind === 'emission' ? 'add' : 'modulate2x'\n const slot = kind === 'emission' ? emissionTexture : detailTexture\n if (!slot) return { operation }\n\n const entry = resolve(slot.name)\n // Not in the host's libraries: retail always has them, and a white `add` would hide the model.\n if (!entry) return undefined\n return { operation, texture: drawTexture(slot, entry) }\n}\n\n/**\n * `DrawBackdrop`, `DrawStarsphere` and the draw they share. A starsphere's zeroed view translation is\n * a world moved to the camera, as one view serves a frame. Which lights a room leaves on for it\n * isn't read: space turns them off (`0x4101e0`), and no reference scene has any.\n */\nconst skyState = (\n sky: 'starsphere' | 'backdrop',\n world: Matrix4,\n camera: Camera,\n aspect: number,\n { backdropNear, backdropFar }: FrameLimits,\n): Partial<Draw> => ({\n depthWrite: false,\n depthFunc: 'always',\n ...(sky === 'backdrop'\n ? {\n projection: projectionMatrix({ ...camera, near: backdropNear, far: backdropFar }, aspect),\n }\n : {\n world: Matrix4.multiply(Matrix4.translation(camera.position), world),\n sceneAmbient: WHITE,\n lightless: true,\n }),\n})\n\nexport interface Queued {\n depth: number\n draws: Draw[]\n}\n\n/**\n * `ComputeBatchDepth`: the mean of a reference's vertices along the view's Z. It is negative ahead of\n * the camera, so ascending is back to front, `Bin1SortOrder`'s default of 2 (`ku_dragon_pair`, whose\n * objects are 30 apart: the order is measured, but that the key is this mean is only read).\n */\nconst batchDepth = (\n mesh: VMeshData,\n reference: VMeshRef,\n world: Matrix4,\n view: Matrix4,\n): number => {\n const { x, y, z, w } = Matrix4.multiply(view, world)\n const stride = vertexByteLength(mesh.format)\n const bytes = new DataView(mesh.vertices.buffer, mesh.vertices.byteOffset)\n let sum = 0\n\n for (let at = 0; at < reference.vertexCount; at++) {\n const offset = (reference.vertexStart + at) * stride\n const px = bytes.getFloat32(offset, true)\n const py = bytes.getFloat32(offset + 4, true)\n const pz = bytes.getFloat32(offset + 8, true)\n\n // The vertex's view-space Z: the Z component of each column of `view · world`, weighted.\n sum += x.z * px + y.z * py + z.z * pz + w.z\n }\n\n return sum / reference.vertexCount\n}\n\n/** The batcher's bin 1, far before near. Stable, where retail's qsort leaves equal keys in no set order. */\nexport const flushQueued = (queued: Queued[], draws: Draw[]): void => {\n queued.sort((a, b) => a.depth - b.depth)\n for (const queue of queued) draws.push(...queue.draws)\n queued.length = 0\n}\n\n/** Lists a model's draws, its parts in the order given and each part's groups in order. */\nexport const collectModel = (\n model: SceneModel,\n camera: Camera,\n aspect: number,\n view: Matrix4,\n time: number,\n draws: Draw[],\n /** The batcher's bin 1. None while it's off (`SetBinOrder(1, -1)`): each part draws where it stands. */\n queued: Queued[] | undefined,\n unsupported: Set<string>,\n unregistered: Set<string>,\n limits: FrameLimits = RETAIL_FRAME_LIMITS,\n /** `kDrawNoCull`: the object was found wholly inside, so its parts aren't tested. */\n noCull = false,\n /** A room camera's: a part covering under a pixel of it isn't drawn (`FRoomCamera`, rank 2). */\n viewport?: Viewport,\n): void => {\n const resolve: Resolve = (name) => entryOf(name, model, unsupported, time)\n\n for (const part of model.parts) {\n const {\n reference,\n world,\n mesh: generated,\n materialId: faceMaterial,\n materialName,\n extent,\n } = part\n const mesh = generated ?? model.mesh(reference.meshId)\n\n if (!mesh) {\n unsupported.add(`mesh ${reference.meshId}`)\n continue\n }\n\n // `RenderInstance`, per part: a compound's children recurse whatever became of their parent. A\n // sky is tested as it's drawn, at the camera. Reports below come first, so none depends on the view.\n const placed =\n model.sky === 'starsphere'\n ? Matrix4.multiply(Matrix4.translation(camera.position), world)\n : world\n const { center, radius } = reference.boundingSphere\n const visible =\n noCull ||\n sphereInFrustum(\n Matrix4.transformPoint(center, Matrix4.multiply(view, placed)),\n (radius < 0.001 ? 1 : radius) * largestAxis(world),\n camera,\n aspect,\n viewport,\n )\n\n for (const { materialId, startIndex, elementCount } of getMeshDraw(mesh, reference)) {\n const material = model.material(faceMaterial ?? materialId)\n\n if (!material) {\n unsupported.add(`material ${materialName ?? faceMaterial ?? materialId}`)\n continue\n }\n\n const type = mapMaterialType(material, model.materialMap)\n // `SubmitNull` draws nothing, and an unregistered type has no fallback (`0x6ecc47e`).\n if (type === 'NullMaterial') continue\n\n if (!REGISTERED_TYPES.has(type)) {\n unregistered.add(material.name)\n continue\n }\n\n const kind = CLASSES[type]\n\n if (!kind) {\n unsupported.add(material.name)\n continue\n }\n\n const { x, y, z } = material.diffuse ?? WHITE\n // `EcEt` draws its `Et` on stage 0, and engine glow has no texture at all.\n const slot =\n kind === 'emissive'\n ? material.emissionTexture\n : kind === 'glow'\n ? undefined\n : material.diffuseTexture\n const entry = slot && resolve(slot.name)\n const second = secondStage(kind, material, mesh, resolve)\n // Only the single-pass family asks for an instance (`ApplyVerifyMatAnim`) among those built.\n const anim =\n (kind === 'single' || kind === 'singleTwo' || kind === 'hudAnim' || kind === 'water') &&\n model.materialAnimations\n ? getMaterialAnim(model.materialAnimations, material.name)\n : undefined\n const animated =\n type === 'EyeMaterial' && part.eyeOffset\n ? { offset: part.eyeOffset, scale: [1, 1] as [number, number] }\n : anim && sampleUvAnimation(anim, time)\n\n if (!visible) continue\n\n // A queued material's passes stay together, being one submission (`ProcessQueuedBin`).\n const passes = passesOf(kind, type, material, model, limits).map((pass) =>\n model.cloaked && kind !== 'nomad'\n ? cloak(pass, kind, type, material, model.fade ?? 1)\n : pass,\n )\n const target: Draw[] = []\n // The sky's override calls the batched face's `Submit` itself, so it never reaches a queue\n // (`FMaterialImpl::DrawBackdrop`), and draws where it stands.\n const queuedHere = queued && !model.sky && BATCHED.test(type) && passes[0]!.blend\n\n if (queuedHere)\n queued.push({ depth: batchDepth(mesh, reference, world, view), draws: target })\n\n const shell =\n kind === 'atmosphere' ? atmosphereOf(material, world, view, extent ?? 1) : undefined\n\n for (const {\n alpha,\n depthWrite,\n depthFunc,\n blendMode,\n alphaFunction,\n unlit,\n mask,\n ...pass\n } of passes) {\n const cube = pass.environment ? resolve(pass.environment)?.entry : undefined\n const stage = mask === undefined ? second : mask && maskStage(mask, resolve)\n ;(queuedHere ? target : draws).push({\n mesh,\n reference,\n byteOffset: (startIndex - reference.indexStart) * Uint16Array.BYTES_PER_ELEMENT,\n count: elementCount,\n // `SubmitAtmosphereLock` scales only what it draws: its UVs come from the unscaled object.\n world: shell ? Matrix4.multiply(world, Matrix4.scaling(shell.scale)) : world,\n materialName: material.name,\n // `Dc` is never read by the nomad class.\n diffuse:\n kind === 'nomad' || FIXED_COLOUR.has(kind)\n ? [1, 1, 1, alpha!]\n : kind === 'glow'\n ? [0, 0, 0, 1]\n : [x, y, z, alpha ?? material.opacity ?? 1],\n // Setting `Dc` overwrites `Ac` (`0x6eb2439`), and both start white. 37 retail materials differ.\n ambient: FIXED_COLOUR.has(kind)\n ? WHITE\n : kind === 'glow'\n ? BLACK\n : ((kind === 'hudIcon' || kind === 'exclusion'\n ? model.instance?.ambient\n : undefined) ??\n material.diffuse ??\n material.ambient ??\n WHITE),\n emissive:\n kind === 'glow'\n ? (material.emission ?? ENGINE_GLOW)\n : (kind !== 'emission' &&\n kind !== 'lightMap' &&\n kind !== 'nebula' &&\n material.emission) ||\n BLACK,\n colorVertex: (mesh.format & VertexFormat.Diffuse) !== 0,\n nomad: kind === 'nomad',\n depthWrite: depthWrite ?? true,\n depthFunc: depthFunc ?? 'less',\n blendMode: blendMode ?? 'alpha',\n unlit: unlit ?? (kind === 'lightMap' || kind === 'nebula'),\n alphaFunction: alphaFunction ?? 'greater',\n ...(shell ? { atmosphere: shell.atmosphere } : {}),\n // `SubmitExclusionGeometry` draws with `D3DRS_AMBIENT` white, so `Ac` arrives unscaled.\n ...(kind === 'exclusion' ? { sceneAmbient: WHITE } : {}),\n // A slot with no texture draws as an empty stage, which reads as white.\n ...(slot && entry ? { texture: drawTexture(slot, entry) } : {}),\n ...(stage ? { second: stage } : {}),\n ...(animated ? { uvTransform: animated } : {}),\n ...pass,\n ...(cube?.type === 'cube' ? { environmentTexture: cube } : {}),\n ...(part.skin ? { skin: part.skin } : {}),\n ...(model.sky ? skyState(model.sky, world, camera, aspect, limits) : {}),\n })\n }\n }\n }\n}\n\nexport const BLACK_BACKGROUND: Vector3 = { x: 0, y: 0, z: 0 }\n\nexport const hooksOf = (draws: Draw[]): FrameHook[] => {\n // A sky blends before anything opaque, and isn't what this hook waits for.\n const firstBlended = draws.findIndex(({ blend, depthFunc }) => blend && depthFunc !== 'always')\n\n return [\n { name: 'begin', before: 0 },\n { name: 'opaque', before: firstBlended === -1 ? draws.length : firstBlended },\n { name: 'end', before: draws.length },\n ]\n}\n\nexport const collectFrame = ({\n camera,\n aspect,\n ambient,\n lights,\n models,\n background,\n time = 0,\n effects = [],\n limits,\n}: Scene): Frame => {\n const resolved = { ...RETAIL_FRAME_LIMITS, ...limits }\n const draws: Draw[] = []\n const unsupported = new Set<string>()\n const unregistered = new Set<string>()\n const view = viewMatrix(camera)\n const queued: Queued[] = []\n\n for (const model of models)\n collectModel(\n model,\n camera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n resolved,\n )\n\n // A room flushes its queue once, after all its objects (`RoomBatcherEnd`, `ku_dragon_pair`).\n flushQueued(queued, draws)\n\n const effectDraws: EffectDraw[] = []\n\n for (const { instance, texture, visible } of effects)\n collectEffect(instance, view, texture, effectDraws, unsupported, visible)\n\n return {\n background: background ?? BLACK_BACKGROUND,\n hooks: hooksOf(draws),\n view,\n projection: projectionMatrix(camera, aspect),\n ambient,\n lights,\n draws,\n effects: effectDraws,\n unsupported: [...unsupported],\n unregistered: [...unregistered],\n }\n}\n","/**\n * An engine instance's extent: `EngineComputeInstanceExtent` (`0x661ed90`) in\n * `src/EngBase/EngBase.cpp`. A space sky stands at its centre (`StarSphereLoadLayer`), and a solar\n * without a body is tested against it (`CObject::get_physical_radius_r`). Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { CompoundNode } from '@treewyrm/freelancer/compound'\nimport type { RigidModel, RigidPart } from '@treewyrm/freelancer/rigid'\n\nexport interface Extent {\n /** In the model's own space. */\n center: Vector3\n radius: number\n}\n\nconst ORIGIN: Vector3 = { x: 0, y: 0, z: 0 }\n\n/**\n * A part's own sphere: its mesh reference's (`CreateMeshInstance`, `Extra2C` and `Extra38`), the\n * first level's for a multilevel part, and a `.sph`'s radius. A part with no mesh is a point at its\n * origin, which is an inference: its `GetExtra` isn't traced.\n */\nconst ownSphere = (part: RigidPart): Extent => {\n if (part.type === 'sphere') return { center: ORIGIN, radius: part.radius }\n if (part.type !== 'rigid' || !part.part) return { center: ORIGIN, radius: 0 }\n\n const source = part.part\n const reference = source.type === 'multilevel' ? source.levels[0]?.reference : source.reference\n\n return reference\n ? { center: reference.boundingSphere.center, radius: reference.boundingSphere.radius }\n : { center: ORIGIN, radius: 0 }\n}\n\nconst distance = (a: Vector3, b: Vector3): number =>\n Math.sqrt((a.z - b.z) ** 2 + (a.y - b.y) ** 2 + (a.x - b.x) ** 2)\n\n/** The box around a part's sphere and each child's extent, and a radius holding all of them. */\nconst extentOf = (own: Extent, world: Matrix4, children: Extent[]): Extent => {\n const center = Matrix4.transformPoint(own.center, world)\n const axes = ['x', 'y', 'z'] as const\n const least = { x: center.x - own.radius, y: center.y - own.radius, z: center.z - own.radius }\n const most = { x: center.x + own.radius, y: center.y + own.radius, z: center.z + own.radius }\n\n for (const child of children)\n for (const axis of axes) {\n least[axis] = Math.min(least[axis], child.center[axis] - child.radius)\n most[axis] = Math.max(most[axis], child.center[axis] + child.radius)\n }\n\n const middle = {\n x: Math.fround((most.x + least.x) * 0.5),\n y: Math.fround((most.y + least.y) * 0.5),\n z: Math.fround((most.z + least.z) * 0.5),\n }\n let radius = Math.max(...axes.map((axis) => most[axis] - least[axis])) * 0.5\n\n radius = Math.max(radius, distance(middle, center) + own.radius)\n\n for (const child of children)\n radius = Math.max(radius, distance(child.center, middle) + child.radius)\n\n return { center: middle, radius: Math.fround(radius) }\n}\n\n/**\n * Every part's extent first, then its parent's around them. The engine caches the first answer\n * (`Instance->Extent`), and finds it as the model loads, with every part still at the root: what\n * `starsphere_li01` and its stars measure in `space_order`, where posed parts miss by up to 15.\n */\nconst compoundExtent = (node: CompoundNode<RigidPart>): Extent =>\n extentOf(ownSphere(node.part), Matrix4.identity, node.children.map(compoundExtent))\n\n/** The extent of a model as it loads, with its root at the origin. */\nexport const instanceExtent = (model: RigidModel): Extent =>\n model.type === 'compound'\n ? compoundExtent(model)\n : extentOf(ownSphere(model), Matrix4.identity, [])\n","/**\n * `ZONE::Intersect` (`LAB_0633aa40`, `src/Common/common_zone.cpp`): whether a segment meets a zone,\n * by the clip of its shape. Only whether it does is kept; where is never read by what calls it here.\n * Pure.\n */\nimport type { Vector3 } from '@treewyrm/freelancer/math'\n\nconst f = Math.fround\n\nexport type ZoneShapeType = 'sphere' | 'ellipsoid' | 'box' | 'cylinder' | 'ring'\n\ninterface Frame {\n position: Vector3\n /** `GetOrientation`'s columns. */\n axes: readonly [Vector3, Vector3, Vector3]\n}\n\nconst sub = (a: Vector3, b: Vector3): Vector3 => ({\n x: f(a.x - b.x),\n y: f(a.y - b.y),\n z: f(a.z - b.z),\n})\n\n// `EngineTransposeTransform`: into the zone's own frame.\nconst toLocal = ({ axes }: Frame, d: Vector3): Vector3 => ({\n x: f(axes[0].x * d.x + axes[0].y * d.y + axes[0].z * d.z),\n y: f(axes[1].x * d.x + axes[1].y * d.y + axes[1].z * d.z),\n z: f(axes[2].x * d.x + axes[2].y * d.y + axes[2].z * d.z),\n})\n\n/** `FUN_06334ac0`: the segment enters the sphere, or starts in it. */\nconst clipSphere = (start: Vector3, end: Vector3, center: Vector3, radius: number): boolean => {\n // Solves |s + t·d|² = r² for t in [0, 1]; `b` is the half coefficient `d·s`, so t = (-b ± √disc) / a.\n const d = sub(end, start)\n const s = sub(start, center)\n const a = f(d.z * d.z + d.y * d.y + d.x * d.x)\n const b = d.z * s.z + d.y * s.y + s.x * d.x\n const c = s.z * s.z + s.y * s.y + s.x * s.x\n const disc = f(b * b - (c - radius * radius) * a)\n if (!(disc >= 0)) return false\n\n if (!(disc > 0)) {\n const t = -(b / a)\n\n return t >= 0 && f(t) <= 1\n }\n\n const root = Math.sqrt(disc)\n const t1 = f((-b - root) * (1 / a))\n const t2 = f((root - b) * (1 / a))\n\n // A start inside takes the exit, which isn't held to the segment.\n return !(t1 > 1) && !(t2 < 0)\n}\n\n/** `ClipSideWall`: the nearer root on the wall of `radius`, within its height. */\nconst sideWall = (\n a: number,\n b: number,\n disc: number,\n ls: Vector3,\n le: Vector3,\n half: number,\n best: number,\n): number => {\n const height = (t: number) => half >= Math.abs((le.y - ls.y) * t + ls.y)\n\n if (disc > 0) {\n const root = Math.sqrt(disc)\n const twoA = a + a\n const t1 = f((-b - root) / twoA)\n const t2 = f((root - b) / twoA)\n\n if (t1 >= 0 && t1 <= best && height(t1)) {\n if (t2 >= 0 && t2 <= t1 && half >= Math.abs(f(le.y - ls.y) * t2 + ls.y)) return t2\n return t1\n }\n\n if (t2 >= 0 && t2 <= best && height(t2)) return t2\n return best\n }\n\n if (disc === 0) {\n const t = -b / (a + a)\n if (t >= 0 && f(t) <= best && height(f(t))) return f(t)\n }\n\n return best\n}\n\n/** The cylinder's and ring's walls and caps (`FUN_06334f30`, `FUN_06335440`). */\nconst clipTube = (\n frame: Frame,\n start: Vector3,\n end: Vector3,\n outer: number,\n inner: number | undefined,\n height: number,\n): boolean => {\n const ls = toLocal(frame, sub(start, frame.position))\n const le = toLocal(frame, sub(end, frame.position))\n const half = f(height * 0.5)\n // The same quadratic in the XZ plane (here `b` is the full 2·d·s, `best` starts at 2: no hit), for\n // the outer wall then the inner; then the two caps at y = ±half.\n const dx = le.x - ls.x\n const dz = le.z - ls.z\n const a = f(dz * dz + dx * dx)\n const b = 2 * (ls.z * dz + ls.x * dx)\n const c = ls.z * ls.z + ls.x * ls.x\n let best = sideWall(a, b, b * b - (c - outer * outer) * a * 4, ls, le, half, 2)\n\n if (inner !== undefined)\n best = sideWall(a, b, b * b - (c - inner * inner) * a * 4, ls, le, half, best)\n\n const ld = toLocal(frame, sub(end, start))\n\n for (const num of [f(-half - ls.y), f(half - ls.y)]) {\n if (!((ld.y > 0 && num > 0) || (ld.y < 0 && num < 0))) continue\n\n const t = num / ld.y\n if (!(t > 0) || !(f(t) < best)) continue\n\n const x = ls.x + f(f(dx) * f(t))\n const z = ls.z + f(dz) * f(t)\n const radial = z * z + x * x\n if (radial < outer * outer && (inner === undefined || radial > inner * inner)) best = f(t)\n }\n\n return best >= 0 && best <= 1\n}\n\n/** `FUN_06335b10`: a start inside hits; otherwise the nearest face crossed, held only below 1. */\nconst clipBox = (frame: Frame, start: Vector3, end: Vector3, size: Vector3): boolean => {\n const ls = toLocal(frame, sub(start, frame.position))\n const le = toLocal(frame, sub(end, frame.position))\n const half = [f(size.x * 0.5), f(size.y * 0.5), f(size.z * 0.5)] as const\n\n if (size.x * 0.5 > Math.abs(ls.x) && half[1] > Math.abs(ls.y) && half[2] > Math.abs(ls.z))\n return true\n\n const ld = toLocal(frame, sub(end, start))\n const l = [ls.x, ls.y, ls.z]\n const e = [le.x, le.y, le.z]\n const dir = [ld.x, ld.y, ld.z]\n let best = 2\n\n // Slabs: per axis, t at the face the segment is heading toward, a hit if the point there is\n // inside the other two half-extents.\n for (let axis = 0; axis < 3; axis++) {\n const along = dir[axis]!\n const num = along > 0 ? -half[axis]! - l[axis]! : along < 0 ? half[axis]! - l[axis]! : 0\n if (!(along > 0 ? num > 0 : along < 0 ? num < 0 : false)) continue\n\n const t = num / along\n // The x faces aren't compared with the best so far.\n if (axis > 0 && !(t < best)) continue\n\n const point = l.map((value, at) => value + (e[at]! - value) * f(t))\n\n if ([0, 1, 2].every((other) => other === axis || half[other]! > Math.abs(point[other]!)))\n best = f(t)\n }\n\n return best <= 1\n}\n\n/** Whether the segment from `start` to `end` meets the zone (`ZONE::Intersect`). */\nexport const segmentMeetsZone = (\n type: ZoneShapeType,\n frame: Frame & { radius: number; size: Vector3 },\n start: Vector3,\n end: Vector3,\n): boolean => {\n const { size } = frame\n\n switch (type) {\n case 'ellipsoid': {\n // Scaled by its written size into a unit sphere (`FUN_06334d10`).\n const unit = (point: Vector3) => {\n const local = toLocal(frame, sub(point, frame.position))\n\n return { x: f(local.x / size.x), y: f(local.y / size.y), z: f(local.z / size.z) }\n }\n\n return clipSphere(unit(start), unit(end), { x: 0, y: 0, z: 0 }, 1)\n }\n case 'box':\n return clipBox(frame, start, end, size)\n case 'cylinder':\n return clipTube(frame, start, end, size.x, undefined, size.y)\n case 'ring':\n return clipTube(frame, start, end, size.x, size.y, size.z)\n case 'sphere':\n return clipSphere(start, end, frame.position, frame.radius)\n }\n}\n","/**\n * Retail's own arithmetic where several subsystems share it: the fast inverse square root, its\n * random points on and in a sphere, and colour channels truncated to a byte. Each copy in the\n * executable rounds as this does; the library's generic versions would change the picture.\n */\nimport type { Vector3 } from '@treewyrm/freelancer/math'\nimport type { Random } from './lightning.js'\n\nconst f = Math.fround\n\n/** `rand()`'s 0 to 32767 onto [0, 1), as the executables scale it: 1 / 32768. */\nexport const RAND_UNIT = 3.0517578125e-5\n\n/** 2π as a float. */\nexport const TWO_PI = 6.2831854820251465\n\nconst floats = new Float32Array(1)\nconst bits = new Int32Array(floats.buffer)\n\n/** `1 / √squared` from the `0x5f3759df` estimate and one Newton step, left unrounded (`FUN_00507e70`). */\nexport const inverseRoot = (squared: number): number => {\n floats[0] = squared\n bits[0] = 0x5f3759df - (bits[0]! >> 1)\n\n const estimate = floats[0]!\n\n return (1.5 - estimate * estimate * squared * 0.5) * estimate\n}\n\n/** `random_inside_sphere` (`0x631db20`): uniform direction (cos θ, φ uniform) at radius ∛u. */\nexport const insideSphere = (random: Random, radius: number): Vector3 => {\n const scaled = f(Math.pow(random() * RAND_UNIT, 1 / 3) * radius)\n const cos = random() * RAND_UNIT * 2 - 1\n const sin = f(Math.sin(Math.acos(cos)) * scaled)\n const phi = random() * RAND_UNIT * TWO_PI\n\n return { x: f(Math.sin(phi) * sin), y: f(f(cos) * scaled), z: f(Math.cos(phi) * sin) }\n}\n\n/** `random_on_unit_sphere` (`0x631da50`). */\nexport const onSphere = (random: Random): Vector3 => {\n const u1 = f(random() * RAND_UNIT)\n const u2 = f(random() * RAND_UNIT)\n const cos = Math.min(Math.max(f(u1 + u1 - 1), -1), 1)\n const theta = Math.acos(cos)\n const phi = u2 * TWO_PI\n const sin = Math.sin(theta)\n\n return { x: f(Math.sin(phi) * sin), y: f(Math.cos(theta)), z: f(Math.cos(phi) * sin) }\n}\n\n/** Truncated toward zero and held to a byte. */\nexport const clampByte = (value: number): number => Math.min(Math.max(Math.trunc(value), 0), 255)\n\n/** A unit channel as a byte: times 255 on the FPU, truncated, held. */\nexport const unitByte = (value: number): number => clampByte(value * 255)\n\n/** {@link unitByte} with the product rounded to a float first. */\nexport const unitByteRounded = (value: number): number => clampByte(f(value * 255))\n","/**\n * A system's nebulae as the frame sees them: which one the camera answers to, and the fog and ambient\n * each gives what it holds. `FNebulaEffect` in `src/freelancer/Client/cli_nebula.cpp`, `ZONE` in\n * `src/Common/common_zone.cpp`. Pure, no GL.\n */\nimport { Quat, type Matrix4, type Shape, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { SceneModel } from './frame.js'\nimport type { Clouds } from './clouds.js'\nimport type { NebulaExterior } from './exterior.js'\nimport type { NebulaLightning } from './lightning.js'\nimport type { TextureShape } from './ring.js'\nimport { segmentMeetsZone } from './zone-segment.js'\nimport { inverseRoot, unitByte } from './retail.js'\n\n/**\n * What a nebula asks of its zone: `IZone`'s position, `GetRadius`, `GetRadiusAlong`, `GetSize` and\n * `GetOrientation`.\n */\nexport interface Zone {\n /** Its `shape`: what the exclusion managers measure by kind (`AsteroidExclusionZone::update_dist`). */\n type: Shape['type']\n position: Vector3\n /** The sphere around it. */\n radius: number\n /** From its centre to its surface along a unit direction in world space. */\n radiusAlong: (direction: Vector3) => number\n /** `GetSize`: its `size` as written, a missing value 0 (`Universe` zone loading). */\n size: Vector3\n /** `GetOrientation`'s columns: its own x, y and z in world space. */\n axes: readonly [Vector3, Vector3, Vector3]\n /** `GetSurfacePoint` (`ZONE`, vt+0x44): where its surface is, for a point. */\n surfacePoint: (point: Vector3) => Vector3\n /** `InZone` (`0x6339220`) with no margin: whether a point is in it. */\n holds: (point: Vector3) => boolean\n /** `Intersect` (vt+0x4c): whether a segment meets it, or starts in it. */\n meets: (start: Vector3, end: Vector3) => boolean\n}\n\n/** A system's `[Nebula]`: its zone, and what its file's `[Fog]` and `[NebulaLight]` say. */\nexport interface SpaceNebula {\n zone: Zone\n fog: {\n /** `near`, 0 when absent. */\n near?: number\n /** `distance`, `limits.nebulaFogDistance` when absent. */\n distance?: number\n /** `color` over 255, each kept below 1 (`ParseFogSection`). */\n color: Vector3\n }\n /** `[NebulaLight] ambient`, as written, 0 to 255. */\n ambient?: Vector3\n /**\n * `[NebulaLight]`'s suns seen from in it: their glows drawn again at `sun_burnthrough_intensity`\n * times its depth, 0.5 when absent, and `sun_burnthrough_scaler` times their size, 1.75 when absent\n * (`FNebulaEffect`'s constructor; `DrainMeshAndAsteroids`, `0x51fad9`).\n */\n burnthrough?: { intensity?: number; scaler?: number }\n /** `[Exclusion Zones]`, in file order: holes in its fog. */\n exclusions?: readonly NebulaExclusion[]\n /** Its flashes, of its fog and of a light, which retail gives every nebula. None when absent. */\n lightning?: NebulaLightning\n /** `[Exterior] fill_shape`: the two sheets drawn across it from outside and in its edge. */\n fill?: TextureShape\n /** `[Exterior]`'s bits about it, seen from outside and in its edge. */\n exterior?: NebulaExterior\n /** Its `[Clouds]`, in file order, drawn about the camera in it. */\n clouds?: readonly Clouds[]\n /** Its zone's `edge_fraction`, which a puff spawning in its edge is held to. 0 when absent. */\n edgeFraction?: number\n}\n\n/** An `exclusion` of a nebula's file, and its zone, which retail requires to be a sphere. */\nexport interface NebulaExclusion {\n zone: Zone\n /** The zone's `edge_fraction`, 0 to 1: how far in from its surface the hole deepens. 0 when absent. */\n edgeFraction?: number\n /** `fog_far`: where the fog ends deep in it. None when absent (`NebulaExclusionZone`'s -1). */\n fogFar?: number\n /** Its `zone_shell`, drawn about it while the camera is in it. */\n shell?: ExclusionShell\n}\n\n/** A `zone_shell` and the keys after it (`FNebulaZoneShell`), shared by every zone naming it. */\nexport interface ExclusionShell {\n /** The model placed under `world`, its levels picked as the game's camera picks them. */\n place: (world: Matrix4) => SceneModel\n /** The zone's transform, unscaled: `IZone::GetTransform`. */\n transform: Matrix4\n /** `shell_scalar`, at least 1. 1 when absent. */\n scalar?: number\n /** `max_alpha`, at most 1. 1 when absent. */\n maxAlpha?: number\n /**\n * `exclusion_tint` over 255, each held to 1. Retail leaves it uninitialised when absent, so a shell\n * without one draws in whatever the heap held: the host decides.\n */\n tint: Vector3\n}\n\n/** What retail hardcodes about nebulae, and a mod can patch. */\nexport interface NebulaLimits {\n /** A `[Fog]` with no `distance` (`FNebulaEffect::Load`). */\n nebulaFogDistance: number\n /** Past the fog's end, the far plane in a core (`FogFarClamp`, `0x5d9668`). */\n nebulaFarMargin: number\n /** The least far plane in a core (`+0x2bc`, set by `FNebulaEffect`'s constructor). */\n nebulaLeastFar: number\n /** Past an exclusion zone's diameter, the least far plane in it (`FogFarClamp`, `0x5db0c0`). */\n exclusionFarMargin: number\n}\n\nexport const RETAIL_NEBULA_LIMITS: Readonly<NebulaLimits> = {\n nebulaFogDistance: 10000,\n nebulaFarMargin: 500,\n nebulaLeastFar: 5000,\n exclusionFarMargin: 500,\n}\n\n/** D3D's fog: linear, none nearer than `start` and all of `color` from `end`, or exponential. */\nexport interface Fog {\n /** 0 to 1, whole bytes. */\n color: Vector3\n start: number\n end: number\n /** `D3DFOGMODE`. A nebula's is linear; a room's `fogmode` can be any. Linear when absent. */\n mode?: 'linear' | 'exp' | 'exp2'\n /** What `exp` and `exp2` read: `e^-(density × W)`, and `e^-(density × W)²`. */\n density?: number\n}\n\nconst f = Math.fround\n\nconst sub = (a: Vector3, b: Vector3): Vector3 => ({\n x: f(a.x - b.x),\n y: f(a.y - b.y),\n z: f(a.z - b.z),\n})\n\nconst scaled = ({ x, y, z }: Vector3, by: number): Vector3 => ({\n x: f(x * by),\n y: f(y * by),\n z: f(z * by),\n})\n\n/** The `size` a zone of `shape` is written with: a sphere's one value, a cylinder's two. */\nconst writtenSize = (shape: Shape): Vector3 => {\n switch (shape.type) {\n case 'sphere':\n return { x: shape.radius, y: 0, z: 0 }\n case 'ellipsoid':\n return shape.radii\n case 'box':\n return shape.size\n case 'cylinder':\n return { x: shape.radius, y: shape.height, z: 0 }\n case 'ring':\n return { x: shape.radius, y: shape.innerRadius, z: shape.height }\n }\n}\n\n/** A zone as written: what `shape` can't hold. A sphere's `rotate` turns its axes alone. */\nexport interface WrittenZone {\n /** Its `size`, a missing value 0. From `shape` when absent, as the game's files write it. */\n size?: Vector3\n /** Its `rotate`. From `shape` when absent, none for a sphere. */\n orientation?: Quat\n}\n\n/**\n * `ZONE::GetRadius`, `GetRadiusAlong`, `GetSize`, `GetOrientation` and `GetSurfacePoint` for each\n * shape the game knows.\n */\nexport const zoneOf = (shape: Shape, written: WrittenZone = {}): Zone => {\n const reach = reachOf(shape, written)\n const { position: centre, axes, size } = reach\n // In the zone's own frame and back: `EngineTransposeTransform`, `EngineTransformMatrix`.\n const toLocal = (d: Vector3): Vector3 => ({\n x: f(axes[0].x * d.x + axes[0].y * d.y + axes[0].z * d.z),\n y: f(axes[1].x * d.x + axes[1].y * d.y + axes[1].z * d.z),\n z: f(axes[2].x * d.x + axes[2].y * d.y + axes[2].z * d.z),\n })\n const zone = {\n ...reach,\n type: shape.type,\n meets: (start: Vector3, end: Vector3) => segmentMeetsZone(shape.type, reach, start, end),\n holds: (point: Vector3) => inZone(shape.type, reach, toLocal, point),\n }\n const toWorld = (l: Vector3): Vector3 => ({\n x: f(axes[0].x * l.x + axes[1].x * l.y + axes[2].x * l.z),\n y: f(axes[0].y * l.x + axes[1].y * l.y + axes[2].y * l.z),\n z: f(axes[0].z * l.x + axes[1].z * l.y + axes[2].z * l.z),\n })\n const plus = (a: Vector3, b: Vector3): Vector3 => ({\n x: f(a.x + b.x),\n y: f(a.y + b.y),\n z: f(a.z + b.z),\n })\n\n if (shape.type === 'box') {\n // `ClampPointToBoxSurface` (`FUN_062dba00`): each axis outside held to its face; a point\n // inside goes to the face it's nearest.\n const half = [f(size.x * 0.5), f(size.y * 0.5), f(size.z * 0.5)]\n\n return {\n ...zone,\n surfacePoint: (point) => {\n const local = toLocal(sub(point, centre))\n const values = [local.x, local.y, local.z]\n const over = values.map((value, axis) => f(Math.abs(value) - half[axis]!))\n let outside = false\n\n const out = values.map((value, axis) => {\n if (over[axis]! < 0) return value\n outside = true\n return Math.sign(value) < 0 || Object.is(value, -0) ? -half[axis]! : half[axis]!\n })\n\n if (!outside) {\n let nearest = 2\n\n if (over[0]! >= over[1]!) {\n if (over[0]! >= over[2]!) nearest = 0\n } else if (over[1]! >= over[2]!) nearest = 1\n\n const value = values[nearest]!\n\n out[nearest] =\n Math.sign(value) < 0 || Object.is(value, -0) ? -half[nearest]! : half[nearest]!\n }\n\n return plus(toWorld({ x: out[0]!, y: out[1]!, z: out[2]! }), centre)\n },\n }\n }\n\n if (shape.type === 'ring') {\n // `LAB_0633a398`: the nearest point of its middle circle, out along the tube to its surface.\n const middle = f((size.y + size.x) * 0.5)\n const half = size.z * 0.5\n const cutoff = half / Math.sqrt(size.x * size.x + half * half)\n\n return {\n ...zone,\n surfacePoint: (point) => {\n const local = toLocal(sub(point, centre))\n const rim = scaled({ x: local.x, y: 0, z: local.z }, middle / Math.hypot(local.x, local.z))\n let tube = sub(local, rim)\n const length = Math.sqrt(tube.x * tube.x + tube.y * tube.y + tube.z * tube.z)\n if (!(length < f(1e-4))) tube = scaled(tube, 1 / length)\n\n const y = Math.abs(tube.y)\n const reach =\n y > cutoff\n ? half / y\n : ((size.x - size.y) * 0.5) / Math.sqrt(tube.z * tube.z + tube.x * tube.x)\n\n return plus(centre, toWorld(plus(rim, scaled(tube, reach))))\n },\n }\n }\n\n // `0x633a2af`: any other shape, out from the centre to its reach that way.\n return {\n ...zone,\n surfacePoint: (point) => {\n const delta = sub(point, centre)\n const length = Math.sqrt(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z)\n if (length < f(1e-4)) return centre\n\n const unit = scaled(delta, 1 / length)\n const reach = f(zone.radiusAlong(unit))\n\n return plus(scaled(unit, reach), centre)\n },\n }\n}\n\n/**\n * `ZONE::InZone` (`0x6339220`) at a margin of 0. Within its sphere, then by shape: a sphere is\n * held, an ellipsoid by its reach that way, a box strictly inside its faces, a cylinder by its\n * height and radius. A ring's inner bound is `Inner + y`, with `Inner` as `sqrt(y² + z² / 4)` where\n * the other tests have the margin: an odd bound, but `common.dll` has it (`0x63394c0`, `0x6339543`).\n */\nconst inZone = (\n type: Shape['type'],\n { position, radius, radiusAlong, size }: Omit<Zone, 'surfacePoint' | 'meets' | 'holds' | 'type'>,\n toLocal: (d: Vector3) => Vector3,\n point: Vector3,\n): boolean => {\n const dx = f(point.x - position.x)\n const dy = f(point.y - position.y)\n const exact = point.z - position.z\n const dz = f(exact)\n const squared = exact * dz + dx * dx + dy * dy\n if (squared < f(1e-4)) return true\n\n const distance = f(squared)\n if (!(distance < radius * radius)) return false\n\n switch (type) {\n case 'sphere':\n return true\n case 'ellipsoid': {\n const length = f(Math.sqrt(distance))\n const inverse = 1 / length\n const unit = { x: f(dx * inverse), y: f(dy * inverse), z: f(dz * inverse) }\n\n return radiusAlong(unit) >= length\n }\n case 'box': {\n // `ClampToBoxSurface`'s distance, negated inside, under 0: on a face is out.\n const local = toLocal({ x: dx, y: dy, z: dz })\n\n return (\n Math.abs(local.x) < f(size.x * 0.5) &&\n Math.abs(local.y) < f(size.y * 0.5) &&\n Math.abs(local.z) < f(size.z * 0.5)\n )\n }\n case 'cylinder': {\n const local = toLocal({ x: dx, y: dy, z: dz })\n if (!(size.y * 0.5 >= Math.abs(local.y))) return false\n return local.x * local.x + local.z * local.z - size.x * size.x < 0\n }\n case 'ring': {\n const local = toLocal({ x: dx, y: dy, z: dz })\n const inner = f(Math.sqrt(size.y * size.y + size.z * size.z * 0.25))\n\n if (!(size.z * 0.5 >= Math.abs(local.y))) return false\n\n const radial = local.x * local.x + local.z * local.z\n if (!(radial - size.x * size.x <= 0)) return false\n return radial - ((inner + inner + size.y) * size.y + inner * inner) >= 0\n }\n }\n}\n\n/** Everything of a zone but its surface point and segment and point tests. */\nconst reachOf = (\n shape: Shape,\n written: WrittenZone,\n): Omit<Zone, 'surfacePoint' | 'meets' | 'holds' | 'type'> => {\n const position = shape.center\n const turn = written.orientation ?? (shape.type === 'sphere' ? Quat.identity : shape.orientation)\n\n const axis = (direction: Vector3): Vector3 => {\n const { x, y, z } = Quat.transform(direction, turn)\n\n return { x: f(x), y: f(y), z: f(z) }\n }\n\n const size = written.size ?? writtenSize(shape)\n const own = {\n size: { x: f(size.x), y: f(size.y), z: f(size.z) },\n axes: [\n axis({ x: 1, y: 0, z: 0 }),\n axis({ x: 0, y: 1, z: 0 }),\n axis({ x: 0, y: 0, z: 1 }),\n ] as const,\n }\n\n if (shape.type === 'sphere') {\n const radius = f(shape.radius)\n\n return { position, radius, radiusAlong: () => radius, ...own }\n }\n\n // `EngineTransposeTransform`: the direction in the zone's own frame.\n const inverse = Quat.conjugate(shape.orientation)\n const local = (direction: Vector3) => Quat.transform(direction, inverse)\n\n if (shape.type === 'ellipsoid') {\n const { x, y, z } = shape.radii\n const a = x * x\n const b = y * y\n const c = z * z\n\n return {\n ...own,\n position,\n radius: f(Math.max(x, y, z)),\n // `EllipsoidRadiusAlong` (`0x633dc90`): `1 / √(Σ d² / radius²)`, the radii squared cleared\n // from the denominators (`a`, `b`, `c` are x², y², z²).\n radiusAlong: (direction) => {\n const d = local(direction)\n const sum = d.x * d.x * c * b + d.z * d.z * b * a + d.y * d.y * c * a\n const product = a * (c * b) * sum\n\n return product > 1e-4 ? Math.sqrt(product) / sum : 0\n },\n }\n }\n\n if (shape.type === 'box') {\n const { x, y, z } = shape.size\n\n const along = (size: number, component: number) => {\n const magnitude = Math.abs(component)\n\n return magnitude > f(1e-4) ? size / magnitude : f(1e10)\n }\n\n return {\n ...own,\n position,\n radius: f(Math.sqrt(x * x + y * y + z * z) * 0.5),\n radiusAlong: (direction) => {\n const d = local(direction)\n\n return Math.min(f(along(x, d.x)), along(y, d.y), f(along(z, d.z))) * 0.5\n },\n }\n }\n\n // A cylinder's height is its `size` y and a ring's its z, and only the outer radius counts.\n const { radius } = shape\n const half = shape.height * 0.5\n const cutoff = half / Math.sqrt(radius * radius + half * half)\n\n return {\n ...own,\n position,\n radius: f(Math.sqrt(radius * radius + half * half)),\n radiusAlong: (direction) => {\n const d = local(direction)\n const y = Math.abs(d.y)\n\n return y > cutoff ? half / y : radius / Math.sqrt(d.x * d.x + d.z * d.z)\n },\n }\n}\n\n/** `FNebulaEffect::ZoneExteriorFactor`: 0 outside, rising to 1 a fog distance in from its surface. */\nexport const exteriorFactor = (zone: Zone, distance: number, point: Vector3): number => {\n const offset = sub(point, zone.position)\n const squared = f(offset.x * offset.x + offset.z * offset.z + offset.y * offset.y)\n if (squared > zone.radius * zone.radius) return 0\n if (squared < 0.1) return 1\n\n const length = Math.sqrt(squared)\n const edge = zone.radiusAlong(scaled(offset, 1 / length)) - f(length)\n if (edge < 0) return 0\n if (f(edge) > distance) return 1\n return f(f(edge) / distance)\n}\n\n/**\n * `ZONE::GetImmersion` (`0x633ac30`) for a zone `radiusAlong` describes, as a sphere is: 0 outside,\n * rising to 1 an edge fraction of the way in.\n */\nexport const immersion = (zone: Zone, edgeFraction: number, point: Vector3): number => {\n const offset = sub(point, zone.position)\n const squared = offset.x * offset.x + offset.z * offset.z + offset.y * offset.y\n if (zone.radius * zone.radius < squared) return 0\n\n // `ClassifyPoint`: how far out it is, over the reach that way.\n const length = Math.sqrt(offset.y * offset.y + offset.z * offset.z + offset.x * offset.x)\n let value = 0\n\n if (!(length < f(1e-4))) {\n const reach = zone.radiusAlong(scaled(offset, 1 / f(length)))\n\n value = reach > f(1e-4) ? f(length) / reach : 0\n }\n\n if (value >= 1) return 0\n if (1 - edgeFraction > f(value)) return 1\n if (edgeFraction < 1e-4) return 1\n return (1 - f(value)) / edgeFraction\n}\n\n/** The exclusion zone the camera is in, and its immersion there (`+0x24`, `+0x28`). */\nexport interface InExclusion {\n exclusion: NebulaExclusion\n immersion: number\n}\n\n// `sort`'s key: the squared distance from a zone's sphere, 0 inside.\nconst sortKey = ({ zone }: NebulaExclusion, eye: Vector3): number => {\n const offset = sub(eye, zone.position)\n const length = f(Math.sqrt(offset.y * offset.y + offset.z * offset.z + offset.x * offset.x))\n const distance = length - zone.radius\n\n return distance < 0 ? 0 : f(distance * distance)\n}\n\n/**\n * A nebula's `NebulaExclusionZoneMgr` as its clouds see it: the zones in the order its last sort left\n * them, each keyed by the camera's squared distance from it then. Before the first sort every key is\n * 1e7 (`NebulaExclusionZone`'s constructor), so nothing is in a zone. `FNebulaEffect::Update` sorts\n * only once the camera was in the nebula the frame before, so what it places on entering a system is\n * never hidden.\n */\nexport class ExclusionOrder {\n #sorted: { exclusion: NebulaExclusion; key: number }[]\n\n constructor(exclusions: readonly NebulaExclusion[]) {\n this.#sorted = exclusions.map((exclusion) => ({ exclusion, key: f(1e7) }))\n }\n\n /** `sort`, about `eye`. Equal keys keep their order, where retail's sort isn't stable. */\n sort(eye: Vector3): void {\n for (const entry of this.#sorted) entry.key = sortKey(entry.exclusion, eye)\n this.#sorted.sort((a, b) => a.key - b.key)\n }\n\n /** `is_in_exclusion_zone` for `point`: only zones keyed within 10 are asked. */\n at(point: Vector3): InExclusion | undefined {\n for (const { exclusion, key } of this.#sorted) {\n if (key > 10) return undefined\n\n const value = immersion(exclusion.zone, exclusion.edgeFraction ?? 0, point)\n if (value > f(1e-5)) return { exclusion, immersion: f(value) }\n }\n\n return undefined\n }\n}\n\n/**\n * `NebulaExclusionZoneMgr::is_in_exclusion_zone` for `point`, over the zones sorted around the camera:\n * only those within √10 of it are asked. Retail keeps the camera's zone while its immersion stays at\n * 1e-4 or more, and sorts now and then; this looks afresh each time, and an equal distance keeps\n * file order, where retail's sort isn't stable.\n */\nexport const exclusionAt = (\n exclusions: readonly NebulaExclusion[],\n eye: Vector3,\n point: Vector3 = eye,\n): InExclusion | undefined => {\n const sorted = exclusions\n .map((exclusion) => ({ exclusion, key: sortKey(exclusion, eye) }))\n .sort((a, b) => a.key - b.key)\n\n for (const { exclusion, key } of sorted) {\n if (key > 10) return undefined\n\n const value = immersion(exclusion.zone, exclusion.edgeFraction ?? 0, point)\n if (value > f(1e-5)) return { exclusion, immersion: f(value) }\n }\n\n return undefined\n}\n\n/** What `FNebulaEffect::Update` keeps from where the camera is, each frame. */\nexport interface NebulaState {\n nebula: SpaceNebula\n fogDistance: number\n /** `+0x294`: how deep the camera is, over the fog's whole span, up to 1. */\n depth: number\n /** `+0x2ac`, the fog's start. */\n start: number\n /** `+0x2b0`, the fog's end. */\n end: number\n /** How far the camera is outside its surface, negative inside (`Update`'s `D`). */\n surface: number\n /** Only while the camera is in the nebula. */\n inExclusion?: InExclusion\n}\n\n/** `FNebulaEffect::Update`'s depth and fog range. */\nexport const nebulaState = (\n nebula: SpaceNebula,\n eye: Vector3,\n limits: NebulaLimits = RETAIL_NEBULA_LIMITS,\n): NebulaState => {\n const { zone, fog } = nebula\n const near = f(fog.near ?? 0)\n const fogDistance = f(fog.distance ?? limits.nebulaFogDistance)\n const offset = sub(eye, zone.position)\n const length = f(Math.sqrt(offset.y * offset.y + offset.z * offset.z + offset.x * offset.x))\n const span = f(fogDistance + near)\n const surface = f(length - zone.radiusAlong(scaled(offset, 1 / length)))\n const depth = surface > 0 ? 0 : -surface > span ? 1 : f(-surface / span)\n\n if (depth > 0) {\n const state: NebulaState = { nebula, fogDistance, depth, start: near, end: span, surface }\n const inExclusion = exclusionAt(nebula.exclusions ?? [], eye)\n if (!inExclusion) return state\n\n // Its `fog_far` pulls the end towards it, as deep as the camera is in it.\n const { exclusion, immersion: by } = inExclusion\n const far = exclusion.fogFar ?? -1\n const end = by > 0 && far > near ? f((1 - by) * span + far * by) : span\n\n return { ...state, end, inExclusion }\n }\n\n // Outside, the fog's range follows the camera's distance from the surface.\n const start = surface + near\n\n return { nebula, fogDistance, depth, start: f(start), end: f(start + fogDistance), surface }\n}\n\n/** `FNebulaEffect::FogFactor`: where the fog ends for what stands at `point`. */\nexport const fogEnd = (state: NebulaState, point: Vector3): number => {\n if (state.inExclusion) {\n // From the fog's own span, out to the end, by how deep the point is in the camera's zone.\n const { zone, edgeFraction = 0 } = state.inExclusion.exclusion\n const by = immersion(zone, edgeFraction, point)\n const span = f(f(state.nebula.fog.near ?? 0) + state.fogDistance)\n\n return f((1 - by) * span + by * state.end)\n }\n\n const factor = exteriorFactor(state.nebula.zone, state.fogDistance, point)\n if (!(factor < 1)) return state.end\n return f(state.end / Math.max(factor * factor, f(1e-4)))\n}\n\n/** `FNebulaEffect::FogFarClamp`: the pass's far plane in its core, before the system's cuts it. */\nexport const fogFar = (state: NebulaState, limits: NebulaLimits = RETAIL_NEBULA_LIMITS): number => {\n const sum = state.end + limits.nebulaFarMargin\n const far = sum < limits.nebulaLeastFar ? limits.nebulaLeastFar : f(sum)\n if (!state.inExclusion) return far\n\n // At least across the camera's zone and a margin.\n const { radius } = state.inExclusion.exclusion.zone\n const least = radius + radius + limits.exclusionFarMargin\n\n return far > least ? far : f(least)\n}\n\n// `FogApplyColorAndRange`: each channel to a byte, by truncation.\nconst byte = (value: number) => unitByte(value) / 255\n\n/** The fog `FogApplyColorAndRange` sets, in `colour` or the nebula's own. */\nexport const fogOf = (start: number, end: number, color: Vector3): Fog => ({\n color: { x: byte(color.x), y: byte(color.y), z: byte(color.z) },\n start,\n end,\n})\n\n/** The nebula a point is in, and how far, from 0 to 1: `Gameobj`'s `+0x38` and `+0x3c`. */\nexport interface Within {\n state: NebulaState\n factor: number\n}\n\n/** `StarSysFindNebula` (`0x5553b0`): the `hint` if it holds `point`, or the first that does. */\nexport const findNebula = (\n nebulae: readonly NebulaState[],\n point: Vector3,\n hint?: SpaceNebula,\n): Within | undefined => {\n const hinted = hint && nebulae.find((state) => state.nebula === hint)\n\n for (const state of hinted ? [hinted, ...nebulae] : nebulae) {\n const factor = exteriorFactor(state.nebula.zone, state.fogDistance, point)\n if (factor > 0) return { state, factor }\n }\n\n return undefined\n}\n\n/** The nebula the camera answers to (`DAT_00675244`), and how far it's in. */\nexport interface SpaceField {\n state: NebulaState\n /** `DAT_0067524c`: 0 outside it, 1 in its edge, 2 in its core. */\n enclosure: 0 | 1 | 2\n}\n\n// The distance by one Newton step from `0x5f3759df`, as `SelectFieldControllers` has it.\nconst roughLength = (squared: number): number => f(inverseRoot(squared) * squared)\n\n/** A nebula `SelectFieldControllers` leaves to the far list (`ZItemNebula`), keyed by its score. */\nexport interface DeferredNebula {\n state: NebulaState\n key: number\n}\n\n/** The camera's field, and every other nebula, drawn from the far list. */\nexport interface NebulaList {\n field?: SpaceField\n deferred: DeferredNebula[]\n}\n\n/**\n * `SelectFieldControllers` (`0x51b730`): the first nebula the camera is in, taking a core over an\n * edge, or else the one whose surface is nearest within `range`. Each other nebula is deferred with\n * the squared distance to its surface, however far, and a field it replaces with the best score.\n * In a core, none is (`ClearBuckets`, `0x51b9c7`).\n */\nexport const listNebulae = (\n nebulae: readonly NebulaState[],\n eye: Vector3,\n range: number,\n): NebulaList => {\n let best = f(range * range)\n let field: SpaceField | undefined\n const deferred: DeferredNebula[] = []\n\n for (const state of nebulae) {\n const { zone } = state.nebula\n const dx = zone.position.x - eye.x\n const dy = zone.position.y - eye.y\n const dz = zone.position.z - eye.z\n const squared = dx * dx + dy * dy + dz * dz\n const distance = roughLength(squared)\n const inverse = f(1 / distance)\n const hit = f(zone.radiusAlong({ x: f(inverse * dx), y: f(inverse * dy), z: f(inverse * dz) }))\n const score = distance <= hit ? 0 : f((distance - hit) * (distance - hit))\n\n if (field && field.enclosure !== 0) {\n deferred.push({ state, key: score })\n continue\n }\n\n const enclosed = exteriorFactor(zone, state.fogDistance, eye)\n if (enclosed >= 1) return { field: { state, enclosure: 2 }, deferred: [] }\n\n if (enclosed > 0) {\n if (field) deferred.push({ state: field.state, key: best })\n field = { state, enclosure: 1 }\n } else if (score < best) {\n if (field) deferred.push({ state: field.state, key: best })\n best = score\n field = { state, enclosure: 0 }\n } else deferred.push({ state, key: score })\n }\n\n return { ...(field && { field }), deferred }\n}\n\n/** `listNebulae`'s field alone. */\nexport const pickField = (\n nebulae: readonly NebulaState[],\n eye: Vector3,\n range: number,\n): SpaceField | undefined => listNebulae(nebulae, eye, range).field\n","/**\n * Whether the game draws an effect, keeps running it unseen, or ends it: `EffectTypeBucketWalk` and\n * `FParticleEffect::UpdateVisibility` (`0x4f86c0`) in `src/freelancer/Client/`. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Camera } from './camera.js'\nimport { findNebula, type NebulaState, type SpaceField, type SpaceNebula } from './nebula.js'\n\n/** An `[EffectType]` row, each key over its built-in one. */\nexport interface EffectType {\n priority: number\n /** `generic_priority`, for an effect drawn through its generic appearance. */\n genericPriority: number\n /** `lod_type`: which `[EffectLOD]` row, 1 to 6. 0 is none. */\n lodType: number\n radius: number\n /** `visibility = EXIST_OFFSCREEN`: unseen, it runs on instead of ending. */\n existOffscreen: boolean\n /** `update = UPDATE_OFFSCREEN`: unseen, its effect still steps (`0x4f8ae9`). */\n updateOffscreen: boolean\n /** `pbubble`: past near, how far it shows narrows from far by `generic_effect_perf`. */\n pbubble: { near: number; far: number }\n /**\n * `run_time`: seconds it runs before it ends, counted down as it's walked (`0x4f8a57`). Under 0,\n * until its effect ends; killed, at most 1 more (`0x4f8680`).\n */\n runTime: number\n}\n\n// Nickname order, which `SpaceEffect.type` indexes: priority, generic priority, lod type, radius,\n// EXIST_OFFSCREEN, pbubble near and far.\n// prettier-ignore\nconst ROWS: readonly (readonly [number, number, number, number, 0 | 1, number, number])[] = [\n [0, 0, 0, 10, 0, 100, 500], [1, 0.5, 3, 10, 0, 100, 500], [1, 0.5, 4, 50, 1, 100, 500],\n [1, 0.5, 5, 100, 1, 100, 500], [0, 0, 3, 10, 0, 100, 500], [1, 0.5, 4, 50, 0, 100, 500],\n [0, 0, 6, 7.5, 0, 100, 500], [0, 0, 6, 7.5, 0, 100, 500], [0, 0, 6, 5, 0, 100, 500],\n [1, 0.5, 6, 7.5, 0, 100, 500], [0.5, 0.5, 2, 100, 1, 100, 500], [1, 0.5, 2, 15, 1, 100, 500],\n [1, 0.5, 5, 50, 1, 100, 500], [0.5, 0.5, 6, 7.5, 0, 100, 500], [1, 0.5, 4, 20, 0, 100, 500],\n [1, 0.5, 6, 7.5, 0, 100, 500], [1, 0.5, 4, 20, 0, 100, 500], [0.5, 0.5, 6, 7.5, 0, 100, 500],\n [1, 0.5, 5, 100, 0, 100, 500], [0.5, 0.5, 3, 5, 0, 100, 500], [0.5, 0.5, 6, 7.5, 0, 100, 500],\n [0.5, 0.5, 4, 20, 1, 100, 500], [0.5, 0.5, 5, 20, 1, 100, 500], [0.5, 0.5, 3, 5, 1, 100, 500],\n [0, 0, 3, 5, 1, 100, 500], [1, 0.5, 1, 100, 1, 100, 500], [1, 0.5, 1, 100, 1, 500, 2000],\n [0.5, 0.5, 6, 7.5, 1, 100, 500], [0.5, 0.5, 6, 25, 1, 250, 1000], [0, 0, 6, 7.5, 1, 100, 500],\n [1, 0.5, 3, 5, 0, 100, 500], [1, 0.5, 4, 100, 0, 500, 1500], [1, 0.5, 5, 100, 1, 100, 500],\n [1, 0.5, 5, 500, 1, 1000, 5000], [1, 0.5, 5, 500, 1, 1000, 5000], [0.5, 0.5, 0, 500, 1, 100, 500],\n [1, 1, 0, 500, 1, 100, 500], [1, 0.5, 0, 0, 1, 100, 500], [1, 0.5, 0, 0, 1, 1000, 2500],\n [0.5, 0.5, 0, 50, 1, 100, 500], [1, 0.5, 0, 50, 1, 100, 500], [0.5, 0.5, 4, 50, 0, 100, 500],\n [0.5, 0.5, 4, 50, 1, 100, 500], [0, 0, 5, -1, 0, 100, 500], [1, 0.5, 2, 15, 1, 100, 500],\n [1, 1, 0, -1, 1, 100, 500], [1, 1, 0, -1, 1, 100, 500],\n]\n\n// `UPDATE_OFFSCREEN` by row (`+0x15` of each), read from the unpacked `Freelancer.exe`.\nconst UPDATE_OFFSCREEN = new Set([2, 3, 24, 25, 26, 35, 36, 37, 38, 45])\n\n// `run_time` by row: 15, or -1 where it lasts (`.data` `0x612a80`, `+0x18` of each row).\nconst NO_RUN_TIME = new Set([\n 10, 11, 12, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 42,\n 44, 45, 46,\n])\n\n/** Each row's nickname, which an `[Effect]`'s `effect_type` and an `[EffectType]` name. */\nexport const EFFECT_TYPE_NAMES: readonly string[] = [\n 'EFT_NONE',\n 'EFT_EXPLOSION_SMALL',\n 'EFT_EXPLOSION_MEDIUM',\n 'EFT_EXPLOSION_LARGE',\n 'EFT_EXPLOSION_DEBRIS',\n 'EFT_EXPLOSION_SHIP',\n 'EFT_EXPLOSION_MISSILE',\n 'EFT_EXPLOSION_MINE',\n 'EFT_MUZZLE_FLASH',\n 'EFT_MUZZLE_LARGE_FLASH',\n 'EFT_MISSILE_DRIVE',\n 'EFT_WEAPON_PROJ',\n 'EFT_WEAPON_LARGE_PROJ',\n 'EFT_WEAPON_IMPACT',\n 'EFT_WEAPON_LARGE_IMPACT',\n 'EFT_WEAPON_COUNTER_MEASURE',\n 'EFT_WEAPON_MINE',\n 'EFT_DAMAGE_HULL',\n 'EFT_DAMAGE_LARGE_SHIELD',\n 'EFT_DAMAGE_SHIELD',\n 'EFT_DAMAGE_CRUISE',\n 'EFT_DAMAGE_SMOKE',\n 'EFT_DAMAGE_LARGE_SMOKE',\n 'EFT_DEBRIS_TRAIL',\n 'EFT_ENGINE_CONTRAIL',\n 'EFT_ENGINE_TRAIL',\n 'EFT_ENGINE_LARGE_TRAIL',\n 'EFT_ENGINE_FIRE',\n 'EFT_ENGINE_LARGE_FIRE',\n 'EFT_ENGINE_THRUSTER',\n 'EFT_EQUIP_CLOAK',\n 'EFT_EQUIP_LARGE_CLOAK',\n 'EFT_EQUIP_ATTACHED',\n 'EFT_EQUIP_ATTACHED_LARGE',\n 'EFT_EQUIP_ATTACHED_INSANELY_LARGE',\n 'EFT_MISC_DUST',\n 'EFT_MOTION_DUST',\n 'EFT_JUMP_EFFECTS',\n 'EFT_JUMP_GATE_EFFECTS',\n 'EFT_LANE_ACTIVE',\n 'EFT_LANE_TUBE',\n 'EFT_LANE_SHIP',\n 'EFT_LANE_SHIP_TRAVEL',\n 'EFT_CUSTOM_EFFECTS',\n 'EFT_CODE_PROJ_EFFECT',\n 'EFT_TRACTORBEAM',\n 'EFT_FLASHLIGHT',\n]\n\n/**\n * An `effect_type` or `[EffectType]` nickname as `SpaceEffect.type` takes it: case and all, as\n * `EffectTypeIndexFromName` (`0x4fd500`) compares. `undefined` for a name not in the table.\n */\nexport const effectTypeIndex = (name: string): number | undefined => {\n const at = EFFECT_TYPE_NAMES.indexOf(name)\n\n return at < 0 ? undefined : at\n}\n\nconst LOD_TYPE_NAMES = ['trail', 'weapon', 'small', 'medium', 'large', 'small_distant']\n\n/**\n * An `[EffectType]`'s `lod_type`, `EFT_LOD_TRAIL` to `EFT_LOD_SMALL_DISTANT`, as 1 to 6: any case\n * (`LoadEffectTypeSection`). `undefined` for any other, which leaves the row's as it was.\n */\nexport const effectLodType = (name: string): number | undefined => {\n const at = LOD_TYPE_NAMES.findIndex((lod) => `eft_lod_${lod}` === name.toLowerCase())\n\n return at < 0 ? undefined : at + 1\n}\n\n/**\n * An `[EffectLOD]`'s `type`, `lod_type_trail` to `lod_type_small_distant`, as the row of\n * `effectLods` it fills, 1 to 6: any case (`LoadEffectLodSection`, `0x42dae0`).\n */\nexport const effectLodRow = (name: string): number | undefined => {\n const at = LOD_TYPE_NAMES.findIndex((lod) => `lod_type_${lod}` === name.toLowerCase())\n\n return at < 0 ? undefined : at + 1\n}\n\n/** `EFT_NONE` to `EFT_FLASHLIGHT`, the table `[EffectType]` overlays (`.data` `0x612a68`). */\nexport const RETAIL_EFFECT_TYPES: readonly Readonly<EffectType>[] = ROWS.map(\n ([priority, genericPriority, lodType, radius, existOffscreen, near, far], index) => ({\n priority,\n genericPriority,\n lodType,\n radius,\n existOffscreen: existOffscreen === 1,\n updateOffscreen: UPDATE_OFFSCREEN.has(index),\n pbubble: { near, far },\n runTime: NO_RUN_TIME.has(index) ? -1 : 15,\n }),\n)\n\n/** An `[EffectLOD]` row: how large on screen, in pixels, it fades in over, and the least it shows at. */\nexport interface EffectLodSizes {\n maxLodScreenSize: number\n minLodScreenSize: number\n minScreenSize: number\n}\n\n/** What the retail effect is drawn under, besides the camera. */\nexport interface EffectViewOptions {\n /** The `generic_effect_perf` option, 0 to 1. 1 when absent: every priority shows, to `pbubble`'s far. */\n effectDetail?: number\n /** Over `RETAIL_EFFECT_TYPES`, by index. */\n effectTypes?: readonly (Partial<EffectType> | undefined)[]\n /** `[EffectLOD]` rows by `lod_type`, 1 to 6. None when absent, as the static initialiser's -1s. */\n effectLods?: readonly (EffectLodSizes | undefined)[]\n /** The viewport's width in pixels, which the LOD's screen size reads. No LOD when absent. */\n viewportWidth?: number\n}\n\n/** A placed effect, as the view test asks of it. */\nexport interface PlacedEffect {\n type: number\n /** Where it is: its world transform's translation. */\n position: Vector3\n /** Drawn through its `[Effect]`'s generic appearance, which has its own priority. */\n generic?: boolean\n /** The ship or solar it's on. */\n watched?: {\n position: Vector3\n /** Its cloak, 0 to 1. At 1 the effect hides. */\n cloak?: number\n /** The nebula it was last in, tried first. */\n nebula?: SpaceNebula\n }\n}\n\n/**\n * `draw`: seen. `run`: unseen, and `EXIST_OFFSCREEN`. `die`: unseen, and frozen in place to end.\n * `hold`: not walked this frame, so neither drawn nor stepped, as in a gate tunnel.\n */\nexport interface EffectView {\n fate: 'draw' | 'run' | 'die' | 'hold'\n /** The `ALCHEMY_LOD` blend, 0 to 1, for its next step's `lod`. */\n lod: number\n}\n\n// `EffectLodRowBlend` (`0x42da00`): undefined when it's too small to show.\nconst lodBlend = (row: EffectLodSizes, radius: number, distance: number, xScale: number) => {\n if (distance < 1e-5) return 1\n\n // `size` is the radius in pixels; the blend is where it falls between the row's two LOD sizes.\n const size = (radius / distance) * xScale\n if (!(size > row.minScreenSize)) return undefined\n\n const blend = (size - row.minLodScreenSize) / (row.maxLodScreenSize - row.minLodScreenSize)\n if (blend > 1) return 1\n return Math.fround(blend < 0 ? 0 : blend)\n}\n\n/** The camera's place in the frame: its view, its nebula, and the system's nebulae. */\nexport interface EffectViewFrame {\n camera: Camera\n aspect: number\n view: Matrix4\n field?: SpaceField\n nebulae: readonly NebulaState[]\n}\n\n/**\n * `UpdateVisibility` and what `EffectTypeBucketWalk` does with it. The game keeps last frame's answer\n * where it doesn't test, but clears it once an effect draws, so that answer is taken as unseen.\n */\nexport const viewEffect = (\n { type, position, generic = false, watched }: PlacedEffect,\n { camera, aspect, view, field, nebulae }: EffectViewFrame,\n { effectDetail = 1, effectTypes = [], effectLods = [], viewportWidth }: EffectViewOptions = {},\n): EffectView => {\n const info: EffectType = { ...RETAIL_EFFECT_TYPES[type]!, ...effectTypes[type] }\n const unseen: EffectView = { fate: info.existOffscreen ? 'run' : 'die', lod: 1 }\n const perf = Math.fround(1 - effectDetail)\n\n if (watched) {\n if ((watched.cloak ?? 0) >= 1) return unseen\n\n if (field) {\n const within = findNebula(nebulae, watched.position, watched.nebula)\n\n if (!within) {\n if (field.enclosure === 2) return unseen\n } else {\n if (within.state !== field.state) return unseen\n\n // `G_FieldRadiusSq`: the fog's end in the edge or core, and 0 from outside.\n const radius = field.enclosure === 0 ? 0 : field.state.end\n const dx = Math.fround(position.x - camera.position.x)\n const dy = Math.fround(position.y - camera.position.y)\n const dz = Math.fround(position.z - camera.position.z)\n if (dz * dz + dy * dy + dx * dx > Math.fround(radius * radius)) return unseen\n }\n }\n }\n\n if (!((generic ? info.genericPriority : info.priority) >= perf)) return unseen\n\n const { radius } = info\n const at = Matrix4.transformPoint(position, view)\n const depth = Math.fround(-at.z)\n if (!(camera.near < Math.fround(depth + radius))) return unseen\n\n const { near, far } = info.pbubble\n if (!((far - near) * (1 - perf) + near > depth - radius)) return unseen\n\n let lod = 1\n const row = info.lodType > 0 && info.lodType < 7 ? effectLods[info.lodType] : undefined\n\n if (row && viewportWidth !== undefined) {\n // `XScale`, half the viewport over tan(fovx½).\n const xScale = Math.fround(viewportWidth / 2 / Math.tan((camera.fovh * Math.PI) / 180))\n const blend = lodBlend(row, radius, depth, xScale)\n if (blend === undefined) return { ...unseen, lod: 0 }\n lod = blend\n }\n\n return withinSides(at, camera, aspect, radius) ? { fate: 'draw', lod } : { ...unseen, lod }\n}\n\n/** A sphere at a place in view space against the side planes, as `ClassifySphere` has them. */\nexport const withinSides = (\n at: Vector3,\n camera: Camera,\n aspect: number,\n radius: number,\n): boolean => {\n const tanX = Math.tan((camera.fovh * Math.PI) / 180)\n const tanY = tanX / aspect\n const sideX = (Math.abs(at.x) + tanX * at.z) / Math.hypot(1, tanX)\n const sideY = (Math.abs(at.y) + tanY * at.z) / Math.hypot(1, tanY)\n\n return sideX <= radius && sideY <= radius\n}\n","/**\n * A planet's ring seen from outside: `PlanetaryRings::PlanetRing`, `src/freelancer/Client/\n * texture_panels.cpp`. A flat band between its zone's two radii, cut into eight pieces that join the\n * space frame's lists like objects. Its `[Clouds]`, seen from inside, aren't built. Pure, no GL.\n */\nimport { Matrix3, Matrix4, type RingShape, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER, type SamplerState } from '#/texture/texture.js'\nimport type { Clouds } from './clouds.js'\nimport type { Draw } from './frame.js'\n\nconst f = Math.fround\n\n/** A `[Shape]`'s rectangle in its texture, as UVs. */\nexport interface TextureShape {\n texture: Texture\n u0: number\n v0: number\n u1: number\n v1: number\n}\n\n// `DAT_005c99c8`: a hundredth of a pixel in from each edge, so an atlas's neighbours don't bleed.\nconst UV_INSET = f(0.01)\n\n/**\n * `TexShapeSetRect` (`0x4256c0`): a `[Shape]`'s `x`, `y`, `w` and `h` in `texture`'s pixels. A corner\n * of 1 or less is a fraction of the texture, and so is an extent; a zero extent is all of it.\n */\nexport const textureShape = (\n texture: Texture,\n { x = 0, y = 0, w = 0, h = 0 }: { x?: number; y?: number; w?: number; h?: number },\n): TextureShape => {\n const width = f(texture.width)\n const height = f(texture.height)\n\n if (x <= 1 && y <= 1) {\n x = f(width * x)\n y = f(height * y)\n }\n\n if (w === 0 || h === 0) {\n w = width\n h = height\n } else if (w <= 1 && h <= 1) {\n w = f(width * w)\n h = f(height * h)\n }\n\n const right = f(x + w)\n const bottom = f(y + h)\n\n return {\n texture,\n u0: f(f(x + UV_INSET) / width),\n v0: f(f(y + UV_INSET) / height),\n u1: f(f(right - UV_INSET) / width),\n v1: f(f(bottom - UV_INSET) / height),\n }\n}\n\n/** A ring file's `[Exterior]`, over `PlanetRing::Load`'s defaults. The host reads the INI. */\nexport interface RingExterior {\n /** `shape`. Without one the ring draws nothing. */\n shape?: TextureShape\n /** `detail_shape`, on the second UV set. */\n detail?: TextureShape\n /** `detail_tile` as written: the detail's V at the inner edge, then its U on odd segments. */\n detailTile?: readonly [number, number]\n /** `color` over 255. Kept from the last ring loaded when absent: black here. */\n color?: Vector3\n /** 1 when absent, and halved without a detail shape. */\n opacity?: number\n /** `num_segments`, 32 when absent. */\n segments?: number\n /** `transition_dist`, 150 when absent: how far past its edges its immersion fades. */\n transitionDistance?: number\n}\n\nexport interface RingOptions {\n /** `high_detail_textures`: under 0.4 the detail shape is dropped (`0x50ac65`). 1 when absent. */\n highDetailTextures?: number\n}\n\n/** A run of segments drawn as one, and the sphere about its vertices that the view tests. */\nexport interface RingPiece {\n first: number\n last: number\n center: Vector3\n radius: number\n /** Its strip, in world space. */\n mesh: VMeshData\n reference: VMeshRef\n}\n\nexport interface PlanetRing {\n pieces: RingPiece[]\n shape?: TextureShape\n detail?: TextureShape\n zone: RingShape\n transitionDistance: number\n /** Its `[Clouds]`, which the host makes with `RING_CLOUD_VISIBILITY` and its own `rand()`. */\n clouds?: readonly Clouds[]\n}\n\n// `DAT_005c97f8`, the float 2π as a double, and `DAT_005db098`.\nconst TWO_PI = 6.2831854820251465\nconst LAST_BIAS = f(1e-4)\nconst PIECES = 8\n\n// XYZ, D3DCOLOR and two UV sets: FVF 0x242, 32 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 2)\nconst STRIDE = 32\n\n/** The zone's frame, as `ZoneToTransform` gives it: `R · v + t`. */\nconst zoneTransform = ({ center, orientation }: RingShape): Matrix4 =>\n Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(orientation), center)\n\n/**\n * `PlanetRing::Load`'s mesh (`0x50a8d3` on): a vertex at the outer radius and one at the inner for\n * each segment, then eight pieces of them, each with the box's sphere. And `DrawPiece`'s strip for\n * each (`0x50b77e`): the shape's left edge on even segments and its right on odd, its top at the\n * outer radius and its bottom at the inner, in the colour and opacity, all in world space.\n */\nexport const buildRing = (\n exterior: RingExterior,\n zone: RingShape,\n { highDetailTextures = 1 }: RingOptions = {},\n): PlanetRing => {\n const segments = Math.trunc(exterior.segments ?? 32)\n const { shape } = exterior\n const detail = highDetailTextures >= 0.4 ? exterior.detail : undefined\n // `0x50ace5`: with any texture and no detail shape, the opacity is halved.\n const opacity = f(\n (exterior.opacity ?? 1) * (detail === undefined && (shape || exterior.detail) ? 0.5 : 1),\n )\n const transform = zoneTransform(zone)\n const outer = f(zone.radius)\n const inner = f(zone.innerRadius)\n\n const count = segments * 2\n const positions: Vector3[] = []\n const step = f(TWO_PI / segments)\n let angle = 0\n\n for (let segment = 0; segment < segments; segment++) {\n const sin = Math.sin(angle)\n const cos = Math.cos(angle)\n\n const at = (radius: number) => {\n const { x, y, z } = Matrix4.transformPoint(\n { x: f(sin * radius), y: 0, z: f(radius * cos) },\n transform,\n )\n\n return { x: f(x), y: f(y), z: f(z) }\n }\n\n positions.push(at(outer), at(inner))\n angle = f(angle + step)\n }\n\n // Wraps past the last segment back to the first, so the final piece closes the ring.\n const vertex = (index: number) => positions[index >= count ? index - count : index]!\n\n const color = exterior.color ?? { x: 0, y: 0, z: 0 }\n // `ftol` truncates, and only the low byte is kept.\n const bytes = [color.z, color.y, color.x, opacity].map((c) => Math.trunc(c * 255) & 0xff)\n const [tileV, tileU] = [\n f(exterior.detailTile?.[0] ?? 10),\n Math.trunc(exterior.detailTile?.[1] ?? 2),\n ]\n\n const span = f(segments / PIECES)\n let end = 0\n let previous = 0\n const pieces: RingPiece[] = []\n\n for (let index = 0; index < PIECES; index++) {\n // Pieces end at multiples of `segments / 8`, each starting on the last one's end segment.\n end += span\n\n const first = previous\n const last = Math.trunc(LAST_BIAS + end)\n\n previous = last\n\n const corners = Array.from({ length: (last - first + 1) * 2 }, (_, at) =>\n vertex(first * 2 + at),\n )\n const min = { x: Infinity, y: Infinity, z: Infinity }\n const max = { x: -Infinity, y: -Infinity, z: -Infinity }\n\n for (const point of corners)\n for (const axis of ['x', 'y', 'z'] as const) {\n min[axis] = Math.min(min[axis], point[axis])\n max[axis] = Math.max(max[axis], point[axis])\n }\n\n const center = {\n x: f((max.x + min.x) * 0.5),\n y: f((max.y + min.y) * 0.5),\n z: f((max.z + min.z) * 0.5),\n }\n const radius = f(Math.hypot(max.x - center.x, max.y - center.y, max.z - center.z))\n\n const vertices = new Uint8Array(corners.length * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n // Strip order: outer then inner vertex per segment. Per vertex: xyz at byte 0, BGRA at 12, uv0 at\n // 16, uv1 at 24; U flips left/right by segment parity, V top/bottom by outer/inner.\n corners.forEach((point, at) => {\n const segment = first + (at >> 1)\n const odd = (segment & 1) !== 0\n const outerEdge = (at & 1) === 0\n\n floats.set([point.x, point.y, point.z], (at * STRIDE) / 4)\n vertices.set(bytes, at * STRIDE + 12)\n floats.set(\n [\n odd ? (shape?.u1 ?? 0) : (shape?.u0 ?? 0),\n outerEdge ? (shape?.v0 ?? 0) : (shape?.v1 ?? 0),\n odd ? tileU : 0,\n outerEdge ? 0 : tileV,\n ],\n (at * STRIDE + 16) / 4,\n )\n })\n\n const mesh: VMeshData = {\n name: `ring piece ${index}`,\n version: 1,\n primitive: Primitive.TriangleStrip,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: corners.length - 1,\n elementCount: corners.length,\n padding: 0,\n },\n ],\n indices: Uint16Array.from(corners, (_, at) => at),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: corners.length,\n indexStart: 0,\n indexCount: corners.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min, max },\n boundingSphere: { center, radius },\n }\n\n pieces.push({ first, last, center, radius, mesh, reference })\n }\n\n return {\n pieces,\n zone,\n transitionDistance: f(exterior.transitionDistance ?? 150),\n ...(shape ? { shape } : {}),\n ...(detail ? { detail } : {}),\n }\n}\n\n/**\n * `PlanetRing::GetImmersion` (`0x50bd70`): 1 within the band, ramping to 0 over `transition_dist`\n * past its radii and past its height. Retail takes the zone's `size` z as the half height here, so\n * `zone.height` is that value as written.\n */\nexport const ringImmersion = (\n { zone, transitionDistance }: Pick<PlanetRing, 'zone' | 'transitionDistance'>,\n point: Vector3,\n): number => {\n const outer = f(zone.radius)\n const inner = f(zone.innerRadius)\n const half = f(zone.height)\n const outerSquared = f(outer * outer)\n const innerSquared = f(inner * inner)\n const softOuter = f((outer + transitionDistance) * (outer + transitionDistance))\n const softInner = f((inner - transitionDistance) * (inner - transitionDistance))\n const local = Matrix4.transformPoint(point, Matrix4.invert(zoneTransform(zone)))\n const y = Math.abs(local.y)\n let factor = 1\n\n if (!(y < half)) {\n const ramp = 1 - (y - half) / transitionDistance\n\n factor = f(ramp)\n if (!(ramp > 0)) return 0\n }\n\n const radial = local.x * local.x + local.z * local.z\n const radialF = f(radial)\n\n if (radial > softOuter) return 0\n if (radialF > outerSquared) return ((softOuter - radialF) / (softOuter - outerSquared)) * factor\n if (radialF > innerSquared) return factor\n if (radialF > softInner) return ((radialF - softInner) / (innerSquared - softInner)) * factor\n return 0\n}\n\n// `DrawPiece`'s `0x4223d0` and `0x422410` set stage 0's `ADDRESSU` and `ADDRESSV` (13 and 14) to\n// clamp, then wrap: the decomp takes them for filters. Stage 1's addressing and both filters are the\n// device's as the frame left them: `ring_outside` captures both stages wrapping, linear, mips point.\nconst RING_SAMPLER: SamplerState = { ...DEFAULT_SAMPLER, wrapU: 'repeat', wrapV: 'repeat' }\n\nconst BLACK = { x: 0, y: 0, z: 0 }\n\n/**\n * `DrawPiece` (`0x50b510`): a piece's strip, unlit, in its vertex colour times the shape, the detail\n * doubling it, blended over what's there with `LEQUAL` and no depth writes or culling. Nothing\n * without a shape. Its alpha test and fog are whatever the frame left on: `ring_outside` captures\n * `GREATER 0` and no fog, outside a nebula. In one, the last object's fog may still be on: uncaptured.\n */\nexport const ringPieceDraw = (ring: PlanetRing, piece: RingPiece): Draw | undefined => {\n const { shape, detail } = ring\n if (!shape) return undefined\n return {\n mesh: piece.mesh,\n reference: piece.reference,\n byteOffset: 0,\n count: piece.reference.indexCount,\n world: Matrix4.identity,\n materialName: 'ring',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: { name: shape.texture.name, entry: shape.texture, sampler: RING_SAMPLER, uvSet: 0 },\n ...(detail\n ? {\n second: {\n operation: 'modulate2x' as const,\n texture: {\n name: detail.texture.name,\n entry: detail.texture,\n sampler: RING_SAMPLER,\n uvSet: 1,\n },\n },\n }\n : {}),\n cull: 'none',\n depthWrite: false,\n depthFunc: 'lequal',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'alpha',\n unlit: true,\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n","/**\n * An asteroid field's cubes: one mesh of its `[Cube]` asteroids, drawn at every cube of a grid near\n * the camera that the zone holds, no exclusion zone takes, and its id doesn't leave empty, each\n * turned by its id. `CliAsteroidDrawNearField` (`FUN_00522a60`) and `CliAsteroidMergeCubeMesh` in\n * `src/freelancer/Client/cli_asteroid.cpp`; the grid, ids and rotations are Common's\n * (`common_casteroid.cpp`, `common_casteroidfield.cpp`). Deterministic. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n getMeshDraw,\n Primitive,\n setMapCount,\n vertexByteLength,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { vertexLayout } from '#/mesh/plan.js'\nimport type { AsteroidBand } from './band.js'\nimport type { AsteroidBillboards } from './billboards.js'\nimport type { Camera } from './camera.js'\nimport type { DynamicAsteroids } from './dynamic.js'\nimport type { SceneModel } from './frame.js'\nimport { immersion, type Zone } from './nebula.js'\n\nconst f = Math.fround\n\n/** Each axis's four angles in radians, `[Cube]`'s `xaxis_rotation` and the rest. */\nexport type CubeRotations = readonly [readonly number[], readonly number[], readonly number[]]\n\n/** `CAsteroidField`'s constructor: quarter turns about each axis. */\nexport const RETAIL_CUBE_ROTATIONS: CubeRotations = [0, 1, 2].map(() => [\n 0,\n f(1.5707963),\n f(3.14159265),\n f(4.71238898),\n]) as unknown as CubeRotations\n\n// `DAT_0639d210`, the degrees-to-radians every angle here is read with.\nconst DEGREES = f(0.017453292)\n\n/** `xaxis_rotation` and its kin as written, in degrees, to `CubeRotations`. */\nexport const cubeRotations = (degrees: readonly (readonly number[])[]): CubeRotations =>\n degrees.map((axis) => axis.map((value) => f(value * DEGREES))) as unknown as CubeRotations\n\n/** The nudge and `ftol` Common snaps each coordinate with: 0.1 away from zero, then truncated. */\nconst nudge = (value: number): number => Math.trunc(value > 0 ? value + f(0.1) : value - f(0.1))\n\n/** `closest_cube_coord` (`0x42ff0`): a cube's centre on one axis. */\nconst cubeCoord = (coord: number, size: number): number => {\n const half = Math.trunc((size + 1) * 0.5)\n const step = Math.trunc(coord / size) * size\n\n return coord > 0 ? step + half : step - half\n}\n\n/** `CAsteroidField::closest_cube_pos` (`0x45ee0`). */\nexport const closestCubePosition = ({ x, y, z }: Vector3, size: number): Vector3 => ({\n x: cubeCoord(nudge(x), size),\n y: cubeCoord(nudge(y), size),\n z: cubeCoord(nudge(z), size),\n})\n\n/** `compute_cube_id` (`0x62a6010`): 0 for a position past the grid. */\nexport const cubeId = ({ x, y, z }: Vector3): number => {\n const [nx, ny, nz] = [nudge(x), nudge(y), nudge(z)]\n let gx = Math.abs(nx) >>> 7\n let gy = Math.abs(ny) >>> 7\n let gz = Math.abs(nz) >>> 7\n if (gx >= 0x400 || gy >= 0x200 || gz >= 0x400) return 0\n // Packed `x:11 | z:11 | y:10` bits: each axis a 128-unit cell count with its sign on top.\n if (nx < 0) gx |= 0x400\n if (nz < 0) gz |= 0x400\n if (ny < 0) gy |= 0x200\n return ((gz << 10) | gy | (gx << 21)) >>> 0\n}\n\n/** Rotations about X, then Y, then Z: `Rz · Ry · Rx`, as Common composes them row by row. */\nconst rotationOf = (ax: number, ay: number, az: number): Matrix4 => {\n const c = (angle: number) => f(Math.cos(angle))\n const s = Math.sin\n // Rows of `R`, applied as `R · v`.\n let rows = [\n [1, 0, 0],\n [0, 1, 0],\n [0, 0, 1],\n ]\n\n // Rotates rows `i` and `j` of `rows` in their plane, which left-multiplies the matrix.\n const turn = (i: number, j: number, angle: number, sign: 1 | -1) => {\n const [ci, si] = [c(angle), s(angle)]\n\n rows = rows.map((row) => [...row])\n\n for (let col = 0; col < 3; col++) {\n const a = rows[i]![col]!\n const b = rows[j]![col]!\n\n rows[i]![col] = f(a * ci - sign * b * si)\n rows[j]![col] = f(b * ci + sign * a * si)\n }\n }\n\n turn(1, 2, ax, 1)\n turn(0, 2, ay, -1)\n turn(0, 1, az, 1)\n\n const [r0, r1, r2] = rows as [number[], number[], number[]]\n\n return {\n x: { x: r0[0]!, y: r1[0]!, z: r2[0]!, w: 0 },\n y: { x: r0[1]!, y: r1[1]!, z: r2[1]!, w: 0 },\n z: { x: r0[2]!, y: r1[2]!, z: r2[2]!, w: 0 },\n w: { x: 0, y: 0, z: 0, w: 1 },\n }\n}\n\n/** An `asteroid =` line's turn, its three angles in degrees as written. */\nexport const entryOrientation = (x: number, y: number, z: number): Matrix4 =>\n rotationOf(x * DEGREES, y * DEGREES, z * DEGREES)\n\n/**\n * `compute_cube_orientation` (`0x62a4010`): an LCG seeded with the cube's id says whether it's\n * empty, at `frequency`, and which of each axis's four angles turns it.\n */\nexport const cubeOrientation = (\n id: number,\n rotations: CubeRotations,\n frequency: number,\n): Matrix4 | undefined => {\n let state = id >>> 0\n\n // The MSVC `rand()` step: 15 bits from the high half of a 32-bit LCG.\n const next = () => {\n state = (Math.imul(state, 214013) + 2531011) >>> 0\n return (state >>> 16) & 0x7fff\n }\n\n // The first draw's top two bits say how many more steps to discard.\n for (let warm = (next() >> 13) & 3; warm > 0; warm--)\n state = (Math.imul(state, 214013) + 2531011) >>> 0\n\n if (frequency >= 0 && next() * f(1 / 32768) < frequency) return undefined\n\n const pick = () => Math.min(Math.max(Math.trunc(next() * f(4 / 32768)), 0), 3)\n const [i, j, k] = [pick(), pick(), pick()]\n\n return rotationOf(rotations[0][i]!, rotations[1][j]!, rotations[2][k]!)\n}\n\n/** One `asteroid =` of a `[Cube]`: the level it draws, and where in the cube. */\nexport interface CubeAsteroid {\n mesh: VMeshData\n reference: VMeshRef\n /** Its offset in the cube: the line's three, each held to [-1, 1], times half a cube. */\n offset: Vector3\n orientation: Matrix4\n}\n\n/**\n * The layout a cube's mesh takes: retail copies every asteroid as FVF `0x252` (`CopyVertexData`), so\n * position, normal and the first UV set, whatever else a source holds. Its diffuse is never read with\n * lighting on, and what `CopyVertexData` writes for a source without one is unread here, so it's kept\n * only when every source has one.\n */\nconst cubeFormat = (asteroids: readonly CubeAsteroid[]): VertexFormat => {\n for (const { mesh } of asteroids)\n if (\n !(mesh.format & VertexFormat.Normal) ||\n !vertexLayout(mesh.format).attributes.some(({ name }) => name === 'uv0')\n )\n throw new Error(\n `An asteroid's FVF 0x${mesh.format.toString(16)} lacks a normal or UV, unread`,\n )\n\n const diffuse = asteroids.every(({ mesh }) => mesh.format & VertexFormat.Diffuse)\n\n return setMapCount(\n VertexFormat.Position | VertexFormat.Normal | (diffuse ? VertexFormat.Diffuse : 0),\n 1,\n )\n}\n\n/**\n * `CliAsteroidMergeCubeMesh`: every asteroid's vertices turned and moved into the cube, one mesh in\n * list order, drawn whole with the first's material, each copied into `cubeFormat`'s layout.\n */\nexport const mergeCube = (\n asteroids: readonly CubeAsteroid[],\n): { mesh: VMeshData; reference: VMeshRef } | undefined => {\n const first = asteroids[0]\n if (!first) return undefined\n\n const format = cubeFormat(asteroids)\n const stride = vertexByteLength(format)\n const layout = vertexLayout(format)\n const normal = layout.attributes.find(({ name }) => name === 'normal')\n let vertexCount = 0\n for (const { reference } of asteroids) vertexCount += reference.vertexCount\n\n const vertices = new Uint8Array(vertexCount * stride)\n const indices: number[] = []\n let base = 0\n\n for (const { mesh, reference, offset, orientation } of asteroids) {\n const source = vertexLayout(mesh.format)\n\n // Byte ranges to move per attribute from the source stride to the cube's; floats are 4 bytes each.\n const copies = layout.attributes.map((to) => {\n const from = source.attributes.find(({ name }) => name === to.name)!\n\n return { from: from.offset, to: to.offset, bytes: to.normalizedBytes ? to.size : to.size * 4 }\n })\n\n for (let at = 0; at < reference.vertexCount; at++) {\n const read = (reference.vertexStart + at) * source.stride\n const write = (base + at) * stride\n\n for (const { from, to, bytes } of copies)\n vertices.set(mesh.vertices.subarray(read + from, read + from + bytes), write + to)\n }\n\n // Turns this asteroid's copied positions and normals in place, then moves the positions by `offset`.\n const view = new DataView(vertices.buffer, base * stride, reference.vertexCount * stride)\n\n for (let at = 0; at < reference.vertexCount; at++) {\n const read = (offsetBytes: number) =>\n [0, 4, 8].map((k) => view.getFloat32(at * stride + offsetBytes + k, true))\n const write = (offsetBytes: number, { x, y, z }: Vector3) =>\n [x, y, z].forEach((value, k) =>\n view.setFloat32(at * stride + offsetBytes + k * 4, value, true),\n )\n const [px, py, pz] = read(0) as [number, number, number]\n const p = Matrix4.transformDirection({ x: px, y: py, z: pz }, orientation)\n\n write(0, { x: f(offset.x + f(p.x)), y: f(f(p.y) + offset.y), z: f(f(p.z) + offset.z) })\n\n if (normal) {\n const [nx, ny, nz] = read(normal.offset) as [number, number, number]\n const n = Matrix4.transformDirection({ x: nx, y: ny, z: nz }, orientation)\n\n write(normal.offset, { x: f(n.x), y: f(n.y), z: f(n.z) })\n }\n }\n\n // Rebases each index from the source mesh's vertex space to this asteroid's slice of the cube.\n for (const { startIndex, elementCount, baseVertex } of getMeshDraw(mesh, reference))\n for (let at = 0; at < elementCount; at++)\n indices.push(mesh.indices[startIndex + at]! + baseVertex - reference.vertexStart + base)\n\n base += reference.vertexCount\n }\n\n const materialId = first.mesh.groups[first.reference.groupStart]?.materialId ?? 0\n const mesh: VMeshData = {\n name: 'asteroid cube',\n version: 1,\n primitive: Primitive.TriangleList,\n format,\n groups: [\n {\n materialId,\n vertexStart: 0,\n vertexEnd: vertexCount - 1,\n elementCount: indices.length,\n padding: 0,\n },\n ],\n indices: Uint16Array.from(indices),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount,\n indexStart: 0,\n indexCount: indices.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: first.reference.boundingBox,\n boundingSphere: first.reference.boundingSphere,\n }\n\n return { mesh, reference }\n}\n\n/** A zone that takes cubes, as `[Exclusion Zones]` names it. */\nexport interface CubeExclusion {\n zone: Zone\n /** Its zone's `edge_fraction`. 0 when absent. */\n edgeFraction?: number\n /** `empty_cube_frequency` of its own: then it thins the cubes rather than taking them. */\n emptyFrequency?: number\n /** `exclude_billboards` above 0: no billboard stands in it. */\n excludeBillboards?: boolean\n /** `billboard_count`, truncated, when above 0: how many billboards stand in it. */\n billboardCount?: number\n /**\n * `exclude_dynamic_asteroids` above 0, on a sphere or an ellipsoid (`062a4f81`): no dynamic\n * asteroid is placed about a point in it.\n */\n excludeDynamicAsteroids?: boolean\n}\n\n/** What the cube walk needs of a field, as its file and zone give it. The host reads them. */\nexport interface CubeField {\n zone: Zone\n /** Its zone's `edge_fraction`. 0 when absent. */\n edgeFraction?: number\n /** `cube_size`, 400 when absent. */\n cubeSize: number\n /** `fill_dist`, 1200 when absent. */\n fillDistance: number\n /** `empty_cube_frequency`, 0 when absent. */\n emptyFrequency?: number\n /** `max_alpha`, 1 when absent. */\n maxAlpha?: number\n /**\n * `test_asteroid_placement`, set by the key alone: no cube is drawn, though its band, billboards\n * and dynamic asteroids are (`CliAsteroidDrawNearField`, `0x522a80`). No retail file sets it.\n */\n testPlacement?: boolean\n rotations?: CubeRotations\n exclusions?: readonly CubeExclusion[]\n /**\n * `+0x230`: how far the walk reaches, from the `Asteroids` option as last applied, `(1 - d) ·\n * 0.65 + d`. 1 when absent, as at 1 and at load.\n */\n detailScale?: number\n}\n\n/** A cube to draw: where, turned how, and how faded. */\nexport interface CubeDraw {\n position: Vector3\n orientation: Matrix4\n /** `max_alpha`, less over the last half cube before the walk's reach. */\n alpha: number\n}\n\n/** `CAsteroidField::near_field` (`0x62a53c0`): within the zone, or near enough its surface. */\nexport const nearField = (field: CubeField, eye: Vector3): boolean => {\n const fill = Math.trunc(field.fillDistance * (field.detailScale ?? 1))\n const margin = f((field.cubeSize + fill) * f(1.74))\n const { zone } = field\n const d = {\n x: f(eye.x - zone.position.x),\n y: f(eye.y - zone.position.y),\n z: f(eye.z - zone.position.z),\n }\n const reach = zone.radius + margin\n const squared = d.x * d.x + d.z * d.z + d.y * d.y\n if (squared > reach * reach) return false\n\n const distance = Math.sqrt(f(squared))\n let excess = 0\n\n if (distance > f(0.0001)) {\n const length = f(distance)\n const inverse = 1 / length\n\n excess =\n length - zone.radiusAlong({ x: f(d.x * inverse), y: f(d.y * inverse), z: f(d.z * inverse) })\n }\n\n return excess <= margin\n}\n\n/**\n * `CAsteroidField::near_field_fraction` (`0x62a54e0`): 1 at the zone's surface, falling to 0 `distance`\n * past it, and unclamped within, so over 1. A distance of 0 or less is `(fill_dist + cube_size) · 1.2`; the client passes 1000.\n */\nexport const nearFieldFraction = (\n field: Pick<CubeField, 'zone' | 'fillDistance' | 'cubeSize'>,\n eye: Vector3,\n distance: number,\n): number => {\n const reachBy = distance > 0 ? distance : f((field.fillDistance + field.cubeSize) * f(1.2))\n const { zone } = field\n const d = {\n x: f(eye.x - zone.position.x),\n y: f(eye.y - zone.position.y),\n z: f(eye.z - zone.position.z),\n }\n const reach = zone.radius + reachBy\n const squared = d.x * d.x + d.z * d.z + d.y * d.y\n if (squared > reach * reach) return 0\n\n const root = Math.sqrt(f(squared))\n const inverse = 1 / root\n const excess =\n f(root) - zone.radiusAlong({ x: f(d.x * inverse), y: f(d.y * inverse), z: f(d.z * inverse) })\n if (!(excess <= reachBy)) return 0\n return f(1 - excess / reachBy)\n}\n\n/**\n * `AsteroidExclusionZone::update_dist` (`0x62bc4e0`): how far outside a zone the camera is, squared,\n * 0 within. A sphere by its radius and an ellipsoid by its reach toward the camera, each summing the\n * squares in its own order; **any other shape is 0**, so a box or a cylinder is always asked.\n */\nexport const outsideSquared = ({ zone }: CubeExclusion, eye: Vector3): number => {\n const dx = f(eye.x - zone.position.x)\n const dy = f(eye.y - zone.position.y)\n const dz = f(eye.z - zone.position.z)\n let length: number\n let radius: number\n\n if (zone.type === 'sphere') {\n length = f(Math.sqrt(dz * dz + dy * dy + dx * dx))\n radius = zone.radius\n } else if (zone.type === 'ellipsoid') {\n // No zero-length test: at the centre the distance is NaN, which no cut-off passes over.\n length = f(Math.sqrt(dz * dz + dx * dx + dy * dy))\n\n const inverse = 1 / length\n\n radius = zone.radiusAlong({ x: f(dx * inverse), y: f(dy * inverse), z: f(dz * inverse) })\n } else return 0\n\n const distance = length - radius\n\n // Squared when not below 0, unordered too (`JP`).\n return distance < 0 ? 0 : f(distance * distance)\n}\n\n/**\n * `is_cliasteroid_excluded` (`0x62bc200`) over the zones nearest first: a zone holding the cube takes\n * it, or thins it to its own frequency; past `reach`, squared, the scan stops.\n */\nconst excluded = (\n zones: readonly { exclusion: CubeExclusion; key: number }[],\n reach: number,\n point: Vector3,\n): { taken: boolean; frequency?: number } => {\n let frequency: number | undefined\n\n for (const { exclusion, key } of zones) {\n if (key > reach) break\n\n if (immersion(exclusion.zone, exclusion.edgeFraction ?? 0, point) !== 0) {\n if (!((exclusion.emptyFrequency ?? -1) >= 0)) return { taken: true }\n frequency = exclusion.emptyFrequency\n }\n }\n\n return frequency === undefined ? { taken: false } : { taken: false, frequency }\n}\n\n/**\n * `CliAsteroidDrawNearField`: the cubes to draw, in the walk's order. A box of cubes spans the view\n * out to `fill_dist`; each is kept if it's within the side planes and the reach, the zone holds it\n * past 0.001, no exclusion takes it, and its id doesn't leave it empty. The camera's own cube is\n * drawn last if the walk missed it. Nothing past `nearField`, nor with `testPlacement`.\n */\nexport const fieldCubes = (\n field: CubeField,\n camera: Camera,\n aspect: number,\n /** Counts the centres within view depth and the frustum, which the zone and exclusions are asked. */\n counted?: { tested: number },\n): CubeDraw[] => {\n const eye = camera.position\n if (field.testPlacement || !nearField(field, eye)) return []\n\n const size = field.cubeSize\n const rotations = field.rotations ?? RETAIL_CUBE_ROTATIONS\n const maxAlpha = f(field.maxAlpha ?? 1)\n const frame = Matrix4.fromRotationTranslation(camera.orientation, { x: 0, y: 0, z: 0 })\n const col0 = { x: frame.x.x, y: frame.x.y, z: frame.x.z }\n const col1 = { x: frame.y.x, y: frame.y.y, z: frame.y.z }\n const col2 = { x: frame.z.x, y: frame.z.y, z: frame.z.z }\n const add = (a: Vector3, b: Vector3) => ({ x: f(a.x + b.x), y: f(a.y + b.y), z: f(a.z + b.z) })\n const sub = (a: Vector3, b: Vector3) => ({ x: f(a.x - b.x), y: f(a.y - b.y), z: f(a.z - b.z) })\n const scale = (a: Vector3, s: number) => ({ x: f(a.x * s), y: f(a.y * s), z: f(a.z * s) })\n const dot = (a: Vector3, b: Vector3) => a.x * b.x + a.z * b.z + a.y * b.y\n\n // Inward normals of the view's right, left, top and bottom planes (`d0`..`d3`), in world space;\n // `col0`..`col2` are the camera's right, up and back axes.\n const halfX = f((camera.fovh * Math.PI) / 180)\n const fovY = f(Math.atan(Math.tan(halfX) / aspect))\n const angleX = f(Math.PI / 2) - halfX\n const angleY = f(Math.PI / 2) - fovY\n const [sinX, cosX, sinY, cosY] = [\n Math.sin(angleX),\n Math.cos(angleX),\n Math.sin(angleY),\n Math.cos(angleY),\n ].map(f) as [number, number, number, number]\n const backX = scale(col2, cosX)\n const d0 = sub(scale(col0, -sinX), backX)\n const d1 = sub(scale(col0, sinX), backX)\n const backY = scale(col2, cosY)\n const d2 = sub(scale(col1, -sinY), backY)\n const d3 = sub(scale(col1, sinY), backY)\n\n const margin = f(size * f(1.25))\n const nearPoint = add(eye, scale(col2, margin))\n const tanX = f(Math.tan(halfX))\n const tanY = f(Math.tan(fovY))\n const fill = Math.trunc(field.fillDistance) * f(field.detailScale ?? 1)\n const extX = Math.trunc(tanX * fill)\n const extY = Math.trunc(tanY * fill)\n\n // The walk's box: the cube behind the eye and the far plane's four corners, snapped to centres.\n const seed = closestCubePosition(add(scale(col2, size), eye), size)\n let [minX, maxX, minY, maxY, minZ, maxZ] = [seed.x, seed.x, seed.y, seed.y, seed.z, seed.z]\n const negZ = { x: -col2.x, y: -col2.y, z: -col2.z }\n const farCentre = add(scale(negZ, fill), eye)\n const latX = scale(col0, extX)\n const latY = scale(col1, extY)\n const farXp = add(farCentre, latX)\n const farXm = sub(farCentre, latX)\n\n for (const corner of [add(farXp, latY), sub(farXp, latY), sub(farXm, latY), add(farXm, latY)]) {\n const snapped = closestCubePosition(corner, size)\n ;[minX, maxX] = [Math.min(minX, snapped.x), Math.max(maxX, snapped.x)]\n ;[minY, maxY] = [Math.min(minY, snapped.y), Math.max(maxY, snapped.y)]\n ;[minZ, maxZ] = [Math.min(minZ, snapped.z), Math.max(maxZ, snapped.z)]\n }\n\n const halfCube = f(size * 0.5)\n const reachWide = fill + margin\n const reach = f(reachWide)\n const fadeStart = f(reachWide - halfCube)\n const exclusionReach = f(\n Math.pow(Math.trunc(field.fillDistance) * (field.detailScale ?? 1) * 1.25, 2),\n )\n const zones = (field.exclusions ?? [])\n .map((exclusion) => ({ exclusion, key: outsideSquared(exclusion, eye) }))\n .sort((a, b) => a.key - b.key)\n const playerId = cubeId(closestCubePosition(eye, size))\n let playerSeen = false\n\n /** The tests every cube passes, the walk's and the camera's own: its turn, or none. */\n const keep = (position: Vector3, id: number): Matrix4 | undefined => {\n if (!(immersion(field.zone, field.edgeFraction ?? 0, position) > f(0.001))) return undefined\n\n const { taken, frequency } = excluded(zones, exclusionReach, position)\n if (id === 0 || taken) return undefined\n return cubeOrientation(id, rotations, frequency ?? field.emptyFrequency ?? 0)\n }\n\n const cubes: CubeDraw[] = []\n\n for (let x = minX; x <= maxX; x += size)\n for (let y = minY; y <= maxY; y += size)\n for (let z = minZ; z <= maxZ; z += size) {\n const position = closestCubePosition({ x, y, z }, size)\n const delta = sub(position, nearPoint)\n const depth = Math.abs(dot(negZ, delta))\n if (depth > reach) continue\n\n // Outside a side when its slope passes the half-FOV tangent and it is behind that plane.\n const inverse = 1 / depth\n const slopeX = dot(delta, col0) * inverse\n if (!(tanX >= Math.abs(slopeX)) && dot(slopeX > 0 ? d0 : d1, delta) < 0) continue\n\n const slopeY = dot(delta, col1) * inverse\n if (!(tanY >= Math.abs(slopeY)) && dot(slopeY > 0 ? d2 : d3, delta) < 0) continue\n if (counted) counted.tested++\n if (!(immersion(field.zone, field.edgeFraction ?? 0, position) > f(0.001))) continue\n\n const id = cubeId(position)\n const { taken, frequency } = excluded(zones, exclusionReach, position)\n if (id === 0 || taken) continue\n if (id === playerId) playerSeen = true\n\n const orientation = cubeOrientation(id, rotations, frequency ?? field.emptyFrequency ?? 0)\n if (!orientation) continue\n\n let alpha = maxAlpha\n\n if (fadeStart < depth) {\n const ramp = ((reach - depth) / halfCube) * maxAlpha\n\n alpha = ramp > maxAlpha ? maxAlpha : ramp < 0 ? 0 : f(ramp)\n if (alpha <= f(0.001)) continue\n }\n\n cubes.push({ position, orientation, alpha })\n }\n\n if (!playerSeen && playerId !== 0) {\n const position = closestCubePosition(eye, size)\n const orientation = keep(position, playerId)\n if (orientation) cubes.push({ position, orientation, alpha: maxAlpha })\n }\n\n return cubes\n}\n\n/** A field as the frame draws it: its cube walk, its merged mesh's lookups, and its colours. */\nexport interface SpaceAsteroidField extends CubeField {\n /** `mergeCube`'s mesh, with the lookups its material and textures resolve through. */\n cube: Pick<SceneModel, 'material' | 'texture' | 'materialMap'> & {\n mesh: VMeshData\n reference: VMeshRef\n }\n /** `diffuse_color` over 255, or `tint_field`'s. */\n diffuse: Vector3\n /** `ambient_color` over 255, or `tint_field`'s. */\n ambient: Vector3\n /** `ambient_increase`, 0 to 255 a channel, added to the ambient the field is lit by. */\n ambientIncrease?: Vector3\n /**\n * `contains_fog_zone`: lit and fogged by the nebula the camera is in, at its depth. Without, by\n * the nebula holding its zone's centre, in full.\n */\n containsFogZone?: boolean\n /** Its `[Band]`, built from its zone and colours. */\n band?: AsteroidBand\n /** Its `[ExclusionBand]`s, in file order, each about its own `zone`. */\n exclusionBands?: readonly AsteroidBand[]\n /** Its `[AsteroidBillboards]`, when the `Asteroids` option is above 1 and effects are on. */\n billboards?: AsteroidBillboards\n /**\n * Its `[DynamicAsteroids]`, in file order, each with its archetype's top level as `mergeCube`\n * gives it alone: the whole mesh drawn with its first group's material.\n */\n dynamic?: readonly { rocks: DynamicAsteroids; model: SpaceAsteroidField['cube'] }[]\n}\n","/**\n * An equipment light's flare: `CliEquipLight` in `src/freelancer/Client/client_equip_fx.cpp`, which\n * blinks and queues a bulb and a glow as screen quads, and `ScreenQuadEnqueueFlare` in\n * `screen_quad_state.cpp`, which sizes and clips them. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Camera } from './camera.js'\nimport type { Random } from './lightning.js'\nimport { inverseRoot } from './retail.js'\n\nconst f = Math.fround\n\n/** A `[Light]`'s flare keys, as `CliEQLight` holds them. The host reads the INI, `inherit` too. */\nexport interface FlareLight {\n /** `color` over 255. */\n color: Vector3\n /** `glow_color` over 255. A `color` line copies itself here while this is still black. */\n glowColor: Vector3\n /** `min_color` over 255: the bulb's colour while the blink is dark. */\n minColor: Vector3\n bulbSize: number\n glowSize: number\n /** `avg_delay`: about how long between blinks. None at 0 or less. */\n avgDelay: number\n /** `blink_duration`: how long one lasts, at most `avg_delay`'s draw. */\n blinkDuration: number\n /**\n * `flare_cone` in degrees, as written: past the first from its forward axis the glow is gone, and\n * from the second to the first it fades. None when absent.\n */\n flareCone?: readonly [number, number]\n}\n\n/** `FCliEQLight`'s constructor (`0x40a9e0`), what a `[Light]` with no keys has. */\nexport const RETAIL_FLARE_LIGHT: Readonly<FlareLight> = {\n color: { x: 0, y: 0, z: 0 },\n glowColor: { x: 0, y: 0, z: 0 },\n minColor: { x: 0, y: 0, z: 0 },\n bulbSize: 1,\n glowSize: 1,\n avgDelay: 0,\n blinkDuration: 0.3,\n}\n\n// `DAT_005caeec`, `DAT_005da4c0` and `DAT_005da4b8`: a period of 0.9 to 1.1 of `avg_delay`.\nconst RAND_UNIT = 3.0517578125e-5\nconst JITTER_SCALE = 0.20000004768371582\nconst JITTER_BASE = 0.8999999761581421\n\n/**\n * A light's blink: `CliEquipLightInit` (`0x4fda00`) and its tick (`0x4fdd00`). A triangle up to 1 and\n * back over the lit part of each period, dark for the rest; always 1 when it doesn't blink. Each\n * light draws its period and phase from the game's `rand()` as it's made.\n */\nexport class LightBlink {\n #rate = 0\n #duty = 1\n #phase: number\n brightness = 1\n\n constructor(\n { avgDelay, blinkDuration }: Pick<FlareLight, 'avgDelay' | 'blinkDuration'>,\n random: Random = () => Math.floor(Math.random() * 0x8000),\n ) {\n const period = (random() * RAND_UNIT * JITTER_SCALE + JITTER_BASE) * f(avgDelay)\n\n if (period > 0) {\n const rate = 1 / f(period)\n\n this.#rate = f(rate)\n\n const lit = f(blinkDuration) > f(period) ? f(period) : f(blinkDuration)\n\n this.#duty = f(rate * lit)\n }\n\n this.#phase = f(random() * RAND_UNIT)\n }\n\n /**\n * A period and phase given, not drawn: `FFlashLight`'s second constructor (`FUN_00557630`), which a\n * room's `[FlashlightSet]` makes its lights with. A phase below 0 stays dark until it's passed 0.\n */\n static timed(period: number, phase: number, blinkDuration: number): LightBlink {\n const blink = new LightBlink({ avgDelay: 0, blinkDuration }, () => 0)\n\n blink.#phase = f(phase)\n\n if (f(period) > 0) {\n const inverse = 1 / f(period)\n\n blink.#rate = f(inverse)\n\n const lit = f(period) < f(blinkDuration) ? f(period) : f(blinkDuration)\n\n blink.#duty = f(inverse * lit)\n }\n\n return blink\n }\n\n /** Where in its period it is, 0 to 1. */\n get phase(): number {\n return this.#phase\n }\n\n /** Advances by `step`, which the game holds to 0.1, only on a frame its object drew. */\n tick(step: number): void {\n if (this.#rate === 0) return\n\n const phase = f(step) * this.#rate + this.#phase\n\n this.#phase = f(phase >= 1 ? phase - Math.floor(phase) : phase)\n\n if (this.#phase > this.#duty) {\n this.brightness = 0\n return\n }\n\n const wave = (2 / this.#duty) * this.#phase\n\n this.brightness = f(wave > 1 ? 2 - wave : wave)\n }\n}\n\n/** A light on a ship or solar: its keys, where its hardpoint is, and its blink. */\nexport interface SpaceFlare {\n light: FlareLight\n /** The hardpoint's frame in the world. */\n world: Matrix4\n /** Steady at full brightness when absent. */\n blink?: LightBlink\n}\n\n/** One quad as the batcher records it (`FScreenQuadRecord`): D3D pixels, depth and `1 / w`. */\nexport interface ScreenQuad {\n x0: number\n y0: number\n x1: number\n y1: number\n /** `1 - near / -z`, the depth it's tested at. */\n z: number\n rhw: number\n u0: number\n v0: number\n u1: number\n v1: number\n /** `0xAARRGGBB`, alpha always 255. */\n color: number\n}\n\n/** A texture frame's rectangle, `GetTextureFrame`'s: `u0`, `v0`, `u1`, `v1`. Whole when absent. */\nexport type FrameRect = readonly [number, number, number, number]\n\nconst WHOLE: FrameRect = [0, 0, 1, 1]\n\n/**\n * `ScreenQuadClip1D` (`0x404670`): an edge pair clipped to [lo, hi], its attribute pair following\n * over `span`. Nothing when it's wholly outside.\n */\nconst clip = (\n edges: [number, number],\n attributes: [number, number],\n lo: number,\n hi: number,\n span: number,\n): boolean => {\n if (edges[1] < lo) return false\n if (edges[0] >= hi) return false\n\n const below = lo - edges[0]\n\n if (below > 0) {\n edges[0] = f(below + edges[0])\n attributes[0] = f((attributes[1] - attributes[0]) * (below / span) + attributes[0])\n }\n\n const above = hi - edges[1]\n if (!(above < 0)) return true\n edges[1] = f(above + edges[1])\n attributes[1] = f((attributes[1] - attributes[0]) * (above / span) + attributes[1])\n return true\n}\n\n/** `EnqueueFlareQuad`: one square, unless it's a pixel or less, black, or off the screen. */\nconst flareQuad = (\n rect: readonly [number, number, number, number],\n frame: FrameRect,\n color: Vector3,\n radiusX: number,\n radiusY: number,\n x: number,\n y: number,\n z: number,\n rhw: number,\n): ScreenQuad | undefined => {\n if (!(radiusX > 1)) return undefined\n\n // `ftol` truncates, and only each component's low byte is kept.\n const [r, g, b] = [color.x, color.y, color.z].map((c) => Math.trunc(c * 255))\n if ((r! + g! + b!) >>> 0 <= 1) return undefined\n\n const xs: [number, number] = [f(x - radiusX), f(x + radiusX)]\n const ys: [number, number] = [f(y - radiusY), f(y + radiusY)]\n const us: [number, number] = [frame[0], frame[2]]\n const vs: [number, number] = [frame[1], frame[3]]\n\n if (!clip(xs, us, rect[0], rect[2], radiusX + radiusX)) return undefined\n if (!clip(ys, vs, rect[1], rect[3], radiusY + radiusY)) return undefined\n return {\n x0: xs[0],\n y0: ys[0],\n x1: xs[1],\n y1: ys[1],\n z,\n rhw,\n u0: us[0],\n v0: vs[0],\n u1: us[1],\n v1: vs[1],\n color: (0xff000000 | ((r! & 0xff) << 16) | ((g! & 0xff) << 8) | (b! & 0xff)) >>> 0,\n }\n}\n\n// `DAT_005c77f4`, the degrees-to-radians `flare_cone` is read with.\nconst DEGREES = f(0.017453292)\n\n/** `CliEquipLightDrawFlare` (`0x4fdda0`): the glow's fade as the light faces away from the camera. */\nconst fadeOf = ({ flareCone }: FlareLight, world: Matrix4, eye: Vector3): number => {\n if (!flareCone) return 1\n\n const full = f(Math.cos(flareCone[1] * DEGREES))\n const none = f(Math.cos(flareCone[0] * DEGREES))\n if (!(full > none)) return 1\n\n const d = [f(world.w.x - eye.x), f(world.w.y - eye.y), f(world.w.z - eye.z)] as const\n // The fast inverse square root (`0x4fde1e`).\n const inverse = inverseRoot(f(d[2] * d[2] + d[1] * d[1] + d[0] * d[0]))\n const [x, y, z] = d.map((c) => f(c * inverse)) as [number, number, number]\n // The rotation's third column: its forward axis, as `Matrix4` holds columns.\n const dot = f(z * world.z.z + y * world.z.y + x * world.z.x)\n if (dot < none) return 0\n if (dot < full) return f((dot - none) / (full - none))\n return 1\n}\n\nexport interface FlareView {\n camera: Camera\n /** The camera's view, `viewMatrix(camera)`. */\n view: Matrix4\n /** The projection's, width over height. */\n aspect: number\n /** The viewport, in pixels. */\n width: number\n height: number\n frame?: FrameRect\n}\n\n/**\n * A light's bulb then its glow at `world`, the hardpoint's frame (`ScreenQuadEnqueueFlare`,\n * `0x4038f0`): squares of its sizes at its depth, each dropped under a pixel. Nothing behind the\n * camera, though anything nearer than the near plane passes as retail lets it.\n */\nexport const flareQuads = (\n light: FlareLight,\n world: Matrix4,\n brightness: number,\n { camera, view, aspect, width, height, frame = WHOLE }: FlareView,\n): ScreenQuad[] => {\n // The camera's rectangle ends on its last pixel: `space_order`'s quads stand half a pixel up and\n // left of a 1024 by 768 one's centre, at the scale of its full width.\n const rect = [0, 0, width - 1, height - 1] as const\n const cot = 1 / Math.tan((camera.fovh * Math.PI) / 180)\n // Screen y runs down where the view's runs up.\n const scale = { x: (width / 2) * cot, y: -(height / 2) * aspect * cot }\n const fade = fadeOf(light, world, camera.position)\n const { color, glowColor, minColor } = light\n const glow = {\n x: brightness * glowColor.x,\n y: brightness * glowColor.y,\n z: brightness * glowColor.z,\n }\n const bulb = {\n x: f(f(brightness * f(color.x - minColor.x)) + minColor.x),\n y: f(f(brightness * f(color.y - minColor.y)) + minColor.y),\n z: f(brightness * f(color.z - minColor.z) + minColor.z),\n }\n const faded = { x: f(f(glow.x) * fade), y: f(f(glow.y) * fade), z: f(f(glow.z) * fade) }\n\n const at = Matrix4.transformPoint({ x: world.w.x, y: world.w.y, z: world.w.z }, view)\n const depth = f(f(at.z) - f(at.z) * 0.001)\n if (depth - camera.near >= 0) return []\n\n // `rhw` is 1 / the depth ahead; a size or offset in pixels is the view's times `scale` · `rhw`.\n const rhw = f(-1 / depth)\n const perX = f(scale.x) * rhw\n const perY = f(scale.y) * rhw\n const bulbX = f(light.bulbSize) * perX\n const glowX = f(perX * f(light.glowSize))\n if (bulbX < 1 && glowX < 1) return []\n\n const x = f((rect[2] - rect[0]) * 0.5 + f(at.x) * f(scale.x) * rhw + rect[0])\n const y = f((rect[3] - rect[1]) * 0.5 + f(at.y) * f(scale.y) * rhw + rect[1])\n const z = f(1 - camera.near * rhw)\n const quads = [\n flareQuad(rect, frame, bulb, f(bulbX), f(Math.abs(f(light.bulbSize) * perY)), x, y, z, rhw),\n flareQuad(rect, frame, faded, glowX, f(Math.abs(perY * f(light.glowSize))), x, y, z, rhw),\n ]\n\n return quads.filter((quad) => quad !== undefined)\n}\n","/**\n * A nebula's fog overlay: `FNebulaEffect::DrawFogOverlay` (`LAB_00508b00`, `cli_nebula.cpp`). Inside\n * a field, after the main lists, one quad over the viewport in the fog's colour, as opaque as the\n * camera is deep, so what lies outside the nebula fades to its fog. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport type { Draw } from './frame.js'\nimport type { NebulaState, SpaceNebula } from './nebula.js'\nimport { unitByteRounded } from './retail.js'\n\nconst f = Math.fround\n\n// XYZ, D3DCOLOR and one UV set: Win3D's FVF 0x142, 24 bytes. The UVs are stale in retail; unread.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\n// `ScaleClampToByte`: times 255, truncated, held to a byte.\nconst byte = unitByteRounded\n\n/**\n * `+0x2b8`, per nebula: set on the frame the camera's depth reaches 1, which still draws, and cleared\n * once it's under 1 again. While set, no overlay. Kept here as retail keeps it on the nebula.\n */\nconst latched = new WeakMap<SpaceNebula, boolean>()\n\n/**\n * The overlay for a frame in a field, or nothing: none at a depth of 0 or less, nor past the frame\n * that reached 1. The quad runs from the viewport's corner to its last pixel, `0` to `width - 1`\n * (`GetViewport`'s rectangle ends on it), under `Win3DSetOrtho2DForCamera`, so retail leaves the\n * last column and row bare. Without a viewport it covers the whole view. Untextured (`0xde1` off),\n * blended, with no depth test or writes and no culling; `ALPHAREF` is the frame's, 0 as captured.\n */\nexport const fogOverlayDraw = (\n { nebula, depth }: NebulaState,\n view: Matrix4,\n viewport?: { width: number; height: number },\n): Draw | undefined => {\n if (depth < 1) latched.set(nebula, false)\n if (!(depth < 1) && latched.get(nebula)) return undefined\n if (!(depth > 0)) return undefined\n if (depth >= 1) latched.set(nebula, true)\n\n const { color } = nebula.fog\n const bytes = [byte(color.z), byte(color.y), byte(color.x), byte(depth)]\n // In clip space: the ortho's x · 2 / width - 1 and 1 - y · 2 / height.\n const right = viewport ? f(f(viewport.width - 1) * (2 / viewport.width) - 1) : 1\n const bottom = viewport ? f(1 - f(viewport.height - 1) * (2 / viewport.height)) : -1\n const corners = [\n [-1, 1],\n [right, 1],\n [right, bottom],\n [-1, bottom],\n ]\n const vertices = new Uint8Array(corners.length * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n // Per vertex: xyz floats at byte 0, BGRA at 12, the unread UV set after.\n corners.forEach(([x, y], at) => {\n floats.set([x!, y!, 0], (at * STRIDE) / 4)\n vertices.set(bytes, at * STRIDE + 12)\n })\n\n const mesh: VMeshData = {\n name: 'fog overlay',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [{ materialId: 0, vertexStart: 0, vertexEnd: 3, elementCount: 6, padding: 0 }],\n indices: new Uint16Array([0, 1, 2, 0, 2, 3]),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: 4,\n indexStart: 0,\n indexCount: 6,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: 6,\n // Its corners are in clip space: the host's view is undone by `world`, the projection is none.\n world: Matrix4.invert(view),\n projection: Matrix4.identity,\n materialName: 'fog overlay',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n cull: 'none',\n depthWrite: false,\n depthFunc: 'always',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'alpha',\n unlit: true,\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n","/**\n * A nebula's exterior: `[Exterior]`'s bits, billboards on rings of latitude about its zone, pulled in\n * from its surface. `NebulaRebuild` (`FUN_00506600`) places them, `NebulaOrientBolts`\n * (`FUN_00507340`) turns each to the camera, and `NebulaDrawBolts` (`FUN_00507ed0`) draws them from\n * `FNebulaEffect::DrawBoltsPass`, in `src/freelancer/Client/cli_nebula.cpp`. Each bit's size, spin\n * and shape come from the game's `rand()`; where they stand doesn't. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport { classifySphere, type Camera } from './camera.js'\nimport type { Draw } from './frame.js'\nimport type { Random } from './lightning.js'\nimport { fogOf, type NebulaState, type Zone } from './nebula.js'\nimport type { TextureShape } from './ring.js'\nimport { RAND_UNIT, TWO_PI, unitByteRounded } from './retail.js'\n\nconst f = Math.fround\n\n/** An `[Exterior]` section, over `FNebulaEffect`'s constructor and `Load`'s defaults. */\nexport interface ExteriorSettings {\n /** `shape`s, at most eight; a name the shapes don't hold is `undefined`. The first's texture is bound. */\n shapes: readonly (TextureShape | undefined)[]\n /** `shape_weights`, one a shape. 1 each when absent. */\n weights?: readonly number[]\n /** `bit_radius`. Retail leaves it uninitialised when absent: the host decides. */\n bitRadius: number\n /** `bit_radius_random_variation`, held to [0, 0.9999]: a bit is 1 ± it of the radius. 0 when absent. */\n radiusVariation?: number\n /** `color` over 255. Retail leaves it uninitialised when absent: the host decides. */\n color: Vector3\n /** `plane_slices`, 1 when absent: how many rings of latitude. */\n planeSlices?: number\n /** `min_bits`, 4 when absent: a ring's bits at the poles' end. */\n minBits?: number\n /** `max_bits`, 8 when absent: a ring's bits at the middle. */\n maxBits?: number\n /**\n * `equator_bias`, 1 when absent: how far the rings spread from the equator toward the poles, 0 to\n * the whole way, 1 none. The constructor's 0 at `+0xd0` is 1 here.\n */\n equatorBias?: number\n /** `move_bit_percent`, 0.75 when absent: how many `bit_radius` a bit is pulled in from the surface. */\n moveBitPercent?: number\n /** `opacity`, 0.75 when absent. */\n opacity?: number\n}\n\n/** What the game's `Nebula` option scales (`NebulaRebuild`): `DAT_006132e0` to `DAT_006132e8`. */\nexport interface ExteriorLimits {\n /** A bit's size at no detail, of its full. */\n leastSize: number\n /** The bits' count at no detail, of their full. */\n leastCount: number\n /** Their opacity at no detail, of its full. */\n leastOpacity: number\n /** Under this detail, no bits (`0x5d5b58`). */\n leastDetail: number\n}\n\nexport const RETAIL_EXTERIOR_LIMITS: Readonly<ExteriorLimits> = {\n leastSize: f(0.707),\n leastCount: f(0.35),\n leastOpacity: 0.5,\n leastDetail: 0.05,\n}\n\ninterface Bit {\n /** From the zone's centre. */\n position: Vector3\n radius: number\n shape: TextureShape | undefined\n /** Its up, which `NebulaOrientBolts` keeps square to the camera. */\n axis: Vector3\n}\n\nconst PI = f(Math.PI)\n\n// XYZ, D3DCOLOR and one UV set: Win3D's FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\n// `ScaleClampToByte`: times 255, truncated, held to a byte.\nconst byte = unitByteRounded\n\n/**\n * Whether the game blends a texture by its alpha (`FUN_00552420`): DXT1 to DXT5 do, and so does any\n * format whose descriptor has alpha bits (`DAT_00615ec8`). A 24-bit Targa is narrowed to R5G6B5 (M1)\n * and a 16-bit one is X1R5G5B5 (`GetTgaSourceFormat`), so neither does.\n */\nexport const textureHasAlpha = ({ format }: Texture): boolean =>\n format !== 'rgb24_888' && format !== 'rgb16_565' && format !== 'rgb16_555' && format !== 'none'\n\nexport class NebulaExterior {\n readonly settings: ExteriorSettings\n readonly zone: Zone\n #bits: Bit[] = []\n /** `+0xb8`: the opacity at this detail. */\n #opacity: number\n /** `+0x58`: since the bits last turned to the camera. The constructor's 0.2. */\n #sinceTurned = f(0.2)\n /** `+0x54`: since they were last sorted. The constructor's 10. */\n #sinceSorted = 10\n /** `+0x294` as `Update` last left it, which it reads before working it out again. */\n #lastDepth = 0\n\n constructor(\n settings: ExteriorSettings,\n zone: Zone,\n {\n random = () => Math.floor(Math.random() * 0x8000),\n detail = 1,\n limits = RETAIL_EXTERIOR_LIMITS,\n }: { random?: Random; detail?: number; limits?: ExteriorLimits } = {},\n ) {\n this.settings = settings\n this.zone = zone\n\n const opacity = f(settings.opacity ?? 0.75)\n\n this.#opacity = opacity\n if (detail < limits.leastDetail) return\n\n const less = 1 - detail\n const ease = 1 - less * less\n const scale = f((limits.leastSize * (1 - ease) + ease) * f(settings.bitRadius))\n const density = f(less * limits.leastCount + detail)\n\n this.#opacity = f(((1 - ease) * limits.leastOpacity + ease) * opacity)\n\n const middleCount = Math.trunc((settings.maxBits ?? 8) * density + 0.5)\n const endCount = Math.trunc((settings.minBits ?? 4) * density + 0.5)\n const slices = settings.planeSlices ?? 1\n if (slices <= 0) return\n\n const weights = settings.shapes.map((_, at) => settings.weights?.[at] ?? 1)\n const sum = weights.reduce((total, weight) => total + weight, 0)\n const normal = weights.map((weight) => f((1 / sum) * weight))\n\n // A ring's count, from the poles' end to the middle and back.\n const mid = f((slices - 1) * 0.5)\n const inverseMid = f(1 / mid)\n let total = middleCount\n\n if (slices !== 1) {\n total = 0\n\n for (let slice = 0; slice < slices; slice++) {\n const w = slice > mid ? 1 - (slice - mid) * inverseMid : slice * inverseMid\n\n total += Math.floor((1 - w) * endCount + middleCount * w + 0.5)\n }\n }\n\n // Each bit's size, spin and shape, the two caps' too.\n const variation = Math.min(Math.max(settings.radiusVariation ?? 0, 0), f(0.9999))\n const low = f(1 - variation)\n const high = f(variation + 1)\n\n for (let index = 0; index < total + 2; index++) {\n const radius = f((random() * RAND_UNIT * (high - low) + low) * scale)\n const angle = random() * RAND_UNIT * TWO_PI\n const axis = { x: f(Math.sin(angle)), y: f(Math.cos(angle)), z: 0 }\n const pick = f(random() * RAND_UNIT)\n let running = 0\n let shape: TextureShape | undefined\n\n for (let at = 0; at < normal.length; at++) {\n running += normal[at]!\n\n if (pick < running) {\n shape = settings.shapes[at]\n break\n }\n }\n\n this.#bits.push({ position: BLACK, radius, shape, axis })\n }\n\n // The rings of latitude, each turned half a step past the middle.\n const centre = zone.position\n const spread = f(1 - (settings.equatorBias ?? 1))\n const margin = f(settings.moveBitPercent ?? 0.75) * f(settings.bitRadius)\n\n // The zone's surface point toward `point`, from its centre, pulled in by `margin` along that ray.\n const place = (index: number, point: Vector3) => {\n const surface = zone.surfacePoint(point)\n const offset = {\n x: f(surface.x - centre.x),\n y: f(surface.y - centre.y),\n z: f(surface.z - centre.z),\n }\n const length = Math.sqrt(offset.z * offset.z + offset.y * offset.y + offset.x * offset.x)\n const shrink = (length - margin) / length\n const bit = this.#bits[index]\n\n if (bit)\n bit.position = { x: f(shrink * offset.x), y: f(shrink * offset.y), z: f(shrink * offset.z) }\n }\n\n let index = 0\n let phase = 0\n\n for (let slice = 0; slice < slices; slice++) {\n let count = middleCount\n\n if (slices !== 1) {\n const w = slice > mid ? 1 - (slice - mid) / mid : slice / mid\n\n count = Math.floor((1 - w) * endCount + middleCount * w + 0.5)\n if (slice > mid) phase = f(PI / count)\n }\n\n // The ring's polar angle: evenly spaced in cosine within ±`spread`, so 0 puts all on the equator.\n const latitude = Math.acos((((slice + 1) / (slices + 1)) * 2 - 1) * spread)\n\n if (count <= 0) continue\n\n const cos = f(Math.cos(latitude))\n const sin = Math.sin(latitude)\n const y = f(centre.y + cos)\n\n for (let bit = 0; bit < count; bit++, index++) {\n const angle = (bit * TWO_PI) / count + phase\n const x = Math.cos(angle) * sin\n const z = f(Math.sin(angle) * sin)\n\n place(index, { x: f(centre.x + x), y, z: f(centre.z + z) })\n }\n }\n\n place(index++, { x: centre.x, y: f(centre.y + 1), z: centre.z })\n place(index, { x: centre.x, y: f(centre.y - 1), z: centre.z })\n }\n\n /** The bits, from the zone's centre, in the order they draw. */\n get bits(): readonly Readonly<Bit>[] {\n return this.#bits\n }\n\n /**\n * `FNebulaEffect::Update`'s part: unless the camera was all the way in last frame, the bits turn\n * to it once a second, or at once on a cut (`NebulaOrientBolts`). Then the clocks run on.\n */\n update(eye: Vector3, step: number, depth: number, cut = false): void {\n if (this.#lastDepth < 1 && (this.#sinceTurned > 1 || cut)) {\n this.#turn(eye)\n this.#sinceTurned = 0\n }\n\n this.#lastDepth = depth\n this.#sinceTurned = f(step + this.#sinceTurned)\n this.#sinceSorted = f(step + this.#sinceSorted)\n }\n\n /** `NebulaOrientBolts`: each bit's up made square to the way to the camera, when it's far off. */\n #turn(eye: Vector3): void {\n const centre = this.zone.position\n const rx = f(eye.x - centre.x)\n const ry = f(eye.y - centre.y)\n const rz = f(eye.z - centre.z)\n\n // With `d` the unit way to the camera: `axis` = unit(`d` × `axis`) × `d`. Left alone when\n // |`d` · `axis`| is over 0.25.\n for (const bit of this.#bits) {\n const a = rx - bit.position.x\n const b = ry - bit.position.y\n const c = rz - bit.position.z\n const cf = f(c)\n const inverse = f(1 / Math.sqrt(c * cf + b * b + a * a))\n const dx = f(a * inverse)\n const dy = b * inverse\n const dzExt = cf * inverse\n const dz = f(dzExt)\n const o = bit.axis\n if (!(Math.abs(dzExt * o.z + dy * o.y + dx * o.x) > 0.25)) continue\n\n const cx = dy * o.z - dz * o.y\n const cy = dz * o.x - dx * o.z\n const cz = dx * o.y - dy * o.x\n const czf = f(cz)\n const inverseC = f(1 / Math.sqrt(cz * czf + cy * cy + cx * cx))\n const nx = f(cx * inverseC)\n const ny = cy * inverseC\n const nz = czf * inverseC\n\n bit.axis = { x: f(ny * dz - nz * dy), y: f(nz * dx - dz * nx), z: f(dy * nx - ny * dx) }\n }\n }\n\n /**\n * `NebulaDrawBolts` from `DrawBoltsPass`: none once the camera is all the way in, nor when the zone\n * is out of view. Sorted far to near once 1.15 s have passed. Each bit faces the camera about its\n * up, its back half skipped and its edge fading, fading too as the camera comes within its radius,\n * and over the second half of the camera's depth. Unlit, unculled, with no depth test or writes,\n * `ALPHAREF` 4, fogged in the nebula's colour to past its fog's span (`DrawBoltsPass`). `camera` is\n * the 250000 far plane its callers set; `projection` is that.\n */\n draw(\n { nebula, depth, start, fogDistance }: NebulaState,\n camera: Camera,\n view: Matrix4,\n aspect: number,\n projection: Matrix4,\n ): Draw | undefined {\n if (!this.#bits.length || !(depth < 1)) return undefined\n\n const centre = this.zone.position\n const eye = camera.position\n const inView = Matrix4.transformPoint(centre, view)\n if (classifySphere(inView, this.zone.radius, camera, aspect) < 3) return undefined\n\n if (this.#sinceSorted > f(1.15)) {\n this.#sort(eye)\n this.#sinceSorted = 0\n }\n\n const bound = this.settings.shapes[0]\n if (!bound) return undefined\n\n const alpha = textureHasAlpha(bound.texture)\n\n let base = this.#opacity\n if (depth > 0.5) base = f((1 - (depth - 0.5 + (depth - 0.5))) * base)\n\n let tx = f(eye.x - centre.x)\n let ty = f(eye.y - centre.y)\n let tz = f(eye.z - centre.z)\n const toCamera = f(1 / f(Math.sqrt(f(f(tx * tx + tz * tz) + ty * ty))))\n\n tx = f(tx * toCamera)\n ty = f(ty * toCamera)\n tz = f(tz * toCamera)\n\n const { color } = this.settings\n const corners: { at: number[]; uv: [number, number]; bytes: number[] }[] = []\n\n for (const { position: s, radius, shape, axis } of this.#bits) {\n const p = { x: f(centre.x + s.x), y: f(centre.y + s.y), z: f(centre.z + s.z) }\n const v = { x: f(p.x - eye.x), y: f(p.y - eye.y), z: f(p.z - eye.z) }\n const ahead = -Matrix4.transformPoint(p, view).z\n if (ahead <= 0) continue\n\n // Its offset from the centre against the way to the camera: the back half isn't drawn.\n let a = base\n const inverse = f(1 / f(Math.sqrt(f(f(s.x * s.x + s.z * s.z) + s.y * s.y))))\n const dot = f(f(tx * f(s.x * inverse) + tz * f(s.z * inverse)) + ty * f(s.y * inverse))\n if (dot < 0) continue\n if (dot < 0.05) a = f(dot * base * 20)\n\n // `q` = view × up scaled to the radius is the bit's right, `h` = `q` × view its up; the corners\n // are `p ± q ± h`.\n let qx = f(v.y * axis.z - v.z * axis.y)\n let qy = f(v.z * axis.x - v.x * axis.z)\n let qz = f(v.x * axis.y - v.y * axis.x)\n const qs = f(radius / f(Math.sqrt(f(f(qx * qx + qz * qz) + qy * qy))))\n\n qx = f(qx * qs)\n qy = f(qy * qs)\n qz = f(qz * qs)\n\n let hx = f(qy * v.z - qz * v.y)\n let hy = f(qz * v.x - v.z * qx)\n let hz = f(v.y * qx - qy * v.x)\n const hs = f(radius / f(Math.sqrt(f(f(hz * hz + hy * hy) + hx * hx))))\n\n hx = f(hx * hs)\n hy = f(hy * hs)\n hz = f(hz * hs)\n\n if (ahead < radius) a = f(f(ahead / radius) * a)\n if (a < 0.01 || !shape) continue\n\n // With alpha, `Color4f`; without, added, `Color3f` of the colour times it.\n const bytes = alpha\n ? [byte(color.z), byte(color.y), byte(color.x), byte(a)]\n : [byte(color.z * a), byte(color.y * a), byte(color.x * a), 255]\n const corner = (q: number, h: number, uv: [number, number]) =>\n corners.push({\n at: [\n f(f(p.x + q * qx) + h * hx),\n f(f(p.y + q * qy) + h * hy),\n f(f(p.z + q * qz) + h * hz),\n ],\n uv,\n bytes,\n })\n\n corner(1, 1, [shape.u0, shape.v0])\n corner(1, -1, [shape.u1, shape.v0])\n corner(-1, -1, [shape.u1, shape.v1])\n corner(-1, 1, [shape.u0, shape.v1])\n }\n\n if (!corners.length) return undefined\n\n const vertices = new Uint8Array(corners.length * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n corners.forEach(({ at, uv, bytes }, index) => {\n floats.set(at, (index * STRIDE) / 4)\n vertices.set(bytes, index * STRIDE + 12)\n floats.set(uv, (index * STRIDE + 16) / 4)\n })\n\n // `Win3DEnd` makes each quad (0, 1, 2) and (0, 2, 3).\n const indices = new Uint16Array(\n Array.from({ length: corners.length / 4 }, (_, quad) =>\n [0, 1, 2, 0, 2, 3].map((corner) => quad * 4 + corner),\n ).flat(),\n )\n const mesh: VMeshData = {\n name: 'nebula exterior',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: corners.length - 1,\n elementCount: indices.length,\n padding: 0,\n },\n ],\n indices,\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: corners.length,\n indexStart: 0,\n indexCount: indices.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n // `DrawBoltsPass`: from the fog's start, past its span by twenty times as far as that is out.\n const near = f(nebula.fog.near ?? 0)\n const reach = Math.max(((start - near) * 20) / fogDistance, 0)\n const end = f((reach + 1) * fogDistance + start)\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: indices.length,\n // In world space, under the camera's own view.\n world: Matrix4.identity,\n projection,\n materialName: 'nebula exterior',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: {\n name: bound.texture.name,\n entry: bound.texture,\n sampler: DEFAULT_SAMPLER,\n uvSet: 0,\n },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'always',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: alpha ? 'alpha' : 'add',\n unlit: true,\n alphaReference: 4,\n alphaFunction: 'greater',\n fog: fogOf(start, end, nebula.fog.color),\n }\n }\n\n /**\n * The bubble sort `NebulaDrawBolts` runs, far to near by distance from the camera: a pair swaps only\n * when the later is farther by more than 10, and a distance is kept for the next pair only just\n * after a swap, as retail has it.\n */\n #sort(eye: Vector3): void {\n const bits = this.#bits\n const centre = this.zone.position\n\n const distance = ({ position: s }: Bit) => {\n const dx = f(f(centre.x + s.x) - eye.x)\n const dy = f(f(centre.y + s.y) - eye.y)\n const dz = f(f(centre.z + s.z) - eye.z)\n\n return dx * dx + dy * dy + dz * dz\n }\n\n let swapped: number\n\n do {\n swapped = 0\n if (bits.length <= 1) break\n\n let cached = false\n let previous = 0\n\n for (let at = 1; at < bits.length; at++) {\n if (!cached) previous = distance(bits[at - 1]!)\n\n const current = distance(bits[at]!)\n\n if (!(previous < current)) {\n cached = false\n continue\n }\n\n if (!(Math.abs(previous - current) > 10)) continue\n swapped++\n ;[bits[at - 1], bits[at]] = [bits[at]!, bits[at - 1]!]\n cached = true\n }\n } while (swapped > 0)\n }\n}\n","/**\n * A sun: a solar's `star`, a `[star]` of `solar\\StarArch.ini`. `FStarSphere` in\n * `src/freelancer/Client/star_sphere.cpp`, whose name is the decomp's: it is no sky. Its `star_glow`\n * and `star_center` are fans turned to the camera (`DrawBillboard`, `0x5118d0`, and `FUN_0050cd50`),\n * drawn as the solar's own draw in the lists (`FClientSolarGameobj::Slot188`) and again in a field.\n * Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Camera } from './camera.js'\nimport type { LensGlow, StarLensFlare, StarSpines } from './corona.js'\nimport { textureHasAlpha } from './exterior.js'\nimport type { Draw } from './frame.js'\nimport type { TextureShape } from './ring.js'\nimport { unitByte } from './retail.js'\n\nconst f = Math.fround\n\n/** A `[star_glow]`, over `FStarSphere`'s defaults. `star_glow` and `star_center` both name one. */\nexport interface StarGlow {\n /** `shape`, a `tex_shape` of `StarArch.ini`'s `[Texture]`. Nothing draws without one. */\n shape?: TextureShape\n /** `scale`, 1 when absent: times the star's `radius`, half the fan's width. */\n scale?: number\n /** `inner_color`, at the fan's centre. White when absent; each is held to 1 as it's drawn. */\n innerColor?: Vector3\n /** `outer_color`, at its rim. White when absent. */\n outerColor?: Vector3\n}\n\n/**\n * A `[star]`, which the host reads (`FStarSphere::Load`, `0x511020`). Its `alpha` keys, its\n * `star_glow`'s included, are read and never used: the fans take their alpha from the caller.\n */\nexport interface Star {\n /** `radius`, 1000 when absent. */\n radius?: number\n /**\n * `star_glow`: the first of the section's `star_glow` keys that names a `[star_glow]`. With none,\n * the defaults: no shape, so nothing draws, but its scale of 1 still sizes the star.\n */\n glow?: StarGlow\n /** `star_center`: the last key's, and none when that names no `[star_glow]`. */\n center?: StarGlow\n /** `lens_glow`: the first that names a `[lens_glow]`. Its defaults when none does. */\n lensGlow?: LensGlow\n /** `spines`: the first that names a `[spines]`. None when none does. */\n spines?: StarSpines\n /** `lens_flare`: the first that names a `[lens_flare]`. None when none does. */\n lensFlare?: StarLensFlare\n /**\n * `+0x20` and `+0x24`, 1 s each when absent: how fast the flare follows what the corona shows.\n * `intensity_fade_in` and `_out` write them, a 0 as 1e-7, but so do `zone_occlusion_fade_in` and\n * `_out`, unheld (`0x511381`, `0x5113b7`): whichever comes last in the section wins.\n */\n intensityFade?: { fadeIn?: number; fadeOut?: number }\n /**\n * `+0x28` and `+0x2c`, 2 s each when absent: how fast a zone between hides it. No key reaches them\n * in retail, which a mod's patch could.\n */\n zoneOcclusionFade?: { fadeIn?: number; fadeOut?: number }\n}\n\n/** `StarSphereMaxGlowScale` (`0x512620`): the solar's sphere, `Slot178`'s radius about its position. */\nexport const starRadius = ({ radius = 1000, glow, center }: Star): number => {\n const glowScale = f(glow?.scale ?? 1)\n const centerScale = f(center ? (center.scale ?? 1) : 0)\n\n return f((centerScale > glowScale ? centerScale : glowScale) * f(radius))\n}\n\n// XYZ, D3DCOLOR and one UV set: Win3D's FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\nconst WHITE: Vector3 = { x: 1, y: 1, z: 1 }\n\n// `ScaleClampToByte`: times 255 on the FPU, truncated, held to a byte.\nconst byte = unitByte\n\nconst add = (a: Vector3, b: Vector3): Vector3 => ({\n x: f(a.x + b.x),\n y: f(a.y + b.y),\n z: f(a.z + b.z),\n})\nconst sub = (a: Vector3, b: Vector3): Vector3 => ({\n x: f(a.x - b.x),\n y: f(a.y - b.y),\n z: f(a.z - b.z),\n})\nconst scaled = ({ x, y, z }: Vector3, by: number): Vector3 => ({\n x: f(x * by),\n y: f(y * by),\n z: f(z * by),\n})\n\n/**\n * `FUN_0050cd50`: a fan of eight triangles about the centre, through each corner and edge midpoint,\n * the inner colour at the centre and the outer at the rim. A texture with alpha blends by it,\n * one without as `ONE, INVSRCCOLOR` (`0x50cd6e`).\n */\nconst glowDraw = (\n { shape, scale = 1, innerColor = WHITE, outerColor = WHITE }: StarGlow,\n position: Vector3,\n size: number,\n right: Vector3,\n up: Vector3,\n alpha: number,\n projection: Matrix4,\n): Draw | undefined => {\n if (!shape) return undefined\n\n const across = scaled(scaled(right, size), f(scale))\n const over = scaled(scaled(up, size), f(scale))\n // Top left, top right, bottom right, bottom left (`0x50ce2d` on).\n const c0 = add(sub(position, across), over)\n const c1 = add(add(position, across), over)\n const c2 = sub(add(position, across), over)\n const c3 = sub(sub(position, across), over)\n const centre = scaled(add(add(add(c0, c1), c2), c3), 0.25)\n const half = (a: Vector3, b: Vector3) => scaled(add(a, b), 0.5)\n const { u0, v0, u1, v1 } = shape\n const um = f(f(u0 + u1) * 0.5)\n const vm = f(f(v0 + v1) * 0.5)\n // The centre, then the rim clockwise from the top left through corners and edge midpoints, closed.\n const fan: [Vector3, number, number][] = [\n [centre, um, vm],\n [c0, u0, v0],\n [half(c1, c0), um, v0],\n [c1, u1, v0],\n [half(c2, c1), u1, vm],\n [c2, u1, v1],\n [half(c3, c2), um, v1],\n [c3, u0, v1],\n [half(c3, c0), u0, vm],\n [c0, u0, v0],\n ]\n const a = byte(alpha)\n const inner = [byte(innerColor.z), byte(innerColor.y), byte(innerColor.x), a]\n const outer = [byte(outerColor.z), byte(outerColor.y), byte(outerColor.x), a]\n\n const vertices = new Uint8Array(fan.length * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n fan.forEach(([{ x, y, z }, u, v], index) => {\n floats.set([x, y, z], (index * STRIDE) / 4)\n vertices.set(index === 0 ? inner : outer, index * STRIDE + 12)\n floats.set([u, v], (index * STRIDE + 16) / 4)\n })\n\n const count = fan.length\n const mesh: VMeshData = {\n name: 'star glow',\n version: 1,\n primitive: Primitive.TriangleFan,\n format: FORMAT,\n groups: [\n { materialId: 0, vertexStart: 0, vertexEnd: count - 1, elementCount: count, padding: 0 },\n ],\n indices: Uint16Array.from({ length: count }, (_, at) => at),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: count,\n indexStart: 0,\n indexCount: count,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count,\n // In world space, under the camera's own view (`Win3DApplyCamera`).\n world: Matrix4.identity,\n projection,\n materialName: 'star glow',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n // Frame 0 of the shape's texture (`TexShapeGetGpuHandle`).\n texture: { name: shape.texture.name, entry: shape.texture, sampler: DEFAULT_SAMPLER, uvSet: 0 },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'always',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: textureHasAlpha(shape.texture) ? 'alpha' : 'screen',\n unlit: true,\n // What the frame left: `GREATER 0` in `sun_ahead`, on the far list and in a field alike.\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n\n/**\n * `FStarSphere::DrawBillboard` (`0x5118d0`): the star's `star_glow`, then its `star_center` at\n * `alpha` squared, each a square of `radius × size × scale` across, turned to face the camera about\n * its up. Unlit, unculled, with no depth test or writes, under `projection`: the camera's own, its far\n * plane at 250000. The solar's own draw gives an `alpha` and `size` of 1 (`DrawSimple`).\n */\nexport const starGlowDraws = (\n star: Star,\n position: Vector3,\n camera: Camera,\n projection: Matrix4,\n alpha = 1,\n size = 1,\n): Draw[] => {\n const { position: eye, orientation } = camera\n // From the camera to the star, z rounded to a float before it's squared (`0x511970`).\n const dx = position.x - eye.x\n const dy = position.y - eye.y\n const dz = position.z - eye.z\n const dzf = f(dz)\n const inverse = f(1 / Math.sqrt(dz * dzf + dy * dy + dx * dx))\n const dir = { x: f(dx * inverse), y: f(dy * inverse), z: f(dzf * inverse) }\n\n // Across: the way to it crossed with the camera's up, `(m[1], m[4], m[7])`; z unrounded.\n const upX = orientation.x.y\n const upY = orientation.y.y\n const upZ = orientation.z.y\n const rx = f(dir.y * upZ - upY * dir.z)\n const ry = f(dir.z * upX - upZ * dir.x)\n const rz = upY * dir.x - dir.y * upX\n const across = 1 / Math.sqrt(rz * rz + ry * ry + rx * rx)\n const right = { x: f(rx * across), y: f(ry * across), z: f(rz * across) }\n // Up: across crossed with the way to it.\n const up = {\n x: f(right.y * dir.z - right.z * dir.y),\n y: f(right.z * dir.x - dir.z * right.x),\n z: f(dir.y * right.x - right.y * dir.x),\n }\n\n const scale = f((star.radius ?? 1000) * size)\n const draws: Draw[] = []\n const glow = glowDraw(star.glow ?? {}, position, scale, right, up, alpha, projection)\n if (glow) draws.push(glow)\n\n if (star.center) {\n const centre = glowDraw(star.center, position, scale, right, up, f(alpha * alpha), projection)\n if (centre) draws.push(centre)\n }\n\n return draws\n}\n","/**\n * What a ray hits among objects' collision shapes: `PhysicalSystem::FindRayCollisions`\n * (`FUN_0628d1a0`, `src/Common/common_physicalsystem.cpp`), which asks IVP's ray solver of every\n * object in the system and takes its hits nearest first. Each convex hull the ray enters is a hit of\n * its own, so one object can give several. Pure.\n */\nimport { Matrix4, Ray, Vector3 } from '@treewyrm/freelancer/math'\nimport { HullType, type Hull, type Node, type Surface } from '@treewyrm/freelancer/surface'\nimport type { RayHit } from './corona.js'\n\n/** One of an object's physics shapes, in the frame its points are in. */\nexport interface HitboxSurface {\n surface: Surface\n /** Its frame in the world: the object's for the root part's, its own part's for a `!fxd` one. */\n world: Matrix4\n}\n\n/**\n * An object's collision shapes as `BuildIVP_Real` (`0x6288dd0`) makes them: its `.sur`'s root part,\n * which holds every fixed child's hulls too, and each `!fxd` part's own. A `.sph` solar's is a ball\n * of its `solar_radius` instead (`BuildIVP_Sphere`, from `CSolar`'s `0x62b78c5`).\n */\nexport interface Hitbox {\n surfaces?: readonly HitboxSurface[]\n /** A ball about the object's position. Its hits have no hull, so part 0, never a shield. */\n ball?: number\n /** Whether a hull's id, a part's, is a shield's (`CObject::is_shield_part`). None when absent. */\n shield?: (id: number) => boolean\n}\n\n/** An object a ray can hit, and what the hit reports of it. */\nexport interface HitboxObject {\n /** Handed back as the hit's `object`. */\n object?: unknown\n /** `CObject::WorldPosition`. */\n position: Vector3\n /** `CObject::Radius`. */\n radius: number\n hitbox: Hitbox\n}\n\n/** Whether a segment, `length` along a unit ray, comes within a node's sphere. */\nconst reaches = (node: Node, ray: Ray, length: number): boolean => {\n const span = Ray.sphere(ray, node)\n\n return span !== undefined && span.min <= length && span.max >= 0\n}\n\n/**\n * How far along a unit ray it enters a convex hull, its faces wound counter-clockwise from outside,\n * within `length`, or nothing. A ray starting inside one is taken as not hitting it: what IVP's\n * solver does there isn't read, and only a camera inside a hitbox would show it.\n */\nconst enters = (\n hull: Hull,\n points: readonly Vector3[],\n ray: Ray,\n length: number,\n): number | undefined => {\n const span = Ray.hull(ray, points, faces(hull))\n\n return span && span.min >= 0 && span.min <= length ? span.min : undefined\n}\n\nfunction* faces({ faces }: Hull): Generator<readonly [number, number, number]> {\n for (const { points } of faces) yield points\n}\n\n/** How far along a unit ray it enters a ball from outside, within `length`, or nothing. */\nconst entersBall = (center: Vector3, radius: number, ray: Ray, length: number) => {\n const span = Ray.sphere(ray, { center, radius })\n\n return span && span.min > 0 && span.min <= length ? span.min : undefined\n}\n\n/** The unit ray from `from` toward `to`, and how far `to` is along it; none where they meet. */\nconst rayBetween = (from: Vector3, to: Vector3): { ray: Ray; length: number } | undefined => {\n const delta = Vector3.subtract(to, from)\n const length = Vector3.magnitude(delta)\n if (!(length > 0)) return undefined\n return { ray: { origin: from, direction: Vector3.divideScalar(delta, length) }, length }\n}\n\n/**\n * `FindRayCollisions` from `from` to `to`: each hull entered, nearest first, at most `limit`. Inner\n * nodes' bounding hulls only cull, as IVP's ledge tree uses them.\n */\nexport const castRay = (\n objects: readonly HitboxObject[],\n from: Vector3,\n to: Vector3,\n limit: number,\n): RayHit[] => {\n const found: { distance: number; hit: RayHit }[] = []\n const cast = rayBetween(from, to)\n\n for (const { object, position, radius, hitbox } of objects) {\n const hit: RayHit = { position, radius, ...(object !== undefined && { object }) }\n\n if (hitbox.ball !== undefined && cast) {\n const distance = entersBall(position, hitbox.ball, cast.ray, cast.length)\n if (distance !== undefined) found.push({ distance, hit })\n }\n\n for (const { surface, world } of hitbox.surfaces ?? []) {\n const inverse = Matrix4.invert(world)\n const local = rayBetween(\n Matrix4.transformPoint(from, inverse),\n Matrix4.transformPoint(to, inverse),\n )\n if (!local) continue\n\n const { ray, length } = local\n\n const visit = (node: Node) => {\n if (!reaches(node, ray, length)) return\n\n const { hull } = node\n\n if (hull && hull.type === HullType.Enabled) {\n const distance = enters(hull, surface.points, ray, length)\n\n if (distance !== undefined) {\n const shield = hitbox.shield?.(hull.id) ?? false\n\n found.push({ distance, hit: shield ? { ...hit, shield } : hit })\n }\n }\n\n if (node.left) visit(node.left)\n if (node.right) visit(node.right)\n }\n\n visit(surface.root)\n }\n }\n\n return found\n .sort((a, b) => a.distance - b.distance)\n .slice(0, limit)\n .map(({ hit }) => hit)\n}\n","/**\n * A sun's `lens_glow` corona and the state behind its flare: `FStarSphere::UpdateIntensity`\n * (`LAB_00511690`), `FStarSphere::Draw` (`LAB_00511ca0`), `FUN_0050da20` and `FUN_0050e6f0` in\n * `src/freelancer/Client/star_sphere.cpp`. Samples about the sun on screen each cast a ray from the\n * camera, which what's big enough on screen blocks; each sample's alpha eases toward whether it's\n * seen, and the corona is drawn in screen pixels from them. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Camera } from './camera.js'\nimport { textureHasAlpha } from './exterior.js'\nimport type { BlendMode, Draw } from './frame.js'\nimport type { TextureShape } from './ring.js'\nimport type { Star } from './star.js'\nimport { unitByte } from './retail.js'\n\nconst f = Math.fround\n\n/** A `[lens_glow]`, over `SunEffectBodyInit`'s defaults (`FUN_0050d300`, `FUN_0050d420`). */\nexport interface LensGlow {\n /** `shape`. Nothing draws without one, but its samples still block the flare. */\n shape?: TextureShape\n /** `radius_scale`, 2 when absent: the corona's reach, in the star's radii. */\n radiusScale?: number\n /** `inner_color`, at the centre. White when absent. */\n innerColor?: Vector3\n /** `outer_color`, at the rim. White when absent. */\n outerColor?: Vector3\n /** `glow_fade_in_seconds` and `glow_fade_out_seconds`, 0.25 when absent: each sample's easing. */\n fadeIn?: number\n fadeOut?: number\n /** `interior_tween`, 0.5 when absent: where the inner ring stands, centre to rim. */\n interiorTween?: number\n /** `interior_ray_tween`, 1 when absent: where on screen the inner ring's rays are cast from. */\n interiorRayTween?: number\n /** `max_LOD`, truncated, 5 when absent: the most samples, from 0 (one) to 5 (25). */\n maxLod?: number\n}\n\n/** What a ray from the camera hits: `PhySys::FindRayCollisions`'s `RayHit`, and its `CObject`. */\nexport interface RayHit {\n /** What the host calls the object, compared with the sun's own solar and the player's ship. */\n object?: unknown\n /** `CObject::WorldPosition`. */\n position: Vector3\n /** `CObject::Radius`. */\n radius: number\n /** The part hit is a shield's: it never blocks. */\n shield?: boolean\n}\n\n/** What the corona asks of the frame. */\nexport interface CoronaView {\n camera: Camera\n view: Matrix4\n /** The viewport in pixels. */\n width: number\n height: number\n /**\n * `PhySys::FindRayCollisions` from the camera to `to`, at most `limit` hits. None when absent, so\n * nothing blocks.\n */\n rayHits?: (from: Vector3, to: Vector3, limit: number) => readonly RayHit[]\n /** The sun's own solar, which its rays pass through (`0x50c767`). */\n own?: unknown\n /** The player's ship from the cockpit, which they pass through too (`0x50c798`). */\n player?: unknown\n /** The corona's fewest samples, `sunLeastLod`. */\n leastLod: number\n /** `1 - ZoneOcclusion`: the corona's alpha. */\n visibility: number\n}\n\n/**\n * The `SunEffect` option, as `PerfOptions.ini` writes it, to the quality `G_SunEffectQuality`:\n * times 1.33333, held to 1 (`LAB_00510bf0`). At 0 or less no corona, spine or flare draws.\n */\nexport const sunEffectQuality = (option: number): number => f(Math.min(option * 1.33333, 1))\n\n/**\n * The corona's least LOD at a quality: `ftol((1 - Q) · max + 0.5)`. A star is made after the option\n * is applied and before its `max_LOD` is read, so this is of the default 5 (`0x510e9c`); the option\n * changed in a system gives its stars their own `max_LOD`'s instead, which the host can pass.\n */\nexport const sunLeastLod = (quality: number, maxLod = 5): number =>\n Math.trunc(maxLod * (1 - quality) + 0.5)\n\ninterface Slot {\n x: number\n y: number\n u: number\n v: number\n alpha: number\n}\n\n/** What `FStarSphere` and its `lens_glow` body keep between frames. */\ninterface StarState {\n /** `+0x60`: the last update's step. */\n step: number\n /** `+0x64`: the flare's brightness, easing toward what the corona shows. */\n intensity: number\n /** `+0x38`: 1 less how much of the corona showed at the last draw. */\n hidden: number\n /** `+0x34`: eased toward 1 while a zone is between the camera and the sun. */\n zoneOcclusion: number\n /** The centre, then the rim's twelve (`+0x00`), then the inner ring's twelve (`+0x138`). */\n rim: Slot[]\n inner: Slot[]\n /** `+0x258`: each inner quad's diagonal. */\n diagonals: number[]\n /** `+0x2b0`. */\n lod: number\n /** `+0x70`: the sun's depth in view at the last draw, which the flare needs below 0. */\n viewZ: number\n /** `+0x7c`, `+0x80`, `+0x88`: where it was on screen, and its pixel scale, when last projected. */\n x: number\n y: number\n pixelScale: number\n /** This library's: the fades as the frame began, for `starSettled`. */\n began?: number[]\n}\n\nconst states = new WeakMap<Star, StarState>()\n\n/** What eases between frames: the flare's intensity, the zone's occlusion, each slot's alpha. */\nconst fades = ({ intensity, zoneOcclusion, rim, inner }: StarState): number[] => [\n intensity,\n zoneOcclusion,\n ...rim.map(({ alpha }) => alpha),\n ...inner.map(({ alpha }) => alpha),\n]\n\n/** `SunBodyBakeCorona` (`FUN_0050d930`): the rim on a unit circle, the inner ring tweened in. */\nconst stateOf = (star: Star): StarState => {\n let state = states.get(star)\n if (state) return state\n\n const rim: Slot[] = [{ x: 0, y: 0, u: 0.5, v: 0.5, alpha: 1 }]\n\n for (let at = 1; at < 13; at++) {\n const angle = f((at - 1) * f(0.5235987901687622))\n const c = f(Math.cos(angle))\n const s = f(Math.sin(angle))\n\n rim.push({ x: c, y: -s, u: f((c + 1) * 0.5), v: f(0.5 - s * 0.5), alpha: 1 })\n }\n\n const tween = f(star.lensGlow?.interiorTween ?? 0.5)\n const keep = f(1 - tween)\n const centre = rim[0]!\n const inner = rim.slice(1).map((edge) => ({\n x: f(keep * centre.x + tween * edge.x),\n y: f(keep * centre.y + tween * edge.y),\n u: f(keep * centre.u + tween * edge.u),\n v: f(keep * centre.v + tween * edge.v),\n alpha: 1,\n }))\n\n state = {\n step: 0,\n intensity: 1,\n hidden: 0,\n zoneOcclusion: 0,\n rim,\n inner,\n diagonals: Array.from({ length: 12 }, () => 1),\n lod: 0,\n viewZ: 0,\n x: 0,\n y: 0,\n pixelScale: 0,\n }\n states.set(star, state)\n return state\n}\n\n/** `ApproachFloat`: up by one step, down by the other, never past the target. */\nconst approach = (current: number, target: number, up: number, down: number): number => {\n if (target > current) return f(Math.min(current + up, target))\n if (target < current) return f(Math.max(current - down, target))\n return current\n}\n\n/** `ApproachSlotAlpha` and `FUN_00512460`: the approach, held to [0, 1]. */\nconst ease = (slot: Slot, target: number, up: number, down: number) => {\n slot.alpha = Math.min(Math.max(approach(slot.alpha, target, up, down), 0), 1)\n}\n\n/** `CoronaSlotFadeToZero`: a step toward 0, landing on it rather than past. */\nconst fadeToZero = (slot: Slot, up: number, down: number) => {\n if (0 > slot.alpha) {\n const next = up + slot.alpha\n\n slot.alpha = f(next)\n if (next > 0) slot.alpha = 0\n } else if (0 < slot.alpha) {\n const next = slot.alpha - down\n\n slot.alpha = f(next)\n if (next < 0) slot.alpha = 0\n }\n\n slot.alpha = Math.min(Math.max(slot.alpha, 0), 1)\n}\n\n/**\n * `UpdateIntensity`, the solar's own update: the step the next draw eases by, and the flare's\n * brightness toward what the corona last showed. Retail's suns write `intensity_fade_in` 0, which\n * loads as 1e-7, then `zone_occlusion_fade_in`, which lands there too (`0x511381`).\n */\nexport const updateStar = (star: Star, step: number) => {\n const state = stateOf(star)\n\n state.began = fades(state)\n state.step = f(step)\n\n const { fadeIn = 1, fadeOut = 1 } = star.intensityFade ?? {}\n\n state.intensity = approach(\n state.intensity,\n f(1 - state.hidden),\n f(state.step / fadeIn),\n f(state.step / fadeOut),\n )\n}\n\n/**\n * Whether the frame since its last update left every fade as it found it: with the camera still,\n * the next frame would draw it the same, so a host may stop drawing. Not before its first frame.\n */\nexport const starSettled = (star: Star): boolean => {\n const state = states.get(star)\n const began = state?.began\n if (!state || !began) return false\n return fades(state).every((value, at) => value === began[at])\n}\n\n/** The flare's brightness, `+0x64`, and how much a zone hides it, `+0x34`. */\nexport const starIntensity = (star: Star): { intensity: number; zoneOcclusion: number } => {\n const { intensity, zoneOcclusion } = stateOf(star)\n\n return { intensity, zoneOcclusion }\n}\n\n/**\n * The cockpit pass fully inside a field: no draw, only the zone's occlusion at 1\n * (`SpaceEnvFxBeginCockpitPass`, `0x51c99f`).\n */\nexport const hideStar = (star: Star) => {\n stateOf(star).zoneOcclusion = 1\n}\n\n/** `FUN_0050f2a0`: how much of the corona shows, the centre weighted against its rings by LOD. */\nconst shown = ({ rim, inner, lod }: StarState): number => {\n const centre = rim[0]!.alpha\n if (lod === 0) return centre\n\n let sum = 0\n for (const { alpha } of rim.slice(1)) sum = f(sum + alpha)\n if (lod < 3) return f(centre * f(0.2) + sum * f(1 / 12) * f(0.8))\n for (const { alpha } of inner) sum = f(sum + alpha)\n return f(centre * f(0.1) + sum * f(1 / 24) * f(0.9))\n}\n\n/** The camera's screen, as `SpaceCameraSetViewport` sets it up (`0x40fd87`). */\nconst screenOf = ({ fovh, near }: Camera, width: number, height: number) => {\n const aspect = f(width / height)\n const halfWidth = f(width * 0.5)\n const halfHeight = height * 0.5\n // Pixels per view unit at depth 1; `scaleY` is negative because screen Y runs down.\n const tanX = Math.tan(fovh * f(Math.PI / 180))\n const scaleX = f(halfWidth / tanX)\n const scaleY = f(-(halfHeight / f(tanX / aspect)))\n\n return { centreX: halfWidth, centreY: f(halfHeight), scaleX, scaleY, near }\n}\n\ntype Screen = ReturnType<typeof screenOf>\n\n/** `FUN_0050c750`: whether something the ray hits covers more than 0.65 of the sun's pixel scale. */\nconst blocked = (from: Vector3, to: Vector3, pixelScale: number, view: CoronaView): boolean => {\n const { rayHits, own, player, camera } = view\n if (!rayHits) return false\n\n const threshold = f(pixelScale * f(0.65))\n const perUnit = f(camera.near * f(screenOf(camera, view.width, view.height).scaleX / camera.near))\n\n for (const hit of rayHits(from, to, 6).slice(0, 6)) {\n if (hit.shield) continue\n if (hit.object !== undefined && (hit.object === own || hit.object === player)) continue\n\n // The hit's radius in pixels, `scaleX · radius / depth`, with the depth held to 0.1 or more.\n let z = f(Matrix4.transformPoint(hit.position, view.view).z)\n if (z > f(-0.1)) z = f(-0.1)\n if (perUnit * (-1 / z) * hit.radius > threshold) return true\n }\n\n return false\n}\n\n/** `FUN_0050da20`'s per-sample ray (`Unproject`): through the screen point, as far as the sun. */\nconst sampleBlocked = (\n screen: Screen,\n view: CoronaView,\n distance: number,\n pixelScale: number,\n x: number,\n y: number,\n): boolean => {\n const { camera } = view\n // A screen pixel to a point on the near plane in camera space, then to world by the orientation's\n // rows, normalised and run out to the sun's `distance`.\n const local = {\n x: f(f(x - screen.centreX) * f(screen.near / screen.scaleX)),\n y: f(f(y - screen.centreY) * f(screen.near / screen.scaleY)),\n z: -screen.near,\n }\n const { x: rx, y: ry, z: rz } = camera.orientation\n const dir = {\n x: f(rx.x * local.x + rx.y * local.y + rx.z * local.z),\n y: f(ry.x * local.x + ry.y * local.y + ry.z * local.z),\n z: f(rz.x * local.x + rz.y * local.y + rz.z * local.z),\n }\n const inverse = 1 / Math.sqrt(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z)\n const eye = camera.position\n const reachZ = f(f(dir.z * inverse) * distance)\n const to = {\n x: f(f(dir.x * inverse) * distance + eye.x),\n y: f(f(dir.y * inverse) * distance + eye.y),\n z: f(reachZ + eye.z),\n }\n\n return blocked(eye, to, pixelScale, view)\n}\n\n// `FUN_0050da20`'s sample strides by LOD, inner then outer (`0x50de76`).\nconst STRIDES: readonly (readonly [number, number])[] = [\n [14, 14],\n [4, 14],\n [2, 14],\n [2, 2],\n [1, 2],\n [1, 1],\n]\n// `+0x2f8`: pixel scales below which each LOD holds.\nconst LOD_SCALES = [8, 15, 25, 40, 60]\n\n/** `CoronaBlendPair` (`0x50e541`): 0.7 of the lesser, 0.3 of the greater. */\nconst blendPair = (own: number, neighbour: number): number =>\n own > neighbour ? f(neighbour * 0.7 + own * 0.3) : f(neighbour * 0.3 + own * 0.7)\n\n/** `FUN_0050da20`: each sample's alpha eased toward whether its ray is clear, then the gaps filled. */\nconst sample = (\n state: StarState,\n glow: LensGlow,\n sun: Vector3,\n at: { x: number; y: number; pixelScale: number },\n view: CoronaView,\n) => {\n const { rim, inner } = state\n const up = f(state.step / f(glow.fadeIn ?? 0.25))\n const down = f(state.step / f(glow.fadeOut ?? 0.25))\n const screen = screenOf(view.camera, view.width, view.height)\n const { width, height } = view\n const { x: sx, y: sy, pixelScale } = at\n\n let lod = LOD_SCALES.findIndex((scale) => scale > pixelScale)\n if (lod < 0) lod = 5\n lod = lod >= view.leastLod ? lod - view.leastLod : 0\n state.lod = Math.min(lod, Math.trunc(glow.maxLod ?? 5))\n\n const margin = Math.max(pixelScale * f(glow.radiusScale ?? 2), 50)\n const onScreen = (x: number, y: number) =>\n x > -margin && width + margin > x && y > -margin && height + margin > y\n const eye = view.camera.position\n const dx = sun.x - eye.x\n const dy = sun.y - eye.y\n const dz = sun.z - eye.z\n const distance = f(Math.sqrt(dx * dx + dz * dz + dy * dy))\n\n const cast = (slot: Slot, x: number, y: number, by: number) => {\n if (!onScreen(x, y)) return ease(slot, by * 0, up, down)\n\n const clear = sampleBlocked(screen, view, distance, pixelScale, x, y) ? 0 : 1\n\n ease(slot, f(clear * by), up, down)\n }\n\n const centre = rim[0]!\n\n cast(centre, f(pixelScale * centre.x + sx), f(pixelScale * centre.y + sy), 1)\n\n const [innerStride, outerStride] = STRIDES[state.lod]!\n\n if (state.lod > 2) {\n const by = f((centre.alpha + 1) * 0.5)\n const spread = f(glow.interiorRayTween ?? 1)\n\n for (let index = 0; index < 12; index += outerStride) {\n const slot = inner[index]!\n\n cast(slot, f(pixelScale * slot.x * spread + sx), f(pixelScale * slot.y * spread + sy), by)\n }\n }\n\n if (state.lod > 0) {\n let by = f((centre.alpha + 1) * 0.5)\n\n for (let index = 1; index < 13; index += innerStride) {\n const slot = rim[index]!\n\n // From the third LOD each takes the inner ring's sample before it, and keeps it.\n if (state.lod > 2) by = f((inner[index - 1]!.alpha + 1) * 0.5)\n cast(slot, f(pixelScale * slot.x + sx), f(pixelScale * slot.y + sy), by)\n }\n }\n\n if (state.lod === 0) {\n for (const slot of rim.slice(1)) slot.alpha = centre.alpha\n return\n }\n\n // The skipped samples, halfway each pass from their sampled neighbours, the rim wrapping past 12.\n for (let stride = innerStride; stride > 1;) {\n const half = Math.trunc(stride * 0.5)\n\n for (let index = 1; index < 13; index += stride) {\n const next = index + stride\n const neighbour = rim[next > 12 ? next - 12 : next]!.alpha\n\n rim[index + half]!.alpha = blendPair(rim[index]!.alpha, neighbour)\n }\n\n stride = half\n }\n\n if (state.lod === 2)\n for (let index = 0; index < 12; index += 2)\n inner[index]!.alpha = f((rim[index + 1]!.alpha + centre.alpha) * 0.5)\n\n if (state.lod <= 2) return\n\n for (let stride = outerStride; stride > 1;) {\n const half = Math.trunc(stride * 0.5)\n\n for (let index = 0; index < 12; index += stride) {\n const next = index + stride\n const neighbour = inner[next > 11 ? next - 12 : next]!.alpha\n\n inner[index + half]!.alpha = blendPair(inner[index]!.alpha, neighbour)\n }\n\n stride = half\n }\n}\n\n// `ScaleClampToByte`: times 255 on the FPU, truncated, held to a byte.\nconst byte = unitByte\n// XYZ, D3DCOLOR and one UV set: Win3D's FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\nconst WHITE: Vector3 = { x: 1, y: 1, z: 1 }\n\n/** A Win3D vertex in screen pixels: position, `Win3DColor4f`'s colour and alpha, and UV. */\ninterface ScreenVertex {\n x: number\n y: number\n u: number\n v: number\n color: Vector3\n alpha: number\n}\n\n/**\n * Screen-pixel vertices under `Win3DSetProjection(0, W - 1, H - 1, 0)` with an identity modelview\n * (`0x511f25`, `0x51256b`). Depth is off, so they stand at clip z 0 where retail's ortho puts them\n * on its far edge: the same pixels, never clipped. `Win3DEnd` makes quads (0, 1, 2) and (0, 2, 3).\n */\nconst screenDraw = (\n name: string,\n primitive: Primitive | 'quads',\n vertices: readonly ScreenVertex[],\n shape: TextureShape,\n blendMode: BlendMode,\n view: { view: Matrix4; width: number; height: number },\n): Draw => {\n const bytes = new Uint8Array(vertices.length * STRIDE)\n const floats = new Float32Array(bytes.buffer)\n\n vertices.forEach(({ x, y, u, v, color, alpha }, index) => {\n floats.set([x, y, 0], (index * STRIDE) / 4)\n bytes.set([byte(color.z), byte(color.y), byte(color.x), byte(alpha)], index * STRIDE + 12)\n floats.set([u, v], (index * STRIDE + 16) / 4)\n })\n\n const indices =\n primitive === 'quads'\n ? Uint16Array.from({ length: (vertices.length / 4) * 6 }, (_, at) => {\n const quad = Math.trunc(at / 6) * 4\n\n return quad + [0, 1, 2, 0, 2, 3][at % 6]!\n })\n : Uint16Array.from({ length: vertices.length }, (_, index) => index)\n\n const count = indices.length\n const mesh: VMeshData = {\n name,\n version: 1,\n primitive: primitive === 'quads' ? Primitive.TriangleList : primitive,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: vertices.length - 1,\n elementCount: count,\n padding: 0,\n },\n ],\n indices,\n vertices: bytes,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: vertices.length,\n indexStart: 0,\n indexCount: count,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n const { width, height } = view\n // Pixels to clip: X 0..W-1 to -1..1, Y 0..H-1 to 1..-1, Z flattened to 0.\n const projection: Matrix4 = {\n x: { x: 2 / (width - 1), y: 0, z: 0, w: 0 },\n y: { x: 0, y: -2 / (height - 1), z: 0, w: 0 },\n z: { x: 0, y: 0, z: 0, w: 0 },\n w: { x: -1, y: 1, z: 0, w: 1 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count,\n world: Matrix4.invert(view.view),\n projection,\n materialName: name,\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n // Frame 0 of the shape's texture (`TexShapeGetGpuHandle`).\n texture: { name: shape.texture.name, entry: shape.texture, sampler: DEFAULT_SAMPLER, uvSet: 0 },\n cull: 'none',\n // `ZENABLE` 0: neither tested nor written. `ZWRITEENABLE` is as the frame left it, 1 in\n // `sun_ahead`, and moot, where GL's mask would write through `ALWAYS`.\n depthWrite: false,\n depthFunc: 'always',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode,\n unlit: true,\n // What the screen quads left: `GREATER 0`, as `sun_ahead` captures it.\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n\n/** A band's sign: above 0.999, below 0.001, or between (`CoronaAlphaSignBand`). */\nconst band = (value: number): number => (value > f(0.999) ? 1 : value < f(0.001) ? -1 : 0)\n\n/**\n * `FUN_0050e6f0`: under the third LOD, a fan from the centre round the rim; from it, the band\n * between the inner ring and the rim, each quad split along the diagonal its alphas favour, then a\n * fan from the centre round the inner ring. Each vertex at half its sample's alpha\n * (`CoronaEmitVertex`, `FUN_0050f230`).\n */\nconst coronaDraws = (\n state: StarState,\n glow: LensGlow,\n at: { x: number; y: number; pixelScale: number },\n view: CoronaView,\n): Draw[] => {\n const { shape } = glow\n if (!shape) return []\n\n const inner = glow.innerColor ?? WHITE\n const outer = glow.outerColor ?? WHITE\n // Set only once a `[lens_glow]` is found (`0x50d6f7`), which a shape needs.\n const tween = f(glow.interiorTween ?? 0.5)\n const keep = f(1 - tween)\n const middle = {\n x: f(keep * inner.x + tween * outer.x),\n y: f(keep * inner.y + tween * outer.y),\n z: f(keep * inner.z + tween * outer.z),\n }\n const scale = f(f(glow.radiusScale ?? 2) * at.pixelScale)\n const emit = (slot: Slot, color: Vector3): ScreenVertex => ({\n x: f(scale * slot.x + at.x),\n y: f(scale * slot.y + at.y),\n u: slot.u,\n v: slot.v,\n color,\n alpha: f(0.5 * slot.alpha * view.visibility),\n })\n // A texture with alpha adds by it, one without adds whole (`0x50e81a`).\n const blendMode: BlendMode = textureHasAlpha(shape.texture) ? 'alphaAdd' : 'add'\n const draw = (primitive: Primitive, vertices: ScreenVertex[]) =>\n screenDraw('corona', primitive, vertices, shape, blendMode, view)\n const { rim, inner: ring, diagonals } = state\n const centre = emit(rim[0]!, inner)\n\n if (state.lod < 3)\n return [\n draw(Primitive.TriangleFan, [\n centre,\n ...rim.slice(1).map((slot) => emit(slot, outer)),\n emit(rim[1]!, outer),\n ]),\n ]\n\n const triangles: ScreenVertex[] = []\n\n for (let index = 0; index < 12; index++) {\n const local = index + 1\n const mid = ring[index]!\n const midA = ring[local <= 11 ? local : local - 12]!\n const rimB = rim[local]!\n const rimC = rim[local + 1 <= 12 ? local + 1 : local + 1 - 12]!\n let first = band(mid.alpha)\n let second = band(midA.alpha)\n\n if (first === second) {\n first = band(rimB.alpha)\n second = band(rimC.alpha)\n }\n\n if (first !== second)\n diagonals[index] = first === 1 ? 0 : first === -1 ? 1 : second === 1 ? 1 : 0\n\n const m = (slot: Slot) => emit(slot, middle)\n const o = (slot: Slot) => emit(slot, outer)\n\n // The quad `midA`, `mid`, `rimB`, `rimC` split along `midA`–`rimB` (0) or `mid`–`rimC` (1).\n triangles.push(\n ...(diagonals[index] === 0\n ? [m(midA), m(mid), o(rimB), m(midA), o(rimB), o(rimC)]\n : [m(midA), m(mid), o(rimC), m(mid), o(rimB), o(rimC)]),\n )\n }\n\n return [\n draw(Primitive.TriangleList, triangles),\n draw(Primitive.TriangleFan, [\n centre,\n ...ring.map((slot) => emit(slot, middle)),\n emit(ring[0]!, middle),\n ]),\n ]\n}\n\n/** One `spine`: its length and width in the star's pixel scale, its colours base to tip, alpha. */\nexport interface StarSpine {\n length: number\n width: number\n innerColor: Vector3\n outerColor: Vector3\n alpha: number\n}\n\n/** A `[spines]` (`FUN_0050fba0`), over `FStarSphere`'s defaults. */\nexport interface StarSpines {\n /** `shape`. Nothing draws without one. */\n shape?: TextureShape\n /** `radius_scale`, 1 when absent: every spine's length and width times it. */\n radiusScale?: number\n /** `min_radius` and `max_radius`, 1 and 1000 when absent: the pixel scale held between. */\n minRadius?: number\n maxRadius?: number\n /** In file order, spread evenly round from the right, anticlockwise on screen. */\n spines: readonly StarSpine[]\n}\n\n/** A `bead` of a `[lens_flare]`: how far along, how big, its colour and alpha. */\nexport interface FlareBead {\n along: number\n size: number\n color: Vector3\n alpha: number\n}\n\n/** A `[lens_flare]` (`FUN_0050f3a0`), over `FStarSphere`'s defaults. */\nexport interface StarLensFlare {\n /** `shape`: its texture, whole. Nothing draws without one. */\n shape?: TextureShape\n /** `min_radius` and `max_radius`, 5 and 800 when absent: the pixel scale held between. */\n minRadius?: number\n maxRadius?: number\n /**\n * Its beads. Retail sorts them by where the heap put them, but they add, so any order gives the\n * same pixels.\n */\n beads: readonly FlareBead[]\n}\n\n/** `FUN_00510990`: how much of the corona shows about a spine, by the samples near it. */\nconst spineShown = ({ rim, inner, lod }: StarState, index: number, count: number): number => {\n const outer = (at: number) => rim[at]!.alpha\n const ring = (at: number) => inner[at]!.alpha\n const wrapOuter = (at: number) => (at > 12 ? at - 12 : at)\n const wrapLow = (at: number) => (at < 0 ? at + 12 : at)\n const wrapHigh = (at: number) => (at > 11 ? at - 12 : at)\n\n // A weighted blur of the rim samples about the spine's base, and from LOD 3 the inner ring's;\n // each divisor is its weights' total (4 or 9, 10 or 24). The rim wraps over 1..12, the ring 0..11.\n switch (count) {\n case 12: {\n const sum = outer(wrapOuter(index + 1))\n\n return lod <= 2 ? sum : (sum + ring(index)) / 2\n }\n case 4:\n case 6: {\n // The first spine's base is the centre's sample, as retail indexes it.\n const base = count === 6 ? index * 2 : Math.trunc(index * 3)\n let sum = outer(wrapOuter(base + 1))\n\n sum = sum + sum + outer(base) + outer(wrapOuter(base + 2))\n if (lod <= 2) return sum / 4\n sum = sum + ring(wrapLow(base - 1)) + ring(base) * 3 + ring(wrapHigh(base + 1))\n return sum / 9\n }\n case 2: {\n const base = Math.trunc(index * 6)\n const minus = base - 1 < 1 ? base - 1 + 12 : base - 1\n const twice = outer(base) + outer(base)\n let sum = outer(minus) + twice\n\n sum = sum + outer(wrapOuter(base + 1)) * 4\n sum = sum + (outer(wrapOuter(base + 2)) + outer(wrapOuter(base + 2)))\n sum = sum + outer(wrapOuter(base + 2))\n if (lod <= 2) return sum / 10\n sum =\n sum +\n ring(wrapLow(base - 2)) +\n ring(wrapLow(base - 1)) * 3 +\n ring(base) * 6 +\n ring(wrapHigh(base + 1)) * 3 +\n ring(wrapHigh(base + 2))\n return sum / 24\n }\n default:\n return 0\n }\n}\n\n// `DAT_0061346c`: how much of a spine's alpha its own corona samples give, against the intensity.\nconst SPINE_BLEND = f(0.8)\n\n/** A spine's angles: `2π / count` apart from 0, summed as floats (`0x50fe1c`). */\nconst spineAngles = (count: number): number[] => {\n const step = f(f(f(Math.PI) * 2) / count)\n let angle = 0\n\n return Array.from({ length: count }, () => {\n const at = angle\n\n angle = f(angle + step)\n return at\n })\n}\n\n/**\n * `FUN_00510160`: each spine three quads out from the sun, base to the inner ring's radius, to the\n * rim's, to its tip, fading in from nothing at the base, added by alpha (`SRCALPHA, ONE`).\n */\nconst spinesDraw = (\n state: StarState,\n star: Star,\n at: { x: number; y: number; pixelScale: number },\n visibility: number,\n view: CoronaView,\n): Draw | undefined => {\n const settings = star.spines\n const shape = settings?.shape\n if (!settings || !shape) return undefined\n\n const { minRadius = 1, maxRadius = 1000, radiusScale = 1 } = settings\n let scale = at.pixelScale\n\n if (scale > f(maxRadius)) scale = f(maxRadius)\n else if (scale < f(minRadius)) scale = f(minRadius)\n\n const glow = star.lensGlow ?? {}\n const tween = f(glow.interiorTween ?? 0.5)\n const bodyScale = f(glow.radiusScale ?? 2)\n const innerR = f(tween * bodyScale * scale)\n const outerR = f(scale * bodyScale * (tween + 1) * 0.5)\n const centreAlpha = state.rim[0]!.alpha\n const { x: sx, y: sy } = at\n const { u0, v0, u1, v1 } = shape\n const count = settings.spines.length\n const angles = spineAngles(count)\n const vertices: ScreenVertex[] = []\n\n settings.spines.forEach((spine, index) => {\n const cos = f(Math.cos(angles[index]!))\n const sin = f(Math.sin(angles[index]!))\n const length = scale * f(spine.length * f(radiusScale))\n const halfWidth = scale * f(spine.width * f(radiusScale)) * 0.5\n const t0 = f(innerR * (1 / length))\n const t1 = f((1 / length) * outerR)\n // Out along (cos, -sin), across by (sin, cos) · ±half width.\n const point = (across: number, out: number) => ({\n x: f(across * sin + sx + f(cos * out)),\n y: f(across * cos - f(sin * out) + sy),\n })\n const alpha = f(\n ((1 - SPINE_BLEND) * state.intensity + spineShown(state, index, count) * SPINE_BLEND) *\n spine.alpha *\n visibility,\n )\n const uInner = f(t0 * u1 + u0 * (1 - t0))\n const uOuter = f(t1 * u1 + u0 * (1 - t1))\n const lerp = (t: number): Vector3 => ({\n x: f((1 - t) * spine.innerColor.x + t * spine.outerColor.x),\n y: f((1 - t) * spine.innerColor.y + t * spine.outerColor.y),\n z: f((1 - t) * spine.innerColor.z + t * spine.outerColor.z),\n })\n const innerColor = lerp(t0)\n const outerColor = lerp(t1)\n const innerAlpha = f(alpha * centreAlpha)\n const rows = [\n { out: 0, u: u0, color: spine.innerColor, alpha: 0 },\n { out: innerR, u: uInner, color: innerColor, alpha: innerAlpha },\n { out: outerR, u: uOuter, color: outerColor, alpha },\n { out: length, u: u1, color: spine.outerColor, alpha },\n ]\n\n for (let quad = 0; quad < 3; quad++) {\n const near = rows[quad]!\n const far = rows[quad + 1]!\n const corner = (row: typeof near, across: number, v: number): ScreenVertex => ({\n ...point(across, row.out),\n u: row.u,\n v,\n color: row.color,\n alpha: row.alpha,\n })\n\n vertices.push(\n corner(near, -halfWidth, v0),\n corner(far, -halfWidth, v0),\n corner(far, halfWidth, v1),\n corner(near, halfWidth, v1),\n )\n }\n })\n if (!vertices.length) return undefined\n return screenDraw('spines', 'quads', vertices, shape, 'alphaAdd', view)\n}\n\n/**\n * `FStarSphere::Draw` (`LAB_00511ca0`) after the effects: the zone's occlusion eased toward\n * `zoneBlocked`, what showed of the corona noted for the flare, the sun projected, its samples\n * cast, then its spines and its corona drawn. Nothing past a zone's full occlusion, nor with the sun\n * behind.\n */\nexport const starCorona = (\n star: Star,\n position: Vector3,\n zoneBlocked: boolean,\n view: Omit<CoronaView, 'visibility'>,\n): Draw[] => {\n const state = stateOf(star)\n const glow = star.lensGlow ?? {}\n const { fadeIn = 2, fadeOut = 2 } = star.zoneOcclusionFade ?? {}\n // Toward 1 by the fade-out's step and back by the fade-in's (`0x511cf6`).\n const target = zoneBlocked ? 1 : 0\n\n if (target > state.zoneOcclusion) {\n const next = state.step / fadeOut + state.zoneOcclusion\n\n state.zoneOcclusion = next > target ? target : f(next)\n } else if (target < state.zoneOcclusion) {\n const next = state.zoneOcclusion - state.step / fadeIn\n\n state.zoneOcclusion = next < target ? target : f(next)\n }\n\n if (!(state.zoneOcclusion < 1)) return []\n\n const { camera, width, height } = view\n const inView = Matrix4.transformPoint(position, view.view)\n\n state.viewZ = f(inView.z)\n state.hidden = f(1 - shown(state))\n\n const all = [...state.rim, ...state.inner]\n const up = f(state.step / f(glow.fadeIn ?? 0.25))\n const down = f(state.step / f(glow.fadeOut ?? 0.25))\n // `Project`: nothing nearer than the near plane.\n const local = { x: f(inView.x), y: f(inView.y), z: f(inView.z) }\n\n if (!(-camera.near >= local.z)) {\n if (state.hidden < 1) for (const slot of all) ease(slot, 0, up, down)\n return []\n }\n\n const screen = screenOf(camera, width, height)\n const invZ = -1 / local.z\n\n state.x = f(local.x * screen.scaleX * invZ + screen.centreX)\n state.y = f(local.y * screen.scaleY * invZ + screen.centreY)\n\n const depth = Math.max(f(-local.z), f(0.1))\n\n state.pixelScale = f(\n camera.near * f(screen.scaleX / camera.near) * ((star.radius ?? 1000) / depth),\n )\n\n const { x, y, pixelScale } = state\n\n if (local.z >= 0) return []\n\n const reach = Math.max(f(f(glow.radiusScale ?? 2) * pixelScale * 2), 50)\n const bodyOnScreen = x > -reach && width + reach > x && y > -reach && height + reach > y\n // The longest spine, after `radius_scale`, times the pixel scale (`0x511fe5`).\n const radiusScale = f(star.spines?.radiusScale ?? 1)\n const longest = (star.spines?.spines ?? []).reduce(\n (most, { length }) => (most > f(length * radiusScale) ? most : f(length * radiusScale)),\n 0,\n )\n const spineReach = f(longest * pixelScale)\n const spinesOnScreen =\n x > -spineReach && width + spineReach > x && y > -spineReach && height + spineReach > y\n const at = { x, y, pixelScale }\n\n if (bodyOnScreen) sample(state, glow, position, at, { ...view, visibility: 1 })\n else if (!spinesOnScreen) {\n if (state.hidden < 1) {\n const glowUp = 5 / f(glow.fadeIn ?? 0.25)\n const glowDown = 5 / f(glow.fadeOut ?? 0.25)\n for (const slot of all) fadeToZero(slot, glowUp, glowDown)\n }\n\n return []\n } else if (state.hidden < 1) for (const slot of all) fadeToZero(slot, up, down)\n\n const visibility = f(1 - state.zoneOcclusion)\n const draws: Draw[] = []\n\n if (spinesOnScreen) {\n const spines = spinesDraw(state, star, at, visibility, { ...view, visibility })\n if (spines) draws.push(spines)\n }\n\n if (bodyOnScreen) draws.push(...coronaDraws(state, glow, at, { ...view, visibility }))\n return draws\n}\n\n/**\n * `FStarSphere::DrawFlare` (`LAB_005124f0`), at the cockpit pass's end: the beads along the line\n * from the sun through the screen's middle, at the screen place and pixel scale the last draw left,\n * each a square of the whole texture, added by alpha (`SRCALPHA, ONE`). They fade as the sun nears\n * the middle, brighten with `Intensity`, and go with the zone's occlusion and the sun behind.\n */\nexport const starFlare = (\n star: Star,\n view: { view: Matrix4; width: number; height: number },\n): Draw | undefined => {\n const state = stateOf(star)\n // The pass gives 1 for its step, so this is the zone's visibility (`0x51250a`).\n const visibility = f(1 - state.zoneOcclusion)\n if (!(visibility * state.intensity > 0)) return undefined\n if (!(state.viewZ < 0)) return undefined\n\n const flare = star.lensFlare\n const shape = flare?.shape\n if (!flare || !shape) return undefined\n\n const { width, height } = view\n // The viewport's rectangle ends on its last pixel.\n const midX = (width - 1) * 0.5\n const midY = f((height - 1) * 0.5)\n const fadeBy = 1 - state.intensity\n const brightness = 1 - fadeBy * fadeBy\n let scale = state.pixelScale\n\n if (scale > f(flare.maxRadius ?? 800)) scale = f(flare.maxRadius ?? 800)\n else if (scale < f(flare.minRadius ?? 5)) scale = f(flare.minRadius ?? 5)\n\n const half = f(scale * brightness * visibility)\n // Beads sit at the sun + 3 · (middle - sun) · `along`; the alpha ramps in by squared distance\n // from the middle inside a tenth of the width.\n const dx = midX - state.x\n const dy = midY - state.y\n const tenth = (width - 1) * 0.1\n const limit = f(tenth * tenth)\n const squared = dy * dy + dx * dx\n const fade = squared < limit ? f(squared / limit) : 1\n const axisX = f(dx * 3)\n const axisY = f(dy * 3)\n const vertices: ScreenVertex[] = []\n\n for (const { along, size, color, alpha } of flare.beads) {\n const cx = f(axisX * along + state.x)\n const cy = f(f(axisY * along) + state.y)\n const h = f(half * size)\n const x0 = f(cx - h)\n const x1 = f(cx + h)\n const y0 = f(cy - h)\n const y1 = f(cy + h)\n const a = f(fade * alpha)\n\n vertices.push(\n { x: x0, y: y0, u: 0, v: 0, color, alpha: a },\n { x: x1, y: y0, u: 1, v: 0, color, alpha: a },\n { x: x1, y: y1, u: 1, v: 1, color, alpha: a },\n { x: x0, y: y1, u: 0, v: 1, color, alpha: a },\n )\n }\n\n if (!vertices.length) return undefined\n return screenDraw('lens flare', 'quads', vertices, shape, 'alphaAdd', view)\n}\n","/**\n * A frame's own triangles of code-built effects, as D3D's FVF `0x142` (XYZ, D3DCOLOR, one UV) holds\n * them: world-placed, unlit, the texture times each vertex's colour, added, unculled, `LEQUAL` and no\n * depth writes. The shots' batch and a tractor's lines are drawn so. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport type { Draw } from './frame.js'\nimport type { Fog } from './nebula.js'\nimport { DEFAULT_SAMPLER, type SamplerState } from '#/texture/texture.js'\n\n/** Vertices as `x, y, z, u, v`, colours as D3D's bytes `b, g, r, a`, and triangles. */\nexport interface ImmediateBatch {\n vertices: number[]\n colors: number[]\n indices: number[]\n count: number\n}\n\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst ORIGIN: Vector3 = { x: 0, y: 0, z: 0 }\n\n// Left as Alchemy's `BeginDraw` set it, the last before either, which set none. Captured for the\n// shots in `beam_shots`: clamped, linear, mips by nearest.\nconst IMMEDIATE_SAMPLER: SamplerState = { ...DEFAULT_SAMPLER, wrapU: 'clamp', wrapV: 'clamp' }\n\n/**\n * One draw of a batch, at the texture's first frame. The fog is the effects', black in a nebula; the\n * alpha test is inherited, `GREATER 0`, captured for the shots in `beam_shots`. Nothing with\n * nothing built.\n */\nexport const immediateDraw = (\n name: string,\n { count, vertices: built, colors, indices }: ImmediateBatch,\n texture: Texture,\n fog?: Fog,\n): Draw | undefined => {\n if (!indices.length) return undefined\n\n const vertices = new Uint8Array(count * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n // Interleaves into 24-byte vertices: xyz at 0, BGRA bytes at 12, uv at 16.\n for (let at = 0; at < count; at++) {\n floats.set(built.slice(at * 5, at * 5 + 3), (at * STRIDE) / 4)\n vertices.set(colors.slice(at * 4, at * 4 + 4), at * STRIDE + 12)\n floats.set(built.slice(at * 5 + 3, at * 5 + 5), (at * STRIDE + 16) / 4)\n }\n\n const mesh: VMeshData = {\n name,\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: count - 1,\n elementCount: indices.length,\n padding: 0,\n },\n ],\n indices: Uint16Array.from(indices),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: count,\n indexStart: 0,\n indexCount: indices.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: ORIGIN, max: ORIGIN },\n boundingSphere: { center: ORIGIN, radius: 0 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: indices.length,\n world: Matrix4.identity,\n materialName: name,\n diffuse: [1, 1, 1, 1],\n ambient: ORIGIN,\n emissive: ORIGIN,\n colorVertex: true,\n nomad: false,\n texture: { name: texture.name, entry: texture, sampler: IMMEDIATE_SAMPLER, uvSet: 0 },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'lequal',\n lightless: true,\n ...(fog && { fog }),\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'add',\n unlit: true,\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n","/**\n * A gun's shot, as the game draws it: `FBeamEffect` (`src/freelancer/Client/beam_effect.cpp`), a cross\n * of tris along the shot that grows to its length over its first moments and fades once it's over.\n * All of a frame's shots are one additive batch, after the effects (`EffectVertexBatchFlush`). What\n * moves a shot, and what it hits, is the host's. Pure, no GL.\n */\nimport { Matrix3, Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport type { Camera } from './camera.js'\nimport {\n RETAIL_EFFECT_TYPES,\n withinSides,\n type EffectType,\n type EffectViewOptions,\n} from './effect-view.js'\nimport type { Draw } from './frame.js'\nimport { immediateDraw, type ImmediateBatch } from './immediate.js'\nimport type { Fog } from './nebula.js'\n\nconst f = Math.fround\n\n// `EFT_CODE_PROJ_EFFECT`, which `Start` hardcodes (`LAB_004f9600`).\nconst BEAM_EFFECT_TYPE = 0x2c\n\n/** What retail hardcodes, and a mod can patch. */\nexport interface BeamLimits {\n /** The shot's sphere, in the view test (`FUN_004f9540`'s `+0x74`). */\n radius: number\n /** Seconds it fades over, once it's over, and the most it can have left (`DAT_006129cc`). */\n fade: number\n /** Added to `core_length` and `tail_length` for how far it travels while it grows (`DAT_005d9e0c`). */\n growthPad: number\n}\n\nexport const RETAIL_BEAM_LIMITS: Readonly<BeamLimits> = {\n radius: 50,\n fade: f(0.3),\n growthPad: 7.5,\n}\n\n/** A `[BeamSpear]` or `[BeamBolt]`, as `FUN_0042e4a0` reads it: colours are 0 to 1, by 1/255 as a float. */\nexport interface BeamArchetype {\n kind: 'spear' | 'bolt'\n tipColor: Vector3\n tailColor: Vector3\n coreColor: Vector3\n secCoreColor: Vector3\n outerColor: Vector3\n secOuterColor: Vector3\n headBrightness: number\n trailBrightness: number\n tipLength: number\n tailLength: number\n coreLength: number\n coreWidth: number\n secCoreWidth: number\n headWidth: number\n /** The width on a shot's first frame, from outside the cockpit. */\n flashSize: number\n /** `head_texture = ball`: the top half of the head's V, where anything else has the bottom. */\n ballHead: boolean\n /** `trail_texture = thin`: the left of the trail's U, where anything else has the right. */\n thinTrail: boolean\n}\n\n/** As written, a colour 0 to 255: the keys `[BeamSpear]` and `[BeamBolt]` use. */\nexport interface BeamSection {\n kind: BeamArchetype['kind']\n tipColor?: Vector3\n tailColor?: Vector3\n coreColor?: Vector3\n secCoreColor?: Vector3\n outerColor?: Vector3\n secOuterColor?: Vector3\n headBrightness?: number\n trailBrightness?: number\n tipLength?: number\n tailLength?: number\n coreLength?: number\n coreWidth?: number\n secCoreWidth?: number\n headWidth?: number\n flashSize?: number\n headTexture?: string\n trailTexture?: string\n}\n\nconst BRIGHTNESS_LEAST = f(0.01)\nconst BYTE_TO_UNIT = f(0.003921569)\n\n// `WriteRgb255`. A key not written keeps `FUN_0042e430`'s default, 1, which no 1/255 scale reached.\nconst unit = (color: Vector3 | undefined): Vector3 =>\n color\n ? {\n x: f(f(color.x) * BYTE_TO_UNIT),\n y: f(f(color.y) * BYTE_TO_UNIT),\n z: f(f(color.z) * BYTE_TO_UNIT),\n }\n : { x: 1, y: 1, z: 1 }\n\nconst brightness = (value: number): number =>\n value < BRIGHTNESS_LEAST ? BRIGHTNESS_LEAST : value > 1 ? 1 : value\n\n/**\n * A section to what's drawn: each key defaults to 1 (`FUN_0042e430`), then `FUN_0042e920` holds the\n * lengths to the widths and each brightness to 0.01 to 1. A bolt's tail is held to `sec_core_width`\n * where a spear's is to `core_width`.\n */\nexport const beamArchetype = (section: BeamSection): BeamArchetype => {\n const coreWidth = f(section.coreWidth ?? 1)\n const secCoreWidth = f(section.secCoreWidth ?? 1)\n\n return {\n kind: section.kind,\n tipColor: unit(section.tipColor),\n tailColor: unit(section.tailColor),\n coreColor: unit(section.coreColor),\n secCoreColor: unit(section.secCoreColor),\n outerColor: unit(section.outerColor),\n secOuterColor: unit(section.secOuterColor),\n headBrightness: brightness(f(section.headBrightness ?? 1)),\n trailBrightness: brightness(f(section.trailBrightness ?? 1)),\n tipLength: Math.max(f(section.tipLength ?? 1), coreWidth),\n tailLength: Math.max(\n f(section.tailLength ?? 1),\n section.kind === 'bolt' ? secCoreWidth : coreWidth,\n ),\n coreLength: f(section.coreLength ?? 1),\n coreWidth,\n secCoreWidth,\n headWidth: Math.max(f(section.headWidth ?? 1), coreWidth),\n flashSize: f(section.flashSize ?? 1),\n // Each is compared to five characters, its case kept (`Match5`).\n ballHead: section.headTexture === 'ball',\n thinTrail: section.trailTexture === 'thin',\n }\n}\n\n/**\n * `LookMatrix` (`Common/common_csys.cpp`): the turn whose -Z runs along `direction`. The player's guns\n * look along each barrel's aim like this, the shot's own orientation aside (`CliBeamActivateEffects`).\n * Its side is a retail quirk: `(-x, y)` of the negated direction, and `+Y` straight ahead.\n */\nexport const lookMatrix = ({ x, y, z }: Vector3): Matrix3 => {\n const length = Math.sqrt(x * x + y * y + z * z)\n const inverse = -1 / length\n const lookX = length > 1e-4 ? f(inverse * x) : 1\n const lookY = length > 1e-4 ? f(inverse * y) : 0\n const lookZ = length > 1e-4 ? f(inverse * z) : 0\n const straight = !(Math.abs(lookX) >= 1e-4 || Math.abs(lookY) >= 1e-4)\n const sideX = straight ? 0 : -lookX\n const sideY = straight ? 1 : lookY\n const c0 = f(lookY * 0 - lookZ * sideX)\n const c1 = f(lookZ * sideY - lookX * 0)\n const c2 = f(sideX * lookX - sideY * lookY)\n const scale = f(1 / Math.sqrt(c2 * c2 + c1 * c1 + c0 * c0))\n const c0n = c0 * scale\n const c1n = c1 * scale\n const c2n = f(c2 * scale)\n\n // Columns: `look × c`, `c` (normalised, from look and the quirky side) and `look`.\n return {\n x: {\n x: f(lookZ * c1n - c2n * lookY),\n y: f(c2n * lookX - lookZ * c0n),\n z: f(c0n * lookY - c1n * lookX),\n },\n y: { x: f(c0n), y: f(c1n), z: c2n },\n z: { x: lookX, y: lookY, z: lookZ },\n }\n}\n\n/** Where a shot starts, as `CliBeamActivateEffects` (`0x53f340`) has it. */\nexport interface BeamStart {\n orientation: Matrix3\n position: Vector3\n /** How fast it leaves, which sets how long it takes to grow to its length. */\n speed: number\n /**\n * The player's own: it looks along each barrel's aim (`lookMatrix`), and a spear's first frame\n * takes `flash_size`. Only then does a spear flash, and never from the cockpit.\n */\n look?: boolean\n}\n\n/**\n * One shot, from the frame it's fired to the frame it's gone. Each frame the host places it, and\n * `collectSpaceFrame` ages and draws it.\n *\n * A hit ends it at once (`FClientBeamGameobj::Slot194`): the host stops giving it. A life that runs\n * out `kill`s it: it coasts on and fades, and the host drops it once it's `dead`.\n */\nexport class BeamEffect {\n readonly archetype: BeamArchetype\n orientation: Matrix3\n position: Vector3\n private readonly limits: BeamLimits\n private readonly look: boolean\n private readonly growth: number\n private age = -1\n private left = -1\n private velocity?: Vector3\n dead = false\n\n constructor(\n archetype: BeamArchetype,\n { orientation, position, speed, look = false }: BeamStart,\n limits: Partial<BeamLimits> = {},\n ) {\n this.archetype = archetype\n this.orientation = orientation\n this.position = position\n this.limits = { ...RETAIL_BEAM_LIMITS, ...limits }\n this.look = look\n // `FUN_004fc8b0`.\n this.growth = f(\n (f(archetype.coreLength) + f(archetype.tailLength) + this.limits.growthPad) / speed,\n )\n }\n\n /** Where the shot's object is. A killed shot goes on by itself, and this does nothing. */\n place(orientation: Matrix3, position: Vector3) {\n if (this.velocity) return\n this.orientation = orientation\n this.position = position\n }\n\n /**\n * Its life ran out (`LAB_004f97a0`): from its object's velocity it coasts, and fades over\n * `limits.fade`, or what it has left of that if killed again.\n */\n kill(velocity: Vector3) {\n this.velocity ??= velocity\n if (this.left < 0 || this.left > this.limits.fade) this.left = this.limits.fade\n }\n\n /**\n * One frame of the walk (`EffectTypeBucketWalk`), the step held to 0.1 there: its coast, then\n * `UpdateVisibility`, then `TickDraw`, ending with what it builds into `batch`, if it's seen.\n */\n walk(step: number, seen: BeamSeen, batch: BeamBatch) {\n if (this.dead) return\n\n const { velocity, position } = this\n\n if (velocity)\n this.position = {\n x: f(position.x + step * velocity.x),\n y: f(position.y + step * velocity.y),\n z: f(position.z + step * velocity.z),\n }\n\n const fate = seen(this.position, this.limits.radius)\n\n if (fate === 'die') {\n this.dead = true\n return\n }\n\n this.age = this.age >= 0 ? f(this.age + step) : 0\n\n if (this.left > 0) {\n this.left = f(this.left - step)\n\n if (this.left <= 0) {\n this.dead = true\n return\n }\n }\n\n if (fate === 'draw') this.build(batch)\n }\n\n // `LAB_004fa0a0`, past the option: the growth's `t` and the fade's intensity. On a first frame\n // both kinds build a spear, so the flash in `FUN_004fb1e0` is never reached.\n private build(batch: BeamBatch) {\n const { archetype, age, growth, left, limits, look } = this\n const t = age < growth ? f(age / growth) : 1\n const intensity = left > 0 ? f(left / limits.fade) : 1\n\n if (t === 0 || archetype.kind === 'spear')\n buildSpear(archetype, this, t, intensity, look && t === 0 && !batch.firstPerson, batch)\n else buildBolt(archetype, this, t, intensity, batch)\n }\n}\n\n/** The view test's answer for a place and radius. */\nexport type BeamSeen = (position: Vector3, radius: number) => 'draw' | 'run' | 'die'\n\n/**\n * `LAB_004f9980`, and what the walk does with it: under its type's priority a shot ends, wherever it\n * is, and past the camera or its `pbubble` it runs unseen if `EXIST_OFFSCREEN`, which retail's type\n * is. Its radius is its own, not its type's, and no fog, LOD or cloak is asked of it. Where retail\n * keeps last frame's answer, it's been cleared by that frame's build, so it's taken as unseen.\n */\nexport const beamView = (\n camera: Camera,\n aspect: number,\n view: Matrix4,\n { effectDetail = 1, effectTypes = [] }: EffectViewOptions = {},\n): BeamSeen => {\n const info: EffectType = {\n ...RETAIL_EFFECT_TYPES[BEAM_EFFECT_TYPE]!,\n ...effectTypes[BEAM_EFFECT_TYPE],\n }\n const perf = f(1 - effectDetail)\n const { near, far } = info.pbubble\n const reach = f(f(far - near) * f(1 - perf) + near)\n const unseen = info.existOffscreen ? 'run' : 'die'\n\n return (position, radius) => {\n if (!(info.priority >= perf)) return 'die'\n\n const at = Matrix4.transformPoint(position, view)\n const depth = f(-at.z)\n if (!(camera.near < f(depth + radius))) return unseen\n if (!(reach > f(depth - radius))) return unseen\n return withinSides(at, camera, aspect, radius) ? 'draw' : unseen\n }\n}\n\n/** A frame's vertices and triangles, as `FUN_0046eab0` and `FUN_004fc9a0` append them. */\nexport interface BeamBatch extends ImmediateBatch {\n firstPerson: boolean\n}\n\nexport const beamBatch = (firstPerson = false): BeamBatch => ({\n firstPerson,\n vertices: [],\n colors: [],\n indices: [],\n count: 0,\n})\n\n// `ColorByte`: truncated, and only the low byte stored, unclamped.\nconst lowByte = (value: number): number => Math.trunc(value) & 0xff\n\nconst scaled = (scale: number, { x, y, z }: Vector3): readonly [number, number, number] => [\n lowByte(scale * x * 255),\n lowByte(scale * y * 255),\n lowByte(scale * z * 255),\n]\n\nconst add = (\n batch: BeamBatch,\n { x, y, z }: Vector3,\n [r, g, b]: readonly [number, number, number],\n u: number,\n v: number,\n): number => {\n batch.vertices.push(x, y, z, u, v)\n batch.colors.push(b, g, r, 0xff)\n return batch.count++\n}\n\nconst triangle = (batch: BeamBatch, a: number, b: number, c: number) => {\n batch.indices.push(a, b, c)\n}\n\n// `FUN_004fca50`.\nconst quad = (batch: BeamBatch, a: number, b: number, c: number, d: number) => {\n batch.indices.push(a, b, c, a, c, d)\n}\n\n// A local offset to world: the orientation's columns (`x`, `y`, `z`) weighted by it, plus `position`.\nconst placed = ({ orientation: r, position: t }: Placed, x: number, y: number, z: number) => ({\n x: f(r.x.x * x + r.y.x * y + r.z.x * z + t.x),\n y: f(r.x.y * x + r.y.y * y + r.z.y * z + t.y),\n z: f(r.x.z * x + r.y.z * y + r.z.z * z + t.z),\n})\n\ntype Placed = Pick<BeamEffect, 'orientation' | 'position'>\n\nconst UV_HALF = 0.5\nconst UV_CORE = 0.75\nconst UV_MID = 0.25\nconst UV_THIN = f(0.45)\nconst UV_WIDE = f(0.55)\n\nconst headV = ({ ballHead }: BeamArchetype) =>\n ballHead ? ([0, UV_HALF, 0.25] as const) : ([UV_HALF, 1, 0.75] as const)\nconst trailV = ({ thinTrail }: BeamArchetype) =>\n thinTrail ? ([0, UV_THIN] as const) : ([UV_WIDE, 1] as const)\n\n// `FUN_004fa270`, a spear, and either kind's first frame: the head's fan, then a double fan out of the\n// shot's centre to its ends. `head_texture`'s V and the corner order are as listed, unlike a bolt's.\nconst buildSpear = (\n arch: BeamArchetype,\n at: Placed,\n t: number,\n intensity: number,\n flash: boolean,\n batch: BeamBatch,\n) => {\n const near = flash ? arch.flashSize : arch.coreWidth\n const head = arch.headWidth < near ? near : arch.headWidth\n const end = f(f(arch.tailLength - near) * t + near)\n const start = f(-(f(arch.tipLength - near) * t + near))\n const [v0, v1, vMid] = headV(arch)\n const [u0, u1] = trailV(arch)\n const scale0 = f(intensity * arch.headBrightness)\n const scale1 = f(intensity * arch.trailBrightness)\n const centre = at.position\n\n const core0 = scaled(scale0, arch.coreColor)\n const outer0 = scaled(scale0, arch.outerColor)\n const i0 = add(batch, centre, core0, UV_CORE, vMid)\n const i1 = add(batch, placed(at, head, 0, 0), outer0, UV_HALF, v0)\n const i2 = add(batch, placed(at, 0, head, 0), outer0, UV_HALF, v1)\n const i3 = add(batch, placed(at, -head, 0, 0), outer0, 1, v1)\n const i4 = add(batch, placed(at, 0, -head, 0), outer0, 1, v0)\n\n const a0 = add(batch, centre, scaled(scale1, arch.coreColor), 0, u0)\n const a1 = add(batch, placed(at, 0, 0, start), scaled(scale1, arch.tipColor), UV_MID, u1)\n const a2 = add(batch, placed(at, 0, 0, end), scaled(scale1, arch.tailColor), UV_MID, u1)\n const outer1 = scaled(scale1, arch.outerColor)\n const a3 = add(batch, placed(at, near, 0, 0), outer1, UV_MID, u0)\n const a4 = add(batch, placed(at, -near, 0, 0), outer1, UV_MID, u0)\n const a5 = add(batch, placed(at, 0, near, 0), outer1, UV_MID, u0)\n const a6 = add(batch, placed(at, 0, -near, 0), outer1, UV_MID, u0)\n\n triangle(batch, i0, i1, i2)\n triangle(batch, i0, i3, i2)\n triangle(batch, i0, i3, i4)\n triangle(batch, i0, i1, i4)\n\n for (const reach of [a1, a2])\n for (const side of [a3, a4, a5, a6]) triangle(batch, a0, reach, side)\n}\n\n// `FUN_004fb1e0`, a bolt: the head's fan, a fan back to its tip, a tube to `core_length`, a fan to its\n// tail. Its lengths have the core's width off them, held at 0.\nconst buildBolt = (\n arch: BeamArchetype,\n at: Placed,\n t: number,\n intensity: number,\n batch: BeamBatch,\n) => {\n const near = arch.coreWidth\n const head = arch.headWidth < near ? near : arch.headWidth\n const tip = Math.max(f(arch.tipLength - near), 0)\n const tail = Math.max(f(arch.tailLength - near), 0)\n const mid = f(Math.max(arch.coreLength, 0) * t)\n const start = f(-(tip * t + near))\n const end = f(tail * t + near)\n const [v0, v1] = headV(arch)\n const vMid = f((v0 + v1) * 0.5)\n const [u0, u1] = trailV(arch)\n const scale0 = f(intensity * arch.headBrightness)\n const scale1 = f(intensity * arch.trailBrightness)\n const centre = at.position\n\n const outer0 = scaled(scale0, arch.outerColor)\n const i0 = add(batch, centre, scaled(scale0, arch.coreColor), UV_CORE, vMid)\n const i1 = add(batch, placed(at, head, 0, 0), outer0, UV_HALF, v0)\n const i2 = add(batch, placed(at, 0, head, 0), outer0, 1, v0)\n const i3 = add(batch, placed(at, -head, 0, 0), outer0, 1, v1)\n const i4 = add(batch, placed(at, 0, -head, 0), outer0, UV_HALF, v1)\n\n const a0 = add(batch, centre, scaled(scale1, arch.coreColor), 0, u1)\n const a1 = add(batch, placed(at, 0, 0, start), scaled(scale1, arch.tipColor), UV_MID, u0)\n const outer1 = scaled(scale1, arch.outerColor)\n const a2 = add(batch, placed(at, near, 0, 0), outer1, UV_MID, u1)\n const b0 = add(batch, placed(at, -near, 0, 0), outer1, UV_MID, u1)\n const b1 = add(batch, placed(at, 0, near, 0), outer1, UV_MID, u1)\n const b2 = add(batch, placed(at, 0, -near, 0), outer1, UV_MID, u1)\n const b3 = add(batch, placed(at, 0, 0, mid), scaled(scale1, arch.secCoreColor), 0, u0)\n const b4 = add(batch, placed(at, 0, 0, f(end + mid)), scaled(scale1, arch.tailColor), UV_MID, u1)\n // `FUN_004fc950`: these are rounded to floats first, where the others' products stay on the FPU.\n const { secOuterColor: secOuter } = arch\n const secOuter1 = [\n lowByte(f(scale1 * secOuter.x) * 255),\n lowByte(f(scale1 * secOuter.y) * 255),\n lowByte(f(scale1 * secOuter.z) * 255),\n ] as const\n const c0 = add(batch, placed(at, near, 0, mid), secOuter1, UV_MID, u0)\n const c1 = add(batch, placed(at, -near, 0, mid), secOuter1, UV_MID, u0)\n const c2 = add(batch, placed(at, 0, near, mid), secOuter1, UV_MID, u0)\n const c3 = add(batch, placed(at, 0, -near, mid), secOuter1, UV_MID, u0)\n\n triangle(batch, i0, i1, i2)\n triangle(batch, i0, i3, i2)\n triangle(batch, i0, i3, i4)\n triangle(batch, i0, i1, i4)\n for (const ring of [a2, b0, b1, b2]) triangle(batch, a0, a1, ring)\n quad(batch, a0, b3, c0, a2)\n quad(batch, a0, b3, c1, b0)\n quad(batch, a0, b3, c2, b1)\n quad(batch, a0, b3, c3, b2)\n for (const ring of [c0, c1, c2, c3]) triangle(batch, b3, b4, ring)\n}\n\n/**\n * `EffectVertexBatchFlush` (`FUN_004f9de0`): every shot of the frame in one draw, at `code_beam`'s\n * first frame, its UVs the whole texture's, under the effects' walk's `LEQUAL` and fog.\n */\nexport const beamDraw = (batch: BeamBatch, texture: Texture, fog?: Fog): Draw | undefined =>\n immediateDraw('code_beam', batch, texture, fog)\n","/**\n * A tractor's lines, as the game draws them: `FCliTractorBeam` (`src/freelancer/Client/\n * cli_tractor_beam.cpp`, `BuildGeometry`), each arm a jittered beam of camera-facing quads from the\n * tractor to its loot, and once its tip is in the loot, five arcs of sparks off it\n * (`Win3DDrawFuzzyLine`, `Win3DDrawFuzzyArc` in `win3d_immediate.cpp`). Where the arms are, and what\n * they hold, is the host's, each frame. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport { classifySphere, type Camera } from './camera.js'\nimport type { Draw } from './frame.js'\nimport { immediateDraw, type ImmediateBatch } from './immediate.js'\nimport type { Random } from './lightning.js'\nimport type { Fog } from './nebula.js'\nimport { unitByte } from './retail.js'\n\nconst f = Math.fround\n\n/** What retail hardcodes, and a mod can patch. */\nexport interface TractorLimits {\n /** The most arms drawn, counting only those holding loot (`JG 0xa`, `0x512e5f`). */\n arms: number\n /** The beam's segment length, and so its quads' (`0x40a00000`). */\n width: number\n /** How far each point strays, by the segment length (`0x3e4ccccd`). */\n jitter: number\n /** The loot's radius, by its physical radius: where the beam stops (`DAT_005cf100`). */\n lootScale: number\n /** The most the beam's end strays in `+x` and `+y` (`0x3f000000`). */\n endJitter: number\n /** Arcs off a loot the tip is in (`0x513227`). */\n sparks: number\n /** An arc's segment length. */\n sparkWidth: number\n /** The arcs' cone, at a tip a whole radius in (`DAT_005db708`, 0.8π). */\n sparkSpread: number\n /** How far back along the beam from the loot's centre the arcs turn about (`DAT_005d3e08`). */\n sparkPullBack: number\n /** A beam quad's length and width past its segment (`DAT_005c9804`). */\n lineQuad: number\n /** An arc quad's (`DAT_005c9800`). */\n arcQuad: number\n}\n\nexport const RETAIL_TRACTOR_LIMITS: Readonly<TractorLimits> = {\n arms: 11,\n width: 5,\n jitter: f(0.2),\n lootScale: 0.2,\n endJitter: 0.5,\n sparks: 5,\n sparkWidth: 1,\n sparkSpread: 2.5132741928100586,\n sparkPullBack: f(0.3),\n lineQuad: 1.25,\n arcQuad: f(1.2),\n}\n\n/** One arm holding loot, as `TractorArm` has it this frame. An arm with none is left out. */\nexport interface TractorArm {\n /** `GetTipPos`: how far the arm has reached. */\n tip: Vector3\n /** The loot's place (`CObject +0x2c`). */\n loot: Vector3\n /** Its physical radius (`get_physical_radius_r`). */\n radius: number\n}\n\n/**\n * A working tractor this frame (`IsFunctioning`); the host leaves out one that isn't. Its `color`\n * and `maxLength` are its `[Tractor]`'s `color` and `max_length`, as written.\n */\nexport interface TractorBeam {\n /** `CETractor::GetSourcePos`. */\n source: Vector3\n maxLength: number\n /** 0 to 255, as written: each is truncated to a byte (`FCliTractor::ReadUnknown`). */\n color: Vector3\n /** In the tractor's own order. */\n arms: readonly TractorArm[]\n}\n\nexport interface TractorView {\n camera: Camera\n aspect: number\n view: Matrix4\n /** `rand()`. Retail's is the game's one stream, so a picture's jitter can't match, only its kind. */\n random?: Random\n limits?: Partial<TractorLimits>\n}\n\nconst BYTE_TO_UNIT = f(1 / 255)\nconst RAND_UNIT = f(1 / 32767)\n\n// `Win3DColor3f`: by 255, truncated, then held to a byte.\nconst byte = unitByte\n\n// `CliTractorBeamInit` (`FUN_00512be0`): the bytes `ReadUnknown` kept, over 255 as a float.\nexport const colorBytes = ({ x, y, z }: Vector3): [number, number, number, number] => {\n const unit = (value: number) => byte(f((Math.trunc(value) & 0xff) * BYTE_TO_UNIT))\n\n return [unit(z), unit(y), unit(x), 0xff]\n}\n\nexport type V = [number, number, number]\n\nconst sub = (a: V, b: V): V => [f(a[0] - b[0]), f(a[1] - b[1]), f(a[2] - b[2])]\nconst add = (a: V, b: V): V => [f(a[0] + b[0]), f(a[1] + b[1]), f(a[2] + b[2])]\nconst scale = (a: V, by: number): V => [f(a[0] * by), f(a[1] * by), f(a[2] * by)]\nconst length = ([x, y, z]: V) => Math.sqrt(y * y + z * z + x * x)\nconst rescale = (a: V, wanted: number): V => scale(a, wanted / length(a))\nconst cross = (d: V, e: V): V => [\n f(e[2] * d[1] - e[1] * d[2]),\n f(d[2] * e[0] - e[2] * d[0]),\n f(e[1] * d[0] - d[1] * e[0]),\n]\nconst vector = ({ x, y, z }: Vector3): V => [x, y, z]\n\n// Common's `RandomVector`: a cube's point pushed out to the sphere, no rejection.\nconst randomVector = (random: Random, radius: number): V => {\n const x = f(random() - 0x3fff)\n const y = f(random() - 0x3fff)\n const z = random() - 0x3fff\n const by = radius / Math.sqrt(z * z + y * y + x * x)\n\n return [f(x * by), f(y * by), f(by * z)]\n}\n\n/** The quads' batches and the colour they share, built into. */\ninterface Lines {\n batches: ImmediateBatch[]\n color: readonly number[]\n eye: V\n}\n\nconst emptyBatch = (): ImmediateBatch => ({ vertices: [], colors: [], indices: [], count: 0 })\n\n// Past this a draw's 16-bit indices run out: a long beam goes on in another draw.\nconst MOST_VERTICES = 0x10000\n\nconst QUAD_UVS = [0, 0, 1, 0, 1, 1, 0, 1]\n\n/**\n * One segment's quad corners, in `FuzzyEmitQuad`'s order: its length along, by\n * `(next - cur) × (eye - cur)` across, turned to the eye, each by `quadScale` past it. The beam's\n * is half as wide as long (`narrow`); an arc's is square.\n */\nexport const segmentCorners = (\n cur: V,\n next: V,\n eye: V,\n quadScale: number,\n narrow: boolean,\n): [V, V, V, V] => {\n const side = cross(sub(next, cur), sub(eye, cur))\n const mid = add(cur, scale(sub(next, cur), 0.5))\n const half = length(sub(mid, cur))\n const along = scale(sub(cur, mid), quadScale)\n const across = scale(rescale(side, f(narrow ? half * 0.5 : half)), quadScale)\n\n return [add(mid, along), add(mid, across), sub(mid, along), sub(mid, across)]\n}\n\n// `FuzzyEmitQuad`: one quad, the whole texture over it. A point gone NaN, as an arc of half a turn\n// has no axis, leaves the quad to D3D, which draws nothing for it: none is built.\nconst quad = (lines: Lines, corners: readonly V[]) => {\n if (!corners.every((corner) => corner.every(Number.isFinite))) return\n\n let batch = lines.batches.at(-1)!\n if (batch.count + 4 > MOST_VERTICES) lines.batches.push((batch = emptyBatch()))\n\n const first = batch.count\n\n corners.forEach((corner, at) => {\n batch.vertices.push(...corner, QUAD_UVS[at * 2]!, QUAD_UVS[at * 2 + 1]!)\n batch.colors.push(...lines.color)\n })\n batch.count += 4\n batch.indices.push(first, first + 1, first + 2, first, first + 2, first + 3)\n}\n\nconst segment = (lines: Lines, cur: V, next: V, quadScale: number, narrow: boolean) =>\n quad(lines, segmentCorners(cur, next, lines.eye, quadScale, narrow))\n\n// `Win3DDrawFuzzyLine` (`FUN_00423be0`), textured: `floor(length / width) + 1` segments, each inner\n// point jittered by `jitter × width`, the last the end itself.\nconst fuzzyLine = (\n lines: Lines,\n random: Random,\n start: V,\n end: V,\n width: number,\n { jitter, lineQuad }: TractorLimits,\n) => {\n const dir = sub(end, start)\n const reach = length(dir)\n const count = Math.floor(reach / width) + 1\n const unit = rescale(dir, f(f(reach) / count))\n const stray = f(jitter * width)\n let cur = start\n\n for (let at = 1; at <= count; at++) {\n const next = at === count ? end : add(add(start, scale(unit, at)), randomVector(random, stray))\n\n segment(lines, cur, next, lineQuad, true)\n cur = next\n }\n}\n\n// `Win3DDrawFuzzyArc` (`FUN_004231f0`), textured: from `start` about `centre` toward `end`, on the\n// sphere through `start`, in chords of about `width`. Nothing if either end is on the centre.\nconst fuzzyArc = (\n lines: Lines,\n random: Random,\n start: V,\n end: V,\n centre: V,\n width: number,\n { jitter, arcQuad }: TractorLimits,\n) => {\n const from = sub(start, centre)\n const reachExt = length(from)\n const radius = f(reachExt)\n\n if (reachExt < 0.001) return\n\n const toEndRaw = sub(end, centre)\n if (length(toEndRaw) < 0.001) return\n\n const stray = f(jitter * width)\n const toEnd = rescale(toEndRaw, radius)\n const radiusSq = f(radius * radius)\n const cosineExt = (toEnd[2] * from[2] + toEnd[1] * from[1] + toEnd[0] * from[0]) / radiusSq\n let cosine = f(cosineExt)\n\n if (cosineExt < -1) cosine = -1\n else if (cosine > 1) cosine = 1\n\n const angle = f(Math.acos(cosine))\n // A chord of `width` on this radius subtends `acos(1 - width² / 2r²)`; the arc is cut into that many.\n let chord = f(1 - (width * width) / (radiusSq + radiusSq))\n\n if (chord < -1) chord = -1\n else if (chord > 1) chord = 1\n\n const count = Math.floor(angle / Math.acos(chord)) + 1\n const step = f(angle / count)\n const axis = cross(from, toEnd)\n const axisLength = length(axis)\n const unitAxis: V = [axis[0] / axisLength, axis[1] / axisLength, axis[2] / axisLength]\n let cur = start\n\n for (let at = 1; at <= count; at++) {\n const next =\n at === count\n ? add(centre, toEnd)\n : add(add(centre, rotate(from, unitAxis, at * step)), randomVector(random, stray))\n\n segment(lines, cur, next, arcQuad, false)\n cur = next\n }\n}\n\n/**\n * The quaternion's turn of `v` by `angle` about a unit `axis`, as Rodrigues gives it: from `start`\n * toward the end about `start × end`, as `tractor_reach` captures an arc of two chords.\n */\nexport const rotate = (v: V, [kx, ky, kz]: V, angle: number): V => {\n const c = Math.cos(angle)\n const s = Math.sin(angle)\n const dot = (kx * v[0] + ky * v[1] + kz * v[2]) * (1 - c)\n\n return [\n f(v[0] * c + (ky * v[2] - kz * v[1]) * s + kx * dot),\n f(v[1] * c + (kz * v[0] - kx * v[2]) * s + ky * dot),\n f(v[2] * c + (kx * v[1] - ky * v[0]) * s + kz * dot),\n ]\n}\n\n/**\n * `LookMatrixYup` (`Common/common_csys.cpp`), as its three columns: the third is `-direction`\n * normalised, the second an up beside it from `(-x, 0, z)` of that, the first their cross.\n */\nexport const lookMatrixYup = ([x, y, z]: V): [V, V, V] => {\n const lengthSq = x * x + y * y + z * z\n const inverse = -1 / Math.sqrt(lengthSq)\n const look: V = lengthSq > 1e-4 ? [f(inverse * x), f(inverse * y), f(inverse * z)] : [0, 0, -1]\n const [lx, ly, lz] = look\n const straight = Math.abs(lx) < 1e-4 && Math.abs(lz) < 1e-4\n const refX = straight ? 0 : -lx\n const refZ = straight ? 1 : lz\n const upX = f(refX * ly - lz * 0)\n const upY = f(refZ * lz - refX * lx)\n const upZ = f(lx * 0 - ly * refZ)\n const upInverse = f(1 / Math.sqrt(upZ * upZ + upY * upY + upX * upX))\n const ux = upX * upInverse\n const uy = upY * upInverse\n const uz = f(upZ * upInverse)\n\n return [\n [f(lz * uy - uz * ly), f(uz * lx - ux * lz), f(ly * ux - uy * lx)],\n [f(ux), f(uy), uz],\n look,\n ]\n}\n\n// One arm (`0x512e8b` to `0x51335c`): the beam to its tip, held to the loot's shell, its end strayed;\n// then past the shell, arcs from that end about a point just short of the loot's centre.\nconst arm = (\n lines: Lines,\n random: Random,\n source: V,\n { tip: tipAt, loot: lootAt, radius: physical }: TractorArm,\n limits: TractorLimits,\n) => {\n const tip = vector(tipAt)\n const loot = vector(lootAt)\n const toTip = sub(tip, source)\n const tipDistance = f(length(toTip))\n const tipDir = scale(toTip, 1 / tipDistance)\n const toLoot = sub(loot, source)\n const lootDistance = f(length(toLoot))\n const radius = f(physical * limits.lootScale)\n const reach = f(lootDistance - radius)\n const excess = f(tipDistance - reach)\n let end: V = tip\n\n if (excess > 0) {\n const lootLength = length(toLoot)\n const shell = lootLength !== 0 ? scale(toLoot, reach / lootLength) : toLoot\n\n end = add(shell, source)\n }\n\n const strayY = f(random() * limits.endJitter * RAND_UNIT)\n const strayX = random() * limits.endJitter * RAND_UNIT\n\n end = [f(end[0] + strayX), f(end[1] + strayY), end[2]]\n fuzzyLine(lines, random, source, end, limits.width, limits)\n if (!(excess > 0)) return\n\n const spread = f((excess / radius) * limits.sparkSpread)\n const [column0, column1, column2] = lookMatrixYup(toLoot)\n const centre = sub(loot, scale(tipDir, limits.sparkPullBack))\n const sinSpread = Math.sin(spread)\n const cosSpread = f(Math.cos(spread))\n\n for (let at = 0; at < limits.sparks; at++) {\n const theta = random() * f(2 * Math.PI) * RAND_UNIT\n // A point on the cone of half-angle `spread` about the loot-to-source axis, then taken to world by\n // `lookMatrixYup`'s columns.\n const cone: V = [f(Math.cos(theta) * sinSpread), f(Math.sin(theta) * sinSpread), cosSpread]\n const turned: V = [0, 1, 2].map((row) =>\n f(column0[row]! * cone[0] + column1[row]! * cone[1] + column2[row]! * cone[2]),\n ) as V\n\n fuzzyArc(lines, random, end, add(turned, centre), centre, limits.sparkWidth, limits)\n }\n}\n\nconst DEFAULT_RANDOM: Random = () => Math.floor(Math.random() * 0x8000)\n\n/**\n * `EFT_TRACTORBEAM`'s bucket of the effects' walk (`SpaceEffectsDrawFrame`, after the shots' and\n * before their flush): each tractor whose sphere of `maxLength` about its source the camera sees\n * (`EffectInCameraView`). Every quad is one immediate draw in retail (`FuzzyEmitQuad`); added, with\n * no depth writes, as one they come to the same picture. `line`'s frame 0 times the tractor's colour,\n * unlit, unculled, in the effects' fog (`0x512e4a`). Unseen it runs on, as its type is\n * `EXIST_OFFSCREEN`, and it has nothing to run.\n */\nexport const tractorDraws = (\n tractors: readonly TractorBeam[],\n texture: Texture,\n { camera, aspect, view, random = DEFAULT_RANDOM, limits: given = {} }: TractorView,\n fog?: Fog,\n): Draw[] => {\n const limits = { ...RETAIL_TRACTOR_LIMITS, ...given }\n const eye = vector(camera.position)\n const draws: Draw[] = []\n\n for (const { source, maxLength, color, arms } of tractors) {\n const at = Matrix4.transformPoint(source, view)\n if (classifySphere(at, f(maxLength), camera, aspect) < 3) continue\n\n const lines: Lines = { batches: [emptyBatch()], color: colorBytes(color), eye }\n for (const held of arms.slice(0, limits.arms)) arm(lines, random, vector(source), held, limits)\n\n for (const batch of lines.batches) {\n const draw = immediateDraw('line', batch, texture, fog)\n if (draw) draws.push(draw)\n }\n }\n\n return draws\n}\n","/**\n * A nebula's fill sheets: `FNebulaEffect::DrawFogShell` (`LAB_00508cf0`) and the sheets it draws\n * (`NebulaUpdateBoltCamera`, `FUN_005074e0`, `cli_nebula.cpp`). Two quads through the zone's centre,\n * each turned about one of its axes to face the camera and faded as the camera comes round to look\n * along that axis, textured with `fill_shape` in the fog's colour. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Draw } from './frame.js'\nimport type { NebulaState, Zone } from './nebula.js'\nimport { inverseRoot, unitByteRounded } from './retail.js'\n\nconst f = Math.fround\n\n// XYZ, D3DCOLOR and one UV set: Win3D's FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\nconst REACH = f(1.15)\n\n// `ScaleClampToByte`: times 255, truncated, held to a byte.\nconst byte = unitByteRounded\n\nconst dot = (a: Vector3, b: Vector3): number => a.y * b.y + a.x * b.x + a.z * b.z\n\nconst cross = (a: Vector3, b: Vector3): Vector3 => ({\n x: f(b.z * a.y - a.z * b.y),\n y: f(a.z * b.x - b.z * a.x),\n z: f(b.y * a.x - a.y * b.x),\n})\n\nconst scale = ({ x, y, z }: Vector3, by: number): Vector3 => ({\n x: f(x * by),\n y: f(y * by),\n z: f(z * by),\n})\n\n/** A sheet's edge: across the zone, out to its surface that way and 15% past (`0x50777c`). */\nconst edgeOf = (zone: Zone, edge: Vector3): Vector3 => {\n const unit = scale(edge, inverseRoot(f(edge.x * edge.x + edge.z * edge.z + edge.y * edge.y)))\n const reach = f(f(zone.radiusAlong(unit)) * REACH)\n\n return scale(unit, reach / Math.sqrt(unit.x * unit.x + unit.y * unit.y + unit.z * unit.z))\n}\n\n/** How much of a sheet shows, by how far the camera's look is off its axis: `(1 - |cos|) - by`. */\nconst facing = (axis: Vector3, look: Vector3, by: number, times: number): number => {\n const raw = (1 - Math.abs(dot(axis, look)) - f(by)) * f(times)\n if (raw > 1) return 1\n return f(raw) < 0 ? 0 : f(raw)\n}\n\n/**\n * The sheets for a nebula, or nothing: none once the camera's depth reaches 1, nor without a fill\n * shape, nor when both face the camera. Sheet A stands along the zone's longer of x and z, sheet B\n * along its y, each `size` × 1.15 from the centre, and across it to the zone's surface × 1.15.\n * A sphere written with one value has no y, so its sheet B has no height, and draws.\n *\n * Unlit, unculled, alpha-blended, with no depth test or writes (`DrawFogShell`), under the 250000 far\n * plane its callers set; `projection` is that. Fog and `ALPHAREF` are what the frame left: fog is off\n * wherever retail calls it, as the far list's nodes and `DrawBoltsPass` leave it, and the alpha test\n * is taken as `GREATER 0`. **Uncaptured.**\n */\nexport const fillSheetsDraw = (\n { nebula, depth }: NebulaState,\n eye: Vector3,\n projection: Matrix4,\n): Draw | undefined => {\n const { fill, zone } = nebula\n if (!(depth < 1) || !fill) return undefined\n\n const { size, position: center } = zone\n const [x, y, z] = zone.axes\n const long = size.x > size.z\n let axisA = long ? x : z\n const axisB = long ? z : x\n\n // From the camera to the zone: `FUN_00423b60` takes the zone's position first (`0x507644`), where\n // the decomp has it the other way. Only the edges' sign shows it, which `nebula_sheets` captures.\n const offset = { x: f(center.x - eye.x), y: f(center.y - eye.y), z: f(center.z - eye.z) }\n const look = scale(\n offset,\n inverseRoot(f(offset.y * offset.y + offset.x * offset.x + offset.z * offset.z)),\n )\n\n const faceA = facing(axisA, look, 0.0001, 204.08163)\n const edgeA = edgeOf(zone, cross(look, axisA))\n\n axisA = scale(axisA, (long ? size.x : size.z) * REACH)\n\n let faceB = facing(y, look, 0.2, 5)\n\n // Only a sheet B that shows is refined by the other axis, and not held to 1 then.\n if (faceB > 0) {\n const refined = (1 - Math.abs(dot(axisB, look)) - f(0.2)) * faceB * 5\n\n faceB = refined < 0 ? 0 : f(refined)\n }\n\n const edgeB = edgeOf(zone, cross(look, y))\n const axisY = scale(y, f(size.y * REACH))\n\n const { color } = nebula.fog\n const { u0, v0, u1, v1 } = fill\n const corners: { at: [number, number, number]; uv: [number, number]; alpha: number }[] = []\n\n // One quad: centre ± `edge` (across the view, `near`/`far`) ± `axis` (along the zone's axis).\n const sheet = (edge: Vector3, axis: Vector3, alpha: number, rounded: boolean) => {\n const near = { x: f(center.x + edge.x), y: f(center.y + edge.y), z: f(center.z + edge.z) }\n const far = { x: f(center.x - edge.x), y: f(center.y - edge.y), z: f(center.z - edge.z) }\n // Sheet B's last corner keeps x and y unrounded across both subtractions (`0x507dbf`).\n const lastX = rounded ? f(far.x - axis.x) : f(center.x - edge.x - axis.x)\n const lastY = rounded ? f(far.y - axis.y) : f(center.y - edge.y - axis.y)\n\n corners.push(\n { at: [f(near.x - axis.x), f(near.y - axis.y), f(near.z - axis.z)], uv: [u0, v0], alpha },\n { at: [f(near.x + axis.x), f(near.y + axis.y), f(near.z + axis.z)], uv: [u1, v0], alpha },\n { at: [f(far.x + axis.x), f(far.y + axis.y), f(far.z + axis.z)], uv: [u1, v1], alpha },\n { at: [lastX, lastY, f(far.z - axis.z)], uv: [u0, v1], alpha },\n )\n }\n if (faceA > 0) sheet(edgeA, axisA, faceA, true)\n if (faceB > 0) sheet(edgeB, axisY, faceB, false)\n if (!corners.length) return undefined\n\n const vertices = new Uint8Array(corners.length * STRIDE)\n const view = new Float32Array(vertices.buffer)\n\n corners.forEach(({ at, uv, alpha }, index) => {\n view.set(at, (index * STRIDE) / 4)\n vertices.set([byte(color.z), byte(color.y), byte(color.x), byte(alpha)], index * STRIDE + 12)\n view.set(uv, (index * STRIDE + 16) / 4)\n })\n\n // `Win3DEnd` makes each quad (0, 1, 2) and (0, 2, 3).\n const indices = new Uint16Array(\n Array.from({ length: corners.length / 4 }, (_, quad) =>\n [0, 1, 2, 0, 2, 3].map((corner) => quad * 4 + corner),\n ).flat(),\n )\n const mesh: VMeshData = {\n name: 'fill sheets',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: corners.length - 1,\n elementCount: indices.length,\n padding: 0,\n },\n ],\n indices,\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: corners.length,\n indexStart: 0,\n indexCount: indices.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: indices.length,\n // In world space, under the camera's own view (`Win3DApplyCamera`).\n world: Matrix4.identity,\n projection,\n materialName: 'fill sheets',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n // Frame 0 of the shape's texture (`TexShapeGetGpuHandle`).\n texture: { name: fill.texture.name, entry: fill.texture, sampler: DEFAULT_SAMPLER, uvSet: 0 },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'always',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'alpha',\n unlit: true,\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n","/**\n * A system's lights as the game gives them to one object: `StarSysApplyObjectLighting` (`0x5554d0`) in\n * `src/freelancer/Client/space_scene_obj_draw.cpp`, and `engine_light.cpp`. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { SceneLight, Spot } from './frame.js'\nimport { clampByte, unitByte } from './retail.js'\n\n/** An `[IGraph]`'s `point = x, value` keys, in file order. A colour graph's values are `0xAARRGGBB`. */\nexport interface Graph {\n points: readonly (readonly [x: number, value: number])[]\n}\n\n/** A `[LightSource]`, in the order the system file lists them, which is the game's (`GameLightEnable`). */\nexport interface SpaceLight {\n type: 'ambient' | 'point' | 'cone' | 'directional'\n position: Vector3\n /** Made unit, as `direction` is read. Down -Z when absent. */\n direction?: Vector3\n /** As written, 0 to 255. */\n color: Vector3\n range: number\n /** Constant, linear and quadratic. `(0, 1, 0)` when absent (`FEngineLight`'s constructor). */\n attenuation?: Vector3\n /** `atten_curve`, but an ambient light's is its `ambientCurve`: the colour over `[0, range]`. */\n attenuationCurve?: Graph\n /** `ambient_curve`: what an ambient light adds, over `[0, range]`. */\n ambientCurve?: Graph\n /** `color_curve`: a tint over the host's clock, repeating every `period` seconds. */\n colorCurve?: { graph: Graph; period: number }\n /** A cone's angles. A `[LightSource]` has none, so its cone lights nothing; equipment's has. */\n spot?: Spot\n}\n\n/** A `[Light]` equipment's keys, and where its hardpoint is. */\nexport interface EquipmentLight {\n /** The hardpoint's frame in the world: it shines down its -Z. */\n world: Matrix4\n /** `color`, 0 to 1. */\n color: Vector3\n /** `intensity`: its range. No light at all at 0 or less. */\n intensity: number\n /** `lightsource_cone`, a full angle in degrees: a spot below 180, a point light otherwise. */\n cone?: number\n}\n\n/**\n * `CliEquipLightInit` (`0x4fda00`): the light a `[Light]` carries, which retail makes only for the\n * player's own ship. Its range is its intensity, falling off by 16 / range² (`EngineLightSetRadius`).\n */\nexport const equipmentLight = ({\n world,\n color,\n intensity,\n cone = 180,\n}: EquipmentLight): SpaceLight | undefined => {\n if (!(intensity > 0)) return undefined\n\n // `LightColorByte`: rounded, and only the low byte kept.\n const byte = (value: number) => Math.floor(Math.fround(value) * 255 + 0.5) & 0xff\n const position = Matrix4.transformPoint({ x: 0, y: 0, z: 0 }, world)\n const axis = Matrix4.transformDirection({ x: 0, y: 0, z: -1 }, world)\n const light: SpaceLight = {\n type: cone < 180 ? 'cone' : 'point',\n position,\n direction: unit(axis),\n color: { x: byte(color.x), y: byte(color.y), z: byte(color.z) },\n range: intensity,\n attenuation: { x: 1, y: 0, z: Math.fround(16 / (intensity * intensity)) },\n }\n\n // `EngineLightSetConeAngle` (`0x411670`): the inner cone half the outer.\n if (cone < 180) {\n const phi = Math.fround(Math.fround(cone) * Math.fround(Math.PI / 180))\n\n light.spot = { phi, theta: Math.fround(phi * 0.5), falloff: 1 }\n }\n\n return light\n}\n\n/** A `[LightAnim]`: its `frame = time, r, g, b, intensity` keys, as written, in file order. */\nexport interface LightAnimation {\n frames: readonly { time: number; color: Vector3; intensity: number }[]\n}\n\n/** An `[Effect]`'s light keys, and the running effect's place and age. */\nexport interface EffectLight {\n /** Where the effect is: it has no direction. */\n position: Vector3\n /** `lgt_radius`: its range. No light at all at 0 or less. */\n radius: number\n /** `lgt_color`, as written, 0 to 255. */\n color: Vector3\n /** The `[LightAnim]` its `lgt_effect` names. */\n animation?: LightAnimation\n /** `lgt_range_scale`, which scales each key's intensity. 1 when absent. */\n rangeScale?: number\n /** `lgt_time_scale`, which scales each key's time. 1 when absent. */\n timeScale?: number\n /** Seconds since it started. Retail adds each frame's step to a float. */\n elapsed: number\n}\n\n// `LightAnimationLoad` (`0x538bf5` on): whole bytes, and a key's intensity kept above 0.\nconst keyOf = (\n { time, color, intensity }: LightAnimation['frames'][number],\n timeScale: number,\n intensityScale: number,\n) => {\n const byte = (value: number) => Math.trunc(value) & 0xff\n\n return {\n time: Math.fround(Math.fround(time) * timeScale),\n color: { x: byte(color.x), y: byte(color.y), z: byte(color.z) },\n intensity: Math.fround(\n (intensity <= 0 ? Math.fround(0.01) : Math.fround(intensity)) * intensityScale,\n ),\n }\n}\n\n/** `EngineLightSetRadius` (`0x411300`): a point light of that range, falling off by 16 / range². */\nconst pointOfRadius = (position: Vector3, color: Vector3, radius: number): SpaceLight => {\n const range = Math.fround(radius)\n\n return {\n type: 'point',\n position,\n color,\n range,\n attenuation: { x: 1, y: 0, z: Math.fround(16 / (range * range)) },\n }\n}\n\n/**\n * The light an effect carries (`CreateEffectStart`, `0x544299`), run by its animation\n * (`GameLightTickAnim`, `0x5386d0`): gone once the animation's last key has passed.\n */\nexport const effectLight = ({\n position,\n radius,\n color,\n animation,\n rangeScale = 1,\n timeScale = 1,\n elapsed,\n}: EffectLight): SpaceLight | undefined => {\n if (!(radius > 0)) return undefined\n\n const frames = animation?.frames ?? []\n // Before its first step, and with no animation, as the `[Effect]` says.\n if (!frames.length || !(elapsed > 0)) return pointOfRadius(position, color, radius)\n\n const keys = frames.map((frame) => keyOf(frame, Math.fround(timeScale), Math.fround(rangeScale)))\n // Its last key ends it, as `LightAnimationLoad` marks every animation's last.\n if (elapsed >= keys[keys.length - 1]!.time) return undefined\n\n // The last key before now, but from the first: before it, the first two extrapolate.\n let at = 0\n for (let index = 0; index < keys.length; index++) if (elapsed > keys[index]!.time) at = index\n\n const from = keys[at]!\n // One key alone has no next: retail reads past it. Held here.\n const to = keys[at + 1] ?? from\n const span = to.time - from.time\n const blend = span ? Math.fround((elapsed - from.time) / span) : 0\n const channel = (a: number, b: number) => Math.trunc((b - a) * blend + a) & 0xff\n const lit = {\n x: channel(from.color.x, to.color.x),\n y: channel(from.color.y, to.color.y),\n z: channel(from.color.z, to.color.z),\n }\n const intensity = (to.intensity - from.intensity) * blend + from.intensity\n\n return pointOfRadius(position, lit, Math.fround(intensity * Math.fround(radius)))\n}\n\n/** What one object is lit by: at most four lights, and the ambient, 0 to 1. */\nexport interface ObjectLighting {\n lights: SceneLight[]\n ambient: Vector3\n}\n\n// `FindBracketingKeys`, interpolating, as `G_bGraphInterpolate` is 1. A binary search for the keys\n// either side of `x`, returned as `[lo, hi, span]`; before the first or past the last, one key twice.\nconst interpolate = (points: Graph['points'], x: number): [number, number, number] => {\n let lo = 0\n let hi = points.length - 1\n\n if (x <= points[0]![0]) hi = 0\n else if (x >= points[hi]![0]) lo = hi\n else\n while (hi - lo > 1) {\n const mid = Math.trunc((hi + lo) / 2)\n\n if (!(x < points[mid]![0])) lo = mid\n else hi = mid\n }\n\n const span = points[hi]![0] - points[lo]![0]\n\n return [lo, hi, span]\n}\n\n// `FGraphData::Evaluate` and `EvaluateColor` map the caller's range onto the keys' own extent.\nconst graphX = ({ points }: Graph, t: number, max: number, clamp: boolean): number => {\n let at: number\n\n if (clamp) {\n // `GraphRangeWrap`, clamping into `[0, max - 0.001]`.\n const least = 0 < t ? t : 0\n\n at = Math.fround(least < max - 0.001 ? least : max - 0.001)\n } else {\n const fraction = t / Math.fround(max)\n\n at = Math.fround(Math.abs(fraction - Math.floor(fraction)) * Math.fround(max))\n }\n\n let least = points[0]![0]\n let most = least\n\n for (const [x] of points) {\n least = Math.min(least, x)\n most = Math.max(most, x)\n }\n\n return (at / max) * (most - least) + least\n}\n\n/** `FGraphData::Evaluate` over `[0, max]`, clamped. */\nexport const evaluateGraph = (graph: Graph, t: number, max: number): number => {\n const x = graphX(graph, t, max, true)\n const [lo, hi, span] = interpolate(graph.points, x)\n const weight = span > 0 ? (graph.points[hi]![0] - x) / span : 1\n\n return (1 - weight) * graph.points[hi]![1] + graph.points[lo]![1] * weight\n}\n\n/**\n * `FGraphData::EvaluateColor` over `[0, period]`, repeating: its bytes. Its weight runs from the low\n * key while the blend still gives the rest to the high one, so retail's colour curves run backwards\n * between keys (`0x41963c`).\n */\nexport const evaluateColorGraph = (graph: Graph, t: number, period: number): Vector3 => {\n const x = graphX(graph, t, period, false)\n const [lo, hi, span] = interpolate(graph.points, x)\n const weight = span > 0 ? (x - graph.points[lo]![0]) / span : 1\n const high = graph.points[hi]![1] >>> 0\n const low = graph.points[lo]![1] >>> 0\n const channel = (shift: number) =>\n Math.trunc(((high >>> shift) & 0xff) * (1 - weight) + ((low >>> shift) & 0xff) * weight) & 0xff\n\n return { x: channel(16), y: channel(8), z: channel(0) }\n}\n\ninterface Entry {\n light: number\n x: number\n z: number\n range: number\n}\n\ninterface Cell {\n x: number\n z: number\n half: number\n children: (Cell | undefined)[]\n /** Newest first, as each payload is pushed on the front. */\n entries: Entry[]\n}\n\n// `LightGridRebuildImpl`: the root's half size, and its two pools.\nconst ROOT_HALF = 100000\nconst POOL = 256\n\n/**\n * The XZ quadtree `LightGridRebuildImpl` builds once per system. Its cells only narrow the search, but\n * the order it hands lights back in decides which of equal range win the last of the four places.\n */\nclass LightGrid {\n readonly root: Cell = this.cell(0, 0, ROOT_HALF)\n private cells = 0\n private entries = 0\n\n constructor(lights: readonly SpaceLight[]) {\n lights.forEach((light, index) =>\n this.insert(this.root, {\n light: index,\n x: Math.trunc(light.position.x),\n z: Math.trunc(light.position.z),\n range: Math.trunc(light.range),\n }),\n )\n }\n\n private cell(x: number, z: number, half: number): Cell {\n return { x, z, half, children: [undefined, undefined, undefined, undefined], entries: [] }\n }\n\n // `LightGridAllocTreeNode`: the pool runs out at 256, and what needed a cell then is dropped.\n private child(parent: Cell, slot: number, dx: number, dz: number): Cell | undefined {\n const existing = parent.children[slot]\n if (existing) return existing\n if (this.cells >= POOL) return undefined\n this.cells++\n\n const half = Math.trunc(parent.half / 2)\n const made = this.cell(parent.x + dx * half, parent.z + dz * half, half)\n\n parent.children[slot] = made\n return made\n }\n\n /** `LightGridInsert` (`0x537d20`): into every quadrant its square reaches, while it fits one. */\n private insert(start: Cell, entry: Entry): void {\n const { range } = entry\n let cell: Cell | undefined = start\n\n // Children 0..3 stand at (+x, -z), (-x, -z), (+x, +z) and (-x, +z); the last is walked by looping.\n while (range <= cell.half) {\n const x = entry.x - cell.x\n const z = entry.z - cell.z\n\n if (x < range) {\n if (z < range) this.descend(cell, 1, -1, -1, entry)\n if (-z < range) this.descend(cell, 3, -1, 1, entry)\n }\n\n if (range <= -x) return\n if (z < range) this.descend(cell, 0, 1, -1, entry)\n if (range <= -z) return\n cell = this.child(cell, 2, 1, 1)\n if (!cell) return\n }\n\n if (this.entries >= POOL) return\n this.entries++\n cell.entries.unshift(entry)\n }\n\n private descend(cell: Cell, slot: number, dx: number, dz: number, entry: Entry): void {\n const child = this.child(cell, slot, dx, dz)\n if (child) this.insert(child, entry)\n }\n\n /** `LightTreeCollect`: each cell the query's square reaches, itself before its children. */\n collect(cell: Cell | undefined, x: number, z: number, radius: number, into: Cell[]): void {\n if (!cell) return\n if (cell.entries.length) into.push(cell)\n\n const dx = x - cell.x\n const dz = z - cell.z\n\n if (dx < radius) {\n if (dz < radius) this.collect(cell.children[1], x, z, radius, into)\n if (-dz < radius) this.collect(cell.children[3], x, z, radius, into)\n }\n\n if (-dx < radius) {\n if (dz < radius) this.collect(cell.children[0], x, z, radius, into)\n if (-dz < radius) this.collect(cell.children[2], x, z, radius, into)\n }\n }\n}\n\n// `CollectNearbyLights`' second argument for an object; a band's bake asks for 16 (`0x54cfb0`).\nconst MOST_LIGHTS = 4\nconst SORTED_LIMIT = 0x100\n\n// With a curve a directional or cone light turns to face each object, and its last reach test is 3D.\nconst turns = (light: SpaceLight): boolean =>\n light.attenuationCurve !== undefined ||\n light.ambientCurve !== undefined ||\n light.colorCurve !== undefined\n\n/** `EngineLightAffectsPoint` (`0x410a40`). */\nconst reaches = (light: SpaceLight, point: Vector3, radius: number): boolean => {\n if (light.type === 'directional' && !turns(light)) return true\n\n const dx = point.x - light.position.x\n const dy = point.y - light.position.y\n const dz = point.z - light.position.z\n const reach = light.range + radius\n\n return reach * reach > dx * dx + dz * dz + dy * dy\n}\n\n/** `CollectNearbyLights` (`0x537f40`): the widest-reaching lights first, `most` at most. */\nconst collectLights = (\n grid: LightGrid,\n position: Vector3,\n radius: number,\n most: number,\n): number[] => {\n const cells: Cell[] = []\n\n grid.collect(grid.root, Math.trunc(position.x), Math.trunc(position.z), Math.trunc(radius), cells)\n\n // Insertion by range, descending, where an equal range goes in front of those already there.\n const sorted: Entry[] = []\n\n for (const cell of cells)\n for (const entry of cell.entries) {\n if (sorted.some(({ light }) => light === entry.light)) continue\n\n let lo = 0\n let hi = sorted.length\n\n while (lo < hi) {\n const mid = Math.trunc((lo + hi) / 2)\n\n if (entry.range < sorted[mid]!.range) lo = mid + 1\n else hi = mid\n }\n\n if (hi >= SORTED_LIMIT) continue\n sorted.splice(hi, 0, entry)\n sorted.length = Math.min(sorted.length, SORTED_LIMIT)\n }\n\n const kept: number[] = []\n\n for (const { light, x, z, range } of sorted) {\n if (kept.length >= most) break\n\n const dx = position.x - x\n const dz = position.z - z\n const reach = range + radius\n if (reach * reach > dz * dz + dx * dx) kept.push(light)\n }\n\n return kept\n}\n\n/** What `StarSysApplyObjectLighting` keeps of `CollectNearbyLights`: those that reach the object. */\nconst nearbyLights = (\n grid: LightGrid,\n lights: readonly SpaceLight[],\n position: Vector3,\n radius: number,\n): number[] =>\n collectLights(grid, position, radius, MOST_LIGHTS).filter((index) =>\n reaches(lights[index]!, position, radius),\n )\n\n// `-Orient`'s third column, from an identity: a light with no `direction` shines down -Z.\nconst FORWARD: Vector3 = { x: 0, y: 0, z: -1 }\n\n// `EngineLightPackColorBytes` then back: the colour is whole 1/255 steps.\nconst quantize = (value: number): number => clampByte(value) / 255\n\nconst unit = ({ x, y, z }: Vector3): Vector3 => {\n const length = Math.hypot(x, y, z)\n\n return { x: x / length, y: y / length, z: z / length }\n}\n\nconst scale = ({ x, y, z }: Vector3, by: number): Vector3 => ({ x: x * by, y: y * by, z: z * by })\n\n/** `EngineLightGetEffectiveColor` (`0x410850`): its bytes, tinted by `color_curve`, then `atten_curve`. */\nconst effectiveColor = (light: SpaceLight, distance: number, time: number): Vector3 => {\n let color = {\n x: quantize(light.color.x),\n y: quantize(light.color.y),\n z: quantize(light.color.z),\n }\n\n if (light.colorCurve) {\n const { graph, period } = light.colorCurve\n const tint = evaluateColorGraph(graph, Math.fround(time), period)\n\n color = {\n x: (tint.x / 255) * color.x,\n y: (tint.y / 255) * color.y,\n z: (tint.z / 255) * color.z,\n }\n }\n\n if (light.attenuationCurve && light.type !== 'ambient')\n color = scale(color, evaluateGraph(light.attenuationCurve, distance, light.range))\n\n return color\n}\n\n/**\n * The directional lights `BandBakeLighting` (`0x54cfb0`) takes at a band's zone: of the first 16\n * `CollectNearbyLights` gives within 100, the first four directional ones, each the way it travels\n * (`EngineLightSample`). There's no reach test, and an ambient light adds nothing here.\n */\nexport const directionalLightsAt = (\n { lights, grid }: LightSet,\n position: Vector3,\n time: number,\n): { found: number; lights: SceneLight[] } => {\n const found = collectLights(grid, position, 100, 16)\n const lit: SceneLight[] = []\n\n for (const index of found) {\n if (lit.length >= MOST_LIGHTS) break\n\n const light = lights[index]!\n if (light.type !== 'directional') continue\n\n const dx = position.x - light.position.x\n const dy = position.y - light.position.y\n const dz = position.z - light.position.z\n const distance = Math.fround(Math.hypot(dx, dy, dz))\n const direction = turns(light)\n ? unit({ x: dx, y: dy, z: dz })\n : unit(light.direction ?? FORWARD)\n\n lit.push({ color: effectiveColor(light, distance, time), direction })\n }\n\n return { found: found.length, lights: lit }\n}\n\n/** `[Ambient] color` as the device takes it: whole bytes, 0 to 1. */\nexport const systemAmbient = ({ x, y, z }: Vector3): Vector3 => ({\n x: quantize(x),\n y: quantize(y),\n z: quantize(z),\n})\n\n/** What `SpaceObject`'s lighting reads, built once a frame from a system's lights. */\nexport interface LightSet {\n lights: readonly SpaceLight[]\n grid: LightGrid\n}\n\nexport const lightSet = (lights: readonly SpaceLight[]): LightSet => ({\n lights,\n grid: new LightGrid(lights),\n})\n\n/** The `[NebulaLight] ambient` an object is in, as written, and how far in, from 0 to 1. */\nexport interface NebulaAmbient {\n ambient: Vector3\n factor: number\n}\n\n// `0x555595`: towards the nebula's, rounded, and with no clamp, so only the low byte is kept.\nconst towards = (from: number, to: number, by: number): number =>\n (Math.trunc((to - from) * by + from + 0.5) & 0xff) / 255\n\n/**\n * `StarSysApplyObjectLighting` with every option on, from where the object stands and its sphere's\n * radius. `ambient` is the system's `[Ambient]`, as written. Its fog is `collectSpaceFrame`'s.\n */\nexport const lightObject = (\n { lights, grid }: LightSet,\n position: Vector3,\n radius: number,\n ambient: Vector3,\n time: number,\n nebula?: NebulaAmbient,\n): ObjectLighting => {\n // `EngineLightApplyList` reads the bytes it was given back as floats, and adds ambient lights to them.\n const sum = systemAmbient(ambient)\n\n if (nebula) {\n const { ambient: to, factor } = nebula\n const byte = (value: number) => Math.trunc(value) & 0xff\n\n sum.x = towards(Math.round(sum.x * 255), byte(to.x), factor)\n sum.y = towards(Math.round(sum.y * 255), byte(to.y), factor)\n sum.z = towards(Math.round(sum.z * 255), byte(to.z), factor)\n }\n\n const lit: SceneLight[] = []\n\n for (const index of nearbyLights(grid, lights, position, radius)) {\n const light = lights[index]!\n // `EngineLightApplyNearby` (`0x4104e0`).\n const dx = position.x - light.position.x\n const dy = position.y - light.position.y\n const dz = position.z - light.position.z\n const distance = Math.fround(Math.hypot(dx, dy, dz))\n const color = effectiveColor(light, distance, time)\n\n if (light.type === 'ambient') {\n const curve = light.ambientCurve ?? light.attenuationCurve\n const by = curve ? Math.fround(evaluateGraph(curve, distance, light.range)) : 1\n\n sum.x += color.x * by\n sum.y += color.y * by\n sum.z += color.z * by\n // It has no D3D type to draw as, so adds only to the ambient.\n continue\n }\n\n // Under a byte's worth, it's left off.\n if (color.z + color.y + color.x < 1 / 255) continue\n // A cone from `[LightSource]` has no angles, and D3D's spot falloff gives nothing outside 0°.\n if (light.type === 'cone' && !light.spot) continue\n\n // A curve turns it to shine from its position at the object.\n const direction = turns(light)\n ? unit({ x: dx, y: dy, z: dz })\n : unit(light.direction ?? FORWARD)\n\n if (light.type === 'directional') lit.push({ color, direction })\n else\n lit.push({\n color,\n direction: light.type === 'cone' ? direction : FORWARD,\n position: light.position,\n range: light.range,\n attenuation: light.attenuation ?? { x: 0, y: 1, z: 0 },\n ...(light.type === 'cone' && { spot: light.spot }),\n })\n }\n\n const byte = (value: number) => unitByte(value) / 255\n\n return { lights: lit, ambient: { x: byte(sum.x), y: byte(sum.y), z: byte(sum.z) } }\n}\n","/**\n * A system's frame as the game orders it: `SpaceObjDrawPass` (`0x51c200`), in\n * `src/freelancer/Client/space_scene_obj_draw.cpp`. Pure, no GL. Objects join one of five lists, each\n * drains far to near, and the batcher flushes after every object.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport { collectEffect, type EffectDraw } from '#/alchemy/draw.js'\nimport {\n RETAIL_EFFECT_TYPES,\n viewEffect,\n type EffectView,\n type EffectViewFrame,\n type EffectViewOptions,\n type PlacedEffect,\n} from './effect-view.js'\nimport type { DustOptions, DustZone, SpaceDust } from './dust.js'\nimport { ringImmersion, ringPieceDraw, type PlanetRing, type RingPiece } from './ring.js'\nimport { fieldCubes, nearFieldFraction, type SpaceAsteroidField } from './asteroids.js'\nimport { flareQuads, type FrameRect, type ScreenQuad, type SpaceFlare } from './flare.js'\nimport type { AsteroidBand } from './band.js'\nimport { fogOverlayDraw } from './overlay.js'\nimport { starGlowDraws, type Star } from './star.js'\nimport { castRay, type Hitbox } from './hitbox.js'\nimport {\n hideStar,\n starCorona,\n starFlare,\n sunEffectQuality,\n sunLeastLod,\n updateStar,\n type CoronaView,\n} from './corona.js'\nimport { beamBatch, beamDraw, beamView, type BeamEffect } from './beam.js'\nimport { tractorDraws, type TractorBeam, type TractorLimits } from './tractor.js'\nimport type { Random } from './lightning.js'\nimport { fillSheetsDraw } from './sheets.js'\nimport type { GateTunnel } from './tunnel.js'\nimport {\n directionalLightsAt,\n lightObject,\n lightSet,\n systemAmbient,\n type SpaceLight,\n} from './light.js'\nimport {\n findNebula,\n fogEnd,\n fogFar,\n fogOf,\n ExclusionOrder,\n immersion,\n listNebulae,\n nebulaState,\n RETAIL_NEBULA_LIMITS,\n type NebulaLimits,\n type Fog,\n type SpaceField,\n type SpaceNebula,\n type NebulaState,\n type Within,\n type Zone,\n} from './nebula.js'\nimport { classifySphere, projectionMatrix, viewMatrix, type Camera } from './camera.js'\nimport {\n BLACK_BACKGROUND,\n collectModel,\n flushQueued,\n hooksOf,\n RETAIL_FRAME_LIMITS,\n type Draw,\n type FrameLimits,\n type Frame,\n type Queued,\n type SceneEffect,\n type SceneLight,\n type SceneModel,\n} from './frame.js'\nimport { inverseRoot } from './retail.js'\n\nexport interface SpaceObject {\n /** Not drawn for a sun: its `star` is. */\n model: SceneModel\n /** `get_position`, which its sort distance is from. */\n position: Vector3\n /** `Slot178`, in world space: what it's tested against the view with. */\n sphere: { center: Vector3; radius: number }\n /** Only a solar reaches the far list. Anything else stops at the system's draw range. */\n solar?: {\n /**\n * In `G_LargeSolars` (`0x540d18`), `extent` over 200 and type bit 7 clear: no\n * `solarQueryRange` limit.\n */\n large?: boolean\n /**\n * `CObject::Radius`: the engine's extent of its instance, the root part's top level, not its\n * `.sur`. `sphere`'s radius when absent.\n */\n extent?: number\n /** Planet or moon, `TypeBits & 7` with no star sphere: sorted by its surface, not its centre. */\n planet?: boolean\n }\n /**\n * A ship's `pilot_mesh`, placed at its `HpPilot` less the pilot's own `HpConnect`\n * (`AttachPilotMesh`, `0x544380`). Drawn before the model, only where it reflects (`0x546087`).\n * The game's option 0x1d turns it off, so the host decides.\n */\n pilot?: SceneModel\n /**\n * Equipment with a model, each hung on its hardpoint by `attachJoint` and placed with its own\n * archetype's lists. The engine joins it as the last child of the part holding the hardpoint, so\n * it draws after that part's subtree (`ConnectInstanceChild`, `RenderInstance`); here, after the\n * whole model, in the order given. Only the order within the object can differ: batched glass\n * still waits for its flush, but an unbatched draw on a part with later siblings goes after them.\n */\n attached?: readonly SceneModel[]\n /**\n * Its lights' flares, in the order its effect list holds them. They join the frame only when it\n * draws at the first tier (`GameobjSweepEffectList`), and only then do they blink.\n */\n flares?: readonly SpaceFlare[]\n /**\n * A solar's `star`: a sun. Its draw is its glow and nothing else, neither its model nor what's\n * attached (`Slot188`, `0x548220`); `sphere` is `starRadius` about its position (`Slot178`). The\n * game's sun option (0x24) turns it off, so the host decides.\n */\n star?: Star\n /**\n * Its collision shapes, which a sun's corona rays test. A hit reports `position` and `CObject::Radius`,\n * taken as `solar.extent`, else `sphere`'s radius. Nothing to hit when absent.\n */\n hitbox?: Hitbox\n /** The archetype's `nomad`: goes three lists up, after everything of its kind (`0x51f5b7`). */\n nomad?: boolean\n /** The archetype's `distance_render`. Past it, it stops reflecting, and `lodRange` may apply. */\n distanceRender?: number\n /** The archetype's `LodPick`, the largest of its `LODranges`. Past it, it draws nothing. */\n lodRange?: number\n /**\n * The nebula it was last in, which retail keeps and tries first. It matters only where nebulae\n * overlap, and none do in retail. The first that holds it when absent. `null` for none at all: a\n * solar finds its nebula once, as its `[Object]` is read (`FUN_005485c0`), so one listed before\n * the system's `[Nebula]` sections has none (`asteroid_nebula`'s plant).\n */\n nebula?: SpaceNebula | null\n}\n\n/** A space frame, and what became of each of its effects. */\nexport interface SpaceFrame extends Frame {\n /**\n * In the scene's order: an effect with a `position` is drawn, runs unseen, or ends, as the game\n * would. The host steps it with `lod` next, by no more than `effectMaxStep`. Undefined for one with no position, which draws.\n */\n effectViews: (EffectView | undefined)[]\n /** Each of the scene's `asteroids`, in order: its cubes drawn, and the centres `fieldCubes` tested. */\n asteroidCubes: { drawn: number; tested: number }[]\n}\n\n/** `EffectTypeInfoByIndex`, from `[EffectType]`: the game's walk is by type. */\nexport interface SpaceEffect extends SceneEffect, Partial<Omit<PlacedEffect, 'type'>> {\n /** `[EffectType]`'s index, `EFT_NONE` 0. With a `position`, the view test decides it. */\n type: number\n}\n\nexport interface SpaceScene {\n /** Its `far` is ignored: the frame's comes from `farClip`, or the field's. */\n camera: Camera\n aspect: number\n /** `[Ambient] color`, as written: 0 to 255. */\n ambient: Vector3\n /** Its `[LightSource]`s, in file order. */\n lights: readonly SpaceLight[]\n objects: readonly SpaceObject[]\n /**\n * The star sphere's layers, in the order to draw them: those `skyLayers` names. Each stands at its\n * `instanceExtent` centre, as `StarSphereLoadLayer` (`0x552fd0`) moves it.\n */\n sky?: readonly SceneModel[]\n /** `[SystemInfo] space_farclip`, the far plane, past the draw range by `limits.rangeMargin`. */\n farClip?: number\n /** Over `RETAIL_SPACE_LIMITS`, for a mod that patches them. */\n limits?: Partial<SpaceLimits>\n /** Over `RETAIL_COCKPIT_LIMITS`, for a mod that patches them. */\n cockpitLimits?: Partial<CockpitLimits>\n /** Its `[Nebula]`s, in file order: the first that holds a point is the one it's in. */\n nebulae?: readonly SpaceNebula[]\n /** Within a type in the order given, which is newest first in the game (`FUN_004fc920`). */\n effects?: readonly SpaceEffect[]\n /**\n * Every gun's shot in flight, newest first as the game's list holds them (`EffectTypeListLink`).\n * The frame ages them by `step`. A host drops one once it hits, or once it's `dead`.\n */\n beams?: readonly BeamEffect[]\n /** `tex_shape = code_beam`, from `[Texture]` in `effect_shapes.ini`. */\n beamTexture?: Texture\n /** Every working tractor reaching for loot, newest first as the game's list holds them. */\n tractors?: readonly TractorBeam[]\n /** `tex_shape = line`, from `[Texture]` in `effect_shapes.ini`. */\n lineTexture?: Texture\n /** `rand()` for the tractors' jitter. */\n tractorRandom?: Random\n /** Over `RETAIL_TRACTOR_LIMITS`, for a mod that patches them. */\n tractorLimits?: Partial<TractorLimits>\n /**\n * The camera is the cockpit's (`FFirstPersonCamera`): a shot's first frame shows no flash\n * (`0x4fa2a0`), and the frame goes on with its pass (`FirstPersonCameraSceneDraw`, `0x518420`).\n */\n firstPerson?: boolean\n /** The HUD option (`0xa`), on: from the cockpit, depth is cleared for it even with no mesh. */\n hud?: boolean\n /** Its mesh, when the `cockpit` option's applied value is over 0.999. Only from the cockpit. */\n cockpit?: SpaceCockpit\n /**\n * The effects option (`0x25`), off. The host leaves out the effects and rings then; here it says\n * only that the batcher's bin 1 stays on, so what the cockpit's mesh queues waits for `atEnd`.\n */\n effectsOff?: boolean\n /** `[System] space_color`, 0 to 1. Deep in a nebula, its fog's colour instead. */\n background?: Vector3\n time?: number\n /** The options and data the effects' view test reads. */\n effectView?: EffectViewOptions\n /**\n * Seconds since the last frame, which each nebula's lightning advances by, and each drawn light's\n * blink, held to 0.1. 0 when absent.\n */\n step?: number\n /**\n * Seconds the camera has had since the last frame, for what answers it rather than the world: the\n * suns' fades and the nebulae's turning and sorting. `step` when absent, as in the game, where\n * they're one. A host that stops its world's clock and lets the camera fly passes 0 as `step`.\n */\n cameraStep?: number\n /** The camera cut to this frame, as it does entering a system: clouds are placed afresh. */\n cut?: boolean\n /** The player's ship is in a trade lane: no dynamic asteroid is placed (`0x525da9`). */\n lane?: boolean\n /** Its asteroid fields, in the order the system lists them. */\n asteroids?: readonly SpaceAsteroidField[]\n /** Its planets' rings, which the effects option shows (`0x25`). */\n rings?: readonly PlanetRing[]\n /** The viewport in pixels, which flares are sized and clipped in. No flares when absent. */\n viewport?: { width: number; height: number }\n /** `fx/efx.txm`'s `shine`, from `[Texture]` in `effect_shapes.ini`, and its frame. */\n shine?: { texture: Texture; frame?: FrameRect }\n /**\n * The `SunEffect` option as `PerfOptions.ini` writes it, the effects, sun and sun effects options\n * (0x25, 0x24, 0x28) being on. With none, or none above 0, no sun's corona draws.\n */\n sunEffect?: number\n /**\n * `PhySys::FindRayCollisions`: what a ray from the camera hits. Each hit's `object` is compared\n * with a sun's own `SpaceObject` and with `player`. From the objects' `hitbox`es when absent.\n */\n rayHits?: CoronaView['rayHits']\n /** The player's ship, seen from the cockpit: a sun's rays pass through it. None from outside. */\n player?: unknown\n /** The system's space dust, which the frame updates and steps (`StarSysUpdate`, `0x554ecb`). */\n dust?: SpaceDust\n /** Its zones with a `spacedust`, in file order, which `dust` looks among. */\n dustZones?: readonly DustZone[]\n /** `space_dust_detail` and game option `0x19`. Run times are the effect types'. */\n dustOptions?: Omit<DustOptions, 'runTimes'>\n /**\n * The player is jumping, in the tunnel: the frame is the tunnel, the ship and two of the effect\n * types, and nothing else of the system, whose nebulae, fields and dust it leaves alone.\n */\n jump?: SpaceJump\n}\n\n/** `[Cockpit] mesh`, placed where `FirstPersonCameraUpdate` has it, under the ship's turn. */\nexport interface SpaceCockpit {\n model: SceneModel\n /** Its world bounding sphere (`ClientMeshHolderGetBoundingSphere`), which it's lit by. */\n sphere: { center: Vector3; radius: number }\n /** The ship's nebula, as `Slot18c` gives it, and how deep. Its ambient and fog light the mesh. */\n within?: { state: NebulaState; factor: number }\n}\n\n/** What the cockpit's pass hardcodes, and a mod can patch (`0x5c8914`, `0x5c8918`). */\nexport interface CockpitLimits {\n near: number\n far: number\n /** Its mesh keeps to the back of the depth range, behind all the HUD may draw. */\n depthRange: readonly [number, number]\n /** The rest, which the pass leaves set for the HUD and the scene's end. */\n afterDepthRange: readonly [number, number]\n}\n\nexport const RETAIL_COCKPIT_LIMITS: Readonly<CockpitLimits> = {\n near: 0.05,\n far: 500,\n depthRange: [0.75, 1],\n afterDepthRange: [0, 0.75],\n}\n\n/**\n * The player's jump while its ship is in states 2 and 3, the tunnel (`SpaceObjDrawPass`, `0x51c235`).\n * The host steps the tunnel first (`FJumpShipEffect::Update`), which places the ship.\n */\nexport interface SpaceJump {\n /** The player's ship, where the tunnel beamed it. */\n ship: SpaceObject\n /** The gate's descriptor's `jump_tunnel`, when found. */\n tunnel?: GateTunnel\n /** The descriptor's `jump_ambient`, as written, 0 to 255: the ship's ambient. */\n ambient: Vector3\n /** Its `jump_background_color`, as written, 0 to 255: the clear. */\n background: Vector3\n}\n\n/** A `[Background]` key: `basic_stars`, `complex_stars` or `nebulae`. */\nexport type SkyLayer = 'basic' | 'complex' | 'nebulae'\n\n/**\n * The layers that draw, in order, at the `star_sphere` option: never both kinds of stars\n * (`StarSphereApplyDetail`, `0x552cd0`; `StarSphereRender`, `0x552ea0`). Strictly above each step.\n */\nexport const skyLayers = (detail: number): SkyLayer[] =>\n detail > 0.75\n ? ['complex', 'nebulae']\n : detail > 0.5\n ? ['basic', 'nebulae']\n : detail > 0.001\n ? ['nebulae']\n : []\n\n/** What retail hardcodes, and a mod can patch. Distances are in world units. */\nexport interface SpaceLimits extends FrameLimits, NebulaLimits {\n /** A system with no `space_farclip` (`FUN_00410130`). */\n farClip: number\n /** The least far plane a `space_farclip` can set (`FUN_00410150`). */\n leastFarClip: number\n /** How far short of the far plane the draw range ends (`FUN_00410150`). */\n rangeMargin: number\n /** The far list's plane (`DAT_00610534`). */\n farListPlane: number\n /** How far from the camera a small solar is looked for (`DAT_00613ec8`). */\n solarQueryRange: number\n /** Nearer than this, an object leaves its field's list. Retail holds its square (`0x5dc35c`). */\n nearDistance: number\n /** How deep in another nebula an object can be and still draw (`0x5cbf58`). */\n otherFieldDepth: number\n /** How far short of the draw range a ring piece goes to the far list (`0x5d3d24`). */\n ringFarMargin: number\n /** The most the effect walk steps an effect by: `SpaceEffectsDrawFrame` (`0x4f75eb`). */\n effectMaxStep: number\n}\n\nexport const RETAIL_SPACE_LIMITS: Readonly<SpaceLimits> = {\n ...RETAIL_FRAME_LIMITS,\n ...RETAIL_NEBULA_LIMITS,\n farClip: 21000,\n leastFarClip: 1000,\n rangeMargin: 1000,\n farListPlane: 250000,\n solarQueryRange: 10000,\n nearDistance: 200,\n otherFieldDepth: 0.25,\n ringFarMargin: 5000,\n effectMaxStep: Math.fround(0.1),\n}\n\nconst MAIN = 0\nconst FIELD = 1\nconst FAR = 2\nconst NOMAD_OFFSET = 3\nconst LIST_COUNT = 5\n\n// What `DrainMeshAndAsteroids` walks, after the far list. From outside a field it never walks list 4,\n// so a nomad object in that field draws only if it's near enough to leave it (`0x51fa43`).\nconst OUTSIDE_ORDER = [FAR, FIELD, MAIN, NOMAD_OFFSET + MAIN]\nconst INSIDE_ORDER = [FAR, MAIN, NOMAD_OFFSET + MAIN, FIELD, NOMAD_OFFSET + FIELD]\n\n// `SpaceEffectsDrawFrame` walks these and not 0x2b (`0x4f7650`, `0x4f76b2`).\nconst SKIPPED_EFFECT_TYPE = 0x2b\n// `EFT_JUMP_EFFECTS` and `EFT_ENGINE_FIRE`, the only buckets walked in a tunnel, in this order.\nconst TUNNEL_EFFECT_TYPES = [0x25, 0x1b]\n\ninterface Picked {\n rank: 3 | 4\n /** `GameobjPickLodRetail`'s high word: past 0 it doesn't reflect. 2 never reaches here. */\n tier: 0 | 1\n}\n\n/** `GameobjPickLodRetail` (`0x539820`): whether it's in view and in range, by its sphere. */\nconst pick = (\n { sphere, distanceRender = -1, lodRange = -1 }: SpaceObject,\n view: Matrix4,\n camera: Camera,\n aspect: number,\n): Picked | undefined => {\n const center = Matrix4.transformPoint(sphere.center, view)\n const rank = classifySphere(center, sphere.radius, camera, aspect)\n if (rank === 1) return undefined\n\n const squared = center.x * center.x + center.y * center.y + center.z * center.z\n if (distanceRender > 0 && squared < distanceRender * distanceRender) return { rank, tier: 0 }\n if (lodRange > 0 && squared > lodRange * lodRange) return undefined\n return { rank, tier: distanceRender > 0 ? 1 : 0 }\n}\n\n/**\n * `FUN_0051f2c0`'s tests on a field, for an object in the draw range: the list it starts in, which\n * nearness can still change, or nothing if the field hides it.\n */\nconst fieldList = (\n within: Within | undefined,\n squared: number,\n field: SpaceField | undefined,\n otherFieldDepth: number,\n): number | undefined => {\n if (!field) return MAIN\n\n const own = within?.state === field.state\n const value = within?.factor ?? 0\n if (!own && value > otherFieldDepth) return undefined\n\n // Hidden: from a core, what isn't in it; from outside, what's fully in it; from its edge, what's\n // fully in it past the fog's end.\n const enclosure = own ? value : 0\n if (field.enclosure === 2 && enclosure <= 0) return undefined\n if (field.enclosure === 0 && enclosure >= 1) return undefined\n\n // `G_FieldRadiusSq`, from the fog's end.\n const radius = field.state.end\n\n if (field.enclosure === 1 && enclosure >= 1 && squared > Math.fround(radius * radius))\n return undefined\n\n return enclosure > 0 ? FIELD : MAIN\n}\n\ninterface Listed {\n object: SpaceObject\n key: number\n picked: Picked\n within?: Within\n}\n\n/** A ring's piece, a draw node of its own kind (`PTR_LAB_005dc06c`). */\ninterface ListedPiece {\n ring: PlanetRing\n piece: RingPiece\n key: number\n}\n\n/** A field's band piece, a draw node of the field's kind (`0x005dc034`). */\ninterface ListedBand {\n band: AsteroidBand\n piece: number\n key: number\n}\n\n/** A nebula the camera doesn't answer to, a far node of its own kind (`ZItemNebula`). */\ninterface ListedNebula {\n nebula: NebulaState\n key: number\n}\n\nconst f = Math.fround\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\n/** What `FNebulaEffect` keeps between frames for its exclusion zones, kept here as retail keeps it. */\ninterface NebulaClock {\n order: ExclusionOrder\n /** `+0x294` as last worked out: the constructor's 0. */\n depth: number\n /** `+0x50`, from the constructor's 0.1. */\n since: number\n /** `+0x58`, from the constructor's 0.2, restarted as the bits turn. */\n sinceTurned: number\n}\n\nconst clocks = new WeakMap<SpaceNebula, NebulaClock>()\n\nconst nebulaClock = (nebula: SpaceNebula): NebulaClock => {\n let clock = clocks.get(nebula)\n\n if (!clock) {\n clock = {\n order: new ExclusionOrder(nebula.exclusions ?? []),\n depth: 0,\n since: f(0.1),\n sinceTurned: f(0.2),\n }\n clocks.set(nebula, clock)\n }\n\n return clock\n}\n\n/**\n * A one-piece band's key (`0x51babc`): how far past its zone's surface the camera is, squared, by a\n * length from one Newton step of the `0x5f3759df` estimate; within a quarter of the range, that.\n */\nconst bandSurfaceKey = (zone: Zone, eye: Vector3, nearSquared: number): number => {\n const f = Math.fround\n const dx = f(zone.position.x - eye.x)\n const dy = f(zone.position.y - eye.y)\n const dz = f(zone.position.z - eye.z)\n const sum = dy * dy + dz * dz + dx * dx\n const length = f(inverseRoot(sum) * sum)\n const inverse = 1 / length\n const surface = zone.radiusAlong({ x: f(dx * inverse), y: f(dy * inverse), z: f(dz * inverse) })\n const key = length <= surface ? nearSquared : f((length - surface) * (length - surface))\n\n return key < nearSquared ? nearSquared : key\n}\n\nconst withoutEnvironment = ({ environment: _, ...model }: SceneModel): SceneModel => model\n\n/**\n * An attachment under its object's `envmap_material`, which the game sets on the object's instance\n * (`SetAppearanceInstanceValue`) and its children draw with: the cube is found in the object's.\n */\nconst underOwn =\n (owner: SceneModel) =>\n ({ environment: _, ...model }: SceneModel): SceneModel => {\n const { environment } = owner\n if (!environment) return model\n\n const folded = environment.toLowerCase()\n\n return {\n ...model,\n environment,\n texture: (name) =>\n name.toLowerCase() === folded ? owner.texture(name) : model.texture(name),\n }\n }\n\n/** The far plane: `space_farclip`, held to the least one, or the default (`FUN_00410150`). */\nconst systemFarOf = (farClip: number | undefined, limits: SpaceLimits): number =>\n farClip === undefined ? limits.farClip : Math.max(farClip, limits.leastFarClip)\n\nconst viewOne = (\n effect: SpaceEffect,\n frame: EffectViewFrame,\n options: EffectViewOptions | undefined,\n): EffectView | undefined =>\n effect.type === SKIPPED_EFFECT_TYPE || !effect.position\n ? undefined\n : viewEffect({ ...effect, position: effect.position }, frame, options)\n\n/**\n * The scene's effects' views as `collectSpaceFrame` finds them, stepping nothing: for a host that\n * runs effects ahead of the first frame under a camera that stays put.\n */\nexport const viewSpaceEffects = ({\n camera,\n aspect,\n nebulae = [],\n effects = [],\n farClip,\n limits,\n effectView,\n}: SpaceScene): (EffectView | undefined)[] => {\n const resolved = { ...RETAIL_SPACE_LIMITS, ...limits }\n const { position: eye } = camera\n const states = nebulae.map((nebula) => nebulaState(nebula, eye, resolved))\n const { field } = listNebulae(states, eye, systemFarOf(farClip, resolved) - resolved.rangeMargin)\n const frame = { camera, aspect, view: viewMatrix(camera), field, nebulae: states }\n\n return effects.map((effect) => viewOne(effect, frame, effectView))\n}\n\nexport const collectSpaceFrame = ({\n camera: given,\n aspect,\n ambient,\n lights,\n objects,\n sky = [],\n farClip,\n limits,\n nebulae = [],\n effects = [],\n background,\n time = 0,\n step = 0,\n cameraStep = step,\n effectView,\n viewport,\n shine,\n sunEffect,\n rayHits,\n player,\n rings = [],\n cut = false,\n lane = false,\n asteroids = [],\n dust,\n dustZones = [],\n dustOptions,\n beams = [],\n beamTexture,\n tractors = [],\n lineTexture,\n tractorRandom,\n tractorLimits,\n firstPerson = false,\n hud = false,\n cockpit,\n cockpitLimits,\n effectsOff = false,\n jump,\n}: SpaceScene): SpaceFrame => {\n const resolved = { ...RETAIL_SPACE_LIMITS, ...limits }\n const {\n rangeMargin,\n farListPlane,\n solarQueryRange,\n nearDistance,\n otherFieldDepth,\n ringFarMargin,\n } = resolved\n const systemFar = systemFarOf(farClip, resolved)\n\n if (jump)\n return collectJumpFrame(jump, { ...given, far: systemFar }, aspect, time, effects, {\n effectView,\n limits: resolved,\n hud,\n effectsOff,\n cockpit: firstPerson ? cockpit : undefined,\n firstPerson,\n cockpitLimits: { ...RETAIL_COCKPIT_LIMITS, ...cockpitLimits },\n })\n\n const range = systemFar - rangeMargin\n const { position: eye } = given\n const states = nebulae.map((nebula) => nebulaState(nebula, eye, resolved))\n const { field, deferred } = listNebulae(states, eye, range)\n // `FNebulaEffect::Update`, every nebula's, before the frame. A flashing light joins the system's.\n const flashes: SpaceLight[] = []\n // A nebula's clouds: held to its zone, and hidden deep in its exclusion zones as last sorted.\n const holdsOf = (nebula: SpaceNebula) => (point: Vector3) =>\n immersion(nebula.zone, nebula.edgeFraction ?? 0, point)\n const excludedOf = (nebula: SpaceNebula) => (point: Vector3) =>\n nebulaClock(nebula).order.at(point)?.immersion ?? 0\n\n // Each sun's own update, which the solar runs in the game's tick (`UpdateIntensity`).\n for (const { star } of objects) if (star) updateStar(star, cameraStep)\n\n for (const { nebula, depth, surface } of states) {\n nebula.exterior?.update(eye, cameraStep, depth, cut)\n\n // `FNebulaEffect::Update`: the bits' turn restarts `+0x58`; then, if the camera was in it last\n // frame, its exclusion zones are sorted about it on a cut, or once `+0x50` passes 0.25 while\n // `+0x58` isn't 0.\n const clock = nebulaClock(nebula)\n if (clock.depth < 1 && (clock.sinceTurned > 1 || cut)) clock.sinceTurned = 0\n\n if (clock.depth > 0 && (cut || (clock.since > f(0.25) && clock.sinceTurned !== 0)))\n clock.order.sort(eye)\n\n // Within 300 of its surface, its clouds follow the camera, as many as its depth allows.\n if (surface < 300)\n for (const clouds of nebula.clouds ?? [])\n clouds.update(given, step, depth, holdsOf(nebula), excludedOf(nebula))\n\n clock.since = f(cameraStep + clock.since)\n clock.sinceTurned = f(cameraStep + clock.sinceTurned)\n clock.depth = depth\n nebula.lightning?.update(step, depth, eye)\n\n const light = nebula.lightning?.light\n if (light) flashes.push(light)\n }\n\n const inCore = field?.enclosure === 2\n const far = inCore ? Math.min(fogFar(field.state, resolved), systemFar) : systemFar\n const camera: Camera = { ...given, far }\n const farCamera: Camera = { ...given, far: farListPlane }\n const view = viewMatrix(camera)\n\n // `SelectFieldControllers` lists the other nebulae first, however far they are.\n const lists: (Listed | ListedPiece | ListedBand | ListedNebula)[][] = Array.from(\n { length: LIST_COUNT },\n (_, at) => (at === FAR ? deferred.map(({ state, key }) => ({ nebula: state, key })) : []),\n )\n\n for (const object of objects) {\n const dx = object.position.x - eye.x\n const dy = object.position.y - eye.y\n const dz = object.position.z - eye.z\n const squared = dx * dx + dy * dy + dz * dz\n\n // A small solar comes from a query about the camera (`BspPartition::QuerySphere`, its radius and\n // the range), and the rest from lists that have no such limit.\n if (object.solar && !object.solar.large) {\n // Which radius the object DB's bucket holds isn't read: taken as `extent`, as `large` is.\n const reach = (object.solar.extent ?? object.sphere.radius) + solarQueryRange\n if (squared >= reach * reach) continue\n }\n\n const within =\n object.nebula === null ? undefined : findNebula(states, object.position, object.nebula)\n\n if (squared >= range * range) {\n // A far object in any nebula, or seen from a core, isn't drawn.\n if (!object.solar || inCore || within) continue\n\n const picked = pick(object, view, farCamera, aspect)\n if (picked) lists[FAR]!.push({ object, key: squared, picked })\n continue\n }\n\n const radius = object.solar?.planet ? object.sphere.radius : 0\n const key = squared - radius * radius\n let list = fieldList(within, key, field, otherFieldDepth)\n if (list === undefined) continue\n\n const picked = pick(object, view, camera, aspect)\n if (!picked) continue\n if (key < nearDistance * nearDistance) list = field && field.enclosure !== 0 ? FIELD : MAIN\n lists[object.nomad ? list + NOMAD_OFFSET : list]!.push({ object, key, picked, within })\n }\n\n // `TexturePanelsUpdateAll`, in the system's tick: each ring's clouds by how far in the camera is.\n const ringVisibility = rings.map((ring) => {\n const visibility = Math.fround(ringImmersion(ring, eye))\n\n for (const clouds of ring.clouds ?? [])\n clouds.update(given, step, visibility, (point) => ringImmersion(ring, point))\n\n return visibility\n })\n\n // `EnqueueTexturePanelPieces` (`0x51be10`): each piece the view's sphere test keeps, near ones by\n // how far past their radius, far ones by distance. Retail makes eight pieces of every ring, so its\n // one-piece branch, keyed by the zone's surface, is never reached and isn't built. In a core,\n // neither rings nor bands are listed (`0x51c352`).\n const ringReach = Math.fround((range - ringFarMargin) * (range - ringFarMargin))\n\n for (const ring of inCore ? [] : rings)\n for (const piece of ring.pieces) {\n const center = Matrix4.transformPoint(piece.center, view)\n if (classifySphere(center, piece.radius, camera, aspect) < 3) continue\n\n const dx = piece.center.x - eye.x\n const dy = piece.center.y - eye.y\n const dz = piece.center.z - eye.z\n const squared = dx * dx + dz * dz + dy * dy\n\n if (squared > ringReach) {\n lists[FAR]!.push({ ring, piece, key: Math.fround(squared) })\n continue\n }\n\n const radius = piece.radius * piece.radius\n\n lists[MAIN]!.push({ ring, piece, key: Math.fround(squared < radius ? 0 : squared - radius) })\n }\n\n // `CliAsteroidUpdate` moves each band's fade to the camera, and the first frame bakes its light at\n // its own zone.\n // Then `SpaceObjDrawPass` (`0x51ba40`) lists its pieces: one keyed by the zone's surface, or each\n // the view keeps by distance, those within a quarter of the range nearest first.\n const lighting = lightSet(flashes.length ? [...lights, ...flashes] : lights)\n const rangeSquared = Math.fround(range * range)\n const quarter = range * 0.25\n const nearSquared = Math.fround(quarter * quarter)\n\n for (const asteroid of asteroids) {\n const { band, exclusionBands = [], zone } = asteroid\n if (band) band.update(eye)\n\n // `CliAsteroidUpdate`: every exclusion band is held under how near the field the camera is.\n const fraction = exclusionBands.length ? nearFieldFraction(asteroid, eye, 1000) : 0\n for (const exclusion of exclusionBands) exclusion.update(eye, fraction)\n\n // Then its dynamic asteroids, near the field or not (`0x5223a6`).\n for (const { rocks } of asteroid.dynamic ?? [])\n rocks.update(given, step, {\n blocked: lane,\n effectStep: Math.min(step, resolved.effectMaxStep),\n })\n\n // Its pieces numbered through, its own band's first (`FUN_00524740`, `FUN_00522850`).\n const numbered = [...(band ? [band] : []), ...exclusionBands].flatMap((owner) =>\n owner.pieces.map((piece, at) => ({ owner, piece, at })),\n )\n\n for (const { owner } of numbered)\n if (!owner.isBaked)\n owner.bake({ ambient, ...directionalLightsAt(lighting, owner.position, time) })\n\n if (inCore) continue\n\n if (numbered.length === 1) {\n const key = bandSurfaceKey(zone, eye, nearSquared)\n\n lists[key < rangeSquared ? MAIN : FAR]!.push({ band: numbered[0]!.owner, piece: 0, key })\n continue\n }\n\n for (const {\n owner,\n piece: { center, radius },\n at,\n } of numbered) {\n if (classifySphere(Matrix4.transformPoint(center, view), radius, camera, aspect) < 3) continue\n\n const dx = center.x - eye.x\n const dy = center.y - eye.y\n const dz = center.z - eye.z\n let squared = dz * dz + dx * dx + dy * dy\n\n if (rangeSquared < squared) {\n lists[FAR]!.push({ band: owner, piece: at, key: Math.fround(squared) })\n continue\n }\n\n // `DAT_005dc028`: 0.05f widened to a double.\n if (nearSquared > squared) squared = (nearSquared - squared) * Math.fround(0.05) + nearSquared\n lists[MAIN]!.push({ band: owner, piece: at, key: Math.fround(squared) })\n }\n }\n\n // Retail's sort isn't stable, but equal keys are left in an order the object database decides.\n for (const list of lists) list.sort((a, b) => b.key - a.key)\n\n const draws: Draw[] = []\n const unsupported = new Set<string>()\n const unregistered = new Set<string>()\n const queued: Queued[] = []\n\n // A core hides the sky, and the far list has nothing in it then.\n if (!inCore)\n for (const model of sky) {\n collectModel(\n model,\n camera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n resolved,\n )\n flushQueued(queued, draws)\n }\n\n const linked: SpaceFlare[] = []\n const asteroidCubes = asteroids.map(() => ({ drawn: 0, tested: 0 }))\n const farProjection = projectionMatrix(farCamera, aspect)\n\n /**\n * `CliAsteroidTickOne`'s cubes. The field is lit once, at a point 100 behind the camera with a\n * radius of 250 (`CliAsteroidAmbientPass`), its ambient raised by `ambient_increase`; each cube\n * then sets only the material's colours and its fade, over the material's own stages, and is\n * drawn whole with no part test (`AsteroidUploadMesh`, `AsteroidDrawCube`).\n */\n const drawField = (asteroid: SpaceAsteroidField, index: number) => {\n const counted = { tested: 0 }\n const cubes = fieldCubes(asteroid, given, aspect, counted)\n\n asteroidCubes[index] = { drawn: cubes.length, tested: counted.tested }\n const dynamic = (asteroid.dynamic ?? []).map(({ rocks, model }) => ({\n rocks,\n model,\n draws: rocks.draws(),\n }))\n if (!cubes.length && !asteroid.billboards && !dynamic.some(({ draws }) => draws.length)) return\n\n const frame = Matrix4.fromRotationTranslation(given.orientation, eye)\n const point = Matrix4.transformPoint({ x: 0, y: 0, z: 100 }, frame)\n // `CliAsteroidAmbientPass` (`0x522700`): with `contains_fog_zone`, the camera's nebula at its\n // depth, none outside one. Without, the nebula holding the zone's centre, kept from the first\n // `CliAsteroidUpdate` (`0x522070`), at a factor of 1.\n const fieldNebula = (): Within | undefined => {\n if (asteroid.containsFogZone)\n return field && field.enclosure !== 0\n ? { state: field.state, factor: field.state.depth }\n : undefined\n\n const zoned = findNebula(states, asteroid.zone.position)\n return zoned && { state: zoned.state, factor: 1 }\n }\n const own = fieldNebula()\n const nebula = own?.state\n const lit = lightObject(\n lighting,\n { x: Math.fround(point.x), y: Math.fround(point.y), z: Math.fround(point.z) },\n 250,\n ambient,\n time,\n own && nebula?.nebula.ambient && { ambient: nebula.nebula.ambient, factor: own.factor },\n )\n const raise = asteroid.ambientIncrease ?? { x: 0, y: 0, z: 0 }\n // Ambient to a byte, plus the whole-byte increase, held to 255, back to 0 to 1.\n const byte = (value: number, increase: number) =>\n Math.min(Math.round(value * 255) + Math.trunc(increase), 255) / 255\n const sceneAmbient = {\n x: byte(lit.ambient.x, raise.x),\n y: byte(lit.ambient.y, raise.y),\n z: byte(lit.ambient.z, raise.z),\n }\n const fog = nebula && fogOf(nebula.start, fogEnd(nebula, point), nebula.nebula.fog.color)\n\n // `CliAsteroidTickOne` (`0x5225fd`): its billboards before its cubes, lit at the camera under\n // the same pass's ambient.\n if (asteroid.billboards)\n draws.push(\n ...asteroid.billboards.draw(\n given,\n {\n ambient: sceneAmbient,\n lights: directionalLightsAt(lighting, eye, time).lights,\n ...(fog && { fog }),\n },\n cut,\n ),\n )\n\n const fading = (asteroid.maxAlpha ?? 1) < 1\n const { diffuse, ambient: tint } = asteroid\n\n // A mesh drawn whole at a frame, with no part test; returns where its draws begin.\n const drawWhole = (\n { mesh, reference, ...lookups }: SpaceAsteroidField['cube'],\n world: Matrix4,\n ) => {\n const first = draws.length\n\n collectModel(\n { ...lookups, mesh: () => mesh, parts: [{ reference, world, mesh }] },\n camera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n resolved,\n true,\n )\n return first\n }\n\n for (const { position, orientation, alpha } of cubes) {\n const world = Matrix4.multiply(Matrix4.translation(position), orientation)\n const first = drawWhole(asteroid.cube, world)\n\n for (let index = first; index < draws.length; index++) {\n const blended = alpha < 1\n\n draws[index] = {\n ...draws[index]!,\n diffuse: [diffuse.x, diffuse.y, diffuse.z, alpha],\n // With lighting on and no fade, its own ambient; fading, the diffuse.\n ambient: fading ? diffuse : tint,\n emissive: { x: 0, y: 0, z: 0 },\n // A fading field clears the lights and sets a white ambient (`0x5237f4`).\n lights: fading ? [] : lit.lights,\n sceneAmbient: fading ? { x: 1, y: 1, z: 1 } : sceneAmbient,\n depthFunc: 'lequal',\n depthWrite: !fading,\n blend: blended,\n blendMode: 'alpha',\n alphaFunction: 'greater',\n alphaReference: blended ? 5 : 127,\n ...(fog ? { fog } : {}),\n }\n }\n }\n\n /**\n * `CliDynamicAsteroidDraw`, each section's rocks after the cubes. A fading field's cubes undo\n * the pass, so the rocks run it again (`0x5226b9`): always lit. Each sets its tints and its\n * alpha; whole, it's opaque at `ALPHAREF` 127, else blended at 5. Depth writes are the\n * material's: retail leaves them alone.\n */\n for (const { rocks, model, draws: placed } of dynamic)\n for (const { world, alpha } of placed) {\n const first = drawWhole(model, world)\n\n for (let index = first; index < draws.length; index++) {\n const blended = alpha < 1\n\n draws[index] = {\n ...draws[index]!,\n diffuse: [rocks.diffuse.x, rocks.diffuse.y, rocks.diffuse.z, alpha],\n ambient: rocks.ambient,\n emissive: { x: 0, y: 0, z: 0 },\n lights: lit.lights,\n sceneAmbient,\n depthFunc: 'lequal',\n blend: blended,\n blendMode: 'alpha',\n alphaFunction: 'greater',\n alphaReference: blended ? 5 : 127,\n ...(fog ? { fog } : {}),\n }\n }\n }\n }\n\n /**\n * `FNebulaEffect::DrawExclusionShell` (`0x508f20`): the shell of the exclusion zone the camera is\n * in, scaled to its radius times `shell_scalar` over 1000. Lit with no lights by a white ambient,\n * so its material's ambient, the tint, colours it, and its diffuse alpha is\n * `(immersion - 0.2) · 1.25`, held to [0, 1], times `max_alpha`. No depth writes and no fog; the\n * depth test and culling are the frame's, `LEQUAL` and back faces.\n */\n const drawShell = (state: NebulaState) => {\n const inside = state.inExclusion\n const shell = inside?.exclusion.shell\n if (!inside || !shell) return\n\n const fade = (inside.immersion - Math.fround(0.2)) * Math.fround(1.25)\n const alpha = Math.fround((fade < 0 ? 0 : fade > 1 ? 1 : fade) * (shell.maxAlpha ?? 1))\n const scale = Math.fround(\n inside.exclusion.zone.radius * (shell.scalar ?? 1) * Math.fround(0.001),\n )\n const world = Matrix4.multiply(shell.transform, Matrix4.scaling(scale))\n const first = draws.length\n\n collectModel(\n shell.place(world),\n camera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n resolved,\n )\n flushQueued(queued, draws)\n\n for (let index = first; index < draws.length; index++) {\n const draw = draws[index]!\n\n draws[index] = {\n ...draw,\n diffuse: [draw.diffuse[0], draw.diffuse[1], draw.diffuse[2], alpha],\n ambient: shell.tint,\n lights: [],\n sceneAmbient: { x: 1, y: 1, z: 1 },\n blend: true,\n blendMode: 'alpha',\n depthWrite: false,\n depthFunc: 'lequal',\n cull: 'back',\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n }\n }\n\n // `DrawBoltsPass`'s bits, on the far list's plane.\n const drawExterior = (state: NebulaState) => {\n const draw = state.nebula.exterior?.draw(state, farCamera, view, aspect, farProjection)\n if (draw) draws.push(draw)\n }\n\n for (const at of !field || field.enclosure === 0 ? OUTSIDE_ORDER : INSIDE_ORDER) {\n const onFarList = at === FAR\n const passCamera = onFarList ? farCamera : camera\n\n // `DrainMeshAndAsteroids` outside a field: the field's sheets, under the far list's plane, then\n // its own list (`0x51f9bc`).\n if (at === FIELD && field?.enclosure === 0) {\n const sheets = fillSheetsDraw(field.state, eye, farProjection)\n if (sheets) draws.push(sheets)\n }\n\n for (const listed of lists[at]!) {\n const first = draws.length\n\n // `ZItemNebula`: its sheets, then its exterior.\n if ('nebula' in listed) {\n const sheets = fillSheetsDraw(listed.nebula, eye, farProjection)\n if (sheets) draws.push(sheets)\n drawExterior(listed.nebula)\n continue\n }\n\n if ('band' in listed) {\n const draw = listed.band.pieceDraw(listed.piece)\n if (draw) draws.push({ ...draw, projection: farProjection })\n continue\n }\n\n if ('ring' in listed) {\n const draw = ringPieceDraw(listed.ring, listed.piece)\n if (!draw) continue\n draws.push(\n onFarList\n ? { ...draw, depthFunc: 'always', depthWrite: false, projection: farProjection }\n : draw,\n )\n continue\n }\n\n const { object, picked, within } = listed\n\n // A sun's draw (`Slot188`, `0x548220`) is its glow, under the far list's plane wherever it's\n // listed, and returns before `GameobjSubmitDrawRetail` links lights or draws anything else.\n if (object.star)\n draws.push(...starGlowDraws(object.star, object.position, given, farProjection))\n else {\n if (object.pilot && picked.tier === 0)\n collectModel(\n object.pilot,\n passCamera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n resolved,\n )\n\n // `GameobjSweepEffectList` links its lights at the first tier, each to the bucket's front.\n if (picked.tier === 0 && object.flares) linked.unshift(...[...object.flares].reverse())\n\n // `GameobjSubmitDrawRetail`: only the first tier arms the reflection. What's attached is\n // drawn in the same `RenderInstance`, under the same flags and the object's reflection.\n for (const model of [object.model, ...(object.attached ?? []).map(underOwn(object.model))])\n collectModel(\n picked.tier === 0 ? model : withoutEnvironment(model),\n passCamera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n resolved,\n picked.rank === 4 && picked.tier === 0,\n )\n\n flushQueued(queued, draws)\n }\n\n // `GameobjUpdateDrawLighting`, from where it stands and its sphere's radius. A draw with an\n // ambient of its own, an exclusion zone's, keeps it.\n const nebula = within?.state.nebula\n const lit = lightObject(\n lighting,\n object.position,\n object.sphere.radius,\n ambient,\n time,\n nebula?.ambient && { ambient: nebula.ambient, factor: within!.factor },\n )\n // The same call fogs what a nebula holds, and turns fog off for anything else.\n const fog =\n within &&\n fogOf(within.state.start, fogEnd(within.state, object.position), nebula!.fog.color)\n\n // A sun's draw returns before it (`Slot188`): its glow keeps the frame's ambient, the sky's\n // white, and no fog, as `sun_ahead` and `sun_nebula` capture.\n if (!object.star)\n for (let index = first; index < draws.length; index++) {\n const draw = draws[index]!\n\n draws[index] = {\n ...draw,\n lights: lit.lights,\n sceneAmbient: draw.sceneAmbient ?? lit.ambient,\n ...(fog && { fog }),\n }\n }\n\n // `DrainMeshAndAsteroids` (`0x51f956`) sets `ZFUNC` 4 for the near lists and leaves it, where\n // RP8's default is 2. No material sets 2, so what would have kept the default reads 4.\n if (!onFarList)\n for (let index = first; index < draws.length; index++)\n if (draws[index]!.depthFunc === 'less')\n draws[index] = { ...draws[index]!, depthFunc: 'lequal' }\n\n // `ZENABLE 0` around each node (`DrainBucket`), so it neither reads depth nor leaves any.\n if (onFarList)\n for (let index = first; index < draws.length; index++)\n draws[index] = {\n ...draws[index]!,\n depthFunc: 'always',\n depthWrite: false,\n projection: farProjection,\n }\n }\n\n // `DrainMeshAndAsteroids` in a field: the main lists, in its edge its sheets (`0x51fa8a`), then the\n // fog overlay, then the field's own.\n if (at === NOMAD_OFFSET + MAIN && field?.enclosure === 1) {\n const sheets = fillSheetsDraw(field.state, eye, farProjection)\n if (sheets) draws.push(sheets)\n }\n\n if (at === NOMAD_OFFSET + MAIN && field && field.enclosure !== 0) {\n const overlay = fogOverlayDraw(field.state, view, viewport)\n if (overlay) draws.push(overlay)\n\n // Then every sun of the system, listed or not, in the order its solars were read, burning\n // through the fog: its glow at the field's depth times its `sun_burnthrough_intensity`, larger\n // by its `sun_burnthrough_scaler` (`0x51fad9`). Its fog is what the overlay left: **uncaptured**.\n const { burnthrough } = field.state.nebula\n const alpha = f(field.state.depth * f(burnthrough?.intensity ?? 0.5))\n const size = f(burnthrough?.scaler ?? 1.75)\n\n for (const { star, position } of objects)\n if (star) draws.push(...starGlowDraws(star, position, given, farProjection, alpha, size))\n }\n\n // `DrawBoltsPass`: outside a field after its list (`0x51fa10`), in its edge after the suns'\n // glows (`0x51fb3b`).\n if (\n (at === FIELD && field?.enclosure === 0) ||\n (at === NOMAD_OFFSET + MAIN && field?.enclosure === 1)\n )\n drawExterior(field.state)\n\n // `CliAsteroidTickFields`: outside a field after the main list and the rings' clouds, inside one\n // after its own list, and its nebula's exclusion shell before them (`0x51fb7e`).\n if (at === FIELD && field && field.enclosure !== 0) drawShell(field.state)\n\n if (\n (at === MAIN && (!field || field.enclosure === 0)) ||\n (at === FIELD && field && field.enclosure !== 0)\n )\n asteroids.forEach(drawField)\n\n // `DrawCloudsPanels`, last in a field (`0x51fbb4`): its clouds, fogged to its own range, unculled.\n if (at === NOMAD_OFFSET + FIELD && field && field.enclosure !== 0) {\n const { nebula, start, end } = field.state\n\n for (const clouds of nebula.clouds ?? []) {\n const draw = clouds.draw(given, {\n cut,\n holds: holdsOf(nebula),\n excluded: excludedOf(nebula),\n })\n if (draw) draws.push({ ...draw, fog: fogOf(start, end, nebula.fog.color), cull: 'none' })\n }\n }\n\n // `DrainMeshAndAsteroids` outside a field: the main list, then every ring's clouds while the\n // camera is in it (`TexturePanelsDrawAll`, `DrawPanels`). In a field, no ring's clouds draw.\n if (at === MAIN && (!field || field.enclosure === 0))\n rings.forEach((ring, index) => {\n if (!(ringVisibility[index]! > 0)) return\n\n for (const clouds of ring.clouds ?? []) {\n const draw = clouds.draw(given, { cut, holds: (point) => ringImmersion(ring, point) })\n if (draw) draws.push(draw)\n }\n })\n }\n\n // Bucket `0x2e`'s walk, after the other effects: each light blinks, then queues its flare, and the\n // batch draws once they're all queued (`SpaceEffectsDrawFrame`, `ScreenQuadFlush`).\n const quads: ScreenQuad[] = []\n\n if (linked.length && viewport && !shine) unsupported.add('texture shine')\n\n const blinkStep = Math.min(Math.fround(step), Math.fround(0.1))\n\n for (const { light, world, blink } of linked) {\n blink?.tick(blinkStep)\n\n const brightness = blink?.brightness ?? 1\n if (brightness < 0 || !viewport || !shine) continue\n quads.push(\n ...flareQuads(light, world, brightness, {\n camera,\n view,\n aspect,\n ...viewport,\n ...(shine.frame ? { frame: shine.frame } : {}),\n }),\n )\n }\n\n // `ScaleEnvironmentEffects` once the effects are done: each sun's spines and corona, in the order\n // its solars were read (`SpaceEnvFxBeginCockpitPass`, `0x51c970`). Fully in a field, only its\n // occlusion.\n const afterEffects: Draw[] = []\n const quality = sunEffect === undefined ? 0 : sunEffectQuality(sunEffect)\n // Each object hit is itself, so a sun's own solar is told apart.\n const hitboxes = objects.flatMap((object) =>\n object.hitbox\n ? [\n {\n object,\n position: object.position,\n radius: object.solar?.extent ?? object.sphere.radius,\n hitbox: object.hitbox,\n },\n ]\n : [],\n )\n const castFrom: CoronaView['rayHits'] =\n rayHits ??\n (hitboxes.length ? (from, to, limit) => castRay(hitboxes, from, to, limit) : undefined)\n\n if (quality > 0 && viewport)\n for (const object of objects) {\n const { star, position } = object\n if (!star) continue\n\n if (field?.enclosure === 2) {\n hideStar(star)\n continue\n }\n\n // `FUN_00511b90`: the player in a lane, or any nebula's or field's zone across the line.\n const zones = [...nebulae.map(({ zone }) => zone), ...asteroids.map(({ zone }) => zone)]\n const zoneBlocked = lane || zones.some((zone) => zone.meets(eye, position))\n\n afterEffects.push(\n ...starCorona(star, position, zoneBlocked, {\n camera: given,\n view,\n ...viewport,\n ...(castFrom && { rayHits: castFrom }),\n own: object,\n ...(player !== undefined && { player }),\n leastLod: sunLeastLod(quality),\n }),\n )\n }\n\n const litCockpit = () => {\n const { sphere, within } = cockpit!\n const nebula = within?.state.nebula\n const lit = lightObject(\n lighting,\n sphere.center,\n sphere.radius,\n ambient,\n time,\n nebula?.ambient && { ambient: nebula.ambient, factor: within!.factor },\n )\n const fog =\n within &&\n nebula &&\n fogOf(within.state.start, fogEnd(within.state, sphere.center), nebula.fog.color)\n\n return cockpitDraws(\n cockpit!,\n camera,\n aspect,\n view,\n time,\n hud,\n effectsOff,\n { ...RETAIL_COCKPIT_LIMITS, ...cockpitLimits },\n unsupported,\n unregistered,\n resolved,\n { lights: lit.lights, ambient: lit.ambient, ...(fog && { fog }) },\n )\n }\n\n // `SpaceEnvFxEndCockpitPass` (`0x51c9e0`): then every sun's flare, from where the last draw left it.\n const flares: Draw[] = []\n\n if (quality > 0 && viewport)\n for (const { star } of objects) {\n const flare = star && starFlare(star, { view, ...viewport })\n if (flare) flares.push(flare)\n }\n\n // From the cockpit its mesh goes between them (`0x51848b`, `0x5185e5`), past the depth clear.\n const shownCockpit = firstPerson && cockpit ? litCockpit() : undefined\n\n afterEffects.push(...(shownCockpit?.drawn ?? []), ...flares)\n\n const effectDraws: EffectDraw[] = []\n // A placed effect is drawn only if seen. What it is otherwise the host learns from `effectViews`.\n // The fields' rocks carry theirs, which they step themselves: walked after the host's.\n const carried = asteroids.flatMap(({ dynamic = [] }) =>\n dynamic.map(({ rocks }) => ({ rocks, effects: rocks.effects() })),\n )\n // Newest first, over every field's, as the game's list holds them.\n const rockEffects = carried\n .flatMap(({ effects }) => effects)\n .sort((a, b) => b.serial - a.serial)\n .map(({ effect }) => effect)\n\n // The dust's, held ahead of the camera, after the rocks'.\n if (dust) {\n const types = effectView?.effectTypes ?? []\n const runTimes = RETAIL_EFFECT_TYPES.map((row, at) => types[at]?.runTime ?? row.runTime)\n\n dust.update(given, step, dustZones, { ...dustOptions, runTimes })\n }\n\n const dustEffects = dust ? dust.effects().map(({ effect }) => effect) : []\n const all = [...effects, ...rockEffects, ...dustEffects]\n const effectFrame = { camera, aspect, view, field, nebulae: states }\n const viewsOf = all.map((effect) => viewOne(effect, effectFrame, effectView))\n const views = viewsOf.slice(0, effects.length)\n const viewOf = new Map(rockEffects.map((effect, at) => [effect, viewsOf[effects.length + at]]))\n\n for (const { rocks, effects: theirs } of carried)\n rocks.viewed(theirs.map(({ effect }) => viewOf.get(effect)))\n\n dust?.viewed(viewsOf.slice(effects.length + rockEffects.length))\n\n // The walk is by type bucket, each in list order.\n const walked = all\n .map((effect, at) => ({ effect, at }))\n .filter(\n ({ effect, at }) =>\n effect.type !== SKIPPED_EFFECT_TYPE && (viewsOf[at]?.fate ?? 'draw') === 'draw',\n )\n .sort((a, b) => a.effect.type - b.effect.type || a.at - b.at)\n\n for (const { effect } of walked)\n collectEffect(effect.instance, view, effect.texture, effectDraws, unsupported, effect.visible)\n\n // `SpaceObjDrawPass` fogs effects to black, so what they add fades out.\n const effectFog =\n field && field.enclosure !== 0\n ? fogOf(field.state.start, fogEnd(field.state, eye), BLACK)\n : undefined\n\n // `SpaceEffectsDrawFrame` walks the shots after every other effect, in their own bucket, and draws\n // them as one once the walk is done (`0x4f76cd`). No `code_beam` and retail starts none.\n if (beams.length && !beamTexture) unsupported.add('texture code_beam')\n\n const shots = beamBatch(firstPerson)\n\n if (beamTexture) {\n const seen = beamView(camera, aspect, view, effectView)\n for (const beam of beams) beam.walk(blinkStep, seen, shots)\n }\n\n // Its bucket after the shots' draws as it's walked, ahead of their flush. No `line` and retail\n // starts none (`CliTractorBeamInit`).\n if (tractors.length && !lineTexture) unsupported.add('texture line')\n\n const tractorsDrawn = lineTexture\n ? tractorDraws(\n tractors,\n lineTexture,\n {\n camera,\n aspect,\n view,\n ...(tractorRandom && { random: tractorRandom }),\n ...(tractorLimits && { limits: tractorLimits }),\n },\n effectFog,\n )\n : []\n const beamsDraw = beamTexture && beamDraw(shots, beamTexture, effectFog)\n\n // Deep enough in, the clear is the fog's colour, which its lightning flashes.\n const deep = field && field.state.depth >= 1 ? field.state.nebula : undefined\n const fogged = deep && (deep.lightning?.fogColor(deep.fog.color) ?? deep.fog.color)\n\n return {\n background: fogged ? fogOf(0, 0, fogged).color : (background ?? BLACK_BACKGROUND),\n hooks: hooksOf(draws),\n view,\n projection: projectionMatrix(camera, aspect),\n // Each object has its own. What's left over is the sky's: white, and no lights.\n ambient: systemAmbient(ambient),\n lights: [],\n draws,\n effects: effectDraws,\n ...(effectFog && { effectFog }),\n // `SpaceEffectsDrawFrame` (`0x4f7480`) sets `ZFUNC` 4 around every effect.\n effectDepthFunc: 'lequal',\n effectViews: views,\n asteroidCubes,\n ...(tractorsDrawn.length && { tractors: tractorsDrawn }),\n ...(beamsDraw && { beams: beamsDraw }),\n ...(quads.length && shine && { screenQuads: [{ texture: shine.texture, quads }] }),\n ...(firstPerson && (hud || cockpit) && { clearDepth: true }),\n ...(afterEffects.length && { afterEffects }),\n ...(shownCockpit?.atEnd.length && { atEnd: shownCockpit.atEnd }),\n unsupported: [...unsupported],\n unregistered: [...unregistered],\n }\n}\n\n/**\n * `FirstPersonCameraSceneDraw`'s mesh (`0x5184a7`), lit as the caller's pass lights it. Its parts are\n * tested under the pass's own near and far, then drawn at the back of the depth range. The effects\n * left the batcher's bin 1 off (`SpaceEffectsDrawFrame`, `0x4f75d6`) and only `Win3DDrawAll`'s end\n * turns it on, so each part draws in order, glass too (`cockpit_rh`). With the effects option off\n * it's on, and what it queues waits for the scene's end (`EndSceneHalf`), under the range the pass\n * left and the projection last applied: with the HUD on the frame's, as `HudCameraDraw` re-applies\n * it, and off still the mesh's. That case is uncaptured.\n */\nconst cockpitDraws = (\n { model }: SpaceCockpit,\n given: Camera,\n aspect: number,\n view: Matrix4,\n time: number,\n hud: boolean,\n effectsOff: boolean,\n { near, far, depthRange, afterDepthRange }: CockpitLimits,\n unsupported: Set<string>,\n unregistered: Set<string>,\n limits: FrameLimits,\n lit: { lights: SceneLight[]; ambient: Vector3; fog?: Fog },\n): { drawn: Draw[]; atEnd: Draw[] } => {\n const camera = { ...given, near, far }\n const projection = projectionMatrix(camera, aspect)\n const drawn: Draw[] = []\n const queued: Queued[] | undefined = effectsOff ? [] : undefined\n\n collectModel(model, camera, aspect, view, time, drawn, queued, unsupported, unregistered, limits)\n\n const atEnd: Draw[] = []\n if (queued) flushQueued(queued, atEnd)\n\n // `ZFUNC` is still the 4 the near lists, or the tunnel, left (`cockpit_li`).\n const litDraw = (draw: Draw): Draw => ({\n ...draw,\n lights: lit.lights,\n sceneAmbient: draw.sceneAmbient ?? lit.ambient,\n ...(lit.fog && { fog: lit.fog }),\n ...(draw.depthFunc === 'less' && { depthFunc: 'lequal' as const }),\n })\n\n return {\n drawn: drawn.map((draw) => ({ ...litDraw(draw), projection, depthRange })),\n atEnd: atEnd.map((draw) => ({\n ...litDraw(draw),\n depthRange: afterDepthRange,\n ...(!hud && { projection }),\n })),\n }\n}\n\n/**\n * `SpaceObjDrawPass`'s jump arm (`0x51c235`), out to the system's far plane: the tunnel\n * (`FUN_00504890`), then the ship at its first tier (`Slot188`) with no pilot, as the arm's LOD word's\n * low half is 0 and the pilot wants 3 (`0x546087`), lit by the tunnel's light alone\n * over the jump's ambient (`Slot184`), then only `EFT_JUMP_EFFECTS`' bucket and `EFT_ENGINE_FIRE`'s\n * (`SpaceEffectsDrawFrame`, `0x51c2bc`), which step only those. No flare, beam or other list draws.\n * The pass sets the jump's colour for the clear after it, so retail's first tunnel frame clears to\n * the last colour; here every one clears to it.\n */\nconst collectJumpFrame = (\n { ship, tunnel, ambient, background }: SpaceJump,\n camera: Camera,\n aspect: number,\n time: number,\n effects: readonly SpaceEffect[],\n {\n effectView,\n limits,\n firstPerson,\n hud,\n effectsOff,\n cockpit,\n cockpitLimits,\n }: {\n effectView: EffectViewOptions | undefined\n limits: SpaceLimits\n firstPerson: boolean\n hud: boolean\n effectsOff: boolean\n cockpit: SpaceCockpit | undefined\n cockpitLimits: CockpitLimits\n },\n): SpaceFrame => {\n const view = viewMatrix(camera)\n const draws: Draw[] = tunnel?.draws() ?? []\n const queued: Queued[] = []\n const unsupported = new Set<string>()\n const unregistered = new Set<string>()\n const first = draws.length\n const models = [ship.model, ...(ship.attached ?? []).map(underOwn(ship.model))]\n\n for (const model of models)\n collectModel(\n model,\n camera,\n aspect,\n view,\n time,\n draws,\n queued,\n unsupported,\n unregistered,\n limits,\n )\n\n flushQueued(queued, draws)\n\n // `EngineLightClearRegisteredList`, `jump_ambient` into `D3DRS_AMBIENT`, then the tunnel's light.\n // `ZFUNC` is 4, as the last near list and the tunnel's `Win3DSetDepthWrite` leave it.\n const light = tunnel?.light\n const shipAmbient = systemAmbient(ambient)\n\n for (let index = first; index < draws.length; index++) {\n const draw = draws[index]!\n\n draws[index] = {\n ...draw,\n lights: light ? [light] : [],\n sceneAmbient: draw.sceneAmbient ?? shipAmbient,\n ...(draw.depthFunc === 'less' && { depthFunc: 'lequal' as const }),\n }\n }\n\n // The view test is the walk's, with no field: `G_FieldController` is cleared first.\n const views = effects.map((effect): EffectView | undefined => {\n if (!TUNNEL_EFFECT_TYPES.includes(effect.type)) return { fate: 'hold', lod: 1 }\n if (!effect.position) return undefined\n\n const placed = { ...effect, position: effect.position }\n\n return viewEffect(placed, { camera, aspect, view, nebulae: [] }, effectView)\n })\n\n const effectDraws: EffectDraw[] = []\n\n for (const type of TUNNEL_EFFECT_TYPES)\n effects.forEach((effect, at) => {\n if (effect.type !== type || (views[at]?.fate ?? 'draw') !== 'draw') return\n collectEffect(effect.instance, view, effect.texture, effectDraws, unsupported, effect.visible)\n })\n\n // From the cockpit, its mesh takes no light in the jump, only its ambient (`0x5184d9`).\n const shownCockpit =\n cockpit &&\n cockpitDraws(\n cockpit,\n camera,\n aspect,\n view,\n time,\n hud,\n effectsOff,\n cockpitLimits,\n unsupported,\n unregistered,\n limits,\n { lights: [], ambient: shipAmbient },\n )\n\n return {\n background: { x: background.x / 255, y: background.y / 255, z: background.z / 255 },\n hooks: hooksOf(draws),\n view,\n projection: projectionMatrix(camera, aspect),\n ambient: shipAmbient,\n lights: [],\n draws,\n effects: effectDraws,\n effectDepthFunc: 'lequal',\n effectViews: views,\n asteroidCubes: [],\n ...(firstPerson && (hud || cockpit) && { clearDepth: true }),\n ...(shownCockpit?.drawn.length && { afterEffects: shownCockpit.drawn }),\n ...(shownCockpit?.atEnd.length && { atEnd: shownCockpit.atEnd }),\n unsupported: [...unsupported],\n unregistered: [...unregistered],\n }\n}\n","/**\n * A base room's flashlights: `FFlashLight` in `src/freelancer/Client/flash_light.cpp`, the blinking\n * lights a prop's or ship's `[Light]` equipment carries and a room's `[FlashlightSet]` lines up, and\n * `DrawFlashlightFlares` (`FUN_00558000`), which draws each as two camera-facing quads. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport { Primitive, setMapCount, VertexFormat, type VMeshData } from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Camera } from './camera.js'\nimport { LightBlink, type FlareLight } from './flare.js'\nimport type { Draw } from './frame.js'\nimport type { Random } from './lightning.js'\nimport { inverseRoot, unitByte } from './retail.js'\n\nconst f = Math.fround\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\nconst DEGREES = f(0.017453292)\n\n/** A `[FlashlightSet]` or `[FlashlightLine]` from a room's INI. The host reads it. */\nexport interface FlashlightSet {\n /** `color`, or `icolor` over 255. */\n color: Vector3\n /** The glow's half-size; the bulb's is a quarter of it. */\n scale: number\n /** Seconds between one light's blink and the next's. */\n gap: number\n /** How long each blink lasts. */\n blink: number\n /** The pause after the last light's, before the first's again. */\n endpause: number\n}\n\n/** One light: its colours, sizes and cone, its blink, and where the host has put it. */\nexport class FlashLight {\n readonly color: Vector3\n readonly minColor: Vector3\n readonly bulbSize: number\n readonly glowSize: number\n /** `flare_cone`'s cosines: the glow's gone below `inner`, and whole from `outer`. */\n readonly cone: { inner: number; outer: number }\n readonly blink: LightBlink\n /** Its hardpoint's frame in the world, which the host keeps up to date (`FUN_00558470`). */\n world: Matrix4 = Matrix4.identity\n /** The bulb's colour, `min_color` to `color` with the blink, and the glow's, black to `color`. */\n bulbColor: Vector3\n glowColor: Vector3\n\n constructor(\n color: Vector3,\n minColor: Vector3,\n bulbSize: number,\n glowSize: number,\n cone: { inner: number; outer: number },\n blink: LightBlink,\n ) {\n this.color = color\n this.minColor = minColor\n this.bulbSize = bulbSize\n this.glowSize = glowSize\n this.cone = cone\n this.blink = blink\n this.bulbColor = color\n this.glowColor = color\n }\n\n /**\n * A `[Light]` on a prop or ship (`FUN_00557700`), `always_on` and with a hardpoint. Its glow is\n * `color`'s, not `glow_color`'s, and its period and phase are drawn from `rand()`.\n */\n static fromLight(light: FlareLight, random?: Random): FlashLight {\n const [first, second] = light.flareCone ?? []\n // `0x40adea`: each by `DAT_005c77f4`, the second's cosine first. -1 each when absent.\n const cos = (degrees: number | undefined) =>\n degrees === undefined ? -1 : f(Math.cos(f(degrees) * DEGREES))\n\n return new FlashLight(\n light.color,\n light.minColor,\n f(light.bulbSize),\n f(light.glowSize),\n { inner: cos(first), outer: cos(second) },\n new LightBlink(light, random),\n )\n }\n\n /** `RoomControlLoadFlashlights` (`FUN_0044a3a0`): one light per frame, staggered by `gap`. */\n static ofSet({ color, scale, gap, blink, endpause }: FlashlightSet, frames: readonly Matrix4[]) {\n const count = frames.length\n const period = f((count - 1) * f(gap) + f(endpause))\n const step = period > 0 ? f(f(gap) / period) : 0\n\n return frames.map((world, index) => {\n const light = new FlashLight(\n color,\n BLACK,\n f(f(scale) * 0.25),\n f(scale),\n { inner: 0, outer: 0 },\n LightBlink.timed(period, -(index * step), blink),\n )\n\n light.world = world\n return light\n })\n }\n\n /** `FUN_00557860`: the blink advanced by `step` seconds, and both colours made from it. */\n update(step: number): void {\n this.blink.tick(step)\n\n const level = this.blink.brightness\n const { color, minColor } = this\n\n this.glowColor = { x: f(level * color.x), y: f(level * color.y), z: f(level * color.z) }\n this.bulbColor = {\n x: f(f(color.x - minColor.x) * level + minColor.x),\n y: f(f(color.y - minColor.y) * level + minColor.y),\n z: f(f(color.z - minColor.z) * level + minColor.z),\n }\n }\n}\n\n// `FUN_00557d00`: the fast inverse square root and one Newton step.\nconst normalizeFast = ({ x, y, z }: Vector3): Vector3 => {\n const scale = inverseRoot(f(x * x + y * y + z * z))\n\n return { x: f(scale * x), y: f(scale * y), z: f(scale * z) }\n}\n\n/** `FUN_005579b0`'s cone term: 1 inside `outer`, 0 past `inner`, a ramp between. */\nexport const coneLevel = (light: FlashLight, eye: Vector3): number => {\n const { inner, outer } = light.cone\n if (!(outer > inner)) return 1\n\n const { z: axis, w: position } = light.world\n const dir = normalizeFast({\n x: f(position.x - eye.x),\n y: f(position.y - eye.y),\n z: f(position.z - eye.z),\n })\n const wide = dir.z * axis.z + dir.y * axis.y + dir.x * axis.x\n if (wide < inner) return 0\n\n const dot = f(wide)\n\n return dot < outer ? (dot - inner) / (outer - inner) : 1\n}\n\n// `FUN_00421ad0`: times 255, truncated, clamped. Alpha is 255.\nconst colourBytes = ({ x, y, z }: Vector3): number[] => {\n const byte = unitByte\n\n return [byte(z), byte(y), byte(x), 255]\n}\n\n// XYZ, D3DCOLOR and one UV set: FVF 0x142, 24 bytes, as Win3D's immediate mode draws.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\n// Win3D's quads, triangulated `(0, 1, 2)` and `(0, 2, 3)`.\nconst ORDER = [0, 1, 2, 0, 2, 3]\nconst UVS = [\n [0, 0],\n [1, 0],\n [1, 1],\n [0, 1],\n]\n\ninterface Flare {\n center: Vector3\n size: number\n color: Vector3\n}\n\nconst isBlack = ({ x, y, z }: Vector3) => x === 0 && y === 0 && z === 0\n\n// One pass of `DrawFlashlightFlares`: a quad per light, `Center ∓ R ± U` as `EmitFlareQuad` rounds them.\nconst passDraw = (name: string, flares: Flare[], right: Vector3, up: Vector3, texture: Texture) => {\n const count = flares.length * ORDER.length\n const vertices = new Uint8Array(count * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n flares.forEach(({ center: c, size, color }, index) => {\n const r = { x: f(right.x * size), y: f(right.y * size), z: f(right.z * size) }\n const u = { x: f(up.x * size), y: f(up.y * size), z: f(up.z * size) }\n const left = { x: f(c.x - r.x), y: f(c.y - r.y), z: f(c.z - r.z) }\n const edge = { x: f(c.x + r.x), y: f(c.y + r.y), z: f(c.z + r.z) }\n const corners = [\n [f(left.x + u.x), f(left.y + u.y), f(left.z + u.z)],\n [f(u.x + edge.x), f(u.y + edge.y), f(u.z + edge.z)],\n [f(edge.x - u.x), f(edge.y - u.y), f(edge.z - u.z)],\n [f(c.x - r.x - u.x), f(c.y - r.y - u.y), f(left.z - u.z)],\n ]\n const bytes = colourBytes(color)\n\n ORDER.forEach((corner, at) => {\n const offset = (index * ORDER.length + at) * STRIDE\n\n floats.set(corners[corner]!, offset / 4)\n vertices.set(bytes, offset + 12)\n floats.set(UVS[corner]!, (offset + 16) / 4)\n })\n })\n\n const mesh: VMeshData = {\n name,\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n { materialId: 0, vertexStart: 0, vertexEnd: count - 1, elementCount: count, padding: 0 },\n ],\n indices: Uint16Array.from({ length: count }, (_, at) => at),\n vertices,\n }\n const draw: Draw = {\n mesh,\n reference: {\n meshId: 0,\n vertexStart: 0,\n vertexCount: count,\n indexStart: 0,\n indexCount: count,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n },\n transient: true,\n byteOffset: 0,\n count,\n world: Matrix4.identity,\n materialName: name,\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: { name, entry: texture, sampler: DEFAULT_SAMPLER, uvSet: 0 },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'lequal',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'add',\n unlit: true,\n // The alpha test is the device's as the last draw left it, taken as off: uncaptured.\n alphaReference: 0,\n alphaFunction: 'always',\n }\n\n return draw\n}\n\n/** `fx/efx.txm`'s `shine` and `bulb`. */\nexport interface FlashlightTextures {\n shine: Texture\n bulb: Texture\n}\n\n/** At most this many of a prop's or ship's lights draw (`FUN_00558580`); a room's own aren't held to it. */\nexport const FLASHLIGHTS_PER_SET = 0x20\n\n/**\n * `DrawFlashlightFlares`: every glow, then every bulb, each a quad facing the camera, added, `LEQUAL`\n * without writing depth, no culling and no fog. A black one is left out.\n */\nexport const flashlightDraws = (\n lights: readonly FlashLight[],\n camera: Camera,\n { shine, bulb }: FlashlightTextures,\n): Draw[] => {\n if (lights.length === 0) return []\n\n const { x: right, y: up } = Matrix4.fromRotationTranslation(camera.orientation)\n const centre = (light: FlashLight) => light.world.w\n const glows: Flare[] = []\n const bulbs: Flare[] = []\n\n for (const light of lights) {\n if (!isBlack(light.glowColor)) {\n const level = f(coneLevel(light, camera.position))\n const { x, y, z } = light.glowColor\n\n glows.push({\n center: centre(light),\n size: light.glowSize,\n color: { x: f(x * level), y: f(y * level), z: f(z * level) },\n })\n }\n\n if (!isBlack(light.bulbColor))\n bulbs.push({ center: centre(light), size: light.bulbSize, color: light.bulbColor })\n }\n\n return [\n ...(glows.length ? [passDraw('shine', glows, right, up, shine)] : []),\n ...(bulbs.length ? [passDraw('bulb', bulbs, right, up, bulb)] : []),\n ]\n}\n","/**\n * A room's blob shadows: `DrawShadowLike` (`FLAppearance.cpp`, `src/flmaterials/`), the `efxshadow`\n * quad that `RoomControlDrawShadow` (`FUN_0044b370`) lays on the floor under a character, a ship or a\n * type-5 prop, just before the object draws. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport { setMapCount, VertexFormat, Primitive, type VMeshData } from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Draw } from './frame.js'\nimport type { Fog } from './nebula.js'\n\nexport interface RoomShadow {\n /**\n * A ship's or a type-5 prop's (`DrawFadingShadows`, slot 11): it fades and grows with height, and\n * takes its box. Else a character's (`DrawFixedShadows`, slot 12): a fixed size and darkness, under\n * a point just behind it.\n */\n fading: boolean\n /** `Float1C`, the floor's height: where the quad lies. A prop's is 0. */\n floor: number\n /** The instance's world, whose position it's under and whose Z axis turns it. */\n world: Matrix4\n /**\n * Fading only: the box `IRenderer::GetBounds` gives at 1.0 for the instance's archetype. Which part\n * of a compound answers is unread. Without it, as for an instance with no archetype, the\n * character's small box.\n */\n bounds?: { min: Vector3; max: Vector3 }\n}\n\n/** What `DrawShadowLike` hardcodes (`DAT_06704064..90`), and a mod can patch. */\nexport interface ShadowLimits {\n /** The small box: half its width in X and Z, and what a fixed shadow lifts its quad by. */\n extentX: number\n extentZ: number\n lift: number\n /** How far along its Z axis a fixed shadow sits: behind, as it's negative. */\n offset: number\n /** Above this height over the floor, no shadow; heights are fractions of it. */\n fadeRange: number\n /** A fading quad's scale: `fadeQuad × fade² + scaleBias`. */\n fadeQuad: number\n scaleBias: number\n /** A fading shadow's alpha is this less the fade, a fixed one's `fixedAlpha`; the colour's is its square. */\n fadeAlpha: number\n fixedAlpha: number\n}\n\nexport const RETAIL_SHADOW_LIMITS: Readonly<ShadowLimits> = {\n extentX: 0.28,\n extentZ: 0.24,\n lift: 0.05,\n offset: -0.1,\n fadeRange: 50,\n fadeQuad: 4,\n scaleBias: 0.8,\n fadeAlpha: 0.8,\n fixedAlpha: 0.6,\n}\n\n/** One quad: its corners, each `[x, y, z, u, v]`, and the vertex alpha, of 255. */\nexport interface ShadowQuad {\n corners: [number, number, number, number, number][]\n alpha: number\n}\n\nconst f = Math.fround\n\n/**\n * One shadow's quad, and the scale it leaves. `DAT_06704078` is a global that only a fading shadow\n * sets, so a fixed one takes whatever the last fading one left, in this frame or an earlier one.\n */\nexport const shadowQuad = (\n { fading, floor, world, bounds }: RoomShadow,\n scale: number,\n limits: ShadowLimits = RETAIL_SHADOW_LIMITS,\n): { quad?: ShadowQuad; scale: number } => {\n const { z: axis, w: position } = world\n let x = position.x\n let y = position.y\n let z = position.z\n // [max x, min x, max y, min y, max z, min z], as `GetBounds` writes it.\n let extents: number[]\n\n if (fading && bounds) {\n const { min, max } = bounds\n\n extents = [max.x, min.x, max.y, min.y, max.z, min.z]\n } else {\n const { extentX, extentZ, lift, offset } = limits\n\n extents = [f(extentX), f(-extentX), 0, f(lift), f(extentZ), f(-extentZ)]\n x = f(f(f(offset) * axis.x) + x)\n y = f(f(f(offset) * axis.y) + y)\n z = f(f(f(offset) * axis.z) + z)\n }\n\n // Slot 12's third flag: a fixed quad is lifted.\n const height = fading ? f(floor) : f(floor + extents[3]!)\n let fade = y - height\n if (fade < 0) fade = 0\n\n const range = f(limits.fadeRange)\n if (fade > range) return { scale }\n fade /= range\n if (fading) scale = f(fade * fade * f(limits.fadeQuad) + limits.scaleBias)\n\n let alpha = f(limits.fixedAlpha)\n\n if (fading) {\n alpha = f(limits.fadeAlpha) - fade\n if (alpha < 0) return { scale }\n if (alpha > 1) alpha = 1\n }\n\n if (!(alpha > 0)) return { scale }\n\n // Yaw of the instance's Z axis. Corners are centre ± A ± B in XZ, A = (hx, -hy) the width and\n // B = (zy, zx) the depth: perpendicular, both turned by the yaw and scaled.\n const angle = Math.atan2(axis.x, axis.z)\n const sin = Math.sin(angle) * scale\n const cos = Math.cos(angle) * scale\n // Each width is the whole box's, so the quad is twice its size.\n const widthX = extents[0]! - extents[1]!\n const widthZ = f(extents[4]! - extents[5]!)\n const centerX = f(0.5 * widthX + extents[1]! + x)\n const centerZ = f(widthZ * 0.5 + extents[5]! + z)\n const hx = f(widthX * cos)\n const hy = f(widthX * sin)\n const zx = f(widthZ * cos)\n const zy = f(widthZ * sin)\n const left = f(centerX - hx)\n const back = centerZ - hy\n\n return {\n scale,\n quad: {\n alpha: Math.trunc(alpha * alpha * 255),\n corners: [\n [f(left + zy), height, f(zx + hy + centerZ), 0, 0],\n [f(left - zy), height, f(hy + centerZ - zx), 0, 1],\n [f(hx + centerX - zy), height, f(back - zx), 1, 1],\n [f(zy + hx + centerX), height, f(f(back) + zx), 1, 0],\n ],\n },\n }\n}\n\n// XYZ, D3DCOLOR and one UV set: FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n// The expander's `(0, 1, 2)` then `(3, 0, 2)`.\nconst ORDER = [0, 1, 2, 3, 0, 2]\n\n/**\n * The quad as `DrawShadowLike` states it: lighting off, the texture times white at the quad's alpha,\n * blended, `LEQUAL`, no culling, no depth written, `ZBIAS` 4. The alpha test and fog are the device's\n * as the last object left them; the fog is passed, the test is taken as off: uncaptured.\n */\nexport const shadowDraw = ({ corners, alpha }: ShadowQuad, texture: Texture, fog?: Fog): Draw => {\n const vertices = new Uint8Array(ORDER.length * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n ORDER.forEach((corner, at) => {\n const [x, y, z, u, v] = corners[corner]!\n\n floats.set([x, y, z], (at * STRIDE) / 4)\n vertices.set([255, 255, 255, alpha], at * STRIDE + 12)\n floats.set([u, v], (at * STRIDE + 16) / 4)\n })\n\n const count = ORDER.length\n const mesh: VMeshData = {\n name: 'efxshadow',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n { materialId: 0, vertexStart: 0, vertexEnd: count - 1, elementCount: count, padding: 0 },\n ],\n indices: Uint16Array.from({ length: count }, (_, at) => at),\n vertices,\n }\n\n return {\n mesh,\n reference: {\n meshId: 0,\n vertexStart: 0,\n vertexCount: count,\n indexStart: 0,\n indexCount: count,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n },\n transient: true,\n byteOffset: 0,\n count,\n world: Matrix4.identity,\n materialName: 'efxshadow',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: { name: 'efxshadow', entry: texture, sampler: DEFAULT_SAMPLER, uvSet: 0 },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'lequal',\n depthBias: 4,\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'alpha',\n unlit: true,\n alphaReference: 0,\n alphaFunction: 'always',\n ...(fog && { fog }),\n }\n}\n","/**\n * A base room's frame as the game orders it: `RoomControlDraw` (`FUN_0044b570`), in\n * `src/freelancer/Client/room_control.cpp`. Pure, no GL. Objects draw by sort layer, each lit by its\n * light group's nearest four; the batcher holds their glass until every object has drawn.\n *\n * The glare light has no\n * place: retail sets `SetDirectionalLight`'s globals (`0x66fe1f0`) and nothing in any binary reads them.\n */\nimport type { Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport { collectEffect, type EffectDraw } from '#/alchemy/draw.js'\nimport { projectionMatrix, viewMatrix, type Camera, type Viewport } from './camera.js'\nimport {\n BLACK_BACKGROUND,\n collectModel,\n flushQueued,\n hooksOf,\n RETAIL_FRAME_LIMITS,\n type Draw,\n type Frame,\n type FrameLimits,\n type Queued,\n type SceneEffect,\n type SceneLight,\n type SceneModel,\n} from './frame.js'\nimport type { Fog } from './nebula.js'\nimport {\n FLASHLIGHTS_PER_SET,\n flashlightDraws,\n type FlashLight,\n type FlashlightTextures,\n} from './flashlight.js'\nimport {\n RETAIL_SHADOW_LIMITS,\n shadowDraw,\n shadowQuad,\n type RoomShadow,\n type ShadowLimits,\n} from './shadow.js'\n\n/** A THN `LIGHT` that's on, in world space. Its type is its shape: `SceneLight`'s. */\nexport interface RoomLight extends SceneLight {\n /** `LtGrp`: it lights only objects of its group. */\n group: number\n}\n\nexport interface RoomObject {\n /**\n * Its `render_type` (`ThornGetRenderType`) is the model's `sky`: 1 a starsphere, 2 a backdrop\n * (`FUN_0044af60`). A character's is always a model.\n */\n model: SceneModel\n /** The engine instance's position, which its lights are picked from. */\n position: Vector3\n /** `SrtGrp`, a signed byte: lower layers draw first. 0 when absent. */\n layer?: number\n /** `LtGrp`. 0 when absent, the `FRoomObject` default. */\n lightGroup?: number\n /** Slot 2. Drawn all the same when false, under black ambient (`FUN_0044ae80`). True when absent. */\n visible?: boolean\n /** Picks lights. Unlit, it has none, and the ambient alone. True when absent. */\n lit?: boolean\n /** The room's fog reaches it. True when absent. */\n fog?: boolean\n /**\n * The `SCENE` entity's `ambient` it takes in place of the room's, as written: 0 to 255. A\n * compound gets one only through its scene (`FThornCompound::SetScene`).\n */\n ambient?: Vector3\n /** Its own effects, a ship's flames, after every model, in its layer's turn. */\n effects?: readonly SceneEffect[]\n /** The shadow it casts, drawn just before it: a character's, a ship's with one, a type-5 prop's. */\n shadow?: RoomShadow\n /**\n * Its `always_on` `[Light]`s, in its translucent pass (slot 8), the first 32: a prop's with its\n * fourth THN flag set (`FObjectProp::DrawTranslucent`), a ship's (`FObjectShip::DrawTranslucent`).\n * The host steps and places them.\n */\n flashlights?: readonly FlashLight[]\n}\n\nexport interface RoomShadows {\n /** `efxshadow`, from `fx/efx.txm`. */\n texture: Texture\n /** What the last fading shadow left (`DAT_06704078`): the last frame's `shadowScale`. 1 at first. */\n scale?: number\n /** Over `RETAIL_SHADOW_LIMITS`, for a mod that patches them. */\n limits?: Partial<ShadowLimits>\n}\n\n/** A room's frame, and what its shadows leave for the next. */\nexport interface RoomFrame extends Frame {\n shadowScale: number\n}\n\nexport interface RoomScene {\n camera: Camera\n aspect: number\n /**\n * In pixels: a part covering under one isn't drawn (`FRoomCamera::ClassifySphere`'s rank 2). Every\n * part is sized as if the viewport were infinite when absent.\n */\n viewport?: Viewport\n /** The `SCENE` entity's `ambient`, as written: 0 to 255 (`RoomData`, `+0xd8`). White when absent. */\n ambient?: Vector3\n /**\n * Every THN light that's on, in the order the script registered them (`DAT_0066d130`). A room's own\n * list (`+0xe4`) is never filled in retail, nor is its single-light mode ever set (`+0x4fc`).\n */\n lights: readonly RoomLight[]\n /** In the order they were made, which is the order within a layer (`DAT_00679a10`). */\n objects: readonly RoomObject[]\n /**\n * The `SCENE`'s fog, when it's on and the effects and nebula options are (`GfFogIsActive`). Its\n * `fogtable` N asks D3D for vertex fog, which here is per pixel all the same: uncaptured.\n */\n fog?: Fog\n /**\n * With the shadows option, `shadow_glare` and the room's `ShadowLight` all on (`FUN_0044b370`). No\n * shadows when absent.\n */\n shadows?: RoomShadows\n /**\n * The room's own, from its `[FlashlightSet]`s and `[FlashlightLine]`s, after every object's, all\n * of them, with the effects and flashlights options on. The host steps them (`FRoomRuntime::Update`).\n */\n flashlights?: readonly FlashLight[]\n /** `shine` and `bulb`, which any flashlight needs to draw. */\n flashlightTextures?: FlashlightTextures\n /** The scripts' `PSYS`es, sequence by sequence, after every object's (`FUN_00456740`). */\n effects?: readonly SceneEffect[]\n background?: Vector3\n time?: number\n limits?: Partial<FrameLimits>\n}\n\n/** `FUN_00557170`'s cap, through `GfLightsApplyNearest` (`FUN_005572b0`). */\nexport const ROOM_LIGHTS_PER_OBJECT = 4\n\nconst f = Math.fround\nconst WHITE: Vector3 = { x: 255, y: 255, z: 255 }\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\n/**\n * `GfLightScore` (`FUN_005586f0`): 3 for a directional light, else 2 less its distance squared over\n * its range squared, a spot outside its half cone taking the angle's cosine for the 2. Undefined for\n * no range at all, which isn't picked.\n */\nexport const lightScore = (light: SceneLight, position: Vector3): number | undefined => {\n if (!light.position) return 3\n\n const range = light.range ?? 0\n const rangeSq = range * range\n if (rangeSq === 0) return undefined\n\n // dx and dy stored as floats, dz kept wide and squared against its float.\n const dx = f(position.x - light.position.x)\n const dy = f(position.y - light.position.y)\n const dzWide = position.z - light.position.z\n const dz = f(dzWide)\n const distSq = dzWide * dz + dx * dx + dy * dy\n let base = 2\n\n if (light.spot && !(distSq < 1e-5)) {\n const { x, y, z } = light.direction\n const cos = (z * dz + y * dy + dx * x) / Math.sqrt(distSq)\n if (!(cos > Math.cos(f(light.spot.phi) * 0.5))) base = f(cos)\n }\n\n return f(base - distSq / rangeSq)\n}\n\n/**\n * `GfLightsSelectNearest` (`FUN_00557170`) and `EngineLightApplyList`: the group's lights, highest\n * score first, a later one before an equal one, cut to four, and then any under a byte's worth left off.\n */\nexport const pickRoomLights = (\n lights: readonly RoomLight[],\n position: Vector3,\n group: number,\n): SceneLight[] => {\n const picked: { light: RoomLight; score: number }[] = []\n\n for (const light of lights) {\n if (light.group !== group) continue\n\n const score = lightScore(light, position)\n if (score === undefined) continue\n\n let slot = 0\n\n while (slot < picked.length && score < picked[slot]!.score) slot++\n picked.splice(slot, 0, { light, score })\n }\n\n // No light is skipped for a black diffuse. `EngineLightApplyNearby`'s 1/255 test on the colour runs\n // only for a light without a D3D light, and `EngineLightSetLight` gives every room light one (flag\n // 0x20). So an ambient-only light still adds its ambient, as `li01_01_bar`'s\n // `ambi_LtG09_SET_Amb_Drct` does to the set (captured in `s004x_bar`).\n return picked.slice(0, ROOM_LIGHTS_PER_OBJECT).map(({ light: { group: _, ...light } }) => light)\n}\n\n// `AmbientChannel`, then `GfSetSceneAmbient` (`FUN_00556f20`): the int over 255 as a float, then\n// rounded back to a byte, of which only the low one's kept. `EngineLightApplyList` reads it back\n// unchanged, as every byte survives the trip.\nconst ambientByte = (value: number): number =>\n (Math.floor(f(value * (1 / 255)) * 255 + 0.5) & 0xff) / 255\n\nconst ambientOf = ({ x, y, z }: Vector3): Vector3 => ({\n x: ambientByte(x),\n y: ambientByte(y),\n z: ambientByte(z),\n})\n\n/** What one object is lit by: `FUN_0044ae80`, with the lighting option on. */\nexport const lightRoomObject = (\n { lights, ambient = WHITE, fog }: Pick<RoomScene, 'lights' | 'ambient' | 'fog'>,\n object: RoomObject,\n): { lights: SceneLight[]; ambient: Vector3; fog?: Fog } => ({\n lights:\n object.lit === false ? [] : pickRoomLights(lights, object.position, object.lightGroup ?? 0),\n ambient: ambientOf(object.visible === false ? BLACK : (object.ambient ?? ambient)),\n ...(fog && object.fog !== false && { fog }),\n})\n\n// The layer byte, signed: `FUN_0044c520` orders the set with `SETL`.\nconst signedLayer = ({ layer = 0 }: RoomObject): number => (layer << 24) >> 24\n\nconst layersOf = (objects: readonly RoomObject[]): number[] =>\n [...new Set(objects.map(signedLayer))].sort((a, b) => a - b)\n\nexport const collectRoomFrame = (scene: RoomScene): RoomFrame => {\n const { camera, aspect, objects, background, time = 0, effects = [], limits, shadows } = scene\n const shadowLimits = { ...RETAIL_SHADOW_LIMITS, ...shadows?.limits }\n let shadowScale = shadows?.scale ?? 1\n // `GfFogApply`, then each object's `FUN_0044ae80`: a shadow draws under what the last one left.\n let deviceFog = scene.fog\n const resolved = { ...RETAIL_FRAME_LIMITS, ...limits }\n const draws: Draw[] = []\n const unsupported = new Set<string>()\n const unregistered = new Set<string>()\n const view = viewMatrix(camera)\n const queued: Queued[] = []\n const layers = layersOf(objects)\n\n // Slot 7, layer by layer. A queued record relights its object as the batcher flushes it\n // (`FRoomBatcherSink::BeginRecord`), so its draws keep the object's lighting.\n for (const layer of layers)\n for (const object of objects) {\n if (signedLayer(object) !== layer) continue\n\n if (shadows && object.shadow) {\n const { quad, scale } = shadowQuad(object.shadow, shadowScale, shadowLimits)\n\n shadowScale = scale\n if (quad) draws.push(shadowDraw(quad, shadows.texture, deviceFog))\n }\n\n const own: Draw[] = []\n const held: Queued[] = []\n\n collectModel(\n object.model,\n camera,\n aspect,\n view,\n time,\n own,\n held,\n unsupported,\n unregistered,\n resolved,\n false,\n scene.viewport,\n )\n\n const lit = lightRoomObject(scene, object)\n\n deviceFog = lit.fog\n\n const relit = (draw: Draw): Draw => ({\n ...draw,\n lights: lit.lights,\n // A sky's white and an exclusion zone's are their own.\n sceneAmbient: draw.sceneAmbient ?? lit.ambient,\n ...(lit.fog && { fog: lit.fog }),\n })\n\n draws.push(...own.map(relit))\n for (const queue of held) queued.push({ ...queue, draws: queue.draws.map(relit) })\n }\n\n // `RoomBatcherEnd`: one flush, after every object (`ku_dragon_pair`).\n flushQueued(queued, draws)\n\n // Slot 8 by layer, then the room's own (`DrawFlashlightFlares`).\n const textures = scene.flashlightTextures\n\n if (textures) {\n for (const layer of layers)\n for (const object of objects)\n if (signedLayer(object) === layer && object.flashlights)\n draws.push(\n ...flashlightDraws(object.flashlights.slice(0, FLASHLIGHTS_PER_SET), camera, textures),\n )\n\n if (scene.flashlights) draws.push(...flashlightDraws(scene.flashlights, camera, textures))\n }\n\n // Slot 9 by layer, then the scripts' cue list, under white ambient and no lights. The fog is\n // whatever the last object left, which no effect is known to read: uncaptured.\n const effectDraws: EffectDraw[] = []\n const collect = ({ instance, texture, visible }: SceneEffect) =>\n collectEffect(instance, view, texture, effectDraws, unsupported, visible)\n\n for (const layer of layers)\n for (const object of objects)\n if (signedLayer(object) === layer) object.effects?.forEach(collect)\n\n effects.forEach(collect)\n\n return {\n background: background ?? BLACK_BACKGROUND,\n hooks: hooksOf(draws),\n view,\n projection: projectionMatrix(camera, aspect),\n ambient: { x: 1, y: 1, z: 1 },\n lights: [],\n draws,\n effects: effectDraws,\n unsupported: [...unsupported],\n unregistered: [...unregistered],\n shadowScale,\n }\n}\n","/**\n * Space dust: up to three effects held 60 ahead of the camera. The system's `[Dust]`, the dust of\n * the smallest zone around that point, and the zone's before it, fading. `SpaceDust`\n * (`src/freelancer/Client/space_dust.cpp`, `FUN_0054beb0`), and what `FParticleEffect` does with\n * them as the effect walk steps them (`particle_effect.cpp`). The host starts an effect by name.\n * The streaks are `FLDustAppearance`'s, in `#/alchemy`. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport { viewMatrix, type Camera } from './camera.js'\nimport type { EffectView } from './effect-view.js'\nimport { immersion, type Zone } from './nebula.js'\nimport type { SpaceEffect } from './space.js'\n\nconst f = Math.fround\n\n/** A zone with a `spacedust`, which sets its `0x200000` property. */\nexport interface DustZone {\n zone: Zone\n /** Its `edge_fraction`, 0 when absent. */\n edgeFraction?: number\n /** `spacedust`: an `[Effect]` nickname. Empty as written empty. */\n dust: string\n /** `spacedust_maxparticles`, 0 when absent, which takes 50. */\n maxParticles?: number\n}\n\n/** A started dust effect: what a `SpaceEffect` is but where it is. */\nexport type DustEffect = Omit<SpaceEffect, 'position' | 'watched'>\n\n/** The options `SpaceDustUpdate` reads. */\nexport interface DustOptions {\n /** `space_dust_detail` from `PerfOptions.ini`, 1 when absent (`DAT_00614080`). */\n detail?: number\n /** Game option `0x19`, on when absent. Off, each frame drops every dust effect first. */\n background?: boolean\n /** Each effect type's `run_time`, by index: how long a killed one winds down. -1 when absent. */\n runTimes?: readonly (number | undefined)[]\n}\n\n/** `SpaceDustUpdate`'s numbers, which a mod can patch. */\nexport interface DustLimits {\n /** `DAT_00614084`: the dust's frame, along the camera's Z. */\n offset: number\n /** `DAT_005c8930`: zone dust runs only above this detail. */\n detailThreshold: number\n /** `DAT_005d3e94`: a zone dust's intensity for each of its particles. */\n intensityPerParticle: number\n /** `0x54c013`: a zone's particles when it writes none. */\n defaultZoneParticles: number\n /** `DAT_005c75f0`: a fading dust at or under this intensity is killed. */\n fadeCutoff: number\n /** `FUN_0054bde0`: the system dust's particles at full and at no detail. */\n systemParticles: { full: number; none: number }\n /** `DAT_005e08f8`: the system dust's intensity for each of those. */\n systemIntensityPerParticle: number\n /** `SpaceEffectsDrawFrame` (`0x4f7600`): the most one walk steps an effect by. */\n maxStep: number\n}\n\nexport const RETAIL_DUST_LIMITS: Readonly<DustLimits> = {\n offset: -60,\n detailThreshold: f(0.75),\n intensityPerParticle: f(0.002),\n defaultZoneParticles: 50,\n fadeCutoff: 1e-5,\n systemParticles: { full: 80, none: 30 },\n systemIntensityPerParticle: 0.002,\n maxStep: f(0.1),\n}\n\n/** One `FParticleEffect` the dust holds, or held. */\ninterface Held {\n effect: DustEffect\n /** `LocalXform` as last placed: none until the first. */\n placement?: DustFrame\n /** `SetIntensity`'s, held to [0, 1]: its `sparam`. */\n intensity: number\n /** In its type's walk (`EffectTypeListLink`), which only placing or killing does. */\n linked: boolean\n /** `Flags08` bit 2: it's left the walk, or will at its next. */\n dead: boolean\n /** `+0x78`: under 0 it lasts; killed, 1 at most, and counted down as it's walked. */\n runTime: number\n /** The `ALCHEMY_LOD` blend its last view gave. */\n lod: number\n /** When it was linked: a type's walk is newest first. */\n serial: number\n}\n\n/** A dust effect in the frame's walk, and when it joined it. */\nexport interface DustEffectAt {\n effect: SpaceEffect\n serial: number\n}\n\nlet linkedSoFar = 0\n\n/** Where the dust is: its world, and its point. */\nexport interface DustFrame {\n world: Matrix4\n position: Vector3\n}\n\n/**\n * `GetSmallestZoneWithPropertiesAt(point, 0x200000)` (`0x633b620`): the zone with the least\n * `GetRadius` that holds the point, the first of equals. Retail asks its zone tree, whose order\n * isn't read; this takes the order given, so only equal radii can differ.\n */\nexport const smallestDustZone = (\n zones: readonly DustZone[],\n point: Vector3,\n): DustZone | undefined => {\n let best: DustZone | undefined\n let least = 1e20\n\n for (const candidate of zones) {\n const { radius } = candidate.zone\n if (!(radius < least) || !candidate.zone.holds(point)) continue\n best = candidate\n least = radius\n }\n\n return best\n}\n\n/** Dead, and its instance released: out of the walk, its share of the pools given back. */\nconst end = (held: Held): void => {\n held.dead = true\n held.effect.instance.release()\n}\n\nexport class SpaceDust {\n /** `[Dust] spacedust`, empty when the system has none. */\n readonly system: string\n /** Starts the `[Effect]` of a nickname: none when there's no such archetype. */\n readonly start: (name: string) => DustEffect | undefined\n readonly limits: Readonly<DustLimits>\n #system: Held | undefined\n /** `DAT_006797b8`'s particles at full and at no detail: 80 and 30 once a `[Dust]` is read. */\n #systemParticles: { full: number; none: number }\n /** `DAT_00679790`: the zone dust's name, compared as the string cache interns it. */\n #zoneName = ''\n #zone: Held | undefined\n #zoneParticles = 0\n #fading: Held | undefined\n #fadingParticles = 0\n /** Killed, and winding down where they were last placed. */\n #ending: Held[] = []\n\n /**\n * `FUN_0054bde0`, from `StarSysLoadIni`'s `[Dust]`: a system with no such section passes none, and\n * its particles stay 0.\n */\n constructor(\n system: string | undefined,\n start: (name: string) => DustEffect | undefined,\n limits: Partial<DustLimits> = {},\n ) {\n this.system = system ?? ''\n this.start = start\n this.limits = { ...RETAIL_DUST_LIMITS, ...limits }\n this.#systemParticles =\n system === undefined ? { full: 0, none: 0 } : { ...this.limits.systemParticles }\n }\n\n /** `ParticleEffect::Start`: nothing to hold when there's no archetype. */\n #create(name: string, runTimes: DustOptions['runTimes']): Held | undefined {\n const effect = this.start(name)\n if (!effect) return undefined\n return {\n effect,\n intensity: 0,\n linked: false,\n dead: false,\n runTime: runTimes?.[effect.type] ?? -1,\n lod: 1,\n serial: 0,\n }\n }\n\n /**\n * `FUN_0054bdc0` and `FParticleEffect::Kill` (`0x4f84d0`): its emitters stop, its run time is held\n * to 1, and it's linked if it wasn't, to end in the walk. One never placed has made nothing, and\n * goes at once.\n */\n #kill(held: Held | undefined): void {\n if (!held || held.dead) return\n if (!held.placement) return end(held)\n held.effect.instance.stop()\n if (held.runTime < 0 || held.runTime > 1) held.runTime = 1\n this.#link(held)\n this.#ending.push(held)\n }\n\n /** `EffectTypeListLink` (`0x4f7af0`): pushed to its type's front, unless linked or dead. */\n #link(held: Held): void {\n if (held.linked || held.dead) return\n held.linked = true\n held.serial = ++linkedSoFar\n }\n\n /** `PlaceDustEffect`: at the dust's frame, at an intensity held to [0, 1], and linked. */\n #place(held: Held, placement: DustFrame, intensity: number): void {\n held.placement = placement\n held.intensity = intensity < 0 ? 0 : intensity > 1 ? 1 : intensity\n this.#link(held)\n }\n\n #dropZones(): void {\n this.#kill(this.#fading)\n this.#fading = undefined\n this.#kill(this.#zone)\n this.#zone = undefined\n this.#zoneName = ''\n this.#zoneParticles = 0\n this.#fadingParticles = 0\n }\n\n /** Every effect it holds, released at once: for a host done with this dust. */\n release(): void {\n for (const held of [this.#system, this.#zone, this.#fading, ...this.#ending])\n if (held && !held.dead) end(held)\n\n this.#system = this.#zone = this.#fading = undefined\n this.#ending = []\n }\n\n /**\n * The dust's frame: the camera's, `offset` along its Z (`FUN_0054c320`). That axis is the\n * orientation's third column, `(x.z, y.z, z.z)`.\n */\n frame({ position, orientation }: Camera): DustFrame {\n const along = this.limits.offset\n const point = {\n x: f(f(orientation.x.z * along) + position.x),\n y: f(f(orientation.y.z * along) + position.y),\n z: f(f(orientation.z.z * along) + position.z),\n }\n\n return { world: Matrix4.fromRotationTranslation(orientation, point), position: point }\n }\n\n /**\n * `SpaceDustUpdate` (`FUN_0054beb0`) from `StarSysUpdate`, then each linked effect stepped as the\n * walk does, by at most `maxStep`. Zone dust runs only above the detail threshold: the zone is the\n * smallest of `zones` that holds the dust's point, its intensity its particles over 500 times\n * its immersion there. A new name hands the old effect to the fading slot, which runs at the\n * rest of that immersion until it's under `fadeCutoff`. The system's dust starts on the first\n * update and is placed from the next, at 80 particles over 500, or toward 30 as detail falls.\n */\n update(\n camera: Camera,\n step: number,\n zones: readonly DustZone[],\n { detail = 1, background = true, runTimes }: DustOptions = {},\n ): void {\n const limits = this.limits\n\n // No early return: what's dropped is started again below, each frame (`0x54becb`).\n if (!background && (this.#system || this.#zone || this.#fading)) {\n this.#dropZones()\n this.#kill(this.#system)\n this.#system = undefined\n }\n\n const placement = this.frame(camera)\n const point = placement.position\n\n if (detail > limits.detailThreshold) {\n const found = smallestDustZone(zones, point)\n const name = found?.dust ?? ''\n const particles = found ? found.maxParticles || limits.defaultZoneParticles : 0\n const blend = found ? f(immersion(found.zone, found.edgeFraction ?? 0, point)) : 1\n\n // `StringAlloc` interns without case, so the pointers compare that way.\n if (name.toLowerCase() !== this.#zoneName.toLowerCase()) {\n this.#zoneName = name\n this.#kill(this.#fading)\n this.#fading = this.#zone\n this.#fadingParticles = this.#zoneParticles\n this.#zone = name ? this.#create(name, runTimes) : undefined\n }\n\n this.#zoneParticles = particles\n\n if (this.#fading) {\n const fade = this.#fadingParticles * limits.intensityPerParticle * (1 - blend)\n\n if (!(fade <= limits.fadeCutoff)) this.#place(this.#fading, placement, f(fade))\n else {\n this.#kill(this.#fading)\n this.#fading = undefined\n }\n }\n\n if (this.#zone) {\n const level = this.#zoneParticles * limits.intensityPerParticle * blend\n\n this.#place(this.#zone, placement, f(level))\n }\n } else this.#dropZones()\n\n if (this.#system) {\n const { full, none } = this.#systemParticles\n const level = ((1 - detail) * none + full * detail) * limits.systemIntensityPerParticle\n\n this.#place(this.#system, placement, f(level))\n } else if (this.system) this.#system = this.#create(this.system, runTimes)\n\n this.#run(camera, step)\n }\n\n /** Every effect held or ending, linked and alive. */\n #walked(): Held[] {\n const held = [this.#fading, this.#zone, this.#system, ...this.#ending]\n\n return held.filter((each): each is Held => !!each && each.linked && !each.dead)\n }\n\n /**\n * `FParticleEffect::TickDraw` (`0x4f8a20`): a run time above 0 counts down, and at or under 0\n * the effect ends unstepped. Otherwise it steps where it was placed, and ends once its effect\n * has (`IsAlive`).\n */\n #run(camera: Camera, step: number): void {\n const dt = step > this.limits.maxStep ? this.limits.maxStep : step\n const view = viewMatrix(camera)\n\n for (const held of this.#walked()) {\n if (held.runTime > 0) {\n held.runTime = f(held.runTime - dt)\n\n if (held.runTime <= 0) {\n end(held)\n continue\n }\n }\n\n held.effect.instance.advance(dt, {\n sparam: held.intensity,\n lod: held.lod,\n ...(held.placement && { placement: held.placement.world }),\n view,\n })\n if (held.effect.instance.finished) end(held)\n }\n\n this.#ending = this.#ending.filter(({ dead }) => !dead)\n }\n\n /** The effects for the frame's walk, newest linked first, each where it was last placed. */\n effects(): DustEffectAt[] {\n return this.#walked()\n .sort((a, b) => b.serial - a.serial)\n .map((held) => ({\n effect: {\n ...held.effect,\n ...(held.placement && { position: held.placement.position }),\n },\n serial: held.serial,\n }))\n }\n\n /**\n * What the frame's view test made of `effects()`, in its order. Unseen and not\n * `EXIST_OFFSCREEN`, an effect is frozen and dead, and isn't placed again (`0x4f789f`).\n */\n viewed(views: readonly (EffectView | undefined)[]): void {\n this.#walked()\n .sort((a, b) => b.serial - a.serial)\n .forEach((held, at) => {\n const view = views[at]\n if (!view) return\n held.lod = view.lod\n if (view.fate === 'die') end(held)\n })\n this.#ending = this.#ending.filter(({ dead }) => !dead)\n }\n}\n","/**\n * An asteroid field's `[AsteroidBillboards]`: flat rocks scattered in a sphere ahead of the camera,\n * each a triangle facing it, beyond the field's cubes. `BillboardEnsureRocks` (`FUN_0054de10`) and\n * `BillboardDraw` (`FUN_0054e900`) with its lighting (`FUN_0054e130`) and emission (`FUN_0054f9f0`),\n * in `src/freelancer/Client/asteroid_billboard.cpp` and `cli_asteroid.cpp`. Each rock's size, flips\n * and place are the game's `rand()`, so a run matches retail in kind. Pure, no GL.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport { outsideSquared, type CubeExclusion } from './asteroids.js'\nimport type { Camera } from './camera.js'\nimport type { Draw, SceneLight } from './frame.js'\nimport type { Random } from './lightning.js'\nimport type { Fog } from './nebula.js'\nimport { immersion, type Zone } from './nebula.js'\nimport type { TextureShape } from './ring.js'\nimport { insideSphere, inverseRoot, onSphere, RAND_UNIT } from './retail.js'\n\nconst f = Math.fround\n\n/** An `[AsteroidBillboards]` section, over the field's constructor defaults. The host reads it. */\nexport interface BillboardSettings {\n /** `shape`. None draws nothing. */\n shape?: TextureShape\n /** `count`, truncated, 100 when absent. */\n count?: number\n /**\n * `size`, ordered least first: a rock is between the two. When absent the constructor's 500 then\n * 100, unordered, so rocks run from 500 down to 100.\n */\n size?: readonly [number, number]\n /** `start_dist`, 1500 when absent: how far ahead the rocks begin. */\n startDistance?: number\n /** `fade_dist_percent`, held to [0, 1], 0.3 when absent: how much of the sphere fades. */\n fadePercent?: number\n /** `ambient_intensity`, 1 when absent. */\n ambientIntensity?: number\n /** `color_shift`, 1 each when absent. */\n colorShift?: Vector3\n}\n\n/** What a field gives its billboards. */\nexport interface BillboardField {\n zone: Zone\n edgeFraction?: number\n /** `fill_dist`, truncated, and the `Asteroids` option's reach, `(1 - d) · 0.65 + d`. */\n fillDistance: number\n detailScale?: number\n cubeSize: number\n /** The field's colours: `diffuse_color` and `ambient_color` over 255. */\n diffuse: Vector3\n ambient: Vector3\n /** Its exclusion zones; with none, retail has no manager, and every rock stands. */\n exclusions?: readonly CubeExclusion[]\n}\n\n/** What the frame lights the billboards with at the camera, after the field's ambient pass. */\nexport interface BillboardLighting {\n /** `D3DRS_AMBIENT` as the pass left it: whole bytes, 0 to 1. */\n ambient: Vector3\n /** Up to four directional lights there, each the way it shines (`directionalLightsAt`). */\n lights: readonly SceneLight[]\n /** The `LIGHTING` option: off, the rocks are the tinted diffuse. On when absent. */\n lit?: boolean\n /** What the ambient pass left on: the field's nebula's fog. */\n fog?: Fog\n}\n\ninterface Rock {\n position: Vector3\n half: number\n alpha: number\n visible: boolean\n flipU: boolean\n flipV: boolean\n swap: boolean\n negate: boolean\n /** Its index over the count: rocks past a zone's density are left out. */\n phase: number\n}\n\n// `DAT_005e0b00`: 35°, as a float.\nconst TAN = Math.tan(0.6108652353286743)\n\n// XYZ, D3DCOLOR and one UV set: FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\nconst clampOne = ({ x, y, z }: Vector3): Vector3 => ({\n x: x < 1 ? x : 1,\n y: y < 1 ? y : 1,\n z: z < 1 ? z : 1,\n})\n\n// The colour `FUN_0054f9f0` packs: each times 255, truncated, alpha unmasked, the rest a byte.\nconst bytesOf = (alpha: number, { x, y, z }: Vector3): number[] => [\n Math.trunc(z * 255) & 0xff,\n Math.trunc(y * 255) & 0xff,\n Math.trunc(x * 255) & 0xff,\n Math.trunc(alpha * 255) & 0xff,\n]\n\nexport class AsteroidBillboards {\n readonly settings: BillboardSettings\n readonly field: BillboardField\n readonly random: Random\n #rocks: Rock[] = []\n /** `Float00`: the rocks' sphere. */\n readonly radius: number\n /** `Float04`: how far ahead its centre is. */\n readonly ahead: number\n /** `Float2C`: how much of it fades, short of the centre's depth. */\n readonly fade: number\n /** `Float40` and `Float44`: nearer than the first a rock fades, gone by the second. */\n readonly nearFade: readonly [number, number]\n /** `DensityScale`: with no zone's density, rocks past it are left out. */\n readonly density: number\n /** Each exclusion zone's `billboard_count` over the count. */\n readonly #densities: readonly (number | undefined)[]\n readonly #diffuse: Vector3\n readonly #ambient: Vector3\n /** Kept between frames, as `Up` is on the block. */\n #up: Vector3 = { x: 0, y: 1, z: 0 }\n\n constructor(\n settings: BillboardSettings,\n field: BillboardField,\n {\n random = () => Math.floor(Math.random() * 0x8000),\n detail = 1,\n }: { random?: Random; detail?: number } = {},\n ) {\n this.settings = settings\n this.field = field\n this.random = random\n\n // `BillboardSetQuality`: the count and the start scaled by detail.\n const qualityA = f((1 - detail) * 0.25 + detail)\n const square = detail * detail\n const qualityB = f((1 - square) * 0.75 + square)\n\n // Load raises the count to the largest exclusion zone's, and each zone's count over that.\n const exclusions = field.exclusions ?? []\n let count = Math.trunc(settings.count ?? 100)\n let density = 1\n const counts = exclusions.map(({ billboardCount }) =>\n billboardCount === undefined ? undefined : Math.trunc(billboardCount),\n )\n\n if (exclusions.length) {\n const most = Math.max(\n -1,\n ...counts.map((value) => (value !== undefined && value > 0 ? value : -1)),\n )\n const used = Math.max(count, most)\n\n density = f(count / used)\n count = used\n }\n\n this.density = density\n\n const inverse = f(1 / count)\n\n this.#densities = counts.map((value) =>\n value !== undefined && value > 0 ? f(value * inverse) : value,\n )\n\n const [low, high] = settings.size ?? [500, 100]\n const range = f(high - low)\n const rockCount = Math.trunc(count * qualityA)\n const step = f(1 / rockCount)\n const coin = () => random() * RAND_UNIT > 0.5\n\n for (let index = 0; index < rockCount; index++) {\n const half = f((random() * range * RAND_UNIT + low) * 0.5)\n\n this.#rocks.push({\n position: BLACK,\n half,\n alpha: 1,\n visible: true,\n flipU: coin(),\n flipV: coin(),\n swap: coin(),\n negate: coin(),\n phase: f(index * step),\n })\n }\n\n const start = settings.startDistance ?? 1500\n const percent = Math.min(Math.max(settings.fadePercent ?? 0.3, 0), 1)\n\n // A sphere whose near edge is `a` ahead and whose radius is `TAN` of its centre's distance.\n if (start > 0) {\n const a = qualityB * start\n const r = (a * TAN) / (1 - TAN)\n\n this.radius = f(r)\n this.ahead = f(r + a)\n this.fade = f(r * f(percent))\n } else {\n this.radius = 2500\n this.ahead = 4000\n this.fade = 700\n }\n\n // `BillboardSetFadePlanes`: from the cubes' reach to a cube and a quarter past it.\n const fill = f(Math.trunc(field.fillDistance) * (field.detailScale ?? 1))\n const far = f(field.cubeSize * 1.25 + fill)\n\n this.nearFade = fill < far ? [far, fill] : [fill, far]\n\n // `BillboardApplyTints`.\n const shift = settings.colorShift ?? { x: 1, y: 1, z: 1 }\n\n this.#diffuse = clampOne({\n x: f(shift.x * field.diffuse.x),\n y: f(shift.y * field.diffuse.y),\n z: f(shift.z * field.diffuse.z),\n })\n this.#ambient = clampOne(field.ambient)\n }\n\n get rocks(): readonly Readonly<Rock>[] {\n return this.#rocks\n }\n\n /**\n * `BillboardNearCamera` (`FUN_0054e040`): whether the camera is within the sphere's reach, a\n * quarter past it, of the field's surface.\n */\n near(eye: Vector3): boolean {\n const { zone } = this.field\n const margin = f((this.ahead + this.radius) * 1.25)\n const d = {\n x: f(eye.x - zone.position.x),\n y: f(eye.y - zone.position.y),\n z: f(eye.z - zone.position.z),\n }\n const reach = zone.radius + margin\n const squared = d.x * d.x + d.z * d.z + d.y * d.y\n if (squared > reach * reach) return false\n\n const distance = f(Math.sqrt(f(squared)))\n const inverse = 1 / distance\n const along = zone.radiusAlong({\n x: f(d.x * inverse),\n y: f(d.y * inverse),\n z: f(d.z * inverse),\n })\n\n return distance - along <= margin\n }\n\n /**\n * `is_billboard_excluded` over the zones nearest the camera first: a zone excluding billboards\n * that holds the point leaves it out; else the first with a count holding it gives its density.\n */\n #excluded(order: readonly number[], point: Vector3): { out: boolean; density?: number } {\n const exclusions = this.field.exclusions ?? []\n let density: number | undefined\n\n for (const at of order) {\n const exclusion = exclusions[at]!\n const inside = immersion(exclusion.zone, exclusion.edgeFraction ?? 0, point) !== 0\n\n if (exclusion.excludeBillboards) {\n if (inside) return { out: true }\n continue\n }\n\n const value = this.#densities[at]\n if (density !== undefined || !(value !== undefined && value > 0)) continue\n if (inside) density = value\n }\n\n return { out: false, ...(density !== undefined && { density }) }\n }\n\n /** Whether a rock placed at its position stands: in the field, and not excluded or thinned. */\n #stands(rock: Rock, order: readonly number[] | undefined): boolean {\n const { zone, edgeFraction = 0 } = this.field\n if (immersion(zone, edgeFraction, rock.position) === 0) return false\n if (!order) return true\n\n const { out, density } = this.#excluded(order, rock.position)\n if (out) return false\n return !(rock.phase > (density !== undefined && density > 0 ? density : this.density))\n }\n\n /**\n * `BillboardDraw`: the rocks placed afresh in the sphere on a cut, or those that left it on its\n * surface; faded toward its edge, more narrowly past its centre, and near the cubes' reach.\n * Opaque rocks draw first, `ALPHAREF` 128 and no blending, then the faded ones blended with no\n * depth writes, `ALPHAREF` 5. Each a triangle facing the camera, its base on the right or the up,\n * lit at its corners from the camera's light. Nothing when the camera is far from the field.\n */\n draw(camera: Camera, lighting: BillboardLighting, cut = false): Draw[] {\n const shape = this.settings.shape\n const eye = camera.position\n if (!this.near(eye)) return []\n\n const { forward, right, up, centre } = this.#axes(camera)\n\n this.#up = up\n\n const colours = this.#colours(lighting, forward, right, up)\n\n if (!shape) return []\n\n const radiusSquared = this.radius * this.radius\n const exclusions = this.field.exclusions ?? []\n const order = exclusions.length\n ? exclusions\n .map((exclusion, at) => ({ at, key: outsideSquared(exclusion, eye) }))\n .sort((a, b) => a.key - b.key)\n .map(({ at }) => at)\n : undefined\n const { random } = this\n\n const away = (rock: Rock) => {\n const dx = rock.position.x - centre.x\n const dy = rock.position.y - centre.y\n const dz = rock.position.z - centre.z\n\n return dx * dx + dz * dz + dy * dy\n }\n\n for (const rock of this.#rocks) {\n let squared: number\n\n if (cut) {\n const offset = insideSphere(random, this.radius)\n\n rock.position = {\n x: f(centre.x + offset.x),\n y: f(centre.y + offset.y),\n z: f(centre.z + offset.z),\n }\n rock.visible = this.#stands(rock, order)\n if (!rock.visible) continue\n squared = away(rock)\n } else {\n squared = away(rock)\n\n if (squared > radiusSquared + 10) {\n // Back on the sphere's surface, unseen this frame.\n const on = onSphere(random)\n\n rock.position = {\n x: f(this.radius * on.x + centre.x),\n y: f(this.radius * on.y + centre.y),\n z: f(f(this.radius * on.z) + centre.z),\n }\n rock.alpha = 0\n rock.visible = this.#stands(rock, order)\n continue\n }\n }\n\n if (!rock.visible) continue\n\n rock.alpha = this.#fade(rock.position, squared, eye, forward)\n }\n\n const first = this.#rocks[0]\n\n const emit = (rocks: Rock[]) => {\n const vertices = new Uint8Array(rocks.length * 3 * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n rocks.forEach((rock, at) => {\n const size = f(rock.half + rock.half)\n const r = { x: f(right.x * size), y: f(right.y * size), z: f(right.z * size) }\n const u = { x: f(up.x * size), y: f(up.y * size), z: f(up.z * size) }\n // The base's UVs by its flips.\n const corner = Number(rock.flipU) + Number(rock.flipV) * 2\n const [u0, v0, u1, v1] =\n corner === 0\n ? [0, 0, 1, 0]\n : corner === 1\n ? [1, 0, 1, 1]\n : corner === 2\n ? [1, 1, 0, 1]\n : [0, 1, 0, 0]\n const a = rock.swap ? r : u\n let b = rock.swap ? u : r\n if (rock.negate) b = { x: -b.x, y: -b.y, z: -b.z }\n\n const p = rock.position\n // Retail picks the corner colour by rock 0's U flip and this rock's V flip.\n const pick = Number(first!.flipU) + Number(rock.flipV) * 2\n const cornerColour = colours.corners[pick]!\n const triangle: [Vector3, [number, number], Vector3][] = [\n [{ x: f(p.x - a.x), y: f(p.y - a.y), z: f(p.z - a.z) }, [u0!, v0!], cornerColour],\n [{ x: f(a.x + p.x), y: f(a.y + p.y), z: f(a.z + p.z) }, [u1!, v1!], cornerColour],\n [{ x: f(b.x + p.x), y: f(b.y + p.y), z: f(b.z + p.z) }, [0.5, 0.5], colours.centre],\n ]\n\n triangle.forEach(([position, uv, colour], k) => {\n const index = at * 3 + k\n\n floats.set([position.x, position.y, position.z], (index * STRIDE) / 4)\n vertices.set(bytesOf(rock.alpha, colour), index * STRIDE + 12)\n floats.set(uv, (index * STRIDE + 16) / 4)\n })\n })\n return vertices\n }\n\n const opaque = this.#rocks.filter(\n (rock) => rock.visible && rock.alpha >= 1 && rock.alpha >= f(0.02),\n )\n const faded = this.#rocks.filter(\n (rock) => rock.visible && rock.alpha < 1 && rock.alpha > f(0.02),\n )\n const draws: Draw[] = []\n\n if (opaque.length)\n draws.push(this.#drawOf(emit(opaque), opaque.length * 3, false, shape, lighting.fog))\n\n if (faded.length)\n draws.push(this.#drawOf(emit(faded), faded.length * 3, true, shape, lighting.fog))\n\n return draws\n }\n\n /**\n * The look, right and up at `camera`, the kept up turned to square with the look, and the\n * sphere's centre ahead.\n */\n #axes(camera: Camera): { forward: Vector3; right: Vector3; up: Vector3; centre: Vector3 } {\n const eye = camera.position\n const frame = Matrix4.fromRotationTranslation(camera.orientation, eye)\n const look = Matrix4.transformDirection({ x: 0, y: 0, z: -1 }, frame)\n const forward = { x: f(look.x), y: f(look.y), z: f(look.z) }\n const centre = {\n x: f(forward.x * this.ahead + eye.x),\n y: f(forward.y * this.ahead + eye.y),\n z: f(forward.z * this.ahead + eye.z),\n }\n // `right` = look × kept up, then `up` = right × look; each normalised.\n const kept = this.#up\n const cx = forward.y * kept.z - forward.z * kept.y\n const cy = forward.z * kept.x - forward.x * kept.z\n const cz = f(forward.x * kept.y - forward.y * kept.x)\n // The reciprocal square root `FUN_0054e900` inlines.\n const rightInverse = f(inverseRoot(f(cx * cx + cz * cz + cy * cy)))\n const right = { x: f(cx * rightInverse), y: f(cy * rightInverse), z: f(cz * rightInverse) }\n const turned = {\n x: f(right.y * forward.z - right.z * forward.y),\n y: f(right.z * forward.x - forward.z * right.x),\n z: f(forward.y * right.x - right.y * forward.x),\n }\n const upInverse = inverseRoot(\n f(turned.x * turned.x + turned.y * turned.y + turned.z * turned.z),\n )\n const up = {\n x: f(upInverse * turned.x),\n y: f(upInverse * turned.y),\n z: f(upInverse * turned.z),\n }\n\n return { forward, right, up, centre }\n }\n\n /**\n * A rock's alpha at `point`, `squared` from the sphere's centre: faded toward the sphere's edge,\n * the band narrowing with depth past its centre, then in front of the cubes' reach. Under 0.02\n * it isn't drawn; retail skips the near fade then, which only lowers it.\n */\n #fade(point: Vector3, squared: number, eye: Vector3, forward: Vector3): number {\n const radiusSquared = this.radius * this.radius\n const percent = f(Math.min(Math.max(this.settings.fadePercent ?? 0.3, 0), 1))\n const [nearHigh, nearLow] = this.nearFade\n const depth = f(\n (point.x - eye.x) * forward.x + (point.z - eye.z) * forward.z + (point.y - eye.y) * forward.y,\n )\n let alpha: number\n\n if (depth > this.ahead) {\n const t = Math.min(1 - (this.radius - (depth - this.ahead)) / this.radius, 1)\n const band = ((1 - percent) * t * 0.5 + percent) * this.radius\n const bandSquared = band * band\n\n alpha = squared > radiusSquared - bandSquared ? f((radiusSquared - squared) / bandSquared) : 1\n } else {\n const fadeSquared = this.fade * this.fade\n\n alpha = squared > radiusSquared - fadeSquared ? f((radiusSquared - squared) / fadeSquared) : 1\n }\n\n if (alpha < f(0.02) || depth >= nearHigh) return alpha\n return depth < nearLow ? 0 : f(((depth - nearLow) / (nearHigh - nearLow)) * alpha)\n }\n\n /** The alpha a rock at `point` draws with, seen from `camera`. */\n alphaAt(camera: Camera, point: Vector3): number {\n const { forward, centre } = this.#axes(camera)\n const dx = point.x - centre.x\n const dy = point.y - centre.y\n const dz = point.z - centre.z\n\n return this.#fade(point, dx * dx + dz * dz + dy * dy, camera.position, forward)\n }\n\n /**\n * The rocks' colours seen from `camera`: a corner's toward the right, the left, the up and the\n * down, and the centre's.\n */\n coloursAt(camera: Camera, lighting: BillboardLighting): { corners: Vector3[]; centre: Vector3 } {\n const { forward, right, up } = this.#axes(camera)\n\n return this.#colours(lighting, forward, right, up)\n }\n\n /**\n * `FUN_0054e130`: the ambient the pass left, times `ambient_intensity`, the tinted ambient and\n * `color_shift`, then each directional light by how it falls on four directions a step off the\n * look, toward each side and up and down, and the look itself; each held to 1.\n */\n #colours(\n { ambient, lights, lit = true }: BillboardLighting,\n forward: Vector3,\n right: Vector3,\n up: Vector3,\n ): { corners: Vector3[]; centre: Vector3 } {\n if (!lit) return { corners: [0, 1, 2, 3].map(() => this.#diffuse), centre: this.#diffuse }\n\n const scale = f(f(this.settings.ambientIntensity ?? 1) * f(1 / 255))\n const shift = this.settings.colorShift ?? { x: 1, y: 1, z: 1 }\n const tint = this.#ambient\n const base = {\n x: f(f(f(Math.round(ambient.x * 255) * scale) * tint.x) * f(shift.x)),\n y: f(f(f(Math.round(ambient.y * 255) * scale) * tint.y) * f(shift.y)),\n z: f(f(f(Math.round(ambient.z * 255) * scale) * tint.z) * f(shift.z)),\n }\n const sides = [\n right,\n { x: -right.x, y: -right.y, z: -right.z },\n up,\n { x: -up.x, y: -up.y, z: -up.z },\n BLACK,\n ]\n const outputs = sides.map(() => ({ ...base }))\n\n for (const light of lights.slice(0, 4)) {\n const colour = {\n x: f(light.color.x * this.#diffuse.x),\n y: f(light.color.y * this.#diffuse.y),\n z: f(light.color.z * this.#diffuse.z),\n }\n\n sides.forEach((side, at) => {\n let d = { x: f(forward.x + side.x), y: f(forward.y + side.y), z: f(forward.z + side.z) }\n const inverse = 1 / Math.sqrt(d.x * d.x + d.y * d.y + d.z * d.z)\n\n d = { x: f(inverse * d.x), y: f(inverse * d.y), z: f(inverse * d.z) }\n\n // Wrapped diffuse: 0 at a dot of -0.5, rising to 1 at 1.\n const dot = d.z * light.direction.z + d.y * light.direction.y + d.x * light.direction.x\n const weight = dot < -0.5 ? 0 : f((dot + 0.5) / 1.5)\n const out = outputs[at]!\n\n out.x = f(out.x + f(colour.x * weight))\n out.y = f(out.y + f(colour.y * weight))\n out.z = f(out.z + f(colour.z * weight))\n })\n }\n\n const clamped = outputs.map(clampOne)\n\n return { corners: clamped.slice(0, 4), centre: clamped[4]! }\n }\n\n #drawOf(\n vertices: Uint8Array,\n count: number,\n blended: boolean,\n shape: TextureShape,\n fog?: Fog,\n ): Draw {\n const mesh: VMeshData = {\n name: 'asteroid billboards',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n { materialId: 0, vertexStart: 0, vertexEnd: count - 1, elementCount: count, padding: 0 },\n ],\n indices: Uint16Array.from({ length: count }, (_, at) => at),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: count,\n indexStart: 0,\n indexCount: count,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count,\n world: Matrix4.identity,\n materialName: 'asteroid billboards',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: {\n name: shape.texture.name,\n entry: shape.texture,\n sampler: DEFAULT_SAMPLER,\n uvSet: 0,\n },\n cull: 'none',\n depthWrite: !blended,\n depthFunc: 'lequal',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: blended,\n blendMode: 'alpha',\n unlit: true,\n alphaReference: blended ? 5 : 128,\n alphaFunction: 'greater',\n ...(fog && { fog }),\n }\n }\n}\n","/**\n * An asteroid field's `[DynamicAsteroids]`: a few loose rocks on a sphere about a point ahead of the\n * camera, drifting and turning, faded in as they come within it and placed afresh on its surface\n * once they drift out. `CliDynamicAsteroidUpdate` (`FUN_00525c80`), `Place` (`FUN_00525200`) and\n * `CliDynamicAsteroidDraw` (`FUN_005261b0`) in `src/freelancer/Client/cli_asteroid_dynamic.cpp`.\n * Places and motions are the game's `rand()`, so a run matches retail in kind. A rock's archetype\n * may carry a `particle_effect`, which the host starts and this runs on the rock. Pure, no GL.\n */\nimport { Matrix3, Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport { outsideSquared, type CubeExclusion } from './asteroids.js'\nimport { viewMatrix, type Camera } from './camera.js'\nimport type { EffectView } from './effect-view.js'\nimport type { Random } from './lightning.js'\nimport { immersion, type Zone } from './nebula.js'\nimport type { SpaceEffect } from './space.js'\nimport { onSphere, RAND_UNIT } from './retail.js'\n\nconst f = Math.fround\n\n/** A `[DynamicAsteroids]` section, over the manager's constructor (`FUN_005256a0`). The host reads it. */\nexport interface DynamicSettings {\n /** `count`, truncated, 10 when absent. */\n count?: number\n /**\n * `placement_radius`, 150 when absent. Its spawn point is 0.7 of it ahead, or 75 when absent.\n * Every retail file also has `placement_offset`, which nothing reads.\n */\n placementRadius?: number\n /** `max_velocity`, 50 when absent: the most a rock moves on each axis, a second. */\n maxVelocity?: number\n /** `max_angular_velocity`, 5 when absent: the most it turns about each axis, radians a second. */\n maxAngularVelocity?: number\n /** `color_shift`, 1 each when absent. */\n colorShift?: Vector3\n}\n\n/** What a field gives its dynamic asteroids. */\nexport interface DynamicField {\n /** The section's `zone`, or the field's: the spawn point must be within it. None, anywhere. */\n zone?: Zone\n /** That zone's `edge_fraction`. 0 when absent. */\n edgeFraction?: number\n /** The field's `diffuse_color` and `ambient_color` over 255. */\n diffuse: Vector3\n ambient: Vector3\n /** Its exclusion zones; those with `excludeDynamicAsteroids` keep the spawn point out. */\n exclusions?: readonly CubeExclusion[]\n}\n\n/** A started `particle_effect`: what a `SpaceEffect` is but where it is, which the rock gives it. */\nexport type DynamicEffect = Omit<SpaceEffect, 'position' | 'watched'>\n\n/** One rock to draw: its frame and its fade. */\nexport interface DynamicDraw {\n world: Matrix4\n alpha: number\n}\n\ninterface Rock {\n position: Vector3\n orientation: Matrix3\n velocity: Vector3\n /** Its angular velocity about its own axes. */\n spin: Vector3\n /** `Alpha` (`+0xb0`): the fade last worked out, never written when it's made. */\n alpha: number\n /** `bPlaced` (`+0xad`): within the sphere since it was last placed. */\n placed: boolean\n /** Its companion's `particle_effect`, started as it was placed. */\n effect?: DynamicEffect\n /** What the effect's `SetIntensity` was last given: its `sparam`. */\n intensity: number\n /** The `ALCHEMY_LOD` blend its effect's last view gave. */\n lod: number\n /** When its effect started, over every field's: the game walks a type's newest first. */\n serial: number\n}\n\n/** A started rock effect, and when it started. */\nexport interface DynamicEffectAt {\n effect: SpaceEffect\n serial: number\n}\n\nlet started = 0\n\nconst RAND_TWICE = 6.103515625e-5\n// `DAT_005d3e6c` and `DAT_00613858`: the recycle distance and the fade band, over the radius squared.\nconst FAR = f(1.05)\nconst FADE = f(0.35)\n// `DAT_005d3e44`: a rock at or under this alpha isn't drawn.\nconst VISIBLE = f(0.005)\n// `DAT_005d1494`: how far into its zone the spawn point must be.\nconst IMMERSED = f(0.001)\n/**\n * `set_max_dynamicasteroid_exclusion_distance(100)` at load (`0x521516`), squared: exclusion zones\n * further outside than this from the camera aren't asked.\n */\nconst EXCLUSION_REACH = 10000\n\n/** A right-handed turn about a unit axis, its columns the turned axes: `Matrix3.axisAngle` holds rows. */\nconst turn = (axis: Vector3, angle: number): Matrix3 =>\n Matrix3.transpose(Matrix3.axisAngle(axis, angle))\n\nconst clampOne = ({ x, y, z }: Vector3): Vector3 => ({\n x: x < 1 ? x : 1,\n y: y < 1 ? y : 1,\n z: z < 1 ? z : 1,\n})\n\nexport class DynamicAsteroids {\n readonly settings: DynamicSettings\n readonly field: DynamicField\n readonly random: Random\n /** `SlotCount`: `count` scaled by the `Asteroids` option, `(1 - d) · 0.5 + d`, rounded. */\n readonly count: number\n /** `PlacementRadius` and `PlacementRadiusInner`. */\n readonly radius: number\n readonly ahead: number\n /** `TintedDiffuse` and `TintedAmbient`: `color_shift` times the field's, held under 1. */\n readonly diffuse: Vector3\n readonly ambient: Vector3\n /** Starts the archetype's `particle_effect` afresh: none when it has none. */\n readonly effect: (() => DynamicEffect) | undefined\n #rocks: (Rock | undefined)[]\n\n constructor(\n settings: DynamicSettings,\n field: DynamicField,\n {\n random = () => Math.floor(Math.random() * 0x8000),\n detail = 1,\n effect,\n }: { random?: Random; detail?: number; effect?: () => DynamicEffect } = {},\n ) {\n this.settings = settings\n this.field = field\n this.random = random\n this.effect = effect\n\n // `FUN_00520850` and `CliAsteroidApplyDetail` store the scale as a float.\n const scale = f((1 - detail) * 0.5 + detail)\n\n this.count = Math.trunc(Math.trunc(settings.count ?? 10) * scale + 0.5)\n this.#rocks = Array.from({ length: this.count }, () => undefined)\n\n const radius = settings.placementRadius\n\n this.radius = f(radius ?? 150)\n this.ahead = radius === undefined ? 75 : f(radius * 0.7)\n\n // `CliDynamicAsteroidApplyParentTints`.\n const shift = settings.colorShift ?? { x: 1, y: 1, z: 1 }\n\n this.diffuse = clampOne({\n x: f(field.diffuse.x * shift.x),\n y: f(shift.y * field.diffuse.y),\n z: f(shift.z * field.diffuse.z),\n })\n this.ambient = clampOne({\n x: f(shift.x * field.ambient.x),\n y: f(shift.y * field.ambient.y),\n z: f(shift.z * field.ambient.z),\n })\n }\n\n get rocks(): readonly (Readonly<Rock> | undefined)[] {\n return this.#rocks\n }\n\n /** `CliDynamicAsteroidUpdate`'s spawn point: `ahead` along the view, `(m[2], m[5], m[8])`. */\n centre({ position, orientation }: Camera): Vector3 {\n const back = -this.ahead\n\n return {\n x: f(f(orientation.x.z * back) + position.x),\n y: f(f(orientation.y.z * back) + position.y),\n z: f(f(orientation.z.z * back) + position.z),\n }\n }\n\n /** Whether a rock may be placed about this point: in the zone, and in no zone that keeps them out. */\n #allowed(centre: Vector3, eye: Vector3): boolean {\n const { zone, edgeFraction = 0, exclusions = [] } = this.field\n if (zone && !(immersion(zone, edgeFraction, centre) > IMMERSED)) return false\n\n // `is_dynamic_asteroid_excluded` over the zones nearest the camera first.\n const order = exclusions\n .map((exclusion) => ({ exclusion, key: outsideSquared(exclusion, eye) }))\n .sort((a, b) => a.key - b.key)\n\n for (const { exclusion, key } of order) {\n if (key > EXCLUSION_REACH) break\n\n if (\n exclusion.excludeDynamicAsteroids &&\n immersion(exclusion.zone, exclusion.edgeFraction ?? 0, centre) !== 0\n )\n return false\n }\n\n return true\n }\n\n /**\n * A rock's fade at a point about the spawn point: 1 within, falling over the outer 0.35 of the\n * radius squared to 0 at 1.05 of it. Past that, none: the rock is placed afresh.\n */\n #fade(centre: Vector3, { x, y, z }: Vector3): number | undefined {\n const squared = this.radius * this.radius\n const far = FAR * squared\n const fade = squared * FADE\n const dx = f(x - centre.x)\n const dy = f(y - centre.y)\n const dz = f(z - centre.z)\n const distance = f(dz * dz + dy * dy + dx * dx)\n if (distance > far) return undefined\n return f(distance > far - fade ? (far - distance) / fade : 1)\n }\n\n /** The fade of a rock at a point in the world, under this camera. */\n alphaAt(camera: Camera, point: Vector3): number | undefined {\n return this.#fade(this.centre(camera), point)\n }\n\n /** `Place`: at a point, unturned, with a velocity squared toward the edges and a spin. */\n #place(rock: Rock, position: Vector3): void {\n const { random } = this\n const most = f(this.settings.maxVelocity ?? 50)\n const spin = f(this.settings.maxAngularVelocity ?? 5)\n\n // A draw as [-1, 1) with its square's size and its own sign, times the most.\n const axis = () => {\n const value = f(random() * RAND_TWICE - 1)\n const square = f(value * value)\n\n return f((value > 0 ? square : -square) * most)\n }\n\n const [vx, vy, vz] = [axis(), axis(), axis()]\n // The first draw turns about Y, the second about X.\n const first = f(random() * RAND_UNIT)\n const second = f(random() * RAND_UNIT * spin)\n const third = f(random() * spin * RAND_TWICE - spin)\n const firstScaled = f(first * spin)\n\n rock.position = position\n rock.orientation = Matrix3.identity\n rock.velocity = { x: vx, y: vy, z: vz }\n rock.spin = { x: f(second + second - spin), y: f(firstScaled + firstScaled - spin), z: third }\n }\n\n /**\n * The physics' step between frames: each placed rock moves at its velocity and turns at its spin\n * about its own axes. Retail's is IVP's (`CDynamicAsteroid::init_physics`: mass 1, linear damping\n * 1e-5, no angular damping), which this takes as constant motion. Unchecked: the damping, the\n * precession of a body that isn't round, and collisions, which retail turns on once placed.\n */\n #move(step: number): void {\n if (!(step > 0)) return\n\n for (const rock of this.#rocks) {\n if (!rock?.placed) continue\n\n const { position: p, velocity: v, spin: w } = rock\n\n rock.position = { x: f(p.x + v.x * step), y: f(p.y + v.y * step), z: f(p.z + v.z * step) }\n\n const rate = Math.hypot(w.x, w.y, w.z)\n\n if (rate > 0)\n rock.orientation = Matrix3.multiply(\n rock.orientation,\n turn({ x: w.x / rate, y: w.y / rate, z: w.z / rate }, rate * step),\n )\n }\n }\n\n /**\n * `CliDynamicAsteroidUpdate`, after the physics has moved the rocks by `step` seconds; the order\n * of the two is a guess. A rock inside 1.05 of the sphere is faded over its outer 0.35, by the\n * radius squared. Any other is placed afresh on the sphere, or released if the spawn point is\n * outside the zone, in a zone that excludes them, or `blocked`: the player's ship in a lane.\n * Their effects step by `effectStep`, the effect walk's own, `step` when absent.\n */\n update(\n camera: Camera,\n step = 0,\n { blocked = false, effectStep = step }: { blocked?: boolean; effectStep?: number } = {},\n ): void {\n this.#move(step)\n this.#recycle(camera, blocked)\n this.#run(camera, effectStep)\n }\n\n #recycle(camera: Camera, blocked: boolean): void {\n const centre = this.centre(camera)\n const allowed = !blocked && this.#allowed(centre, camera.position)\n\n for (let index = 0; index < this.count; index++) {\n let rock = this.#rocks[index]\n\n if (rock?.placed) {\n const alpha = this.#fade(centre, rock.position)\n\n if (alpha !== undefined) {\n rock.alpha = alpha\n continue\n }\n\n rock.placed = false\n }\n\n if (!allowed) {\n this.#rocks[index] = undefined\n continue\n }\n\n // A new rock's alpha is the heap's: until it's next faded, taken as 0.\n rock ??= {\n position: centre,\n orientation: Matrix3.identity,\n velocity: { x: 0, y: 0, z: 0 },\n spin: { x: 0, y: 0, z: 0 },\n alpha: 0,\n placed: false,\n intensity: 0,\n lod: 1,\n serial: 0,\n }\n this.#rocks[index] = rock\n\n const unit = onSphere(this.random)\n\n this.#place(rock, {\n x: f(this.radius * unit.x + centre.x),\n y: f(this.radius * unit.y + centre.y),\n z: f(this.radius * unit.z + centre.z),\n })\n\n // The old effect is dropped and the archetype's started afresh, at intensity 0 (`0x52607e`).\n if (this.effect) {\n rock.effect?.instance.release()\n rock.effect = this.effect()\n rock.serial = ++started\n rock.intensity = 0\n rock.lod = 1\n }\n\n rock.placed = true\n }\n }\n\n /**\n * Each rock's effect stepped on, held at its rock's frame, at the intensity its last draw gave.\n * Where in the frame retail's effects step against the rocks' update is a guess. One that has\n * ended is dropped, as its rock's effect list is swept (`FUN_004fd040`).\n */\n #run(camera: Camera, step: number): void {\n if (!this.effect) return\n\n const view = viewMatrix(camera)\n\n for (const rock of this.#rocks) {\n if (!rock?.effect) continue\n rock.effect.instance.advance(step, {\n sparam: rock.intensity,\n lod: rock.lod,\n placement: Matrix4.fromRotationTranslation(rock.orientation, rock.position),\n view,\n })\n\n if (rock.effect.instance.finished) {\n rock.effect.instance.release()\n delete rock.effect\n }\n }\n }\n\n /**\n * The rocks' effects for the frame's walk, in slot order, each where its rock is, with when it\n * started: the frame walks every field's newest first, as the game's list is (`FUN_004fc920`).\n */\n effects(): DynamicEffectAt[] {\n const effects: DynamicEffectAt[] = []\n\n for (const rock of this.#rocks)\n if (rock?.effect)\n effects.push({\n effect: {\n ...rock.effect,\n position: rock.position,\n watched: { position: rock.position },\n },\n serial: rock.serial,\n })\n\n return effects\n }\n\n /** What the frame's view test made of `effects()`, in its order: each one's `lod` next step. */\n viewed(views: readonly (EffectView | undefined)[]): void {\n let at = 0\n for (const rock of this.#rocks) if (rock?.effect) rock.lod = views[at++]?.lod ?? rock.lod\n }\n\n /**\n * `CliDynamicAsteroidDraw`'s rocks, in slot order: each above 0.005, at the alpha it was last\n * faded to, which a rock placed this frame kept from before. Each drawn hands its alpha, held to\n * [0, 1], to its effect as its intensity (`0x5265c4`, `FParticleEffect::SetIntensity`).\n */\n draws(): DynamicDraw[] {\n const draws: DynamicDraw[] = []\n\n for (const rock of this.#rocks) {\n if (!rock || !(rock.alpha > VISIBLE)) continue\n rock.intensity = rock.alpha < 0 ? 0 : rock.alpha > 1 ? 1 : rock.alpha\n draws.push({\n world: Matrix4.fromRotationTranslation(rock.orientation, rock.position),\n alpha: rock.alpha,\n })\n }\n\n return draws\n }\n}\n","/**\n * A nebula's lightning: `[BackgroundLightning]` flashes its fog's colour, which deep inside is the clear\n * colour, and `[DynamicLightning]` flashes a light at the camera. `FNebulaEffect::FillFogRgb` and\n * `NebulaAmbientTick` in `src/freelancer/Client/cli_nebula.cpp`.\n */\nimport type { Vector3 } from '@treewyrm/freelancer/math'\nimport type { SpaceLight } from './light.js'\nimport { clampByte } from './retail.js'\n\n/** `[BackgroundLightning]`, each key over what `FNebulaEffect`'s constructor sets. */\nexport interface BackgroundLightningSettings {\n /** `gap`: about how long between flashes, from 0.8 to 1.5 of it. */\n gap: number\n /** `duration`: how long a flash lasts. None at all at 0 or less. */\n duration: number\n /** `color` over 255: added to the fog's, by up to `intensity`. */\n color: Vector3\n intensity: number\n}\n\n/** `[DynamicLightning]`, each key over what `FNebulaEffect`'s constructor sets. */\nexport interface DynamicLightningSettings {\n /** `gap`: about how long between flashes, from 0.8 to 1.5 of it. */\n gap: number\n /** `duration`: how long a flash lasts. No light at all at 0 or less. */\n duration: number\n /** `color` over 255, by up to the intensity. */\n color: Vector3\n /** `ambient_intensity`. */\n ambientIntensity: number\n /** `intensity_increase`: added while the background flashes too. */\n intensityIncrease: number\n}\n\n/** Checked in `Freelancer-original.exe`, `0x504b06` to `0x504b42`: every nebula flashes unless told not to. */\nexport const RETAIL_BACKGROUND_LIGHTNING: Readonly<BackgroundLightningSettings> = {\n gap: 10,\n duration: 0.5,\n color: { x: 0.25, y: 0.25, z: 0.25 },\n intensity: 1,\n}\n\n/** Checked in `Freelancer-original.exe`, `0x504b4e` to `0x504b8a`. */\nexport const RETAIL_DYNAMIC_LIGHTNING: Readonly<DynamicLightningSettings> = {\n gap: 3,\n duration: 0.5,\n color: { x: 1, y: 1, z: 1 },\n ambientIntensity: 0.25,\n intensityIncrease: 0.75,\n}\n\n/** What retail's light (`Load`, `0x50604f` on) is besides its colour and direction. */\nconst DYNAMIC_RANGE = 500000\n\ninterface LightState {\n direction: Vector3\n /** 0 to 255. */\n color: Vector3\n on: boolean\n}\n\n/** `rand()`'s range: whole numbers from 0 to 32767. */\nexport type Random = () => number\n\nconst RAND_SCALE = Math.fround(3.0517578125e-5)\nconst f = Math.fround\n\n// Kept below 1, as `ParseFogSection` keeps the fog's.\nconst below = (value: number) => (value < 1 ? value : 1)\nconst byte = clampByte\n\n/**\n * One nebula's lightning timers, which the host keeps for as long as the nebula exists.\n * `collectSpaceFrame` advances them as retail does: the light on every frame by the scene's `step`,\n * and the background only on a frame the camera is deep in the nebula. Retail draws from the game's\n * one `rand()`, so its flashes can't be matched, only their kind.\n */\nexport class NebulaLightning {\n readonly background: BackgroundLightningSettings\n readonly dynamic: DynamicLightningSettings\n readonly random: Random\n // `+0x1c`, `Update`'s step, which `FillFogRgb` reads too.\n #step = 0\n // `+0x258`: below 0 counts up to the next flash, above 0 through one.\n #backgroundTimer: number\n // `+0x26c`: the background flashed on its last call.\n #flashing = false\n // `+0x27c`, and the light, which exists only with a positive duration.\n #dynamicTimer = -1\n #light: LightState | undefined\n #position: Vector3 = { x: 0, y: 0, z: 0 }\n\n constructor(\n settings: {\n background?: Partial<BackgroundLightningSettings>\n dynamic?: Partial<DynamicLightningSettings>\n } = {},\n random: Random = () => Math.floor(Math.random() * 0x8000),\n ) {\n this.background = { ...RETAIL_BACKGROUND_LIGHTNING, ...settings.background }\n this.dynamic = { ...RETAIL_DYNAMIC_LIGHTNING, ...settings.dynamic }\n this.random = random\n\n // `gap` starts the first wait at its full length; without it, `Load`'s -1.\n const gap = settings.background?.gap\n\n this.#backgroundTimer = gap === undefined ? -1 : -gap\n\n // Down -Z from the constructor's identity, and off.\n if (this.dynamic.duration > 0)\n this.#light = {\n direction: { x: 0, y: 0, z: -1 },\n color: { x: 255, y: 255, z: 255 },\n on: false,\n }\n }\n\n /** A flash on the next step rather than after its wait, for an editor: retail has no such call. */\n fire(kind: 'background' | 'dynamic'): void {\n if (kind === 'background') this.#backgroundTimer = 0\n else this.#dynamicTimer = 0\n }\n\n /** `FNebulaEffect::Update`'s part, each frame: `depth` is its `+0x294`, where `eye` is. */\n update(step: number, depth: number, eye: Vector3): void {\n this.#step = step\n\n const light = this.#light\n if (!light) return\n // Out of it, off. Part way in, as it was.\n if (!(depth > 0)) light.on = false\n if (!(depth >= 1)) return\n this.#position = eye\n this.#tick(light)\n }\n\n // `NebulaAmbientTick` (`0x5097c0`).\n #tick(light: LightState): void {\n const { gap, duration, color, ambientIntensity, intensityIncrease } = this.dynamic\n const previous = this.#dynamicTimer\n const timer = this.#step + previous\n\n this.#dynamicTimer = f(timer)\n\n if (!(previous > 0)) {\n if (!(timer > 0)) return\n } else if (timer > duration) {\n // The next flash's wait, and its direction: the third number lands in x.\n this.#dynamicTimer = f((this.random() * RAND_SCALE * f(0.7) - 1.5) * f(gap))\n\n const first = this.random() * RAND_SCALE\n const second = this.random() * RAND_SCALE\n const third = this.random() * RAND_SCALE\n const z = first + first - 1\n const y = second + second - 1\n const x = third + third - 1\n const inverse = f(1 / Math.sqrt(z * z + y * y + x * x))\n\n light.direction = { x: f(x * inverse), y: f(y * inverse), z: f(f(z) * inverse) }\n light.on = false\n return\n }\n\n const intensity = this.#flashing\n ? f(f(ambientIntensity) + f(intensityIncrease))\n : f(ambientIntensity)\n const first = f(this.random() * RAND_SCALE)\n const flicker = this.random() * first * intensity * RAND_SCALE\n const red = below(f(flicker * f(color.x)))\n const green = below(f(flicker * f(color.y)))\n const blue = below(flicker * f(color.z))\n\n light.color = {\n x: byte(f(red * 255)),\n y: byte(f(green * 255)),\n z: byte(blue * 255),\n }\n light.on = true\n }\n\n /** Its light while it flashes: directional, at the camera, after the system's own. */\n get light(): SpaceLight | undefined {\n const light = this.#light\n if (!light?.on) return undefined\n return {\n type: 'directional',\n position: this.#position,\n direction: light.direction,\n color: light.color,\n range: DYNAMIC_RANGE,\n }\n }\n\n /** `FillFogRgb`: `base`, the fog's colour, or a flash over it, `update`'s step later. */\n fogColor(base: Vector3): Vector3 {\n const { gap, duration, color, intensity } = this.background\n if (duration <= 0) return base\n\n const previous = this.#backgroundTimer\n const timer = this.#step + previous\n\n this.#backgroundTimer = f(timer)\n this.#flashing = false\n\n if (previous > 0) {\n this.#flashing = true\n\n if (timer > duration)\n this.#backgroundTimer = f((this.random() * RAND_SCALE * f(0.7) - 1.5) * f(gap))\n } else if (timer > 0) this.#flashing = true\n\n if (!this.#flashing) return base\n\n const first = f(this.random() * RAND_SCALE)\n const scale = this.random() * f(intensity) * first * RAND_SCALE\n\n return {\n x: below(f(scale * f(color.x) + base.x)),\n y: below(f(f(scale * f(color.y)) + base.y)),\n z: below(f(f(scale * f(color.z)) + base.z)),\n }\n }\n}\n","/**\n * A jump gate's tunnel: `FGateTunnel`, in `src/freelancer/Client/gate_tunnel.cpp`. A tube along a\n * random spline, which the player's ship is beamed along while it jumps, drawn as rings of strips\n * around it, fading and narrowing ahead. Nine curves of `num_spline_control_points` each: the path's\n * x, y and z, the radius, a rotation nothing reads, three colour offsets and a brightness, scrolled\n * on as the ship nears the end. Pure, no GL.\n */\nimport { cubicAt, Matrix4, type CubicSegment, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Texture } from '@treewyrm/freelancer/texture'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Draw, SceneLight } from './frame.js'\nimport type { Random } from './lightning.js'\nimport { clampByte, unitByte } from './retail.js'\n\nconst f = Math.fround\n\n// XYZ, D3DCOLOR and one UV set: Win3D's FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\n\n// `DAT_005da778`, a curve's draws onto [0, 1], and `DAT_005caeec`, the light's onto [0, 1).\nconst RAND_UNIT = f(1 / 32767)\nconst RAND_HALF_UNIT = f(1 / 32768)\nconst TWO_PI = f(6.2831855)\n// `DAT_005da738`, a double: how far `BuildFrame` looks ahead along the path.\nconst FRAME_STEP = 5e-6\n// `DAT_00613254`, `_58` and `_5c`, with no writer: the scroll's head, tail and pad.\nconst SCROLL_HEAD = 3\nconst SCROLL_TAIL = 3\nconst SCROLL_PAD = 1\nconst SCROLL = SCROLL_TAIL + SCROLL_PAD + SCROLL_HEAD + 1\n// `DAT_00613260`, `_68`, `_6c` and `_70`.\nconst LIGHT_WEIGHT = 6\nconst LOOK_AHEAD = f(0.02)\nconst STEP_GROWTH = f(1.1)\nconst ALPHA_BIAS = f(0.05)\n// `Draw`'s window about the ship, as `EmitLayer`'s float arguments.\nconst WINDOW_AHEAD = f(0.1)\nconst WINDOW_BEHIND = f(-0.01)\n\n/** A `[layer]` of a `[gate_tunnel]`, as `GateTunnelIniLoad` (`0x4fe1c0`) reads it. */\nexport interface TunnelLayer {\n /** `texture`, a shape of `FX/effect_shapes.ini`: its texture's first frame, whole. None if not found. */\n texture?: Texture\n /** `color`, 0 to 1: the bytes as written over 255. */\n color: Vector3\n /**\n * `near_alpha` and `far_alpha`. Retail's files write `near_alpha_factor` and `far_alpha_factor`,\n * which `Freelancer-original.exe` has no string for, so every retail layer fades from 1 to 0.\n */\n nearAlpha: number\n farAlpha: number\n radiusFactor: number\n /** `u_offset` and `v_offset`: where the texture starts, scrolled on by `du` and `dv` a second. */\n uOffset: number\n vOffset: number\n du: number\n dv: number\n vScale: number\n}\n\n/** A `[layer]`'s defaults (`0x4fe70c`). */\nexport const RETAIL_TUNNEL_LAYER: Readonly<TunnelLayer> = {\n color: { x: 0.5, y: 0.5, z: 0.5 },\n nearAlpha: 1,\n farAlpha: 0,\n radiusFactor: 1,\n uOffset: 0,\n vOffset: 0,\n du: f(0.09),\n dv: f(0.07),\n vScale: 10,\n}\n\n/**\n * A `[gate_tunnel]`'s keys, as `GateTunnelIniLoad` reads them. `fade_distance`, `near_alpha` and\n * `far_alpha` here are never read.\n */\nexport interface TunnelSettings {\n writeDepth: boolean\n /** `num_spline_control_points`. Under 2 builds no curves, where retail reads past their ends. */\n controlPoints: number\n /** `x_range`, `y_range` and `z_range`: the path wanders `x` and `y` across, and runs `z` long. */\n range: Vector3\n minRadius: number\n maxRadius: number\n /** What the radius is ahead of the ship, at the window's far end. */\n farRadiusFactor: number\n /** Of the path, a second. */\n minSpeed: number\n maxSpeed: number\n timeToMaxSpeed: number\n /** `num_t_steps`: along the path, the first strip's length 1 / it. */\n tSteps: number\n /** `num_s_steps`: around each ring. */\n sSteps: number\n minRotation: number\n maxRotation: number\n /** `min_rgb` and `max_rgb`, 0 to 1: the colour offsets' range. */\n minRgb: Vector3\n maxRgb: Vector3\n /** Two at most: a third is refused. */\n layers: readonly TunnelLayer[]\n}\n\n/** `FGateTunnel`'s constructor (`0x4fee30`). */\nexport const RETAIL_TUNNEL: Readonly<TunnelSettings> = {\n writeDepth: true,\n controlPoints: 11,\n range: BLACK,\n minRadius: 50,\n maxRadius: 50,\n farRadiusFactor: 1,\n minSpeed: f(3e-5),\n maxSpeed: f(0.06),\n timeToMaxSpeed: 8,\n tSteps: 200,\n sSteps: 12,\n minRotation: f(-Math.PI),\n maxRotation: f(Math.PI),\n minRgb: BLACK,\n maxRgb: BLACK,\n layers: [],\n}\n\n/** `SetState`: 0 idle, 1 built for the jump out, 2 in the tunnel, 3 jumping in. */\nexport type TunnelState = 0 | 1 | 2 | 3\n\n/**\n * `GateTunnelSolveSpline` (`FUN_005018a0`): the natural-end cubic through `y[0..n]`, as\n * `naturalSpline` solves it but rounded to a float at every step.\n */\nexport const solveSpline = (y: readonly number[], n: number): CubicSegment[] => {\n const gamma = new Array<number>(n + 1).fill(0)\n const delta = new Array<number>(n + 1).fill(0)\n const d = new Array<number>(n + 1).fill(0)\n\n // Forward sweep of the tridiagonal system for the knot derivatives `d`, then back-substitution;\n // `c0..c3` are each segment's power-basis cubic over t in [0, 1].\n gamma[0] = 0.5\n for (let i = 1; i < n; i++) gamma[i] = f(1 / (4 - gamma[i - 1]!))\n gamma[n] = f(1 / (2 - gamma[n - 1]!))\n delta[0] = f((y[1]! - y[0]!) * gamma[0]! * 3)\n\n for (let i = 1; i < n; i++)\n delta[i] = f(((y[i + 1]! - y[i - 1]!) * 3 - delta[i - 1]!) * gamma[i]!)\n\n delta[n] = f(((y[n]! - y[n - 1]!) * 3 - delta[n - 1]!) * gamma[n]!)\n d[n] = delta[n]!\n for (let i = n - 1; i >= 0; i--) d[i] = f(delta[i]! - d[i + 1]! * gamma[i]!)\n return Array.from({ length: n }, (_, i) => ({\n c0: y[i]!,\n c1: d[i]!,\n c2: f((y[i + 1]! - y[i]!) * 3 - (d[i]! + d[i]!) - d[i + 1]!),\n c3: f((y[i]! - y[i + 1]!) * 2 + d[i]! + d[i + 1]!),\n }))\n}\n\n/** `FGateTunnelCurve`: control values and their spline, and the range new values are drawn from. */\nexport class TunnelCurve {\n samples: number[] = []\n segments: CubicSegment[] = []\n minimum = 0\n maximum = 1\n\n constructor(private readonly random: Random) {}\n\n // `rand() * DAT_005da778 * (max - min) + min`, kept as a float.\n draw(): number {\n return f(this.random() * RAND_UNIT * (this.maximum - this.minimum) + this.minimum)\n }\n\n /** `FUN_00501810`: at 1 the last control value; anything else, segment `floor(n t)` at the rest. */\n sample(t: number): number {\n const count = this.segments.length\n if (t === 1) return this.samples[count]!\n\n const scaled = count * t\n const whole = Math.trunc(scaled)\n\n return cubicAt(this.segments[whole]!, scaled - whole)\n }\n\n /** `EmitLayer`'s inlined brightness sample: the same, its fraction rounded to a float. */\n sampleRounded(t: number): number {\n const count = this.segments.length\n if (t === 1) return this.samples[count]!\n\n const scaled = count * t\n const whole = Math.trunc(scaled)\n\n return cubicAt(this.segments[whole]!, f(scaled - whole))\n }\n\n /** `FUN_005012e0`: `count` values drawn from the range, the first `head` and last `tail` 0. */\n randomize(count: number, minimum: number, maximum: number, head: number, tail: number): void {\n this.minimum = minimum\n this.maximum = maximum\n\n const values = Array.from({ length: count }, () => this.draw())\n for (let i = 0; i < head && i < count; i++) values[i] = 0\n for (let i = Math.max(count - tail, 0); i < count; i++) values[i] = 0\n this.set(values)\n }\n\n /** `FUN_00501470`: the last `shift` values to the front, the rest drawn afresh. Not under 8. */\n scroll(shift: number): void {\n const count = this.samples.length\n if (shift < 8 || count < 8) return\n\n const values = this.samples\n for (let i = 0; i < shift; i++) values[i] = values[count - shift + i]!\n for (let i = shift; i < count; i++) values[i] = this.draw()\n this.segments = solveSpline(values, count - 1)\n }\n\n /** `FUN_00501750`. */\n set(values: readonly number[]): void {\n this.samples = [...values]\n this.segments = solveSpline(this.samples, this.samples.length - 1)\n }\n}\n\n/** `BuildFrame` (`FUN_004ffbb0`): the path's frame at `t`, its axes not made unit. */\ninterface PathFrame {\n left: Vector3\n up: Vector3\n point: Vector3\n}\n\nconst round = ({ x, y, z }: Vector3): Vector3 => ({ x: f(x), y: f(y), z: f(z) })\nconst length = ({ x, y, z }: Vector3): number => Math.sqrt(x * x + y * y + z * z)\n\n/** `ScaleClampToByte`: times 255, truncated, held to a byte. */\nconst byte = unitByte\n\n// `NormalizeInPlace`, over the sum as given.\nconst normalize = (v: Vector3, squared: number): Vector3 => {\n const inverse = 1 / Math.sqrt(squared)\n\n return { x: f(inverse * v.x), y: f(inverse * v.y), z: f(inverse * v.z) }\n}\n\n/**\n * One loaded `[gate_tunnel]`. The game keeps one of each and hands it to the player's jump\n * (`FJumpShipEffect`, `0x503440`), which places it at the archetype's `jump_out_hp` and drives its state;\n * the host does both. Loading draws its curves, and so does each jump out.\n */\nexport class GateTunnel {\n /** The gate's `jump_out_hp` in the world: the path runs down its -Z, from 5 out. */\n frame: Matrix4 = Matrix4.identity\n state: TunnelState = 0\n /** Where the ship is along the path, 0 to 1. */\n phase = 0\n /** The ship, as `Update` beams it along the path in states 2 and 3: right, up and back, and where. */\n ship: Matrix4 | undefined\n\n readonly layers: TunnelLayer[]\n private readonly settings: TunnelSettings\n private readonly random: Random\n private readonly pathX: TunnelCurve\n private readonly pathY: TunnelCurve\n private readonly pathZ: TunnelCurve\n private readonly radius: TunnelCurve\n private readonly rotation: TunnelCurve\n private readonly brightness: TunnelCurve\n private readonly offsetR: TunnelCurve\n private readonly offsetG: TunnelCurve\n private readonly offsetB: TunnelCurve\n private speedClock = 0\n private segment = 0\n private lit: { color: Vector3; direction: Vector3; enabled: boolean } | undefined\n\n constructor(\n settings: Partial<TunnelSettings> = {},\n { random = () => Math.floor(Math.random() * 0x8000) }: { random?: Random } = {},\n ) {\n this.settings = { ...RETAIL_TUNNEL, ...settings }\n // Each layer's offsets scroll, so it's this tunnel's own.\n this.layers = this.settings.layers.slice(0, 2).map((layer) => ({ ...layer }))\n this.random = random\n\n const curve = () => new TunnelCurve(random)\n\n this.pathX = curve()\n this.pathY = curve()\n this.pathZ = curve()\n this.radius = curve()\n this.rotation = curve()\n this.brightness = curve()\n this.offsetR = curve()\n this.offsetG = curve()\n this.offsetB = curve()\n this.build()\n }\n\n /**\n * The light `EnterState1` makes: directional, mostly down, white, flickering once a draw has\n * switched it on. In the tunnel the player's ship is lit by it alone, over the jump's\n * `jump_ambient` (`FClientShipGameobj::Slot184`, `0x546480`); `EnterState3` releases it, so a ship\n * jumping in has none.\n */\n get light(): SceneLight | undefined {\n if (!this.lit) return undefined\n\n const { color, direction } = this.lit\n\n return { color: { x: color.x / 255, y: color.y / 255, z: color.z / 255 }, direction }\n }\n\n /** `SetState` (`FUN_004ff360`). */\n setState(state: TunnelState): void {\n this.state = state\n\n if (state === 0) {\n this.segment = 0\n this.phase = 0\n this.speedClock = 0\n this.ship = undefined\n } else if (state === 1) {\n this.speedClock = 0\n this.build()\n this.makeLight()\n } else if (state === 2) this.speedClock = 0\n else this.lit = undefined\n }\n\n /** `Update` (`FUN_004ff3c0`), each step of the jump's states 2 and 3. */\n update(step: number): void {\n if (this.state === 0) return\n\n const { controlPoints, minSpeed, maxSpeed, timeToMaxSpeed } = this.settings\n\n if (this.state === 2 || this.state === 3) {\n const clock = step + this.speedClock\n\n this.speedClock = f(clock)\n\n let ratio = clock / timeToMaxSpeed\n if (1 < ratio) ratio = 1\n\n // Speed ramps linearly from `minSpeed` to `maxSpeed` over `timeToMaxSpeed`; phase is path fraction.\n const phase = (ratio * (maxSpeed - minSpeed) + minSpeed) * step + this.phase\n\n this.phase = f(phase)\n this.segment = Math.trunc((controlPoints - 1) * phase)\n\n // Near the path's end every curve scrolls on, and the ship moves back as far.\n const limit = controlPoints - SCROLL_PAD - SCROLL_HEAD - 1\n\n if (this.segment >= limit) {\n this.pathX.scroll(SCROLL)\n this.pathY.scroll(SCROLL)\n this.rotation.scroll(SCROLL)\n this.radius.scroll(SCROLL)\n this.offsetR.scroll(SCROLL)\n this.offsetG.scroll(SCROLL)\n this.offsetB.scroll(SCROLL)\n this.brightness.scroll(SCROLL)\n\n // The samples moved back `limit - 3` control points, so the phase does, in 1/segments units.\n const segments = controlPoints - 1\n\n this.segment = 3\n this.phase = f(this.phase - limit / segments + 3 / segments)\n }\n\n const here = this.pathPoint(this.phase)\n const ahead = this.pathPoint(f(LOOK_AHEAD + this.phase))\n const dir = round({ x: ahead.x - here.x, y: ahead.y - here.y, z: ahead.z - here.z })\n const inverse = 1 / length(dir)\n const back = { x: -f(dir.x * inverse), y: -f(dir.y * inverse), z: -f(dir.z * inverse) }\n // `N × (0, 1, 0)`, negated, and then `N × R`.\n const right = { x: -f(back.y * 0 - back.z), y: -f(back.z * 0 - back.x * 0), z: -f(back.x) }\n const up = round({\n x: right.z * back.y - right.y * back.z,\n y: back.z * right.x - right.z * back.x,\n z: right.y * back.x - back.y * right.x,\n })\n\n const axis = (v: Vector3) => {\n const by = 1 / length(v)\n\n return { x: f(v.x * by), y: f(v.y * by), z: f(v.z * by), w: 0 }\n }\n\n this.ship = { x: axis(right), y: axis(up), z: axis(back), w: { ...here, w: 1 } }\n }\n\n // A light a draw switched on flickers, in brightness and about its direction.\n const lit = this.lit\n\n if (lit?.enabled) {\n const a = f(this.random() * RAND_HALF_UNIT)\n const dim = 1 - this.random() * a * RAND_HALF_UNIT\n // `ScaleVec3` by 255, truncated and held to a byte.\n const scaled = (value: number) => clampByte(f(f(value * dim) * 255))\n\n lit.color = { x: scaled(f(0.8)), y: scaled(f(0.8)), z: scaled(1) }\n\n const d = lit.direction\n const weighted = {\n x: f(LIGHT_WEIGHT * d.x),\n y: f(LIGHT_WEIGHT * d.y),\n z: f(LIGHT_WEIGHT * d.z),\n }\n const randZ = this.random() * RAND_HALF_UNIT\n const randY = this.random() * RAND_HALF_UNIT\n const jitterX = this.random() * RAND_HALF_UNIT * 2 - 1\n const jittered = {\n x: f(jitterX + weighted.x),\n y: f(randY * 2 - 1 + weighted.y),\n z: f(f(randZ * 2 - 1) + weighted.z),\n }\n\n lit.direction = normalize(\n jittered,\n jittered.x * jittered.x + jittered.y * jittered.y + jittered.z * jittered.z,\n )\n }\n\n for (const layer of this.layers) {\n layer.uOffset = f(step * layer.du + layer.uOffset)\n layer.vOffset = f(step * layer.dv + layer.vOffset)\n }\n }\n\n /**\n * `Draw` (`FUN_004ffab0`): each layer from 0.1 of the path ahead of the ship to 0.01 behind, one\n * strip around the tube at a time, nearer strips longer by 1.1 each. Unculled and blended, the\n * first layer by alpha and the second `ONE, INVSRCALPHA`, unlit in its vertex colour times the\n * texture, which wraps; depth written as `write_depth_buffer` says. It switches the light on.\n *\n * Depth is tested `LEQUAL`, Win3D's own state, and the alpha test and fog are what the frame left:\n * `GREATER 0` and none, as `jump_hole` captured them.\n */\n draws(): Draw[] {\n if (this.state === 0) return []\n if (this.lit) this.lit.enabled = true\n\n const draws: Draw[] = []\n\n this.layers.forEach((layer, index) => this.emitLayer(layer, index, draws))\n return draws\n }\n\n // The curves, as loading and `EnterState1` build them, in that order of `rand()`.\n private build(): void {\n const {\n controlPoints: count,\n range,\n minRadius,\n maxRadius,\n minRotation,\n maxRotation,\n } = this.settings\n const { minRgb, maxRgb } = this.settings\n\n if (count < 2) return\n // `RebuildPath(0)`: x with its first three 0, y the same, and z falling away along -Z.\n this.pathX.minimum = f(range.x * -0.5)\n this.pathX.maximum = f(range.x * 0.5)\n\n const xs = Array.from({ length: count }, () => this.pathX.draw())\n for (let i = 0; i < 3 && i < count; i++) xs[i] = 0\n this.pathX.set(xs)\n this.pathY.randomize(count, f(range.y * -0.5), f(range.y * 0.5), 3, 0)\n this.pathZ.set(Array.from({ length: count }, (_, i) => f(-((i * range.z) / count) - 5)))\n this.radius.randomize(count, minRadius, maxRadius, 0, 0)\n this.rotation.randomize(count, minRotation, maxRotation, 3, 0)\n this.offsetR.randomize(count, minRgb.x, maxRgb.x, 0, 0)\n this.offsetG.randomize(count, minRgb.y, maxRgb.y, 0, 0)\n this.offsetB.randomize(count, minRgb.z, maxRgb.z, 0, 0)\n this.brightness.randomize(count, 0.5, 1, 0, 0)\n }\n\n // `EnterState1`'s light: white, down, the first draw kept for z.\n private makeLight(): void {\n const randZ = this.random() * RAND_HALF_UNIT\n const x = f(this.random() * RAND_HALF_UNIT * 2 - 1)\n const z = f(randZ * 2 - 1)\n const direction = normalize({ x, y: -5, z }, 25 + z * z + x * x)\n\n this.lit = { color: { x: 255, y: 255, z: 255 }, direction, enabled: false }\n }\n\n // `HudTransformPoint` of the path at `t`, sampled z, y, x.\n private pathPoint(t: number): Vector3 {\n const local = {\n x: f(this.pathX.sample(t)),\n y: f(this.pathY.sample(t)),\n z: f(this.pathZ.sample(t)),\n }\n\n return round(Matrix4.transformPoint(local, this.frame))\n }\n\n private pathFrame(t: number): PathFrame {\n const aheadSum = t + FRAME_STEP\n const ahead = aheadSum > 1 ? f(t - FRAME_STEP) : f(aheadSum)\n const point = this.pathPoint(t)\n const next = this.pathPoint(ahead)\n const delta = round({ x: next.x - point.x, y: next.y - point.y, z: next.z - point.z })\n const inverse = 1 / length(delta)\n const forward = {\n x: f(-(delta.x * inverse)),\n y: f(-(delta.y * inverse)),\n z: f(-(delta.z * inverse)),\n }\n // `F × (0, 1, 0)`, negated: the left axis, then `F × L`.\n const left = {\n x: -f(forward.y * 0 - forward.z),\n y: -f(forward.z * 0 - forward.x * 0),\n z: -f(forward.x),\n }\n const up = round({\n x: left.z * forward.y - left.y * forward.z,\n y: forward.z * left.x - left.z * forward.x,\n z: left.y * forward.x - forward.y * left.x,\n })\n\n return { left, up, point }\n }\n\n // `EmitLayer` (`FUN_004ffe50`), with `num_t_steps` negated as `Draw` has it: from ahead, back.\n private emitLayer(layer: TunnelLayer, index: number, draws: Draw[]): void {\n const { tSteps, sSteps, farRadiusFactor, writeDepth } = this.settings\n let step = f(1 / -tSteps)\n const ringStep = f(1 / sSteps)\n const phase = this.phase\n const clamp = (value: number) => (1 < value ? 1 : 0 > value ? 0 : value)\n const startSum = clamp(WINDOW_AHEAD + phase)\n const start = f(startSum)\n const end = f(clamp(WINDOW_BEHIND + phase))\n const span = f(Math.abs(end - startSum))\n const color = layer.color\n\n let t = start\n\n for (;;) {\n if (step > 0 ? !(t < end) : !(t > end)) break\n\n const grown = STEP_GROWTH * step\n\n step = f(grown)\n\n const unclamped = f(t + grown)\n let next = 0 > unclamped ? 0 : unclamped\n if (grown > 0 ? end < next : end > next) next = end\n\n const fraction = (at: number) => f(clamp(Math.abs(at - phase) / span))\n\n // Radius lerps to `radius × farRadiusFactor` by how far `at` is from the ship, over the window.\n const size = (at: number) => {\n const radius = this.radius.sample(at) * layer.radiusFactor\n\n return f((radius * farRadiusFactor - radius) * fraction(at) + radius)\n }\n\n const size0 = size(t)\n const size1 = size(next)\n const frame0 = this.pathFrame(t)\n const frame1 = this.pathFrame(next)\n\n // Alpha from far to near, as the step runs backwards, cubed.\n const [from, to] =\n step < 0 ? [layer.farAlpha, layer.nearAlpha] : [layer.nearAlpha, layer.farAlpha]\n\n const progress = (at: number) => {\n const p = Math.abs(at - start) / span + ALPHA_BIAS\n\n return p < 1 ? p : 1\n }\n\n const alphaRange = to - from\n const base0 = f(alphaRange * progress(t) + from)\n const alpha0 = f(base0 * base0 * base0)\n const base1 = progress(next) * f(alphaRange) + from\n const alpha1 = f(base1 * base1 * base1)\n\n // Blue reads the red offsets, checked in `Freelancer-original.exe` (`0x500543`, `0x5005ce`\n // load `[esi+0x1bc]`): the blue curve is built and never sampled.\n const tint = (at: number, last: boolean) => {\n const r = f(this.offsetR.sample(at))\n const g = f(this.offsetG.sample(at))\n const b = last ? this.offsetR.sample(at) : f(this.offsetR.sample(at))\n const shade = this.brightness.sampleRounded(at)\n\n return [\n f(f(color.x + r) * shade),\n f(f(color.y + g) * shade),\n f(shade * f(color.z + b)),\n ] as const\n }\n\n const tint0 = tint(t, false)\n const tint1 = tint(next, true)\n\n const vertices: number[][] = []\n const colors: number[][] = []\n\n // A ring vertex: path point + left · r cos + up · r sin.\n const place = ({ left, up, point }: PathFrame, radius: number, cos: number, sin: number) => {\n const x = f(radius * cos)\n const y = f(radius * sin)\n const turned = round({\n x: left.x * x + up.x * y,\n y: left.y * x + up.y * y,\n z: left.z * x + up.z * y,\n })\n\n return [f(point.x + turned.x), f(point.y + turned.y), f(point.z + turned.z)]\n }\n\n // Around the ring in turns, a vertex on each end per angle (a strip); `sum <= 1` repeats the\n // first angle at 1 to close it.\n let angle = 0\n\n for (;;) {\n const radians = angle * TWO_PI\n const cos = Math.cos(radians)\n const sin = Math.sin(radians)\n const u = f(angle + layer.uOffset)\n\n vertices.push([...place(frame0, size0, cos, sin), u, f(t * layer.vScale + layer.vOffset)])\n colors.push([...tint0, alpha0])\n vertices.push([\n ...place(frame1, size1, cos, sin),\n u,\n f(next * layer.vScale + layer.vOffset),\n ])\n colors.push([...tint1, alpha1])\n\n const sum = angle + ringStep\n\n angle = f(sum)\n if (!(sum <= 1)) break\n }\n\n draws.push(stripDraw(layer, index, vertices, colors, writeDepth))\n t = unclamped\n }\n }\n}\n\n// One strip, as `Win3DEnd` issues it: `D3DPT_TRIANGLESTRIP` in the world, under the camera's view.\nconst stripDraw = (\n layer: TunnelLayer,\n index: number,\n corners: readonly number[][],\n colors: readonly number[][],\n depthWrite: boolean,\n): Draw => {\n const vertices = new Uint8Array(corners.length * STRIDE)\n const view = new Float32Array(vertices.buffer)\n\n corners.forEach(([x, y, z, u, v], at) => {\n const [r, g, b, a] = colors[at]!\n\n view.set([x!, y!, z!], (at * STRIDE) / 4)\n vertices.set([byte(b!), byte(g!), byte(r!), byte(a!)], at * STRIDE + 12)\n view.set([u!, v!], (at * STRIDE + 16) / 4)\n })\n\n const mesh: VMeshData = {\n name: 'gate tunnel',\n version: 1,\n primitive: Primitive.TriangleStrip,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: corners.length - 1,\n elementCount: corners.length,\n padding: 0,\n },\n ],\n indices: Uint16Array.from(corners, (_, at) => at),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount: corners.length,\n indexStart: 0,\n indexCount: corners.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n const { texture } = layer\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: corners.length,\n world: Matrix4.identity,\n materialName: 'gate tunnel',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n // Stage 0's `ADDRESSU` and `ADDRESSV` wrap (`Draw`, `0x4ffb14`).\n ...(texture && {\n texture: { name: texture.name, entry: texture, sampler: DEFAULT_SAMPLER, uvSet: 0 },\n }),\n cull: 'none',\n depthWrite,\n depthFunc: 'lequal',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: index === 0 ? 'alpha' : 'premultiplied',\n unlit: true,\n alphaReference: 0,\n alphaFunction: 'greater',\n }\n}\n","/**\n * The effects a host places on things, kept by key and run as the game walks them:\n * `EffectTypeBucketWalk` and `FParticleEffect::TickDraw` (`0x4f8a20`), `Start` and `Kill`, in\n * `src/freelancer/Client/particle_effect.cpp`. Each frame the host says where every effect is; the\n * frame says what it saw; then each steps as the game would have. Pure, no GL.\n */\nimport type { Matrix4 } from '@treewyrm/freelancer/math'\nimport { viewMatrix } from './camera.js'\nimport { RETAIL_EFFECT_TYPES, type EffectViewOptions, type PlacedEffect } from './effect-view.js'\nimport type { DynamicEffect } from './dynamic.js'\nimport { RETAIL_SPACE_LIMITS, type SpaceEffect, type SpaceFrame, type SpaceScene } from './space.js'\n\nconst f = Math.fround\n\n/** One effect where it is this frame. */\nexport interface EffectPlacement {\n /** Names its instance across frames: the first frame a key is placed starts it. */\n key: unknown\n /** Starts its `[Effect]` afresh: the instance, its textures and its type. */\n start: () => DynamicEffect\n /** Its world transform, which it steps at and is tested by. */\n world: Matrix4\n /** `SetIntensity`'s value, its `sparam`. 0 when absent. */\n sparam?: number\n watched?: PlacedEffect['watched']\n generic?: boolean\n /**\n * Its owner let go (`FParticleEffect::Kill`, `0x4f84d0`): from the first frame that says so its\n * emitters stop and it has at most a second left. Where it goes then is still the host's.\n */\n released?: boolean\n}\n\ninterface Held {\n effect: SpaceEffect\n world: Matrix4\n sparam: number\n /** The `ALCHEMY_LOD` blend its last view gave. */\n lod: number\n /** `+0x78`, from its type at `Start` (`0x4f830f`): above 0, counted down as it's walked. */\n runTime: number\n /** When it started: a type's walk is newest first (`EffectTypeListLink`). */\n serial: number\n released: boolean\n /** Destroyed unseen, run out or played out: the key starts nothing while it's still placed. */\n ended: boolean\n}\n\n/** Ended: held so its key starts nothing, its instance released. */\nconst end = (held: Held): void => {\n held.ended = true\n held.effect.instance.release()\n}\n\nexport class PlacedEffects {\n #held = new Map<unknown, Held>()\n readonly #of = new WeakMap<SpaceEffect, Held>()\n #serial = 0\n\n /**\n * This frame's effects for `SpaceScene.effects`, newest first. A key not placed again is dropped,\n * and one that has ended stays out for as long as it's placed: the game destroys an effect it no\n * longer sees, and nothing starts it again (`0x4f789f`).\n */\n place(\n placements: readonly EffectPlacement[],\n { effectTypes = [] }: EffectViewOptions = {},\n ): SpaceEffect[] {\n const next = new Map<unknown, Held>()\n const placed: Held[] = []\n\n for (const { key, start, world, sparam = 0, watched, generic, released } of placements) {\n let held = this.#held.get(key) ?? next.get(key)\n\n if (!held) {\n const effect = start()\n const runTime =\n effectTypes[effect.type]?.runTime ?? RETAIL_EFFECT_TYPES[effect.type]?.runTime\n\n held = {\n effect,\n world,\n sparam,\n lod: 1,\n runTime: runTime ?? -1,\n serial: this.#serial++,\n released: false,\n ended: false,\n }\n }\n\n next.set(key, held)\n if (held.ended) continue\n held.world = world\n held.sparam = sparam\n\n if (released && !held.released) {\n held.released = true\n held.effect.instance.stop()\n // `0x4f8680`: under 0 or over 1, a second; a NaN is kept.\n if (held.runTime < 0 || held.runTime > 1) held.runTime = 1\n }\n\n const { instance, texture, type, visible } = held.effect\n\n held.effect = {\n instance,\n texture,\n type,\n ...(visible && { visible }),\n position: { x: world.w.x, y: world.w.y, z: world.w.z },\n ...(watched && { watched }),\n ...(generic && { generic }),\n }\n this.#of.set(held.effect, held)\n placed.push(held)\n }\n\n // One no longer placed is destroyed (`0x4f789f`), its share of the pools with it.\n for (const [key, held] of this.#held)\n if (!next.has(key) && !held.ended) held.effect.instance.release()\n\n this.#held = next\n return placed.sort((a, b) => b.serial - a.serial).map(({ effect }) => effect)\n }\n\n /**\n * After the frame, each placed effect as the walk leaves it: unseen and not `EXIST_OFFSCREEN`, it's\n * destroyed. Otherwise its run time counts down and it ends at 0, or once its effect has; then it\n * steps by `scene.step`, held to `effectMaxStep`, at its view's LOD, unless it's unseen and its type\n * isn't `UPDATE_OFFSCREEN` (`0x4f8ae9`). Not walked (`hold`), nothing happens to it.\n */\n step(scene: SpaceScene, { effectViews }: Pick<SpaceFrame, 'effectViews'>): void {\n const { effects = [], camera, effectView, limits } = scene\n const most = limits?.effectMaxStep ?? RETAIL_SPACE_LIMITS.effectMaxStep\n const dt = Math.min(scene.step ?? 0, most)\n const view = viewMatrix(camera)\n const types = effectView?.effectTypes ?? []\n\n effects.forEach((effect, at) => {\n const held = this.#of.get(effect)\n if (!held || held.ended) return\n\n const seen = effectViews[at]\n if (seen?.fate === 'hold') return\n if (seen?.fate === 'die') return end(held)\n\n if (held.runTime > 0) {\n held.runTime = f(held.runTime - dt)\n if (held.runTime <= 0) return end(held)\n }\n\n if (held.effect.instance.finished) return end(held)\n if (seen) held.lod = seen.lod\n\n const updates =\n types[effect.type]?.updateOffscreen ?? RETAIL_EFFECT_TYPES[effect.type]?.updateOffscreen\n if (seen?.fate === 'run' && !updates) return\n held.effect.instance.advance(dt, {\n placement: held.world,\n view,\n sparam: held.sparam,\n lod: held.lod,\n })\n })\n }\n\n /** Every effect held, released: for a host done with them all. */\n release(): void {\n for (const held of this.#held.values()) if (!held.ended) end(held)\n this.#held.clear()\n }\n\n /** Whether a key's effect has ended, or `undefined` where it isn't held. */\n ended(key: unknown): boolean | undefined {\n return this.#held.get(key)?.ended\n }\n}\n","/**\n * An asteroid field's `[Band]`: a ring of upright quads about its zone, seen from afar. The ring\n * (`BandBuildExclusionRings`, `FUN_0054c8b0`), each point's fade and facing (`BandUpdate`,\n * `FUN_0054d410`), its lighting, baked once (`BandBakeLighting`, `FUN_0054cfb0`), and a piece's quads\n * (`BandDrawPiece`, `FUN_0054d4e0`), all in `src/freelancer/Client/cli_asteroid.cpp`. Pure, no GL;\n * a band keeps each point's facing between frames, as retail does.\n */\nimport { Matrix4, Quat, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport type { Draw, SceneLight } from './frame.js'\nimport type { TextureShape } from './ring.js'\nimport { clampByte, unitByteRounded } from './retail.js'\n\nconst f = Math.fround\n\n/** A `[Band]` as written, over `FUN_0054c580`'s defaults. The host reads the INI. */\nexport interface BandSettings {\n /** `shape`: only its texture is used. Without one the band draws nothing. */\n shape?: TextureShape\n /** `texture_aspect`, 1 when absent; read times 1.15. */\n textureAspect?: number\n /** `height`, 1000 when absent. */\n height?: number\n /** `offset_dist` takes this from the zone's size; `offset_percent` scales the size by it. */\n offset?: { distance: number } | { percent: number }\n /** `color_shift`, 1 when absent: the field's colours are multiplied by it. */\n colorShift?: Vector3\n /** `fade`'s four distances, in heights: 1500, 2500, 100000 and 130000 when absent. */\n fade?: readonly [number, number, number, number]\n /** `vert_increase`, at least 1: points to a ring's segment, and how often U repeats. */\n vertIncrease?: number\n /** `render_parts`, 1 when absent: the pieces the ring is cut into, at most half its points. */\n renderParts?: number\n /** `cull_mode`: 1 hides the faces turned away, 2 those turned toward. 0 when absent. */\n cullMode?: number\n /** `ambient_intensity`, 1 when absent. */\n ambientIntensity?: number\n}\n\n/** What a band takes of its field: the zone's frame and `size` as written, and the field's colours. */\nexport interface BandField {\n position: Vector3\n orientation: Quat\n /** `size` as written; a sphere's has its radius in X alone. */\n size: Vector3\n /** `diffuse_color` over 255. */\n diffuse: Vector3\n /** `ambient_color` over 255. */\n ambient: Vector3\n /** `ambient_increase`, 0 to 255. */\n ambientIncrease?: Vector3\n}\n\n/** One of the pieces the frame lists: a run of the ring's points and the sphere the view tests. */\nexport interface BandPiece {\n first: number\n last: number\n center: Vector3\n radius: number\n}\n\n/** What the bake lights a band with: the system's `[Ambient]` as written, and the lights it found. */\nexport interface BandLighting {\n ambient: Vector3\n /** How many lights `CollectNearbyLights` found. With none, nothing is baked. */\n found: number\n lights: readonly SceneLight[]\n}\n\n// `DAT_006140a4`: how far round the back a light still reaches.\nconst SOFT = 0.75\n// `DAT_005d3e08`, `DAT_005c75e0`, `DAT_005e0a60`: edge-on, a point fades out.\nconst EDGE_HIDDEN = f(0.3)\nconst EDGE_FADED = 0.5\nconst EDGE_SLOPE = 5\n// `DAT_005c99c8`: below this a point is transparent.\nconst LEAST_ALPHA = f(0.01)\nconst TWO_PI = f(6.28318548)\nconst PI = f(3.14159274)\n\n// XYZ, D3DCOLOR and one UV set: FVF 0x142, 24 bytes, as Win3D's immediate mode draws.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\n\nconst BLACK: Vector3 = { x: 0, y: 0, z: 0 }\nconst WHITE: Vector3 = { x: 1, y: 1, z: 1 }\n\n// `ScaleClampToByte`: times 255, truncated, held to a byte.\nconst byte = unitByteRounded\n\n// The tint clamp of `FUN_0054d970`: an upper bound only.\nconst tint = (value: number): number => (value < 1 ? value : 1)\n\n/** `FUN_00422b80`'s even test, which `BandBuildExclusionRings` picks a piece's centre by. */\nconst even = (n: number): boolean => (n & 1) === 0\n\nexport class AsteroidBand {\n readonly settings: BandSettings\n /** Its zone's centre, where it is lit. */\n readonly position: Vector3\n /**\n * `+0x54`: what its alpha is held under. The field's own band keeps 1; an `[ExclusionBand]` takes\n * `nearFieldFraction` each frame.\n */\n private maxAlpha = 1\n /** Each point of the ring, in world space, with its outward normal. */\n readonly points: readonly { position: Vector3; normal: Vector3 }[]\n readonly halfHeight: number\n readonly pieces: readonly BandPiece[]\n /** The squares of the four fade distances, in world units. */\n private readonly fades: readonly [number, number, number, number]\n private readonly diffuse: Vector3\n private readonly ambient: Vector3\n private readonly increase: Vector3\n /** `+0x34` and `+0x38` of each point: its fade, and whether the camera is on its normal's side. */\n private readonly fade: Float32Array\n private readonly facing: Uint8Array\n /** `+0x1c` and `+0x28`: the colour seen from the normal's side, and from behind. */\n private front: Vector3[]\n private back: Vector3[]\n private baked = false\n\n constructor(settings: BandSettings, field: BandField) {\n this.settings = settings\n this.position = field.position\n\n const shift = settings.colorShift ?? WHITE\n\n // `BandApplyTints` and `BandSetAmbientIncrease`, as the field's `[Band]` is read.\n this.diffuse = {\n x: tint(f(shift.x * field.diffuse.x)),\n y: tint(f(shift.y * field.diffuse.y)),\n z: tint(f(shift.z * field.diffuse.z)),\n }\n this.ambient = {\n x: tint(f(shift.x * field.ambient.x)),\n y: tint(f(shift.y * field.ambient.y)),\n z: tint(f(shift.z * field.ambient.z)),\n }\n\n const raise = field.ambientIncrease ?? BLACK\n\n this.increase = { x: f(raise.x / 255), y: f(raise.y / 255), z: f(raise.z / 255) }\n\n const sizeX = f(field.size.x)\n const sizeZ = field.size.z < 0.1 ? sizeX : f(field.size.z)\n const aspect = f((settings.textureAspect ?? 1) * 1.15)\n const height = f(settings.height ?? 1000)\n const vertIncrease = Math.max(Math.trunc(settings.vertIncrease ?? 1), 1)\n // Points on the ring: the ellipse's perimeter, about π(a + b), in quad widths, rounded.\n const count =\n Math.trunc(f(f(f(f(sizeX + sizeZ) * PI) / f(aspect * height)) + 0.5)) * vertIncrease\n const [inner, near, far, outer] = (settings.fade ?? [1500, 2500, 100000, 130000]).map((d) =>\n f(f(d * height) * f(d * height)),\n ) as [number, number, number, number]\n\n this.fades = [inner, near, far, outer]\n this.halfHeight = f(height * 0.5)\n\n const offset = settings.offset ?? { distance: 0 }\n const [radiusX, radiusZ] =\n 'distance' in offset\n ? [f(sizeX - offset.distance), f(sizeZ - offset.distance)]\n : [f(sizeX * offset.percent), f(sizeZ * offset.percent)]\n\n // The zone's frame as `ZoneToTransform` gives a ring's: its own X and Z where its axes are, as\n // `zoneOf`'s. A tilted band is uncaptured.\n const positions = Array.from({ length: count }, (_, at) => {\n const angle = f(f(at / count) * TWO_PI)\n const local = { x: f(Math.cos(angle) * radiusX), y: 0, z: f(Math.sin(angle) * radiusZ) }\n const turned = Quat.transform(local, field.orientation)\n\n return {\n x: f(f(turned.x) + field.position.x),\n y: f(f(turned.y) + field.position.y),\n z: f(f(turned.z) + field.position.z),\n }\n })\n\n // Each point's normal: the average of the two neighbouring chords', each crossed with world up.\n const outward = (from: Vector3, to: Vector3): Vector3 => {\n const dx = f(to.x - from.x)\n const dz = f(to.z - from.z)\n const length = f(Math.sqrt(f(dz * dz + dx * dx)))\n\n return { x: f(dz / length), y: 0, z: f(-dx / length) }\n }\n\n this.points = positions.map((position, at) => {\n const previous = positions[(at - 1 + count) % count]!\n const next = positions[(at + 1) % count]!\n const a = outward(position, next)\n const b = outward(previous, position)\n const sum = { x: f(a.x + b.x), z: f(a.z + b.z) }\n const length = Math.sqrt(sum.x * sum.x + sum.z * sum.z)\n\n return { position, normal: { x: f(sum.x / length), y: 0, z: f(sum.z / length) } }\n })\n\n // `render_parts`, held to half the points, each a run from where the last ended.\n // Run ends are `trunc(k · count / parts)`, accumulated as floats; `middle` is the run's midpoint.\n let parts = Math.max(Math.trunc(settings.renderParts ?? 1), 1)\n if (parts > f(count * 0.5)) parts = Math.trunc(f(count * 0.5))\n\n const step = f(count / parts)\n let total = 0\n let start = 0\n const pieces: BandPiece[] = []\n\n for (let index = 0; index < parts && count > 0; index++) {\n total = f(total + step)\n\n const end = Math.trunc(f(total + f(0.0001)))\n const span = end - start\n let middle = start - Math.trunc(f(span * -0.5))\n if (middle >= count) middle -= count\n\n const a = positions[middle]!\n\n // An even run's centre is between its middle point and the next, off by half a segment, as\n // `Freelancer-original.exe` has it (`0x54ce17`..`0x54ce46`). The view tests that sphere.\n const center = even(span)\n ? (() => {\n const b = positions[middle + 1 >= count ? middle + 1 - count : middle + 1]!\n\n return { x: f(f(a.x + b.x) * 0.5), y: f(f(a.y + b.y) * 0.5), z: f(f(a.z + b.z) * 0.5) }\n })()\n : a\n\n const reach = (point: Vector3) =>\n f(Math.hypot(f(center.x - point.x), f(center.y - point.y), f(center.z - point.z)))\n const radius = Math.max(\n reach(positions[start >= count ? start - count : start]!),\n reach(positions[end >= count ? end - count : end]!),\n )\n\n pieces.push({ first: start, last: end, center, radius })\n start = end\n }\n\n this.pieces = pieces\n\n this.fade = new Float32Array(count).fill(1)\n this.facing = new Uint8Array(count).fill(1)\n this.front = Array.from({ length: count }, () => WHITE)\n this.back = Array.from({ length: count }, () => ({ x: f(0.2), y: f(0.2), z: f(0.2) }))\n }\n\n /**\n * `BandUpdate`: each point's fade from the camera, in by `fade`'s first two distances and out by\n * its last two, and edge-on below a |cos| of 0.5. Where it's faded out past the far end, its\n * facing is last frame's. `maxAlpha` is kept for the draw; under 0.001 nothing else is updated.\n */\n update(eye: Vector3, maxAlpha = 1): void {\n this.maxAlpha = maxAlpha\n if (maxAlpha < 0.001) return\n\n const [inner, near, far, outer] = this.fades\n\n this.points.forEach(({ position, normal }, at) => {\n const dx = f(eye.x - position.x)\n const dy = f(eye.y - position.y)\n const dz = f(eye.z - position.z)\n const squared = dx * dx + dz * dz + dy * dy\n let fade: number\n let inside = false\n\n if (squared > near) {\n if (squared < far) fade = 1\n else if (squared > outer) fade = 0\n else fade = f((outer - squared) / (outer - far))\n } else if (squared < inner) {\n fade = 0\n inside = true\n } else fade = f((squared - inner) / (near - inner))\n\n this.fade[at] = fade\n if (!(fade > 0) && !inside) return\n\n const inverse = 1 / Math.sqrt(squared)\n const dot = dz * inverse * normal.z + dy * inverse * normal.y + dx * inverse * normal.x\n\n this.facing[at] = dot > 0 ? 1 : 0\n\n const edge = f(Math.abs(dot))\n\n if (edge < EDGE_HIDDEN) this.fade[at] = 0\n else if (edge < EDGE_FADED) this.fade[at] = f(f(f(edge - EDGE_HIDDEN) * fade) * EDGE_SLOPE)\n })\n }\n\n /** Whether `bake` has run with lights to bake. */\n get isBaked(): boolean {\n return this.baked\n }\n\n /**\n * `BandBakeLighting`, once: both sides of each point, the ambient plus each light's diffuse by how\n * squarely it falls, softened round the back, and held under 1. The ambient is the system's\n * raised by `ambient_increase`, in the band's ambient tint, times `ambient_intensity`.\n */\n bake({ ambient, found, lights }: BandLighting): void {\n if (found <= 0) return\n\n const intensity = f(this.settings.ambientIntensity ?? 1)\n const system = (value: number) => f(clampByte(value) * 0.003921569)\n const base = {\n x: f(f(f(system(ambient.x) + this.increase.x) * this.ambient.x) * intensity),\n y: f(f(f(system(ambient.y) + this.increase.y) * this.ambient.y) * intensity),\n z: f(f(f(system(ambient.z) + this.increase.z) * this.ambient.z) * intensity),\n }\n const { diffuse } = this\n\n // The normal at `+0x10` (`0x54d169`, `[ebx - 4]` from `+0x14`): the decomp reads a float later.\n const sides = this.points.map(({ normal }) => {\n const a = { ...base }\n const b = { ...base }\n\n for (const { direction, color } of lights) {\n const dot = direction.x * normal.x + direction.y * normal.y + direction.z * normal.z\n\n // Wrapped diffuse, `t` from 0 at a dot of -`SOFT` to 1 at 1; `a` takes it for the flipped dot.\n if (-SOFT < dot) {\n const t = (SOFT + dot) / (SOFT + 1)\n\n b.x = f(b.x + color.x * diffuse.x * t)\n b.y = f(b.y + color.y * diffuse.y * t)\n b.z = f(b.z + color.z * diffuse.z * t)\n }\n\n if (-SOFT < -dot) {\n const t = (SOFT - dot) / (SOFT + 1)\n\n a.x = f(a.x + color.x * diffuse.x * t)\n a.y = f(a.y + color.y * diffuse.y * t)\n a.z = f(a.z + color.z * diffuse.z * t)\n }\n }\n\n const hold = ({ x, y, z }: Vector3) => ({\n x: Math.min(x, 1),\n y: Math.min(y, 1),\n z: Math.min(z, 1),\n })\n\n return { front: hold(a), back: hold(b) }\n })\n\n this.front = sides.map(({ front }) => front)\n this.back = sides.map(({ back }) => back)\n this.baked = true\n }\n\n /**\n * `BandDrawPiece`: a quad between each two points of the piece, in two passes, those with either end\n * turned away and then those turned toward; each end in its side's colour and its fade, under\n * the alpha `update` was given, U stepping by `vert_increase`. A quad with both ends transparent is left out, and a\n * piece with none draws nothing. Unlit, blended, both sides, with no depth test or writes.\n */\n pieceDraw(index: number): Draw | undefined {\n const { maxAlpha } = this\n const { shape } = this.settings\n if (!shape || maxAlpha < LEAST_ALPHA) return undefined\n\n const piece = this.pieces[index] ?? this.pieces[0]\n if (!piece) return undefined\n\n const count = this.points.length\n const vertIncrease = Math.max(Math.trunc(this.settings.vertIncrease ?? 1), 1)\n const inverse = f(1 / vertIncrease)\n const cull = this.settings.cullMode ?? 0\n const corners: number[] = []\n const colours: number[] = []\n let cursor = 0\n let next = 1\n\n for (let pass = 0; pass < 2; pass++) {\n if (pass + 1 === cull || piece.first >= piece.last) continue\n\n for (let at = piece.first; at < piece.last; at++) {\n // `cursor` and `next` count a quad's ends in segments; U wraps every `vert_increase` of them.\n if (next > vertIncrease) {\n cursor -= vertIncrease\n next -= vertIncrease\n }\n\n const other = at + 1 >= count ? at + 1 - count : at + 1\n const [facesA, facesB] = [this.facing[at]!, this.facing[other]!]\n const drawn = pass === 0 ? facesA === 0 || facesB === 0 : facesA !== 0 && facesB !== 0\n\n if (drawn) {\n const end = (point: number, faces: number) => {\n let alpha = this.fade[point]!\n if ((faces === 0 && cull === 1) || (faces !== 0 && cull === 2)) alpha = 0\n return { alpha, color: faces === 0 ? this.back[point]! : this.front[point]! }\n }\n\n const a = end(at, facesA)\n const b = end(other, facesB)\n\n if (!(a.alpha < LEAST_ALPHA) || !(b.alpha < LEAST_ALPHA)) {\n const u0 = f(cursor * inverse)\n const u1 = f(next * inverse)\n const half = this.halfHeight\n const pa = this.points[at]!.position\n const pb = this.points[other]!.position\n const colourOf = ({ color }: typeof a, alpha: number) => [\n byte(color.z),\n byte(color.y),\n byte(color.x),\n byte(alpha),\n ]\n const ca = colourOf(a, maxAlpha < a.alpha ? maxAlpha : a.alpha)\n const cb = colourOf(b, maxAlpha < b.alpha ? maxAlpha : b.alpha)\n const top = (p: Vector3) => [p.x, f(p.y + half), p.z]\n const bottom = (p: Vector3) => [p.x, f(p.y - half), p.z]\n\n // Two triangles: the quad between the points' top and bottom edges, `half` above and below.\n for (const [corner, colour, u, v] of [\n [top(pa), ca, u0, 1],\n [bottom(pa), ca, u0, 0],\n [bottom(pb), cb, u1, 0],\n [bottom(pb), cb, u1, 0],\n [top(pb), cb, u1, 1],\n [top(pa), ca, u0, 1],\n ] as const) {\n corners.push(...corner, u, v)\n colours.push(...colour)\n }\n }\n }\n\n cursor++\n next++\n }\n }\n\n const vertexCount = corners.length / 5\n if (vertexCount === 0) return undefined\n\n const vertices = new Uint8Array(vertexCount * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n // Interleaves into 24-byte vertices: xyz at 0, BGRA bytes at 12, uv at 16.\n for (let at = 0; at < vertexCount; at++) {\n floats.set(corners.slice(at * 5, at * 5 + 3), (at * STRIDE) / 4)\n vertices.set(colours.slice(at * 4, at * 4 + 4), at * STRIDE + 12)\n floats.set(corners.slice(at * 5 + 3, at * 5 + 5), (at * STRIDE + 16) / 4)\n }\n\n const mesh: VMeshData = {\n name: 'band',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: vertexCount - 1,\n elementCount: vertexCount,\n padding: 0,\n },\n ],\n indices: Uint16Array.from({ length: vertexCount }, (_, at) => at),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount,\n indexStart: 0,\n indexCount: vertexCount,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: piece.center, max: piece.center },\n boundingSphere: { center: piece.center, radius: piece.radius },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: vertexCount,\n world: Matrix4.identity,\n materialName: 'band',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: {\n name: shape.texture.name,\n entry: shape.texture,\n sampler: DEFAULT_SAMPLER,\n uvSet: 0,\n },\n cull: 'none',\n depthWrite: false,\n // `FUN_00522850` turns the depth test off and the far plane to 250000 on either list.\n depthFunc: 'always',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n blend: true,\n blendMode: 'alpha',\n unlit: true,\n // `ALPHAREF` 5 around it; the test and its `GREATER` are the frame's, as captured.\n alphaReference: 5,\n alphaFunction: 'greater',\n }\n }\n}\n","/**\n * `[Clouds]`: puffs about the camera, which a planet ring and a nebula share. `FNebulaClouds` in\n * `src/freelancer/Client/cli_nebula.cpp` (parse, seed, update) and `TexturePanelDrawClouds`\n * (`FUN_00551500`) in `texture_panels.cpp`. Seeded and respawned by the game's `rand()`, so a run\n * matches retail in kind, never puff for puff. Its lightning bolts are a nebula's, not built here.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport {\n Primitive,\n setMapCount,\n VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\nimport { DEFAULT_SAMPLER } from '#/texture/texture.js'\nimport { viewMatrix, type Camera } from './camera.js'\nimport type { Draw } from './frame.js'\nimport type { Random } from './lightning.js'\nimport type { TextureShape } from './ring.js'\nimport { insideSphere, inverseRoot, onSphere, RAND_UNIT } from './retail.js'\n\nconst f = Math.fround\n\n/** A `[Clouds]` section, over `FUN_00550240`'s defaults. The host reads the INI. */\nexport interface CloudSettings {\n /** `puff_count`. */\n puffCount: number\n /** `puff_radius`, 50 when absent. */\n puffRadius?: number\n /** `puff_colora` and `puff_colorb` over 255: each puff's colour lies between. B is A when absent. */\n colorA?: Vector3\n colorB?: Vector3\n /** `puff_shape`s, at most eight, one texture between them: the first's is bound for all. */\n shapes: readonly (TextureShape | undefined)[]\n /** `puff_weights`, one a shape. Even when absent. */\n weights?: readonly number[]\n /** `puff_max_alpha`, 0.75 when absent. */\n maxAlpha?: number\n /** `puff_drift`: how fast a puff wanders. 0 when absent. */\n drift?: number\n /** `max_distance`, 1500 when absent: the puffs' sphere is half of it plus a puff's radius. */\n maxDistance?: number\n /** `near_fade_distance`, 50 and 100 when absent: nearer than the first, nothing. */\n nearFade?: readonly [number, number]\n /** `lightning_color` over 255, `lightning_intensity` and its timing: a puff's flash. */\n lightning?: { color: Vector3; intensity?: number; gap: number; duration: number }\n /** `disable_lightning_flash`. */\n disableFlash?: boolean\n}\n\n/**\n * How the owner's visibility drives its puffs: past `full` they're opaque, `budget` of it allows all\n * of them, and under `spawn` a puff is placed only where the owner holds it. A nebula's are 0.1, 0.3\n * and 0.3 (`FUN_00550240`); a ring sets its own.\n */\nexport interface CloudVisibility {\n full: number\n budget: number\n spawn: number\n}\n\nexport const NEBULA_CLOUD_VISIBILITY: Readonly<CloudVisibility> = {\n full: f(0.1),\n budget: f(0.3),\n spawn: f(0.3),\n}\n\n/** `PlanetRing::Load` (`0x50a735`). */\nexport const RING_CLOUD_VISIBILITY: Readonly<CloudVisibility> = {\n full: 0.5,\n budget: f(0.9),\n spawn: f(1.1),\n}\n\ninterface Puff {\n position: Vector3\n size: number\n color: Vector3\n shape: number\n velocity: Vector3\n /** The drift's clock, negative while it waits. -1 with no lightning. */\n timer: number\n /** `+0x3c`, how much of the lightning colour it flashes. */\n flash: number\n active: boolean\n hidden: boolean\n /** Its depth in view at the last draw: the order puffs are kept in. */\n depth: number\n}\n\n// XYZ, D3DCOLOR and one UV set: FVF 0x142, 24 bytes.\nconst FORMAT = setMapCount(VertexFormat.Position | VertexFormat.Diffuse, 1)\nconst STRIDE = 24\n\nconst BLACK = { x: 0, y: 0, z: 0 }\n\nexport interface CloudDrawOptions {\n /** The camera cut this frame (`+0xbc`): the puffs are placed afresh first. */\n cut?: boolean\n /** How far a point is in what holds the clouds, which a fresh puff must be. */\n holds?: (point: Vector3) => number\n /** How far a point is in an exclusion zone of the owner's: past 0.9, a puff there is hidden. */\n excluded?: (point: Vector3) => number\n}\n\n// `DAT_005e0e00`: how deep in an exclusion zone hides a puff.\nconst EXCLUDED = f(0.9)\n\nexport class Clouds {\n readonly settings: CloudSettings\n readonly visibility: CloudVisibility\n readonly random: Random\n #puffs: Puff[] = []\n /** Its sphere's radius (`+0x100`). */\n readonly radius: number\n /** How far past the near fade its sphere stands (`+0xbc`). */\n readonly reach: number\n #fade = 0\n #budget = 0\n #active = 0\n /** `+0xf4`: where its sphere is, ahead of the camera. */\n #centre: Vector3 = BLACK\n /** `+0x6c`: the billboards' up, kept across frames. */\n #up: Vector3\n\n constructor(\n settings: CloudSettings,\n {\n visibility = NEBULA_CLOUD_VISIBILITY,\n random = () => Math.floor(Math.random() * 0x8000),\n detail = 1,\n }: { visibility?: CloudVisibility; random?: Random; detail?: number } = {},\n ) {\n this.settings = settings\n this.visibility = visibility\n this.random = random\n\n const n = 1 / Math.SQRT2\n\n this.#up = { x: f(n), y: f(n), z: 0 }\n\n const puffRadius = f(settings.puffRadius ?? 50)\n const maxDistance = f(settings.maxDistance ?? 1500)\n\n this.radius = f(maxDistance * 0.5 + puffRadius)\n\n // `FUN_00550a94`: how far ahead the sphere goes so the near fade's cone stays inside it.\n const [near] = settings.nearFade ?? [50, 100]\n\n if (near > 0) {\n const tan = Math.tan(0.6108652551968893)\n const a = f((this.radius * f(0.8)) / tan - near)\n const b = (tan * near + puffRadius * f(1.2)) * 1.25\n let x = b > this.radius ? a : Math.sqrt(this.radius * this.radius - b * b)\n if (x > a) x = a\n\n const result = x + near - this.radius\n\n this.reach = result < 0 ? 0 : f(result)\n } else this.reach = 0\n\n // `CloudsDetailFactors`: fewer, bigger puffs at low detail.\n const a = 1 - detail\n const countScale = f(0.5 * a + detail)\n const ease = 1 - a * a\n const sizeScale = f((1 - ease) * f(0.707) + ease)\n\n // `FUN_00550b60`: each puff somewhere in its sphere, about the origin until the first update.\n const count = Math.trunc(settings.puffCount * countScale + 0.5)\n const weights = this.#weights()\n const colorA = settings.colorA ?? BLACK\n const colorB = settings.colorB ?? colorA\n\n for (let index = 0; index < count; index++) {\n const position = insideSphere(random, this.radius)\n const size = f(\n (random() * RAND_UNIT * 0.40000003576278687 + f(0.8)) * f(puffRadius * sizeScale),\n )\n const t = random() * RAND_UNIT\n const color = {\n x: f(f(colorB.x - colorA.x) * t + colorA.x),\n y: f(f(f(colorB.y - colorA.y) * t) + colorA.y),\n z: f(f(f(colorB.z - colorA.z) * t) + colorA.z),\n }\n // Weighted pick by running sum of `weights`; the first draw is the fallback past rounding.\n let shape = Math.trunc((random() * weights.length) / 32768)\n const pick = f(random() * RAND_UNIT)\n let running = 0\n\n for (let at = 0; at < weights.length; at++) {\n running += weights[at]!\n\n if (pick < running) {\n shape = at\n break\n }\n }\n\n const velocity = insideSphere(random, f(settings.drift ?? 0))\n const lightning = settings.lightning\n const timer =\n lightning && lightning.duration > 0\n ? f((-0.800000011920929 - random() * RAND_UNIT * 0.699999988079071) * lightning.gap)\n : -1\n\n this.#puffs.push({\n position,\n size,\n color,\n shape,\n velocity,\n timer,\n flash: 0,\n active: true,\n hidden: false,\n depth: 0,\n })\n }\n }\n\n /**\n * `FUN_005513b0`, on a camera cut: as many as the budget allows anywhere in the sphere, the rest\n * hidden, each kept only where `holds` says the owner is, and hidden deep in an exclusion zone.\n */\n #regenerate(holds?: (point: Vector3) => number, excluded?: (point: Vector3) => number): void {\n const { random, settings } = this\n\n this.#puffs.forEach((puff, index) => {\n if (index >= this.#budget) {\n puff.active = false\n puff.hidden = true\n return\n }\n\n const sample = insideSphere(random, this.radius)\n\n puff.position = {\n x: f(this.#centre.x + sample.x),\n y: f(this.#centre.y + sample.y),\n z: f(this.#centre.z + sample.z),\n }\n puff.velocity = insideSphere(random, f(settings.drift ?? 0))\n\n const inside = holds !== undefined && holds(puff.position) > 0\n\n puff.active = inside\n puff.hidden = !inside || (excluded !== undefined && excluded(puff.position) > EXCLUDED)\n })\n }\n\n /** `puff_weights` over their sum, one a shape, even when absent. */\n #weights(): number[] {\n const { shapes, weights = [] } = this.settings\n const raw = shapes.map((_, at) => weights[at] ?? 1)\n const sum = raw.reduce((total, weight) => total + weight, 0)\n\n return raw.map((weight) => f(weight / sum))\n }\n\n /** How many are in its sphere, as of the last update. */\n get active(): number {\n return this.#active\n }\n\n get puffs(): readonly Readonly<Puff>[] {\n return this.#puffs\n }\n\n /** The first shown puff's flash on the next step, for an editor: retail has no such call. */\n fire(): void {\n const puff = this.#puffs.find(({ active, hidden }) => active && !hidden)\n\n if (puff) puff.timer = 0\n }\n\n /**\n * `FUN_00550d40`: the sphere follows the camera; puffs that left it go, and as many as\n * `visibility` allows come back on its surface, where `holds` says the owner is, and drift. One\n * back deep in an exclusion zone counts, hidden.\n */\n update(\n camera: Camera,\n step: number,\n visibility: number,\n holds?: (point: Vector3) => number,\n excluded?: (point: Vector3) => number,\n ): void {\n const { settings, random } = this\n const count = this.#puffs.length\n\n this.#budget = Math.min(\n Math.max(Math.trunc((visibility / this.visibility.budget) * count), 0),\n count,\n )\n this.#fade =\n visibility > this.visibility.full\n ? 1\n : visibility <= 0\n ? 0\n : visibility / this.visibility.full\n\n const ahead = f(this.reach + this.radius)\n const cull = f(this.radius * this.radius * f(1.02))\n const frame = Matrix4.fromRotationTranslation(camera.orientation, camera.position)\n const { x, y, z } = Matrix4.transformPoint({ x: 0, y: 0, z: -ahead }, frame)\n\n this.#centre = { x: f(x), y: f(y), z: f(z) }\n\n let active = 0\n\n for (const puff of this.#puffs) {\n if (this.#fade <= 0) {\n puff.active = false\n puff.hidden = true\n }\n\n if (!puff.active) continue\n\n const dx = this.#centre.x - puff.position.x\n const dy = this.#centre.y - puff.position.y\n const dz = this.#centre.z - puff.position.z\n\n if (dz * dz + dy * dy + dx * dx > cull) {\n puff.active = false\n puff.hidden = true\n } else active++\n }\n\n // Nearest first by the last draw's depth (`DAT_006140b0` 1): a stable sort, as a bubble sort is.\n this.#puffs.sort((a, b) => b.depth - a.depth)\n\n const lightning = settings.lightning\n\n for (const puff of this.#puffs) {\n if (!puff.active && active < this.#budget) {\n const on = onSphere(random)\n const position = {\n x: f(this.radius * on.x + this.#centre.x),\n y: f(this.radius * on.y + this.#centre.y),\n z: f(f(this.radius * on.z) + this.#centre.z),\n }\n\n puff.position = position\n puff.velocity = insideSphere(random, f(settings.drift ?? 0))\n\n if (visibility >= this.visibility.spawn || (holds && holds(position) > 0)) {\n active++\n puff.active = true\n puff.hidden = excluded !== undefined && excluded(position) > EXCLUDED\n }\n }\n\n if (!puff.active || puff.hidden) continue\n\n if (lightning && lightning.duration > 0) {\n const old = puff.timer\n\n puff.timer = f(step + old)\n\n if (old >= 0) {\n if (puff.timer > lightning.duration)\n puff.timer = f(\n (-0.800000011920929 - random() * RAND_UNIT * 0.699999988079071) * lightning.gap,\n )\n } else if (puff.timer >= 0) {\n // The drift direction it picks here is read only by a nebula's bolts: its two draws are\n // taken, and the direction isn't kept.\n random()\n random()\n }\n\n if (puff.timer >= 0) {\n const a = f(random() * RAND_UNIT)\n\n puff.flash = f(random() * a * RAND_UNIT)\n }\n }\n\n const p = puff.position\n\n puff.position = {\n x: f(step * puff.velocity.x + p.x),\n y: f(step * puff.velocity.y + p.y),\n z: f(f(step * puff.velocity.z) + p.z),\n }\n }\n\n this.#active = active\n }\n\n /**\n * `TexturePanelDrawClouds`: each puff a square facing the camera, turned to the kept up, faded\n * near the camera and toward its sphere's edge, all in one list of the first shape's texture.\n * Unlit, blended, both sides, no depth writes, the alpha test at 5. Nothing with none active.\n * Its depth function is the main list's, `LEQUAL`, and it draws in view space.\n */\n draw(camera: Camera, { cut = false, holds, excluded }: CloudDrawOptions = {}): Draw | undefined {\n const { settings } = this\n\n if (cut) this.#regenerate(holds, excluded)\n\n const first = settings.shapes[0]\n if (this.#active === 0 || !first) return undefined\n\n const view = viewMatrix(camera)\n const frame = Matrix4.invert(view)\n\n // The kept up, laid in the plane facing the camera, then into view space.\n const w = Matrix4.transformDirection({ x: 0, y: 0, z: 1 }, frame)\n const n = this.#up\n const c1 = {\n x: f(w.z * n.y - w.y * n.z),\n y: f(w.x * n.z - w.z * n.x),\n z: f(w.y * n.x - w.x * n.y),\n }\n let up = {\n x: f(w.y * c1.z - w.z * c1.y),\n y: f(w.z * c1.x - w.x * c1.z),\n z: f(w.x * c1.y - w.y * c1.x),\n }\n const inverse = inverseRoot(f(up.x * up.x + up.y * up.y + up.z * up.z))\n\n up = { x: f(inverse * up.x), y: f(inverse * up.y), z: f(inverse * up.z) }\n this.#up = up\n\n // In view space: `p` is the up's direction on screen and `q` its perpendicular, both unit XY.\n const v = Matrix4.transformDirection(up, view)\n const vi = inverseRoot(f(v.x * v.x + v.y * v.y))\n const p = { x: f(v.x * vi), y: f(v.y * vi), z: 0 }\n let q = { x: p.y, y: -p.x, z: 0 }\n const qi = inverseRoot(f(q.y * q.y + q.z * q.z + q.x * q.x))\n\n q = { x: f(q.x * qi), y: f(q.y * qi), z: 0 }\n\n const radiusSquared = f(this.radius * this.radius)\n const inner = f(this.radius * f(0.7))\n const innerSquared = f(inner * inner)\n const ring = f(1 / (radiusSquared - innerSquared))\n const [nearLow, nearHigh] = (settings.nearFade ?? [50, 100]).map(f) as [number, number]\n const nearSpan = f(1 / (nearHigh - nearLow))\n const ahead = f(this.reach + this.radius)\n const threshold = f(ahead * f(0.8))\n const lightning = settings.lightning\n const intensity = lightning?.intensity ?? 1\n\n const corners: number[] = []\n const colours: number[] = []\n\n for (const puff of this.#puffs) {\n let alpha = f(f(settings.maxAlpha ?? 0.75) * this.#fade)\n\n if (!puff.active || puff.hidden) continue\n\n const at = Matrix4.transformPoint(puff.position, view)\n const depth = -at.z\n\n puff.depth = f(depth)\n if (depth < nearLow) continue\n\n // Past `threshold` the alpha ramps linearly in squared distance from the sphere's centre,\n // from 0.7 of its radius to the edge.\n if (depth > threshold) {\n const dx = 0 - at.x\n const dy = 0 - at.y\n const dz = -ahead - at.z\n const squared = dz * dz + dy * dy + dx * dx\n if (squared > radiusSquared) continue\n if (f(squared) > innerSquared) alpha = f((radiusSquared - f(squared)) * alpha * ring)\n }\n\n if (alpha < 0.02) continue\n\n let near = alpha\n\n if (puff.depth <= nearLow) continue\n if (puff.depth < nearHigh) near = f((puff.depth - nearLow) * alpha * nearSpan)\n if (near < 0.02) continue\n\n let color = puff.color\n\n if (lightning && !settings.disableFlash && intensity > 0 && puff.timer >= 0) {\n const flash = (c: number) => f(f(c * puff.flash) * intensity)\n const sum = {\n x: f(color.x + flash(lightning.color.x)),\n y: f(color.y + flash(lightning.color.y)),\n z: f(color.z + flash(lightning.color.z)),\n }\n\n color = { x: Math.min(sum.x, 1), y: Math.min(sum.y, 1), z: Math.min(sum.z, 1) }\n }\n\n const shape = settings.shapes[puff.shape]\n if (!shape) continue\n\n // `_ftol` truncates, and only each low byte is kept: B, G, R, A in memory.\n const byte = (value: number) => Math.trunc(value * 255) & 0xff\n const diffuse = [byte(color.z), byte(color.y), byte(color.x), byte(near)]\n\n // Corners at the centre ± `q` · size ± `p` · size, drawn as triangles c0 c1 c2 and c2 c3 c0.\n const sp = { x: f(p.x * puff.size), y: f(p.y * puff.size) }\n const sq = { x: f(q.x * puff.size), y: f(q.y * puff.size) }\n const z = f(at.z)\n const vx = f(at.x)\n const vy = f(at.y)\n const c0 = [f(f(vx - sq.x) - sp.x), f(f(vy - sq.y) - sp.y), z]\n const c1v = [f(f(vx + sq.x) - sp.x), f(f(vy + sq.y) - sp.y), z]\n const c2 = [f(f(vx + sq.x) + sp.x), f(f(vy + sq.y) + sp.y), z]\n const c3 = [f(f(vx - sq.x) + sp.x), f(f(vy - sq.y) + sp.y), z]\n const uv = [\n [shape.u0, shape.v0],\n [shape.u1, shape.v0],\n [shape.u1, shape.v1],\n [shape.u1, shape.v1],\n [shape.u0, shape.v1],\n [shape.u0, shape.v0],\n ]\n ;[c0, c1v, c2, c2, c3, c0].forEach((corner, k) => {\n corners.push(...corner, ...uv[k]!)\n colours.push(...diffuse)\n })\n }\n\n const vertexCount = corners.length / 5\n if (vertexCount === 0) return undefined\n\n const vertices = new Uint8Array(vertexCount * STRIDE)\n const floats = new Float32Array(vertices.buffer)\n\n for (let at = 0; at < vertexCount; at++) {\n const [x, y, z, u, v] = corners.slice(at * 5, at * 5 + 5)\n\n floats.set([x!, y!, z!], (at * STRIDE) / 4)\n vertices.set(colours.slice(at * 4, at * 4 + 4), at * STRIDE + 12)\n floats.set([u!, v!], (at * STRIDE + 16) / 4)\n }\n\n const mesh: VMeshData = {\n name: 'clouds',\n version: 1,\n primitive: Primitive.TriangleList,\n format: FORMAT,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: vertexCount - 1,\n elementCount: vertexCount,\n padding: 0,\n },\n ],\n indices: Uint16Array.from({ length: vertexCount }, (_, at) => at),\n vertices,\n }\n const reference: VMeshRef = {\n meshId: 0,\n vertexStart: 0,\n vertexCount,\n indexStart: 0,\n indexCount: vertexCount,\n groupStart: 0,\n groupCount: 1,\n boundingBox: { min: BLACK, max: BLACK },\n boundingSphere: { center: BLACK, radius: 0 },\n }\n\n return {\n mesh,\n reference,\n transient: true,\n byteOffset: 0,\n count: vertexCount,\n // Its corners are in view space: the game draws them under an identity.\n world: frame,\n materialName: 'clouds',\n diffuse: [1, 1, 1, 1],\n ambient: BLACK,\n emissive: BLACK,\n colorVertex: true,\n nomad: false,\n texture: {\n name: first.texture.name,\n entry: first.texture,\n sampler: DEFAULT_SAMPLER,\n uvSet: 0,\n },\n cull: 'none',\n depthWrite: false,\n depthFunc: 'lequal',\n lightless: true,\n negateNormals: false,\n normalizeNormals: false,\n // A texture with alpha blends by it. One without, retail sets `SRCBLEND` twice and leaves\n // `DESTBLEND`: uncaptured, and no retail cloud texture is opaque.\n blend: true,\n blendMode: 'alpha',\n unlit: true,\n alphaReference: 5,\n alphaFunction: 'greater',\n }\n }\n}\n","/** An Alchemy node read into what the simulation and draw use. Absent properties stay absent here. */\nimport type {\n AnimatedColor,\n AnimatedCurve,\n AnimatedFloat,\n AnimatedTransform,\n Blending,\n Node,\n PropertyName,\n} from '@treewyrm/freelancer/alchemy'\n\ninterface Common {\n name: string\n /** Absent, 3 (`0x623f7b0`). `FLT_MAX` and `Infinity` both mean never. */\n lifeSpan: number\n transform?: AnimatedTransform\n}\n\ninterface EmitterCommon extends Common {\n category: 'emitter'\n lodCurve?: AnimatedFloat\n /** Signed: one retail cone holds `0xCDCDCDCD`, which the DLL adds as it stands (`0x6245cf6`). */\n initialParticles: number\n frequency?: AnimatedCurve\n maxParticles?: AnimatedCurve\n initLifeSpan?: AnimatedCurve\n pressure?: AnimatedCurve\n emitCount?: AnimatedCurve\n velocityApproach?: AnimatedCurve\n}\n\nexport interface CubeEmitter extends EmitterCommon {\n kind: 'cube-emitter'\n width?: AnimatedCurve\n height?: AnimatedCurve\n depth?: AnimatedCurve\n minSpread?: AnimatedCurve\n maxSpread?: AnimatedCurve\n}\n\nexport interface SphereEmitter extends EmitterCommon {\n kind: 'sphere-emitter'\n minRadius?: AnimatedCurve\n maxRadius?: AnimatedCurve\n}\n\nexport interface ConeEmitter extends EmitterCommon {\n kind: 'cone-emitter'\n minRadius?: AnimatedCurve\n maxRadius?: AnimatedCurve\n minSpread?: AnimatedCurve\n maxSpread?: AnimatedCurve\n}\n\nexport interface Sprite {\n color?: AnimatedColor\n alpha?: AnimatedFloat\n texture?: string\n blend?: Blending\n texFrame?: AnimatedFloat\n commonTexFrame?: AnimatedCurve\n useCommonTexFrame: boolean\n flipU: boolean\n flipV: boolean\n}\n\ninterface AppearanceCommon extends Common {\n category: 'appearance'\n lodCurve?: AnimatedFloat\n}\n\nexport interface BasicAppearance extends AppearanceCommon, Sprite {\n kind: 'basic-appearance'\n triTexture: boolean\n quadTexture: boolean\n motionBlur: boolean\n size?: AnimatedFloat\n rotate?: AnimatedFloat\n aspect?: AnimatedFloat\n}\n\nexport interface DustAppearance extends AppearanceCommon, Sprite {\n kind: 'dust-appearance'\n size?: AnimatedFloat\n}\n\nexport interface PerpAppearance extends AppearanceCommon, Sprite {\n kind: 'perp-appearance'\n size?: AnimatedFloat\n viewingAngleFade: boolean\n}\n\nexport interface RectAppearance extends AppearanceCommon, Sprite {\n kind: 'rect-appearance'\n motionBlur: boolean\n centerOnPos: boolean\n viewingAngleFade: boolean\n scale?: AnimatedFloat\n length?: AnimatedFloat\n width?: AnimatedFloat\n}\n\nexport interface BeamAppearance extends AppearanceCommon, Sprite {\n kind: 'beam-appearance'\n quadTexture: boolean\n disablePlaceHolder: boolean\n dupeFirstParticle: boolean\n scale?: AnimatedFloat\n width?: AnimatedFloat\n}\n\nexport interface OrientedAppearance extends AppearanceCommon, Sprite {\n kind: 'oriented-appearance'\n scale?: AnimatedFloat\n width?: AnimatedFloat\n height?: AnimatedFloat\n viewingAngleFade: boolean\n /** Keyed on each particle's age, on top of its position (`0x622c6dd`). */\n particleTransform?: AnimatedTransform\n}\n\nexport interface ParticleAppearance extends AppearanceCommon {\n kind: 'particle-appearance'\n lifeName?: string\n deathName?: string\n useDynamicRotation: boolean\n smoothRotation: boolean\n}\n\nexport interface MeshAppearance extends AppearanceCommon {\n kind: 'mesh-appearance'\n}\n\ninterface FieldCommon extends Common {\n category: 'field'\n}\n\nexport interface RadialField extends FieldCommon {\n kind: 'radial-field'\n radius?: AnimatedCurve\n attenuation?: AnimatedFloat\n magnitude?: AnimatedCurve\n approach?: AnimatedCurve\n}\n\nexport interface CollideField extends FieldCommon {\n kind: 'collide-field'\n reflectivity?: AnimatedCurve\n}\n\nexport interface TurbulenceField extends FieldCommon {\n kind: 'turbulence-field'\n magnitude?: AnimatedCurve\n approach?: AnimatedCurve\n}\n\nexport interface AirField extends FieldCommon {\n kind: 'air-field'\n magnitude?: AnimatedCurve\n approach?: AnimatedCurve\n}\n\nexport interface GravityField extends FieldCommon {\n kind: 'gravity-field'\n gravity?: AnimatedCurve\n}\n\nexport interface DustField extends FieldCommon {\n kind: 'dust-field'\n maxRadius?: AnimatedCurve\n}\n\nexport interface BeamField extends FieldCommon {\n kind: 'beam-field'\n}\n\nexport interface FolderNode extends Common {\n category: 'folder'\n kind: 'folder'\n}\n\nexport type NodeDescriptor =\n | CubeEmitter\n | SphereEmitter\n | ConeEmitter\n | BasicAppearance\n | DustAppearance\n | PerpAppearance\n | RectAppearance\n | BeamAppearance\n | OrientedAppearance\n | ParticleAppearance\n | MeshAppearance\n | RadialField\n | CollideField\n | TurbulenceField\n | AirField\n | GravityField\n | DustField\n | BeamField\n | FolderNode\n\nexport type Emitter = Extract<NodeDescriptor, { category: 'emitter' }>\nexport type Appearance = Extract<NodeDescriptor, { category: 'appearance' }>\nexport type Field = Extract<NodeDescriptor, { category: 'field' }>\n\n/** A node's descriptor, or `undefined` for a type no DLL registers. */\nexport const describeNode = (node: Node): NodeDescriptor | undefined => {\n // The DLL's reader sets each as it comes (`0x62291d1`), so of two the last stands (`effect_sprites`).\n const find = (name: PropertyName) => node.properties.filter((one) => one.name === name).at(-1)\n\n const flag = (name: PropertyName, fallback = false) => {\n const found = find(name)\n\n return found?.type === 'boolean' ? found.value : fallback\n }\n\n const scalar = (name: PropertyName, fallback: number) => {\n const found = find(name)\n\n return found?.type === 'float' || found?.type === 'integer' ? found.value : fallback\n }\n\n const text = (name: PropertyName) => {\n const found = find(name)\n\n return found?.type === 'string' ? found.value : undefined\n }\n\n const float = (name: PropertyName) => {\n const found = find(name)\n\n return found?.type === 'animatedFloat' ? found.value : undefined\n }\n\n const curve = (name: PropertyName) => {\n const found = find(name)\n\n return found?.type === 'animatedCurve' ? found.value : undefined\n }\n\n const color = () => {\n const found = find('BasicApp_Color')\n\n return found?.type === 'animatedColor' ? found.value : undefined\n }\n\n const blend = () => {\n const found = find('BasicApp_BlendInfo')\n\n return found?.type === 'blending' ? found.value : undefined\n }\n\n const transformOf = (name: PropertyName) => {\n const found = find(name)\n\n return found?.type === 'transform' ? found.value : undefined\n }\n\n const common: Common = {\n name: text('Node_Name') ?? '',\n lifeSpan: scalar('Node_LifeSpan', 3),\n transform: transformOf('Node_Transform'),\n }\n const emitter = (): EmitterCommon => ({\n ...common,\n category: 'emitter',\n lodCurve: float('Emitter_LODCurve'),\n initialParticles: scalar('Emitter_InitialParticles', 0),\n frequency: curve('Emitter_Frequency'),\n maxParticles: curve('Emitter_MaxParticles'),\n initLifeSpan: curve('Emitter_InitLifeSpan'),\n pressure: curve('Emitter_Pressure'),\n emitCount: curve('Emitter_EmitCount'),\n velocityApproach: curve('Emitter_VelocityApproach'),\n })\n const appearance = (): AppearanceCommon => ({\n ...common,\n category: 'appearance',\n lodCurve: float('Appearance_LODCurve'),\n })\n const sprite = (): Sprite => ({\n color: color(),\n alpha: float('BasicApp_Alpha'),\n texture: text('BasicApp_TexName'),\n blend: blend(),\n texFrame: float('BasicApp_TexFrame'),\n commonTexFrame: curve('BasicApp_CommonTexFrame'),\n useCommonTexFrame: flag('BasicApp_UseCommonTexFrame'),\n flipU: flag('BasicApp_FlipTexU'),\n flipV: flag('BasicApp_FlipTexV'),\n })\n const field = (): FieldCommon => ({ ...common, category: 'field' })\n\n switch (node.type) {\n case 'FxCubeEmitter':\n return {\n ...emitter(),\n kind: 'cube-emitter',\n width: curve('CubeEmitter_Width'),\n height: curve('CubeEmitter_Height'),\n depth: curve('CubeEmitter_Depth'),\n minSpread: curve('CubeEmitter_MinSpread'),\n maxSpread: curve('CubeEmitter_MaxSpread'),\n }\n case 'FxSphereEmitter':\n return {\n ...emitter(),\n kind: 'sphere-emitter',\n minRadius: curve('SphereEmitter_MinRadius'),\n maxRadius: curve('SphereEmitter_MaxRadius'),\n }\n case 'FxConeEmitter':\n return {\n ...emitter(),\n kind: 'cone-emitter',\n minRadius: curve('ConeEmitter_MinRadius'),\n maxRadius: curve('ConeEmitter_MaxRadius'),\n minSpread: curve('ConeEmitter_MinSpread'),\n maxSpread: curve('ConeEmitter_MaxSpread'),\n }\n case 'FxBasicAppearance':\n return {\n ...appearance(),\n ...sprite(),\n kind: 'basic-appearance',\n triTexture: flag('BasicApp_TriTexture'),\n quadTexture: flag('BasicApp_QuadTexture'),\n motionBlur: flag('BasicApp_MotionBlur'),\n size: float('BasicApp_Size'),\n rotate: float('BasicApp_Rotate'),\n aspect: float('BasicApp_HToVAspect'),\n }\n case 'FLDustAppearance':\n return { ...appearance(), ...sprite(), kind: 'dust-appearance', size: float('BasicApp_Size') }\n case 'FxPerpAppearance':\n return {\n ...appearance(),\n ...sprite(),\n kind: 'perp-appearance',\n size: float('BasicApp_Size'),\n viewingAngleFade: flag('RectApp_ViewingAngleFade'),\n }\n case 'FxRectAppearance':\n return {\n ...appearance(),\n ...sprite(),\n kind: 'rect-appearance',\n motionBlur: flag('BasicApp_MotionBlur'),\n centerOnPos: flag('RectApp_CenterOnPos'),\n viewingAngleFade: flag('RectApp_ViewingAngleFade'),\n scale: float('RectApp_Scale'),\n length: float('RectApp_Length'),\n width: float('RectApp_Width'),\n }\n case 'FLBeamAppearance':\n return {\n ...appearance(),\n ...sprite(),\n kind: 'beam-appearance',\n // On unless the file says otherwise: the constructor's flag word is 2 (`0x6204a47`).\n quadTexture: flag('BasicApp_QuadTexture', true),\n disablePlaceHolder: flag('BeamApp_DisablePlaceHolder'),\n dupeFirstParticle: flag('BeamApp_DupeFirstParticle'),\n scale: float('RectApp_Scale'),\n width: float('RectApp_Width'),\n }\n case 'FxOrientedAppearance':\n return {\n ...appearance(),\n ...sprite(),\n kind: 'oriented-appearance',\n scale: float('RectApp_Scale'),\n width: float('OrientedApp_Width'),\n height: float('OrientedApp_Height'),\n viewingAngleFade: flag('RectApp_ViewingAngleFade'),\n particleTransform: transformOf('MeshApp_ParticleTransform'),\n }\n case 'FxParticleAppearance':\n return {\n ...appearance(),\n kind: 'particle-appearance',\n lifeName: text('ParticleApp_LifeName'),\n deathName: text('ParticleApp_DeathName'),\n useDynamicRotation: flag('ParticleApp_UseDynamicRotation'),\n smoothRotation: flag('ParticleApp_SmoothRotation'),\n }\n case 'FxMeshAppearance':\n return { ...appearance(), kind: 'mesh-appearance' }\n case 'FxRadialField':\n return {\n ...field(),\n kind: 'radial-field',\n radius: curve('RadialField_Radius'),\n attenuation: float('RadialField_Attenuation'),\n magnitude: curve('RadialField_Magnitude'),\n approach: curve('RadialField_Approach'),\n }\n case 'FxCollideField':\n return {\n ...field(),\n kind: 'collide-field',\n reflectivity: curve('CollideField_Reflectivity'),\n }\n case 'FxTurbulenceField':\n return {\n ...field(),\n kind: 'turbulence-field',\n magnitude: curve('TurbulenceField_Magnitude'),\n approach: curve('TurbulenceField_Approach'),\n }\n case 'FxAirField':\n return {\n ...field(),\n kind: 'air-field',\n magnitude: curve('AirField_Magnitude'),\n approach: curve('AirField_Approach'),\n }\n case 'FxGravityField':\n return { ...field(), kind: 'gravity-field', gravity: curve('GravityField_Gravity') }\n // It borrows an emitter's property name (`0x6212c20`).\n case 'FLDustField':\n return { ...field(), kind: 'dust-field', maxRadius: curve('SphereEmitter_MaxRadius') }\n case 'FLBeamField':\n return { ...field(), kind: 'beam-field' }\n case 'FxNode':\n return { ...common, category: 'folder', kind: 'folder' }\n default:\n return undefined\n }\n}\n","/** One effect as a list of nodes, each knowing its parent, children and links. Holds no run state. */\nimport {\n CONTROL_ROOT_ID,\n type Effect,\n type Node,\n type NodeInstance,\n} from '@treewyrm/freelancer/alchemy'\nimport { describeNode, type NodeDescriptor } from './nodes.js'\n\nexport interface EffectNode {\n /** The file's entry this came from, which is how a host names it. */\n instance: NodeInstance\n /** What a CRC resolves to. A flagged entry is a folder and never looked up (`0x621efe7`). */\n descriptor?: NodeDescriptor\n /** The CRC, as text, when it resolved to nothing or to a type no DLL registers. */\n missing?: string\n /** Index in `EffectScene.nodes`, or -1 at the top level. */\n parent: number\n /** In the order they're inserted into their parent, which is entry order. */\n children: number[]\n /** From the `Pair` records, in file order. */\n targets: number[]\n /** Sorts siblings: appearances 100, fields 200, emitters 300, folders 400 (`+0x38`). */\n key: number\n}\n\nexport interface EffectScene {\n name: string\n nodes: EffectNode[]\n /** Top-level nodes, in entry order. */\n top: number[]\n /** The node a placement reaches, or none, in which case every top-level node takes it. */\n root?: number\n}\n\n/** Finds a node by CRC. The namespace is one across all loaded files, so which file is the host's. */\nexport type ResolveNode = (crc: number) => Node | undefined\n\n/** An effect by name, for `FxParticleAppearance`. Names no library defines mean no particle. */\nexport type EffectLookup = (name: string) => EffectScene | undefined\n\nconst CLASS_KEY = { appearance: 100, field: 200, emitter: 300, folder: 400 } as const\n\nexport const buildEffect = (effect: Effect, resolve: ResolveNode): EffectScene => {\n const scene: EffectScene = { name: effect.name, nodes: [], top: [] }\n const indices = new Map<NodeInstance, number>()\n const flat: NodeInstance[] = []\n\n const gather = (instance: NodeInstance) => {\n flat.push(instance)\n for (const child of instance.children) gather(child)\n }\n for (const instance of effect.children) gather(instance)\n\n // What the game builds from is the array, whose order the tree doesn't keep.\n const sorted = flat\n .map((instance, walked) => ({ instance, order: instance.sort ?? flat.length + walked }))\n .sort((a, b) => a.order - b.order)\n .map(({ instance }) => instance)\n\n for (const instance of sorted) {\n indices.set(instance, scene.nodes.length)\n\n const node = instance.flags ? undefined : resolve(instance.crc)\n const descriptor: NodeDescriptor | undefined = instance.flags\n ? { name: '', lifeSpan: 3, category: 'folder', kind: 'folder' }\n : node && describeNode(node)\n\n scene.nodes.push({\n instance,\n descriptor,\n missing: descriptor ? undefined : `0x${(instance.crc >>> 0).toString(16)}`,\n parent: -1,\n children: [],\n targets: [],\n key: CLASS_KEY[descriptor?.category ?? 'folder'],\n })\n // The last flagged `Control Root` in entry order: each overwrites the one before (`0x621f088`).\n if (instance.flags && instance.crc === CONTROL_ROOT_ID) scene.root = scene.nodes.length - 1\n }\n\n sorted.forEach((instance, index) => {\n const node = scene.nodes[index]!\n\n for (const child of instance.children) {\n const at = indices.get(child)!\n\n scene.nodes[at]!.parent = index\n node.children.push(at)\n }\n\n node.children.sort((a, b) => a - b)\n\n for (const target of instance.targets) {\n const at = indices.get(target)\n if (at !== undefined) node.targets.push(at)\n }\n })\n scene.nodes.forEach((node, index) => {\n if (node.parent < 0) scene.top.push(index)\n })\n return scene\n}\n\n/** Builds and caches effects by name, the first of a name winning. */\nexport const lookupOver = (effects: readonly Effect[], resolve: ResolveNode): EffectLookup => {\n const byName = new Map<string, Effect>()\n for (const effect of effects) if (!byName.has(effect.name)) byName.set(effect.name, effect)\n\n const built = new Map<string, EffectScene>()\n\n return (name) => {\n const known = built.get(name)\n if (known) return known\n\n const effect = byName.get(name)\n if (!effect) return undefined\n\n const scene = buildEffect(effect, resolve)\n\n built.set(name, scene)\n return scene\n }\n}\n","/** The one patch a `.sph` draws six times, turned: `FSphereMaterialSlot::Tessellate`. Pure, no GL. */\nimport {\n Primitive,\n type VertexFormat,\n type VMeshData,\n type VMeshRef,\n} from '@treewyrm/freelancer/vmesh'\n\nexport interface SpherePatch {\n mesh: VMeshData\n reference: VMeshRef\n}\n\n// FVF 0x112, as `FSphereAnim::Init` sets it.\nconst STRIDE_FLOATS = 8\n\n// Past this a patch outgrows 16-bit indices, which retail's maximum of 10 never nears.\nconst MAXIMUM_LEVEL = 14\n\n/**\n * The `+Z` face, S along +X and T along +Y, in rows from T = 0. Retail lerps normalized corners and\n * normalizes again, which comes to `normalize(2S - 1, 2T - 1, 1)` before float rounding.\n */\nconst writeVertices = (radius: number, cells: number, odd: boolean): Float32Array => {\n const rows = odd ? 2 * cells + 1 : cells + 1\n const data: number[] = []\n\n for (let row = 0; row < rows; row++) {\n const t = row / (rows - 1)\n const shifted = odd && row % 2 === 1\n const columns = shifted ? cells : cells + 1\n\n for (let column = 0; column < columns; column++) {\n const s = (shifted ? column + 0.5 : column) / cells\n const x = 2 * s - 1\n const y = 2 * t - 1\n const scale = 1 / Math.hypot(x, y, 1)\n const nx = Math.fround(x * scale)\n const ny = Math.fround(y * scale)\n const nz = Math.fround(scale)\n\n data.push(nx * radius, ny * radius, nz * radius, nx, ny, nz, s, t)\n }\n }\n\n return new Float32Array(data)\n}\n\n/** An even level: two triangles a cell, the diagonal alternating (`0x6c2d1a2`). */\nconst evenIndices = (cells: number): number[] => {\n const width = cells + 1\n const indices: number[] = []\n\n for (let row = 0; row < cells; row++)\n for (let column = 0; column < cells; column++) {\n const p = row * width + column\n const q = p + width\n\n if ((row + column) % 2 !== 0) indices.push(p, p + 1, q, p + 1, q + 1, q)\n else indices.push(p, q + 1, q, p, p + 1, q + 1)\n }\n\n return indices\n}\n\n/** An odd level: four triangles a cell, round the vertex at its centre (`0x6c2cd10`). */\nconst oddIndices = (cells: number): number[] => {\n const width = cells + 1\n const stride = 2 * cells + 1\n const indices: number[] = []\n\n for (let row = 0; row < cells; row++)\n for (let column = 0; column < cells; column++) {\n // `a` and `c` are the cell's corners in this and the next corner row, `m` its centre between;\n // a corner row and its centre row together hold `stride` vertices.\n const a = row * stride + column\n const m = a + width\n const c = a + stride\n\n indices.push(a, a + 1, m, a + 1, c + 1, m, c + 1, c, m, c, a, m)\n }\n\n return indices\n}\n\nconst buildPatch = (radius: number, level: number): SpherePatch => {\n // Level 2n and 2n + 1 share a grid of 2^n cells; odd adds each cell's centre. `2^level * 2` triangles.\n const cells = 1 << (level >> 1)\n const odd = level % 2 !== 0\n const vertices = writeVertices(radius, cells, odd)\n const indices = odd ? oddIndices(cells) : evenIndices(cells)\n const vertexCount = vertices.length / STRIDE_FLOATS\n const corner = radius * Math.SQRT1_2\n\n return {\n mesh: {\n name: `sphere ${radius} ${level}`,\n version: 1,\n primitive: Primitive.TriangleList,\n format: 0x112 as VertexFormat,\n groups: [\n {\n materialId: 0,\n vertexStart: 0,\n vertexEnd: vertexCount - 1,\n elementCount: indices.length,\n padding: 0,\n },\n ],\n indices: new Uint16Array(indices),\n vertices: new Uint8Array(vertices.buffer),\n },\n reference: {\n meshId: 0,\n vertexStart: 0,\n vertexCount,\n indexStart: 0,\n indexCount: indices.length,\n groupStart: 0,\n groupCount: 1,\n boundingBox: {\n min: { x: -corner, y: -corner, z: radius * Math.sqrt(1 / 3) },\n max: { x: corner, y: corner, z: radius },\n },\n boundingSphere: { center: { x: 0, y: 0, z: 0 }, radius },\n },\n }\n}\n\nconst patches = new Map<string, SpherePatch>()\n\n/**\n * The patch at a radius and level. Vertices hold the radius, since a world scale would scale normals.\n * The same object comes back each time, so a renderer's buffers for it are shared between spheres.\n */\nexport const spherePatch = (radius: number, level: number): SpherePatch => {\n if (!Number.isInteger(level) || level < 0 || level > MAXIMUM_LEVEL)\n throw new RangeError(`Sphere level must be an integer in 0..${MAXIMUM_LEVEL}, not ${level}`)\n\n const key = `${radius}/${level}`\n let patch = patches.get(key)\n\n if (!patch) {\n patch = buildPatch(radius, level)\n patches.set(key, patch)\n }\n\n return patch\n}\n","/** A `.sph` where a camera sees it: `FSphereAnim::Draw` and `UpdateLevel`, in `RendComp`. Pure, no GL. */\nimport { getResourceId } from '@treewyrm/freelancer'\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Material } from '@treewyrm/freelancer/material'\nimport type { Sphere } from '@treewyrm/freelancer/rigid'\nimport { mapMaterialType, type MaterialMapRule } from '#/material/map.js'\nimport { spherePatch } from '#/mesh/sphere.js'\nimport type { Camera } from './camera.js'\nimport { DEFAULT_SHELL_SCALE, type PlacedPart } from './frame.js'\nimport { lodScale } from './level.js'\n\nexport interface SphereOptions {\n /** Decides the level and which faces draw. */\n camera: Camera\n /** Of the viewport, in pixels: the level bounds the sphere's error on screen. */\n width: number\n /** Pins a level, for a host choosing its own density. Faces still cull. */\n level?: number\n /** Finds the seventh side's `Scale`, which its shell culls by. 1 if absent. */\n material?: (id: number) => Material | undefined\n /** As on `SceneModel`, for that side's type. */\n materialMap?: readonly MaterialMapRule[]\n /** Over `RETAIL_SPHERE_LEVELS`, for a mod that patches them. */\n levels?: Partial<SphereLevels>\n}\n\n/** `FSphereAnim::Init`'s bounds on a sphere's level, and the bias on its pixel size. */\nexport interface SphereLevels {\n minimum: number\n maximum: number\n bias: number\n}\n\n// What a sphere starts with, and keeps unless `solarSphereLevels` reaches it.\nexport const RETAIL_SPHERE_LEVELS: Readonly<SphereLevels> = { minimum: 3, maximum: 9, bias: 1.5 }\n\n/**\n * `SolarSpheresApplyDetail` (`0x5488a0`): the maximum, 7 to 10, and the bias, 3 to 1, the\n * `level_of_detail` option gives a solar's sphere. Retail applies it only as the option changes, to the\n * solars that exist then (`SetPerfOptionValue`): at startup none do, so a system's planets keep\n * `RETAIL_SPHERE_LEVELS` until the player moves the slider in it, and lose it when it reloads.\n */\nexport const solarSphereLevels = (detail: number): Pick<SphereLevels, 'maximum' | 'bias'> => {\n const { scale } = lodScale(detail)\n const t = Math.min(Math.max(scale + scale - 1, 0), 1)\n\n return { maximum: Math.trunc(3 * t + 7), bias: Math.trunc(3.5 - (t + t)) }\n}\n\nconst K = Math.sqrt(1 / 3)\n\nconst axes = (x: Vector3, y: Vector3, z: Vector3): Matrix4 => ({\n x: { ...x, w: 0 },\n y: { ...y, w: 0 },\n z: { ...z, w: 0 },\n w: { x: 0, y: 0, z: 0, w: 1 },\n})\n\nconst X = { x: 1, y: 0, z: 0 }\nconst Y = { x: 0, y: 1, z: 0 }\nconst Z = { x: 0, y: 0, z: 1 }\nconst NEGATIVE_X = { x: -1, y: 0, z: 0 }\nconst NEGATIVE_Y = { x: 0, y: -1, z: 0 }\nconst NEGATIVE_Z = { x: 0, y: 0, z: -1 }\n\n// `SphereFaceRotation`, turning the `+Z` patch: `M0..M5` are +Z, +X, -Z, -X, +Y, -Y.\nconst FACES: readonly Matrix4[] = [\n axes(X, Y, Z),\n axes(NEGATIVE_Z, Y, X),\n axes(NEGATIVE_X, Y, NEGATIVE_Z),\n axes(Z, Y, NEGATIVE_X),\n axes(X, NEGATIVE_Z, Y),\n axes(X, Z, NEGATIVE_Y),\n]\n\n// Each face's cube corners, by `Draw`'s numbering. Only those of the face nearest the camera are\n// tested, so a face draws by sharing a visible corner with it, and the one opposite never draws.\nconst FACE_CORNERS: readonly (readonly number[])[] = [\n [0, 3, 4, 7],\n [0, 1, 4, 5],\n [1, 2, 5, 6],\n [2, 3, 6, 7],\n [0, 1, 2, 3],\n [4, 5, 6, 7],\n]\nconst CORNERS: readonly Vector3[] = [\n { x: K, y: K, z: K },\n { x: K, y: K, z: -K },\n { x: -K, y: K, z: -K },\n { x: -K, y: K, z: K },\n { x: K, y: -K, z: K },\n { x: K, y: -K, z: -K },\n { x: -K, y: -K, z: -K },\n { x: -K, y: -K, z: K },\n]\n\nconst dot = (a: Vector3, b: Vector3): number => a.x * b.x + a.y * b.y + a.z * b.z\n\n/**\n * `UpdateLevel` (`0x6c2c430`), from `metric`, the world size of a pixel at the sphere times the bias.\n * Out of `acos`'s range, or at no distance, x87's `ftol` gives `INT_MIN`, so the lowest level.\n */\nexport const sphereLevel = (\n radius: number,\n metric: number,\n { minimum, maximum }: Pick<SphereLevels, 'minimum' | 'maximum'> = RETAIL_SPHERE_LEVELS,\n): number => {\n // `acos(1 - metric / radius)` is the angle whose sagitta `r(1 - cos)` is `metric`; the level is\n // round(2 · log2(quarter turn ÷ that angle)).\n const ratio = Math.PI / 2 / Math.acos(1 - metric / radius)\n const level = Math.trunc(2 * Math.log2(ratio) + 0.5)\n if (!Number.isFinite(level)) return minimum\n return Math.min(maximum, Math.max(minimum, level))\n}\n\n/** Which faces draw, in order, at this radius. A world's rotation turns the cube; its scale isn't read. */\nconst visibleFaces = (radius: number, world: Matrix4, position: Vector3): number[] => {\n const turn = ({ x, y, z }: Vector3): Vector3 => ({\n x: world.x.x * x + world.y.x * y + world.z.x * z,\n y: world.x.y * x + world.y.y * y + world.z.y * z,\n z: world.x.z * x + world.y.z * y + world.z.z * z,\n })\n const away = { x: position.x - world.w.x, y: position.y - world.w.y, z: position.z - world.w.z }\n const distance = Math.hypot(away.x, away.y, away.z)\n const toCamera = { x: away.x / distance, y: away.y / distance, z: away.z / distance }\n\n let best = 0\n let most = -1\n\n FACES.forEach(({ z: normal }, face) => {\n const facing = dot(toCamera, turn(normal))\n\n if (facing > most) {\n most = facing\n best = face\n }\n })\n\n // A corner shows when its dot with the way to the camera passes the horizon, radius ÷ distance.\n const threshold = Math.min(radius / distance, K)\n const visible = FACE_CORNERS[best]!.filter(\n (corner) => dot(toCamera, turn(CORNERS[corner]!)) > threshold,\n )\n\n return FACES.flatMap((_, face) =>\n face === best || FACE_CORNERS[face]!.some((corner) => visible.includes(corner)) ? [face] : [],\n )\n}\n\n/**\n * A sphere's visible faces, as parts, then its shell's, which is the same patch under the seventh\n * material and culls by its own larger radius. Materials repeat by `Sides`, a retail sun naming one.\n */\nexport const placeSphere = (\n { radius, sides }: Sphere,\n world: Matrix4,\n { camera, width, level, material, materialMap, levels }: SphereOptions,\n): PlacedPart[] => {\n const { x, y, z } = camera.position\n const distance = Math.hypot(x - world.w.x, y - world.w.y, z - world.w.z)\n // `Draw` divides by `ZNear * GetXScaleOverNear()`, which is `HalfWidth / tan(fovx½)` (`space_camera.cpp`).\n const pixel = (Math.tan((camera.fovh * Math.PI) / 180) / (width / 2)) * distance\n const bounds = { ...RETAIL_SPHERE_LEVELS, ...levels }\n const { mesh, reference } = spherePatch(\n radius,\n level ?? sphereLevel(radius, pixel * bounds.bias, bounds),\n )\n const part = (face: number, name: string): PlacedPart => ({\n reference,\n mesh,\n world: Matrix4.multiply(world, FACES[face]!),\n materialId: getResourceId(name),\n materialName: name,\n })\n const parts = visibleFaces(radius, world, camera.position).map((face) =>\n part(face, sides[face % sides.length]!),\n )\n const shell = sides[FACES.length]\n if (shell === undefined) return parts\n\n // `FSphereHandle::Load` reads `Scale` only from a seventh side that's an `AtmosphereMaterial`.\n const found = material?.(getResourceId(shell))\n const scale =\n found && mapMaterialType(found, materialMap) === 'AtmosphereMaterial'\n ? (found.scale ?? DEFAULT_SHELL_SCALE)\n : 1\n const extent = radius * scale\n\n return [\n ...parts,\n ...visibleFaces(extent, world, camera.position).map((face) => ({\n ...part(face, shell),\n extent,\n })),\n ]\n}\n","/**\n * Parameter curves: the `IParamCurve` classes in `src/Thorn/ParamCurve.cpp`, and the progress every\n * property animation shares (`FThornEvent::EvaluateProgress`).\n */\nimport { catmullRom } from '@treewyrm/freelancer/math'\nimport type { ParamCurve } from '@treewyrm/freelancer/thn/scene'\n\nconst f = Math.fround\n\n/** A curve over `[0, 1]`: what `IParamCurve::Evaluate` returns. */\nexport interface Curve {\n readonly type: string\n evaluate(t: number): number\n}\n\ninterface Key {\n t: number\n v: number\n in: number\n out: number\n}\n\n/** The tangent rule a Hermite curve's keys get on every rebuild (`ApplyHermiteTangents`). */\ntype Mode = 'step' | 'linear' | 'rampUp' | 'rampDown' | 'smooth' | 'bumpOut' | 'bumpIn' | 'free'\n\n/** `SpecFor`'s table. `LinearPCurve` registers twice; which DACOM returns isn't read, so the list one. */\nconst TYPES: Record<\n string,\n { kind: 'catmullRom' | 'linear' | 'hermite'; mode?: Mode; floor?: true }\n> = {\n CatmullRomPCurve: { kind: 'catmullRom' },\n ThornParamCurve: { kind: 'catmullRom', floor: true },\n LinearPCurve: { kind: 'linear' },\n ThornLPCurve: { kind: 'linear', floor: true },\n SmoothPCurve: { kind: 'hermite', mode: 'smooth' },\n StepPCurve: { kind: 'hermite', mode: 'step' },\n RampUpPCurve: { kind: 'hermite', mode: 'rampUp' },\n RampDownPCurve: { kind: 'hermite', mode: 'rampDown' },\n BumpOutPCurve: { kind: 'hermite', mode: 'bumpOut' },\n BumpInPCurve: { kind: 'hermite', mode: 'bumpIn' },\n FreeFormPCurve: { kind: 'hermite', mode: 'free' },\n}\n\n/** `ThornNameEqual`: DACOM finds its classes ignoring case. */\nconst typeOf = (name: string) =>\n Object.entries(TYPES).find(([key]) => key.toLowerCase() === name.toLowerCase())\n\n/**\n * The keys a curve holds after `points`, in id order: `(0, 0)` and `(1, 1)` first, each row at\n * exactly 0 or 1 replacing one, any other in `[0, 1]` added, and any outside dropped (`AddKey`).\n */\nconst keysOf = (points: readonly (readonly number[])[]): Key[] => {\n const keys: Key[] = [\n { t: 0, v: 0, in: 0, out: 0 },\n { t: 1, v: 1, in: 0, out: 0 },\n ]\n\n for (const [t = 0, v = 0, inSlope = 0, outSlope = 0] of points) {\n const key = { t: f(t), v: f(v), in: f(inSlope), out: f(outSlope) }\n if (key.t < 0 || key.t > 1) continue\n\n if (key.t === 0) keys[0] = key\n else if (key.t === 1) keys[1] = key\n else keys.push(key)\n }\n\n return keys\n}\n\n/** The evaluation list: by time, ties in id order (`SortEvaluationList`'s merge sort is stable). */\nconst byTime = (keys: readonly Key[]): Key[] => keys.slice().sort((a, b) => a.t - b.t)\n\n/** `ClampNonNegative`: the non-negative classes hold every value at the running maximum. */\nconst floored = (keys: Key[]): Key[] => {\n let floor = 0\n\n return keys.map((key) => {\n const v = key.v < floor ? floor : key.v\n\n floor = v\n return { ...key, v }\n })\n}\n\n/** A step key's outgoing slope: the all-ones word `Hermite1D` tests for. */\nconst STEP = Number.NaN\n\n/** `ApplyHermiteTangents`, over every pair, `dt` held at 1e-4 or more. */\nconst withTangents = (knots: Key[], mode: Mode): void => {\n for (let index = 0; index + 1 < knots.length; index++) {\n const a = knots[index]!\n const b = knots[index + 1]!\n const dt = f(b.t - a.t) < f(1e-4) ? f(1e-4) : f(b.t - a.t)\n const dv = f(b.v - a.v)\n const slope = f(dv / dt)\n const double = f(dv / f(dt * 0.5))\n\n if (mode === 'step') a.out = STEP\n else if (mode === 'linear') ((a.out = slope), (b.in = slope))\n else if (mode === 'smooth') ((a.out = 0), (b.in = 0))\n else if (mode === 'rampUp') ((a.out = 0), (b.in = double))\n else if (mode === 'rampDown') ((a.out = double), (b.in = 0))\n else if (mode === 'bumpOut')\n if (a.v <= b.v) ((a.out = double), (b.in = 0))\n else ((a.out = 0), (b.in = double))\n else if (mode === 'bumpIn')\n if (a.v < b.v) ((a.out = 0), (b.in = double))\n else ((a.out = double), (b.in = 0))\n }\n}\n\n/**\n * The Hermite knots, rebuilt in id order: each inserted before the first knot at or after its\n * time (`InsertDerivedRecord`), tangents applied after each insertion.\n */\nconst knotsOf = (keys: readonly Key[], mode: Mode): Key[] => {\n const knots: Key[] = []\n\n for (const key of keys) {\n const at = knots.findIndex((knot) => knot.t >= key.t)\n\n knots.splice(at < 0 ? knots.length : at, 0, { ...key })\n withTangents(knots, mode)\n }\n\n return knots\n}\n\n/** `Hermite1D` (`FUN_06f30480`): the file's `(t, v, in, out)` rows are value and slopes. */\nconst hermite = (a: Key, b: Key, t: number): number => {\n if (a.t === t) return a.v\n if (b.t === t) return b.v\n\n const dt = b.t - a.t\n const s = f((t - a.t) / dt)\n\n if (Number.isNaN(a.out)) return a.v\n\n const s2 = s * s\n const s3 = s2 * s\n\n // Cubic Hermite basis in `s`: tangent terms scaled by `dt` (out, in), then value terms (a, b).\n return (\n (s3 - 2 * s2 + s) * a.out * dt +\n (s3 - s2) * b.in * dt +\n (2 * s3 - 3 * s2 + 1) * a.v +\n (3 * s2 - 2 * s3) * b.v\n )\n}\n\n/**\n * `HermiteEvaluate` (`FUN_06f30520`): held at either end, otherwise the pair around `t` found from a\n * proportional guess, walking forward past keys at or before `t` or back past those after it.\n */\nconst evaluateHermite = (knots: readonly Key[], t: number): number => {\n const first = knots[0]!\n const last = knots[knots.length - 1]!\n\n if (knots.length === 1 || t < first.t) return first.v\n if (t > last.t) return last.v\n\n let at = Math.trunc(f((t - first.t) / (last.t - first.t)) * (knots.length - 1))\n\n if (knots[at]!.t <= t) {\n while (at < knots.length && knots[at]!.t <= t) at++\n // Past the end only when `t` is the last key's, which the kernel answers from the left.\n return knots[at] ? hermite(knots[at - 1]!, knots[at]!, t) : knots[at - 1]!.v\n }\n\n while (at > 0 && !(knots[at]!.t < t)) at--\n return hermite(knots[at]!, knots[at + 1]!, t)\n}\n\n/** The list Catmull-Rom (`0x6f2f220`): a key's value at its time, and 0 outside the keys. */\nconst evaluateCatmullRom = (keys: readonly Key[], t: number): number => {\n for (let index = 0; index < keys.length; index++) {\n const key = keys[index]!\n\n if (key.t > t) {\n if (index === 0) return 0\n\n const a = keys[index - 1]!\n const u = f((t - a.t) / (key.t - a.t))\n const p0 = keys[index - 2]?.v ?? a.v\n const p3 = keys[index + 1]?.v ?? key.v\n\n // `CatmullRom1D` (`0x6f2f2f0`), a missing outer value its neighbour's.\n return catmullRom(p0, a.v, key.v, p3, u)\n }\n\n if (key.t === t) return key.v\n }\n\n return 0\n}\n\n/** The list lerp (`0x6f2f920`): between the first key after `t` and the one before, else 0, so 0 at 1. */\nconst evaluateLinear = (keys: readonly Key[], t: number): number => {\n for (let index = 0; index < keys.length; index++) {\n const b = keys[index]!\n\n if (b.t > t) {\n const a = keys[index - 1]\n if (!a) return 0\n return a.v + ((t - a.t) / (b.t - a.t)) * (b.v - a.v)\n }\n }\n\n return 0\n}\n\n/** A `param_curve` as thorn makes it, or nothing for a class DACOM doesn't have. */\nexport const createCurve = (curve: ParamCurve): Curve | undefined => {\n const found = curve.CLSID === undefined ? undefined : typeOf(curve.CLSID)\n if (!found) return undefined\n\n const [type, { kind, mode, floor }] = found\n const keys = keysOf(curve.points ?? [])\n const list = floor ? floored(byTime(keys)) : byTime(keys)\n if (kind === 'catmullRom') return { type, evaluate: (t) => evaluateCatmullRom(list, f(t)) }\n if (kind === 'linear') return { type, evaluate: (t) => evaluateLinear(list, f(t)) }\n\n const knots = knotsOf(keys, mode ?? 'free')\n\n return { type, evaluate: (t) => evaluateHermite(knots, f(t)) }\n}\n\n/** The timing a property animation's progress reads. */\nexport interface Timing {\n /** Milliseconds. */\n start: number\n duration: number\n curve?: Curve\n /** `pcurve_period`, milliseconds; positive loops the curve. */\n period: number\n}\n\n/**\n * `EvaluateProgress`: 1 for an instant event, else the elapsed fraction, through the curve when\n * there is one, which a positive period loops as a sawtooth. **Not clamped.**\n */\nexport const progress = ({ start, duration, curve, period }: Timing, now: number): number => {\n if (duration === 0) return 1\n\n const elapsed = now - start\n if (curve && period > 0) return curve.evaluate(f((elapsed % period) / period))\n\n const ratio = f(elapsed / duration)\n\n return curve ? curve.evaluate(ratio) : ratio\n}\n","/**\n * A script's sound, handed to the host as records: the library plays nothing. Thorn's `audioprops`\n * (`0x6f5e198`, `TickAudioPropAnim`) and the game's sound host (`gf_thorn_sound.cpp`).\n */\nimport type { AudioProps } from '@treewyrm/freelancer/thn/scene'\n\nconst f = Math.fround\n\n/** The eight `audioprops`, in key order. Only `attenuation` and `pan` reach a sound (`0x457630`). */\nexport interface AudioState {\n /** Decibels. */\n attenuation: number\n pan: number\n dmin: number\n dmax: number\n /** Whole degrees. */\n ain: number\n aout: number\n atout: number\n rmix: number\n}\n\n/** An entity's defaults (`0x6f5e198`). */\nexport const DEFAULT_AUDIO: AudioState = {\n attenuation: 0,\n pan: 0,\n dmin: 1,\n dmax: 1e9,\n ain: 360,\n aout: 360,\n atout: 0,\n rmix: 0,\n}\n\n/** An animation's targets before its keys (`ApplyAudioPropAnimDesc`): `dmin` 50 and `dmax` 1000. */\nexport const DEFAULT_AUDIO_TARGET: AudioState = { ...DEFAULT_AUDIO, dmin: 50, dmax: 1000 }\n\nconst KEYS = ['attenuation', 'pan', 'dmin', 'dmax', 'ain', 'aout', 'atout', 'rmix'] as const\n\n/** A block over `base`, each key given a bit in key order. */\nexport const readAudio = (\n props: AudioProps,\n base: AudioState,\n): { audio: AudioState; mask: number } => {\n const audio = { ...base }\n let mask = 0\n\n KEYS.forEach((key, bit) => {\n const value = props[key]\n if (value === undefined) return\n audio[key] = key === 'ain' || key === 'aout' ? Math.trunc(value) : f(value)\n mask |= 1 << bit\n })\n return { audio, mask }\n}\n\n/** `TickAudioPropAnim`: masked keys from `from` toward `to` by `u`, the angles truncated. */\nexport const blendAudio = (\n current: AudioState,\n from: AudioState,\n to: AudioState,\n mask: number,\n u: number,\n): AudioState => {\n const out = { ...current }\n\n KEYS.forEach((key, bit) => {\n if (!(mask & (1 << bit))) return\n\n const value = from[key] + (to[key] - from[key]) * u\n\n out[key] = key === 'ain' || key === 'aout' ? Math.trunc(value) : f(value)\n })\n return out\n}\n\n/** One sound a script is playing, for the host to play and to keep up to date. */\nexport interface SoundRecord {\n entity: string\n /** `[Sound]`, or `VoiceProfile_*`, `BackgroundAmbient`, `BackgroundMusic`, `PlayerShipSound`. */\n template: string\n /**\n * Milliseconds into the sound to play from: `start_time` plus how late in its tick it started\n * (`0x4574d0`). The game plays it from there.\n */\n offset: number\n loop: boolean\n /** A 3D source at the entity, `C` not applied; otherwise 2D, panned. */\n spatial: boolean\n /** The playback's clock when it started, milliseconds. */\n started: number\n}\n\n/**\n * What the game sets on a playing sound (`0x457630`): its volume in decibels, the `[Sound]`'s\n * attenuation plus the entity's and the room's ambience level `L`, each clamped to [−96, 0], and a 2D\n * sound's pan in DirectSound's hundredths, clamped to ±10,000.\n */\nexport const soundLevel = (\n archetype: number,\n { attenuation, pan }: AudioState,\n room = 0,\n): { volume: number; pan: number } => {\n const clamp = (value: number, low: number, high: number) => Math.min(high, Math.max(low, value))\n\n return {\n volume: clamp(archetype + clamp(room + attenuation, -96, 0), -96, 0),\n pan: clamp(100 * pan, -10000, 10000),\n }\n}\n","/**\n * The frame arithmetic thorn does. A frame is `x86math.dll`'s `[R | t]`, applied as `R·v + t`, and\n * `A · B` applies `B` first: the library's `Matrix4` already, holding `R`'s columns.\n *\n * Thorn's quaternions are `{w, x, y, z}`; here they are the library's `{x, y, z, w}`.\n */\nimport { Matrix3, Matrix4, Vector3, type Vector4 } from '@treewyrm/freelancer/math'\nimport { data, type AxisName } from '@treewyrm/freelancer/thn/scene'\n\nexport type Frame = Matrix4\nexport type Quaternion = Vector4\n\nconst f = Math.fround\n\n/** An entity's `spatialprops`: `orient`'s triples are `R`'s columns, which the reader has transposed. */\nexport const placement = (pos?: Vector3, orient?: Matrix3): Frame =>\n Matrix4.fromRotationTranslation(orient ?? Matrix3.identity, pos ?? Vector3.zero)\n\nexport const positionOf = ({ w }: Frame): Vector3 => ({ x: w.x, y: w.y, z: w.z })\n\nexport const withPosition = (frame: Frame, { x, y, z }: Vector3): Frame => ({\n ...frame,\n w: { x, y, z, w: 1 },\n})\n\n/** `[rotation.R | frame.t]`. */\nexport const withRotation = (frame: Frame, rotation: Frame): Frame => ({\n x: rotation.x,\n y: rotation.y,\n z: rotation.z,\n w: frame.w,\n})\n\n/** `R·v`. */\nexport const rotate = (frame: Frame, v: Vector3): Vector3 => Matrix4.transformDirection(v, frame)\n\n/** `[Rᵀ | −Rᵀ·t]`, as thorn builds every inverse it takes. */\nexport const inverse = (frame: Frame): Frame => {\n const { x, y, z } = frame\n const rotation: Frame = {\n x: { x: x.x, y: y.x, z: z.x, w: 0 },\n y: { x: x.y, y: y.y, z: z.y, w: 0 },\n z: { x: x.z, y: y.z, z: z.z, w: 0 },\n w: { x: 0, y: 0, z: 0, w: 1 },\n }\n\n return withPosition(rotation, Vector3.multiplyScalar(rotate(rotation, positionOf(frame)), -1))\n}\n\n/** The rotation whose columns are these. */\nexport const columnsOf = (a: Vector3, b: Vector3, c: Vector3): Frame => ({\n x: { ...a, w: 0 },\n y: { ...b, w: 0 },\n z: { ...c, w: 0 },\n w: { x: 0, y: 0, z: 0, w: 1 },\n})\n\n/** `R(q)` scaled by `2/|q|²`, so a non-unit `q` is tolerated: `x86math.dll` `0x6f723c0`. */\nexport const rotationOf = ({ x, y, z, w }: Quaternion): Frame => {\n const s = 2 / (w * w + x * x + y * y + z * z)\n\n return columnsOf(\n { x: 1 - s * (y * y + z * z), y: s * (x * y + w * z), z: s * (x * z - w * y) },\n { x: s * (x * y - w * z), y: 1 - s * (x * x + z * z), z: s * (y * z + w * x) },\n { x: s * (x * z + w * y), y: s * (y * z - w * x), z: 1 - s * (x * x + y * y) },\n )\n}\n\n/** `R`'s quaternion, by the trace or else its largest diagonal: `x86math.dll` `0x6f72290`. */\nexport const quaternionOf = (frame: Frame): Quaternion => {\n // m[row][column] of R; a Matrix4 holds columns.\n const m = [\n [frame.x.x, frame.y.x, frame.z.x],\n [frame.x.y, frame.y.y, frame.z.y],\n [frame.x.z, frame.y.z, frame.z.z],\n ] as const\n const trace = m[0][0] + m[1][1] + m[2][2]\n\n if (trace > 0) {\n const s = Math.sqrt(trace + 1)\n const r = 0.5 / s\n\n return {\n x: (m[2][1] - m[1][2]) * r,\n y: (m[0][2] - m[2][0]) * r,\n z: (m[1][0] - m[0][1]) * r,\n w: s * 0.5,\n }\n }\n\n // `i` is the largest diagonal entry, `j` and `k` the next two cyclically; `v` is (x, y, z).\n let i = 0\n if (m[1][1] > m[0][0]) i = 1\n if (m[2][2] > m[i]![i]!) i = 2\n\n const j = (i + 1) % 3\n const k = (j + 1) % 3\n const s = Math.sqrt(m[i]![i]! - m[j]![j]! - m[k]![k]! + 1)\n const r = 0.5 / s\n const v = [0, 0, 0]\n\n v[i] = s * 0.5\n v[j] = (m[j]![i]! + m[i]![j]!) * r\n v[k] = (m[k]![i]! + m[i]![k]!) * r\n return { x: v[0]!, y: v[1]!, z: v[2]!, w: (m[k]![j]! - m[j]![k]!) * r }\n}\n\n/**\n * `x86math.dll`'s `+0x58` (`0x6f724d0`), which every \"slerp\" in thorn is: a normalised lerp,\n * folded onto `a`'s hemisphere.\n */\nexport const nlerp = (a: Quaternion, b: Quaternion, t: number): Quaternion => {\n const dot = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w\n const k = dot < 0 ? -1 : 1\n const q = {\n x: a.x + (k * b.x - a.x) * t,\n y: a.y + (k * b.y - a.y) * t,\n z: a.z + (k * b.z - a.z) * t,\n w: a.w + (k * b.w - a.w) * t,\n }\n const n = Math.hypot(q.x, q.y, q.z, q.w)\n\n return { x: q.x / n, y: q.y / n, z: q.z / n, w: q.w / n }\n}\n\n/** Axis 0 to 5: X, Y, Z, −X, −Y, −Z. */\nexport const axisIndex = (name: AxisName | undefined, fallback: number): number =>\n name === undefined ? fallback : data.AXES[name]\n\nconst AXES: readonly Vector3[] = [\n { x: 1, y: 0, z: 0 },\n { x: 0, y: 1, z: 0 },\n { x: 0, y: 0, z: 1 },\n { x: -1, y: 0, z: 0 },\n { x: 0, y: -1, z: 0 },\n { x: 0, y: 0, z: -1 },\n]\n\nconst POLE = 0.99\n\n/**\n * `BuildAxisFrame` (`FUN_06f2e440`): the rotation turning the local `front` axis onto `d`, its `up`\n * leaning toward the scene's up, or within the pole toward `up × front` of the scene. The two axes\n * are written as columns and the third is their cross product. Retail's scene axes are always Y and\n * Z; `6` means those. `d` must not be zero.\n */\nexport const lookAt = (\n d: Vector3,\n front: number,\n up: number,\n sceneUp = 6,\n sceneFront = 6,\n): Frame => {\n // A shared up of 6 skips both shared axes.\n const U = AXES[sceneUp === 6 ? 1 : sceneUp] ?? AXES[1]!\n const F = AXES[sceneUp === 6 || sceneFront === 6 ? 2 : sceneFront] ?? AXES[2]!\n const side = Vector3.cross(U, F)\n let dir = Vector3.normalize(d)\n let lean = U\n\n if (front > 2) dir = Vector3.multiplyScalar(dir, -1)\n if (up > 2) lean = Vector3.multiplyScalar(lean, -1)\n\n const ortho =\n Math.abs(Vector3.dot(lean, dir)) > POLE\n ? Vector3.normalize(Vector3.cross(dir, side))\n : Vector3.normalize(Vector3.cross(dir, Vector3.normalize(Vector3.cross(lean, dir))))\n const out: (Vector3 | undefined)[] = [undefined, undefined, undefined]\n\n out[front % 3] = dir\n out[up % 3] = ortho\n\n // An unwritten column starts as the identity's; retail leaves the caller's buffer there.\n const [x, y, z] = out.map((each, index) => each ?? AXES[index]!) as [Vector3, Vector3, Vector3]\n if (out[0] === undefined) return columnsOf(Vector3.normalize(Vector3.cross(y, z)), y, z)\n\n if (out[1] !== undefined) {\n if (out[2] === undefined) return columnsOf(x, y, Vector3.normalize(Vector3.cross(x, y)))\n return columnsOf(x, y, z)\n }\n\n return columnsOf(x, Vector3.normalize(Vector3.cross(z, x)), z)\n}\n\n/**\n * `ApplyAxisRotFpu` (`0x6f46eef`): a turn of `degrees` about an axis, applied to `base` in scene axes\n * for X, Y and Z and in its own for the negative names, whose sign is **not** flipped.\n */\nexport const axisTurn = (base: Frame, axis: number, degrees: number): Frame => {\n if (axis < 0 || axis > 5) return base\n\n const radians = degrees * f(0.017453292)\n const c = f(Math.cos(radians))\n const s = Math.sin(radians)\n // Right-handed Rx, Ry or Rz, each written as its columns.\n const turn =\n axis % 3 === 0\n ? columnsOf({ x: 1, y: 0, z: 0 }, { x: 0, y: c, z: s }, { x: 0, y: -s, z: c })\n : axis % 3 === 1\n ? columnsOf({ x: c, y: 0, z: -s }, { x: 0, y: 1, z: 0 }, { x: s, y: 0, z: c })\n : columnsOf({ x: c, y: s, z: 0 }, { x: -s, y: c, z: 0 }, { x: 0, y: 0, z: 1 })\n\n return axis <= 2 ? Matrix4.multiply(turn, base) : Matrix4.multiply(base, turn)\n}\n","/**\n * Lights and fog as thorn holds them (`LoadLightProps`, `ApplyLightEventPost`, `EvalLightProps`,\n * `TickFogPropAnim` in `src/Thorn/`), and as the game's hosts hand them to the room\n * (`gf_thorn_light.cpp`, `GfFog*` in `gf_script.cpp`).\n */\nimport { Vector3 } from '@treewyrm/freelancer/math'\nimport { data, type FogProps, type LightProps } from '@treewyrm/freelancer/thn/scene'\nimport type { Fog } from '#/scene/nebula.js'\nimport type { RoomLight } from '#/scene/room.js'\nimport { rotate, type Frame } from './frame.js'\n\nconst f = Math.fround\nconst RADIANS = Math.PI / 180\n\n/** `kThornLightBit*`: which of a block's keys were given. */\nexport const LIGHT_BITS = {\n color: 0x1,\n direction: 0x2,\n range: 0x4,\n cutoff: 0x8,\n on: 0x10,\n infinite: 0x20,\n atten: 0x40,\n theta: 0x80,\n type: 0x100,\n specular: 0x200,\n ambient: 0x400,\n diffuse: 0x800,\n} as const\n\n/** A light block: the legacy keys and the `D3DLIGHT8` beside them. Angles in radians. */\nexport interface LightState {\n on: boolean\n infinite: boolean\n /** Whole numbers, 0 to 255, which reach nothing once there is a `type`. */\n color: Vector3\n /** In the light's own axes. */\n direction: Vector3\n /** `D3DLIGHTTYPE`: 1 point, 2 spot, 3 directional. */\n type: number\n diffuse: Vector3\n specular: Vector3\n ambient: Vector3\n range: number\n atten: Vector3\n theta: number\n /** `cutoff`, as D3D's `Phi`. */\n phi: number\n}\n\n/** `FUN_06f41840`: a white spot, range 1000, theta 144°, phi 180°, `Att2` 100 over range². */\nexport const DEFAULT_LIGHT: LightState = {\n on: true,\n infinite: false,\n color: { x: 255, y: 255, z: 255 },\n direction: { x: 0, y: 0, z: 1 },\n type: 2,\n diffuse: { x: 1, y: 1, z: 1 },\n specular: Vector3.zero,\n ambient: Vector3.zero,\n range: 1000,\n atten: { x: 0, y: 0, z: f(0.0001) },\n theta: f(2.5132741),\n phi: f(Math.PI),\n}\n\nconst truth = (name: string | undefined) => name === 'Y'\n\nconst ints = ({ x, y, z }: Vector3): Vector3 => ({\n x: Math.trunc(x),\n y: Math.trunc(y),\n z: Math.trunc(z),\n})\n\n/** `LoadLightProps` (`FUN_06f27fe0`): the keys a block gives, over `base`, and their mask. */\nexport const readLight = (\n props: LightProps,\n base: LightState,\n): { light: LightState; mask: number } => {\n const light = { ...base }\n let mask = 0\n if (props.on !== undefined) ((light.on = truth(props.on)), (mask |= LIGHT_BITS.on))\n if (props.color) ((light.color = ints(props.color)), (mask |= LIGHT_BITS.color))\n if (props.diffuse) ((light.diffuse = props.diffuse), (mask |= LIGHT_BITS.diffuse))\n if (props.specular) ((light.specular = props.specular), (mask |= LIGHT_BITS.specular))\n if (props.ambient) ((light.ambient = props.ambient), (mask |= LIGHT_BITS.ambient))\n if (props.direction) ((light.direction = props.direction), (mask |= LIGHT_BITS.direction))\n if (props.atten) ((light.atten = props.atten), (mask |= LIGHT_BITS.atten))\n if (props.type) ((light.type = data.LIGHT_TYPES[props.type]), (mask |= LIGHT_BITS.type))\n if (props.range !== undefined) ((light.range = f(props.range)), (mask |= LIGHT_BITS.range))\n\n if (props.cutoff !== undefined)\n ((light.phi = f(props.cutoff * RADIANS)), (mask |= LIGHT_BITS.cutoff))\n\n if (props.theta !== undefined)\n ((light.theta = f(props.theta * RADIANS)), (mask |= LIGHT_BITS.theta))\n\n return { light, mask }\n}\n\n/**\n * An entity's light: the record over the defaults. Only with no `type` does thorn derive the\n * `D3DLIGHT8` from the legacy keys (`0x6f29492`, `0x6f2eb20`): infinite directional, a negative\n * cutoff a point, else a spot; diffuse the colour over 255, `Att (1, 0, 4/range²)`, twice the range.\n * Every retail light has a `type`. That rule is the extension's reading, not traced here.\n */\nexport const lightOf = (props: LightProps | undefined): LightState => {\n const { light, mask } = readLight(props ?? {}, DEFAULT_LIGHT)\n if (mask & LIGHT_BITS.type) return light\n\n const cutoff = light.phi / RADIANS\n const theta = Math.min(light.phi, Math.PI)\n\n return {\n ...light,\n type: light.infinite ? 3 : cutoff < 0 ? 1 : 2,\n diffuse: Vector3.multiplyScalar(light.color, 1 / 255),\n specular: Vector3.zero,\n ambient: Vector3.zero,\n atten: { x: 1, y: 0, z: 4 / (light.range * light.range) },\n range: 2 * light.range,\n theta,\n phi: Math.min(1.1 * theta, Math.PI),\n }\n}\n\n/**\n * A `START_LIGHT_PROP_ANIM`'s block (`ApplyLightEventPost`, `FUN_06f24b40`): `color` also sets the\n * diffuse at a 255th, `infinite` the type, and a negative cutoff makes a point light.\n */\nexport const readLightTarget = (props: LightProps): { light: LightState; mask: number } => {\n const { light, mask } = readLight(props, DEFAULT_LIGHT)\n let out = mask\n\n if (out & LIGHT_BITS.color) {\n light.diffuse = Vector3.multiplyScalar(light.color, f(1 / 255))\n out |= LIGHT_BITS.diffuse\n }\n\n if (out & LIGHT_BITS.cutoff && light.phi < 0) {\n light.type = 1\n light.phi = 0\n light.theta = 0\n out |= LIGHT_BITS.type\n }\n\n return { light, mask: out }\n}\n\nconst lerp = (a: number, b: number, u: number) => f(a + (b - a) * u)\nconst lerp3 = (a: Vector3, b: Vector3, u: number): Vector3 => ({\n x: lerp(a.x, b.x, u),\n y: lerp(a.y, b.y, u),\n z: lerp(a.z, b.z, u),\n})\n\n/**\n * `EvalLightProps`: each masked field from `from` toward `to` by `u`, unclamped; the colour truncated\n * to whole numbers; `on`, `type` and `infinite` switch only once `u` reaches 1. The direction is\n * lerped and not renormalised.\n */\nexport const blendLight = (\n current: LightState,\n from: LightState,\n to: LightState,\n mask: number,\n u: number,\n): LightState => {\n const out = { ...current }\n const done = u >= 1\n\n if (mask & LIGHT_BITS.range) out.range = lerp(from.range, to.range, u)\n if (mask & LIGHT_BITS.cutoff) out.phi = lerp(from.phi, to.phi, u)\n if (mask & LIGHT_BITS.type && done) out.type = to.type\n if (mask & LIGHT_BITS.theta) out.theta = lerp(from.theta, to.theta, u)\n if (mask & LIGHT_BITS.specular) out.specular = lerp3(from.specular, to.specular, u)\n if (mask & LIGHT_BITS.ambient) out.ambient = lerp3(from.ambient, to.ambient, u)\n if (mask & LIGHT_BITS.diffuse) out.diffuse = lerp3(from.diffuse, to.diffuse, u)\n if (mask & LIGHT_BITS.atten) out.atten = lerp3(from.atten, to.atten, u)\n if (mask & LIGHT_BITS.color) out.color = ints(lerp3(from.color, to.color, u))\n if (mask & LIGHT_BITS.infinite && done) out.infinite = to.infinite\n if (mask & LIGHT_BITS.direction) out.direction = lerp3(from.direction, to.direction, u)\n if (mask & LIGHT_BITS.on && done) out.on = to.on\n return out\n}\n\n/**\n * The room's light for a THN light (`Thorn_Light`, `0x452fa0`, and `GameLight::set_d3d`, `0x411120`):\n * at thorn's position, `C` not applied, shining along its frame's turn of `direction`. A point's\n * cone is a whole sphere; a phi past π is π; no attenuation at all is 0.1 constant. Its type is the\n * one it was made with: a later change is ignored. `lt_grp` picks what it lights.\n */\nexport const roomLightOf = (\n light: LightState,\n madeAs: number,\n frame: Frame,\n group: number,\n): RoomLight => {\n const direction = Vector3.normalize(rotate(frame, light.direction))\n const zero = light.atten.x === 0 && light.atten.y === 0 && light.atten.z === 0\n const point = madeAs === 1\n\n return {\n group,\n color: light.diffuse,\n direction,\n ...(light.ambient.x || light.ambient.y || light.ambient.z ? { ambient: light.ambient } : {}),\n ...(madeAs !== 3 && {\n position: { x: frame.w.x, y: frame.w.y, z: frame.w.z },\n range: light.range,\n attenuation: zero ? { x: f(0.1), y: 0, z: 0 } : light.atten,\n ...(!point && {\n spot: { theta: light.theta, phi: Math.min(light.phi, f(Math.PI)), falloff: 1 },\n }),\n }),\n }\n}\n\n/** `GfFog`'s one global state, which every script's `SCENE` shares. Zeroed at room setup. */\nexport interface FogState {\n on: boolean\n /** `fogtable` as passed: true writes `FOGTABLEMODE`, so `Y` is table fog and `N` vertex fog. */\n table: boolean\n /** Whole numbers, 0 to 255. */\n color: Vector3\n /** `D3DFOGMODE`: 0 none, 1 exp, 2 exp2, 3 linear. */\n mode: number\n start: number\n end: number\n density: number\n}\n\nexport const NO_FOG: FogState = {\n on: false,\n table: false,\n color: Vector3.zero,\n mode: 0,\n start: 0,\n end: 0,\n density: 0,\n}\n\n/** A `fogprops` block's values and mask (`0x6f27c50`): on 1, table 2, colour 4, mode 8, then 0x10–0x40. */\nexport const readFog = (props: FogProps): { fog: FogState; mask: number } => {\n const fog = { ...NO_FOG }\n let mask = 0\n if (props.fogon !== undefined) ((fog.on = truth(props.fogon)), (mask |= 1))\n if (props.fogtable !== undefined) ((fog.table = truth(props.fogtable)), (mask |= 2))\n if (props.fogcolor) ((fog.color = ints(props.fogcolor)), (mask |= 4))\n if (props.fogmode) ((fog.mode = data.FOG_MODES[props.fogmode]), (mask |= 8))\n if (props.fogstart !== undefined) ((fog.start = f(props.fogstart)), (mask |= 0x10))\n if (props.fogend !== undefined) ((fog.end = f(props.fogend)), (mask |= 0x20))\n if (props.fogdensity !== undefined) ((fog.density = f(props.fogdensity)), (mask |= 0x40))\n return { fog, mask }\n}\n\n/** `TickFogPropAnim`: on, table and mode switch at `u ≥ 1`; the rest lerp, the colour truncated. */\nexport const blendFog = (\n current: FogState,\n from: FogState,\n to: FogState,\n mask: number,\n u: number,\n): FogState => {\n const out = { ...current }\n\n if (u >= 1) {\n if (mask & 1) out.on = to.on\n if (mask & 2) out.table = to.table\n if (mask & 8) out.mode = to.mode\n }\n\n if (mask & 0x10) out.start = lerp(from.start, to.start, u)\n if (mask & 0x20) out.end = lerp(from.end, to.end, u)\n if (mask & 0x40) out.density = lerp(from.density, to.density, u)\n if (mask & 4) out.color = ints(lerp3(from.color, to.color, u))\n return out\n}\n\nconst MODES = { 1: 'exp', 2: 'exp2', 3: 'linear' } as const\n\n/**\n * The room's fog (`GfFogApply`, `0x454250`): when on and the `fog` option is, in D3D's mode. Per pixel\n * here whichever of vertex and table fog the script asks for.\n */\nexport const roomFogOf = (fog: FogState, enabled = true): Fog | undefined => {\n const mode = MODES[fog.mode as 1 | 2 | 3]\n if (!fog.on || !enabled || !mode) return undefined\n return {\n color: Vector3.multiplyScalar(fog.color, 1 / 255),\n start: fog.start,\n end: fog.end,\n mode,\n density: fog.density,\n }\n}\n","/**\n * A script's events as thorn's parser and factory make them (`0x6f25400`, `AddEventFromDesc`), and\n * what each action does when it starts and at every update (`FThornEvent::Start`, `StillRunning`).\n */\nimport { Matrix4, Vector3 } from '@treewyrm/freelancer/math'\nimport { data, type Event, type EventTypeName, type Script } from '@treewyrm/freelancer/thn/scene'\nimport type { Value } from '@treewyrm/freelancer/thn'\nimport { createCurve, progress, type Timing } from './curve.js'\nimport type { Path } from './path.js'\nimport { blendAudio, DEFAULT_AUDIO_TARGET, readAudio, type AudioState } from './sound.js'\nimport {\n blendFog,\n blendLight,\n readFog,\n readLightTarget,\n type FogState,\n type LightState,\n} from './light.js'\nimport {\n axisIndex,\n axisTurn,\n inverse,\n lookAt,\n nlerp,\n placement,\n positionOf,\n quaternionOf,\n rotate,\n rotationOf,\n type Frame,\n type Quaternion,\n} from './frame.js'\n\nconst f = Math.fround\n\n/** The flag word's bits (`ThornScene.h`). Bit 16 is `q_orient`'s, read by nothing here. */\nexport const FLAGS = {\n USE_SCRIPT_DURATION: 1,\n PATH_POSITION: 2,\n ...data.ATTACH_FLAGS,\n ...data.SOUND_FLAGS,\n} as const\n\n/** What an event needs of the playback it runs in. */\nexport interface Stage {\n /** Thorn's frame for an entity: scene space, which the host keeps. */\n frame(entity: number): Frame\n setPosition(entity: number, position: Vector3): void\n setOrientation(entity: number, orientation: Frame): void\n /** Whether it has an `ICompoundControl`: a `COMPOUND` or `DEFORMABLE`. */\n compound(entity: number): boolean\n /** `ICompoundControl +0x24` for a `target_type` and `target_part`: nothing when it writes nothing. */\n part(entity: number, type: number, name: string): Frame | undefined\n path(entity: number): Path | undefined\n /** `ICompoundControl +0x1c`/`+0x20`, which the host makes a parent link of. */\n connect(event: ThornEvent): void\n disconnect(event: ThornEvent): void\n /** A camera's or monitor's `{fovh, near, far, aspect}`, as thorn caches them. */\n cameraProps(entity: number): CameraProps\n /** `ApplyCameraProps`: stored, and on from a camera to every monitor linked to it. */\n setCameraProps(entity: number, props: CameraProps): void\n /** `SET_CAMERA`'s link: the monitor follows the camera from now on. */\n cut(monitor: number, camera: number): void\n /** Whether the entity is a `CAMERA` (not a `MONITOR`). */\n camera(entity: number): boolean\n /** A `LIGHT`'s block as its host holds it, or nothing for another entity. */\n light(entity: number): LightState | undefined\n setLight(entity: number, light: LightState): void\n /** The host's one fog state, `on` as in effect (`0x454480`). */\n fog(): FogState\n /** `0x6f43140`: pushed by mask. */\n setFog(fog: FogState, mask: number): void\n /** The entity's type. */\n kind(entity: number): string | undefined\n /** `IPSysControl +0xc`: a new instance of its effect; false where the game made no host. */\n psysStart(entity: number): boolean\n /** `+0x10`: the effect killed outright. */\n psysStop(entity: number): void\n /** `+0x1c`: the host's cache of the last `sparam` set, 0 at first. */\n sparam(entity: number): number\n /** `+0x18`: cached, and handed to the effect only while one runs. */\n setSparam(entity: number, value: number): void\n /** The clock after the tick's step, which a starting event is handed (`ClockAfterDt_`). */\n readonly now: number\n /** `ISoundControl +0xc`: plays the entity's sound, cutting off what it was playing. */\n soundStart(entity: number, record: { offset: number; loop: boolean; spatial: boolean }): boolean\n /** `+0x10`: cut dead. */\n soundStop(entity: number): void\n /** `ICompoundControl +0xc`/`+0x10`: a script started on a compound or character, and stopped. */\n motionStart(entity: number, motion: MotionRecord): boolean\n motionStop(entity: number, motion: MotionRecord): void\n /** `IIKControl +0xc`/`+0x14`/`+0x10`: a character's aim, its target re-sent at every update. */\n aimStart(entity: number, aim: AimRecord): boolean\n aimUpdate(entity: number, aim: AimRecord): void\n aimStop(entity: number, aim: AimRecord): void\n /** `ICompoundControl +0x28`/`+0x14`: a character's floor height. */\n floor(entity: number): number | undefined\n setFloor(entity: number, height: number): void\n /** A `SOUND`'s `audioprops`, or nothing for another entity. */\n audio(entity: number): AudioState | undefined\n setAudio(entity: number, audio: AudioState): void\n readonly sceneUp: number\n readonly sceneFront: number\n}\n\n/** A `START_MOTION` as thorn hands it to the host (`ApplyMotionDesc`, parser `0x6f25a9d`). */\nexport interface MotionRecord {\n readonly event: Event\n animation: string\n /** Seconds into each channel. */\n startTime: number\n /** The blend-in, seconds; 0 replaces. */\n transTime: number\n timeScale: number\n /** An amplitude, not a mix weight. */\n weight: number\n /** Radians, or −1 for the character's own yaw. Only parsed off a `COMPOUND`. */\n heading: number\n /** Only parsed on a `COMPOUND`: its object map's translation scale. */\n transScale: number\n lockedBone: string | undefined\n /** 1 backwards, 2 loop, 4 bounce, 128 keep what is beneath once blended in. */\n eventFlags: number\n}\n\n/** A `START_IK` as thorn hands it on (`BuildIkPose`): the target and the look-at toward it, in scene space. */\nexport interface AimRecord {\n readonly event: Event\n endEffector: string\n countToRoot: number\n damping: number\n pointAt: boolean\n moveTo: boolean\n /** Seconds. */\n transitionDuration: number\n eventFlags: number\n target: Vector3\n /** Turns the joint's `front` onto the target, its `up` toward the scene's. */\n rotation: Frame\n}\n\n/** Thorn's four camera slots: `fovh` (half the horizontal angle, degrees), planes, and `hvaspect`. */\nexport type CameraProps = readonly [fovh: number, near: number, far: number, aspect: number]\n\n/** One event, from load to finish. */\nexport interface ThornEvent {\n /** The action it runs as: a `START_PATH_ANIMATION` on an entity becomes an `ATTACH_ENTITY`. */\n readonly action: EventTypeName\n readonly type: number\n readonly source: Event\n /** Milliseconds. */\n readonly start: number\n readonly duration: number\n readonly flags: number\n readonly primary: number\n /** −1 for none. */\n readonly secondary: number\n /** Set at start: −1 never ends. */\n end: number\n /** True to join the active list. */\n begin(stage: Stage): boolean\n /** One update at `now`; the engine then asks whether it still runs. */\n update(stage: Stage, now: number): void\n /** Its end, or every running event's at a stop: `FThornEvent::Stop`. */\n finish?(stage: Stage): void\n}\n\n/**\n * Seconds to whole milliseconds: `time · 1000` rounded to the x87's 24-bit precision, which D3D8\n * leaves it at without `FPU_PRESERVE`, then chopped (`LuaMillisecondsToRetailInt`).\n */\nexport const milliseconds = (seconds: number): number => Math.trunc(f(seconds * 1000))\n\n/** A flag set as the parser reads it, from the typed `flags` or one the typed layer left unknown. */\nconst flagNames = (event: Event): readonly string[] | number | undefined => {\n if ('flags' in event && event.flags) return event.flags\n\n const raw: Value | undefined = event.unknown?.['flags']\n if (raw?.type === 'identifier') return raw.names\n if (raw?.type === 'number') return Number(raw.literal)\n return undefined\n}\n\n/**\n * The flag word: bit 1 when `duration` is nil (`0x6f25760`), then a `flags` key replaces it whole\n * (`0x6f257c9`). `STREAM` and `FOG_PROPS_REMOVED` have no measured bit, so count for nothing.\n */\nexport const flagWord = (event: Event): number => {\n const names = flagNames(event)\n if (names === undefined) return event.duration === undefined ? FLAGS.USE_SCRIPT_DURATION : 0\n if (typeof names === 'number') return names\n\n let word = 0\n for (const name of names) word |= (FLAGS as Record<string, number>)[name] ?? 0\n return word\n}\n\nconst unknownTarget = (event: Event) => {\n const type = event.unknown?.['target_type']\n const part = event.unknown?.['target_part']\n const types = data.TARGET_TYPES as Record<string, number>\n\n return {\n type:\n type?.type === 'identifier' && type.names.length === 1\n ? types[type.names[0]!]\n : type?.type === 'number'\n ? Number(type.literal)\n : undefined,\n part: part?.type === 'string' ? part.value : undefined,\n }\n}\n\n/** `target_type` and `target_part`, wherever the typed layer put them. */\nconst targetOf = (event: Event): { type: number; part: string | undefined } => {\n const raw = unknownTarget(event)\n const typed =\n 'target_type' in event && event.target_type !== undefined\n ? data.TARGET_TYPES[event.target_type]\n : undefined\n const part = 'target_part' in event ? event.target_part : undefined\n\n return { type: typed ?? raw.type ?? 0, part: part ?? raw.part }\n}\n\nconst timingOf = (event: Event, start: number, duration: number): Timing => ({\n start,\n duration,\n ...(event.param_curve && { curve: createCurve(event.param_curve) }),\n // `_ftol` of the value, milliseconds with no ×1000 (`0x6f25885`); −1 when absent.\n period: event.pcurve_period === undefined ? -1 : Math.trunc(event.pcurve_period),\n})\n\n/** `ApplyEndTime`: never with `USE_SCRIPT_DURATION`, else `start + duration`. */\nconst endOf = (flags: number, start: number, duration: number): number =>\n flags & FLAGS.USE_SCRIPT_DURATION ? -1 : (start + duration) | 0\n\n/** Whether `+0x24` is asked: a `target_part`, a `target_type` other than `ROOT`, on a compound. */\nconst asksPart = (stage: Stage, parent: number, type: number, part: string | undefined) =>\n part !== undefined && type !== 0 && stage.compound(parent)\n\n/** An attach's `P`: the frame `+0x24` writes over the parent's own, which a miss leaves. */\nconst parentFrame = (stage: Stage, parent: number, type: number, part: string | undefined) =>\n (asksPart(stage, parent, type, part) && stage.part(parent, type, part!)) || stage.frame(parent)\n\n/** `ATTACH_ENTITY` (`StartAttachEntity`, `TickAttachEntity`). */\nconst attach = (base: Base, event: Event): ThornEvent => {\n const { type, part } = targetOf(event)\n const offset = ('offset' in event && event.offset) || Vector3.zero\n const front = axisIndex('front' in event ? event.front : undefined, 5)\n const up = axisIndex('up' in event ? event.up : undefined, 1)\n const has = (bit: number) => (base.flags & bit) !== 0\n let rel: Frame = Matrix4.identity\n\n return {\n ...base,\n action: 'ATTACH_ENTITY',\n type: data.EVENT_TYPES.ATTACH_ENTITY,\n begin(stage) {\n this.end = endOf(base.flags, base.start, base.duration)\n\n // Whatever the flags; only `PARENT_CHILD` and `ORIENTATION_RELATIVE` read it.\n const P = parentFrame(stage, base.secondary, type, part)\n\n // The child's frame in `P`'s space, so `P · rel` holds it where it was as `P` moves.\n rel = Matrix4.multiply(inverse(P), stage.frame(base.primary))\n return true\n },\n update(stage) {\n const P = parentFrame(stage, base.secondary, type, part)\n const child = base.primary\n\n if (has(FLAGS.PARENT_CHILD)) {\n const held = Matrix4.multiply(P, rel)\n if (has(FLAGS.POSITION)) stage.setPosition(child, positionOf(held))\n if (has(FLAGS.ORIENTATION)) stage.setOrientation(child, held)\n return\n }\n\n const o = has(FLAGS.ENTITY_RELATIVE) ? rotate(P, offset) : offset\n const target = Vector3.add(positionOf(P), o)\n if (has(FLAGS.POSITION)) stage.setPosition(child, target)\n\n if (has(FLAGS.ORIENTATION))\n stage.setOrientation(child, has(FLAGS.ORIENTATION_RELATIVE) ? Matrix4.multiply(P, rel) : P)\n else if (has(FLAGS.LOOK_AT)) {\n // From where the child is now, after any position written above.\n const d = Vector3.subtract(target, positionOf(stage.frame(child)))\n\n if (Vector3.dot(d, d) !== 0)\n stage.setOrientation(child, lookAt(d, front, up, stage.sceneUp, stage.sceneFront))\n }\n },\n }\n}\n\n/**\n * `START_PATH_ANIMATION` (`TickPathAnim`): the object along its path's frame as it is now, between\n * `start_percent` and `stop_percent`. Orientation, then position, every update.\n */\nconst pathAnimation = (\n base: Base,\n event: Event & { action: 'START_PATH_ANIMATION' },\n): ThornEvent => {\n const from = event.start_percent ?? 0\n const scale = f((event.stop_percent ?? 1) - from)\n const offset = event.offset ?? Vector3.zero\n const front = axisIndex(event.front, 5)\n const up = axisIndex(event.up, 1)\n const has = (bit: number) => (base.flags & bit) !== 0\n\n /** `EvaluateControlBackedCurve`: 1 for a zero span, the start plus the span's share, unclamped. */\n const percent = (now: number): number => {\n if (scale === 0) return 1\n\n const { curve, period, start, duration } = base.timing\n const elapsed = now - start\n const share = curve\n ? curve.evaluate(period > 0 ? f((elapsed % period) / period) : f(elapsed / duration))\n : elapsed / duration\n\n return share * scale + from\n }\n\n return {\n ...base,\n begin() {\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n const path = stage.path(base.secondary)\n if (!path) return\n\n const u = percent(now)\n const object = stage.frame(base.primary)\n const R = stage.frame(base.secondary)\n let position = positionOf(object)\n let orientation: Frame = object\n const at = has(FLAGS.POSITION) ? path.position(u) : undefined\n if (at) position = Matrix4.transformPoint(Vector3.add(at, offset), R)\n\n if (has(FLAGS.ORIENTATION))\n if (has(FLAGS.LOOK_AT)) {\n const tangent = path.tangent(u)\n\n if (tangent)\n orientation = lookAt(rotate(R, tangent), front, up, stage.sceneUp, stage.sceneFront)\n } else {\n const q = path.orientation(u)\n if (q) orientation = Matrix4.multiply(R, rotationOf(q))\n }\n\n stage.setOrientation(base.primary, orientation)\n stage.setPosition(base.primary, position)\n },\n }\n}\n\n/**\n * `START_SPATIAL_PROP_ANIM` (`TickSpatialPropAnim`): each update moves the entity the share still\n * left of the way to an absolute target, or a second entity's live frame, then turns `axisrot`.\n */\nconst spatialAnimation = (\n base: Base,\n event: Event & { action: 'START_SPATIAL_PROP_ANIM' },\n): ThornEvent => {\n const props = event.spatialprops ?? {}\n const mask =\n (props.pos ? 1 : 0) | (props.q_orient || props.orient ? 2 : 0) | (props.axisrot ? 4 : 0)\n const { type, part } = targetOf(event)\n const toPosition = props.pos ?? Vector3.zero\n const toQuaternion: Quaternion =\n props.q_orient ?? quaternionOf(placement(undefined, props.orient))\n const [angle = 0, axisName] = props.axisrot ?? []\n const axis = axisIndex(axisName, 1)\n let last = 0\n let applied = 0\n\n return {\n ...base,\n begin() {\n applied = 0\n last = 0\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n if (mask === 0) return\n\n const u = f(progress(base.timing, now))\n // `SpatialWrapScale`: the share of what's left, kept on the target once `u` reaches 1.\n const delta = f(u - last)\n let share: number\n\n if (delta === 0) share = 0\n else if (u >= 1) share = 1\n else if (f(1 - last) === 0) ((share = 1), (last = u))\n else ((share = f(delta / (1 - last))), (last = u))\n\n const current = stage.frame(base.primary)\n const from = positionOf(current)\n const fromQuaternion = quaternionOf(current)\n let target = { position: toPosition, quaternion: toQuaternion }\n\n if (base.secondary !== -1) {\n // `+0x24` writes over an identity at the origin here, so a miss is that (`0x6f46d23`).\n const other = asksPart(stage, base.secondary, type, part)\n ? (stage.part(base.secondary, type, part!) ?? Matrix4.identity)\n : stage.frame(base.secondary)\n\n target = { position: positionOf(other), quaternion: quaternionOf(other) }\n }\n\n if (mask & 1)\n stage.setPosition(\n base.primary,\n Vector3.add(from, Vector3.multiplyScalar(Vector3.subtract(target.position, from), share)),\n )\n\n if (mask & 2)\n stage.setOrientation(\n base.primary,\n rotationOf(nlerp(fromQuaternion, target.quaternion, share)),\n )\n\n if (mask & 4) {\n // Degrees still to turn: the total at `u` less what earlier updates already applied.\n const turn = f(u * angle - applied)\n\n applied = f(u * angle)\n // From the orientation read before this update's own write.\n stage.setOrientation(base.primary, axisTurn(rotationOf(fromQuaternion), axis, turn))\n }\n },\n }\n}\n\n/**\n * `CONNECT_HARDPOINTS`: thorn computes nothing, and hands the event to the first target's host at\n * its start and its end (`0x6f48320`, `0x6f483c0`). The game's failures log and still succeed.\n */\nconst connection = (base: Base): ThornEvent => ({\n ...base,\n begin(stage) {\n this.end = endOf(base.flags, base.start, base.duration)\n if (!stage.compound(base.primary)) return false\n stage.connect(this)\n return true\n },\n update() {},\n finish(stage) {\n stage.disconnect(this)\n },\n})\n\n/**\n * `SET_CAMERA` (`StartSetCamera`, `0x6f44ec0`): links monitor and camera, copies the camera's slots and\n * pose onto the monitor, and returns false, so it is never active and its duration means nothing.\n */\nconst setCamera = (base: Base): ThornEvent => ({\n ...base,\n begin(stage) {\n stage.cut(base.primary, base.secondary)\n return false\n },\n update() {},\n})\n\n/**\n * `START_CAMERA_PROP_ANIM` (`TickCameraPropAnim`). Its keys land **by position** (`0x6f5e148`):\n * `fovh` the fov, `aspect` the near plane, `near` the far plane, `far` the aspect. `from` is a\n * camera's slots at the start; `to` the event's, or a second camera's live ones.\n */\nconst cameraAnimation = (\n base: Base,\n event: Event & { action: 'START_CAMERA_PROP_ANIM' },\n): ThornEvent => {\n const keys = event.cameraprops ?? {}\n const values = [keys.fovh, keys.aspect, keys.near, keys.far]\n const mask = values.reduce<number>(\n (bits, value, slot) => (value === undefined ? bits : bits | (1 << slot)),\n 0,\n )\n const to = values.map((value) => f(value ?? 0))\n let from: readonly number[] = [0, 0, 0, 0]\n\n return {\n ...base,\n begin(stage) {\n if (stage.camera(base.primary)) from = stage.cameraProps(base.primary)\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n if (mask === 0) return\n\n const target =\n base.secondary !== -1 && stage.camera(base.secondary)\n ? stage.cameraProps(base.secondary)\n : to\n const u = progress(base.timing, now)\n const out = [...stage.cameraProps(base.primary)]\n\n for (let slot = 0; slot < 4; slot++)\n if (mask & (1 << slot)) out[slot] = f(from[slot]! + (target[slot]! - from[slot]!) * u)\n\n stage.setCameraProps(base.primary, out as unknown as CameraProps)\n },\n }\n}\n\n/**\n * `START_LIGHT_PROP_ANIM` (`StartLightPropAnim`, `TickLightPropAnim`): a light from its block as it\n * started toward the event's, or a second light's live one. On a `SCENE` it animates the ambient\n * through `ILightControl`, which the game doesn't implement: nothing.\n */\nconst lightAnimation = (\n base: Base,\n event: Event & { action: 'START_LIGHT_PROP_ANIM' },\n): ThornEvent => {\n const { light: to, mask } = readLightTarget(event.lightprops ?? {})\n let from: LightState | undefined\n\n return {\n ...base,\n begin(stage) {\n from = stage.light(base.primary)\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n if (mask === 0) return\n\n const target = (base.secondary !== -1 && stage.light(base.secondary)) || to\n const current = stage.light(base.primary)\n if (!current || !from) return\n stage.setLight(\n base.primary,\n blendLight(current, from, target, mask, progress(base.timing, now)),\n )\n },\n }\n}\n\n/** `START_FOG_PROP_ANIM` (`StartFogPropAnim`, `TickFogPropAnim`), always on the `SCENE`. */\nconst fogAnimation = (base: Base, event: Event & { action: 'START_FOG_PROP_ANIM' }): ThornEvent => {\n const { fog: to, mask } = readFog(event.fogprops ?? {})\n let from: FogState | undefined\n\n return {\n ...base,\n begin(stage) {\n if (stage.kind(base.primary) === 'SCENE') from = stage.fog()\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n if (mask === 0 || !from || stage.kind(base.primary) !== 'SCENE') return\n\n const u = f(progress(base.timing, now))\n\n stage.setFog(blendFog(stage.fog(), from, to, mask, u), mask)\n },\n }\n}\n\n/**\n * `START_PSYS` (`0x6f48760`): the one Start with no end-time prologue, so its end is `start +\n * duration` whatever the flags, and its end kills the effect: the duration is its whole life.\n */\nconst startPsys = (base: Base): ThornEvent => ({\n ...base,\n begin(stage) {\n this.end = (base.start + base.duration) | 0\n return stage.kind(base.primary) === 'PSYS' && stage.psysStart(base.primary)\n },\n update() {},\n finish(stage) {\n stage.psysStop(base.primary)\n },\n})\n\n/**\n * `START_PSYS_PROP_ANIM` (`StartPsysPropAnim`, `TickPsysPropAnim`): `sparam` from the host's cache at\n * the start toward the event's, or a second effect's cached one, by the shared progress.\n */\nconst psysAnimation = (\n base: Base,\n event: Event & { action: 'START_PSYS_PROP_ANIM' },\n): ThornEvent => {\n const to = event.psysprops?.sparam\n let from = 0\n\n return {\n ...base,\n begin(stage) {\n if (stage.kind(base.primary) === 'PSYS') from = stage.sparam(base.primary)\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n if (to === undefined || stage.kind(base.primary) !== 'PSYS') return\n\n const target =\n base.secondary !== -1 && stage.kind(base.secondary) === 'PSYS'\n ? stage.sparam(base.secondary)\n : f(to)\n const u = f(progress(base.timing, now))\n\n stage.setSparam(base.primary, f(from + (target - from) * u))\n },\n }\n}\n\n/**\n * `START_SOUND` (`0x6f44a20`, the host's `0x4574d0`): plays from `start_time`, integer milliseconds\n * with no ×1000, plus how far past its start the tick's clock is; `LOOP` loops it; its end cuts it.\n */\nconst startSound = (\n base: Base,\n event: Event & { action: 'START_SOUND' },\n /** Made `SPATIAL` by any `START_SOUND` of its own with flags bit 2, at parse (`0x6f258fd`). */\n spatial: boolean,\n): ThornEvent => {\n const offset = Math.trunc(event.start_time ?? 0)\n\n return {\n ...base,\n begin(stage) {\n this.end = endOf(base.flags, base.start, base.duration)\n if (stage.kind(base.primary) !== 'SOUND') return false\n return stage.soundStart(base.primary, {\n offset: offset + (stage.now - base.start),\n loop: (base.flags & FLAGS.LOOP) !== 0,\n spatial,\n })\n },\n update() {},\n finish(stage) {\n stage.soundStop(base.primary)\n },\n }\n}\n\n/** `START_AUDIO_PROP_ANIM` (`StartAudioPropAnim`, `TickAudioPropAnim`): all eight sent every update. */\nconst audioAnimation = (\n base: Base,\n event: Event & { action: 'START_AUDIO_PROP_ANIM' },\n): ThornEvent => {\n const { audio: to, mask } = readAudio(event.audioprops ?? {}, DEFAULT_AUDIO_TARGET)\n let from: AudioState | undefined\n\n return {\n ...base,\n begin(stage) {\n from = stage.audio(base.primary) ?? from\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n const current = stage.audio(base.primary)\n if (mask === 0 || !current || !from) return\n\n const target = (base.secondary !== -1 && stage.audio(base.secondary)) || to\n\n stage.setAudio(\n base.primary,\n blendAudio(current, from, target, mask, progress(base.timing, now)),\n )\n },\n }\n}\n\n/** `START_MOTION` (`0x6f43cd0`): the whole record to the host, kept on `S_OK`; Finish stops it at once. */\nconst startMotion = (\n base: Base,\n event: Event & { action: 'START_MOTION' },\n compound: boolean,\n): ThornEvent => {\n const motion: MotionRecord = {\n event,\n animation: event.animation ?? '',\n startTime: f(event.start_time ?? 0),\n transTime: f(event.trans_time ?? 0),\n timeScale: f(event.time_scale ?? 1),\n weight: f(event.weight ?? 1),\n heading: compound ? -1 : f(event.heading ?? -1),\n transScale: compound ? f(event.trans_scale ?? 1) : 1,\n lockedBone: event.locked_bone,\n eventFlags: event.event_flags ?? 0,\n }\n\n return {\n ...base,\n begin(stage) {\n this.end = endOf(base.flags, base.start, base.duration)\n return stage.compound(base.primary) && stage.motionStart(base.primary, motion)\n },\n update() {},\n finish(stage) {\n stage.motionStop(base.primary, motion)\n },\n }\n}\n\n/**\n * `START_IK` (`0x6f44140`, `0x6f444f0`): the end effector's bone frame, the target's position or its\n * part's, and the look-at from one to the other, which the host's aim takes at start and every\n * update. Only a character has an `IIKControl`.\n */\nconst startIk = (base: Base, event: Event & { action: 'START_IK' }): ThornEvent => {\n const { type, part } = targetOf(event)\n const front = axisIndex(event.front, 5)\n const up = axisIndex(event.up, 1)\n\n const aim = (stage: Stage): AimRecord => {\n const effector =\n stage.part(base.primary, data.TARGET_TYPES.PART, event.end_effector ?? '') ?? Matrix4.identity\n let target = positionOf(stage.frame(base.secondary))\n\n if (part !== undefined && type !== 0 && stage.compound(base.secondary)) {\n const found = stage.part(base.secondary, type, part)\n // `+0x24` writes over the target's position and an identity, a miss leaving them.\n if (found) target = positionOf(found)\n }\n\n return {\n event,\n endEffector: event.end_effector ?? '',\n countToRoot: event.count_to_root ?? 0,\n damping: f(event.damping ?? 1),\n pointAt: (event.point_at ?? 0) !== 0,\n moveTo: (event.move_to ?? 0) !== 0,\n transitionDuration: f(event.transition_duration ?? 1),\n eventFlags: event.event_flags ?? 0,\n target,\n rotation: lookAt(\n Vector3.subtract(target, positionOf(effector)),\n front,\n up,\n stage.sceneUp,\n stage.sceneFront,\n ),\n }\n }\n\n let current: AimRecord | undefined\n\n return {\n ...base,\n begin(stage) {\n this.end = endOf(base.flags, base.start, base.duration)\n if (stage.kind(base.primary) !== 'DEFORMABLE') return false\n current = aim(stage)\n return stage.aimStart(base.primary, current)\n },\n update(stage) {\n if (stage.kind(base.primary) !== 'DEFORMABLE') return\n current = aim(stage)\n stage.aimUpdate(base.primary, current)\n },\n finish(stage) {\n if (current) stage.aimStop(base.primary, current)\n },\n }\n}\n\n/**\n * `START_FLR_HEIGHT_ANIM` (`StartFloorHeightAnim`, `TickFloorHeightAnim`): a character's floor chases\n * `floor_height`, or a second entity's `y`, or its part's, by the share still left, as a spatial\n * animation chases its target.\n */\nconst floorAnimation = (\n base: Base,\n event: Event & { action: 'START_FLR_HEIGHT_ANIM' },\n): ThornEvent => {\n const { type, part } = targetOf(event)\n const height = f(event.floor_height ?? 0)\n let last = 0\n\n return {\n ...base,\n begin() {\n last = 0\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n },\n update(stage, now) {\n const current = stage.floor(base.primary)\n if (current === undefined) return\n\n const u = f(progress(base.timing, now))\n const delta = f(u - last)\n let share: number\n\n if (delta === 0) share = 0\n else if (u >= 1) share = 1\n else if (f(1 - last) === 0) ((share = 1), (last = u))\n else ((share = f(delta / (1 - last))), (last = u))\n\n let target = height\n\n if (base.secondary !== -1) {\n target = positionOf(stage.frame(base.secondary)).y\n\n if (part !== undefined && type !== 0 && stage.compound(base.secondary)) {\n const found = stage.part(base.secondary, type, part)\n if (found) target = found.w.y\n }\n }\n\n stage.setFloor(base.primary, f(current + (target - current) * share))\n },\n }\n}\n\n/** An action run for its timing alone: what it does belongs to a later step. */\nconst inert = (base: Base): ThornEvent => ({\n ...base,\n begin() {\n switch (base.action) {\n default:\n // A motion, sound or IK joins only on its host's `S_OK`: taken as given until its step.\n this.end = endOf(base.flags, base.start, base.duration)\n return true\n }\n },\n update() {},\n})\n\ntype Base = Omit<ThornEvent, 'begin' | 'update'> & { timing: Timing }\n\n/** The actions this library runs. The rest are scheduled and timed, and do nothing yet. */\nexport const RUN: ReadonlySet<EventTypeName> = new Set([\n 'ATTACH_ENTITY',\n 'CONNECT_HARDPOINTS',\n 'SET_CAMERA',\n 'START_CAMERA_PROP_ANIM',\n 'START_FOG_PROP_ANIM',\n 'START_LIGHT_PROP_ANIM',\n 'START_PSYS',\n 'START_PSYS_PROP_ANIM',\n 'START_SOUND',\n 'START_AUDIO_PROP_ANIM',\n 'START_MOTION',\n 'START_IK',\n 'START_FLR_HEIGHT_ANIM',\n 'START_PATH_ANIMATION',\n 'START_SPATIAL_PROP_ANIM',\n])\n\n/** Actions the factory refuses without a second target (`EventAllowsMissingSecondary`). */\nconst NEEDS_SECOND: ReadonlySet<EventTypeName> = new Set([\n 'SET_CAMERA',\n 'START_PATH_ANIMATION',\n 'ATTACH_ENTITY',\n 'CONNECT_HARDPOINTS',\n 'START_IK',\n])\n\n/**\n * Every event the factory accepts, in script order: a first target that names an entity, and a\n * second that does when given or required. Entity ids are the script's order, first name winning.\n */\nexport const eventsOf = (script: Script): ThornEvent[] => {\n const ids = new Map<string, number>()\n\n script.entities.forEach((entity, index) => {\n if (!ids.has(entity.entity_name)) ids.set(entity.entity_name, index)\n })\n\n const out: ThornEvent[] = []\n // The parser ORs 2 into a sound entity's own flags for each of these, so every start hears it.\n const spatial = new Set(\n script.events.flatMap((source) =>\n source.action === 'START_SOUND' && flagWord(source) & 2\n ? [ids.get(source.targets[0] ?? '')]\n : [],\n ),\n )\n\n for (const source of script.events) {\n const [first, second] = source.targets\n const primary = first === undefined ? undefined : ids.get(first)\n const secondary = second === undefined ? -1 : (ids.get(second) ?? -2)\n if (primary === undefined || secondary === -2) continue\n\n let action: EventTypeName = source.action\n\n // A path animation onto an entity of type 1 to 8 is parsed as an attach (`0x6f258c0`).\n if (action === 'START_PATH_ANIMATION' && secondary >= 0) {\n const kind = data.ENTITY_TYPES[script.entities[secondary]!.type]\n if (kind >= 1 && kind <= 8) action = 'ATTACH_ENTITY'\n }\n\n if (secondary === -1 && NEEDS_SECOND.has(action)) continue\n\n let start = milliseconds(source.time)\n // START_IK at 0 starts at 1 ms, after the motions (`0x6f25962`).\n if (action === 'START_IK' && start === 0) start = 1\n\n const duration = source.duration === undefined ? 0 : milliseconds(source.duration)\n const base: Base = {\n action,\n type: data.EVENT_TYPES[action],\n source,\n start,\n duration,\n flags: flagWord(source),\n primary,\n secondary,\n end: -1,\n timing: timingOf(source, start, duration),\n }\n\n if (action === 'ATTACH_ENTITY') out.push(attach(base, source))\n else if (source.action === 'START_PATH_ANIMATION') out.push(pathAnimation(base, source))\n else if (source.action === 'START_SPATIAL_PROP_ANIM') out.push(spatialAnimation(base, source))\n else if (action === 'CONNECT_HARDPOINTS') out.push(connection(base))\n else if (action === 'SET_CAMERA') out.push(setCamera(base))\n else if (source.action === 'START_CAMERA_PROP_ANIM') out.push(cameraAnimation(base, source))\n else if (source.action === 'START_LIGHT_PROP_ANIM') out.push(lightAnimation(base, source))\n else if (source.action === 'START_FOG_PROP_ANIM') out.push(fogAnimation(base, source))\n else if (action === 'START_PSYS') out.push(startPsys(base))\n else if (source.action === 'START_PSYS_PROP_ANIM') out.push(psysAnimation(base, source))\n else if (source.action === 'START_SOUND')\n out.push(startSound(base, source, spatial.has(primary)))\n else if (source.action === 'START_AUDIO_PROP_ANIM') out.push(audioAnimation(base, source))\n else if (source.action === 'START_MOTION')\n out.push(startMotion(base, source, script.entities[primary]!.type === 'COMPOUND'))\n else if (source.action === 'START_IK') out.push(startIk(base, source))\n else if (source.action === 'START_FLR_HEIGHT_ANIM') out.push(floorAnimation(base, source))\n else out.push(inert(base))\n }\n\n return out\n}\n","/**\n * A `MOTION_PATH`'s spline: `CV_CROrientationSplinePath` and `CV_CRSplinePath` in\n * `src/Thorn/SplinePath.cpp`. Uniform Catmull-Rom between keys, sampled 16 times a segment, and\n * travelled at constant speed along those chords: the parameter is normalised chord length.\n */\nimport { Quat, Vector3, Vector4 } from '@treewyrm/freelancer/math'\nimport type { PathProps } from '@treewyrm/freelancer/thn/scene'\nimport { columnsOf, nlerp, quaternionOf, type Quaternion } from './frame.js'\n\nconst f = Math.fround\nconst SAMPLES = 16\nconst IDENTITY: Quaternion = { x: 0, y: 0, z: 0, w: 1 }\n\nexport interface Path {\n /** In the path's own axes. Held at the first and last key outside `(0, 1)`. */\n position(u: number): Vector3 | undefined\n /** The unit Catmull-Rom tangent toward increasing `u`, lerped between samples; not held at the ends. */\n tangent(u: number): Vector3 | undefined\n /** Squad between keys' orientations; a position-only path has none. */\n orientation(u: number): Quaternion | undefined\n}\n\n/** `CatmullRomTangent3D` (`FUN_06f213d0`): the derivative over its length, a zero one dividing by 0. */\nconst crTangent = (p0: Vector3, p1: Vector3, p2: Vector3, p3: Vector3, s: number): Vector3 => {\n const d = Vector3.catmullRomTangent(p0, p1, p2, p3, s)\n\n return Vector3.multiplyScalar(d, 1 / Math.sqrt(Vector3.dot(d, d)))\n}\n\nconst scale = Vector4.multiplyScalar\n\n/** `QuatLogRetail`: `(0, v·θ/sin θ)`, or `(0, v)` at `|w| ≥ 1` or a sine under 0.001. No hemisphere fold. */\nconst log = (q: Quaternion): Quaternion => {\n if (!(Math.abs(q.w) < 1)) return { ...q, w: 0 }\n\n const angle = Math.acos(q.w)\n const sin = Math.sin(angle)\n if (sin < f(0.001)) return { ...q, w: 0 }\n return { ...scale(q, angle / sin), w: 0 }\n}\n\n/** `QuatExpRetail`: `(cos |v|, v·sin |v|/|v|)`, `v` kept under a sine of 0.001. */\nconst exp = (q: Quaternion): Quaternion => {\n const n = Math.hypot(q.x, q.y, q.z)\n const sin = Math.sin(n)\n const v = sin < f(0.001) ? q : scale(q, sin / n)\n\n return { x: v.x, y: v.y, z: v.z, w: Math.cos(n) }\n}\n\n/** `QuatSquadControl`, `Quat.squadControl` with retail's log and exp: `q · exp(−¼(log(q⁻¹·prev) + log(q⁻¹·next)))`. */\nconst control = (prev: Quaternion, q: Quaternion, next: Quaternion): Quaternion => {\n const inverse = Quat.invert(q)\n const a = log(Quat.multiply(inverse, prev))\n const b = log(Quat.multiply(inverse, next))\n\n return Quat.multiply(q, exp(scale(Vector4.add(a, b), -0.25)))\n}\n\n/** `EvalCrOrientation` (`FUN_06f21770`) and `QuatSquad` (`FUN_06f248c0`): `Quat.squad`, every blend an nlerp. */\nconst squad = (q0: Quaternion, q1: Quaternion, q2: Quaternion, q3: Quaternion, s: number) =>\n nlerp(nlerp(q1, q2, s), nlerp(control(q0, q1, q2), control(q1, q2, q3), s), f((1 - s) * s * 2))\n\n/**\n * A path from its `pathprops`, or nothing where thorn's load fails: a `NULL` path, or fewer than two\n * keys (`0x6f358fb`), and every animation on it does nothing.\n */\nexport const createPath = (props: PathProps | undefined): Path | undefined => {\n if (!props || props.path_type === 'NULL') return undefined\n\n const keys: { position: Vector3; orientation?: Quaternion }[] =\n props.path_type === 'CV_CROrientationSplinePath'\n ? props.points.map(({ position, orientation }) => ({ position, orientation }))\n : props.points.map((position) => ({ position }))\n const n = keys.length\n if (n < 2) return undefined\n\n const closed = props.flag === 'CLOSED'\n // The ends (`ApplyPersistGhosts`): open, the end keys doubled; closed, wrapped round.\n const points = [\n closed ? keys[n - 1]!.position : keys[0]!.position,\n ...keys.map((key) => key.position),\n closed ? keys[0]!.position : keys[n - 1]!.position,\n ...(closed ? [keys[1]!.position] : []),\n ]\n // Quaternions are wrapped by neither; a closed path's last ghost is never written in retail.\n const quats = [\n keys[0]!.orientation ?? IDENTITY,\n ...keys.map((key) => key.orientation ?? IDENTITY),\n keys[n - 1]!.orientation ?? IDENTITY,\n IDENTITY,\n ]\n const last = closed ? n + 1 : n\n const neighbours = <T>(list: readonly T[], k: number) =>\n [list[k - 1]!, list[k]!, list[k + 1]!, list[k + 2]!] as const\n\n // `RebuildSampleTables`: per segment, the running chord length at 17 samples; then all over the total.\n const tables: number[][] = []\n // `times[k]` is the normalised length where segment `k` starts (`times[last]` is 1);\n // slots 0 and `last + 1` stay 0.\n const times: number[] = [0, 0]\n let total = 0\n\n for (let k = 1; k < last; k++) {\n const [p0, p1, p2, p3] = neighbours(points, k)\n const table = [total]\n // `FUN_06f21000`.\n let previous = Vector3.catmullRom(p0, p1, p2, p3, 0)\n let length = 0\n\n for (let j = 1; j <= SAMPLES; j++) {\n const current = Vector3.catmullRom(p0, p1, p2, p3, f(j * 0.0625))\n\n length = f(length + Vector3.distance(previous, current))\n table.push(f(total + length))\n previous = current\n }\n\n tables[k] = table\n total = f(total + length)\n times[k + 1] = total\n }\n\n for (const table of tables) if (table) table.forEach((value, j) => (table[j] = f(value / total)))\n times[1] = 0\n times[last + 1] = 0\n for (let k = 0; k < times.length; k++) times[k] = f(times[k]! / total)\n\n /** `FindPathSegment`: past every key time at or before `u`, from the first live one. */\n const segmentOf = (u: number): number | undefined => {\n let k = 1\n\n while (k < last && !(times[k]! > u)) k++\n\n const segment = k - 1\n\n return segment >= 1 && segment < last ? segment : undefined\n }\n\n /** `FindSample`: the sample interval holding `u`, an exact hit the one before, and the fraction. */\n const sampleOf = (k: number, u: number): [number, number] => {\n const table = tables[k]!\n let at = 8\n\n // Binary search of the 17-entry table from its middle, stepping 4, 2, 1.\n for (let step = 8; step > 1;) {\n step = Math.trunc(step / 2)\n at += u < table[at]! ? -step : step\n }\n\n if (!(u > table[at]!)) at--\n return [at, f((u - table[at]!) / (table[at + 1]! - table[at]!))]\n }\n\n const along = (\n u: number,\n curve: (p0: Vector3, p1: Vector3, p2: Vector3, p3: Vector3, s: number) => Vector3,\n ): Vector3 | undefined => {\n const k = segmentOf(u)\n if (k === undefined) return undefined\n\n const [j, fraction] = sampleOf(k, u)\n const [p0, p1, p2, p3] = neighbours(points, k)\n const a = curve(p0, p1, p2, p3, f(j * 0.0625))\n const b = curve(p0, p1, p2, p3, f((j + 1) * 0.0625))\n\n return Vector3.lerp(a, b, fraction)\n }\n\n const oriented = props.path_type === 'CV_CROrientationSplinePath'\n\n return {\n position: (u) => (u <= 0 ? points[1] : u >= 1 ? points[last] : along(u, Vector3.catmullRom)),\n tangent: (u) => along(u, crTangent),\n orientation: (u) => {\n if (!oriented) {\n // `BuildSlot5MatrixRetail` (`LAB_06f34420`): `Z = −t`, `X = Ŷ × Z`, `Y = Z × X`. Its asm isn't\n // decoded in the decomp; this is the extension's emulated reading. No retail path uses it.\n const t = along(u, crTangent)\n if (!t) return undefined\n\n const z = Vector3.multiplyScalar(Vector3.normalize(t), -1)\n const x = Vector3.normalize(Vector3.cross({ x: 0, y: 1, z: 0 }, z))\n\n return quaternionOf(columnsOf(x, Vector3.cross(z, x), z))\n }\n\n if (u <= 0) return quats[1]\n if (u >= 1) return quats[last]\n\n const k = segmentOf(u)\n if (k === undefined) return undefined\n\n const [j, fraction] = sampleOf(k, u)\n const [q0, q1, q2, q3] = neighbours(quats, k)\n const a = squad(q0, q1, q2, q3, f(j * 0.0625))\n const b = squad(q0, q1, q2, q3, f((j + 1) * 0.0625))\n\n return nlerp(a, b, fraction)\n },\n }\n}\n","/**\n * A script's entities as the game spawns them into a room (`FGfScript::Spawn`, `FUN_0044ed90`): which\n * get a host at all, and what a compound's or character's room object carries. The host resolves\n * templates by `category` and loads the models; this maps the rest onto `RoomObject`.\n */\nimport type { Vector3 } from '@treewyrm/freelancer/math'\nimport { data, type Entity } from '@treewyrm/freelancer/thn/scene'\nimport type { RoomObject } from '#/scene/room.js'\nimport type { Frame } from './frame.js'\nimport type { Playback } from './playback.js'\n\n/** One `rtcslider.ini` line: `set = name, t` on at `t` and above, `set_less` below `t`. */\nexport interface RtcSetting {\n name: string\n threshold: number\n less?: boolean\n}\n\n/**\n * `RtcSlider::is_enabled` (`common!0x627a920`): the first line for a name, ignoring case (`CreateID`), at\n * the player's cutscene-detail `slider`. A name with no line is on.\n */\nexport const rtcEnabled = (\n settings: readonly RtcSetting[],\n slider: number,\n name: string,\n): boolean => {\n const setting = settings.find((each) => each.name.toLowerCase() === name.toLowerCase())\n if (!setting) return true\n return setting.less ? slider < setting.threshold : setting.threshold <= slider\n}\n\n/** A `userprops` value, its key matched ignoring case as thorn's map does (`_memicmp`). */\nexport const userProp = (entity: Entity, key: string): string | undefined => {\n const props = entity.userprops ?? {}\n const found = Object.keys(props).find((each) => each.toLowerCase() === key.toLowerCase())\n\n return found === undefined ? undefined : props[found]\n}\n\nexport interface SpawnOptions {\n /** `rtcslider.ini`'s lines. Every name is on when absent. */\n rtc?: readonly RtcSetting[]\n /** The cutscene-detail slider, 0 to 1. */\n slider?: number\n}\n\n/**\n * Whether the game makes a host for an entity: not when its `priority` is a setting the slider has\n * off, nor a `PSYS` with no `priority` while `script_particles` is off (`0x44efd3`).\n */\nexport const spawns = (entity: Entity, { rtc = [], slider = 1 }: SpawnOptions = {}): boolean => {\n const priority = userProp(entity, 'priority')\n if (priority !== undefined && !rtcEnabled(rtc, slider, priority)) return false\n\n if (entity.type === 'PSYS' && priority === undefined)\n return rtcEnabled(rtc, slider, 'script_particles')\n\n return true\n}\n\n/** `ThornGetRenderType` (`common!0x627c0b0`): `usr_flg` bit 0 starsphere, bit 1 backdrop, which wins. */\nexport const renderTypeOf = (entity: Entity): 'starsphere' | 'backdrop' | undefined => {\n const flags = entity.usr_flg ?? 0\n\n return flags & 2 ? 'backdrop' : flags & 1 ? 'starsphere' : undefined\n}\n\n/** A compound or character the room draws, all but its model. */\nexport interface RoomEntity {\n entity: Entity\n /** `template_name`, `NULL` as nothing, the entity's own name when absent (`0x6f28a60`). */\n template: string\n /** `userprops.category`, which the host resolves `template` by, case included. */\n category: string | undefined\n /** Where the host puts it: `C · T`. */\n world: Frame\n /** Its starsphere or backdrop render type, which the host gives the model as `sky`. */\n sky: 'starsphere' | 'backdrop' | undefined\n /** `running_lights`: whether its `always_on` lights draw. */\n runningLights: boolean\n /** The `RoomObject` fields this decides. */\n object: Omit<RoomObject, 'model'>\n}\n\nconst has = (entity: Entity, flag: keyof typeof data.RENDER_FLAGS) =>\n 'flags' in entity && (entity.flags?.includes(flag) ?? false)\n\n/**\n * Every `COMPOUND` and `DEFORMABLE` the game spawns, in script order, with what `SetFlags` and the\n * spawn give its room object (`0x44de85`, `FThornCompound::SetFlags`): `LIT_AMBIENT` is `visible`,\n * `LIT_DYNAMIC` is `lit`, fog unless `nofog`, `srt_grp` its signed layer, `lt_grp` its light group,\n * and its scene's ambient. A `REFERENCE` is another script's, so isn't here.\n */\nexport const roomEntities = (playback: Playback, options: SpawnOptions = {}): RoomEntity[] => {\n const ambient: Vector3 | undefined = playback.ambient\n\n return playback.script.entities.flatMap((entity) => {\n if (entity.type !== 'COMPOUND' && entity.type !== 'DEFORMABLE') return []\n if (has(entity, 'REFERENCE') || !spawns(entity, options)) return []\n\n const world = playback.world(entity.entity_name)\n if (!world) return []\n\n const template =\n entity.template_name === 'NULL' ? '' : (entity.template_name ?? entity.entity_name)\n const category = userProp(entity, 'category')\n // The player's ship (`0x44dda1`): its `IsVisible` is `xor al,al` (`0x44fd00`), so black ambient.\n const playerShip = category === 'Spaceship' && template === 'PlayerShip'\n\n return [\n {\n entity,\n template,\n category,\n world,\n // A character's render type is always 0.\n sky: entity.type === 'COMPOUND' ? renderTypeOf(entity) : undefined,\n runningLights: userProp(entity, 'running_lights') !== undefined,\n object: {\n position: { x: world.w.x, y: world.w.y, z: world.w.z },\n layer: entity.srt_grp ?? 0,\n lightGroup: entity.lt_grp ?? 0,\n visible: has(entity, 'LIT_AMBIENT') && !playerShip,\n lit: has(entity, 'LIT_DYNAMIC'),\n fog: userProp(entity, 'nofog') === undefined,\n ...(ambient && { ambient }),\n },\n },\n ]\n })\n}\n","/**\n * One script's engine: `FThornScene` (`src/Thorn/ThornScene.cpp`). It keeps its own clock in whole\n * milliseconds and only moves forward by a delta (`Tick`, engine `+0x68`): every event start and end\n * inside a step is visited at its own instant, in order, so one jump equals any run of smaller ones.\n *\n * Thorn renders nothing. Each entity is a proxy for what the host owns, and here its frame in scene\n * space is plain data, which {@link Playback.world} places as the game's host classes do.\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport { data, type Entity, type EventTypeName, type Script } from '@treewyrm/freelancer/thn/scene'\nimport {\n eventsOf,\n milliseconds,\n RUN,\n type AimRecord,\n type CameraProps,\n type MotionRecord,\n type Stage,\n type ThornEvent,\n} from './events.js'\nimport {\n axisIndex,\n inverse,\n placement,\n positionOf,\n withPosition,\n withRotation,\n type Frame,\n} from './frame.js'\nimport { createPath, type Path } from './path.js'\nimport { lightOf, NO_FOG, roomFogOf, roomLightOf, type FogState, type LightState } from './light.js'\nimport type { Fog } from '#/scene/nebula.js'\nimport type { EffectInstance } from '#/alchemy/effect.js'\nimport { DEFAULT_AUDIO, readAudio, type AudioState, type SoundRecord } from './sound.js'\nimport type { RoomLight } from '#/scene/room.js'\nimport { spawns, type SpawnOptions } from './room.js'\n\n/** What the host answers for its entities, by name. Every frame is in the entity's own space. */\nexport interface ThornHost {\n /**\n * A hardpoint's frame relative to the entity's root at its current pose, or nothing found. The game\n * matches names ignoring case, the last duplicate winning (`HardpointSummary::find_name`).\n */\n hardpoint?(entity: string, name: string): Frame | undefined\n /** A `DEFORMABLE`'s bone by name, ignoring case, relative to its root; nothing when missing. */\n bone?(entity: string, name: string): Frame | undefined\n /**\n * `ICompoundControl +0x18` and `IPSysControl +0x14`: a compound's, deformable's or effect's time\n * moves on, before the events at each update instant and once more by 0 at the end of a tick.\n */\n advance?(entity: string, milliseconds: number): void\n}\n\nexport interface PlaybackOptions {\n loop?: boolean\n /**\n * The host's scene frame `C`: a room character's setpoint over its actor (`ThornScriptGetCsys`),\n * the identity everywhere else. Thorn's own scene frame is always the identity in the game.\n */\n frame?: Frame\n host?: ThornHost\n /** The room's fog, which every script shares: pass one holder to them all. A fresh room's when absent. */\n fog?: { state: FogState }\n /** The `fog` detail option, which `GfFogSetOn` ANDs into `on`. */\n fogEnabled?: boolean\n /**\n * A new instance of a `PSYS`'s `[VisEffect]`, named by its template ignoring case, or nothing\n * where there's none. `PlayerShipEngines` is the player ship's own engines: the host's.\n */\n createEffect?: (entity: string, template: string) => EffectInstance | undefined\n /** The detail gate, which decides which entities get a host at all. */\n spawn?: SpawnOptions\n /**\n * What runs a compound's or character's scripts and aims: false where the game's host answers\n * other than `S_OK`. The records are kept either way, and every start succeeds without one.\n */\n characters?: CharacterHost\n /**\n * What a `REFERENCE` binds to: a live entity of that type and name in another script, by name, or\n * where the room's set script puts it, in this script's space; nothing leaves it at its record.\n */\n resolve?: (\n type: Entity['type'],\n name: string,\n ) => { playback: Playback; name: string } | { frame: Frame } | undefined\n}\n\n/**\n * A `CONNECT_HARDPOINTS` while it runs. The game finds the part owning each hardpoint, names\n * ignoring case, and links the child's under the parent's so the two hardpoints meet:\n * `childPart = parentPart · H_parent · inverse(H_child)` ({@link connectedFrame}, `0x44fdd0`).\n */\nexport interface Connection {\n readonly event: ThornEvent\n readonly child: string\n readonly hardpoint: string\n readonly parent: string\n readonly parentHardpoint: string\n}\n\n/**\n * Where a connected child part goes (`engbase.dll` `0x6626690`): the parent part's world frame, its\n * hardpoint's frame on it, and the child's hardpoint on the child part. Fixed hardpoints only; a\n * revolute or prismatic child takes a branch not decoded.\n */\nexport const connectedFrame = (\n parentPart: Frame,\n parentHardpoint: Frame,\n childHardpoint: Frame,\n): Frame => Matrix4.multiply(Matrix4.multiply(parentPart, parentHardpoint), inverse(childHardpoint))\n\n/**\n * Thorn's first play from 0 to `milliseconds`, as the game starts a script: started, ticked by 0,\n * then one exact jump. A rewind isn't this: thorn's restores no transform.\n */\nexport const replay = (\n script: Script,\n milliseconds: number,\n options?: PlaybackOptions,\n): Playback => {\n const playback = new Playback(script, options)\n\n playback.start(0)\n playback.tick(0)\n playback.tick(milliseconds)\n return playback\n}\n\n/** A camera or monitor in the world, as its host holds it. */\nexport interface CameraView {\n world: Frame\n /** Half the horizontal angle, degrees. */\n fovh: number\n near: number\n far: number\n /** `hvaspect`, which the game never reads: its aspect getter and setter are stubs (`0x454190`). */\n aspect: number\n}\n\n/** `cameraprops`' defaults (`0x6f29270`). */\nconst DEFAULT_CAMERA: CameraProps = [60, 0.1, 100000, 1.3333]\n\nconst cameraPropsOf = (entity: Entity): CameraProps => {\n if (entity.type !== 'CAMERA') return DEFAULT_CAMERA\n\n const { fovh, nearplane, farplane, hvaspect } = entity.cameraprops ?? {}\n const [a, b, c, d] = DEFAULT_CAMERA\n\n return [fovh ?? a, nearplane ?? b, farplane ?? c, hvaspect ?? d].map(\n Math.fround,\n ) as unknown as CameraProps\n}\n\n/** `FThornScene`'s playback states, as far as a tick tells them apart. */\nexport type PlaybackState = 'loaded' | 'playing' | 'looping' | 'stopped' | 'done'\n\n/** Host classes that place their engine object at `C · T`: the rest take thorn's frame as it is. */\nconst PLACED_BY_C: ReadonlySet<Entity['type']> = new Set([\n 'COMPOUND',\n 'DEFORMABLE',\n 'CAMERA',\n 'MONITOR',\n 'MARKER',\n])\n\n/** The game's compound and character hosts, as far as thorn drives them. */\nexport interface CharacterHost {\n startMotion?(entity: string, motion: MotionRecord): boolean\n stopMotion?(entity: string, motion: MotionRecord): void\n startAim?(entity: string, aim: AimRecord): boolean\n updateAim?(entity: string, aim: AimRecord): void\n stopAim?(entity: string, aim: AimRecord): void\n /** `IDeformable +0x60`: the root's floor, which each motion applies at its next evaluation. */\n setFloor?(entity: string, height: number): void\n /**\n * A character's root (`0x452ab0`–`0x452c20`): a position write keeps `x` and `z` and discards `y`,\n * and `root` is where it stands now, root motion and all, which thorn reads back. In thorn's space.\n */\n setPosition?(entity: string, position: Vector3): void\n setOrientation?(entity: string, orientation: Frame): void\n root?(entity: string): Frame | undefined\n /** `ICompoundControl +0x18`, with the clock. */\n advance?(entity: string, milliseconds: number): void\n}\n\n/** What a `REFERENCE` can name (`FUN_00456790`'s callers). */\nconst REFERABLE: ReadonlySet<Entity['type']> = new Set(['MARKER', 'CAMERA', 'LIGHT', 'SOUND'])\n\n/** Advanced by the clock (`RegisterFrameEntity`). */\nconst ADVANCED: ReadonlySet<Entity['type']> = new Set(['COMPOUND', 'DEFORMABLE', 'PSYS'])\n\n/**\n * VC6's `std::sort`, as thorn sorts its master list and each active group: median-of-three\n * partitions above 16 (`SortMasterPartitions`, `PartitionActiveEventTypes`), then insertion. Equal\n * keys keep their order only in a range of 16 or fewer.\n */\nexport const retailSort = <T>(items: T[], key: (item: T) => number): T[] => {\n const k = (index: number) => key(items[index]!)\n\n const partition = (begin: number, end: number) => {\n while (end - begin > 16) {\n const a = k(begin)\n const b = k(begin + Math.trunc((end - begin) / 2))\n const c = k(end - 1)\n const pivot = a < b ? (b < c ? b : c <= a ? a : c) : a < c ? a : b < c ? c : b\n let left = begin\n let right = end\n\n // Hoare scan: swap pairs on the wrong side of the pivot until the cursors cross.\n for (;;) {\n while (k(left) < pivot) left++\n\n do right--\n while (pivot < k(right))\n\n if (right <= left) break\n\n const swap = items[left]!\n\n items[left] = items[right]!\n items[right] = swap\n left++\n }\n\n // Recurse into the smaller half and loop on the larger.\n if (end - left <= left - begin) {\n partition(left, end)\n end = left\n } else {\n partition(begin, left)\n begin = left\n }\n }\n }\n if (items.length > 16) partition(0, items.length)\n\n for (let index = 1; index < items.length; index++) {\n const item = items[index]!\n let at = index\n\n while (at > 0 && key(item) < k(at - 1)) {\n items[at] = items[at - 1]!\n at--\n }\n\n items[at] = item\n }\n\n return items\n}\n\ninterface EntityState {\n readonly entity: Entity\n frame: Frame\n readonly path: Path | undefined\n /** A camera's or monitor's slots. */\n props: CameraProps\n /** A camera's monitors, or a monitor's camera (`MonitorLinks`). */\n links: number[]\n /** A `REFERENCE`'s live entity in another script, which its reads and writes go to. */\n target: { playback: Playback; id: number } | undefined\n /** A `SOUND`'s `audioprops`: its record's, or the defaults for a `REFERENCE` (`0x6f4255f`). */\n audio: AudioState | undefined\n /** A `LIGHT`'s block, and the type it was made with, which the host keeps. */\n light: LightState | undefined\n readonly madeAs: number\n}\n\nexport class Playback implements Stage {\n readonly script: Script\n /** Milliseconds: `trunc(duration · 1000)`. */\n readonly duration: number\n readonly loop: boolean\n readonly host: ThornHost\n /** `C`. */\n readonly sceneFrame: Frame\n readonly sceneUp: number\n readonly sceneFront: number\n /** Actions in the script that are scheduled and timed, but whose effect a later step brings. */\n readonly ignored: readonly EventTypeName[]\n\n #state: PlaybackState = 'loaded'\n #clock = 0\n readonly #entities: EntityState[]\n readonly #ids = new Map<string, number>()\n readonly #master: ThornEvent[]\n #pending: ThornEvent[] = []\n #active: ThornEvent[] = []\n /** Every end instant still to come, ascending, each once. */\n #stops: number[] = []\n #connections: Connection[] = []\n readonly #fog: { state: FogState }\n readonly #sounds = new Map<number, SoundRecord>()\n readonly #motions: { entity: number; motion: MotionRecord }[] = []\n readonly #aims = new Map<number, AimRecord>()\n readonly #floors = new Map<number, number>()\n readonly #characters: CharacterHost\n #now = 0\n readonly #effects = new Map<number, { instance?: EffectInstance; sparam: number }>()\n readonly #createEffect: PlaybackOptions['createEffect']\n readonly #spawn: SpawnOptions\n readonly #fogEnabled: boolean\n\n constructor(script: Script, options: PlaybackOptions = {}) {\n const { loop = false, frame = Matrix4.identity, host = {} } = options\n\n this.script = script\n this.duration = milliseconds(script.duration)\n this.loop = loop\n this.host = host\n this.sceneFrame = frame\n this.#fog = options.fog ?? { state: NO_FOG }\n this.#fogEnabled = options.fogEnabled ?? true\n this.#createEffect = options.createEffect\n this.#spawn = options.spawn ?? {}\n this.#characters = options.characters ?? {}\n // The second pass sets a character's floor from its record, after its pose (`0x44f1d2`).\n script.entities.forEach((entity, id) => {\n if (entity.type === 'DEFORMABLE')\n this.#floors.set(id, Math.fround(entity.compoundprops?.floor_height ?? 0))\n })\n\n // The first SCENE's axes; only LOOK_AT reads them, and 6 means Y and Z.\n const scene = script.entities.find((entity) => entity.type === 'SCENE')\n\n this.sceneUp = scene?.type === 'SCENE' ? axisIndex(scene.up, 6) : 6\n this.sceneFront = scene?.type === 'SCENE' ? axisIndex(scene.front, 6) : 6\n // Thorn pushes no initial state: every host starts from the record.\n this.#entities = script.entities.map((entity) => ({\n entity,\n target: undefined,\n frame:\n 'spatialprops' in entity\n ? placement(entity.spatialprops?.pos, entity.spatialprops?.orient)\n : Matrix4.identity,\n path: entity.type === 'MOTION_PATH' ? createPath(entity.pathprops) : undefined,\n props: cameraPropsOf(entity),\n light: entity.type === 'LIGHT' ? lightOf(entity.lightprops) : undefined,\n audio:\n entity.type !== 'SOUND'\n ? undefined\n : entity.flags?.includes('REFERENCE')\n ? DEFAULT_AUDIO\n : readAudio(entity.audioprops ?? {}, DEFAULT_AUDIO).audio,\n madeAs: entity.type === 'LIGHT' ? lightOf(entity.lightprops).type : 0,\n links: [],\n }))\n script.entities.forEach(({ entity_name }, index) => {\n if (!this.#ids.has(entity_name)) this.#ids.set(entity_name, index)\n })\n // At spawn (`FGfScript::Spawn`): a `REFERENCE` marker, camera, light or sound binds to a live one.\n this.#entities.forEach((state) => {\n const { entity } = state\n if (!entity.flags?.includes('REFERENCE') || !REFERABLE.has(entity.type)) return\n\n const found = options.resolve?.(entity.type, entity.entity_name)\n if (!found) return\n\n if ('frame' in found) state.frame = found.frame\n else {\n const id = found.playback.#ids.get(found.name)\n if (id !== undefined) state.target = { playback: found.playback, id }\n }\n })\n // Loaded in script order, each after the equal starts before it, then sorted again (`FinalizeLoad`).\n this.#master = retailSort(\n eventsOf(script).sort((a, b) => (a.start >>> 0) - (b.start >>> 0)),\n (event) => event.start >>> 0,\n )\n this.ignored = [\n ...new Set(this.#master.map((event) => event.action).filter((action) => !RUN.has(action))),\n ]\n }\n\n get state(): PlaybackState {\n return this.#state\n }\n\n /** `ClockMs_`: the last instant every active event was updated at. */\n get clock(): number {\n return this.#clock\n }\n\n /** The events running now, in the order they update. */\n get active(): readonly ThornEvent[] {\n return this.#active\n }\n\n /** Every `CONNECT_HARDPOINTS` running, in the order made: the host links each child part. */\n get connections(): readonly Connection[] {\n return this.#connections\n }\n\n /** An entity's frame in thorn's scene space, by name. */\n frameOf(name: string): Frame | undefined {\n const id = this.#ids.get(name)\n\n return id === undefined ? undefined : this.#entities[id]!.frame\n }\n\n /**\n * Where the host puts an entity: `C · T` for a compound, deformable, camera, monitor or marker,\n * thorn's `T` as it is for a light, sound or effect (`Thorn_Psys` never applies `C`). A player\n * ship's `HpMount` offset after it is the host's.\n */\n world(name: string): Frame | undefined {\n const id = this.#ids.get(name)\n if (id === undefined) return undefined\n\n const { entity } = this.#entities[id]!\n const frame = this.#engineFrame(id)\n\n return PLACED_BY_C.has(entity.type) ? Matrix4.multiply(this.sceneFrame, frame) : frame\n }\n\n /** `StartPlayback` (`LAB_06f39460`), then a tick by `milliseconds`. The game starts at 0. */\n start(milliseconds = 0): void {\n if (this.#state === 'loaded' || this.#state === 'stopped' || this.#state === 'done') {\n this.#clock = 0\n this.#pending = this.#master.slice()\n } else if (this.#state === 'looping') this.#pending = this.#master.slice()\n\n this.#state = this.loop ? 'looping' : 'playing'\n this.tick(milliseconds)\n }\n\n /** `StopPlayback`: every running event finished, the clock back at 0. */\n stop(): void {\n this.#clock = 0\n this.#pending = this.#master.slice()\n this.#stopAll()\n this.#state = 'stopped'\n }\n\n /**\n * `Tick` (engine `+0x68`): forward by whole milliseconds. A negative step rewinds to 0 and replays,\n * **restoring no transform**. Past the end a loop restarts at exactly 0; a script that doesn't\n * loop finishes every running event and is done.\n */\n tick(milliseconds: number): void {\n // Clock times are int32, so `>>> 0` below compares them unsigned.\n let next = (this.#clock + Math.trunc(milliseconds)) | 0\n\n if (milliseconds < 0) {\n if (next < 0) next = 0\n this.#stopAll()\n this.#clock = 0\n this.#pending = this.#master.slice()\n }\n\n const from = this.#clock\n\n this.#now = next\n if (next >>> 0 < from >>> 0) return\n if (this.#state !== 'playing' && this.#state !== 'looping') return\n\n this.#dispatch(from, next)\n this.#drain(next)\n this.#update(next)\n // Every control once more by 0, so an effect gets the frame this tick's events wrote.\n if (this.#clock !== 0) this.#advance(this.#clock)\n\n if (next >>> 0 > this.duration >>> 0) {\n if (this.loop) {\n this.stop()\n this.start(0)\n return\n }\n\n this.#stopAll()\n this.#state = 'done'\n }\n }\n\n // Stage: what events read and write.\n\n frame(entity: number): Frame {\n const state = this.#entities[entity]\n if (state?.target) return state.target.playback.frame(state.target.id)\n\n if (state?.entity.type === 'DEFORMABLE') {\n const root = this.#characters.root?.(state.entity.entity_name)\n if (root) return root\n }\n\n return state?.frame ?? Matrix4.identity\n }\n\n /**\n * Where the engine has an entity: its thorn frame, unless a running `CONNECT_HARDPOINTS` links it\n * under a parent, the last made winning. Then its hardpoint sits on the parent's, `parent ·\n * H_parent · inverse(H_child)`, both relative to their roots; thorn's own frame is left as it was\n * (THORN.md, `CONNECT_HARDPOINTS`). The child's hardpoint is taken on its root part, which moves the\n * whole object; on another part retail moves that part alone, which is not reproduced.\n */\n #engineFrame(entity: number, depth = 0): Frame {\n const state = this.#entities[entity]\n const name = state?.entity.entity_name\n const link =\n depth < 8 && !state?.target\n ? this.#connections.filter((connection) => connection.child === name).at(-1)\n : undefined\n const parent = link && this.#ids.get(link.parent)\n const parentHardpoint = link && this.host.hardpoint?.(link.parent, link.parentHardpoint)\n const childHardpoint = link && this.host.hardpoint?.(link.child, link.hardpoint)\n\n if (parent === undefined || !parentHardpoint || !childHardpoint) return this.frame(entity)\n\n return connectedFrame(this.#engineFrame(parent, depth + 1), parentHardpoint, childHardpoint)\n }\n\n /** A camera's write goes on to every monitor linked to it (`0x6f41490`, `0x6f414d0`). */\n setPosition(entity: number, position: Vector3): void {\n const state = this.#entities[entity]\n if (!state) return\n // A reference's host forwards to its target's (`ThornReferenceSetPosition`), thorn's frame raw.\n if (state.target) return state.target.playback.setPosition(state.target.id, position)\n state.frame = withPosition(state.frame, position)\n\n if (state.entity.type === 'DEFORMABLE')\n this.#characters.setPosition?.(state.entity.entity_name, position)\n\n if (state.entity.type === 'CAMERA')\n for (const link of state.links) this.setPosition(link, position)\n }\n\n setOrientation(entity: number, orientation: Frame): void {\n const state = this.#entities[entity]\n if (!state) return\n if (state.target) return state.target.playback.setOrientation(state.target.id, orientation)\n state.frame = withRotation(state.frame, orientation)\n\n if (state.entity.type === 'DEFORMABLE')\n this.#characters.setOrientation?.(state.entity.entity_name, orientation)\n\n if (state.entity.type === 'CAMERA')\n for (const link of state.links) this.setOrientation(link, orientation)\n }\n\n cameraProps(entity: number): CameraProps {\n return this.#entities[entity]?.props ?? DEFAULT_CAMERA\n }\n\n setCameraProps(entity: number, props: CameraProps): void {\n const state = this.#entities[entity]\n if (!state) return\n state.props = props\n\n if (state.entity.type !== 'MONITOR')\n for (const link of state.links) this.setCameraProps(link, props)\n }\n\n light(entity: number): LightState | undefined {\n return this.#entities[entity]?.light\n }\n\n setLight(entity: number, light: LightState): void {\n const state = this.#entities[entity]\n if (state?.light) state.light = light\n }\n\n fog(): FogState {\n const { state } = this.#fog\n\n return { ...state, on: state.on && this.#fogEnabled }\n }\n\n setFog(fog: FogState, mask: number): void {\n const state = { ...this.#fog.state }\n if (mask & 1) state.on = fog.on && this.#fogEnabled\n if (mask & 0xa) ((state.table = fog.table), (state.mode = fog.mode))\n\n if (mask & 0x70)\n ((state.start = fog.start), (state.end = fog.end), (state.density = fog.density))\n\n if (mask & 4) state.color = fog.color\n this.#fog.state = state\n }\n\n psysStart(entity: number): boolean {\n const state = this.#entities[entity]\n if (!state || !spawns(state.entity, this.#spawn)) return false\n\n const { entity_name, template_name } = state.entity\n const template = template_name === 'NULL' ? '' : (template_name ?? entity_name)\n const effect = this.#effects.get(entity) ?? { sparam: 0 }\n\n // An instance already running is abandoned, not stopped; none starts at the cached sparam.\n effect.instance = this.#createEffect?.(entity_name, template)\n this.#effects.set(entity, effect)\n return true\n }\n\n psysStop(entity: number): void {\n const effect = this.#effects.get(entity)\n if (effect) effect.instance = undefined\n }\n\n sparam(entity: number): number {\n return this.#effects.get(entity)?.sparam ?? 0\n }\n\n setSparam(entity: number, value: number): void {\n const effect = this.#effects.get(entity) ?? { sparam: 0 }\n\n effect.sparam = value\n this.#effects.set(entity, effect)\n if (effect.instance) effect.instance.context.sparam = value\n }\n\n /** Every running effect, in the order made: what the room draws of this script's `PSYS`es. */\n get effects(): { entity: string; instance: EffectInstance }[] {\n return [...this.#effects.entries()]\n .sort(([a], [b]) => a - b)\n .flatMap(([id, { instance }]) =>\n instance ? [{ entity: this.#entities[id]!.entity.entity_name, instance }] : [],\n )\n }\n\n motionStart(entity: number, motion: MotionRecord): boolean {\n const state = this.#entities[entity]\n if (!state || !spawns(state.entity, this.#spawn)) return false\n if (this.#characters.startMotion?.(state.entity.entity_name, motion) === false) return false\n this.#motions.push({ entity, motion })\n return true\n }\n\n motionStop(entity: number, motion: MotionRecord): void {\n const at = this.#motions.findIndex((each) => each.motion === motion)\n if (at >= 0) this.#motions.splice(at, 1)\n this.#characters.stopMotion?.(this.#entities[entity]!.entity.entity_name, motion)\n }\n\n aimStart(entity: number, aim: AimRecord): boolean {\n const state = this.#entities[entity]\n if (!state || !spawns(state.entity, this.#spawn)) return false\n if (this.#characters.startAim?.(state.entity.entity_name, aim) === false) return false\n this.#aims.set(entity, aim)\n return true\n }\n\n aimUpdate(entity: number, aim: AimRecord): void {\n this.#aims.set(entity, aim)\n this.#characters.updateAim?.(this.#entities[entity]!.entity.entity_name, aim)\n }\n\n aimStop(entity: number, aim: AimRecord): void {\n if (this.#aims.get(entity) === aim) this.#aims.delete(entity)\n this.#characters.stopAim?.(this.#entities[entity]!.entity.entity_name, aim)\n }\n\n floor(entity: number): number | undefined {\n return this.#floors.get(entity)\n }\n\n setFloor(entity: number, height: number): void {\n if (!this.#floors.has(entity)) return\n this.#floors.set(entity, height)\n this.#characters.setFloor?.(this.#entities[entity]!.entity.entity_name, height)\n }\n\n /** The scripts running on compounds and characters, in the order started. */\n get motions(): { entity: string; motion: MotionRecord }[] {\n return this.#motions.map(({ entity, motion }) => ({\n entity: this.#entities[entity]!.entity.entity_name,\n motion,\n }))\n }\n\n /** Every character's running aim, its target as of the last update. */\n get aims(): { entity: string; aim: AimRecord }[] {\n return [...this.#aims.entries()].map(([id, aim]) => ({\n entity: this.#entities[id]!.entity.entity_name,\n aim,\n }))\n }\n\n /** A character's floor height: its record's, then what `START_FLR_HEIGHT_ANIM` sets. */\n floorOf(name: string): number | undefined {\n const id = this.#ids.get(name)\n\n return id === undefined ? undefined : this.#floors.get(id)\n }\n\n get now(): number {\n return this.#now\n }\n\n soundStart(\n entity: number,\n { offset, loop, spatial }: { offset: number; loop: boolean; spatial: boolean },\n ): boolean {\n const state = this.#entities[entity]\n if (!state || !spawns(state.entity, this.#spawn)) return false\n\n const { entity_name, template_name } = state.entity\n\n this.#sounds.set(entity, {\n entity: entity_name,\n template: template_name === 'NULL' ? '' : (template_name ?? ''),\n offset,\n loop,\n spatial: spatial || (state.entity.flags?.includes('SPATIAL') ?? false),\n started: this.#now,\n })\n return true\n }\n\n soundStop(entity: number): void {\n this.#sounds.delete(entity)\n }\n\n audio(entity: number): AudioState | undefined {\n return this.#entities[entity]?.audio\n }\n\n setAudio(entity: number, audio: AudioState): void {\n const state = this.#entities[entity]\n if (state?.audio) state.audio = audio\n }\n\n /**\n * Every sound playing, in the order made, with its entity's `audioprops` now and, for a 3D one,\n * where thorn has it. The host plays, cuts and adjusts them to match.\n */\n get sounds(): (SoundRecord & { audio: AudioState; position: Vector3 })[] {\n return [...this.#sounds.entries()]\n .sort(([a], [b]) => a - b)\n .map(([id, record]) => {\n const { audio, frame } = this.#entities[id]!\n\n return { ...record, audio: audio ?? DEFAULT_AUDIO, position: positionOf(frame) }\n })\n }\n\n kind(entity: number): string | undefined {\n return this.#entities[entity]?.entity.type\n }\n\n /** The room's fog as the frame takes it, or none. */\n get roomFog(): Fog | undefined {\n return roomFogOf(this.#fog.state)\n }\n\n /** The `SCENE`'s `ambient`, 0 to 255, as the record writes it: nothing animates it in the game. */\n get ambient(): Vector3 | undefined {\n const scene = this.script.entities.find((entity) => entity.type === 'SCENE')\n\n return scene?.type === 'SCENE' ? scene.ambient : undefined\n }\n\n /**\n * Every `LIGHT` that's on and spawned, in the order made, as the room's (`0x44b450`). A\n * `REFERENCE` is another script's light.\n */\n roomLights(options: SpawnOptions = {}): RoomLight[] {\n return this.#entities.flatMap(({ entity, light, madeAs, frame }) =>\n light?.on && !entity.flags?.includes('REFERENCE') && spawns(entity, options)\n ? [roomLightOf(light, madeAs, frame, entity.lt_grp ?? 0)]\n : [],\n )\n }\n\n camera(entity: number): boolean {\n return this.#entities[entity]?.entity.type === 'CAMERA'\n }\n\n cut(monitor: number, camera: number): void {\n const to = this.#entities[monitor]\n const from = this.#entities[camera]\n if (!to || !from) return\n\n if (!from.links.includes(monitor)) {\n from.links.push(monitor)\n\n // `UnbindMonitorChildren` (`0x6f41660`) skips the node after each it unlinks.\n const kept: number[] = []\n\n to.links.forEach((link, index) => {\n if (index % 2 === 1) return kept.push(link)\n\n const other = this.#entities[link]\n if (other) other.links = other.links.filter((each) => each !== monitor)\n })\n to.links = kept\n if (!to.links.includes(camera)) to.links.push(camera)\n }\n\n this.setCameraProps(monitor, from.props)\n this.setPosition(monitor, positionOf(from.frame))\n this.setOrientation(monitor, from.frame)\n }\n\n /** A camera's or monitor's view in the world: its placement through `C`, and its slots. */\n view(name: string): CameraView | undefined {\n const id = this.#ids.get(name)\n const state = id === undefined ? undefined : this.#entities[id]\n\n if (!state || (state.entity.type !== 'CAMERA' && state.entity.type !== 'MONITOR'))\n return undefined\n\n const [fovh, near, far, aspect] = state.props\n\n return { world: Matrix4.multiply(this.sceneFrame, state.frame), fovh, near, far, aspect }\n }\n\n /** The camera a monitor follows, by name. */\n linkedCamera(monitor: string): string | undefined {\n const id = this.#ids.get(monitor)\n const state = id === undefined ? undefined : this.#entities[id]\n const link = state?.entity.type === 'MONITOR' ? state.links[0] : undefined\n\n return link === undefined ? undefined : this.#entities[link]?.entity.entity_name\n }\n\n compound(entity: number): boolean {\n const type = this.#entities[entity]?.entity.type\n\n return type === 'COMPOUND' || type === 'DEFORMABLE'\n }\n\n /**\n * `ICompoundControl +0x24`. A compound answers a hardpoint, or `PART` `root` or `\"\"` with its root,\n * in **world** space (`0x451b90`: `C` is not undone, and thorn takes it as scene space); any other\n * part writes nothing. A deformable answers a hardpoint or a bone in scene space (`0x452730`).\n */\n part(entity: number, type: number, name: string): Frame | undefined {\n const state = this.#entities[entity]\n if (!state) return undefined\n\n const { entity_name, type: kind } = state.entity\n const own = (local: Frame | undefined) =>\n local && Matrix4.multiply(this.#engineFrame(entity), local)\n\n if (kind === 'COMPOUND') {\n const scene =\n type === data.TARGET_TYPES.HARDPOINT\n ? own(this.host.hardpoint?.(entity_name, name))\n : name === '' || name.toLowerCase() === 'root'\n ? state.frame\n : undefined\n\n return scene && Matrix4.multiply(this.sceneFrame, scene)\n }\n\n if (kind === 'DEFORMABLE')\n return own(\n type === data.TARGET_TYPES.HARDPOINT\n ? this.host.hardpoint?.(entity_name, name)\n : this.host.bone?.(entity_name, name),\n )\n\n return undefined\n }\n\n path(entity: number): Path | undefined {\n return this.#entities[entity]?.path\n }\n\n connect(event: ThornEvent): void {\n if (event.source.action !== 'CONNECT_HARDPOINTS') return\n\n const [child = '', parent = ''] = event.source.targets\n\n this.#connections.push({\n event,\n child,\n hardpoint: event.source.hardpoint ?? '',\n parent,\n parentHardpoint: event.source.parent_hardpoint ?? '',\n })\n }\n\n disconnect(event: ThornEvent): void {\n this.#connections = this.#connections.filter((connection) => connection.event !== event)\n }\n\n // The schedule.\n\n /** `FrameUpdateEntities`: each compound, deformable and effect moves on to `now`. */\n #advance(now: number): void {\n const elapsed = (now - this.#clock) | 0\n\n this.#entities.forEach(({ entity, frame }, id) => {\n if (!ADVANCED.has(entity.type)) return\n this.host.advance?.(entity.entity_name, elapsed)\n if (entity.type !== 'PSYS') this.#characters.advance?.(entity.entity_name, elapsed)\n\n // `Thorn_Psys` (`0x453ff0`): seconds, the override placement from thorn's frame, `C` never\n // applied, then both passes. Only while an instance exists.\n const instance = this.#effects.get(id)?.instance\n if (instance)\n instance.advance(Math.fround(elapsed * 0.001), { placement: frame, placing: 'override' })\n })\n this.#clock = now\n }\n\n /** `UpdateActive`: the controls move on, then every running event updates; the finished drop out. */\n #update(now: number): void {\n this.#advance(now)\n\n for (let index = 0; index < this.#active.length;) {\n const event = this.#active[index]!\n\n event.update(this, now)\n\n if (now >>> 0 < event.end >>> 0 || event.end < 0) index++\n else {\n this.#active.splice(index, 1)\n event.finish?.(this)\n }\n }\n }\n\n /** `StopAll`: every running event finished, with no last update. */\n #stopAll(): void {\n this.#stops = []\n for (const event of this.#active.splice(0)) event.finish?.(this)\n }\n\n /** `DrainTimedStops` in a tick: an update at every end instant before `now`. */\n #drain(now: number): void {\n while (this.#stops.length && this.#stops[0]! < now) this.#update(this.#stops.shift()!)\n }\n\n /**\n * `DispatchWindow`: every pending event starting in `[from, to]`, in order. Before each, the ends\n * before its instant are updated at, then everything at its instant once, so it starts against the\n * world as it stands then.\n */\n #dispatch(from: number, to: number): void {\n const first = this.#pending.findIndex((event) => event.start >>> 0 >= from >>> 0)\n if (first < 0 || this.#pending[first]!.start >>> 0 > to >>> 0) return\n\n let last = first\n\n while (last < this.#pending.length && this.#pending[last]!.start >>> 0 <= to >>> 0) last++\n\n const updated = new Set<number>()\n\n for (const event of this.#pending.slice(first, last)) {\n while (this.#stops.length && this.#stops[0]! >>> 0 < event.start >>> 0) {\n const stop = this.#stops.shift()!\n\n this.#update(stop)\n updated.add(stop)\n }\n\n if (!updated.has(event.start)) {\n this.#update(event.start)\n updated.add(event.start)\n }\n\n if (event.begin(this)) {\n this.#active.push(event)\n\n if (event.end >= 0) {\n this.#stops = this.#stops.filter((stop) => stop !== event.end)\n this.#stops.push(event.end)\n this.#stops.sort((a, b) => a - b)\n }\n }\n\n this.#regroup()\n }\n\n this.#pending.splice(first, last - first)\n }\n\n /**\n * `RebuildActiveGroups`: grouped by the entity acted on, groups by entity id, each sorted by action\n * number (`EmitActiveGroup`), and an event's second target's group emitted just before it, so a\n * parent updates before its children however long the chain.\n */\n #regroup(): void {\n const groups = new Map<number, { events: ThornEvent[]; visited: boolean }>()\n\n for (const event of this.#active) {\n const group = groups.get(event.primary)\n\n if (group) group.events.push(event)\n else groups.set(event.primary, { events: [event], visited: false })\n }\n\n const out: ThornEvent[] = []\n\n const emit = (group: { events: ThornEvent[]; visited: boolean }) => {\n if (group.visited) return\n group.visited = true\n retailSort(group.events, (event) => event.type)\n\n for (const event of group.events) {\n const parent = event.secondary === -1 ? undefined : groups.get(event.secondary)\n if (parent) emit(parent)\n out.push(event)\n }\n }\n for (const id of [...groups.keys()].sort((a, b) => a - b)) emit(groups.get(id)!)\n this.#active = out\n }\n}\n\n/** A live, spawned entity by type and name: what another script's `REFERENCE` can bind to. */\nexport const findEntity = (playback: Playback, type: Entity['type'], name: string): boolean =>\n playback.script.entities.some(\n (entity) =>\n entity.type === type && entity.entity_name === name && !entity.flags?.includes('REFERENCE'),\n )\n","/**\n * How the game drives a script's engine: `FGfScript` (`src/freelancer/Client/gf_script_object.cpp`)\n * and the frame's milliseconds (`TickGameflow`, `0x558ac7`).\n */\nimport type { Playback } from './playback.js'\n\nconst f = Math.fround\n\n/** What a frame hands every sequence: whole milliseconds, and the rest carried to the next. */\nexport interface FrameMilliseconds {\n milliseconds: number\n carry: number\n}\n\n/**\n * `0x558ac7`–`0x558afa`: the carry plus the frame's seconds, floored to milliseconds, the remainder\n * kept as a float. At the x87's 24-bit precision, which D3D8 leaves it at.\n */\nexport const frameMilliseconds = (carry: number, seconds: number): FrameMilliseconds => {\n const sum = f(carry + seconds)\n const milliseconds = Math.floor(f(sum * 1000))\n\n return { milliseconds, carry: f(sum - f(milliseconds * 0.001)) }\n}\n\n/**\n * One script as a sequence plays it (`FGfScript::Start`, `Update`): started and ticked by 0 before\n * the first frame, then by each frame's milliseconds. The frame that reaches the end, or skips to\n * it, ticks 100 more, so a script that doesn't loop finishes its events then.\n */\nexport class ScriptRun {\n readonly playback: Playback\n #finished = false\n #skipping = false\n\n constructor(playback: Playback) {\n this.playback = playback\n // `Slot22Start(0)` ticks by 0 itself, and `Slot26Tick(0)` again.\n playback.start(0)\n playback.tick(0)\n }\n\n get finished(): boolean {\n return this.#finished\n }\n\n /** `FGfScript::Pause`, as the skip key sets it: the next update jumps to the end, exactly. */\n skip(): void {\n this.#skipping = true\n }\n\n /**\n * `FGfScript::Update`, true once finished. `catchup` is `0x44f500`'s: how far a finished rebuff\n * voice line lets the scene jump, 0 everywhere else.\n */\n update(milliseconds: number, catchup = 0): boolean {\n const { playback } = this\n\n if (!this.#finished)\n if (!this.#skipping) {\n playback.tick(catchup + milliseconds)\n if (!playback.loop && playback.clock >>> 0 >= playback.duration >>> 0) this.#finished = true\n } else {\n playback.tick(playback.duration - playback.clock)\n this.#finished = true\n this.#skipping = false\n }\n\n if (this.#finished) playback.tick(100)\n return this.#finished\n }\n}\n","/**\n * What the screen shows of the scripts' cameras: the game's view table (`FGfCameraPool`,\n * `src/freelancer/Client/gf_script.cpp`), and the cinematic letterbox (`space_letterbox.cpp`).\n */\nimport type { Matrix3 } from '@treewyrm/freelancer/math'\nimport type { Camera, Viewport } from '#/scene/camera.js'\nimport type { Frame } from './frame.js'\nimport type { CameraView } from './playback.js'\n\nconst f = Math.fround\n\n/** A frame's rotation as the rows a THN `orient` reads into, which a renderer `Camera` takes. */\nexport const rowsOf = ({ x, y, z }: Frame): Matrix3 => ({\n x: { x: x.x, y: y.x, z: z.x },\n y: { x: x.y, y: y.y, z: z.y },\n z: { x: x.z, y: y.z, z: z.z },\n})\n\n/** A script camera's view as the renderer's `Camera`. */\nexport const cameraOf = ({ world, fovh, near, far }: CameraView): Camera => ({\n position: { x: world.w.x, y: world.w.y, z: world.w.z },\n orientation: rowsOf(world),\n fovh,\n near,\n far,\n})\n\n/**\n * `FGfCameraPool`: 256 slots. A `MONITOR` registers selectable with its script's priority (1 for\n * landing, launch and transitions, else 0); a `CAMERA` registers but never shows. A new slot takes\n * the view only over a strictly lower priority (`Allocate`, `0x450580`); freeing the shown one\n * re-elects the highest, ties to the lowest slot (`Free`, `0x450680`). None shown: the room's camera.\n */\nexport class ViewTable {\n readonly #slots: ({ priority: number; selectable: boolean } | undefined)[] = []\n #active = -1\n\n /** The slot shown, or nothing. */\n get active(): number | undefined {\n return this.#active === -1 ? undefined : this.#active\n }\n\n /** A slot for a camera or monitor, or nothing when all 256 are taken. */\n register(priority: number, selectable: boolean): number | undefined {\n let slot = 0\n\n while (slot < 256 && this.#slots[slot]) slot++\n if (slot === 256) return undefined\n this.#slots[slot] = { priority, selectable }\n\n const shown = this.#active === -1 ? -0x100 : this.#slots[this.#active]!.priority\n if (selectable && priority > shown) this.#active = slot\n return slot\n }\n\n release(slot: number): void {\n this.#slots[slot] = undefined\n if (slot !== this.#active) return\n\n let best = -1\n let priority = -0x100\n\n this.#slots.forEach((each, index) => {\n if (each?.selectable && each.priority > priority) {\n priority = each.priority\n best = index\n }\n })\n this.#active = best\n }\n}\n\n/**\n * The letterbox: an amount from 0, no bars, to 1, a 1.85:1 picture, moving toward its target at\n * `speed` a second. A script that takes the camera aims it at 1 and lets go at 0, both at 3.\n */\nexport class Letterbox {\n amount = 0\n target = 0\n speed = 3\n animating = false\n\n /** `SetLetterboxTarget` (`FUN_0041a0f0`): under an opaque fade it jumps there. */\n aim(target: number, speed = 3, faded = false): void {\n if (faded) this.amount = target\n this.target = target\n this.speed = speed\n this.animating = true\n }\n\n /** The head of `UpdateRoomLetterbox` (`FUN_0041a140`): true while it was moving. */\n step(seconds: number): boolean {\n if (!this.animating) return false\n\n if (this.amount < this.target) {\n const sum = this.speed * seconds + this.amount\n\n this.amount = f(sum)\n if (!(sum >= this.target)) return true\n this.amount = this.target\n } else if (this.amount > this.target) {\n const difference = this.amount - this.speed * seconds\n\n this.amount = f(difference)\n if (!(difference <= this.target)) return true\n this.amount = this.target\n }\n\n this.animating = false\n return true\n }\n\n /** `GetLetterboxBarHeight`: each bar, in pixels, rounded half up. */\n bar({ width, height }: Viewport): number {\n const surface = width / height\n // The aspect eases from the surface's to 1.85 with `amount`; each bar is half the height it leaves.\n const aspect = (f(1.85) - surface) * this.amount + surface\n\n return Math.floor((height - width / aspect) * 0.5 + 0.5)\n }\n\n /**\n * The picture between the bars, and its aspect, which the room camera's projection takes in\n * place of the surface's, the horizontal angle held.\n */\n view(surface: Viewport): { top: number; viewport: Viewport; aspect: number } {\n const bar = this.bar(surface)\n const viewport = { width: surface.width, height: surface.height - 2 * bar }\n\n return { top: bar, viewport, aspect: viewport.width / viewport.height }\n }\n}\n","/**\n * How the game plays scripts in a room: sequences of entries, one live at a time\n * (`FGfScriptSequence`, `gf_script_object.cpp`), the manager that updates them all with the same\n * milliseconds and finds the entities they export (`FGfScriptManager`), and a room's set script read\n * as data, never played (`RoomData::read_set_script`, `common_roomdata.cpp`).\n */\nimport { Matrix4, type Vector3 } from '@treewyrm/freelancer/math'\nimport type { Entity, Script } from '@treewyrm/freelancer/thn/scene'\nimport type { RoomLight } from '#/scene/room.js'\nimport { inverse, placement, positionOf, type Frame } from './frame.js'\nimport { lightOf, roomLightOf } from './light.js'\nimport { findEntity, Playback, type PlaybackOptions } from './playback.js'\nimport { renderTypeOf, userProp } from './room.js'\nimport { ScriptRun } from './script.js'\n\n/**\n * An entry's kind: 0 plain, 1 an offer's decision, 2 accept, 3 decline or reject, 4 an info box,\n * 5 a room's traffic, which repeats, 6 a group offer's other branch.\n */\nexport type EntryKind = 0 | 1 | 2 | 3 | 4 | 5 | 6\n\nexport interface SequenceEntry {\n script: Script\n kind?: EntryKind\n /** The host's scene frame `C`: a room character's setpoint over its actor, else the identity. */\n frame?: Frame\n}\n\n/** A sequence's flags (`0x454920`). The host acts on most of them: letterbox, ducking, fades. */\nexport interface SequenceFlags {\n loop?: boolean\n /** Letterboxed, the UI hidden. */\n cinematic?: boolean\n skippable?: boolean\n /** Its live entities are what other scripts' `REFERENCE`s find (`+0x2f`). */\n exported?: boolean\n /** Its monitors' camera priority: 1 for landing, launch and transitions, else 0. */\n priority?: number\n}\n\n/** `FindNextOfKinds` (`FUN_00455f50`): the offset of the next entry of one of `kinds`, or past the end. */\nconst nextOfKinds = (\n kinds: readonly EntryKind[],\n entries: readonly SequenceEntry[],\n current: number,\n) => {\n for (let offset = 1; current + offset < entries.length; offset++)\n if (kinds.includes(entries[current + offset]!.kind ?? 0)) return offset\n\n return entries.length - current\n}\n\nexport class Sequence {\n readonly entries: readonly SequenceEntry[]\n readonly flags: SequenceFlags\n /** The entry playing, or −1 once done. */\n current = -1\n run: ScriptRun | undefined\n /** The decision's answer, which the host sets from the offer dialog. */\n answered: boolean | undefined\n infoClosed = false\n #skip = false\n readonly #options: (frame: Frame | undefined) => PlaybackOptions\n\n constructor(\n entries: readonly SequenceEntry[],\n flags: SequenceFlags = {},\n options: (frame: Frame | undefined) => PlaybackOptions = (frame) => (frame ? { frame } : {}),\n ) {\n this.entries = entries\n this.flags = flags\n this.#options = options\n }\n\n /** `Play` (`FUN_00454f80`): the first entry starts, ticked by 0. */\n play(): void {\n this.#start(0)\n }\n\n get done(): boolean {\n return this.current === -1\n }\n\n get playback(): Playback | undefined {\n return this.run?.playback\n }\n\n /** The skip key (`0x456840`): a cinematic, skippable sequence skips to its decision, which plays. */\n skip(): void {\n if (this.flags.cinematic && this.flags.skippable && !this.done) this.#skip = true\n }\n\n #start(index: number): void {\n this.current = index\n\n const entry = this.entries[index]!\n const options = this.#options(entry.frame)\n\n this.run = new ScriptRun(\n new Playback(entry.script, { ...options, loop: this.flags.loop ?? false }),\n )\n if (entry.kind === 1) this.answered = undefined\n }\n\n /** The offer answered: the looping decision jumps to its end, so the branch starts next update. */\n answer(accepted: boolean): void {\n this.answered = accepted\n this.run?.skip()\n }\n\n /** `NextEntryIndex` (`FUN_00455fc0`), single player. */\n next(): number {\n const kind = this.entries[this.current]?.kind ?? 0\n const step = (kinds: EntryKind[]) => nextOfKinds(kinds, this.entries, this.current)\n\n switch (kind) {\n case 0:\n return this.current + 1\n case 1:\n return (\n this.current +\n (this.answered === undefined ? 0 : step(this.answered ? [0, 2, 4] : [0, 3]))\n )\n case 2:\n return this.current + step([0, 2, 4])\n case 3:\n return this.current + step([0, 3])\n case 4:\n return this.current + (this.infoClosed ? step([0, 2, 4]) : 0)\n case 6:\n return this.current + step([0, 6])\n default:\n // A traffic script repeats.\n return this.current\n }\n }\n\n /**\n * `FGfScriptSequence::Update` (`FUN_00456150`): skipping runs each entry out to its end, stopping\n * at a decision or info box; then the live script by `milliseconds`, and the next entry when it\n * finishes. True once done.\n */\n update(milliseconds: number, catchup = 0): boolean {\n if (this.done) return true\n\n while (this.#skip) {\n this.run!.skip()\n this.run!.update(0)\n\n const next = this.next()\n\n if (next >= this.entries.length) {\n this.current = -1\n this.run = undefined\n return true\n }\n\n const kind = this.entries[next]!.kind ?? 0\n if (kind === 1 || kind === 4) this.#skip = false\n this.#start(next)\n }\n\n if (!this.run!.update(milliseconds, catchup)) return false\n\n const next = this.next()\n\n if (next < this.entries.length) {\n // A decision not yet answered starts again: it loops until the offer is answered.\n this.#start(next)\n return false\n }\n\n this.current = -1\n this.run = undefined\n return true\n }\n}\n\n/** `FGfScriptManager`: every sequence, updated in the order made with the same milliseconds. */\nexport class SequenceManager {\n readonly sequences: Sequence[] = []\n\n add(sequence: Sequence): Sequence {\n this.sequences.push(sequence)\n sequence.play()\n return sequence\n }\n\n /** `FUN_00456650`: each updated; the finished dropped. */\n update(milliseconds: number): void {\n for (const sequence of this.sequences.slice())\n if (sequence.update(milliseconds)) this.sequences.splice(this.sequences.indexOf(sequence), 1)\n }\n\n skip(): void {\n for (const sequence of this.sequences) sequence.skip()\n }\n\n /**\n * `FindCreatedEntity` (`FUN_00456790`): the first live entity of that type and name in the current\n * script of an exporting sequence, by the order the sequences were made.\n */\n find(type: Entity['type'], name: string): { playback: Playback; name: string } | undefined {\n for (const sequence of this.sequences) {\n const playback = sequence.playback\n\n if (sequence.flags.exported && playback && findEntity(playback, type, name))\n return { playback, name }\n }\n\n return undefined\n }\n}\n\n/** A prop the set script lists: the room's own models. */\nexport interface SetProp {\n entity: Entity\n template: string\n category: string\n frame: Frame\n /** `LIT_AMBIENT`, `LIT_DYNAMIC`, fog unless `nofog`. */\n visible: boolean\n lit: boolean\n fog: boolean\n /** A `Room` category or a `hardpoint` userprop: the room's main prop. */\n main: boolean\n lightGroup: number\n layer: number\n sky: 'starsphere' | 'backdrop' | undefined\n loadout: string\n priority: string | undefined\n runningLights: boolean\n}\n\nexport interface SetCamera {\n name: string\n frame: Frame\n fovh: number\n near: number\n far: number\n}\n\n/** A shadow or glare source: directional along its turned direction, else at its position. */\nexport interface SetSource {\n direction?: Vector3\n position?: Vector3\n color: Vector3\n}\n\nexport interface SetScript {\n props: SetProp[]\n /** Every camera, which is a setpoint of the same name too. */\n cameras: SetCamera[]\n setpoints: { name: string; frame: Frame }[]\n /** `LtShadowSource` and `LtGlareSource`. */\n shadow?: SetSource\n glare?: SetSource\n /** Any other light that's on: none in retail. */\n lights: RoomLight[]\n /** The `SCENE`'s, 0 to 255. */\n ambient?: Vector3\n}\n\n/**\n * `RoomData::read_set_script` (`common!0x6274ea0`): the set script as data. Its compounds with a `category`\n * become props, its cameras cameras and setpoints, its markers setpoints, two lights by name the\n * shadow and glare sources, and the rest of the lights only when on. No event runs.\n */\nexport const readSetScript = (script: Script): SetScript => {\n const out: SetScript = { props: [], cameras: [], setpoints: [], lights: [] }\n\n for (const entity of script.entities) {\n const frame =\n 'spatialprops' in entity\n ? placement(entity.spatialprops?.pos, entity.spatialprops?.orient)\n : Matrix4.identity\n const flags = 'flags' in entity ? (entity.flags ?? []) : []\n const name = entity.entity_name\n\n if (entity.type === 'COMPOUND') {\n const category = userProp(entity, 'category')\n // Reported and skipped without one.\n if (category === undefined) continue\n out.props.push({\n entity,\n template: entity.template_name === 'NULL' ? '' : (entity.template_name ?? name),\n category,\n frame,\n visible: flags.includes('LIT_AMBIENT'),\n lit: flags.includes('LIT_DYNAMIC'),\n fog: userProp(entity, 'nofog') === undefined,\n main: category === 'Room' || userProp(entity, 'hardpoint') !== undefined,\n lightGroup: entity.lt_grp ?? 0,\n layer: entity.srt_grp ?? 0,\n sky: renderTypeOf(entity),\n loadout: userProp(entity, 'loadout') ?? '',\n priority: userProp(entity, 'priority'),\n runningLights: userProp(entity, 'running_lights') !== undefined,\n })\n } else if (entity.type === 'CAMERA') {\n const { fovh = 60, nearplane = 0.1, farplane = 100000 } = entity.cameraprops ?? {}\n\n out.cameras.push({ name, frame, fovh, near: nearplane, far: farplane })\n out.setpoints.push({ name, frame })\n } else if (entity.type === 'MARKER') out.setpoints.push({ name, frame })\n else if (entity.type === 'LIGHT') {\n const light = lightOf(entity.lightprops)\n const source = (): SetSource =>\n light.type === 3\n ? { direction: Matrix4.transformDirection(light.direction, frame), color: light.diffuse }\n : { position: positionOf(frame), color: light.diffuse }\n\n if (name.toLowerCase() === 'ltshadowsource') out.shadow = source()\n else if (name.toLowerCase() === 'ltglaresource') out.glare = source()\n else if (light.on) out.lights.push(roomLightOf(light, light.type, frame, entity.lt_grp ?? 0))\n } else if (entity.type === 'SCENE' && entity.ambient) out.ambient = entity.ambient\n }\n\n return out\n}\n\n/**\n * `ThornScriptGetCsys` (`0x627be8f`): the first `DEFORMABLE` whose `actor` isn't `player`, upright at\n * its floor height: `[R | (x, floor_height, z)]`. The identity with none.\n */\nexport const scriptAnchor = (script: Script): Frame => {\n const actor = script.entities.find(\n (entity) =>\n entity.type === 'DEFORMABLE' && userProp(entity, 'actor')?.toLowerCase() !== 'player',\n )\n if (actor?.type !== 'DEFORMABLE') return Matrix4.identity\n\n const { pos, orient } = actor.spatialprops ?? {}\n const frame = placement(pos, orient)\n\n return {\n ...frame,\n w: { x: frame.w.x, y: actor.compoundprops?.floor_height ?? 0, z: frame.w.z, w: 1 },\n }\n}\n\n/**\n * A room character's fidget (`0x445340`): `C = setpoint · G⁻¹`, so its actor lands there. A\n * conversation runs at `C = I`.\n */\nexport const anchoredFrame = (setpoint: Frame, script: Script): Frame =>\n Matrix4.multiply(setpoint, inverse(scriptAnchor(script)))\n\n/**\n * A room's `scene = ambient, path` line (`0x44a540`): a looping, exporting sequence at `C = I`,\n * priority 0, not cinematic.\n */\nexport const ambientSequence = (\n script: Script,\n options?: (frame: Frame | undefined) => PlaybackOptions,\n): Sequence => new Sequence([{ script }], { loop: true, exported: true, priority: 0 }, options)\n","/**\n * Thorn's characters on the library's motion mixer: what the game's `Thorn_Deformable`\n * (`gf_thorn_deformable.cpp`) does with `START_MOTION`, `START_IK` and the floor, as a\n * {@link CharacterHost}. The host makes each character's `Mixer` and finds animations by name.\n */\nimport type { AnimationScript } from '@treewyrm/freelancer/animation'\nimport { Matrix4, Quat } from '@treewyrm/freelancer/math'\nimport type { Mixer } from '#/deformable/mixer.js'\nimport type { AimRecord, MotionRecord } from './events.js'\nimport { quaternionOf, type Frame } from './frame.js'\nimport type { CharacterHost } from './playback.js'\n\nexport interface MixerCharacters {\n /** A character's mixer, by entity name, or nothing for one the host doesn't run. */\n mixer(entity: string): Mixer | undefined\n /**\n * An animation by name, from the one global table every `bodyparts.ini [Animations]` file fills,\n * ignoring case (`0x435100`). A missing one logs and still succeeds: the event does nothing.\n */\n animation(name: string): AnimationScript | undefined\n}\n\n/**\n * A {@link CharacterHost} on mixers. A motion locks its `locked_bone` from its start to its Finish;\n * an aim is the single-joint `point_at` solve, its scene-space rotation handed on as it is, since the\n * solve undoes the parent's world, the character's own turn included (`IkSolveSingleJoint`); keep-beneath\n * from event flag 0x80 (`StartIk`, `0x452460`). Longer chains are left out.\n */\nexport const mixerCharacters = ({\n mixer,\n animation,\n}: MixerCharacters): CharacterHost & {\n /** `ICompoundControl +0x18`: the playback's advance, in milliseconds. */\n advance(entity: string, milliseconds: number): void\n /** Where a character's root stands now, in the character's frame: thorn reads the walk back. */\n root(entity: string): Frame | undefined\n} => {\n const motions = new Map<MotionRecord, number>()\n const aims = new Map<AimRecord['event'], number>()\n /** The motions that locked their bone, which their finish unlocks. */\n const locked = new Set<MotionRecord>()\n\n return {\n startMotion(entity, motion) {\n const character = mixer(entity)\n const script = animation(motion.animation)\n if (!character || !script) return true\n\n const handle = character.start(script, {\n startTime: motion.startTime,\n timeScale: motion.timeScale,\n weight: motion.weight,\n transTime: motion.transTime,\n eventFlags: motion.eventFlags,\n heading: motion.heading,\n })\n if (handle !== undefined) motions.set(motion, handle)\n // Locked after the play whatever it returned, once the animation and part exist (`0x45230a`).\n if (motion.lockedBone) {\n character.lock(motion.lockedBone)\n locked.add(motion)\n }\n return true\n },\n stopMotion(entity, motion) {\n const character = mixer(entity)\n const handle = motions.get(motion)\n\n motions.delete(motion)\n if (!character) return\n if (handle !== undefined) character.stop(handle)\n if (motion.lockedBone && locked.delete(motion)) character.unlock(motion.lockedBone)\n },\n startAim(entity, aim) {\n const character = mixer(entity)\n // An empty chain at 0 or less does nothing; more than one joint isn't built (`0x452460`).\n if (!character || !aim.pointAt || aim.countToRoot !== 1) return true\n\n const handle = character.aim(aim.endEffector, {\n target: quaternionOf(aim.rotation),\n transitionDuration: aim.transitionDuration,\n eventFlags: aim.eventFlags,\n })\n if (handle !== undefined) aims.set(aim.event, handle)\n return true\n },\n updateAim(entity, aim) {\n const handle = aims.get(aim.event)\n if (handle !== undefined) mixer(entity)?.setAimTarget(handle, quaternionOf(aim.rotation))\n },\n stopAim(entity, aim) {\n const handle = aims.get(aim.event)\n\n aims.delete(aim.event)\n if (handle !== undefined) mixer(entity)?.stopAim(handle)\n },\n setFloor(entity, height) {\n mixer(entity)?.setFloor(height)\n },\n setPosition(entity, position) {\n mixer(entity)?.setRootPosition(position)\n },\n setOrientation(entity, orientation) {\n mixer(entity)?.setRootOrientation(quaternionOf(orientation) as Quat)\n },\n advance(entity, milliseconds) {\n mixer(entity)?.advance(Math.fround(milliseconds * 0.001))\n },\n root(entity) {\n const character = mixer(entity)\n if (!character) return undefined\n\n const { position, orientation } = character.root\n\n return Matrix4.fromTRS(position, orientation, 1)\n },\n }\n}\n","/** THN playback: thorn's engine, over the library's `thn/scene` `Script`. It renders nothing. */\nexport { createCurve, progress, type Curve, type Timing } from './curve.js'\nexport {\n eventsOf,\n type AimRecord,\n type CameraProps,\n type MotionRecord,\n flagWord,\n FLAGS,\n milliseconds,\n RUN,\n type Stage,\n type ThornEvent,\n} from './events.js'\nexport {\n axisTurn,\n inverse,\n lookAt,\n nlerp,\n placement,\n quaternionOf,\n rotationOf,\n type Frame,\n type Quaternion,\n} from './frame.js'\nexport { createPath, type Path } from './path.js'\nexport {\n connectedFrame,\n Playback,\n replay,\n retailSort,\n type CameraView,\n type CharacterHost,\n type Connection,\n type PlaybackOptions,\n type PlaybackState,\n type ThornHost,\n} from './playback.js'\nexport { frameMilliseconds, ScriptRun, type FrameMilliseconds } from './script.js'\nexport { cameraOf, Letterbox, rowsOf, ViewTable } from './view.js'\nexport {\n blendFog,\n blendLight,\n DEFAULT_LIGHT,\n LIGHT_BITS,\n lightOf,\n NO_FOG,\n readFog,\n readLight,\n roomFogOf,\n roomLightOf,\n type FogState,\n type LightState,\n} from './light.js'\nexport {\n renderTypeOf,\n roomEntities,\n rtcEnabled,\n spawns,\n userProp,\n type RoomEntity,\n type RtcSetting,\n type SpawnOptions,\n} from './room.js'\nexport {\n blendAudio,\n DEFAULT_AUDIO,\n readAudio,\n soundLevel,\n type AudioState,\n type SoundRecord,\n} from './sound.js'\nexport {\n ambientSequence,\n anchoredFrame,\n readSetScript,\n scriptAnchor,\n Sequence,\n SequenceManager,\n type EntryKind,\n type SequenceEntry,\n type SequenceFlags,\n type SetCamera,\n type SetProp,\n type SetScript,\n type SetSource,\n} from './sequence.js'\nexport { mixerCharacters, type MixerCharacters } from './character.js'\n","/**\n * One animation channel playing on one joint or a character's root: `FTypedChannel` in\n * `engbase.dll`, its clock (`TypedTick`, `FUN_0661b420`), bind (`TypedBind`, `TypedBindType6`) and\n * blends. Pure.\n *\n * Values are a joint's state as `@treewyrm/freelancer/compound` writes it, which `placeCostume`\n * reads. Times and the end test keep float precision, since they decide which frame a step lands\n * on; the values themselves are computed in double (retail rounds them to float as it stores).\n */\nimport { getChannelDuration, sampleChannel, type Channel } from '@treewyrm/freelancer/animation'\nimport type { JointState } from '@treewyrm/freelancer/compound'\nimport { Quat, Vector3, Vector4 } from '@treewyrm/freelancer/math'\n\n/**\n * What a target's parameters hold, by `MixerJointValueCount` (`EngBaseMixer.cpp`): one float for a\n * revolute or prismatic joint, a position for a translational one, a rotation for a sphere, both\n * for a loose joint and for a root.\n */\nexport type Shape = 'value' | 'position' | 'orientation' | 'pose'\n\n/** Where a root is: `Matrix` and `Delta` of a root player, which its samples are carried by. */\nexport interface Placement {\n rotation: Quat\n position: Vector3\n}\n\n/** The `PlayFlags` header a player is bound with: `PlaybackEvalTyped` (`FUN_066126e0`). */\nexport interface Header {\n /** Seconds in. `0` and `-1` (the end) and `-2` (where it stands) are the engine's own markers. */\n start: number\n /** `LoopFlags`: the event flags with bit 0 cleared. */\n flags: number\n /** `Weight`: the speed, negative backwards. */\n rate: number\n /** `Scale`: the motion's `weight`, an amplitude. */\n scale: number\n /** `Field_0x30`: scales a root's and a translational joint's travel. */\n transScale: number\n /** A root's placement at the start; absent, the root's own (`TypedBindType6`). */\n block?: Placement\n}\n\nexport interface Player {\n /** Absent on an aim, whose value its owner solves each tick. */\n channel?: Channel\n shape: Shape\n /**\n * `JointType == 2`: a blend between two angles goes the short way round (`TypedWrapLerpType2`).\n */\n revolute: boolean\n /** An object map, `Kind == 1`: samples are carried by {@link Placement}. */\n root: boolean\n time: number\n rate: number\n flags: number\n scale: number\n transScale: number\n /** `PlayFlags` bit 0: posed and frozen, no tick moves it again (`FUN_0661b070`). */\n held: boolean\n /** `PlayFlags` bit 1: ran off its end or was dropped. */\n ended: boolean\n /** What `CopySampled` hands the mixer. */\n sampled: JointState\n placement: Placement\n}\n\n/** What a tick needs from the character around it. */\nexport interface PlayerContext {\n /** The root as it stands now, for a root player rebinding with no block. */\n root: Placement\n /** `FDeformInstance::OnLoop` (`LAB_065f52b0`): a looping root's height for its next cycle. */\n loopHeight(player: Player): number\n /**\n * An aim's value this tick: its owner's `Apply` (`IkApply`, `LAB_065fb540`). Once stopped, the\n * joint's own value and `stopped`, which ends the player as a channel running out does.\n */\n aim(player: Player): { value: JointState; stopped: boolean }\n}\n\nexport const LOOP = 0x2\nexport const BOUNCE = 0x4\n/** Bound at the block as given, whatever the start time (`TypedBindType6`). */\nexport const AT_BLOCK = 0x40\n\nconst ONE_BITS = 0x3f800000\nconst bits = new DataView(new ArrayBuffer(4))\n\nconst isOne = (value: number): boolean => {\n bits.setFloat32(0, value)\n return bits.getUint32(0) === ONE_BITS\n}\n\nconst PI = Math.fround(Math.PI)\nconst TAU = Math.fround(Math.PI * 2)\n\n/**\n * An amplitude on a rotation, `TypedSlerpType4`: from the identity, unless the scale is exactly 1.\n */\nconst amplified = (orientation: Quat, scale: number): Quat =>\n isOne(scale) ? orientation : Quat.nlerp(Quat.identity, orientation, scale)\n\nexport const duration = ({ channel }: Player): number =>\n channel ? Math.fround(getChannelDuration(channel)) : 0\n\nexport const createPlayer = (\n shape: Shape,\n {\n channel,\n revolute = false,\n root = false,\n }: { channel?: Channel; revolute?: boolean; root?: boolean },\n): Player => ({\n ...(channel ? { channel } : {}),\n shape,\n revolute,\n root,\n time: 0,\n rate: 1,\n flags: 0,\n scale: 1,\n transScale: 1,\n held: false,\n ended: false,\n sampled: rest(shape),\n placement: { rotation: Quat.identity, position: Vector3.zero },\n})\n\n/** A target's parameters before anything writes them. */\nexport const rest = (shape: Shape): JointState => {\n switch (shape) {\n case 'value':\n return { value: 0 }\n case 'position':\n return { position: Vector3.zero }\n case 'orientation':\n return { orientation: Quat.identity }\n case 'pose':\n return { position: Vector3.zero, orientation: Quat.identity }\n }\n}\n\n/** The shape a channel's samples have, or none a target could take. */\nexport const channelShape = (channel: Channel): Shape | undefined => {\n if (channel.type === 'angle') return 'value'\n if (channel.position && channel.orientation) return 'pose'\n if (channel.position) return 'position'\n if (channel.orientation) return 'orientation'\n return undefined\n}\n\n/**\n * `Interpolate` at a time: a pose's position as stored and its rotation amplified\n * (`TypedLerpPosQuatScaled`); every other shape as `Apply` writes it.\n */\nconst interpolate = (player: Player, time: number): JointState => {\n const { channel, shape, scale, transScale } = player\n if (!channel) return player.sampled\n\n const sample = sampleChannel(channel, time, player.revolute)\n\n switch (shape) {\n case 'value':\n return { value: Math.fround(scale * Math.fround(sample.value ?? 0)) }\n case 'position':\n return {\n position: Vector3.multiplyScalar(sample.position ?? Vector3.zero, transScale * scale),\n }\n case 'orientation':\n return { orientation: amplified(sample.orientation ?? Quat.identity, scale) }\n case 'pose':\n return {\n position: sample.position ?? Vector3.zero,\n orientation: amplified(sample.orientation ?? Quat.identity, scale),\n }\n }\n}\n\n/** A root's travel at a time: the stored position times its weight and `trans_scale`. */\nconst travel = (player: Player, time: number): Vector3 =>\n Vector3.multiplyScalar(\n interpolate(player, time).position ?? Vector3.zero,\n player.transScale * player.scale,\n )\n\n/**\n * `Apply` at a time into `sampled`. A root is carried by its placement\n * (`ApplyPositionQuaternionSample`).\n */\nexport const apply = (player: Player, time: number): void => {\n const sample = interpolate(player, time)\n\n if (!player.root) {\n player.sampled = sample\n return\n }\n\n const { rotation, position } = player.placement\n\n // `MulQuat(MatrixToQuat(Matrix), q)`: `x86math!0x6f72740` is the Hamilton `A ⊗ B`, base first.\n player.sampled = {\n position: Vector3.add(Quat.transform(travel(player, time), rotation), position),\n orientation: Quat.multiply(rotation, sample.orientation ?? Quat.identity),\n }\n}\n\n/** `TypedTimePlayable` (`FUN_0661af70`): the engine's markers, or a time within the channel. */\nexport const playable = (player: Player, start: number): boolean => {\n if (start === -1 || start === 0 || start === -2) return true\n return start <= duration(player) && start >= 0\n}\n\n/** `TypedSetTime`: `-1` the end, `-2` where it stands, another negative refused. */\nconst setTime = (player: Player, start: number): void => {\n if (start === -1) player.time = duration(player)\n else if (start === -2) return\n else if (start >= 0) player.time = Math.fround(start)\n}\n\n/**\n * `TypedBind` and, for a root, `TypedBindType6`: at a start of 0 (or with {@link AT_BLOCK}) the\n * root stands at the block; otherwise the block is solved so the root does not jump at the start's\n * sample. With no block the root's own placement stands in, its rotation less the sample's.\n */\nexport const bind = (player: Player, header: Header, root: Placement): void => {\n player.flags = header.flags\n player.rate = Math.fround(header.rate)\n player.scale = Math.fround(header.scale)\n player.transScale = Math.fround(header.transScale)\n setTime(player, header.start)\n player.held = false\n player.ended = false\n if (!player.root) return\n\n const { block } = header\n\n if (header.start === 0 || header.flags & AT_BLOCK) {\n player.placement = block ?? root\n return\n }\n\n // Solves a placement (R, P) with P = origin − R · stored, so the sample at `time` lands on `origin`.\n const position = travel(player, player.time)\n const rotation = block\n ? block.rotation\n : Quat.multiply(\n root.rotation,\n Quat.conjugate(interpolate(player, player.time).orientation ?? Quat.identity),\n )\n const origin = block ? block.position : root.position\n\n player.placement = {\n rotation,\n position: Vector3.subtract(origin, Quat.transform(position, rotation)),\n }\n}\n\n/**\n * `TypedApplyFromArchetype` (`FUN_0661b070`): posed where it stands, or at the end it ran into, and\n * frozen.\n */\nexport const hold = (player: Player): void => {\n player.held = true\n if (!player.channel) return\n\n const time = player.ended ? (player.rate < 0 ? 0 : duration(player)) : player.time\n\n apply(player, time)\n}\n\n/** The first or last keyframe's sample, as `GetFrame` hands it: the end a player runs towards. */\nconst endTime = (player: Player): number => (player.rate < 0 ? 0 : duration(player))\n\n/** The yaw of a rotation's Z axis, as a turn about Y (`PlayInstanceAnim`, `OnLoop`). */\nexport const yaw = (orientation: Quat): Quat => {\n const front = Quat.transform(Vector3.z, orientation)\n\n return turnY(Math.atan2(front.x, front.z))\n}\n\n/** A turn of `angle` radians about Y. */\nexport const turnY = (angle: number): Quat => Quat.axisAngle({ axis: Vector3.y, angle })\n\n/**\n * `TypedTick` (`FUN_0661b420`): advance by `dt · rate` and pose. True when a channel that does not\n * loop has run off its end this tick and nothing had posed it, or when an aim's owner has stopped.\n * A loop rebinds at the start with the overshoot carried, a root at its end placement, upright at\n * its next cycle's height (`OnLoop`); a bounce turns round.\n */\nexport const tick = (player: Player, dt: number, context: PlayerContext): boolean => {\n if (player.held || player.ended) return false\n player.time = Math.fround(dt * player.rate + player.time)\n\n if (!player.channel) {\n const { value, stopped } = context.aim(player)\n\n player.sampled = value\n return stopped\n }\n\n let ran = false\n const length = duration(player)\n const remaining = player.rate < 0 ? player.time : length - player.time\n\n // `remaining` is the time left towards the end it runs to; at or below 0, `wraps` whole lengths\n // were passed and `overshoot` is the part into the next cycle.\n if (remaining <= 0) {\n const wraps = length !== 0 ? Math.abs(Math.trunc(remaining / length)) : 0\n const overshoot = Math.fround(Math.abs(remaining) - wraps * length)\n const header = {\n flags: player.flags,\n rate: player.rate,\n scale: player.scale,\n transScale: player.transScale,\n }\n\n if (player.flags & LOOP) {\n let block: Placement | undefined\n\n if (player.root) {\n apply(player, endTime(player))\n\n const { position = Vector3.zero, orientation = Quat.identity } = player.sampled\n\n block = {\n rotation: yaw(orientation),\n position: { x: position.x, y: context.loopHeight(player), z: position.z },\n }\n }\n\n const start = player.rate < 0 ? length : 0\n\n bind(player, { ...header, start, ...(block ? { block } : {}) }, context.root)\n if (length !== 0) player.time = Math.fround(player.rate < 0 ? length - overshoot : overshoot)\n } else if (player.flags & BOUNCE) {\n // An even number of wraps turns round, an odd one carries on.\n const rate = wraps % 2 === 0 ? -player.rate : player.rate\n const start = rate < 0 ? Math.fround(length - overshoot) : overshoot\n\n bind(player, { ...header, start, rate }, context.root)\n } else {\n player.time = endTime(player)\n player.ended = true\n ran = !player.held\n }\n }\n\n apply(player, player.time)\n return ran\n}\n\n/**\n * `InterpolatePose` of the player a blend reads (`FMixerBlend::Evaluate`). The player's own\n * amplitude applies again over the blend: a weight under 1 dips further while it fades in, as\n * retail does.\n */\nexport const mix = (player: Player, a: JointState, b: JointState, w: number): JointState => {\n switch (player.shape) {\n case 'value': {\n const from = a.value ?? 0\n let to = b.value ?? 0\n\n if (player.revolute) {\n const d = to - from\n\n if (d < -PI) to += TAU\n else if (d > PI) to -= TAU\n }\n\n return { value: Math.fround(player.scale * Math.fround((to - from) * w + from)) }\n }\n case 'position':\n return {\n position: Vector3.multiplyScalar(\n Vector3.lerp(a.position ?? Vector3.zero, b.position ?? Vector3.zero, w),\n player.transScale * player.scale,\n ),\n }\n case 'orientation':\n return {\n orientation: amplified(\n Quat.nlerp(a.orientation ?? Quat.identity, b.orientation ?? Quat.identity, w),\n player.scale,\n ),\n }\n case 'pose':\n return blendPose(a, b, w)\n }\n}\n\n/**\n * A position's lerp and a rotation's nlerp, as two overlays or a pose blend (`MixerBlendPosQuat`).\n */\nexport const blendPose = (a: JointState, b: JointState, w: number): JointState => ({\n position: Vector3.lerp(a.position ?? Vector3.zero, b.position ?? Vector3.zero, w),\n orientation: Quat.nlerp(a.orientation ?? Quat.identity, b.orientation ?? Quat.identity, w),\n})\n\n/** Two overlays' blend by their count (`FMixerBlend::Evaluate`, `0661d349`), no amplitude. */\nexport const blendOverlays = (\n shape: Shape,\n a: JointState,\n b: JointState,\n w: number,\n): JointState => {\n switch (shape) {\n case 'value': {\n const from = a.value ?? 0\n\n return { value: Math.fround(((b.value ?? 0) - from) * w + from) }\n }\n case 'position':\n return { position: Vector3.lerp(a.position ?? Vector3.zero, b.position ?? Vector3.zero, w) }\n case 'orientation':\n return {\n orientation: Quat.nlerp(a.orientation ?? Quat.identity, b.orientation ?? Quat.identity, w),\n }\n case 'pose':\n return blendPose(a, b, w)\n }\n}\n\n/** What `TypedSampleXformType6` hands back: the stored position, and where it stands placed. */\nexport const mapped = (player: Player): { stored: Vector3; placed: Vector3 } => {\n if (player.shape !== 'pose') return { stored: Vector3.zero, placed: Vector3.zero }\n\n const time = player.ended ? endTime(player) : player.time\n const stored = interpolate(player, time).position ?? Vector3.zero\n const { rotation, position } = player.placement\n\n return { stored, placed: Vector3.add(Quat.transform(stored, rotation), position) }\n}\n\n/**\n * `SetChannelOverlayPosition`: a root stands at `target` now and its motion carries on from there.\n */\nexport const placeAt = (player: Player, target: Vector3): void => {\n if (!player.root) return\n\n const { rotation } = player.placement\n\n player.placement = {\n rotation,\n position: Vector3.subtract(target, Quat.transform(travel(player, player.time), rotation)),\n }\n player.sampled = { ...player.sampled, position: target }\n}\n\n/**\n * `SetChannelOverlayOrientation`: a root turns to `orientation` about where it stands. The turn is\n * the root's from `current`; the position kept is the stored one placed, without its weight, as\n * retail has it.\n */\nexport const turnTo = (player: Player, orientation: Quat, current: Quat): void => {\n if (!player.root) return\n\n const sample = interpolate(player, player.time)\n const stored = sample.position ?? Vector3.zero\n const { rotation, position } = player.placement\n // Turns about the stored position's world point: `turned` is the delta `orientation · current⁻¹` applied\n // over `rotation`, and `offset` re-seats the placement so that point stays where it was. Retail\n // reads `current` back from the engine instance, a proper rotation (`SetChannelOverlayOrientation`);\n // here it is the composed root, so both are made unit, or a host turning the root each frame from\n // its own read-back squares the length's float noise away to nothing (s002xe's Lonnigan at 50 s).\n const unit = (q: Quat) => Vector4.normalize(q) as Quat\n const turned = unit(\n Quat.multiply(Quat.multiply(orientation, Quat.conjugate(unit(current))), rotation),\n )\n const world = Vector3.add(Quat.transform(stored, rotation), position)\n const offset = Vector3.subtract(world, Quat.transform(stored, turned))\n\n player.placement = { rotation: turned, position: offset }\n player.sampled = {\n position: world,\n orientation: Quat.multiply(turned, sample.orientation ?? Quat.identity),\n }\n}\n\n/** `TypedAddDelta`: a pose's placement moves by `delta`, a frozen one posed again. */\nexport const shift = (player: Player, delta: Vector3): void => {\n if (player.shape !== 'pose') return\n\n const { rotation, position } = player.placement\n\n player.placement = { rotation, position: Vector3.add(position, delta) }\n if (player.held) hold(player)\n}\n","/**\n * A character's motion mixer: the per-joint blend stacks `engbase.dll` keeps (`EngBaseMixer.cpp`),\n * with the scripts, root placement and aims `deformable2.dll` drives them by. Pure, no GL.\n *\n * Each animated target, a joint or the root, has a stack of leaves (a playing channel), overlays (a\n * snapshot of the target) and blends (a fade from what is beneath to the leaf above). Starting with\n * a transition fades in over what is there; a transition of 0 replaces it. What it writes is a\n * joint's state as `@treewyrm/freelancer/compound` reads it, so `placeCostume`'s `jointState` takes\n * it as is, and the root's placement in the character's frame, for the host to set its root by.\n *\n * Not here: the pose curve a blend runs on a root started with event flags `0x38`\n * (`FMixerBlend::Evaluate` `0661d227`, `MixerBlendAttach` `06616319`), which no retail THN is known\n * to use; aims over more than one joint (the damped least-squares solve, `FUN_065fc000`); aims\n * without `point_at`; compounds' motion, which has no root block or heading.\n */\nimport type { AnimationScript } from '@treewyrm/freelancer/animation'\nimport { getJointMatrix, type Joint, type JointState } from '@treewyrm/freelancer/compound'\nimport { Matrix3, Matrix4, Quat, Vector3 } from '@treewyrm/freelancer/math'\nimport {\n bind,\n blendOverlays,\n channelShape,\n createPlayer,\n hold,\n mapped,\n mix,\n placeAt,\n playable,\n rest,\n shift,\n tick,\n turnTo,\n turnY,\n yaw,\n type Header,\n type Placement,\n type Player,\n type PlayerContext,\n type Shape,\n} from './player.js'\n\n/** Event flags a motion reads. */\nexport const MotionFlag = {\n Backwards: 0x1,\n Loop: 0x2,\n Bounce: 0x4,\n /** Keep what is beneath once the fade in completes, rather than stopping it. */\n KeepBeneath: 0x80,\n} as const\n\n// `G_MixerEaseStep` (`DAT_06629508`): the double 0x3F893B352540C735, which is 3.14159 / 255,\n// not π / 255.\nconst EASE_STEP = 3.14159 / 255\n\n/** `MixerEase` (`FUN_0661d050`): a fade's weight at step `i` of 255, `½(1 − cos(i · step))`. */\nexport const EASE: Float32Array = Float32Array.from({ length: 0x100 }, (_, step) =>\n Math.fround((1 - Math.cos(step * EASE_STEP)) * 0.5),\n)\n\n/**\n * A fade's weight `time` seconds into `duration`: its step is floored, and a zero-length fade is\n * whole.\n */\nexport const fadeWeight = (time: number, duration: number): number => {\n if (!(duration > 0)) return EASE[0xff]!\n\n const step = Math.floor(Math.fround(1 / duration) * time * 255)\n\n return EASE[step] ?? EASE[0xff]!\n}\n\ntype Node = Leaf | Blend | Overlay\n\ninterface Leaf {\n type: 'leaf'\n player: Player\n /** `bRemove`: dropped once this walk's value is written. */\n remove?: boolean\n}\n\ninterface Blend {\n type: 'blend'\n time: number\n duration: number\n /** `Flags` bit 0: once done, stop what it faded from. Off with {@link MotionFlag.KeepBeneath}. */\n dropBeneath: boolean\n}\n\ninterface Overlay {\n type: 'overlay'\n value: JointState\n}\n\ninterface Target {\n /** Absent for the root. */\n name?: string\n shape: Shape\n revolute: boolean\n /** The target's parameters as last written: `GetJointParams`, or the root's placement. */\n value: JointState\n /** `FMixerList`. Absent once empty, as the engine erases it. */\n track?: { nodes: Node[]; fade: number }\n}\n\ninterface Motion {\n type: 'motion'\n handle: number\n /** In the script's map order, which `TypedSampleXformType6` picks the first of. */\n players: { player: Player; target: Target }[]\n height?: number\n}\n\ninterface Aim {\n type: 'aim'\n handle: number\n player: Player\n target: Target\n joint: string\n goal: Quat\n stopped: boolean\n}\n\n/** One animatable joint: its name, its parent's, and the joint its constraint makes. */\nexport interface MixerJoint {\n name: string\n parent: string\n joint: Joint\n}\n\nexport interface MixerOptions {\n /** The root bone's name, which object maps drive. */\n root: string\n /** Every joint, a parent before its children. */\n joints: readonly MixerJoint[]\n /** The root's placement in the character's frame. */\n position?: Vector3\n orientation?: Quat\n}\n\n/** A motion's record, as `START_MOTION` hands it to `IDeformable +0x1c`. */\nexport interface MotionOptions {\n /** Seconds into each channel; past any channel's end the motion does not start. */\n startTime?: number\n /** The players' speed, its sign ignored. */\n timeScale?: number\n /** An amplitude on every channel, not a mix weight. */\n weight?: number\n /** The fade in, per target. 0 stops whatever was on each target. */\n transTime?: number\n eventFlags?: number\n /** Radians about Y the root faces; negative keeps its current yaw. */\n heading?: number\n}\n\nexport interface AimOptions {\n /** The joint's world rotation, in the space the root is placed in: the root's own turn included. */\n target: Quat\n transitionDuration?: number\n eventFlags?: number\n}\n\nconst SHAPES: Partial<Record<Joint['type'], Shape>> = {\n revolute: 'value',\n prismatic: 'value',\n translational: 'position',\n sphere: 'orientation',\n loose: 'pose',\n}\n\n// `SetHeight` (`0x65f50b0`) leaves the root be when the shift is within a float's epsilon.\nconst FLOAT_EPSILON = 1.1920928955078125e-7\n\nconst placementOf = ({ position, orientation }: JointState): Placement => ({\n position: position ?? Vector3.zero,\n rotation: orientation ?? Quat.identity,\n})\n\nconst isLeafOf = (node: Node, player: Player): boolean =>\n node.type === 'leaf' && node.player === player\n\nconst remove = (nodes: Node[], node: Node): void => {\n const at = nodes.indexOf(node)\n if (at >= 0) nodes.splice(at, 1)\n}\n\n/** `MixerMarkDropped`: a dropped leaf's player counts as ended. */\nconst drop = (nodes: Node[], node: Node): void => {\n if (node.type === 'leaf') node.player.ended = true\n remove(nodes, node)\n}\n\n/**\n * `MixerUnlinkParentBlend` (`FUN_066156f0`): a blend, what it faded from (recursively when that is\n * a blend too) and, with `inner`, what it faded to.\n */\nconst unwind = (nodes: Node[], blend: Node, inner: boolean): void => {\n const at = nodes.indexOf(blend)\n const to = nodes[at - 1]\n const from = nodes[at - 2]\n\n if (from?.type === 'blend') unwind(nodes, from, true)\n else if (from) drop(nodes, from)\n\n if (inner && to) drop(nodes, to)\n remove(nodes, blend)\n}\n\n/** What was faded from, a blend with all beneath it or a single node. */\nconst dropBeneath = (nodes: Node[], node: Node | undefined): void => {\n if (node?.type === 'blend') unwind(nodes, node, true)\n else if (node) drop(nodes, node)\n}\n\nexport class Mixer {\n readonly #rootName: string\n readonly #root: Target\n readonly #joints = new Map<string, { parent: string; joint: Joint; target?: Target }>()\n readonly #locks = new Set<string>()\n /** `FDeformInstance`'s list: motions and aims in the order they started. */\n #records: (Motion | Aim)[] = []\n #next = 1\n /** `Offset20`, the floor. */\n #floor = 0\n /**\n * `Offset24`: the root's height over the floor when nothing plays, for a script with no `Root\n * height`.\n */\n #base = 0\n\n constructor({\n root,\n joints,\n position = Vector3.zero,\n orientation = Quat.identity,\n }: MixerOptions) {\n this.#rootName = root\n this.#root = { shape: 'pose', revolute: false, value: { position, orientation } }\n\n for (const { name, parent, joint } of joints) {\n // A fixed or cylinder joint takes no channel (`TypedBindMap`); it is still a parent.\n const shape = SHAPES[joint.type]\n const target: Target | undefined = shape && {\n name,\n shape,\n revolute: joint.type === 'revolute',\n value: rest(shape),\n }\n\n this.#joints.set(name, { parent, joint, ...(target ? { target } : {}) })\n }\n }\n\n /** The root's placement in the character's frame, as the mixer last wrote it. */\n get root(): { position: Vector3; orientation: Quat } {\n const { position, rotation } = placementOf(this.#root.value)\n\n return { position, orientation: rotation }\n }\n\n /** `Offset20`. */\n get floor(): number {\n return this.#floor\n }\n\n /** A joint's state as last written, its rest before anything has. */\n jointState(name: string): JointState | undefined {\n return this.#joints.get(name)?.target?.value\n }\n\n /**\n * `RegisterAnimHandle`: scripts started later leave the joint be, and an aim through it fails.\n */\n lock(name: string): void {\n this.#locks.add(name)\n }\n\n /** `UnregisterAnimHandle`, as THN's Finish of a motion with a `locked_bone` does. */\n unlock(name: string): void {\n this.#locks.delete(name)\n }\n\n /**\n * `PlayInstanceAnim` (`FUN_065f41d0`): bind the script's maps, stand the root upright at its\n * `Root height` over the floor facing `heading`, and fade each target in. `undefined` when the\n * start time is past a channel's end (`TypedTimePlayable`), which retail destroys the script for.\n */\n start(script: AnimationScript, options: MotionOptions = {}): number | undefined {\n const {\n startTime = 0,\n timeScale = 1,\n weight = 1,\n transTime = 0,\n eventFlags = 0,\n heading = -1,\n } = options\n\n this.#sweep()\n\n const players = this.#bindMaps(script)\n const at = Math.fround(startTime)\n const header: Header = {\n start: at,\n flags: eventFlags & 0xfe,\n rate: Math.abs(Math.fround(timeScale)) * (eventFlags & MotionFlag.Backwards ? -1 : 1),\n scale: weight,\n transScale: 1,\n }\n\n if (!players.every(({ player }) => playable(player, at))) return undefined\n\n const root = placementOf(this.#root.value)\n // `RootDataEval`: a start part way in lifts the root by the stored height there, so it does not\n // drop.\n let lift = 0\n\n if (at > 0) {\n for (const { player } of players) bind(player, header, root)\n\n const first = players.find(\n ({ player }) => player.shape === 'position' || player.shape === 'pose',\n )\n if (first) lift = mapped(first.player).stored.y\n }\n\n const height = (script.height ?? this.#base) + this.#floor\n const block: Placement = {\n rotation: heading < 0 ? yaw(root.rotation) : turnY(heading),\n position: { x: root.position.x, y: lift + height, z: root.position.z },\n }\n for (const { player } of players) bind(player, { ...header, block }, root)\n for (const { player, target } of players) this.#attach(target, player, transTime, eventFlags)\n\n const handle = this.#next++\n\n this.#records.push({\n type: 'motion',\n handle,\n players,\n ...(script.height === undefined ? {} : { height: script.height }),\n })\n return handle\n }\n\n /**\n * `DestroyHandle`: THN's Finish. Every target lets go at once, with no fade out\n * (`MixerUnbindTyped`).\n */\n stop(handle: number): void {\n const record = this.#records.find((record) => record.handle === handle)\n if (record?.type !== 'motion') return\n for (const { player, target } of record.players) this.#unbind(target, player)\n this.#records = this.#records.filter((other) => other !== record)\n }\n\n /** Whether any of a motion's channels is still on a target. */\n playing(handle: number): boolean {\n const record = this.#records.find((record) => record.handle === handle)\n if (!record) return false\n return record.type === 'motion'\n ? record.players.some(({ player, target }) => this.#onTrack(target, player))\n : this.#onTrack(record.target, record.player)\n }\n\n /**\n * `FUN_065f5400` for one joint with `point_at`: the joint's world rotation goes to `target`,\n * entering its stack as a motion would, with the transition as its fade. The joint locks;\n * `undefined` when it already was, or is not a sphere joint (on a loose one retail would write a\n * rotation over its position, which is not reproduced).\n */\n aim(\n joint: string,\n { target, transitionDuration = 0, eventFlags = 0 }: AimOptions,\n ): number | undefined {\n const entry = this.#joints.get(joint)?.target\n if (entry?.shape !== 'orientation') return undefined\n if (this.#locks.has(joint)) return undefined\n this.#locks.add(joint)\n\n // `StartIk` (`0x452460`) adds 0x40 for point_at, 0x80 for one joint and 0x100 for the flags'\n // top\n // bit; the play header keeps bit 8 as bit 7 (`(Flags >> 1) & 0x80`).\n const flags = eventFlags | 0x40 | 0x80 | (eventFlags & 0x80 ? 0x100 : 0)\n const keep = (flags >> 1) & MotionFlag.KeepBeneath\n const player = createPlayer('orientation', {})\n\n bind(\n player,\n { start: 0, flags: keep, rate: 1, scale: 1, transScale: 1 },\n placementOf(this.#root.value),\n )\n this.#attach(entry, player, Math.fround(transitionDuration), keep)\n\n const handle = this.#next++\n\n this.#records.push({\n type: 'aim',\n handle,\n player,\n target: entry,\n joint,\n goal: target,\n stopped: false,\n })\n return handle\n }\n\n /** THN re-sends an aim's target at every update. */\n setAimTarget(handle: number, target: Quat): void {\n const record = this.#records.find((record) => record.handle === handle)\n if (record?.type === 'aim') record.goal = target\n }\n\n /**\n * `StopAimNode`: the joint unlocks, and the aim ends as a channel running out does. With\n * {@link MotionFlag.KeepBeneath} it fades back to what is beneath; without, its pose holds.\n */\n stopAim(handle: number): void {\n const record = this.#records.find((record) => record.handle === handle)\n if (record?.type !== 'aim' || record.stopped) return\n record.stopped = true\n this.#locks.delete(record.joint)\n }\n\n /**\n * `MixerWalkAll` (`LAB_066157f0`): every stack ticks, then writes its target. Joints first, then\n * the root.\n */\n advance(dt: number): void {\n const step = Math.fround(dt)\n\n const context: PlayerContext = {\n root: placementOf(this.#root.value),\n loopHeight: (player) => {\n const motion = this.#records.find(\n (record): record is Motion =>\n record.type === 'motion' && record.players.some((bound) => bound.player === player),\n )\n\n return (motion?.height ?? this.#base) + this.#floor\n },\n aim: (player) => {\n const record = this.#records.find(\n (record): record is Aim => record.type === 'aim' && record.player === player,\n )\n\n if (!record || record.stopped)\n return { value: record?.target.value ?? player.sampled, stopped: true }\n\n return { value: { orientation: this.#aimRotation(record) }, stopped: false }\n },\n }\n\n for (const { target } of this.#joints.values()) {\n if (!target) continue\n context.root = placementOf(this.#root.value)\n this.#walk(target, step, context)\n }\n\n context.root = placementOf(this.#root.value)\n this.#walk(this.#root, step, context)\n }\n\n /**\n * `SetPosePos`: the root goes to `position`'s x and z. Its height is each motion's own: `Root\n * height` plus its stored height now plus the floor, or the resting height without one;\n * `position.y` is not read.\n */\n setRootPosition(position: Vector3): void {\n this.#sweep()\n\n let y: number | undefined\n\n for (const record of this.#records) {\n if (record.type !== 'motion') continue\n\n const height =\n record.height === undefined\n ? this.#base\n : record.height + (this.#firstMapped(record)?.stored.y ?? 0)\n\n y = height + this.#floor\n\n const target = { x: position.x, y, z: position.z }\n\n if (!this.#anyTrack()) continue\n // `PlaybackWriteOverlayPos` (`FUN_06612a70`).\n for (const { player } of record.players) placeAt(player, target)\n\n if (record.players.some(({ player }) => player.root))\n this.#overlays(this.#root, (value) => ({ ...value, position: target }))\n }\n\n this.#root.value = {\n ...this.#root.value,\n position: { x: position.x, y: y ?? this.#base + this.#floor, z: position.z },\n }\n }\n\n /**\n * `SetPoseOri`: the root turns to `orientation`, every motion's root turning with it about where\n * it stands.\n */\n setRootOrientation(orientation: Quat): void {\n const current = placementOf(this.#root.value).rotation\n\n if (this.#anyTrack())\n for (const record of this.#records) {\n if (record.type !== 'motion') continue\n // `PlaybackWriteOverlayOrient` (`FUN_06612b80`).\n for (const { player } of record.players) turnTo(player, orientation, current)\n\n if (record.players.some(({ player }) => player.root))\n this.#overlays(this.#root, (value) => ({ ...value, orientation }))\n }\n\n this.#root.value = { ...this.#root.value, orientation }\n }\n\n /**\n * `SetHeight` (`0x65f50b0`): the floor, under every motion's root from the next advance. A\n * motion's root moves by what puts it at its height over the new floor.\n */\n setFloor(height: number): void {\n this.#floor = Math.fround(height)\n this.#sweep()\n\n for (const record of this.#records) {\n if (record.type !== 'motion') continue\n\n let delta: number\n\n if (record.height === undefined) {\n delta = this.#base + this.#floor - placementOf(this.#root.value).position.y\n } else {\n const { stored, placed } = this.#firstMapped(record) ?? {\n stored: Vector3.zero,\n placed: Vector3.zero,\n }\n\n delta = record.height + stored.y + this.#floor - placed.y\n }\n\n if (!(Math.abs(delta) > FLOAT_EPSILON) || !this.#anyTrack()) continue\n\n // `PlaybackAddOverlayPos` (`FUN_06612c60`).\n const step = { x: 0, y: delta, z: 0 }\n for (const { player } of record.players) shift(player, step)\n\n if (record.players.some(({ player }) => player.root))\n this.#overlays(this.#root, (value) => ({\n ...value,\n position: Vector3.add(value.position ?? Vector3.zero, step),\n }))\n }\n }\n\n /**\n * `BindTrackTarget` and `TypedBindMap`: a map binds by name, parent and shape, and not to a\n * locked target.\n */\n #bindMaps({ maps }: AnimationScript): Motion['players'] {\n const players: Motion['players'] = []\n\n for (const map of maps) {\n const shape = channelShape(map.channel)\n\n if (map.type === 'joint') {\n const entry = this.#joints.get(map.child)\n const target = entry?.target\n if (!target || this.#locks.has(map.child)) continue\n if (entry.parent !== map.parent || shape !== target.shape) continue\n\n const { channel } = map\n\n players.push({\n player: createPlayer(shape, { channel, revolute: target.revolute }),\n target,\n })\n } else {\n // An object map names the root, or nothing the character has and so the root\n // (`BindTrackTarget`, `FUN_06612320`).\n // Retail's 1,008 all name `Root`; one naming another joint would drive it as a root, not\n // here.\n if (this.#joints.has(map.object) || this.#locks.has(this.#rootName)) continue\n if (shape !== 'pose') continue\n players.push({\n player: createPlayer('pose', { channel: map.channel, root: true }),\n target: this.#root,\n })\n }\n }\n\n return players\n }\n\n /** `MixerBlendAttach` (`FUN_06616090`). */\n #attach(target: Target, player: Player, duration: number, flags: number): void {\n target.track ??= { nodes: [], fade: 0 }\n\n const track = target.track\n const { nodes } = track\n if (nodes.some((node) => isLeafOf(node, player))) return\n\n const fades = duration > 0\n\n if (fades) {\n // Over nothing, the snapshot always goes once the fade completes.\n if (!nodes.length) {\n flags &= ~MotionFlag.KeepBeneath\n nodes.push({ type: 'overlay', value: target.value })\n }\n } else {\n for (const node of nodes) if (node.type === 'leaf') node.player.ended = true\n nodes.length = 0\n }\n\n // Stack order `[…old, leaf, blend]`: a blend pops what it fades to (the leaf), then what it fades from.\n nodes.push({ type: 'leaf', player })\n if (!fades) return\n nodes.push({\n type: 'blend',\n time: 0,\n duration,\n dropBeneath: !(flags & MotionFlag.KeepBeneath),\n })\n track.fade = duration\n }\n\n /**\n * `MixerUnbindTyped` (`FUN_06615ec0`): a leaf another fade still reads from is swapped for a\n * snapshot of the target; a leaf being faded to takes what it faded from with it.\n */\n #unbind(target: Target, player: Player): void {\n const nodes = target.track?.nodes\n if (!nodes) return\n\n const leaf = nodes.find((node) => isLeafOf(node, player))\n\n if (leaf) {\n const at = nodes.indexOf(leaf)\n const after = nodes[at + 1]\n\n if (after && nodes[at + 2]?.type === 'blend') {\n nodes.splice(at + 1, 0, { type: 'overlay', value: target.value })\n\n const blend = nodes[at + 3]\n if (blend?.type === 'blend') blend.dropBeneath = true\n } else if (after?.type === 'blend') {\n const next = nodes[at + 2]\n\n if (next && nodes[at + 3]?.type === 'blend')\n nodes.splice(at + 2, 0, { type: 'overlay', value: target.value })\n\n dropBeneath(nodes, nodes[at - 1])\n remove(nodes, after)\n }\n\n remove(nodes, leaf)\n }\n\n if (!nodes.length) delete target.track\n }\n\n /**\n * `MixerWalkPlayback` (`EngBaseMixer.cpp`): tick each node, settle what finished, write the\n * stack's value.\n */\n #walk(target: Target, dt: number, context: PlayerContext): void {\n const track = target.track\n if (!track) return\n\n const { nodes } = track\n\n for (const node of [...nodes]) {\n const at = nodes.indexOf(node)\n if (at < 0) continue\n\n if (node.type === 'blend') {\n // `FMixerBlend::Tick`: done at or past its length, the sum compared before it is stored.\n const sum = dt + node.time\n\n node.time = Math.fround(sum)\n if (!(sum >= node.duration)) continue\n if (node.dropBeneath) dropBeneath(nodes, nodes[at - 2])\n remove(nodes, node)\n } else if (node.type === 'leaf') {\n if (!tick(node.player, dt, context)) continue\n\n const next = nodes[at + 1]\n const before = nodes[at - 1]\n\n if (next) {\n // Under a fade it holds its last value; beneath a finished one it goes.\n if (next.type === 'blend' || nodes[at + 2]?.type === 'blend') hold(node.player)\n else remove(nodes, node)\n } else if (!before) {\n hold(node.player)\n node.remove = true\n } else {\n // On top of something: fade back to it over the target's last transition.\n // `[…, before, leaf]` becomes `[…, leaf, before, blend]`: the held leaf fades to what was beneath.\n hold(node.player)\n remove(nodes, node)\n nodes.splice(nodes.indexOf(before), 0, node)\n nodes.push({ type: 'blend', time: 0, duration: track.fade, dropBeneath: true })\n }\n }\n }\n\n const stack = [...nodes]\n const top = stack.pop()\n const value = top && this.#evaluate(top, stack, target)\n if (value) target.value = value\n\n track.nodes = nodes.filter((node) => !(node.type === 'leaf' && node.remove))\n if (!track.nodes.length) delete target.track\n }\n\n /** `MixerStackEvaluate`: a node's value, a blend popping what it fades to and from beneath it. */\n #evaluate(node: Node, stack: Node[], target: Target): JointState | undefined {\n if (node.type === 'leaf') return node.player.sampled\n if (node.type === 'overlay') return node.value\n\n const to = stack.pop()\n const from = stack.pop()\n // Retail would read through a null here; nothing it builds gets there.\n if (!to || !from) return undefined\n\n const a = this.#evaluate(from, stack, target) ?? target.value\n const b = this.#evaluate(to, stack, target) ?? target.value\n const w = fadeWeight(node.time, node.duration)\n // The leaf faded to, or else the one faded from, decides how (`0661d1d7`).\n const leaf = to.type === 'leaf' ? to : from.type === 'leaf' ? from : undefined\n if (leaf) return mix(leaf.player, a, b, w)\n\n if (to.type === 'overlay' && from.type === 'overlay')\n return blendOverlays(target.shape, a, b, w)\n\n // Retail writes a stale value here; nothing it builds gets there either.\n return undefined\n }\n\n /**\n * `IkSolveSingleJoint` with `point_at`: the parent's world rotation undone from the target.\n * Retail reads the parent's world part way through the walk, in the engine's order; here joints\n * walk parents first and the root last, so the parent is this tick's and the root the last one's.\n * Uncertain.\n */\n #aimRotation({ joint, goal }: Aim): Quat {\n const parent = this.#joints.get(joint)?.parent\n const world = parent === undefined ? Matrix4.identity : this.#world(parent)\n\n return Quat.multiply(Quat.conjugate(Matrix4.decompose(world).orientation), goal)\n }\n\n /**\n * A joint's world, from the values as they stand: through its parents to the root's placement. An\n * unknown name is the identity.\n */\n #world(name: string): Matrix4 {\n if (name === this.#rootName) {\n const { position, rotation } = placementOf(this.#root.value)\n\n return Matrix4.fromRotationTranslation(Matrix3.fromQuaternion(rotation), position)\n }\n\n const entry = this.#joints.get(name)\n if (!entry) return Matrix4.identity\n return Matrix4.multiply(\n this.#world(entry.parent),\n getJointMatrix(entry.joint, entry.target?.value),\n )\n }\n\n /**\n * `SweepExpiredList` (`FUN_065f4de0`): forget what no stack holds; with nothing left, note the\n * root's height.\n */\n #sweep(): void {\n this.#records = this.#records.filter((record) =>\n record.type === 'aim'\n ? !record.stopped || this.#onTrack(record.target, record.player)\n : record.players.some(({ player, target }) => this.#onTrack(target, player)),\n )\n\n if (!this.#records.length)\n this.#base = Math.fround(placementOf(this.#root.value).position.y - this.#floor)\n }\n\n #onTrack(target: Target, player: Player): boolean {\n return !!target.track?.nodes.some((node) => isLeafOf(node, player))\n }\n\n /**\n * Whether the character has any stack: `MixerFindKey` on its root, which the overlay writers\n * need.\n */\n #anyTrack(): boolean {\n if (this.#root.track) return true\n for (const { target } of this.#joints.values()) if (target?.track) return true\n return false\n }\n\n /**\n * `PlaybackTouchMappedTyped` (`FUN_066122d0`): the first channel carrying a position, as `mapped`\n * reads it.\n */\n #firstMapped(record: Motion): ReturnType<typeof mapped> | undefined {\n const first = record.players.find(\n ({ player }) => player.shape === 'position' || player.shape === 'pose',\n )\n\n return first && mapped(first.player)\n }\n\n #overlays(target: Target, change: (value: JointState) => JointState): void {\n for (const node of target.track?.nodes ?? [])\n if (node.type === 'overlay') node.value = change(node.value)\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AACA,MAAa,iBACX,QACA,YAC2B;CAC3B,MAAM,KAAK,OAAO,WAAW,UAAU,OAAO;CAC9C,IAAI,CAAC,IAAI,MAAM,IAAI,MAAM,yBAAyB;CAClD,OAAO;AACT;;ACFA,MAAM,WAAW,IAA4B,MAAc,WAAgC;CACzF,MAAM,SAAS,GAAG,aAAa,IAAI;CACnC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,sBAAsB;CAEnD,GAAG,aAAa,QAAQ,MAAM;CAC9B,GAAG,cAAc,MAAM;CAEvB,IAAI,CAAC,GAAG,mBAAmB,QAAQ,GAAG,cAAc,GAAG;EACrD,MAAM,MAAM,GAAG,iBAAiB,MAAM;EAEtC,GAAG,aAAa,MAAM;EACtB,MAAM,IAAI,MAAM,8BAA8B,KAAK;CACrD;CAEA,OAAO;AACT;;AAGA,MAAa,iBACX,IACA,cACA,gBACA,WAAyB,CAAC,MACX;CACf,MAAM,SAAS,QAAQ,IAAI,GAAG,eAAe,YAAY;CACzD,IAAI;CAEJ,IAAI;EACF,WAAW,QAAQ,IAAI,GAAG,iBAAiB,cAAc;CAC3D,SAAS,OAAO;EACd,GAAG,aAAa,MAAM;EACtB,MAAM;CACR;CAEA,MAAM,SAAS,GAAG,cAAc;CAEhC,GAAG,aAAa,QAAQ,MAAM;CAC9B,GAAG,aAAa,QAAQ,QAAQ;CAChC,GAAG,YAAY,MAAM;CAGrB,GAAG,aAAa,MAAM;CACtB,GAAG,aAAa,QAAQ;CAExB,IAAI,CAAC,GAAG,oBAAoB,QAAQ,GAAG,WAAW,GAAG;EACnD,MAAM,MAAM,GAAG,kBAAkB,MAAM;EAEvC,GAAG,cAAc,MAAM;EACvB,MAAM,IAAI,MAAM,wBAAwB,KAAK;CAC/C;CAEA,MAAM,YAAY,CAAC;CACnB,KAAK,MAAM,QAAQ,UAAU,UAAU,QAAQ,GAAG,mBAAmB,QAAQ,IAAI;CAEjF,OAAO;EAAE;EAAQ,UAAU;CAAU;AACvC;;;;;;;AClDA,MAAa,iBACX,EAAE,QAAQ,QACV,SACA,SACW;CACX,MAAM,QAAQ,OAAO;CAGrB,IAAI,SAAS,GAAG,OAAO;CAEvB,MAAM,MAAM,KAAK,OAAO,IAAI;CAC5B,IAAI,EAAE,KAAK,IAAI,GAAG,IAAI,OAAO,OAAO;CAGpC,MAAM,WAAW,QAAQ,MAAM;CAC/B,MAAM,UAAU,KAAK,OACnB,SAAS,SAAS,UAAU,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,SAAS,QAAQ,CAAC,CAChF;CAGA,OAAO,KAAK,MAAO,MAAM,UAAW,KAAK,IAAI;AAC/C;;AAGA,MAAa,cACX,WACA,OACA,YACiD;CACjD,MAAM,KAAK,UAAU,OAAO;CAC5B,IAAI,CAAC,IAAI,OAAO,KAAA;CAEhB,MAAM,OAAO,GAAG,UAAU,KAAK,GAAG,GAAG;CACrC,MAAM,QAAQ,QAAQ,IAAI;CAE1B,OAAO,SAAS,MAAM,SAAS,UAAU,MAAM,SAAS,aAAa;EAAE;EAAM;CAAM,IAAI,KAAA;AACzF;;;;AC1CA,MAAa,eACX,WACA,QACA,SACwB;CACxB,IAAI,CAAC,WAAW,QAAQ,OAAO,KAAA;CAC/B,OAAO,gBAAgB,YAAY,WAAW,QAAQ,IAAI,CAAC;AAC7D;;AAGA,MAAa,gBAAgB,UAA4B;CACvD,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM;CACnC,MAAM,KAAK;EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAAE;CAC1F,MAAM,KAAK;EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAAE;CAC1F,MAAM,KAAK;EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAAE;CAC1F,MAAM,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG;CAC/C,MAAM,IAAI,KAAK,IAAI,GAAG,IAAI,OAAO,IAAI,MAAM;CAE3C,OAAO;EACL,GAAG;GAAE,GAAG,GAAG,IAAI;GAAG,GAAG,GAAG,IAAI;GAAG,GAAG,GAAG,IAAI;GAAG,GAAG;EAAE;EACjD,GAAG;GAAE,GAAG,GAAG,IAAI;GAAG,GAAG,GAAG,IAAI;GAAG,GAAG,GAAG,IAAI;GAAG,GAAG;EAAE;EACjD,GAAG;GAAE,GAAG,GAAG,IAAI;GAAG,GAAG,GAAG,IAAI;GAAG,GAAG,GAAG,IAAI;GAAG,GAAG;EAAE;EACjD,GAAG;GACD,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK;GAC7C,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK;GAC7C,GAAG,EAAE,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,KAAK;GAC7C,GAAG;EACL;CACF;AACF;;AAGA,MAAa,iBAAiB,QAAiB,UAA4B;CACzE,MAAM,KAAK,MAAM,IAAI,OAAO,EAAE;CAC9B,MAAM,KAAK,MAAM,IAAI,OAAO,EAAE;CAC9B,MAAM,KAAK,MAAM,IAAI,OAAO,EAAE;CAE9B,OAAO;EACL,GAAG,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI;EACpD,GAAG,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI;EACpD,GAAG,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI,KAAK,OAAO,EAAE,IAAI;CACtD;AACF;ACfA,MAAa,eAA0B;CACrC,oBAAoB;CACpB,mBAAmB;CACnB,mBAAmB;CAEnB,uBAAuB;CACvB,mBAAmB;CACnB,mBAAmB;CACnB,mBAAmB;CACnB,uBAAuB;AACzB;AAWA,MAAa,eAAe,OAAO,GAAG,QAAmB,kBAA+B;CACtF;CACA,sBAAM,IAAI,IAAI;CACd,QAAQ;CACR,UAAU,OAAO;CACjB,UAAU;AACZ;;AAGA,MAAM,UAAU,UAA+B;CAC7C,MAAM,QAAQ,MAAM;CACpB,MAAM,SAAW,QAAQ,QAAS,IAAM,QAAQ,SAAa,MAAM,WAAW,SAAS;CACvF,MAAM,MAAQ,UAAU,KAAM,IAAM,QAAQ;CAE5C,MAAM,WAAY,MAAM,WAAW,IAAK;CACxC,MAAM,WAAY,MAAM,QAAQ,IAAK;CAErC,MAAM,OAAO,MAAM;CAEnB,OAAO,KAAK,QAAS,OAAO,MAAU,SAAS,IAAK,OAAS,KAAK,OAAO,IAAI,GAAG,CAAC;AACnF;AAEA,MAAM,wBAAQ,IAAI,aAAa,CAAC;AAChC,MAAM,MAAM,IAAI,WAAW,MAAM,MAAM;;AAGvC,MAAM,iBAAiB,YAA4B;CACjD,MAAM,KAAK;CACX,IAAI,KAAK,cAAc,IAAI,MAAO;CAElC,MAAM,QAAQ,MAAM;CAEpB,QAAQ,MAAM,KAAM,UAAU,QAAQ,SAAS;AACjD;AAEA,MAAM,SAAS,GAA8B,QAAgB,MAAc,aACzE,IAAI,QAAQ,GAAG,QAAQ,IAAI,IAAI;AAGjC,MAAMA,YAAU,GAAY,EAAE,GAAG,GAAG,SAA2B;CAC7D,GAAG,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI;CACnC,GAAG,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI;CACnC,GAAG,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI;AACrC;AA8EA,MAAM,WAAW;AAEjB,MAAM,cAAc,aAA4B;CAC9C,yBAAS,IAAI,aAAa,GAAiB;CAC3C,UAAU;CACV,MAAM;CACN,MAAM;CACN,OAAO;CACP;CACA,OAAO;CACP,SAAS;CACT,QAAQ;AACV;AAEA,MAAM,WAAW,MAAY,MAC3B,KAAK,QAAQ,IAAA,MAAa,KAAK,QAAQ,KAAK,QAAQ,IAAA,OAAe,KAAK,QAAQ,IAAA;;AAGlF,MAAM,SAAS;AAEf,MAAM,UAAU,SAAe;CAC7B,MAAM,EAAE,SAAS,UAAU;CAC3B,IAAI,QAAQ,QAAQ;CACpB,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAA,KAAA,MAAuB;CAC3E,KAAK,QAAQ;CACb,KAAK;AACP;AAkBA,MAAM,QAAQ,SAAyB,KAAK,MAAM,SAAS,KAAK,SAAS,UAAU;AAEnF,MAAM,YAAY,KAAK,UAAU;CAAE,MAAM;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAAG,OAAO,CAAC,KAAK,KAAK;AAAE,CAAC;;AAGpF,MAAMC,YAAU,aAA+B;CAC7C,MAAM,SAAS,KAAK,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;CAC5D,IAAI,EAAE,SAAS,IAAI,OAAO,KAAK;CAE/B,MAAM,IAAI;EAAE,GAAG,SAAS,IAAI;EAAQ,GAAG,SAAS,IAAI;EAAQ,GAAG,SAAS,IAAI;CAAO;CAInF,IAAI,KAAK,IAAI,EAAE,CAAC,IAAI,KAAM;EACxB,MAAM,IAAI,KAAK,MAAM,EAAE,GAAG,EAAE,CAAC;EAE7B,OAAO,KAAK,UAAU;GAAE,MAAM;IAAE,GAAG,EAAE,IAAI;IAAG,GAAG;IAAG,GAAG,CAAC,EAAE,IAAI;GAAE;GAAG,OAAO,KAAK,KAAK,EAAE,CAAC;EAAE,CAAC;CAC1F;CAEA,MAAM,IAAI,KAAK,MAAM,EAAE,GAAG,EAAE,CAAC;CAC7B,MAAM,QAAQ,KAAK,UAAU;EAC3B,MAAM,IAAI,IAAI;GAAE,GAAG;GAAG,GAAG,CAAC,EAAE,IAAI;GAAG,GAAG,EAAE,IAAI;EAAE,IAAI;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EACrE,OAAO,KAAK,KAAK,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;CACjD,CAAC;CAED,OAAO,KAAK,SAAS,OAAO,SAAS;AACvC;AAEA,MAAM,eAAe,QAA6B,KAAgB,SAAkB;CAClF,MAAM,OAAO,SAAS,OAAO,WAAW;CAExC,IAAI,KAAK,KAAK;CAEd,OAAO,KAAK,KAAK,KAAK,KAAK,EAAE,CAAE,MAAM,KAAK,KAAK;CAC/C,KAAK,OAAO,IAAI,GAAG,IAAI;AACzB;;AAGA,MAAM,QAAQ,SAAkB;CAC9B,IAAI,KAAK,MAAM;CACf,KAAK,MAAM,SAAS,KAAK,UAAU,KAAK,KAAK;CAC7C,KAAK,WAAW,CAAC;CACjB,KAAK,OAAO;CACZ,KAAK,OAAO;AACd;AAEA,MAAM,UAAU,MAAe,QAAmB;CAChD,MAAM,OAAO,KAAK,SAAS,KAAK,OAAO,WAAW;CAClD,MAAM,KAAK,KAAK,QAAQ,IAAI;CAC5B,IAAI,MAAM,GAAG,KAAK,OAAO,IAAI,CAAC;AAChC;;;AAIA,MAAM,eAAe,QAAmB,IAAI,MAAM,OAAO,QAAQ,IAAI,QAAQ,QAAQ,IAAI,IAAI;;AAG7F,MAAM,mBAAmB,QACvB,IAAI,MAAM,OAAO,QAAQ,IAAI,QAAQ,IAAI,YAAY,aAAa,YAAY;;AAGhF,MAAM,WAAW,KAAgB,QAAmB;CAClD,KAAK,MAAM,QAAQ,IAAI,OAAO;EAC5B,IAAI,KAAK,YAAY,aAAa,aAAa,KAAK,MAAM;EAC1D,KAAK,IAAI;EACT,OAAO,MAAM,GAAG;CAClB;AACF;AAmBA,MAAM,cAAc,OAAkB,OAAgB,UAAmB;CACvE,MAAM,EAAE,UAAU;CAElB,QAAQ,MAAM,MAAd;EACE,KAAK,iBAAiB;GACpB,MAAM,SAASD,SAAO,OAAO;IAAE,GAAG;IAAG,GAAG,CAAC,MAAM;IAAQ,GAAG;GAAE,CAAC;GAE7D,QAAQ,GAAiB,MAAc;IACrC,EAAE,IAAA,MAAkB,OAAO;IAC3B,EAAE,IAAA,IAAe,MAAO,OAAO;IAC/B,EAAE,IAAA,IAAe,MAAO,OAAO;GACjC;EACF;EACA,KAAK,aAAa;GAChB,MAAM,SAASA,SAAO,OAAO;IAAE,GAAG;IAAG,GAAG,MAAM;IAAW,GAAG;GAAE,CAAC;GAC/D,MAAM,EAAE,UAAU;GAGlB,QAAQ,GAAiB,MAAc;IACrC,EAAE,IAAA,KAAgB,EAAE,IAAA,MAAkB,OAAO,IAAI,EAAE,IAAA,MAAkB;IACrE,EAAE,IAAA,IAAe,KAAK,EAAE,IAAA,IAAe,MAAO,OAAO,IAAI,EAAE,IAAA,IAAe,MAAO;IACjF,EAAE,IAAA,IAAe,KAAK,EAAE,IAAA,IAAe,MAAO,OAAO,IAAI,EAAE,IAAA,IAAe,MAAO;GACnF;EACF;EACA,KAAK,oBAAoB;GACvB,MAAM,QAAQ,MAAM,IAAI,QAAQ;GAChC,MAAM,EAAE,WAAW,UAAU;GAG7B,QAAQ,GAAiB,MAAc;IACrC,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI;IAC/B,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI;IAC/B,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI;IAC/B,MAAM,IAAI,cAAc,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;IAC1D,MAAM,OAAO,OAAO,KAAK,IAAI;IAE7B,EAAE,IAAA,KAAgB,EAAE,IAAA,MAAkB,IAAI,IAAI,OAAO,EAAE,IAAA,MAAkB;IACzE,EAAE,IAAA,IAAe,KAAK,EAAE,IAAA,IAAe,MAAO,IAAI,IAAI,OAAO,EAAE,IAAA,IAAe,MAAO;IACrF,EAAE,IAAA,IAAe,KAAK,EAAE,IAAA,IAAe,MAAO,IAAI,IAAI,OAAO,EAAE,IAAA,IAAe,MAAO;GACvF;EACF;EACA,KAAK,gBAAgB;GACnB,MAAM,SAAS,MAAM;GACrB,MAAM,EAAE,WAAW,eAAe,aAAa,UAAU;GACzD,MAAM,EAAE,WAAW,MAAM,IAAI;GAG7B,QAAQ,GAAiB,MAAc;IACrC,MAAM,KAAK,EAAE,KAAM,OAAO;IAC1B,MAAM,KAAK,EAAE,IAAI,KAAM,OAAO;IAC9B,MAAM,KAAK,EAAE,IAAI,KAAM,OAAO;IAC9B,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,IAAI,IAAI,EAAE,IAAI,aAAa;IAC5D,MAAM,IAAI,aAAa,cAAc,QAAQ,aAAa,QAAQ,CAAC,IAAI;IAEvE,EAAE,IAAA,KAAgB,EAAE,IAAA,MAAkB,KAAK,IAAI,EAAE,IAAA,MAAkB;IACnE,EAAE,IAAA,IAAe,KAAK,EAAE,IAAA,IAAe,MAAO,KAAK,IAAI,EAAE,IAAA,IAAe,MAAO;IAC/E,EAAE,IAAA,IAAe,KAAK,EAAE,IAAA,IAAe,MAAO,KAAK,IAAI,EAAE,IAAA,IAAe,MAAO;GACjF;EACF;EACA,KAAK,iBAAiB;GACpB,MAAM,OAAOA,SAAO,OAAO;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE,CAAC;GAC/C,MAAM,UAAU,IAAI,KAAK,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;GACrD,MAAM,IAAI;IAAE,GAAG,KAAK,IAAI;IAAS,GAAG,KAAK,IAAI;IAAS,GAAG,KAAK,IAAI;GAAQ;GAC1E,MAAM,QAAQ,QAAQ,eAAe;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE,GAAG,KAAK;GAChE,MAAM,EAAE,cAAc,OAAO;GAG7B,QAAQ,GAAiB,MAAc;IACrC,MAAM,IAAI,IAAA;IACV,MAAM,SACH,EAAE,KAAM,IAAI,EAAE,IAAI,MAAM,KAAK,EAAE,KAC/B,EAAE,IAAI,KAAM,IAAI,EAAE,IAAI,MAAM,KAAK,EAAE,KACnC,EAAE,IAAI,KAAM,IAAI,EAAE,IAAI,MAAM,KAAK,EAAE;IACtC,IAAI,QAAQ,GAAG;IAEf,MAAM,KAAK,EAAE,KAAM;IACnB,MAAM,KAAK,EAAE,IAAI,KAAM;IACvB,MAAM,KAAK,EAAE,IAAI,KAAM;IAEvB,IADc,KAAK,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,EAAE,IAC/B,GAAG;IAEf,MAAM,OACH,EAAE,KAAM,KAAK,MAAM,KAAK,EAAE,KAC1B,EAAE,IAAI,KAAM,KAAK,MAAM,KAAK,EAAE,KAC9B,EAAE,IAAI,KAAM,KAAK,MAAM,KAAK,EAAE;IACjC,IAAI,MAAM,GAAG;IAGb,MAAM,IAAI,SAAS,QAAQ;IAC3B,MAAM,QAAQ,EAAE,KAAM,IAAI,EAAE;IAC5B,MAAM,QAAQ,EAAE,IAAI,KAAM,IAAI,EAAE;IAChC,MAAM,QAAQ,EAAE,IAAI,KAAM,IAAI,EAAE;IAEhC,EAAE,KAAK,QAAQ,KAAK,EAAE,KAAM,KAAK;IACjC,EAAE,IAAI,KAAK,QAAQ,KAAK,EAAE,IAAI,KAAM,KAAK;IACzC,EAAE,IAAI,KAAK,QAAQ,KAAK,EAAE,IAAI,KAAM,KAAK;IAIzC,IAAI,EADU,KAAK,MAAM,EAAE,IAAK,EAAE,IAAI,IAAK,EAAE,IAAI,EACvC,IAAI,OAAQ;IAEtB,MAAM,MAAM,KAAK,EAAE,KAAM,EAAE,IAAI,EAAE,IAAI,KAAM,EAAE,IAAI,EAAE,IAAI,KAAM,EAAE;IAC/D,MAAM,KAAK,gBAAgB,EAAE,KAAM,MAAM,EAAE;IAC3C,MAAM,KAAK,gBAAgB,EAAE,IAAI,KAAM,MAAM,EAAE;IAC/C,MAAM,KAAK,gBAAgB,EAAE,IAAI,KAAM,MAAM,EAAE;IAC/C,MAAM,QAAQ,IAAI,KAAK;IAEvB,EAAE,KAAK;IACP,EAAE,IAAI,KAAK;IACX,EAAE,IAAI,KAAK;IACX,EAAE,MAAO,OAAO;IAChB,EAAE,IAAI,MAAO,OAAO;IACpB,EAAE,IAAI,MAAO,OAAO;GACtB;EACF;EACA,KAAK,cAAc;GACjB,MAAM,EAAE,WAAW;GACnB,MAAM,UAAU,KAAK,OAAO,SAAS,MAAM;GAG3C,QAAQ,GAAiB,MAAc;IACrC,MAAM,IAAI,cAAc,OAAO;KAAE,GAAG,EAAE;KAAK,GAAG,EAAE,IAAI;KAAK,GAAG,EAAE,IAAI;IAAI,CAAC;IACvE,MAAM,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;IAE1C,IAAI,IAAI,SAAS;KACf,EAAE,IAAA,KAAW;KACb;IACF;IAIA,IAAI,OAAO;IACX,MAAM,OAAO,UAAU;IACvB,IAAI,EAAE,IAAI,KAAK,IAAI,MAAM,OAAO,KAAK,IAAI,SAAS,UAAU;IAC5D,EAAE,IAAA,MAAY,KAAK,SAAS,EAAE,MAAM,SAAS,WAAW,OAAO;GACjE;EACF;EACA,KAAK,cACH;CACJ;AACF;;AAGA,MAAM,eACJ,MACA,SACG;CACH,KAAK,SAAS,KAAK,OAAO,QAAQ,UAAU,CAAC,MAAM,IAAI;CACvD,IAAI,CAAC,KAAK,OAAO,QAAQ;CAEzB,MAAM,UAAU,aAAa,KAAK,KAAK;CAEvC,KAAK,MAAM,SAAS,KAAK,QAAQ;EAC/B,MAAM,QAAQ,WAAW,OAAO,QAAQ,SAAS,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK;EACnF,IAAI,OAAO,KAAK,KAAK;CACvB;AACF;;AAGA,MAAM,SAAS,EAAE,SAAqB,SAAyB;CAC7D,MAAM,EAAE,SAAS,KAAK;CACtB,IAAI,MAAM,MAAM,KAAK,IAAI,IAAI;CAE7B,IAAI,CAAC,KAAK;EACR,sBAAM,IAAI,IAAI;EACd,MAAM,KAAK,IAAI,MAAM,GAAG;CAC1B;CAEA,IAAI,IAAI,IAAI;CAEZ,IAAI,QAAQ;CACZ,KAAK,MAAM,OAAO,KAAK,SAAS,KAAK,GAAG;CACxC,IAAI,QAAQ,MAAM,MAAM,OAAO;CAE/B,IAAI;CACJ,IAAI,SAAS;CAEb,KAAK,MAAM,OAAO,KAAK;EACrB,MAAM,QAAQ,aAAa,GAAG;EAE9B,IAAI,QAAQ,QAAQ;GAClB,SAAS;GACT,SAAS;EACX;CACF;CAEA,IAAI,QAAQ,MAAM,MAAM;AAC1B;AAEA,MAAM,gBAAgB,EAAE,MAAM,cAAsC;CAClE,IAAI,SAAS,OAAO,QAAQ,EAAE,EAAE,MAAA,OAAiB;CACjD,IAAI,CAAC,MAAM,OAAO;CAElB,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,KAAK;EAC1C,MAAM,IAAI,IAAA;EACV,IAAI,QAAQ,MAAM,CAAC,GAAG,OAAO,KAAK,QAAQ,IAAA;CAC5C;CAEA,OAAO;AACT;AAEA,MAAM,SAAS,SAAyB;CACtC,MAAM,EAAE,MAAM,YAAY;CAE1B,IAAI,SAAS;EACX,MAAM,SAAS,QAAQ,MAAM;EAE7B,IAAI,QAAQ;GACV,QAAQ,OAAO,SAAS,IAAI;GAC5B,IAAI,OAAO,UAAU,QAAQ,OAAO,UAAU,IAAI;EACpD;EAEA;CACF;CAEA,IAAI,CAAC,MAAM;CAEX,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,KAAK;EAC1C,MAAM,IAAI,IAAA;EACV,IAAI,CAAC,QAAQ,MAAM,CAAC,GAAG;EACvB,KAAK,QAAQ,IAAA,KAAY;EACzB,KAAK;EACL,KAAK;EACL;CACF;AACF;AAEA,MAAM,WAAW,KAAgB,WAA2B;CAC1D,KAAK,MAAM,QAAQ,IAAI,KAAK;EAC1B,KAAK,IAAI;EAET,MAAM,KAAK,OAAO,SAAS,QAAQ,IAAI;EACvC,IAAI,MAAM,GAAG,OAAO,SAAS,OAAO,IAAI,CAAC;CAC3C;AACF;AAEA,MAAM,gBACJ,MACA,KACA,KACA,MACA,MACA,WACG;CACH,IAAI,KAAK,QAAQ,KAAK,UAAU,OAAO,IAAI;CAE3C,MAAM,IAAI,KAAK,SAAA;CACf,MAAM,IAAI,KAAK;CAEf,EAAE,KAAK,IAAI,EAAE,CAAE;CACf,EAAE,IAAI,KAAK,IAAI,EAAE,CAAE;CACnB,EAAE,IAAI,KAAK,IAAI,EAAE,CAAE;CACnB,EAAE,IAAA,KAAgB,IAAI,EAAE,CAAE;CAC1B,EAAE,IAAA,IAAe,KAAK,IAAI,EAAE,CAAE;CAC9B,EAAE,IAAA,IAAe,KAAK,IAAI,EAAE,CAAE;CAC9B,EAAE,IAAA,KAAY,KAAK;CACnB,EAAE,IAAA,KAAW;CACb,EAAE,IAAA,KAAY;CACd,EAAE,IAAA,KAAY,KAAK;CACnB,EAAE,IAAA,IAAW,KAAK,KAAK;CACvB,EAAE,IAAA,IAAW,KAAK,KAAK;CACvB,EAAE,IAAA,MAAc;CAChB,KAAK;CACL,KAAK;AACP;;AAGA,MAAM,UAAU,SAAe;CAC7B,MAAM,EAAE,YAAY;CACpB,MAAM,OAAO,KAAK,IAAI,UAAU,KAAK,QAAQ,CAAC;CAC9C,MAAM,OAAO,SAAS,KAAK,WAAW,UAAU,IAAI,aAAa,OAAA,EAAa;CAC9E,IAAI,QAAQ;CAEZ,KAAK,IAAI,OAAO,KAAK,MAAM,OAAO,KAAK,MAAM,QAAQ;EACnD,MAAM,IAAI,OAAA;EACV,IAAI,CAAC,QAAQ,MAAM,CAAC,GAAG;EAEvB,IAAI,SAAS,WAAW,UAAU,MAChC,KAAK,IAAI,QAAQ,SAAS,GAAG,IAAA,EAAU,GAAG,QAAA,EAAc;EAE1D;CACF;CAEA,KAAK,UAAU;CACf,KAAK,WAAW;CAChB,KAAK,OAAO;CACZ,KAAK,OAAO;CACZ,KAAK;AACP;;AAGA,MAAM,YAAY,EAAE,GAAG,GAAG,SACvB,IAAI,MAAM,KAAK,QAAQ,IAAI,KAAK,QAAQ,IAAI,KAAK,OAC9C;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE,IACnB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAEzB,MAAM,UAAmB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;AAG5C,MAAM,aAAa,GAAiB,MAAc;CAChD,IAAI,KAAK,EAAE,IAAA;CACX,IAAI,KAAK,EAAE,IAAA,IAAe;CAC1B,IAAI,KAAK,EAAE,IAAA,IAAe;CAC1B,MAAM,KAAK,EAAE,IAAA;CACb,MAAM,KAAK,EAAE,IAAA,IAAW;CACxB,MAAM,KAAK,EAAE,IAAA,IAAW;CACxB,MAAM,UAAU,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE;CACvD,MAAM,SAAS,UAAU,cAAc,OAAO;CAE9C,IAAI,SAAS,MAAM;EACjB,MAAM;EACN,MAAM;EACN,MAAM;CACR,OAAO,IAAI,KAAK,MAAM,SAAS,IAAI,OAAO,IAAI,OAAO,QAAQ,KAAK,MAAM,MAAM;EAC5E,KAAK;EACL,KAAK,KAAK;CACZ,OAAO;EACL,KAAK,KAAK;EACV,KAAK;CACP;CAGA,MAAM,KAAK,KAAK,KAAK,KAAK;CAC1B,MAAM,KAAK,KAAK,KAAK,KAAK;CAC1B,MAAM,KAAK,KAAK,KAAK,KAAK;CAC1B,MAAM,IAAI,cAAc,KAAK,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;CAEhE,EAAE,IAAA,KAAY,KAAK,KAAK,IAAI,KAAK,KAAK;CACtC,EAAE,IAAA,IAAW,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK;CAC1C,EAAE,IAAA,IAAW,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK;AAC5C;AAEA,IAAa,iBAAb,MAA4B;CAC1B,MAA0B,CAAC;CAC3B;;CAEA,OAAO;;CAEP;CACA;CACA,WAAW;CACX,eAAe;CACf,iBAAiB;CACjB;CAEA,YACE,OACA,EAAE,QAAQ,UAA0D,CAAC,GACrE;EACA,KAAK,UAAU;GAAE,OAAO,SAAS,YAAY;GAAG;GAAQ,QAAQ;GAAG,KAAK;EAAE;EAC1E,KAAK,OAAO,KAAK,OAAO,OAAO,KAAA,CAAS;CAC1C;;;;;CAMA,IAAI,WAAoB;EACtB,OAAO,gBAAgB,KAAK,IAAI;CAClC;;CAGA,OAAa;EACX,QAAQ,KAAK,MAAM,KAAK,GAAG;CAC7B;;;;;;CAOA,UAAgB;EACd,KAAK,MAAM,QAAQ,KAAK,KAAK,KAAK,IAAI;EACtC,KAAK,IAAI,SAAS;CACpB;;;;;CAMA,aACE,OAOM;EACN,MAAM,QAAQ,SAAkB;GAC9B,IAAI,KAAK,MAAM;GAEf,MAAM,EAAE,MAAM,YAAY;GAC1B,MAAM,QAAQ,KAAK,IAAI,MAAM,MAAM,KAAK;GACxC,MAAM,EAAE,UAAU;GAElB,MAAM,SACJ,OACA,GACA,SACA,KACA,SACG;IACH,MAAM,IAAI;KACR,GAAG,MAAM,IAAA;KACT,GAAG,MAAM,IAAA,IAAe;KACxB,GAAG,MAAM,IAAA,IAAe;IAC1B;IACA,MAAM,IAAI;KACR,GAAG,MAAM,IAAA,KAAiB,EAAE,IAAI;KAChC,GAAG,MAAM,IAAA,IAAe,KAAM,EAAE,IAAI;KACpC,GAAG,MAAM,IAAA,IAAe,KAAM,EAAE,IAAI;IACtC;IAEA,MACE,OACA,KACA,MACA,QAAQ,eAAe,GAAG,KAAK,GAC/B,QAAQ,mBAAmB,GAAG,KAAK,CACrC;GACF;GAEA,IAAI,MACF,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,KAAK;IAC1C,MAAM,IAAI,IAAA;IACV,IAAI,CAAC,QAAQ,MAAM,CAAC,GAAG;IAEvB,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ,IAAA;IAE1C,MAAM,KAAK,SAAS,GAAG,SAAS,KAAK,QAAQ,IAAA,KAAY,SAAS,KAAK,QAAQ,IAAA,EAAU;GAC3F;GAGF,IAAI,SACG;SAAA,MAAM,EAAE,WAAW,SACtB,IAAI,MAAA,MAAe,MAAA,IAAc,MAAM,OAAO,GAAG,GAAG,MAAA,IAAa,MAAA,EAAY;GAAA;GAEjF,KAAK,MAAM,SAAS,KAAK,UAAU,KAAK,KAAK;EAC/C;EACA,KAAK,MAAM,QAAQ,KAAK,KAAK,KAAK,IAAI;CACxC;;CAGA,QACE,IACA,EAAE,QAAQ,KAAK,WAAW,UAAU,SAAS,SAAyB,CAAC,GACjE;EACN,MAAM,EAAE,SAAS,QAAQ;EACzB,IAAI,WAAW,KAAA,GAAW,QAAQ,SAAS;EAC3C,IAAI,QAAQ,KAAA,GAAW,QAAQ,MAAM;EACrC,KAAK,QAAQ;EACb,KAAK,eAAe,KAAK;EACzB,KAAK,OAAO;EACZ,KAAK,WAAW;EAEhB,IAAI,QAAQ,KAAK,cAAc;GAE7B,MAAM,OAAO,aAAa,IAAI,CAAC,CAAC;GAChC,MAAM,OAAO,aAAa,KAAK,YAAY,CAAC,CAAC;GAE7C,KAAK,iBAAiB,KAAK;GAC3B,KAAK,eAAe,KAAK,MAAM,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,CAAC;EAClF;EAEA,IAAI,WAAW;GACb,MAAM,EAAE,SAAS,KAAK;GACtB,MAAM,MAAM,YAAY,UAAU,WAAW;GAE7C,IAAI,MAAM,KAAK,OAAO;QACjB,KAAK,MAAM,QAAQ,KAAK,KAAK,KAAK,KAAK,OAAO;EACrD;EAEA,KAAK,MAAM,QAAQ,IAAI,MAAM,GAAG,KAAK,SAAS,MAAM,QAAQ,QAAQ;EACpE,KAAK,MAAM,QAAQ,IAAI,MAAM,GAAG,KAAK,MAAM,MAAM,IAAI,GAAG;CAC1D;CAEA,SAAS,MAAe,QAAuB;EAC7C,IAAI,KAAK,MAAM;EAEf,MAAM,EAAE,WAAW,KAAK;EACxB,MAAM,EAAE,eAAe;EACvB,IAAI,YAAY,SAAS,uBAAuB,KAAK,aAAa,IAAsB;EAExF,IAAI,KAAK,QAAQ;GAEf,KAAK,QAAQ,KAAK;GAClB,KAAK,SAAS,KAAA;EAChB,OAAO;GACL,MAAM,QAAQ,YAAY,YAAY,WAAW,QAAQ,KAAK,GAAG;GACjE,MAAM,SAAS,KAAK,WAAW,QAAQ,SAAS,QAAQ,KAAK,QAAQ,IAAI;GAEzE,KAAK,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,KAAK,IAAI;EACzD;EAEA,KAAK,MAAM,SAAS,KAAK,SAAS,MAAM,GAAG,KAAK,SAAS,OAAO,KAAK,KAAK;CAC5E;;CAGA,MAAM,MAAe,IAAY,KAAsB;EACrD,IAAI,KAAK,MAAM;EAEf,IAAI,KAAK,OAAO,EAAE,GAAG;GACnB,KAAK,IAAI;GACT,OAAO,MAAM,GAAG;GAChB;EACF;EAEA,KAAK,MAAM,SAAS,KAAK,SAAS,MAAM,GAAG,KAAK,MAAM,OAAO,IAAI,GAAG;CACtE;;CAGA,OAAO,OAAoB,QAA+C;EACxE,MAAM,MAAiB;GAAE,SAAS,KAAK;GAAS;GAAO,OAAO,CAAC;GAAG,KAAK,CAAC;EAAE;EAE1E,MAAM,MAAM,SAAS,OAAO,UAAU;GACpC,MAAM,OAAgB;IACpB;IACA;IACA,KAAK,MAAM;IACX,YAAY,MAAM;IAClB,QAAQ,KAAA;IACR,UAAU,CAAC;IACX,KAAK;IAEL,UAAU,MAAM,YAAY,YAAY;IACxC,MAAM;IACN,OAAO,QAAQ;IACf,cAAc;GAChB;GAEA,IAAI,MAAM,KAAK,IAAI;EACrB,CAAC;EAGD,MAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,GAAG,MAAM,MAAM,KAAK,CAAC,CAAC,CAAC,QAAQ,GAAG,GAAG,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC;EAE1F,KAAK,MAAM,SAAS,OAAO;GAEzB,IADc,MAAM,MAAM,MACjB,CAAC,YAAY,aAAa,UAAU;GAE7C,MAAM,WAAW,OACf,MAAM,MAAM,GAAG,CAAE,SAAS,QACvB,MAAM,UAAU,KAAK,IAAI,MAAM,IAAI,MAAM,MAAM,CAAE,UAAU,QAAQ,KAAK,CAAC,GAC1E,CACF;GAEF,IAAI,MAAM,MAAM,CAAE,WAAW,QAAQ,KAAK;EAC5C;EAEA,MAAM,MAAM,SAAS,OAAO,UAAU;GACpC,MAAM,OAAO,IAAI,MAAM;GAEvB,KAAK,SAAS,MAAM,UAAU,IAAI,IAAI,MAAM,MAAM,UAAU;GAC5D,KAAK,QAAQ,IAAI;EACnB,CAAC;EACD,KAAK,MAAM,QAAQ,IAAI,OAAO,YAAY,KAAK,QAAQ,KAAK,KAAK,IAAI;EACrE,IAAI,MAAM,MAAM,IAAI,KAAK,UAAU,IAAI,MAAM,MAAO;EACpD,IAAI,MAAM,SAAS,KAAA,GAAW,IAAI,OAAO,IAAI,MAAM,MAAM;EACzD,MAAM,MAAM,SAAS,OAAO,UAAU;GACpC,MAAM,OAAO,IAAI,MAAM;GAEvB,KAAK,MAAM,UAAU,MAAM,SAAS;IAClC,MAAM,QAAQ,IAAI,MAAM;IAExB,IAAI,KAAK,YAAY,aAAa,WAAW,KAAK,WAAW,MAAM,KAAK;SACnE,IACH,KAAK,YAAY,aAAa,gBAC9B,MAAM,YAAY,aAAa,SAE/B,KAAyB,OAAO,KAAK,KAAkB;GAC3D;EACF,CAAC;EACD,OAAO;CACT;;CAGA,WAAW,MAAe,OAAsB;EAC9C,MAAM,UAAU;EAEhB,IAAI,MAAM,YAAY,aAAa,cAAc;GAC/C,QAAQ,SAAS,KAAA;GACjB;EACF;EAEA,QAAQ,SAAS;EACjB,QAAQ,QAAQ;EAChB,QAAQ,OAAO;CACjB;CAEA,QAAQ,MAAqB;EAC3B,MAAM,EAAE,eAAe;EAEvB,QAAQ,YAAY,UAApB;GACE,KAAK,WACH,OAAO,KAAK,eAAe,MAAqB,UAAU;GAC5D,KAAK,cACH,OAAO,KAAK,kBAAkB,MAAwB,UAAU;GAClE,KAAK,SACH,OAAO,KAAK,aAAa,MAAmB,UAAU;GACxD,SACE,KAAK,UAAU,OAAO;IACpB,KAAK,OAAO;IACZ,OAAO,KAAK,MAAM,KAAK;GACzB;EACJ;CACF;CAEA,aAAa,MAAiB,YAAyB;EACrD,KAAK,QAAQ,EAAE,MAAM,aAAa;EAElC,MAAM,EAAE,YAAY;EACpB,MAAM,WAAW,UAAkB,OAAe,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC;EAE/E,KAAK,UAAU,OAAO;GACpB,KAAK,OAAO;GAEZ,MAAM,MAAM,GAA8B,aACxC,MAAM,GAAG,QAAQ,QAAQ,KAAK,KAAK,QAAQ;GAE7C,QAAQ,WAAW,MAAnB;IACE,KAAK;KACH,KAAK,QAAQ;MAAE,MAAM,WAAW;MAAM,QAAQ,GAAG,WAAW,SAAS,GAAG,IAAI;KAAG;KAC/E;IACF,KAAK;KACH,KAAK,QAAQ;MACX,MAAM,WAAW;MACjB,WAAW,GAAG,WAAW,WAAW,CAAC;MACrC,OAAO,QAAQ,GAAG,WAAW,UAAU,CAAC,GAAG,EAAE;KAC/C;KACA;IACF,KAAK;KACH,KAAK,QAAQ;MACX,MAAM,WAAW;MACjB,WAAW,GAAG,WAAW,WAAW,EAAE;MACtC,OAAO,QAAQ,GAAG,WAAW,UAAU,CAAC,GAAG,EAAE;KAC/C;KACA;IACF,KAAK;KACH,KAAK,QAAQ;MACX,MAAM,WAAW;MACjB,WAAW,GAAG,WAAW,WAAW,EAAE;MACtC,eAAe,IAAI,KAAK,IAAI,GAAG,WAAW,QAAQ,EAAE,GAAG,IAAK;MAC5D,aAAa,WAAW;MACxB,OAAO,QAAQ,GAAG,WAAW,UAAU,EAAG,GAAG,EAAE;KACjD;KACA;IACF,KAAK;KACH,KAAK,QAAQ;MACX,MAAM,WAAW;MACjB,cAAc,GAAG,WAAW,cAAc,EAAG;MAC7C;KACF;KACA;IACF,KAAK,cACH,KAAK,QAAQ;KAAE,MAAM,WAAW;KAAM,QAAQ,GAAG,WAAW,WAAW,IAAI;IAAE;GAIjF;GAEA,OAAO,KAAK,MAAM,KAAK;EACzB;CACF;CAEA,kBAAkB,MAAsB,YAA8B;EACpE,KAAK,OAAO;EACZ,KAAK,SAAS,CAAC;EACf,KAAK,aAAa;GAChB,KAAK,QAAQ,MAAM,KAAK,IAAI,WAAW,IAAI,CAAC,EAAE,OAAO,IAAI;EAC3D;EAEA,IAAI,WAAW,SAAS,uBAAuB;GAC7C,KAAK,UAAU,CAAC;GAChB,KAAK,UAAU,OAAO,KAAK,eAAe,MAAM,YAAY,EAAE;GAC9D;EACF;EAIA,MAAM,UAFQ,KAAK,IAAI,MAAM,MAAM,KAAK,MAEnB,CAAC,QAAQ,MAAM,WAAW;GAC7C,MAAM,SAAS,KAAK,IAAI,MAAM,MAAM,OAAO,CAAE;GAE7C,OAAO,QAAQ,aAAa,WAAW,OAAO,SAAS;EACzD,CAAC;EAED,MAAM,OAAO,WAAW,OAAO;EAE/B,KAAK,OAAO;EAEZ,MAAM,OAAO,WAAW,SAAS;EAEjC,KAAK,UAAU,OAAO;GACpB,KAAK,OAAO;GAEZ,MAAM,QAAQ,KAAK,SAAS,KAAK,KAAK,UAAU;GAEhD,IAAI,KAAK,SAAS,KAAK,UAAU,MAAM,MAAM,IAAI,IAAI;QAChD;IACH,KAAK,SAAS;IACd,OAAO,IAAI;IAEX,IAAI,QAAQ;IACZ,MAAM,EAAE,SAAS;IACjB,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,MAAM,KAAK,IAAI,QAAQ,MAAM,IAAA,EAAU,GAAG;IACtE,KAAK,QAAQ;IACb,OAAO,KAAK,OAAO,QAAQ,CAAC,QAAQ,MAAM,KAAK,OAAA,EAAa,GAAG,KAAK;GACtE;GAGA,OAAO;EACT;CACF;;CAGA,UAAU,MAAsB,MAAY,IAAY,MAAqB;EAC3E,MAAM,EAAE,YAAY;EAEpB,YAAY,OAAO,UAAU;GAC3B,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,MAAM,KAAK,MAAM,SAAS,IAAA,EAAU;EAC/D,CAAC;EAGD,IAAI,QAAQ;EAEZ,KAAK,IAAI,OAAO,GAAG,OAAO,KAAK,MAAM,QAAQ;GAC3C,MAAM,IAAI,OAAA;GACV,MAAM,MAAM,QAAQ,IAAA,KAAY;GAChC,IAAI,MAAM,QAAQ,IAAA,IAAY;GAE9B,MAAM,IAAI,QAAA;GACV,IAAI,MAAM,GAAG,QAAQ,WAAW,GAAG,GAAG,IAAA,EAAU;GAChD,QAAQ,IAAA,KAAW;GACnB,QAAQ,KAAK,QAAQ,KAAM,QAAQ,IAAA,KAAiB;GACpD,QAAQ,IAAI,KAAK,QAAQ,IAAI,KAAM,QAAQ,IAAA,IAAe,KAAM;GAChE,QAAQ,IAAI,KAAK,QAAQ,IAAI,KAAM,QAAQ,IAAA,IAAe,KAAM;GAChE,IAAI,MAAM,UAAU,SAAS,CAAC;GAC9B;EACF;EAEA,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,QAAQ,IAAA,KAAA,KAAqB,KAAK;EAClE,KAAK;CACP;CAEA,eAAe,MAAsB,YAAgC,IAAqB;EACxF,KAAK,OAAO;EAEZ,MAAM,UAAU,KAAK;EACrB,MAAM,QAAQ,KAAK,SAAS,KAAK,QAAQ,WAAW;EAEpD,YAAY,OAAO,UAAU;GAC3B,KAAK,MAAM,EAAE,WAAW,SAAS,IAAI,MAAA,KAAc,MAAA,IAAc,MAAM,OAAO,CAAC;EACjF,CAAC;EAED,IAAI,QAAQ;EAEZ,KAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,EAAE,UAAU;GAElB,IAAI,MAAA,MAAe,MAAA,IAAc;IAC/B,MAAA,MAAe;IAEf,IAAI,EAAE,MAAA,KAAc,MAAA,KAAe,KAAK,WAAW,YAAY,QAAQ,EAAE;SACpE,IAAI,CAAC,YAAY,OAAO,OAAO,GAAG,QAAQ,OAAO,SAAS,KAAK,QAAQ;IAE5E,QAAQ,WAAW;IACnB;GACF;GAEA,IACE,CAAC,YAAY,OAAO,OAAO,KAC1B,OAAO,aAAa,KAAA,KAAa,CAAC,YAAY,OAAO,QAAQ,GAC9D;IACA,QAAQ,WAAW;IACnB;GACF;GAEA,QAAQ,OAAO,SAAS,IAAI;GAC5B,IAAI,OAAO,UAAU,QAAQ,OAAO,UAAU,IAAI;EACpD;EAEA,QAAQ,SAAS;EACjB,OAAO;CACT;;CAGA,WAAW,YAAgC,QAAwB,IAAkB;EACnF,MAAM,EAAE,UAAU;EAElB,MAAM,MAAO,MAAA,KAAmB;EAChC,MAAM,MAAO,MAAM,KAAiB;EACpC,MAAM,MAAO,MAAM,KAAiB;EAEpC,MAAM,WAAW;GAAE,GAAG,MAAM;GAAK,GAAG,MAAM;GAAK,GAAG,MAAM;EAAI;EAC5D,IAAI,SAAS,QAAQ,YAAY,QAAQ;EAEzC,IAAI,WAAW,oBAAoB;GACjC,MAAM,WAAW;IAAE,GAAG,MAAA;IAAkB,GAAG,MAAM;IAAgB,GAAG,MAAM;GAAe;GACzF,IAAI,OAAOC,SAAO,QAAQ;GAE1B,IAAI,WAAW,gBAAgB;IAC7B,MAAM,QAAQ,KAAK,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC3D,IAAI,QAAQ,QAAQ;IAEpB,IAAI,EAAE,SAAS,KAAM;KACnB,OAAO,KAAK;KACZ,QAAQ,KAAK;IACf;IAEA,OAAO,QAAQ,KAAK,MAAM,OAAO,OAAO,MAAM,KAAK,IAAI,OAAO,CAAC,CAAC;IAChE,OAAO,OAAO;GAChB;GAEA,SAAS,QAAQ,wBAAwB,QAAQ,eAAe,IAAI,GAAG,QAAQ;EACjF;EAEA,KAAK,OAAO,OAAO,SAAS,MAAM;CACpC;CAEA,OAAO,KAAgB,QAAuB;EAC5C,IAAI,IAAI,MAAM,IAAI,KAAK,WAAW;OAC7B,KAAK,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW;CACnD;;CAGA,aAAa,MAA4B;EACvC,MAAM,aAAa,KAAK;EACxB,IAAI,CAAC,WAAW,WAAW;EAE3B,KAAK,MAAM,UAAU,KAAK,SAAU;GAClC,MAAM,EAAE,UAAU;GAClB,IAAI,OAAO,YAAY,EAAE,MAAA,KAAc,MAAA,KAAe;GAEtD,MAAM,QAAQ,KAAK,QAAQ,SAAS,WAAW,SAAS;GACxD,IAAI,CAAC,OAAO;GACZ,OAAO,WAAW,KAAK,OAAO,OAAO,IAAI;GACzC,KAAK,OACH,OAAO,UACP,QAAQ,YAAY;IAAE,GAAG,MAAM;IAAK,GAAG,MAAM;IAAK,GAAG,MAAM;GAAI,CAAC,CAClE;EACF;CACF;;CAGA,OACE,MACA,UACA,UACA,KACA,MACM;EACN,MAAM,EAAE,eAAe;EACvB,MAAM,EAAE,YAAY;EAEpB,MAAM,SAAS,IAAI;EAEnB,MAAM,SAAS,QAAQ,MAAM;EAE7B,IAAI,WAAW,SAAS,uBAAuB;GAE7C,MAAM,QAAQ,WAAW,WAAW,QAAQ,SAAS,WAAW,QAAQ,IAAI,KAAA;GAC5E,IAAI,CAAC,OAAO;GAEZ,MAAM,wBAAQ,IAAI,aAAA,EAAmB;GAErC,MAAM,IAAI;IAAC,SAAS;IAAG,SAAS;IAAG,SAAS;IAAG,SAAS;IAAG,SAAS;IAAG,SAAS;GAAC,CAAC;GAClF,MAAA,KAAa;GACb,MAAA,KAAc;GACd,MAAA,MAAgB;GAGhB,MAAM,SAAyB;IAAE;IAAO,SADxB,KAAK,OAAO,OAAO,IACW;IAAG,OAAO,KAAK;GAAS;GAEtE,KAAK,QAAS,KAAK,MAAM;GACzB,KAAK,WAAW,YAAY,QAAQ,CAAC;GACrC;EACF;EAEA,MAAM,OAAO,WAAW,SAAS,oBAAoB,SAAS,QAAQ,IAAI;EAE1E,aAAa,KAAK,MAAO,CAAC,UAAU,QAAQ,GAAG,KAAK,MAAM,MAAM,MAAM;CACxE;CAEA,eAAe,MAAmB,YAA2B;EAC3D,KAAK,QAAQ;EACb,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,WAAW;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EACnC,KAAK,aAAa;GAChB,IAAI,KAAK,QAAQ,KAAK,OAAO;EAC/B;EAEA,MAAM,EAAE,YAAY;EACpB,MAAM,OAAO,KAAK,SAAS,MAAM,UAAU;EAG3C,KAAK,UAAU,OAAO;GACpB,KAAK,OAAO;GAEZ,MAAM,UAAU,KAAK,MAAM,KAAK;GAChC,MAAM,SAAS,KAAK;GACpB,IAAI,CAAC,QAAQ,OAAO;GAEpB,IAAI,OAAO,MAAM;IACf,KAAK,SAAS,KAAA;IACd,OAAO;GACT;GAEA,KAAK,QAAQ,QAAQ,QAAQ,KAAK,GAAG;GACrC,OAAO;EACT;CACF;CAEA,SAAS,MAAmB,YAAqB;EAC/C,MAAM,EAAE,YAAY;EAEpB,QAAQ,QAAwB,QAAgB,MAAc;GAC5D,MAAM,MAAM,GAA8B,aAAqB,MAAM,GAAG,QAAQ,GAAG,QAAQ;GAC3F,MAAM,WAAW,GAAG,WAAW,UAAU,EAAE;GAC3C,MAAM,WAAW,GAAG,WAAW,cAAc,CAAC;GAC9C,MAAM,YAAY,GAAG,WAAW,WAAW,GAAG;GAC9C,MAAM,UAAU,IAAI,KAAK;GACzB,IAAI,QAAQ,KAAK,MAAM,UAAU,SAAS;GAC1C,MAAM,OAAO,KAAK,MAAM;GAExB,IAAI,KAAK,OAAO;IACd,KAAK,QAAQ;IACb,SAAS,KAAK,MAAM,WAAW,gBAAgB;IAC/C,KAAK,WAAW;KAAE,GAAG,KAAK;KAAG,GAAG,KAAK;KAAG,GAAG,KAAK;IAAE;GACpD;GAEA,KAAK,MAAM,EAAE,KAAK,WAAW,WAAW,WAAW,UAAU,EAAE,EAAE,aAAa,CAAC,GAAG;IAChF,IAAI,MAAM,KAAK,MAAM;IACrB,IAAI,MAAM,GAAG;IACb,QAAQ,KAAK,MAAM,QAAQ,MAAM,CAAC;GACpC;GAGA,MAAM,OADM,WAAW,WAAW,QAAQ,WAAW,UAAU,QAAQ,QAAQ,GAAG,IAAI,KACpE,QAAQ,KAAK;GAC/B,MAAM,QAAQ,KAAK,MAAM,GAAG;GAE5B,KAAK,QAAQ,MAAM;GAEnB,IAAI,CAAC,OAAO;IACV,IAAI,CAAC,WAAW,KAAK,OAAO;IAC5B;GACF;GAEA,MAAM,OAAO,cAAc,KAAK,OAAO,KAAK,QAAQ;GAEpD,KAAK,WAAW;IAAE,GAAG,KAAK;IAAG,GAAG,KAAK;IAAG,GAAG,KAAK;GAAE;GAGlD,MAAM,QAAQ,UAAU,IAAI,CAAC,GAAG,WAAW,kBAAkB,CAAC,IAAI,UAAU;GAC5E,MAAM,OAAO;IAAE,GAAG,KAAK,IAAI;IAAO,GAAG,KAAK,IAAI;IAAO,GAAG,KAAK,IAAI;GAAM;GAEvE,IAAI,OAAO,WAAW,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI;GAE9D,MAAM,OAAO,GAAG,WAAW,cAAc,GAAK,IAAI,KAAK,MAAM;GAC7D,IAAI,SAAS,OAAO,QAAQ,KAAK,MAAM,IAAI,IAAI;GAE/C,IAAI,EAAE,WAAW,IAAI,SAAS;GAE9B,MAAM,QAAQ,QAAQ,SAAS,aAAa,OAAO,KAAK,GAAG,KAAK,KAAK;GAIrE,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,KAAK;IAChC,MAAM,OAAO,IAAI,IAAI;IACrB,MAAM,MAAM,UAAU;IACtB,MAAM,EAAE,OAAO,cAAc,KAAK,OAAO,YAAY,QAAQ,CAAC;IAC9D,MAAM,KAAK,UAAU,IAAI;IACzB,MAAM,KAAK,UAAU,IAAI;IACzB,MAAM,KAAK,UAAU,IAAI;IACzB,MAAM,WAAW,QAAQ,eACvB;KACE,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI;KACjC,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI;KACjC,GAAG,MAAM,IAAI,KAAK,MAAM,KAAK,IAAI;IACnC,GACA,KACF;IACA,MAAM,WAAWD,SAAO,OAAO;KAAE,GAAG,KAAK,KAAK;KAAG,GAAG,KAAK,KAAK;KAAG,GAAG,KAAK,KAAK;IAAE,CAAC;IAEjF,KAAK,OAAO,QAAQ,UAAU,UAAU,KAAK,QAAQ;GACvD;GAEA,KAAK,OAAO;EACd;CACF;;CAGA,QAAQ,KAAa,KAAsB;EACzC,MAAM,EAAE,UAAU,KAAK;EACvB,MAAM,MAAM,OAAO,KAAK,IAAI,IAAI,KAAK;EACrC,MAAM,SAAS,MAAM,OAAO,KAAK,KAAK,MAAM,SAAS,KAAK,KAAK;EAC/D,MAAM,MAAM,KAAK,IAAI,KAAK;EAE1B,OAAO;GAAE,GAAG,KAAK,IAAI,GAAG,IAAI;GAAK,GAAG,KAAK,IAAI,KAAK;GAAG,GAAG,CAAC,KAAK,IAAI,GAAG,IAAI;EAAI;CAC/E;;CAGA,OAAO,YAAqB,QAAgB,GAAW;EACrD,MAAM,EAAE,UAAU,KAAK;EACvB,MAAM,MAAM,GAA8B,aAAqB,MAAM,GAAG,QAAQ,GAAG,QAAQ;EAE3F,QAAQ,WAAW,MAAnB;GAEE,KAAK,gBAAgB;IACnB,MAAM,YAAY,KAAK,QAAQ,GAAG,WAAW,WAAW,CAAC,GAAG,GAAG,WAAW,WAAW,EAAE,CAAC;IACxF,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI,MAAO,GAAG,WAAW,QAAQ,CAAC;IAI7D,OAAO;KAAE,OAAO;MAAE,GAHR,KAAK,OAAO,KAAK,IAAI,MAAO,GAAG,WAAW,OAAO,CAAC;MAGvC;MAAG,GAFd,KAAK,OAAO,KAAK,IAAI,MAAO,GAAG,WAAW,OAAO,CAAC;KAElC;KAAG;IAAU;GACzC;GAEA,KAAK,kBAAkB;IACrB,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI;IAC/B,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI;IAC/B,MAAM,IAAI,KAAK,OAAO,KAAK,IAAI;IAC/B,MAAM,IAAI,cAAc,KAAK,OAAO,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;IAC1D,MAAM,YAAY;KAAE,GAAG,IAAI;KAAG,GAAG,IAAI;KAAG,GAAG,IAAI;IAAE;IACjD,MAAM,MAAM,GAAG,WAAW,WAAW,CAAC;IACtC,MAAM,SAAS,MAAM,OAAO,KAAK,KAAK,GAAG,WAAW,WAAW,CAAC,IAAI;IAEpE,OAAO;KACL,OAAO;MAAE,GAAG,UAAU,IAAI;MAAQ,GAAG,UAAU,IAAI;MAAQ,GAAG,UAAU,IAAI;KAAO;KACnF;IACF;GACF;GAEA,KAAK,gBAAgB;IACnB,MAAM,YAAY,KAAK,QAAQ,GAAG,WAAW,WAAW,CAAC,GAAG,GAAG,WAAW,WAAW,CAAC,CAAC;IACvF,MAAM,MAAM,GAAG,WAAW,WAAW,CAAC;IACtC,MAAM,SAAS,MAAM,OAAO,KAAK,KAAK,GAAG,WAAW,WAAW,CAAC,IAAI;IAEpE,OAAO;KACL,OAAO;MAAE,GAAG,UAAU,IAAI;MAAQ,GAAG,UAAU,IAAI;MAAQ,GAAG,UAAU,IAAI;KAAO;KACnF;IACF;GACF;EACF;CACF;AACF;AC9uCA,MAAME,SAAgB;CAAE,GAAG;CAAK,GAAG;CAAK,GAAG;AAAI;AAE/C,MAAM,OAAe;CAAE,IAAI;CAAG,IAAI;CAAG,IAAI;CAAG,IAAI;AAAE;AAElD,MAAM,UAAU,MAAc,EAAE,OAAO,aAA6B;CAClE,IAAI,QAAQ,KAAK,KAAK,KAAK;CAC3B,IAAI,QAAQ,KAAK,KAAK,KAAK;CAC3B,IAAI,QAAQ,KAAK,KAAK,KAAK;CAC3B,IAAI,QAAQ,KAAK,KAAK,KAAK;AAC7B;;;;;;;AAQA,MAAM,iBACJ,YACA,MACA,QACA,SACA,aACA,aAMG;CACH,MAAM,OAAO,WAAW;CACxB,MAAM,QAAQ,EAAE,QAAQ,CAAC,OAAO,MAAM,UAAU,CAAC,EAAE;CACnD,IAAI,CAAC,MAAM,OAAO;CAElB,MAAM,QAAQ,QAAQ,IAAI;CAE1B,IAAI,CAAC,OAAO;EACV,YAAY,IAAI,WAAW,MAAM;EACjC,OAAO;CACT;CAEA,IAAI,MAAM,SAAS,QAAQ,OAAO;CAClC,IAAI,MAAM,SAAS,YAAY,OAAO;EAAE,GAAG;EAAO,SAAS;GAAE;GAAM;EAAM;CAAE;CAC3E,IAAI,CAAC,MAAM,OAAO,QAAQ,OAAO;CAEjC,MAAM,QAAQ,MAAM,OAAO;CAC3B,MAAM,UACJ,YAAY,CAAC,WAAW,oBAAoB,cAAc,OAAO,KAAK,KAAK,OAAO,IAAI;CAExF,MAAM,MAAM,UAAkB;EAC5B,MAAM,QAAQ,WAAW,OAAO,OAAO,OAAO;EAC9C,IAAI,CAAC,OAAO,YAAY,IAAI,WAAW,MAAM,MAAM;EACnD,OAAO;CACT;CAEA,IAAI,WAAW,mBAAmB;EAChC,MAAM,WAAW,WAAW,iBACxB,QAAQ,WAAW,gBAAgB,QAAQ,KAAK,GAAG,IACnD;EACJ,MAAM,QAAQ,UAAU,IAAI,IAAI,UAAU,KAAK,MAAM,YAAY,QAAQ,EAAE,GAAG,OAAO,OAAO;EAE5F,OAAO;GAAE,SAAS,GAAG,KAAK;GAAG,QAAQ,CAAC,OAAO,MAAM,OAAO,QAAS,UAAU,CAAC;EAAE;CAClF;CAEA,OAAO;EACL,SAAS,GAAG,OAAO;EACnB,QAAQ,MAAM,OAAO,KAAK,UAAU,OAAO,OAAO,UAAU,CAAC;EAC7D;CACF;AACF;;AAGA,MAAa,aAAa,OAAe,OAAe,YACtD,UAAU,KAAK,UAAU,QAAQ,KAAK,SAAS,QAAQ,QAAQ,IAAI;AAErE,MAAM,WAAW,eAAoD;CACnE,QAAQ,WAAW,MAAnB;EACE,KAAK,oBACH,OAAO;GACL,MAAA;GACA,OAAO,WAAW;GAClB,OAAO,WAAW;GAClB,GAAG,WAAW;GACd,GAAG,WAAW;GACd,MAAM,WAAW;GACjB,OAAO,WAAW;EACpB;EACF,KAAK,mBACH,OAAO;GACL,MAAA;GACA,OAAO,WAAW;GAClB,OAAO,WAAW;GAClB,GAAG,WAAW;GACd,OAAO,WAAW;EACpB;EACF,KAAK,mBACH,OAAO;GACL,MAAA;GACA,OAAO,WAAW;GAClB,OAAO,WAAW;GAClB,GAAG,WAAW;GACd,GAAG,WAAW;GACd,GAAG,WAAW;GACd,OAAO,WAAW;EACpB;EACF,KAAK,mBACH,OAAO;GACL,MAAA;GACA,OAAO,WAAW;GAClB,OAAO,WAAW;GAClB,GAAG,WAAW;EAChB;EACF,KAAK,uBACH,OAAO;GACL,MAAA;GACA,OAAO,WAAW;GAClB,OAAO,WAAW;GAClB,GAAG,WAAW;GACd,GAAG,WAAW;GACd,GAAG,WAAW;GACd,OAAO,WAAW;EACpB;EACF,SACE;CACJ;AACF;;AAGA,MAAa,YAAY,QAAgB,UAAkB,SAAyB;CAClF,MAAM,QAAQ,SAAS;CACvB,IAAI,OACF,QAAQ,MAAM,KAAK,IAAI,QAAQ,QAAQ,IAAI,QAAQ,OAAO,MAAM,QAAQ,OAAO,SAAS,IAAI;CAE9F,MAAM,OAAO,KAAK,IAAI,WAAW,MAAM;CACvC,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,KAAK,OAAO,MAAM,MAAM;CAClE,OAAO;AACT;AAEA,MAAM,SAAS;;AAGf,MAAM,UAAU,OAAe,KAAK,MAAM,IAAI,GAAG,IAAI,OAAQ;;;;;AAkB7D,MAAM,gBACJ,MACA,YACA,UACA,MACA,SAC0D;CAC1D,MAAM,OAAO,KAAK;CAClB,MAAM,EAAE,QAAQ,QAAQ,SAAS;CACjC,MAAM,SAAS,WAAW,WAAW,QAAQ,WAAW,UAAU,QAAQ,GAAG,IAAI;CACjF,MAAM,OAAiB,CAAC;CAExB,KAAK,IAAI,IAAI,KAAK,OAAO,GAAG,KAAK,KAAK,MAAM,KAAK;EAC/C,MAAM,IAAI,IAAA;EAEV,IADY,KAAK,QAAQ,IAAA,MAAa,KAAK,QAAQ,KAAK,QAAQ,IAAA,OACrD,KAAK,QAAQ,IAAA,IAAY,KAAK,KAAK,CAAC;CACjD;CAEA,IAAI,CAAC,KAAK,QAAQ,OAAO,KAAA;CAGzB,MAAM,YAAY,MAAuB;EACvC,MAAM,IAAI,KAAK,KAAA;EACf,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ,IAAA;EAE1C,OAAO;GACL,GAAG,KAAK,QAAQ,IAAA,KAAiB,KAAK,QAAQ,IAAI,KAAM;GACxD,GAAG,KAAK,QAAQ,IAAA,IAAe,KAAM,KAAK,QAAQ,IAAI,KAAM;GAC5D,GAAG,KAAK,QAAQ,IAAA,IAAe,KAAM,KAAK,QAAQ,IAAI,KAAM;EAC9D;CACF;CAEA,MAAM,SAAS,MAAc;EAC3B,MAAM,IAAI,KAAK,KAAA;EAEf,OAAO,KAAK,QAAQ,IAAA,MAAa,KAAK,QAAQ,KAAK,QAAQ,IAAA;CAC7D;CAEA,MAAM,SAAS,MAAc;EAC3B,MAAM,OAAO,KAAK,QAAQ,KAAK,KAAA,KAAA;EAE/B,OAAO,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC,IAAI,IAAI,CAAC,IAAI;CAChE;CAEA,MAAM,SAAsB,CAAC;CAC7B,MAAM,SAAS,KAAK,SAAS;CAE7B,MAAM,QAAQ,GAAW,EAAE,GAAG,GAAG,QAAiB;EAChD,MAAM,MAAM,MAAM,CAAC;EACnB,MAAM,SACH,WAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ,GAAG,IAAI,MAC5D,WAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ,GAAG,IAAI,KAC7D;EACF,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,WAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ,GAAG,IAAIA;EACzF,MAAM,IAAI,WAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ,GAAG,IAAI;EAEtE,OAAO,KAAK;GACV;GACA;GACA;GACA,MAAM,QAAQ;GACd;GACA;GACA;GACA,GAAG,OAAO,CAAC;GACX,WAAW,OAAO,SAAS,OAAO;EACpC,CAAC;CACH;CAEA,MAAM,QAAQ,GAAY,OACvB,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK;CAG5D,IAAI;CACJ,MAAM,UAAU,aAAa,KAAK,KAAK;CAEvC,KAAK,MAAM,SAAS,KAAK,QACvB,IAAI,CAAC,MAAM,QAAQ,MAAM,YAAY,SAAS,cAAc;EAC1D,SAAS,QAAQ,eAAe,MAAM,MAAM,GAAG,OAAO;EACtD;CACF;CAEF,IAAI;CAEJ,IAAI,UAAU,CAAC,KAAK,QAAQ,SAAS,CAAC,CAAC,GAAG,OAAO;MAC5C,IAAI,KAAK,SAAS,GAAG,OAAO,KAAA;MAC5B,IAAI,CAAC,WAAW,oBAAoB;EAEvC,MAAM,KAAK,SAAS,CAAC;EACrB,MAAM,KAAK,SAAS,CAAC;EACrB,MAAM,IAAI,MAAM,CAAC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC;EAExC,IAAI,CAAC,KAAK,IAAI,EAAE,KAAK,OAAO,SAAS,CAAC,GACpC,OAAO;GACL,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK;GAC1B,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK;GAC1B,GAAG,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK;EAC5B;CACJ;CAGA,MAAM,UAAU,SAAS,KAAA,KAAa,CAAC,WAAW;CAElD,IAAI,MAAM,KAAK,GAAG,IAAI;CAEtB,IAAI,OAAO;CAEX,IAAI,CAAC,SAAS;EACZ,OAAO,SAAS,CAAC;EACjB,KAAK,GAAG,IAAI;CACd;CAEA,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;EACpC,MAAM,KAAK,SAAS,UAAU,IAAI,IAAI,CAAC;EACvC,IAAI,QAAQ,KAAK,IAAI,IAAI,GAAG;EAC5B,KAAK,GAAG,EAAE;EACV,OAAO;CACT;CAEA,IAAI,OAAO,SAAS,GAAG,OAAO,KAAA;CAE9B,MAAM,MAAM,WAAW;CACvB,MAAM,cAAc,MAAM,KAAK,KAAK;CACpC,MAAM,WAAW,IAAI,cAAc,OAAO,SAAS,KAAK,aAAa,MAAM;CAC3E,IAAI,IAAI;CAER,MAAM,SAAS,OAAkB,MAAe,SAAiB;EAC/D,SAAS,IACP;GACE,MAAM,IAAI,KAAK,IAAI,MAAM,OAAO;GAChC,MAAM,IAAI,KAAK,IAAI,MAAM,OAAO;GAChC,MAAM,IAAI,KAAK,IAAI,MAAM,OAAO;GAChC,MAAM;GACN,MAAM;GACN,MAAM;GACN,MAAM;GACN,OAAO,IAAI,KAAK,KAAK,KAAK;GAC1B,MAAM,WAAW,KAAK,KAAK,KAAK;EAClC,GACA,CACF;EACA,KAAK;CACP;CAGA,MAAM,UAAU,GAAc,MAAiB;EAC7C,SAAS,IACP;IAAE,EAAE,IAAI,EAAE,KAAK;IAAI,EAAE,IAAI,EAAE,KAAK;IAAI,EAAE,IAAI,EAAE,KAAK;GAAG,EAAE;GAAG,EAAE;GAAG,EAAE;GAAG,EAAE;GAAG;GAAK;EAAG,GAChF,CACF;EACA,KAAK;CACP;CAGA,KAAK,MAAM,QAAQ,MACjB,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,OAAO,QAAQ,KAAK;EAC1C,MAAM,IAAI,OAAO;EACjB,MAAM,IAAI,OAAO,IAAI;EAErB,IAAI,KAAK;GACP,MAAM,GAAG,MAAM,EAAE;GACjB,MAAM,GAAG,MAAM,CAAC;GAChB,OAAO,GAAG,CAAC;GACX,MAAM,GAAG,MAAM,CAAC;GAChB,MAAM,GAAG,MAAM,CAAC;GAChB,OAAO,GAAG,CAAC;GACX,MAAM,GAAG,MAAM,CAAC;GAChB,MAAM,GAAG,MAAM,EAAE;GACjB,OAAO,GAAG,CAAC;GACX,MAAM,GAAG,MAAM,EAAE;GACjB,MAAM,GAAG,MAAM,EAAE;GACjB,OAAO,GAAG,CAAC;EACb,OAAO;GACL,MAAM,GAAG,MAAM,EAAE;GACjB,MAAM,GAAG,MAAM,CAAC;GAChB,MAAM,GAAG,MAAM,EAAE;GACjB,MAAM,GAAG,MAAM,CAAC;GAChB,MAAM,GAAG,MAAM,CAAC;GAChB,MAAM,GAAG,MAAM,EAAE;EACnB;CACF;CAEF,OAAO;EAAE;EAAU,OAAO,IAAI;CAAO;AACvC;;;;;AAMA,MAAM,oBACJ,MACA,YACA,UACA,MACA,QAC0D;CAC1D,MAAM,OAAO,KAAK;CAClB,MAAM,EAAE,QAAQ,QAAQ,SAAS;CACjC,MAAM,SAAS,WAAW,WAAW,QAAQ,WAAW,UAAU,QAAQ,GAAG,IAAI;CACjF,MAAM,MAAgB,CAAC;CACvB,MAAM,QAAQ,UAAqC,QACjD,WAAW,QAAQ,UAAU,QAAQ,GAAG,IAAI;CAE9C,KAAK,IAAI,IAAI,KAAK,MAAM,IAAI,KAAK,MAAM,KAAK;EAC1C,MAAM,IAAI,IAAA;EACV,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ,IAAA;EAC1C,MAAM,MAAM,KAAK,QAAQ,IAAA,KAAY;EACrC,MAAM,OAAO,KAAK,QAAQ,IAAA;EAC1B,IAAI,MAAM,MAAM;EAEhB,MAAM,MAAM,OAAO,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI;EAC9D,IAAI,QAAQ,KAAK,WAAW,OAAO,GAAG;EACtC,MAAM,QAAQ,KAAK,WAAW,OAAO,GAAG,IAAI;EAC5C,IAAI,UAAU,KAAK,QAAQ,OAAO;EAElC,MAAM,SAAS,YAAY,WAAW,mBAAmB,QAAQ,GAAG,KAAK,QAAQ;EACjF,MAAM,IAAI;GACR,GAAG,KAAK,QAAQ,KAAM,KAAK,QAAQ,IAAI,KAAM,UAAU,OAAO,EAAE;GAChE,GAAG,KAAK,QAAQ,IAAI,KAAM,KAAK,QAAQ,IAAI,KAAM,UAAU,OAAO,EAAE;GACpE,GAAG,KAAK,QAAQ,IAAI,KAAM,KAAK,QAAQ,IAAI,KAAM,UAAU,OAAO,EAAE;EACtE;EACA,MAAM,QAAQ,KAAK,WAAW,OAAO,GAAG,IAAI;EAC5C,MAAM,SAAS,KAAK,WAAW,QAAQ,GAAG,IAAI;EAE9C,IAAI,WAAW,kBAAkB;GAG/B,MAAM,IAAI,OAAO;GACjB,MAAM,IAAI,OAAO;GACjB,MAAM,IAAI;IAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;IAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;IAAG,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;GAAE;GACzF,MAAM,IAAI;IAAE,GAAG,IAAI,IAAI,EAAE;IAAG,GAAG,IAAI,IAAI,EAAE;IAAG,GAAG,IAAI,IAAI,EAAE;GAAE;GAC3D,MAAM,SAAS,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;GACvC,MAAM,IAAI,IAAI,KAAK,IAAI,SAAS,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;GACzF,IAAI,IAAI,SAAU;GAClB,IAAI,IAAI,SAAU,WAAW,UAAW,KAAK,YAAY;GACzD,IAAI,UAAU,GAAG;EACnB;EAEA,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,MAAM,WAAW,QAAQ,QAAQ,WAAW,OAAO,QAAQ,GAAG,IAAIA;EACzF,MAAM,UAAU,IAAY,OAC1B,IAAI,KACF,EAAE,IAAI,OAAO,EAAE,IAAI,QAAQ,KAAK,OAAO,EAAE,IAAI,SAAS,IACtD,EAAE,IAAI,OAAO,EAAE,IAAI,QAAQ,KAAK,OAAO,EAAE,IAAI,SAAS,IACtD,EAAE,IAAI,OAAO,EAAE,IAAI,QAAQ,KAAK,OAAO,EAAE,IAAI,SAAS,IACtD,GACA,GACA,GACA,OAAO,KAAK,GACZ,KAAK,IAAI,KAAK,KAAK,KAAK,IACxB,KAAK,IAAI,KAAK,KAAK,KAAK,EAC1B;EAEF,OAAO,IAAI,CAAC;EACZ,OAAO,GAAG,CAAC;EACX,OAAO,GAAG,EAAE;EACZ,OAAO,IAAI,CAAC;EACZ,OAAO,GAAG,EAAE;EACZ,OAAO,IAAI,EAAE;CACf;CAEA,OAAO,IAAI,SAAS;EAAE,UAAU,IAAI,aAAa,GAAG;EAAG,OAAO,IAAI,SAAS;CAAO,IAAI,KAAA;AACxF;AAEA,MAAa,iBACX,UACA,MACA,SACA,OACA,aACA,YACS;CACT,MAAM,EAAE,QAAQ,QAAQ,SAAS;CACjC,MAAM,SAAS,aAAa,IAAI;CAEhC,MAAM,SAAS,SAAkB;EAC/B,IAAI,KAAK,MAAM;EAEf,MAAM,QAAQ,CAAC,WAAW,QAAQ,KAAK,IAAI,MAAM,MAAM,KAAK,MAAO;EACnE,IAAI,SAAS,KAAK,YAAY,aAAa,cAAc,OAAO,IAAsB;EAEtF,KAAK,MAAM,SAAS,KAAK,UAAU,IAAI,SAAS,MAAM,QAAQ,KAAK,KAAK,MAAM,KAAK;CACrF;CAEA,MAAM,UAAU,SAAyB;EACvC,MAAM,EAAE,eAAe;EACvB,IAAI,WAAW,SAAS,uBAAuB;EAE/C,IAAI,WAAW,SAAS,mBAAmB;GAEzC,YAAY,IAAI,oBAAoB,WAAW,MAAM;GACrD;EACF;EAEA,MAAM,OAAO,KAAK;EAClB,IAAI,CAAC,KAAK,OAAO;EAEjB,MAAM,EACJ,SAAS,OACT,QACA,YACE,cACF,YACA,MACA,QACA,SACA,aACA,WAAW,SAAS,iBACtB;EACA,MAAM,SAAS;GACb,MAAM,KAAK,IAAI,MAAM,MAAM,KAAK;GAChC,OAAO,KAAK;GACZ,SAAS;GACT,OAAO,WAAW;EACpB;EAEA,IAAI,WAAW,SAAS,mBAAmB;GAEzC,MAAM,OAAO,QAAQ,SAAS,QAAQ,KAAK,KAAK;GAChD,MAAM,OAAO,aAAa,MAAM,YAAY,UAAU,OAAO,MAAM,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;GACzF,IAAI,MAAM,MAAM,KAAK;IAAE,GAAG;IAAQ,MAAM;IAAa,GAAG;GAAK,CAAC;GAC9D;EACF;EAEA,IAAI,WAAW,SAAS,yBAAyB,WAAW,mBAAmB,QAAQ;GACrF,MAAM,MAAM,QAAQ,eAAe,OAAO,GAAG,aAAa,KAAK,KAAK,CAAC;GACrE,MAAM,QAAQ,iBAAiB,MAAM,YAAY,UAAU,OAAO,MAAM,MAAM,GAAG;GACjF,IAAI,OAAO,MAAM,KAAK;IAAE,GAAG;IAAQ,MAAM;IAAa,GAAG;GAAM,CAAC;GAChE;EACF;EAEA,MAAM,QAAQ,QAAQ,UAAU;EAChC,IAAI,CAAC,OAAO;EAEZ,MAAM,SACJ,WAAW,SAAS,qBAAqB,CAAC,WAAW,WACjD,IACA,QAAQ,WAAW,UAAU,QAAQ,GAAG;EAE9C,IAAI,WAAW,SAAS,sBAAsB,WAAW,GAAG;EAE5D,MAAM,WAAW,SAAS;EAC1B,MAAM,OACJ,WAAW,SAAS,oBAChB,YAAY,SAAS,WAAW,IAC9B;GACE,UAAU,QAAQ,SAAS,UAAU,KAAK,KAAK;GAC/C,MAAM,SAAS;GACf,MAAM,SAAS,SAAS,cAAc,SAAS,gBAAgB,SAAS,QAAQ;EAClF,IACA,KAAA,IACF,KAAA;EACN,IAAI,WAAW,SAAS,qBAAqB,CAAC,MAAM;EAEpD,MAAM,MAAM,QAAQ,eAAe,OAAO,GAAG,aAAa,KAAK,KAAK,CAAC;EACrE,MAAM,QAAQ,WAAW,SAAS;EAElC,MAAM,KAAK;GACT,GAAG;GACH,MAAM;GACN;GACA,MAAM,KAAK;GACX;GACA;GACA,QAAQ,QAAA,IAEJ,WAAW,SAAS,oBAAA,IAElB,WAAW,SAAS,oBAAA,IAElB,WAAW,SAAS,oBAAA,IAAA;GAI5B,OACE,CAAC,SAAS,WAAW,cAAA,IAEjB,WAAW,aAAA,IAAA;GAGjB,MACG,SAAS,WAAW,eAAe,WAAW,cAC9C,WAAW,SAAS,qBAAqB,WAAW;GACvD,UAAU,WAAW,SAAS,qBAAqB,WAAW;GAC9D,MAAM,sBAAsB,cAAc,WAAW;GACrD;GACA;GAEA,GAAI,UAAU,EAAE,cAAc,KAAK,IAAI,KAAK,IAAI,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,EAAE,IAAI,CAAC;GACrF;GACA;EACF,CAAC;CACH;CAEA,KAAK,MAAM,QAAQ,SAAS,KAAK,MAAM,IAAI;AAC7C;;;;ACrnBA,MAAa,sBAAsB;CACjC,UAAU;CACV,QAAQ;CACR,SAAS;CACT,KAAK;CACL,KAAK;CACL,WAAW;CACX,YAAY;AACd;;AAkBA,MAAa,gBAAgB,WAAuC;CAClE,MAAM,aAAgC,CAAC;CACvC,IAAI,SAAS;CAGb,MAAM,OAAO,MAAqB,MAAc,kBAAkB,UAAU;EAC1E,WAAW,KAAK;GAAE;GAAM;GAAM;GAAiB;EAAO,CAAC;EACvD,UAAU,kBAAkB,OAAO,OAAO;CAC5C;CAEA,IAAI,SAAS,aAAa,UAAU,IAAI,YAAY,CAAC;CACrD,IAAI,SAAS,aAAa,QAAQ,IAAI,UAAU,CAAC;CAEjD,IAAI,SAAS,aAAa,WAAW,UAAU;CAC/C,IAAI,SAAS,aAAa,SAAS,IAAI,WAAW,GAAG,IAAI;CACzD,IAAI,SAAS,aAAa,UAAU,UAAU;CAE9C,MAAM,OAAO,YAAY,MAAM;CAE/B,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,OAC5B,IAAI,MAAM,GAAG,IAAI,QAAQ,IAAI,QAAQ,OAAO,CAAC;MACxC,UAAU;CAGjB,OAAO;EAAE,QAAQ,iBAAiB,MAAM;EAAG;CAAW;AACxD;AAEA,MAAMC,UAA4C;EAC/C,UAAU,YAAY;EACtB,UAAU,WAAW;EACrB,UAAU,YAAY;EACtB,UAAU,eAAe;EACzB,UAAU,gBAAgB;EAC1B,UAAU,cAAc;AAC3B;;AAGA,MAAa,YAAY,cAAiC;CACxD,MAAM,OAAOA,QAAM;CACnB,IAAI,SAAS,KAAA,GAAW,MAAM,IAAI,WAAW,+BAA+B,WAAW;CACvF,OAAO;AACT;;;;;AAoBA,MAAa,iBAAiB,MAAiB,cAAuC;CACpF,MAAM,QAAQ,CAAC,GAAG,YAAY,MAAM,SAAS,CAAC;CAC9C,MAAM,UAAU,IAAI,YAClB,MAAM,QAAQ,OAAO,EAAE,mBAAmB,QAAQ,cAAc,CAAC,CACnE;CACA,MAAM,SAAsB,CAAC;CAE7B,IAAI,UAAU;CAEd,KAAK,MAAM,EAAE,YAAY,YAAY,cAAc,gBAAgB,OAAO;EACxE,OAAO,KAAK;GACV;GACA,YAAY,UAAU,YAAY;GAClC,OAAO;EACT,CAAC;EAED,KAAK,IAAI,KAAK,GAAG,KAAK,cAAc,MAClC,QAAQ,aAAa,KAAK,QAAQ,aAAa,MAAO;CAC1D;CAEA,OAAO;EAAE;EAAS;CAAO;AAC3B;;;;;;;AC1GA,MAAa,kBACX,MACA,OACA,YACkC;CAClC,MAAM,6BAAa,IAAI,IAA8B;CAErD,MAAM,SAAS,MAAuB,WAAoB;EACxD,MAAM,QAAQ,KAAK,QACf,QAAQ,SAAS,QAAQ,eAAe,KAAK,OAAO,UAAU,IAAI,CAAC,CAAC,IACpE;EAEJ,WAAW,IAAI,MAAM,KAAK;EAC1B,KAAK,MAAM,SAAS,KAAK,UAAU,MAAM,OAAO,KAAK;CACvD;CAEA,MAAM,MAAM,KAAK;CACjB,OAAO;AACT;AAGA,MAAM,YAAY,KAAK,OAAO,IAAI,KAAK,EAAE;AACzC,MAAM,YAAY,KAAK,OAAO,KAAK,EAAE;AAErC,MAAM,YAAY;;AAGlB,MAAM,aAAa,UAA0B;CAC3C,OAAO,QAAQ,GAAG,SAAS;CAC3B,OAAO,SAAS,KAAK,SAAS;CAC9B,OAAO;AACT;;AAGA,MAAM,YAAY,EAAE,KAAK,UAAwC;CAC/D,MAAM,QAAQ,MAAM;CAEpB,OAAO,SAAS,YACZ;EAAE;EAAO,KAAK,CAAC;EAAW,KAAK;CAAU,IACzC;EAAE,OAAO,UAAU,KAAK;EAAG;EAAK;CAAI;AAC1C;;AAGA,MAAM,WAAW,GAAY,MAAwB,QAAQ,SAAS,GAAG,CAAC;;AAG1E,MAAMC,YAAU,GAAY,MAAwB,QAAQ,UAAU,GAAG,QAAQ,UAAU,CAAC,CAAC;;;;;;;;;AAU7F,MAAa,eAAe,QAAmB,UAA4B;CACzE,MAAM,WAAW,OAAO,YAAY,QAAQ;CAC5C,MAAM,UAAU,MAAM,YAAY,QAAQ;CAE1C,IAAI,MAAM,SAAS,SAAS;EAC1B,MAAM,cAAc,QAAQ,OAAO,aAAa,QAAQ,UAAU,MAAM,WAAW,CAAC;EAGpF,OAAO;GAAE,MAAM;GAAS,UAFP,QAAQ,SAAS,UAAUA,SAAO,SAAS,WAAW,CAExC;GAAG;EAAY;CAChD;CAEA,MAAM,cAAc,QAAQ,OAAO,aAAa,MAAM,WAAW;CAEjE,MAAM,QAAQ;EACZ,MAAM;EACN,UAAU;EACV,QAAQ;EACR;EACA,MANWA,SAAO,MAAM,MAAM,WAM3B;CACL;CACA,IAAI,OAAO,SAAS,YAAY,OAAO;EAAE,GAAG;EAAO,KAAK,MAAM;EAAK,KAAK,MAAM;CAAI;CAElF,MAAM,QAAQ,SAAS,MAAM;CAC7B,MAAM,QAAQ,SAAS,KAAK;CAC5B,MAAM,EAAE,KAAK,QAAQ,MAAM,QAAQ,MAAM,QAAQ,QAAQ;CAEzD,OAAO;EAAE,GAAG;EAAO;EAAK;CAAI;AAC9B;;;ACtFA,MAAa,qBAAqB;;AAGlC,MAAa,kBAAkB,EAAE,QAAqB,YAA4B;CAChF,MAAM,QAAQ,KAAK;CACnB,MAAM,OAAO,KAAK,GAAG,EAAE;CAEvB,IAAI,WAAW,MAAM,IAAI,OAAO,MAAM;CACtC,IAAI,WAAW,KAAK,IAAI,OAAO,KAAK;CAEpC,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,KAAK,QAAQ,MAAM;EAC3C,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,KAAM,KAAK,KAAK,EAAG;EAExC,IAAI,EAAE,MAAM,WAAW,EAAE,MAAM,SAC7B,QAAS,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,OAAQ,EAAE,KAAK,EAAE,MAAM,EAAE;CAClE;CAEA,OAAO;AACT;AAEA,MAAM,cAAc,YAA4B,KAAK,IAAK,UAAU,KAAK,KAAM,GAAG;;AAGlF,MAAa,oBACX,EAAE,OAAA,MACF,UACA,SACY,WAAW,IAAI,IAAI,WAAW,OAAO,CAAC,IAAK;;AAGzD,MAAa,gBACX,QACA,OACA,UACA,SACuB;CACvB,MAAM,WAAW,iBAAiB,OAAO,UAAU,IAAI;CAEvD,MAAM,QAAQ,OAAO,WAAW,EAAE,YAAY,OAAO;EAInD,OAAO,EAFO,eAAe,OAAO,OAAO,OAAO,SAAS,IAAI,IAAI,WAAW,GAEjE,IAAI;CACnB,CAAC;CAED,OAAO,QAAQ,IAAI,KAAA,IAAY;AACjC;;;;AClCA,MAAa,YAAY;AAKzB,MAAMC,YAAS;AACf,MAAMC,kBAAgB;AACtB,MAAM,eAAe;;AAUrB,MAAM,YAAY,YAAmC;CACnD,MAAM,MAAgB,CAAC;CAEvB,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,QAAQ,QAAQ,MAAM;EAC9C,MAAM,CAAC,GAAG,GAAG,KAAK;GAAC,QAAQ;GAAM,QAAQ,KAAK;GAAK,QAAQ,KAAK;EAAG;EACnE,IAAI,MAAM,KAAK,MAAM,KAAK,MAAM,GAAG;EAGnC,IAAI,KAAK,MAAM,GAAG,IAAI,KAAK,GAAG,GAAG,CAAC;OAC7B,IAAI,KAAK,GAAG,GAAG,CAAC;CACvB;CAEA,OAAO;AACT;AAEA,MAAM,aAAa,EAAE,UAAU,UAAiB,UAA4B;CAC1E,MAAM,EAAE,SAAS,UAAU,QAAQ,SAAS,KAAK,WAAW,SAAS,gBAAgB;CACrF,MAAM,QAAQ,SAAS;CACvB,IAAI,QAAQ,OAAS,MAAM,IAAI,WAAW,GAAG,MAAM,+BAA+B;CAGlF,MAAM,SAAS,IAAI,YAAY,UAAU,MAAM;CAE/C,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SACzC,OAAO,SAAS,OAAO,QAAQ,KAAM,UAAU,QAAQ;CAEzD,MAAM,WAAW,IAAI,aAAa,QAAQA,eAAa;CACvD,MAAM,aAAa,IAAI,aAAa,QAAA,CAAwB;CAC5D,MAAM,MAAM;EAAE,GAAG;EAAU,GAAG;EAAU,GAAG;CAAS;CACpD,MAAM,MAAM;EAAE,GAAG;EAAW,GAAG;EAAW,GAAG;CAAU;CAGvD,KAAK,IAAI,UAAU,GAAG,UAAU,OAAO,WAAW;EAChD,MAAM,QAAQ,SAAS;EACvB,MAAM,aAAa,IAAI,QAAQ;EAC/B,MAAM,KAAK,UAAUA;EACrB,MAAM,CAAC,GAAG,GAAG,KAAK;GAChB,OAAO,QAAQ,MAAM;GACrB,OAAO,QAAQ,IAAI,MAAM;GACzB,OAAO,QAAQ,IAAI,MAAM;EAC3B;EAEA,SAAS,IACP;GACE;GACA;GACA;GACA,QAAQ,QAAQ,MAAM;GACtB,QAAQ,QAAQ,IAAI,MAAM;GAC1B,QAAQ,QAAQ,IAAI,MAAM;GAC1B,IAAI,YAAY,aAAa,MAAM;GACnC,IAAI,YAAY,aAAa,IAAI,MAAM;EACzC,GACA,EACF;EACA,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EACzB,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EACzB,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EACzB,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EACzB,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EACzB,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;EAGzB,MAAM,WAAW,UAAU,UAAU;EACrC,MAAM,OAAO,WAAW,eAAe,IAAI;EAC3C,MAAM,QAAQ,OAAO,UAAU;EAC/B,MAAM,MAAM,UAAA;EAEZ,KAAK,IAAI,OAAO,GAAG,OAAO,MAAM,QAAQ;GACtC,MAAM,KAAK,QAAQ,QAAQ,SAAS;GACpC,IAAI,MAAM,OAAO,MAAM,IAAI,WAAW,WAAW,GAAG,mBAAmB,OAAO;GAC9E,WAAW,MAAM,QAAQ;GACzB,WAAW,MAAM,eAAe,QAAQ,aAAa,IAAI,IAAK,YAAY,QAAQ,SAAS;EAC7F;CAIF;CAGA,MAAM,QAAQ,OAAO,QAAQ,EAAE,cAAc,QAAQ,SAAS,CAAC;CAC/D,MAAM,QAAQ,MAAM,KAAK,EAAE,SAAS,gBAClC,cAAc,SAAS,CAAC,GAAG,OAAO,IAAI,SAAS,OAAO,CACxD;CACA,MAAM,SAAS,KAAK,MAAM,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,IAAI;CACzE,MAAM,SAAS;EAAE,IAAI,IAAI,IAAI,IAAI,KAAK;EAAG,IAAI,IAAI,IAAI,IAAI,KAAK;EAAG,IAAI,IAAI,IAAI,IAAI,KAAK;CAAE;CACxF,MAAM,UAAU,IAAI,YAAY,MAAM,KAAK,CAAC;CAE5C,KAAK,MAAM,SAAS,SAClB,IAAI,SAAS,OAAO,MAAM,IAAI,WAAW,oBAAoB,MAAM,QAAQ,MAAM,UAAU;CAE7F,OAAO;EACL,MAAM;GACJ,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,MAAM,KAAK,EAAE,YAAY,QAAQ;IACvC,YAAY,cAAc,QAAQ;IAClC,aAAa;IACb,WAAW,QAAQ;IACnB,cAAc,MAAM,GAAG,CAAE;IACzB,SAAS;GACX,EAAE;GACF;GACA,UAAU,IAAI,WAAW,SAAS,MAAM;EAC1C;EACA,WAAW;GACT,QAAQ;GACR,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY,MAAM;GAClB,aAAa;IAAE;IAAK;GAAI;GACxB,gBAAgB;IAAE;IAAQ;GAAO;EACnC;EACA;CACF;AACF;AAEA,MAAM,wBAAQ,IAAI,QAAyB;;AAG3C,MAAa,YAAY,OAAc,UAA4B;CACjE,IAAI,OAAO,MAAM,IAAI,KAAK;CAE1B,IAAI,CAAC,MAAM;EACT,OAAO,UAAU,OAAO,KAAK;EAC7B,MAAM,IAAI,OAAO,IAAI;CACvB;CAEA,OAAO;AACT;;;;;AAMA,MAAa,aACX,OACA,QACA,SACiB;CACjB,IAAI,MAAM,SAAA,KAAoB,MAAM,IAAI,WAAW,GAAG,MAAM,OAAO,iBAA0B;CAE7F,MAAM,QAAQ,IAAI,aAAa,MAAM,SAAS,EAAE;CAChD,MAAM,UAAU,QAAQ,OAAO,IAAI;CAEnC,MAAM,SAAS,EAAE,aAAa,YAAY,UAAU;EAClD,MAAM,QAAQ,OAAO;EACrB,MAAM,SAAS,QACX,QAAQ,SACN,QAAQ,SAAS,SAAS,KAAK,GAC/B,QAAQ,wBAAwB,aAAa,QAAQ,CACvD,IACA,QAAQ;EAEZ,QAAQ,QAAQ,QAAQ,OAAO,QAAQ,EAAE;CAC3C,CAAC;CACD,OAAO;AACT;AAuBA,MAAM,gBAAgB;;;;;AAMtB,MAAM,aACJ,EAAE,QAAQ,QAAQ,MAAM,MAAM,MAAM,MAAM,YAC1C,OACA,WACiC;CACjC,IAAI,CAAC,OAAO,OAAO,KAAA;CAEnB,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;CAC1B,MAAM,OAAO,UAAU,QAAQ;CAC/B,MAAM,SAAS,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI;CACxD,MAAM,QAAQ,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,IAAI;CACvD,MAAM,CAAC,GAAG,KAAK,CAAC,SAAS,SAAS,UAAU,SAAS,QAAQ,QAAQ;CACrE,IAAI,KAAK,IAAI,CAAC,KAAK,iBAAiB,KAAK,IAAI,CAAC,KAAK,eAAe,OAAO,KAAA;CACzE,OAAO,CAAC,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,CAAC,CAAC,GAAG,KAAK,IAAI,MAAM,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC;AAC9E;AAEA,MAAM,uBAAuB;AAE7B,MAAME,eAAa,EACjB,aACA,eAEA,QAAQ,wBAAwB,aAAa,QAAQ;;AAcvD,MAAa,YACX,OACA,OACA,EAAE,QAAQ,MAAM,SAAS,QAAQ,YAClB;CACf,MAAM,EAAE,MAAM,WAAW,eAAe,SAAS,OAAO,MAAM,MAAM;CACpE,MAAM,OAAiB;EAAE;EAAY,OAAO,UAAU,OAAO,QAAQ,CAAC,IAAI,QAAQ,IAAI;CAAE;CAExF,MAAM,EAAE,WAAW,MAAM;CACzB,MAAM,SAAS,UAAU,UAAU,OAAO;CAC1C,MAAM,SACJ,UACA,UAAU,QAAQ,OAAO,OAAO,OAAO,WAAW,KAAA,IAAY,KAAA,IAAY,OAAO,OAAO;CAE1F,OAAO;EAAE;EAAW;EAAM,OAAO;EAAM;EAAM,GAAI,SAAS,EAAE,WAAW,OAAO,IAAI,CAAC;CAAG;AACxF;;;;;;;AAQA,MAAa,iBACX,QACA,WACA,EAAE,YAAY,OAAO,YAAsD,CAAC,MAC9C;CAC9B,MAAM,0BAAU,IAAI,IAAoD;CAGxE,MAAM,UAAU,MAAc,cAA8C;EAC1E,MAAM,SAAS,QAAQ,IAAI,KAAK,YAAY,CAAC;EAE7C,OACE,UACA,QAAQ,SACN,QAAQ,SAAS,OAAO,OAAO,OAAO,SAAS,GAC/C,QAAQ,OAAOA,YAAU,SAAS,CAAC,CACrC;CAEJ;CAEA,OAAO,OAAO,KAAK,OAAO,OAAO;EAC/B,MAAM,OAAO,aAAa,KAAK;EAC/B,IAAI,CAAC,MAAM,OAAO,KAAA;EAGlB,MAAM,QAAQ,KAAK,KAAK,WAAW,SAAS,cAAc;GACxD,MAAM,QAAQ,OAAO,UAAU,MAAM,SAAS;GAE9C,OAAO,QAAQ,CAAC,KAAK,IAAI,CAAC;EAC5B,CAAC,CAAC,CAAC;EAEH,MAAM,aAAa,eAAe,MAAM,SAAS,WAAW,UAAU;EAEtE,MAAM,SAAkC,CAAC;EACzC,KAAK,MAAM,CAAC,MAAM,UAAU,YAAY,OAAO,KAAK,SAAS;EAG7D,IAAI,SAAS,UAAU,OAAO,GAC5B,KAAK,MAAM,CAAC,SAAS,YACnB,OAAO,KAAK,SAAS,QAAQ,SAAS,WAAW,QAAQ,OAAOA,YAAU,KAAK,IAAI,CAAC,CAAC;EAGzF,MAAM,SAAS,MAAM,MAAM,QACxB,MAAM,EAAE,QAAQ,UAAW,SAAS,KAAA,IAAY,OAAO,QAAQ,GAChE,CACF;EAEA,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS;GAC3C,MAAM,OAAO,MAAM,MAAM;GAEzB,KAAK,MAAM,aAAa,KAAK,YAAY;IACvC,MAAM,OAAO,UAAU,KAAK,YAAY;IACxC,MAAM,QAAQ,OAAO;IAErB,IAAI,QAAQ,IAAI,IAAI,GAEd;SAAA,CAAC,OAAO,OAAO,SAAS,OAAO,MAAM,SAAS;IAAA,OAKlD,QAAQ,IAAI,MAAM;KAAE,OAAO,SAAS,QAAQ;KAAU,WAAWA,YAAU,SAAS;IAAE,CAAC;GAC3F;GAGA,OAAO,WAAW,QAAQ;EAC5B;EAEA,OAAO;CACT,CAAC;AACH;;;;;AAMA,MAAa,gBACX,QACA,WACA,EAAE,OAAO,KAAK,eAAe,YAAY,OAAO,YAAyB,CAAC,MACzD;CACjB,MAAM,MAAM,cAAc,QAAQ,WAAW;EAAE,GAAI,cAAc,EAAE,WAAW;EAAI;CAAK,CAAC;CACxF,MAAM,QAAsB,CAAC;CAE7B,OAAO,SAAS,OAAO,OAAO;EAC5B,MAAM,OAAO,aAAa,KAAK;EAC/B,MAAM,SAAS,IAAI;EACnB,MAAM,QAAQ,KAAK,OAAO;EAC1B,MAAM,WACJ,UAAU,KAAA,KAAa,OAAO,QAC1B,aACE,MAAM,QACN,OACA,KAAK,MACH,IAAI,OAAO,SAAS,IAAI,UAAU,EAAE,GACpC,IAAI,OAAO,SAAS,IAAI,UAAU,EAAE,GACpC,IAAI,OAAO,SAAS,IAAI,UAAU,EAAE,CACtC,GACA,IAAI,OAAO,IACb,IACA,KAAK,IAAI,SAAS,GAAG,MAAM,OAAO,SAAS,CAAC;EAClD,MAAM,SAAS,aAAa,KAAA,IAAY,KAAA,IAAY,MAAM,OAAO;EAGjE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,QAAQ;EAEjC,MAAM,UAAkC,CAAC;EAEzC,MAAM,QAAQ,SAAsB;GAClC,KAAK,MAAM,SAAS,KAAK,UAAU;IACjC,QAAQ,MAAM,SAAS,KAAK;IAC5B,KAAK,KAAK;GACZ;EACF;EAEA,KAAK,IAAI;EACT,MAAM,KACJ,SAAS,QAAQ,MAAM,OAAO;GAC5B;GAEA,MAAM,OAAO,MAAM,QAAQ;GAC3B;GAGA,OAAO,aAAc,gBAAgB,QAAQ,OAAO,IAAI,WAAW;EACrE,CAAC,CACH;CACF,CAAC;CACD,OAAO;AACT;;AAGA,MAAa,aACX,OACA,WACA,UAAuB,CAAC,MACG,aAAa,CAAC,KAAK,GAAG,WAAW,OAAO,CAAC,CAAC;;ACpavE,MAAa,eAAe;CAAC;CAAW;CAAY;CAAY;AAAY;;AAG5E,MAAa,WAAW;;;;;;;;;;;;;;;;;;AAqBxB,MAAMC,UAAQ;CAAE,KAAK;CAAG,MAAM;CAAG,QAAQ;AAAE;AAE3C,MAAa,UAAU,IAA4B,UAAuB,QAAoB;CAC5F,GAAG,UAAU,SAAS,SAAS,MAAMA,QAAM,IAAI,QAAQ,YAAY,CAAC;CACpE,IAAI,CAAC,KAAK;CACV,GAAG,UAAU,SAAS,UAAU,IAAI,MAAM,GAAG,IAAI,MAAM,GAAG,IAAI,MAAM,CAAC;CACrE,GAAG,UAAU,SAAS,UAAU,IAAI,OAAO,IAAI,GAAG;CAClD,GAAG,UAAU,SAAS,YAAY,IAAI,WAAW,CAAC;AACpD;ACvBA,MAAM,eAAe;CAAE,MAAM;CAAG,KAAK;CAAG,YAAY;AAAE;AAEtD,MAAM,iBAAiB;CAAE,QAAQ;CAAG,SAAS;CAAG,MAAM;AAAE;AAExD,MAAM,SAAS;oBACK,oBAAoB,SAAS;oBAC7B,oBAAoB,OAAO;oBAC3B,oBAAoB,QAAQ;oBAC5B,oBAAoB,IAAI;oBACxB,oBAAoB,IAAI;oBACxB,oBAAoB,UAAU;oBAC9B,oBAAoB,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4InD,MAAM,WAAW;;;;;;;;;;;;EAYf,SAAS;;;;;;;;;;;;;uBAaY,aAAa,KAAK;;iCAER,aAAa,IAAI;;;;;;;;;;;;;;yBAczB,eAAe,QAAQ;yBACvB,eAAe,KAAK;;AAG7C,MAAMC,aAAW;CACf;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,GAAG;AACL;AAWA,MAAa,qBAAqB,OAA4C;CAC5E,MAAM,UAAU,cAAc,IAAI,QAAQ,UAAUA,UAAQ;CAE5D,GAAG,WAAW,QAAQ,MAAM;CAC5B,GAAG,UAAU,QAAQ,SAAS,YAAA,CAAwB;CACtD,GAAG,UAAU,QAAQ,SAAS,gBAAA,CAAgC;CAC9D,GAAG,UAAU,QAAQ,SAAS,WAAA,CAAsB;CAEpD,GAAG,oBACD,QAAQ,QACR,GAAG,qBAAqB,QAAQ,QAAQ,OAAO,GAAA,CAEjD;CAEA,MAAM,aAAa,GAAG,aAAa;CAEnC,GAAG,WAAW,GAAG,gBAAgB,UAAU;CAC3C,GAAG,WAAW,GAAG,gBAAA,MAAgC,GAAG,YAAY;CAChE,GAAG,WAAW,GAAG,gBAAgB,IAAI;CACrC,GAAG,eAAe,GAAG,gBAAA,GAA+B,UAAU;CAC9D,OAAO;EAAE,GAAG;EAAS;CAAW;AAClC;AAEA,MAAM,WAAW,WACf,IAAI,aAAa,OAAO,SAAS,EAAE,GAAG,GAAG,QAAQ;CAAC;CAAG;CAAG;AAAC,CAAC,CAAC;;AAG7D,MAAa,oBACX,IACA,EAAE,YACF,EAAE,MAAM,YAAY,SAAS,aACpB;CACT,IAAI,OAAO,SAAA,GAAqB,MAAM,IAAI,WAAW,oBAAgC;CACrF,GAAG,iBAAiB,SAAS,MAAM,OAAO,QAAQ,QAAQ,IAAI,CAAC;CAC/D,GAAG,iBAAiB,SAAS,YAAY,OAAO,QAAQ,QAAQ,UAAU,CAAC;CAC3E,GAAG,UAAU,SAAS,cAAc,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;CACnE,UAAU,IAAI,UAAU,MAAM;AAChC;AAEA,MAAMC,WAAS;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;AAGlC,MAAa,aACX,IACA,UACA,WACS;CACT,IAAI,OAAO,SAAA,GAAqB,MAAM,IAAI,WAAW,oBAAgC;CACrF,GAAG,UAAU,SAAS,YAAY,OAAO,MAAM;CAC/C,IAAI,CAAC,OAAO,QAAQ;CACpB,GAAG,WAAW,SAAS,YAAY,QAAQ,OAAO,KAAK,EAAE,YAAY,KAAK,CAAC,CAAC;CAC5E,GAAG,WAAW,SAAS,gBAAgB,QAAQ,OAAO,KAAK,EAAE,gBAAgB,SAAS,CAAC,CAAC;CACxF,GAAG,WACD,SAAS,eACT,IAAI,aACF,OAAO,SAAS,EAAE,eAAe;EAC/B,MAAM,EAAE,GAAG,GAAG,MAAM,YAAYA;EAEhC,OAAO;GAAC;GAAG;GAAG;GAAG,WAAW,IAAI;EAAC;CACnC,CAAC,CACH,CACF;CACA,GAAG,WAAW,SAAS,YAAY,IAAI,aAAa,OAAO,KAAK,EAAE,YAAY,SAAS,CAAC,CAAC,CAAC;CAC1F,GAAG,WACD,SAAS,kBACT,QAAQ,OAAO,KAAK,EAAE,kBAAkB,eAAeA,QAAM,CAAC,CAChE;CACA,GAAG,WAAW,SAAS,cAAc,QAAQ,OAAO,KAAK,EAAE,cAAc,WAAWA,QAAM,CAAC,CAAC;CAE5F,GAAG,WACD,SAAS,WACT,IAAI,aACF,OAAO,SAAS,EAAE,WAChB,OAAO;EAAC,KAAK,IAAI,KAAK,QAAQ,CAAC;EAAG,KAAK,IAAI,KAAK,MAAM,CAAC;EAAG,KAAK;CAAO,IAAI;EAAC;EAAG;EAAG;CAAC,CACpF,CACF,CACF;AACF;;AAGA,MAAa,mBACX,IACA,EAAE,YACF,SAsBS;CACT,GAAG,iBAAiB,SAAS,OAAO,OAAO,QAAQ,QAAQ,KAAK,KAAK,CAAC;CACtE,OAAO,IAAI,UAAU,KAAK,GAAG;CAC7B,GAAG,WAAW,SAAS,iBAAiB,KAAK,OAAO;CACpD,GAAG,UAAU,SAAS,iBAAiB,KAAK,QAAQ,GAAG,KAAK,QAAQ,GAAG,KAAK,QAAQ,CAAC;CACrF,GAAG,UAAU,SAAS,kBAAkB,KAAK,SAAS,GAAG,KAAK,SAAS,GAAG,KAAK,SAAS,CAAC;CAEzF,IAAI,KAAK,cAAc;EACrB,MAAM,EAAE,GAAG,GAAG,MAAM,KAAK;EAEzB,GAAG,UAAU,SAAS,cAAc,GAAG,GAAG,CAAC;CAC7C;CAEA,GAAG,UAAU,SAAS,aAAa,KAAK,cAAc,IAAI,CAAC;CAC3D,GAAG,UAAU,SAAS,OAAO,KAAK,QAAQ,IAAI,CAAC;CAC/C,GAAG,UAAU,SAAS,OAAO,KAAK,QAAQ,IAAI,CAAC;CAC/C,GAAG,UAAU,SAAS,YAAY,KAAK,gBAAgB,KAAK,CAAC;CAC7D,GAAG,UAAU,SAAS,kBAAkB,KAAK,mBAAmB,IAAI,CAAC;CACrE,GAAG,UAAU,SAAS,gBAAgB,KAAK,cAAc;CACzD,GAAG,UAAU,SAAS,eAAe,eAAe,KAAK,cAAc;CACvE,GAAG,UAAU,SAAS,SAAS,KAAK,OAAO,IAAI,CAAC;CAChD,GAAG,UAAU,SAAS,YAAY,KAAK,aAAa,IAAI,CAAC;CAEzD,IAAI,KAAK,YAAY;EACnB,MAAM,EAAE,WAAW,WAAW,MAAM,MAAM,KAAK;EAE/C,GAAG,UAAU,SAAS,gBAAgB,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS;EACtF,GAAG,UAAU,SAAS,gBAAgB,MAAM,CAAC;CAC/C;CAEA,GAAG,UAAU,SAAS,UAAU,KAAK,UAAU,IAAI,CAAC;CACpD,GAAG,UAAU,SAAS,OAAO,KAAK,SAAS,SAAS,CAAC;CAErD,MAAM,EAAE,QAAQ,UAAU,KAAK,eAAe;EAAE,QAAQ,CAAC,GAAG,CAAC;EAAG,OAAO,CAAC,GAAG,CAAC;CAAE;CAE9E,GAAG,UAAU,SAAS,aAAa,OAAO,IAAK,OAAO,IAAK,MAAM,IAAK,MAAM,EAAG;CAC/E,GAAG,UAAU,SAAS,YAAY,KAAK,cAAc,IAAI,CAAC;CAC1D,GAAG,UAAU,SAAS,aAAa,aAAa,KAAK,QAAQ,aAAa,OAAO;CACjF,GAAG,UAAU,SAAS,gBAAgB,KAAK,QAAQ,UAAU,IAAI,CAAC;CAClE,GAAG,UAAU,SAAS,aAAa,KAAK,QAAQ,SAAS,SAAS,CAAC;CACnE,GAAG,UAAU,SAAS,YAAY,KAAK,QAAQ,QAAQ,CAAC;AAC1D;;;ACrYA,MAAa,cAAc;AAK3B,MAAM,gBAAgB,WAAyB;CAAC;CAAQ;CAAQ;CAAG;AAAC;;AAGpE,MAAMC,WAAQ,MAAuB,IAAI,MAAO;;AAGhD,IAAa,aAAb,MAAwB;CACtB,SAAS,IAAI,aAAa,cAAc,CAAC;CACzC,SAAS;CACT,UAAU;CACV,0BAAU,IAAI,QAA8C;CAC5D,0BAAU,IAAI,QAA+C;CAC7D,0BAAU,IAAI,IAAoB;CAClC,6BAAa,IAAI,IAAoB;CACrC,kCAAkB,IAAI,IAAoB;CAE1C,SAAS,QAAwB;EAC/B,MAAM,SAAS,KAAK;EACpB,MAAM,UAAU,SAAS,UAAU;EAEnC,IAAI,SAAS,KAAK,OAAO,QAAQ;GAC/B,IAAI,OAAO,KAAK,OAAO;GAEvB,OAAO,OAAO,QAAQ,QAAQ;GAE9B,MAAM,QAAQ,IAAI,aAAa,IAAI;GAEnC,MAAM,IAAI,KAAK,MAAM;GACrB,KAAK,SAAS;EAChB;EAEA,KAAK,UAAU;EACf,KAAK;EACL,OAAO;CACT;CAEA,MAAM,MAA4C;EAChD,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI;EACnC,IAAI,UAAU,KAAA,GAAW,OAAO;EAEhC,MAAM,EAAE,WAAW,WAAW;EAC9B,MAAM,SAAS,KAAK,SAAS,IAAI,KAAK,KAAK,UAAU,SAAS,CAAC,CAAC;EAChE,MAAM,IAAI,KAAK;EAGf,EAAE,IAAI;GAAC,UAAU;GAAQ;GAAQ;GAAG;EAAC,GAAG,SAAS,CAAC;EAElD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,YAAY,UAAU,QAAQ,GAAG;GACrD,MAAM,MAAM,SAAS,KAAK,IAAI,IAAI;GAElC,EAAE,MAAM;GACR,EAAE,KAAK,KAAK;EACd;EAEA,KAAK,QAAQ,IAAI,MAAM,MAAM;EAC7B,OAAO;CACT;CAEA,MAAM,MAA6C;EACjD,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI;EACnC,IAAI,UAAU,KAAA,GAAW,OAAO;EAEhC,MAAM,EAAE,WAAW,WAAW;EAC9B,MAAM,SAAS,KAAK,SAAS,IAAI,UAAU,MAAM;EACjD,MAAM,IAAI,KAAK;EAEf,EAAE,IAAI;GAAC,UAAU;GAAQ;GAAQ;GAAG;EAAC,GAAG,SAAS,CAAC;EAElD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,YAAY,UAAU,QAAQ,GAAG;GAErD,MAAM,SAAUA,QAAK,MAAM,CAAC,IAAKA,QAAK,MAAM,CAAC,KAAK,MAAO,IAAKA,QAAK,MAAM,CAAC,OAAO;GAEjF,EAAE,IAAI;IAAC;IAAM,SAAS,KAAM;IAAO,SAAS,IAAK;IAAM,OAAO;GAAI,IAAI,SAAS,IAAI,KAAK,CAAC;EAC3F;EAEA,KAAK,QAAQ,IAAI,MAAM,MAAM;EAC7B,OAAO;CACT;CAEA,SAAS,OAAuB;EAC9B,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK;EACvC,IAAI,UAAU,KAAA,GAAW,OAAO;EAEhC,MAAM,SAAS,KAAK,MAAM;GAAE,QAAQ;GAAG,WAAW,CAAC;IAAE,KAAK;IAAG;GAAM,CAAC;EAAE,CAAC;EAEvE,KAAK,WAAW,IAAI,OAAO,MAAM;EACjC,OAAO;CACT;;CAGA,OAAO,OAA0B,UAAU,GAAW;EACpD,MAAM,OAAO,GAAG,QAAQ,GAAG,MAAM,KAAK,EAAE,IAAI,IAAI,IAAI,SAAS,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG;EAChG,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI;EACnC,IAAI,UAAU,KAAA,GAAW,OAAO;EAEhC,MAAM,SAAS,KAAK,SAAS,IAAI,MAAM,MAAM;EAE7C,KAAK,OAAO,IAAI;GAAC,MAAM;GAAQ;GAAS;GAAG;EAAC,GAAG,SAAS,CAAC;EAEzD,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,IAAI,IAAI,SAAS,MAAM,QAAQ,GAClD,KAAK,OAAO,IAAI;GAAC;GAAI;GAAI;GAAI;EAAE,IAAI,SAAS,IAAI,KAAK,CAAC;EAExD,KAAK,QAAQ,IAAI,MAAM,MAAM;EAC7B,OAAO;CACT;CAEA,UAAU,UAAqC,QAAgB,UAAwB;EACrF,IAAI,CAAC,UAAU,OAAO,aAAa,KAAK,SAAS,QAAQ,CAAC;EAE1D,MAAM,QAAQ,YAAY,UAAU,MAAM;EAC1C,IAAI,CAAC,OAAO,OAAO,aAAa,KAAK,SAAS,CAAC,CAAC;EAChD,OAAO;GAAC,KAAK,MAAM,MAAM,KAAK;GAAG,KAAK,MAAM,MAAM,KAAK;GAAG,MAAM;GAAM,MAAM;EAAM;CACpF;CAEA,UAAU,UAAqC,QAAgB,UAAyB;EACtF,MAAM,QAAQ,YAAY,YAAY,UAAU,MAAM;EACtD,IAAI,OAAO,OAAO;GAAC,KAAK,MAAM,MAAM,KAAK;GAAG,KAAK,MAAM,MAAM,KAAK;GAAG,MAAM;GAAM,MAAM;EAAM;EAE7F,MAAM,QAAQ,WAAW;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE,IAAI;EAChD,MAAM,OAAO,GAAG,MAAM,EAAE,GAAG,MAAM,EAAE,GAAG,MAAM;EAC5C,IAAI,SAAS,KAAK,gBAAgB,IAAI,IAAI;EAE1C,IAAI,WAAW,KAAA,GAAW;GACxB,SAAS,KAAK,MAAM;IAAE,QAAQ;IAAG,WAAW,CAAC;KAAE,KAAK;KAAG;IAAM,CAAC;GAAE,CAAC;GACjE,KAAK,gBAAgB,IAAI,MAAM,MAAM;EACvC;EAEA,OAAO,aAAa,MAAM;CAC5B;AACF;AAEA,MAAa,eAA0B;;;;0CAIG,YAAY,QAAQ,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACtI1E,MAAM,OAAgB;CAAE,GAAG;CAAK,GAAG;CAAK,GAAG;AAAI;AAE/C,MAAM,kBAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,GAAG;AACL;AAGA,MAAM,eAAe;AACrB,MAAM,cAAc;AACpB,MAAM,cAAc;AACpB,MAAM,cAAc;AAEpB,MAAM,WAAW;CAAE,QAAQ;CAAG,UAAU;CAAG,UAAU;CAAG,MAAM;CAAG,MAAM;AAAE;AAEzE,MAAM,eAA0B;;;;;oBAKZ,SAAS,OAAO;oBAChB,SAAS,SAAS;oBAClB,SAAS,SAAS;;oBAElB,SAAS,KAAK;oBACd,SAAS,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkChC,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBA0NG,YAAY;;;;;;gBAMd,YAAY;oBACR,YAAY;oBACZ,YAAY;;;;;;;;;AAUhC,MAAM,aAAwB;;;;;;;;;;;;;;;;;;;AAqB9B,MAAMC,aAAsB;;;;;;;;EAQ1B,SAAS;;;;;;;;;;;AAYX,MAAM,gBAAgB;CACpB;CACA;CACA;CACA;CACA,GAAG;AACL;AAIA,MAAMC,YAAU,IAAI,aAAa;CAC/B;CAAI;CAAG;CAAG;CAAG;CAAG;CAChB;CAAI;CAAG;CAAG;CAAI;CAAI;AACpB,CAAC;AAKD,MAAM,OAAO,IAAI,aAAa;CAC5B;CAAI;CAAG;CAAc;CAAG;CAAG;CAC3B;CAAG;CAAG;CAAc;CAAG;CAAI;CAC3B;CAAG;CAAI;CAAc;CAAI;CAAI;CAC7B;CAAI;CAAI;CAAc;CAAI;CAAG;CAC7B;CAAG;CAAG;CAAa;CAAG;CAAG;CACzB;CAAG;CAAG;CAAa;CAAG;CAAG;CACzB;CAAG;CAAG;CAAa;CAAG;CAAG;AAC3B,CAAC;AAED,MAAM,gBAAgB,KAAK,SAAS;AAEpC,MAAM,eAAA;AACN,MAAM,cAAc;AAEpB,MAAM,UAAU,IAA4B,SAA2C;CACrF,QAAQ,MAAR;EACE,KAAK,aAAa,MAChB,OAAO,GAAG;EACZ,KAAK,aAAa,KAChB,OAAO,GAAG;EACZ,KAAK,aAAa,aAChB,OAAO,GAAG;EACZ,KAAK,aAAa,oBAChB,OAAO,GAAG;EACZ,KAAK,aAAa,aAChB,OAAO,GAAG;EACZ,KAAK,aAAa,oBAChB,OAAO,GAAG;EACZ,KAAK,aAAa,kBAChB,OAAO,GAAG;EACZ,KAAK,aAAa,yBAChB,OAAO,GAAG;EACZ,KAAK,aAAa,kBAChB,OAAO,GAAG;EACZ,KAAK,aAAa,yBAChB,OAAO,GAAG;EACZ,KAAK,aAAa,gBAChB,OAAO,GAAG;EACZ,SACE;CACJ;AACF;;;;;;AAOA,MAAa,gBAAgB,IAA4B,UAAuC;CAC9F,MAAM,WAA6B,CAAC,GAAG,WAAW,GAAG,GAAG;CACxD,IAAI,CAAC,SAAS,MAAM,WAAW,aAAa,MAAM,OAAO;CACzD,IAAI,MAAM,WAAW,aAAa,iBAAiB,OAAO,CAAC,GAAG,WAAW,GAAG,mBAAmB;CAE/F,IAAI,MAAM,WAAW,aAAa,wBAChC,OAAO,CAAC,GAAG,qBAAqB,GAAG,SAAS;CAE9C,MAAM,SAAS,OAAO,IAAI,MAAM,MAAM,KAAK,SAAS;CACpD,IAAI,MAAM,WAAW,aAAa,wBAAwB,OAAO,CAAC,QAAQ,GAAG,mBAAmB;CAChG,IAAI,MAAM,WAAW,aAAa,iBAAiB,OAAO,CAAC,QAAQ,GAAG,SAAS;CAC/E,OAAO,CAAC,QAAQ,OAAO,IAAI,MAAM,MAAM,KAAK,SAAS,EAAE;AACzD;AAiDA,MAAa,wBAAwB,OAA+C;CAClF,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,eAAe;CACnB,MAAM,QAAQ,IAAI,WAAW;CAC7B,IAAI,wBAAQ,IAAI,IAAuB;CACvC,IAAI,wBAAQ,IAAI,IAAU;CAE1B,MAAM,SAAS,OAAoB,SAAe;EAChD,IAAI,MAAM,UAAU,KAAK,MAAM;EAC/B,MAAM,QAAQ,KAAK;EAGnB,MAAM,SAAA;EACN,MAAM,OAAO,KAAK,OAAO;EAEzB,GAAG,WAAW,GAAG,cAAc,MAAM,MAAM;EAC3C,GAAG,oBAAoB,SAAS,UAAU,GAAG,GAAG,OAAO,OAAO,QAAQ,IAAI;EAC1E,GAAG,oBAAoB,SAAS,UAAU,GAAG,GAAG,OAAO,OAAO,QAAQ,OAAO,EAAE;EAC/E,GAAG,oBAAoB,SAAS,MAAM,GAAG,GAAG,OAAO,OAAO,QAAQ,OAAO,EAAE;EAC3E,GAAG,oBAAoB,SAAS,MAAM,GAAG,GAAG,OAAO,OAAO,QAAQ,OAAO,EAAE;CAC7E;CAEA,MAAM,UAAU,SAA4B;EAC1C,MAAM,IAAI,IAAI;EAEd,IAAI,QAAQ,MAAM,IAAI,IAAI;EAE1B,IAAI,CAAC,OAAO;GACV,QAAQ;IACN,QAAQ,GAAG,aAAa;IACxB,OAAO,GAAG,kBAAkB;IAC5B,UAAU;IACV,SAAS;IACT,UAAU;IACV,OAAO;GACT;GACA,MAAM,IAAI,MAAM,KAAK;GACrB,GAAG,gBAAgB,MAAM,KAAK;GAC9B,GAAG,WAAW,GAAG,cAAc,QAAS;GACxC,GAAG,wBAAwB,SAAS,MAAM;GAC1C,GAAG,oBAAoB,SAAS,QAAQ,GAAG,GAAG,OAAO,OAAO,GAAG,CAAC;GAEhE,KAAK,MAAM,YAAY;IAAC,SAAS;IAAU,SAAS;IAAU,SAAS;IAAM,SAAS;GAAI,GAAG;IAC3F,GAAG,wBAAwB,QAAQ;IACnC,GAAG,oBAAoB,UAAU,CAAC;GACpC;EACF;EAEA,GAAG,gBAAgB,MAAM,KAAK;EAC9B,GAAG,WAAW,GAAG,cAAc,MAAM,MAAM;EAG3C,IAAI,MAAM,aAAa,KAAK,UAAU;GACpC,GAAG,WAAW,GAAG,cAAc,KAAK,SAAS,GAAG,YAAY;GAC5D,MAAM,WAAW,KAAK;GACtB,MAAM,QAAQ;EAChB,OAAO,IAAI,MAAM,YAAY,KAAK,SAChC,GAAG,cAAc,GAAG,cAAc,GAAG,KAAK,SAAS,GAAG,KAAK,OAAA,EAAa;OACnE,IAAI,MAAM,WAAW,KAAK,MAAM;GACrC,MAAM,OAAO,MAAM,WAAA;GAGnB,GAAG,cAAc,GAAG,cAAc,OAAO,GAAG,KAAK,SAAS,MAAM,KAAK,OAAA,KAAgB,IAAI;EAC3F;EAEA,MAAM,UAAU,KAAK;EACrB,MAAM,WAAW,KAAK;EACtB,MAAM,OAAO,IAAI;EACjB,OAAO;CACT;CAEA,MAAM,mBAAmB;EACvB,GAAG,cAAc,GAAG,WAAW,WAAW;EAC1C,iBAAiB,GAAG,cAAc;EAClC,GAAG,YAAY,GAAG,YAAY,YAAY;EAE1C,IAAI,iBAAiB,MAAM,SAAS;GAClC,MAAM,OAAO,KAAK,IAAI,GAAG,KAAK,KAAK,MAAM,SAAS,WAAW,CAAC;GAE9D,GAAG,cAAc,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAO;GACjE,GAAG,cAAc,GAAG,YAAY,GAAG,oBAAoB,GAAG,OAAO;GACjE,GAAG,WACD,GAAG,YACH,GACA,GAAG,SACH,aACA,MACA,GACA,GAAG,MACH,GAAG,OACH,MAAM,OAAO,SAAS,GAAG,OAAO,cAAc,CAAC,CACjD;GACA,eAAe,MAAM;EACvB;EAEA,GAAG,cAAc,GAAG,WAAW,YAAY;CAC7C;CAEA,MAAM,kBAAkB,MAAkB,MAAe,eAAwB;EAC/E,MAAM,EAAE,aAAa;EACrB,MAAM,EAAE,OAAO,WAAW;EAC1B,MAAM,QAAQ,UAAuC,MACnD,GAAG,UAAU,UAAU,EAAE,IAAK,EAAE,IAAK,EAAE,IAAK,EAAE,EAAG;EACnD,MAAM,SAAS,MAA0B,aACvC,MAAM,UAAU,MAAM,QAAQ,QAAQ;EAExC,KAAK,SAAS,SAAS,MAAM,UAAU,MAAM,OAAO,QAAQ,IAAI,CAAC;EACjE,KAAK,SAAS,SAAS,MAAM,MAAM,OAAO,CAAC,CAAC;EAC5C,KAAK,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC,CAAC;EACxC,KAAK,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC,CAAC;EACxC,KAAK,SAAS,SAAS,MAAM,MAAM,GAAG,CAAC,CAAC;EACxC,KAAK,SAAS,QAAQ,MAAM,MAAM,MAAM,CAAC,CAAC;EAC1C,KAAK,SAAS,SAAS,MAAM,MAAM,OAAO,CAAC,CAAC;EAC5C,GAAG,UACD,SAAS,UACT,KAAK,OAAO,SAAS,KAAK,KAAK,UAAU,MAAM,OAAO,KAAK,QAAQ,KAAK,YAAY,IAAI,EAC1F;EACA,GAAG,UAAU,SAAS,QAAQ,MAAM,IAAI;EACxC,GAAG,UAAU,SAAS,UAAU,KAAK,MAAM;EAC3C,GAAG,UAAU,SAAS,SAAS,KAAK,KAAK;EACzC,GAAG,UAAU,SAAS,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC/C,GAAG,UAAU,SAAS,YAAY,KAAK,WAAW,IAAI,CAAC;EACvD,GAAG,UAAU,SAAS,QAAQ,KAAK,OAAO,IAAI,CAAC;EAC/C,GAAG,UAAU,SAAS,UAAU,KAAK,MAAM;EAC3C,GAAG,UAAU,SAAS,QAAQ,KAAK,IAAI;EACvC,GAAG,UAAU,SAAS,OAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC;EAC/D,GAAG,iBAAiB,SAAS,cAAc,OAAO,QAAQ,QAAQ,UAAU,CAAC;EAC7E,GAAG,iBACD,SAAS,aACT,OACA,QAAQ,QAAQ,QAAQ,SAAS,MAAM,KAAK,KAAK,CAAC,CACpD;EAEA,IAAI,KAAK,MAAM;GACb,GAAG,iBAAiB,SAAS,YAAY,OAAO,QAAQ,QAAQ,KAAK,KAAK,QAAQ,CAAC;GACnF,GAAG,UAAU,SAAS,QAAQ,KAAK,KAAK,IAAI;GAC5C,GAAG,UAAU,SAAS,YAAY,KAAK,KAAK,IAAI;EAClD;CACF;CAEA,MAAM,gBAAgB;EACpB,WAAW,cAAc,IAAI,cAAcD,YAAU,eAAe;EACpE,SAAS,cAAc,IAAI,YAAYA,YAAU,aAAa;EAE9D,IAAI,CAAC,UAAU;GACb,WAAW,GAAG,aAAa;GAC3B,GAAG,WAAW,GAAG,cAAc,QAAQ;GACvC,GAAG,WAAW,GAAG,cAAcC,WAAS,GAAG,WAAW;EACxD;CACF;CAGA,MAAM,UAAU,UAAiC;EAC/C,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,SAAS,UAAU;GAC1B,MAAM,EAAE,OAAO,WAAW;GAE1B,MAAM,UAAU,MAAM,OAAO,QAAQ,IAAI;GAEzC,KAAK,MAAM,CAAC,MAAM,aAAa;IAC7B,CAAC,MAAM,OAAO,CAAC;IACf,CAAC,MAAM,GAAG,CAAC;IACX,CAAC,MAAM,GAAG,CAAC;IACX,CAAC,MAAM,GAAG,CAAC;IACX,CAAC,MAAM,MAAM,CAAC;IACd,CAAC,MAAM,OAAO,CAAC;GACjB,GACE,MAAM,UAAU,MAAM,QAAQ,QAAQ;GAExC,IAAI,KAAK,OAAO,SAAS,KAAK,KAAK,SAAS,MAAM,OAAO,KAAK,QAAQ,KAAK,YAAY;EACzF;EAEF,WAAW;CACb;CAEA,MAAM,eAAe;EACnB,GAAG,gBAAgB,IAAI;EACvB,GAAG,WAAW,GAAG,cAAc,IAAI;EACnC,GAAG,cAAc,GAAG,WAAW,WAAW;EAC1C,GAAG,YAAY,GAAG,YAAY,IAAI;EAClC,GAAG,cAAc,GAAG,QAAQ;EAC5B,GAAG,UAAU,IAAI;CACnB;CAEA,MAAM,QACJ,OACA,EAAE,MAAM,YAAY,aAAa,KAAK,YAAY,aACzC;EACT,IAAI,CAAC,MAAM,QAAQ;EACnB,QAAQ;EACR,IAAI,CAAC,UAAU,CAAC,MAAM;EAGtB,KAAK,MAAM,WAAW,CAAC,QAAQ,IAAI,GAAG;GACpC,GAAG,WAAW,QAAQ,MAAM;GAC5B,OAAO,IAAI,QAAQ,UAAU,GAAG;EAClC;EAEA,GAAG,QAAQ,GAAG,SAAS;EACvB,GAAG,OAAO,GAAG,KAAK;EAClB,GAAG,UAAU,KAAK;EAClB,GAAG,UAAU,cAAc,WAAW,GAAG,SAAS,GAAG,IAAI;EACzD,GAAG,WAAW,OAAO,MAAM;EAC3B,GAAG,UAAU,OAAO,SAAS,QAAQ,CAAC;EAEtC,OAAO,KAAK;EAEZ,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,CAAC,QAAQ,eAAe,aAAa,IAAI,KAAK,KAAK;GAGzD,GAAG,kBAAkB,QAAQ,aAAa,GAAG,MAAM,GAAG,GAAG;GAEzD,MAAM,aAAa,YAAY,IAAI;GAEnC,IAAI,KAAK,SAAS,UAAU;IAC1B,GAAG,WAAW,OAAO,MAAM;IAC3B,GAAG,UAAU,OAAO,SAAS,WAAW,YAAY;IACpD,GAAG,UAAU,OAAO,SAAS,UAAU,WAAW;IAClD,GAAG,UAAU,OAAO,SAAS,cAAc,aAAa,IAAI,CAAC;IAC7D,eAAe,MAAM,MAAM,UAAU;IAErC,MAAM,EAAE,SAAS;IAEjB,OAAO,IAAI;IACX,GAAG,oBAAoB,GAAG,WAAW,GAAG,GAAG,KAAK,OAAO,KAAK,IAAI;IAChE;GACF;GAEA,GAAG,WAAW,KAAK,MAAM;GACzB,GAAG,UAAU,KAAK,SAAS,WAAW,YAAY;GAClD,GAAG,UAAU,KAAK,SAAS,cAAc,aAAa,IAAI,CAAC;GAC3D,GAAG,iBAAiB,KAAK,SAAS,cAAc,OAAO,QAAQ,QAAQ,UAAU,CAAC;GAClF,GAAG,iBACD,KAAK,SAAS,aACd,OACA,QAAQ,QAAQ,QAAQ,SAAS,MAAM,KAAK,KAAK,CAAC,CACpD;GACA,eAAe,GAAG,aAAa;GAE/B,IAAI,CAAC,WAAW;IACd,YAAY,GAAG,kBAAkB;IACjC,GAAG,gBAAgB,SAAS;IAC5B,GAAG,WAAW,GAAG,cAAc,UAAU;IAEzC,GAAG,wBAAwB,CAAC;IAC5B,GAAG,oBAAoB,GAAG,GAAG,GAAG,OAAO,OAAO,IAAI,CAAC;IACnD,GAAG,wBAAwB,CAAC;IAC5B,GAAG,oBAAoB,GAAG,GAAG,GAAG,OAAO,OAAO,IAAI,EAAE;IACpD,GAAG,wBAAwB,CAAC;IAC5B,GAAG,oBAAoB,GAAG,GAAG,GAAG,OAAO,OAAO,IAAI,EAAE;GACtD;GAEA,GAAG,gBAAgB,SAAS;GAC5B,GAAG,WAAW,GAAG,cAAc,UAAU;GACzC,GAAG,WAAW,GAAG,cAAc,KAAK,UAAU,GAAG,WAAW;GAC5D,GAAG,WAAW,GAAG,WAAW,GAAG,KAAK,KAAK;EAC3C;EAEA,OAAO;CACT;CAEA,MAAM,WAAsC,OAAO,EAAE,MAAM,YAAY,YAAY;EACjF,MAAM,UAAU,MAAM,QAAQ,SAA6B,KAAK,SAAS,QAAQ;EACjF,IAAI,CAAC,QAAQ,QAAQ;EACrB,QAAQ;EACR,IAAI,CAAC,QAAQ;EAEb,IAAI,CAAC,MAAM;GACT,OAAO,GAAG,aAAa;GACvB,GAAG,WAAW,GAAG,cAAc,IAAI;GACnC,GAAG,WAAW,GAAG,cAAc,MAAM,GAAG,WAAW;EACrD;EAEA,MAAM,EAAE,aAAa;EACrB,MAAM,OAAO,UAAuC,CAAC,GAAG,GAAG,OACzD,GAAG,UAAU,UAAU,GAAG,GAAG,CAAC;EAEhC,GAAG,WAAW,OAAO,MAAM;EAC3B,OAAO,IAAI,UAAU,KAAA,CAAS;EAC9B,GAAG,UAAU,SAAS,QAAQ,CAAC;EAC/B,GAAG,UAAU,SAAS,cAAc,CAAC;EACrC,GAAG,UAAU,SAAS,UAAU,WAAW;EAC3C,IAAI,SAAS,aAAa,MAAM,KAAK;EACrC,IAAI,SAAS,aAAa,MAAM,KAAK;EACrC,IAAI,SAAS,cAAc,MAAM,MAAM;EACvC,GAAG,UAAU,SAAS,aAAa,MAAM,KAAK;EAC9C,GAAG,QAAQ,GAAG,SAAS;EACvB,GAAG,OAAO,GAAG,KAAK;EAClB,GAAG,kBAAkB,GAAG,WAAW,GAAG,qBAAqB,GAAG,MAAM,GAAG,GAAG;EAC1E,GAAG,UAAU,KAAK;EAElB,OAAO,OAAO;EAEd,KAAK,MAAM,QAAQ,SAAS;GAC1B,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI;GACrC,IAAI,CAAC,OAAO;GACZ,IAAI,SAAS,eAAe,KAAK;GACjC,eAAe,MAAM,MAAM,UAAU;GAErC,MAAM,EAAE,SAAS;GAEjB,OAAO,IAAI;GAEX,GAAG,WAAW,GAAG,cAAc,IAAI;GACnC,GAAG,oBAAoB,SAAS,QAAQ,GAAG,GAAG,OAAO,OAAO,GAAG,CAAC;GAChE,GAAG,oBAAoB,GAAG,OAAO,GAAG,eAAe,KAAK,OAAO,KAAK,IAAI;GACxE,GAAG,WAAW,GAAG,cAAc,QAAS;GACxC,GAAG,oBAAoB,SAAS,QAAQ,GAAG,GAAG,OAAO,OAAO,GAAG,CAAC;EAClE;EAEA,GAAG,UAAU,SAAS,QAAQ,CAAC;EAC/B,OAAO;CACT;CAGA,MAAM,cAAc;EAClB,KAAK,MAAM,CAAC,MAAM,UAAU,OAC1B,IAAI,CAAC,MAAM,IAAI,IAAI,GAAG;GACpB,GAAG,aAAa,MAAM,MAAM;GAC5B,GAAG,kBAAkB,MAAM,KAAK;GAChC,MAAM,OAAO,IAAI;EACnB;EAEF,wBAAQ,IAAI,IAAI;CAClB;CAEA,MAAM,gBAAgB;EACpB,KAAK,MAAM,SAAS,MAAM,OAAO,GAAG;GAClC,GAAG,aAAa,MAAM,MAAM;GAC5B,GAAG,kBAAkB,MAAM,KAAK;EAClC;EAEA,wBAAQ,IAAI,IAAI;EAChB,IAAI,QAAQ,GAAG,cAAc,OAAO,MAAM;EAC1C,IAAI,MAAM,GAAG,cAAc,KAAK,MAAM;EACtC,IAAI,UAAU,GAAG,aAAa,QAAQ;EACtC,IAAI,MAAM,GAAG,aAAa,IAAI;EAC9B,IAAI,YAAY,GAAG,aAAa,UAAU;EAC1C,IAAI,WAAW,GAAG,kBAAkB,SAAS;EAC7C,IAAI,cAAc,GAAG,cAAc,YAAY;EAC/C,SAAS,OAAO,KAAA;EAChB,WAAW,OAAO,aAAa,YAAY,eAAe,KAAA;EAC1D,wBAAQ,IAAI,IAAI;CAClB;CAEA,OAAO;EAAE;EAAM;EAAS;EAAO;CAAQ;AACzC;;;;;;;;;ACz1BA,MAAM,WAAW;CAAC;CAAc;CAAa,GAAG;AAAY;AAE5D,MAAM,SAAoB;;;;;;;;;;;;;;;;;;;;;;;AAwB1B,MAAM,WAAsB;;;;;;;EAO1B,SAAS;;;;;;;;;;;AAcX,MAAMC,YAAS;;AAGf,MAAM,cAAc,UAA8C;CAChE,MAAM,yBAAS,IAAI,YAAY,MAAM,SAAS,IAAIA,SAAM;CACxD,MAAM,SAAS,IAAI,aAAa,MAAM;CACtC,MAAM,QAAQ,IAAI,WAAW,MAAM;CAEnC,MAAM,SAAS,EAAE,IAAI,IAAI,IAAI,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,IAAI,SAAS,MAAM;EAQtE;GANE;IAAC;IAAI;IAAI;IAAI;GAAE;GACf;IAAC;IAAI;IAAI;IAAI;GAAE;GACf;IAAC;IAAI;IAAI;IAAI;GAAE;GACf;IAAC;IAAI;IAAI;IAAI;GAAE;EAGX,CAAC,CAAC,SAAS,CAAC,GAAG,GAAG,GAAG,IAAI,WAAW;GAExC,MAAM,MAAM,IAAI,IAAI,UAAUA;GAE9B,OAAO,IAAI;IAAC;IAAG;IAAG;IAAG;IAAK;IAAG;GAAC,GAAG,KAAK,CAAC;GAEvC,MAAM,IAAI;IAAE,UAAU,KAAM;IAAO,UAAU,IAAK;IAAM,QAAQ;IAAM,UAAU;GAAE,GAAG,KAAK,EAAE;EAC9F,CAAC;CACH,CAAC;CACD,OAAO;AACT;;AAGA,MAAM,cAAc,UAA+B;CACjD,MAAM,UAAU,IAAI,YAAY,QAAQ,CAAC;CAEzC,KAAK,IAAI,OAAO,GAAG,OAAO,OAAO,QAC/B,QAAQ,IACN;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;CAAC,CAAC,CAAC,KAAK,WAAW,OAAO,IAAI,MAAM,GACpD,OAAO,CACT;CAEF,OAAO;AACT;AAaA,MAAa,4BAA4B,OAAmD;CAC1F,MAAM,UAA8C,cAAc,IAAI,QAAQ,UAAU,QAAQ;CAChG,MAAM,WAAW,GAAG,aAAa;CACjC,MAAM,UAAU,GAAG,aAAa;CAChC,MAAM,QAAQ,GAAG,kBAAkB;CAEnC,GAAG,gBAAgB,KAAK;CACxB,GAAG,WAAW,GAAG,cAAc,QAAQ;CACvC,GAAG,wBAAwB,CAAC;CAC5B,GAAG,oBAAoB,GAAG,GAAG,GAAG,OAAO,OAAOA,WAAQ,CAAC;CACvD,GAAG,wBAAwB,CAAC;CAC5B,GAAG,oBAAoB,GAAG,GAAG,GAAG,eAAe,MAAMA,WAAQ,EAAE;CAC/D,GAAG,wBAAwB,CAAC;CAC5B,GAAG,oBAAoB,GAAG,GAAG,GAAG,OAAO,OAAOA,WAAQ,EAAE;CACxD,GAAG,WAAW,GAAG,sBAAsB,OAAO;CAC9C,GAAG,gBAAgB,IAAI;CAEvB,MAAM,QAAoC,SAAS,EAAE,OAAO,UAAU,aAAa,QAAQ;EACzF,GAAG,WAAW,QAAQ,MAAM;EAC5B,GAAG,UAAU,QAAQ,SAAS,YAAY,OAAO,MAAM;EACvD,GAAG,UAAU,QAAQ,SAAS,WAAA,CAAuB;EACrD,OAAO,IAAI,QAAQ,UAAU,GAAG;EAGhC,GAAG,OAAO,GAAG,UAAU;EACvB,GAAG,UAAU,GAAG,MAAM;EACtB,GAAG,UAAU,KAAK;EAClB,GAAG,QAAQ,GAAG,SAAS;EACvB,GAAG,OAAO,GAAG,KAAK;EAClB,GAAG,kBAAkB,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,GAAG;EACpD,GAAG,gBAAgB,KAAK;EAExB,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,CAAC,MAAM,MAAM,QAAQ;GACzB,YAAY,KAAK;GACjB,GAAG,WAAW,GAAG,cAAc,QAAQ;GACvC,GAAG,WAAW,GAAG,cAAc,WAAW,MAAM,KAAK,GAAG,GAAG,WAAW;GACtE,GAAG,WAAW,GAAG,sBAAsB,WAAW,MAAM,MAAM,MAAM,GAAG,GAAG,WAAW;GACrF,GAAG,aAAa,GAAG,WAAW,MAAM,MAAM,SAAS,GAAG,GAAG,gBAAgB,CAAC;EAC5E;EAEA,GAAG,gBAAgB,IAAI;CACzB;CAEA,MAAM,gBAAgB;EACpB,GAAG,cAAc,QAAQ,MAAM;EAC/B,GAAG,aAAa,QAAQ;EACxB,GAAG,aAAa,OAAO;EACvB,GAAG,kBAAkB,KAAK;CAC5B;CAEA,OAAO;EAAE;EAAM;CAAQ;AACzB;;ACjKA,MAAa,sBAAsB,IAA4B,SAAiC;CAC9F,MAAM,SAAS,GAAG,aAAa;CAE/B,GAAG,WAAW,GAAG,cAAc,MAAM;CACrC,GAAG,WAAW,GAAG,cAAc,KAAK,UAAU,GAAG,WAAW;CAC5D,GAAG,WAAW,GAAG,cAAc,IAAI;CACnC,OAAO;AACT;;AAQA,MAAa,wBACX,IACA,MACA,UACA,EAAE,cACiB;CACnB,MAAM,EAAE,QAAQ,eAAe,aAAa,KAAK,MAAM;CACvD,MAAM,QAAQ,GAAG,kBAAkB;CAEnC,GAAG,gBAAgB,KAAK;CACxB,GAAG,WAAW,GAAG,cAAc,QAAQ;CAEvC,KAAK,MAAM,EAAE,MAAM,MAAM,iBAAiB,YAAY,YAAY;EAChE,MAAM,WAAW,oBAAoB;EAErC,GAAG,wBAAwB,QAAQ;EACnC,GAAG,oBACD,UACA,MACA,kBAAkB,GAAG,gBAAgB,GAAG,OACxC,iBACA,QACA,MACF;CACF;CAEA,MAAM,WAAW,GAAG,aAAa;CAEjC,GAAG,WAAW,GAAG,sBAAsB,QAAQ;CAC/C,GAAG,WAAW,GAAG,sBAAsB,SAAS,GAAG,WAAW;CAE9D,GAAG,gBAAgB,IAAI;CACvB,GAAG,WAAW,GAAG,cAAc,IAAI;CACnC,GAAG,WAAW,GAAG,sBAAsB,IAAI;CAC3C,OAAO;EAAE;EAAO;CAAS;AAC3B;;AC5CA,MAAM,UAAyC;CAE7C,MAAM,EAAE,UAAU,MAAO;CACzB,MAAM,EAAE,UAAU,MAAO;CACzB,MAAM,EAAE,UAAU,MAAO;CACzB,QAAQ;EAAE,UAAU;EAAQ,QAAQ;EAAQ,MAAM;CAAO;CACzD,QAAQ;EAAE,UAAU;EAAQ,QAAQ;EAAQ,MAAM;CAAO;CACzD,OAAO;EAAE,UAAU;EAAQ,QAAQ;EAAQ,MAAM;CAAO;AAC1D;;AAGA,MAAa,iBACX,IACA,EAAE,QAAQ,QAAQ,OAAO,QAAQ,YAChB;CACjB,MAAM,EAAE,UAAU,QAAQ,SAAS,QAAQ;CAE3C,IAAI,WAAW,KAAA,KAAa,CAAC,GAAG,aAAa,+BAA+B,GAC1E,MAAM,IAAI,MAAM,gDAAgD;CAElE,MAAM,OAAO,WAAW,SAAS,GAAG,mBAAmB,GAAG;CAC1D,MAAM,UAAU,GAAG,cAAc;CAEjC,GAAG,YAAY,MAAM,OAAO;CAC5B,GAAG,YAAY,GAAG,kBAAkB,CAAC;CACrC,GAAG,aAAa,MAAM,MAAM,EAAE,CAAE,QAAQ,UAAU,OAAO,MAAM;CAE/D,MAAM,SAAS,QAAQ,SAAS;EAC9B,MAAM,cAAc,WAAW,SAAS,GAAG,8BAA8B,OAAO,GAAG;EAEnF,OAAO,SAAS,QAAQ,UAAU;GAChC,MAAM,IAAI,KAAK,IAAI,GAAG,SAAS,KAAK;GACpC,MAAM,IAAI,KAAK,IAAI,GAAG,UAAU,KAAK;GAErC,IAAI,WAAW,KAAA,GACb,GAAG,wBAAwB,aAAa,OAAO,GAAG,GAAG,GAAG,GAAG,UAAU,MAAM;QACxE,GAAG,cAAc,aAAa,OAAO,GAAG,GAAG,GAAG,GAAG,QAAQ,MAAO,MAAM;EAC7E,CAAC;CACH,CAAC;CAED,GAAG,YAAY,MAAM,IAAI;CACzB,OAAO;AACT;;AAeA,MAAa,kBAAgC;CAC3C,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,OAAO;CACP,OAAO;AACT;AAEA,MAAMC,YAAU,IAA4B,SAC1C,SAAS,WAAW,GAAG,SAAS,SAAS,WAAW,GAAG,kBAAkB,GAAG;AAG9E,MAAM,YAAY,IAA4B,EAAE,QAAQ,aAAmC;CACzF,IAAI,WAAW,WACb,OAAO,WAAW,YAAY,GAAG,yBAAyB,GAAG;CAE/D,OAAO,WAAW,YAAY,GAAG,wBAAwB,GAAG;AAC9D;AAEA,MAAa,iBAAiB,IAA4B,UAAsC;CAC9F,MAAM,UAAU,GAAG,cAAc;CAEjC,GAAG,kBACD,SACA,GAAG,oBACH,MAAM,YAAY,WAAW,GAAG,SAAS,GAAG,OAC9C;CACA,GAAG,kBAAkB,SAAS,GAAG,oBAAoB,SAAS,IAAI,KAAK,CAAC;CACxE,GAAG,kBAAkB,SAAS,GAAG,gBAAgBA,SAAO,IAAI,MAAM,KAAK,CAAC;CACxE,GAAG,kBAAkB,SAAS,GAAG,gBAAgBA,SAAO,IAAI,MAAM,KAAK,CAAC;CACxE,OAAO;AACT;;ACpFA,MAAM,oBAAoB,UAAmC;CAC3D,MAAM,SAAS,IAAI,YAAY,MAAM,UAAU,CAAC;CAChD,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM,OAAO,MAAM,MAAM,KAAK,KAAO,MAAM,KAAK,IAAI,MAAO;CAChG,OAAO;AACT;;AAGA,MAAM,UAAU,OAAe,SAAyB;CACtD,MAAM,OAAO,KAAK,QAAQ;CAE1B,OAAO,KAAK,MAAO,QAAQ,MAAO,MAAM,EAAG;AAC7C;;;;;AAMA,MAAM,eAAe,UAAmC;CACtD,MAAM,SAAS,IAAI,YAAY,MAAM,SAAS,CAAC;CAE/C,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,QAAQ,MACnC,OAAO,MACJ,OAAO,MAAM,KAAK,IAAK,CAAC,KAAK,KAC7B,OAAO,MAAM,KAAK,IAAI,IAAK,CAAC,KAAK,IAClC,OAAO,MAAM,KAAK,IAAI,IAAK,CAAC;CAEhC,OAAO;AACT;;;;;;;AAQA,MAAM,oBAAoB,UACxB,iBAAiB,KAAK,CAAC,CAAC,KAAK,UAAU;CACrC,MAAM,QAAS,SAAS,IAAK;CAG7B,QAAS,QAAQ,UAAW,KAAQ,SAAS,IAAM,SAAS,MAAO,IAAM,QAAQ;AACnF,CAAC;;AAGH,MAAM,sBAAsB,UAC1B,iBAAiB,KAAK,CAAC,CAAC,KAAK,UAAY,SAAS,IAAK,QAAW,SAAS,EAAG;;AAGhF,MAAM,sBAAsB,UAC1B,iBAAiB,KAAK,CAAC,CAAC,KAAK,UAAY,SAAS,IAAK,QAAU,CAAC;AAEpE,MAAM,eAAe,UAAkC;CACrD,MAAM,SAAS,MAAM,MAAM;CAE3B,KAAK,IAAI,KAAK,GAAG,KAAK,MAAM,QAAQ,MAAM,GAAG;EAC3C,OAAO,MAAM,MAAM,KAAK;EACxB,OAAO,KAAK,KAAK,MAAM;CACzB;CAEA,OAAO;AACT;AAEA,MAAM,aAAa,UAAkC;CACnD,MAAM,SAAS,IAAI,WAAY,MAAM,SAAS,IAAK,CAAC;CAEpD,KAAK,IAAI,KAAK,GAAG,KAAK,MAAM,SAAS,GAAG,MAAM;EAC5C,OAAO,KAAK,KAAK,MAAM,KAAK,IAAI;EAChC,OAAO,KAAK,IAAI,KAAK,MAAM,KAAK,IAAI;EACpC,OAAO,KAAK,IAAI,KAAK,MAAM,KAAK;EAChC,OAAO,KAAK,IAAI,KAAK;CACvB;CAEA,OAAO;AACT;;AAGA,MAAM,eAAe,OAAmB,WAA+B;CACrE,MAAM,MAAM,MAAM,SAAS;CAC3B,MAAM,SAAS,IAAI,WAAW,MAAM,MAAM;CAE1C,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,KAC1B,OAAO,IAAI,MAAM,SAAS,IAAI,MAAM,IAAI,KAAK,GAAG,IAAI,SAAS,IAAI,KAAK,GAAG;CAE3E,OAAO;AACT;AAEA,MAAM,cAAc,EAAE,QAAQ,cAAsC;CAClE,QAAQ,QAAR;EACE,KAAK;EACL,KAAK;EACL,KAAK,QACH,OAAO;EACT,KAAK,aACH,OAAO;EACT,KAAK,aAEH,OAAO,YAAY,UAAU,WAAW;EAC1C,KAAK,eACH,OAAO,YAAY,UAAU,WAAW;EAC1C,KAAK,eACH,OAAO;EACT,KAAK,aAEH,OAAO,YAAY,UAAU,WAAW;EAC1C,SACE,MAAM,IAAI,WAAW,0BAA0B,QAAQ;CAC3D;AACF;AAEA,MAAM,aAAa,SAAkB,OAAmB,OAAe;CACrE,MAAM,EAAE,QAAQ,SAAS,MAAM,WAAW;CAE1C,IAAI,YAAY,SAAS;EAEvB,MAAM,OAAO,OAAO,YAAY,OAAO,KAAK,IAAI,GAAG,UAAU,EAAE,CAAC,IAAI;EAEpE,QAAQ,QAAR;GACE,KAAK,aACH,OAAO,YAAY,IAAI;GACzB,KAAK;GACL,KAAK,eACH,OAAO,iBAAiB,IAAI;GAC9B,SACE,OAAO;EACX;CACF;CAGA,QAAQ,QAAR;EACE,KAAK,aACH,OAAO,iBAAiB,KAAK;EAC/B,KAAK,aACH,OAAO,mBAAmB,KAAK;EACjC,KAAK,eACH,OAAO,mBAAmB,KAAK;EACjC,KAAK,eACH,OAAO,YAAY,KAAK;EAC1B,KAAK,aACH,OAAO,UAAU,KAAK;EACxB,SACE,OAAO;CACX;AACF;;AAGA,MAAM,SAAS,OAAmB,SAA6B;CAC7D,MAAM,OAAO,QAAQ;CACrB,MAAM,SAAS,IAAI,WAAW,OAAO,OAAO,CAAC;CAE7C,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KACxB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KACxB,KAAK,IAAI,UAAU,GAAG,UAAU,GAAG,WAAW;EAC5C,MAAM,SAAS,KAAa,WAAmB,OAAO,MAAM,OAAO,UAAU,IAAI;EACjF,MAAM,MACJ,MAAM,IAAI,GAAG,IAAI,CAAC,IAClB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IACtB,MAAM,IAAI,IAAI,GAAG,IAAI,CAAC,IACtB,MAAM,IAAI,IAAI,GAAG,IAAI,IAAI,CAAC;EAE5B,QAAQ,IAAI,OAAO,KAAK,IAAI,WAAY,MAAM,KAAM;CACtD;CAEJ,OAAO;AACT;;AAGA,MAAM,aAAa,QAAsB,UAAgC;CACvE,MAAM,QAAQ,OAAO,IAAI,WAAW;CAGpC,KAAK,IAAI,OAAO,SAAU,MAAM,SAAS,GAAI,OAAO,GAAG,SAAS,GAC9D,MAAM,KAAK,MAAM,MAAM,GAAG,EAAE,GAAI,IAAI,CAAC;CAEvC,OAAO;AACT;;AAGA,MAAa,cAAc,YAAkD;CAC3E,MAAM,EAAE,OAAO,WAAW;CAE1B,IAAI,QAAQ,SAAS,QAAQ;EAC3B,IAAI,QAAQ,WAAW,eAAe,MAAM,IAAI,WAAW,gBAAgB,QAAQ,QAAQ;EAC3F,OAAO;GACL,QAAQ;GACR,QAAQ;GACR;GACA;GACA,OAAO,QAAQ,MAAM,KAAK,WAAW,UAAU,QAAQ,KAAK,CAAC;EAC/D;CACF;CAEA,OAAO;EACL,QAAQ;EACR,QAAQ,WAAW,OAAO;EAC1B;EACA;EACA,OAAO,CAAC,QAAQ,OAAO,KAAK,OAAO,OAAO,UAAU,SAAS,OAAO,EAAE,CAAC,CAAC;CAC1E;AACF;;;AClLA,MAAM,cAAyC,CAAC,GAAG,CAAC;AACpD,MAAM,iBAA+B;CAAE,GAAG;CAAiB,OAAO;CAAS,OAAO;AAAQ;;;;;AAyD1F,MAAa,kBAAkB,OAAyC;CACtE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI,yBAAS,IAAI,IAA8B;CAC/C,IAAI,2BAAW,IAAI,IAAyC;CAC5D,IAAI,2BAAW,IAAI,IAA0B;CAC7C,IAAI,WAAW;CAEf,MAAM,eAAe;EACnB,UAAU,KAAA;EACV,UAAU,KAAA;EACV,QAAQ,KAAA;EACR,yBAAS,IAAI,IAAI;EACjB,2BAAW,IAAI,IAAI;EACnB,2BAAW,IAAI,IAAI;CACrB;CAGA,MAAM,UAAU,UAAiB,MAAM,eAAe;CACtD,MAAM,mBAAmB,OAAO;CAEhC,GAAG,OAAO,iBAAiB,oBAAoB,MAAM;CACrD,GAAG,OAAO,iBAAiB,wBAAwB,UAAU;CAE7D,MAAM,YAAY,EAAE,UAAU,YAAY,iBAAgC;EACxE,GAAG,aAAa,QAAQ;EACxB,IAAI,YAAY,GAAG,aAAa,UAAU;EAE1C,KAAK,MAAM,EAAE,OAAO,cAAc,WAAW,OAAO,GAAG;GACrD,GAAG,kBAAkB,KAAK;GAC1B,GAAG,aAAa,QAAQ;EAC1B;CACF;CAEA,MAAM,WACJ,MACA,WACA,eAC2B;EAC3B,IAAI,YAAY,OAAO,IAAI,IAAI;EAE/B,IAAI,CAAC,WAAW;GACd,YAAY;IAAE,UAAU,mBAAmB,IAAI,IAAI;IAAG,4BAAY,IAAI,IAAI;GAAE;GAC5E,OAAO,IAAI,MAAM,SAAS;EAC5B;EAEA,IAAI,QAAQ,UAAU,WAAW,IAAI,SAAS;EAE9C,IAAI,CAAC,OAAO;GACV,QAAQ,qBAAqB,IAAI,MAAM,UAAU,UAAU,cAAc,MAAM,SAAS,CAAC;GAEzF,IAAI,YAAY;IACd,UAAU,eAAe,GAAG,aAAa;IACzC,GAAG,gBAAgB,MAAM,KAAK;IAC9B,GAAG,WAAW,GAAG,cAAc,UAAU,UAAU;IACnD,GAAG,WAAW,GAAG,cAAc,YAAY,GAAG,WAAW;IAGzD,MAAM,SAAA;IAEN,GAAG,wBAAwB,oBAAoB,SAAS;IACxD,GAAG,oBAAoB,oBAAoB,WAAW,GAAG,GAAG,OAAO,OAAO,QAAQ,CAAC;IACnF,GAAG,wBAAwB,oBAAoB,UAAU;IACzD,GAAG,oBAAoB,oBAAoB,YAAY,GAAG,GAAG,OAAO,OAAO,QAAQ,EAAE;IACrF,GAAG,gBAAgB,IAAI;IACvB,GAAG,WAAW,GAAG,cAAc,IAAI;GACrC;GAEA,UAAU,WAAW,IAAI,WAAW,KAAK;EAC3C;EAEA,OAAO,MAAM;CACf;CAEA,MAAM,aAAa,UAA+C;EAChE,IAAI,UAAU,SAAS,IAAI,KAAK;EAEhC,IAAI,CAAC,SAAS;GACZ,UAAU,cAAc,IAAI,WAAW,KAAK,CAAC;GAC7C,SAAS,IAAI,OAAO,OAAO;EAC7B;EAEA,OAAO;CACT;CAEA,MAAM,aAAa,UAAsC;EACvD,MAAM,MAAM,KAAK,UAAU,KAAK;EAChC,IAAI,UAAU,SAAS,IAAI,GAAG;EAE9B,IAAI,CAAC,SAAS;GACZ,UAAU,cAAc,IAAI,KAAK;GACjC,SAAS,IAAI,KAAK,OAAO;EAC3B;EAEA,OAAO;CACT;CAEA,MAAM,UACJ,OACA,QAAoB,CAAC,GACrB,EAAE,aAA4B,CAAC,MACnB;EACZ,IAAI,UAAU,MAAM,IAAI,MAAM,iCAAiC;EAC/D,IAAI,GAAG,cAAc,GAAG,OAAO;EAC/B,YAAY,kBAAkB,EAAE;EAEhC,MAAM,SAAS;EAEf,MAAM,SAAkC,GAAG,aAAa,GAAG,mBAAmB;EAC9E,MAAM,CAAC,MAAM,QAAQ,OAAO,UAA4C,WACpE;GAAC,SAAS;GAAG,SAAS;GAAG,SAAS;GAAO,SAAS;EAAM,IACxD,SACE;GAAC;GAAG;GAAG,GAAG,aAAa,GAAG,QAAQ,CAAC,CAAC;GAAI,GAAG,aAAa,GAAG,QAAQ,CAAC,CAAC;EAAE,IACvE;GAAC;GAAG;GAAG,GAAG;GAAoB,GAAG;EAAmB;EAG1D,MAAM,SAAS,SAAiB;GAC9B,IAAI,UAAU;IACZ,GAAG,OAAO,GAAG,YAAY;IACzB,GAAG,QAAQ,MAAM,QAAQ,OAAO,MAAM;GACxC;GACA,GAAG,MAAM,IAAI;GACb,GAAG,QAAQ,GAAG,YAAY;EAC5B;EAIA,MAAM,QAAQ,QAAQ,YAAY;GAAE,GAAG,IAAI;GAAO,GAAG,KAAK;GAAQ,GAAG;EAAE,CAAC;EACxE,MAAM,aAAa,QAAQ,SAAS,OAAO,MAAM,UAAU;EAC3D,MAAM,iBAAiB,QAAQ,SAAS,YAAY,MAAM,IAAI;EAE9D,MAAM,mBAAmB;GACvB,GAAG,gBAAgB,GAAG,aAAa,MAAM;GACzC,GAAG,SAAS,MAAM,QAAQ,OAAO,MAAM;GACvC,GAAG,WAAW,OAAO,MAAM;GAC3B,GAAG,eAAe,GAAG,gBAAA,GAA+B,OAAO,UAAU;GACrE,iBAAiB,IAAI,QAAQ;IAAE,GAAG;IAAO;GAAW,CAAC;GAGrD,GAAG,QAAQ,GAAG,MAAM;GACpB,GAAG,QAAQ,GAAG,YAAY;GAC1B,GAAG,QAAQ,GAAG,YAAY;GAC1B,GAAG,QAAQ,GAAG,eAAe;GAC7B,GAAG,QAAQ,GAAG,wBAAwB;GACtC,GAAG,QAAQ,GAAG,mBAAmB;GACjC,GAAG,QAAQ,GAAG,kBAAkB;GAChC,GAAG,OAAO,GAAG,UAAU;GACvB,GAAG,UAAU,GAAG,IAAI;GACpB,GAAG,UAAU,IAAI;GACjB,GAAG,WAAW,GAAG,CAAC;GAClB,GAAG,UAAU,MAAM,MAAM,MAAM,IAAI;GAEnC,GAAG,eAAe,oBAAoB,KAAK,GAAG,CAAC;GAC/C,GAAG,eAAe,oBAAoB,KAAK,GAAG,CAAC;GAC/C,GAAG,eAAe,oBAAoB,QAAQ,GAAG,GAAG,CAAC;GACrD,GAAG,OAAO,GAAG,SAAS;GACtB,GAAG,UAAU,GAAG,GAAG;GACnB,GAAG,cAAc,GAAG,QAAQ;GAC5B,GAAG,kBAAkB,GAAG,WAAW,GAAG,qBAAqB,GAAG,MAAM,GAAG,GAAG;EAC5E;EAGA,MAAM,gBAAgB;GACpB,GAAG,gBAAgB,IAAI;GACvB,GAAG,YAAA,GAA0B,IAAI;GACjC,GAAG,YAAA,GAA8B,IAAI;GACrC,GAAG,YAAA,GAAyB,IAAI;EAClC;EAEA,MAAM,kBAAkB,OAA+B,UAA4B;GACjF,MAAM,QAAsB,CAAC;GAE7B,KAAK,MAAM,EAAE,UAAU,SAAS,aAAa,OAC3C,cAAc,UAAU,MAAM,MAAM,SAAS,uBAAO,IAAI,IAAI,GAAG,OAAO;GAExE,YAAY,qBAAqB,EAAE;GACnC,QAAQ,QAAQ,OAAO;IAAE;IAAI,MAAM,MAAM;IAAM;IAAY;GAAM,CAAC;EACpE;EAEA,MAAM,YAAY,QAAgB,SAAuC;GACvE,KAAK,MAAM,QAAQ,MAAM,OAAO;IAC9B,MAAM,MACJ,KAAK,WAAW,WAAW,OAAO,KAAK,IAAI,KAAK,QAAQ,MAAM,KAAK,QAAQ,KAAA;IAC7E,IAAI,CAAC,KAAK;IACV,QAAQ;IACR,IAAI;KAAE;KAAI;KAAO;KAAgB;IAAe,CAAC;IACjD,WAAW;GACb;EACF;EAEA,WAAW;EAEX,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;EAE1B,GAAG,WAAW,GAAG,GAAG,GAAG,CAAC;EACxB,GAAG,WAAW,CAAC;EACf,MAAM,GAAG,mBAAmB,GAAG,gBAAgB;EAE/C,IAAI,kBAAkB;EACtB,IAAI,YAAY;EAChB,IAAI;EACJ,MAAM,wBAAQ,IAAI,IAAe;EAEjC,MAAM,WAAW,SAAe;GAC9B,IAAI,KAAK,WAAW,MAAM,IAAI,KAAK,IAAI;GACvC,gBAAgB,IAAI,QAAQ,IAAI;GAEhC,MAAM,CAAC,WAAW,YAAY,KAAK,cAAc;GAEjD,GAAG,WAAW,WAAY,QAAS;GAEnC,IAAI,KAAK,SAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS;QAC5C;IACH,GAAG,OAAO,GAAG,SAAS;IACtB,GAAG,SAAS,KAAK,SAAS,SAAS,GAAG,OAAO,GAAG,KAAK;GACvD;GAEA,GAAG,UAAU,KAAK,UAAU;GAC5B,GAAG,UAAU;IAAE,MAAM,GAAG;IAAM,QAAQ,GAAG;IAAQ,QAAQ,GAAG;GAAO,EAAE,KAAK,UAAU;GAEpF,IAAI,KAAK,WAAW;IAClB,GAAG,OAAO,GAAG,mBAAmB;IAChC,GAAG,cAAc,GAAG,CAAC,KAAK,SAAS;GACrC,OAAO,GAAG,QAAQ,GAAG,mBAAmB;GAGxC,IAAI,mBAAmB,CAAC,KAAK,cAAc;IACzC,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;IAE1B,GAAG,UAAU,OAAO,SAAS,cAAc,GAAG,GAAG,CAAC;GACpD;GAEA,kBAAkB,KAAK,iBAAiB,KAAA;GAGxC,IAAI,KAAK,WAAW,GAAG,UAAU,OAAO,SAAS,YAAY,CAAC;QACzD,IAAI,KAAK,QAAQ,UAAU,IAAI,OAAO,UAAU,KAAK,MAAM;QAC3D,IAAI,WAAW,UAAU,IAAI,OAAO,UAAU,MAAM,MAAM;QAC1D,GAAG,UAAU,OAAO,SAAS,YAAY,MAAM,OAAO,MAAM;GAEjE,IAAI,KAAK,QAAQ,YAAY;QACxB,IAAI,CAAC,KAAK,WAAW,YAAY;GAEtC,GAAG,iBACD,OAAO,SAAS,YAChB,OACA,QAAQ,QAAQ,KAAK,aAAa,QAAQ,SAAS,OAAO,KAAK,UAAU,IAAI,UAAU,CACzF;GAEA,IAAI,KAAK,OAAO;IACd,GAAG,OAAO,GAAG,KAAK;IAElB,MAAM,CAAC,QAAQ,eAAe;KAC5B,OAAO,CAAC,GAAG,WAAW,GAAG,mBAAmB;KAC5C,KAAK,CAAC,GAAG,KAAK,GAAG,GAAG;KACpB,UAAU,CAAC,GAAG,WAAW,GAAG,GAAG;KAC/B,UAAU,CAAC,GAAG,WAAW,GAAG,IAAI;KAChC,QAAQ,CAAC,GAAG,KAAK,GAAG,mBAAmB;KACvC,eAAe,CAAC,GAAG,KAAK,GAAG,mBAAmB;IAChD,EAAE,KAAK;IAEP,GAAG,kBAAkB,QAAS,aAAc,GAAG,MAAM,GAAG,GAAG;GAC7D,OAAO,GAAG,QAAQ,GAAG,KAAK;GAE1B,GAAG,cAAc,GAAG,WAAA,CAAuB;GAC3C,GAAG,YAAY,GAAG,YAAY,KAAK,UAAU,UAAU,KAAK,QAAQ,KAAK,IAAI,IAAI;GACjF,GAAG,YAAA,GAA0B,UAAU,KAAK,SAAS,WAAW,eAAe,CAAC;GAEhF,GAAG,cAAc,GAAG,WAAA,CAA2B;GAC/C,GAAG,YACD,GAAG,kBACH,KAAK,qBAAqB,UAAU,KAAK,kBAAkB,IAAI,IACjE;GACA,GAAG,YAAA,GAA8B,UAAU,eAAe,CAAC;GAE3D,MAAM,SAAS,KAAK,QAAQ;GAE5B,GAAG,cAAc,GAAG,WAAA,CAAsB;GAC1C,GAAG,YAAY,GAAG,YAAY,SAAS,UAAU,OAAO,KAAK,IAAI,IAAI;GACrE,GAAG,YAAA,GAAyB,UAAU,QAAQ,WAAW,eAAe,CAAC;GAEzE,IAAI,KAAK,QAAQ,KAAK,KAAK,UAAU,UAAU;IAC7C,GAAG,WAAW,GAAG,gBAAgB,OAAO,UAAU;IAClD,GAAG,cAAc,GAAG,gBAAgB,GAAG,KAAK,KAAK,KAAK;IACtD,GAAG,WAAW,GAAG,gBAAgB,IAAI;IACrC,WAAW,KAAK,KAAK;GACvB;GAEA,GAAG,gBAAgB,QAAQ,KAAK,MAAM,KAAK,WAAW,KAAK,MAAM,UAAU,CAAC;GAC5E,GAAG,aAAa,SAAS,KAAK,KAAK,SAAS,GAAG,KAAK,OAAO,GAAG,gBAAgB,KAAK,UAAU;EAC/F;EAEA,MAAM,MAAM,SAAS,MAAM,OAAO;GAChC,SAAS,EAAE;GACX,QAAQ,IAAI;EACd,CAAC;EAED,GAAG,QAAQ,GAAG,mBAAmB;EAEjC,SAAS,MAAM,MAAM,SAAS,SAAS,SAAS,KAAK;EAErD,IAAI,MAAM,QAAQ,QAAQ;GACxB,YAAY,qBAAqB,EAAE;GACnC,QAAQ,KAAK,MAAM,SAAS;IAC1B;IACA,MAAM,MAAM;IACZ;IACA,KAAK,MAAM;IACX,WAAW,MAAM;IACjB,cAAc,EAAE,cAAc;KAC5B,GAAG,cAAc,GAAG,WAAA,CAAuB;KAC3C,GAAG,YAAY,GAAG,YAAY,UAAU,UAAU,QAAQ,KAAK,IAAI,IAAI;KAEvE,GAAG,YAAA,GAA0B,UAAU,cAAc,CAAC;KACtD,OAAO,YAAY,KAAA;IACrB;GACF,CAAC;GACD,WAAW;EACb;EAEA,IAAI,MAAM,UAAU,UAAU,MAAM,OAAO;GAEzC,WAAW;GACX,kBAAkB;GAClB,YAAY;GACZ,MAAM,UAAU,QAAQ,OAAO;GAC/B,IAAI,MAAM,OAAO,QAAQ,MAAM,KAAK;GACpC,WAAW;EACb;EAEA,IAAI,MAAM,aAAa,QAAQ;GAC7B,UAAU,yBAAyB,EAAE;GACrC,MAAM,KACJ,MAAM,aACN;IAAE;IAAO;GAAO,IACf,EAAE,cAAc;IACf,GAAG,cAAc,GAAG,WAAA,CAAuB;IAC3C,GAAG,YAAY,GAAG,YAAY,UAAU,OAAO,CAAC;IAEhD,GAAG,YAAA,GAA0B,UAAU,cAAc,CAAC;GACxD,GACA,MAAM,SACR;GACA,WAAW;EACb;EAGA,kBAAkB;EAClB,YAAY;EAEZ,IAAI,MAAM,YAAY;GAEpB,GAAG,UAAU,IAAI;GACjB,MAAM,GAAG,gBAAgB;EAC3B;EAEA,MAAM,cAAc,QAAQ,OAAO;EACnC,GAAG,WAAW,GAAG,CAAC;EAClB,SAAS,MAAM,MAAM,SAAS,SAAS,SAAS,KAAK;EACrD,SAAS,MAAM;EAEf,IAAI,MAAM,OAAO,QAAQ;GACvB,WAAW;GACX,kBAAkB;GAClB,YAAY;GACZ,MAAM,MAAM,QAAQ,OAAO;GAC3B,GAAG,WAAW,GAAG,CAAC;EACpB;EAEA,QAAQ;EAER,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,YAAY,OAAO,IAAI,IAAI;GACjC,IAAI,WAAW,SAAS,SAAS;GACjC,OAAO,OAAO,IAAI;EACpB;EAEA,OAAO;CACT;CAEA,MAAM,cAAc,UAA6C;EAC/D,IAAI,cAAc,OAAO;GACvB,MAAM,YAAY,OAAO,IAAI,KAAK;GAClC,IAAI,WAAW,SAAS,SAAS;GACjC,OAAO,OAAO,KAAK;GACnB;EACF;EAEA,MAAM,UAAU,SAAS,IAAI,KAAK;EAClC,IAAI,SAAS,GAAG,cAAc,OAAO;EACrC,SAAS,OAAO,KAAK;CACvB;CAEA,MAAM,gBAAgB;EACpB,IAAI,UAAU;EACd,WAAW;EACX,GAAG,OAAO,oBAAoB,oBAAoB,MAAM;EACxD,GAAG,OAAO,oBAAoB,wBAAwB,UAAU;EAEhE,IAAI,CAAC,GAAG,cAAc,GAAG;GACvB,KAAK,MAAM,aAAa,OAAO,OAAO,GAAG,SAAS,SAAS;GAC3D,KAAK,MAAM,WAAW,SAAS,OAAO,GAAG,GAAG,cAAc,OAAO;GACjE,KAAK,MAAM,WAAW,SAAS,OAAO,GAAG,GAAG,cAAc,OAAO;GACjE,SAAS,QAAQ;GACjB,OAAO,QAAQ;GAEf,IAAI,SAAS;IACX,GAAG,cAAc,QAAQ,MAAM;IAC/B,GAAG,aAAa,QAAQ,UAAU;GACpC;EACF;EAEA,OAAO;CACT;CAEA,OAAO;EAAE;EAAQ;EAAY;CAAQ;AACvC;;ACpfA,MAAM,QAAQ,SAAiB,QAAiC;CAAE,IAAI;CAAQ;CAAS;AAAG;AAC1F,MAAM,QAAQ,SAAiB,QAAiC;CAAE,IAAI;CAAQ;CAAS;AAAG;;;;;;;;AAS1F,MAAa,eAA2C;CACtD,KAAK,YAAY,UAAU;CAC3B,KAAK,YAAY,QAAQ;CACzB,KAAK,iBAAiB,MAAM;CAC5B,KAAK,sBAAsB,SAAS;CACpC,KAAK,iBAAiB,qBAAqB;CAC3C,KAAK,kBAAkB,WAAW;CAClC,KAAK,gBAAgB,WAAW;CAChC,KAAK,aAAa,sBAAsB;CACxC,KAAK,iBAAiB,sBAAsB;CAC5C,KAAK,UAAU,iBAAiB;CAChC,KAAK,iBAAiB,uBAAuB;CAC7C,KAAK,aAAa,mBAAmB;CACrC,KAAK,cAAc,mBAAmB;CACtC,KAAK,aAAa,mBAAmB;CACrC,KAAK,aAAa,mBAAmB;CACrC,KAAK,aAAa,mBAAmB;CACrC,KAAK,aAAa,mBAAmB;CACrC,KAAK,oBAAoB,iBAAiB;CAC1C,KAAK,cAAc,mBAAmB;CACtC,KAAK,aAAa,mBAAmB;CACrC,KAAK,gBAAgB,iBAAiB;CACtC,KAAK,gBAAgB,qBAAqB;CAC1C,KAAK,UAAU,cAAc;AAC/B;AAKA,MAAM,WAAW;AAGjB,MAAM,eAAe;;;;;AAMrB,MAAa,mBACX,EAAE,MAAM,QACR,QAAoC,iBACzB;CACX,MAAM,UAAU,KAAK,MAAM,GAAG,YAAY,CAAC,CAAC,YAAY;CACxD,MAAM,WAAW,KAAK,MAAM,GAAG,YAAY;CAE3C,IAAI,SAAS,KAAK,OAAO,GAAG,OAAO;CAEnC,KAAK,IAAI,KAAK,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM;EAC7C,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK,QAAQ,KAAK,KAAK,OAAO,SAAS,UAAU,QAAQ,GAAG,OAAO,KAAK;CAC9E;CAEA,OAAO;AACT;;AAGA,MAAa,mCAAwC,IAAI,IAAI;CAC3D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;;;ACxGD,MAAa,cAAc,EAAE,UAAU,kBACrC,QAAQ,OAAO,QAAQ,wBAAwB,aAAa,QAAQ,CAAC;AAQvE,MAAMC,OAAI,KAAK;;;;;;AAOf,MAAa,cACX,GACA,QACA,MACA,EAAE,OAAO,aACG;CAEZ,IAAI,EAAE,KAAK,IAAI,CAAC,KAAK,OAAS,OAAO;CAErC,MAAM,OAAOA,KAAE,KAAK,KAAK,OAAO,SAAS,KAAK,KAAK,IAAI,CAAC;CACxD,MAAM,OAAOA,KAAE,QAAQ,QAAQ,OAAO;CACtC,MAAM,SAASA,KAAEA,MAAG,QAAQ,KAAK,EAAG,IAAI,IAAI;CAC5C,MAAM,SAASA,KAAE,EAAEA,MAAG,SAAS,KAAK,EAAG,IAAI,KAAK;CAChD,MAAM,IAAI,EAAE,SAAS;CAErB,OAAO,SAAS,SAAS,IAAI,IAAIA,KAAE,CAAC,KAAK,EAAE,IAAI;AACjD;AAsBA,SAAgB,eACd,EAAE,GAAG,GAAG,KACR,QACA,EAAE,MAAM,MAAM,OACd,QACA,UACe;CACf,MAAM,WAAW,CAAC,IAAI;CACtB,MAAM,UAAU,SAAS;CACzB,IAAI,UAAU,QAAQ,WAAW,KAAK,OAAO;CAI7C,MAAM,OAAO,KAAK,IAAK,OAAO,KAAK,KAAM,GAAG;CAC5C,MAAM,OAAO,OAAO;CACpB,MAAM,aAAa,KAAK,IAAI,CAAC,IAAI,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI;CAC/D,MAAM,aAAa,KAAK,IAAI,CAAC,IAAI,OAAO,KAAK,KAAK,MAAM,GAAG,IAAI;CAC/D,IAAI,YAAY,UAAU,YAAY,QAAQ,OAAO;CACrD,IAAI,YAAY,WAAW,GAAG,QAAQ,MAAM,QAAQ,GAAG,OAAO;CAC9D,OAAO,WAAW,QAAQ,UAAU,OAAO,YAAY,CAAC,UAAU,YAAY,CAAC,SAAS,IAAI;AAC9F;;AAGA,MAAa,mBACX,QACA,QACA,QACA,QACA,aACY,eAAe,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,KAAK;;;;;;AAO1E,MAAa,oBAAoB,EAAE,MAAM,MAAM,OAAe,WAE5D,QAAQ,cAAc,IAAI,KAAK,KAAK,KAAK,IAAK,OAAO,KAAK,KAAM,GAAG,IAAI,MAAM,GAAG,QAAQ,MAAM,GAAG;;;;;;;AC5FnG,MAAa,qBAAqB,EAAE,YAA0B,SAA8B;CAC1F,MAAM,QAAQ,SAAS,QAAQ,KAAK,EAAE,eAAe,MAAM,UAAU,CAAC;CACtE,IAAI,CAAC,SAAS,UAAU,EAAE,QAAQ,IAAI,OAAO;EAAE,QAAQ,CAAC,GAAG,CAAC;EAAG,OAAO,CAAC,GAAG,CAAC;CAAE;CAE7E,IAAI,UAAU,KAAK,IAAI,GAAG,IAAI,IAAI;CAElC,IAAI,YAAY,KAAK,OAAO,GAAG,UAAU;CAEzC,IAAI,KAAK;CAGT,OAAO,KAAK,SAAS,SAAS,KAAK,UAAU,SAAS,GAAG,CAAE,UAAU;EACnE,WAAW,SAAS,GAAG,CAAE;EACzB;CACF;CAEA,MAAM,EAAE,OAAO,aAAa,SAAS;CAErC,OAAO;EACL,QAAQ,CACN,MAAM,UAAU,SAAS,UAAU,SACnC,MAAM,UAAU,SAAS,UAAU,OACrC;EACA,OAAO,CACL,IAAI,MAAM,SAAS,SAAS,SAAS,SACrC,IAAI,MAAM,SAAS,SAAS,SAAS,OACvC;CACF;AACF;;;ACnBA,MAAM,cAAc;AACpB,MAAM,aAAa;;AAGnB,MAAa,YAAY,WAAoD;CAC3E,MAAM,MAAM,SAAS;CACrB,MAAM,QAAQ,MAAM,UAAU,IAAI,KAAK,KAAM,MAAO,SAAS,OAAQ,IAAI;CAEzE,OAAO;EAAE;EAAK,OAAO,KAAK,OAAO,KAAK;CAAE;AAC1C;;;;;;AAOA,MAAM,cACJ,OACA,MACA,OACA,WACkE;CAClE,IAAI,UAAU,GAAG,OAAO,KAAA;CAExB,MAAM,SAAS,KAAK,YAAY;CAChC,MAAM,OAAO,MAAM,MAAM,EAAE,UAAU,QAAQ,KAAA,KAAa,IAAI,YAAY,MAAM,MAAM;CACtF,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,MAAM,EAAE,KAAK,UAAU,SAAS,MAAM;CAEtC,MAAM,SAAS,OAAe,KAAK,OAAO,OAAO;CACjD,MAAM,OAA+B,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,KAAA,CAAS;CAGlF,MAAM,OAAO,MAAM;CACnB,MAAM,UAAU,KAAK,eAAe,KAAK,OAAO,SAAS,IAAI,IAAI;CACjE,MAAM,MAAM,MAAM,KAAK,IAAI,SAAS,KAAK,IAAI;CAC7C,IAAI,UAAU;CAEd,OAAO,UAAU,KAAK,WAAW;EAC/B,IAAI,MAAM,UAAU,CAAC,IAAI,GAAG;EAC5B,KAAK,WAAW;CAClB;CAEA,IAAI,WAAW,OAAO,OAAO;EAAE;EAAM,SAAS;CAAG;CAGjD,MAAM,WAAW,MAAM,KAAK,IAAI,cAAc,QAAQ,MAAM,KAAK,IAAI;CACrE,IAAI,UAAU,KAAK,IAAI,IAAI,MAAM,OAAO,CAAC;CAEzC,KAAK,IAAI,QAAQ,SAAS,QAAQ,OAAO,SAAS;EAChD,IAAI,MAAM,MAAM,QAAQ,CAAC;EACzB,IAAI,EAAE,OAAO,IAAI;EACjB,IAAI,YAAY,MAAM,QAAQ,YAAY,MAAM,QAAQ;EACxD,UAAU,KAAK,IAAI,SAAS,KAAK,OAAO,GAAG,CAAC;EAC5C,KAAK,SAAS,KAAK,OAAO,cAAc,GAAG;CAC7C;CAEA,OAAO;EAAE;EAAM;CAAQ;AACzB;AAEA,MAAM,cAAc,WAClB,OAAO,SAAS,cAAc,KAAK,OAAO,UAAU,CAAC,GAAG,GAAG,EAAA,CAAG,SAAS;;;;;AAMzE,MAAa,YACX,OACA,OACA,EAAE,SAAS,QAAoB,CAAC,MACrB;CACX,IAAI,UAAU;CAEd,KAAK,MAAM,EAAE,QAAQ,UAAU,OAAO;EACpC,MAAM,SAAS,WAAW,WAAW,MAAM,GAAG,MAAM,OAAO,MAAM;EACjE,IAAI,QAAQ,UAAU,KAAK,IAAI,SAAS,OAAO,OAAO;CACxD;CAEA,OAAO;AACT;AAGA,MAAM,OAAO,CAAC,GAAG,GAAG;;;;;;;AAQpB,MAAa,aACX,QACA,MACA,QAA4B,CAAC,GAC7B,EAAE,SAAS,QAAoB,CAAC,MACnB;CAEb,MAAM,QADW,OAAO,SAAS,cAAc,OAAQ,OAAO,UAAU,CAAC,GAAG,GAAG,EAAA,CACzD,MAAM,CAAC;CAC7B,MAAM,SAAS,WAAW,KAAK,QAAQ,MAAM,OAAO,MAAM;CAE1D,OAAO,SAAS,KAAK,KAAK,KAAK,OAAO,OAAO,KAAK,OAAO,GAAG,IAAI;AAClE;;;;;AAMA,MAAa,WACX,QACA,QACA,SAC0B;CAC1B,MAAM,QAAQ,KAAK,WAAW,QAAQ,OAAO,MAAM;CACnD,IAAI,QAAQ,GAAG,OAAO,KAAA;CACtB,OAAO,OAAO,SAAS,cAAc,SAAS,OAAO,OAAO;AAC9D;AAEA,MAAa,eAAe,EAAE,GAAG,GAAG,QAClC,KAAK,IAAI,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,GAAG,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK;;;;;;;AAQ/F,MAAa,eACX,QACA,MACA,WACA,WACW;CAEX,MAAM,UADQ,OAAO,SAAS,cAAc,SAAS,OAAO,OAAO,GAAA,EAC7C,UAAU,eAAe,UAAU;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC5E,MAAM,EAAE,MAAM,QAAQ,eAAe,QAAQ,QAAQ,SAAS,WAAW,MAAM,GAAG,IAAI,CAAC;CAEvF,OAAQ,KAAK,IAAI,CAAC,IAAI,KAAK,IAAK,OAAO,OAAO,KAAK,KAAM,GAAG,IAAK,YAAY,SAAS;AACxF;;ACUA,MAAa,sBAA6C;CACxD,iBAAiB;CACjB,cAAc;CACd,aAAa;AACf;AAyLA,MAAM,UAAmD;CACvD,MAAM;CACN,QAAQ;CACR,UAAU;CACV,YAAY;CACZ,SAAS;CACT,WAAW;CACX,aAAa;CACb,eAAe;CACf,QAAQ;CACR,qBAAqB;CACrB,wBAAwB;CACxB,MAAM;CACN,SAAS;CACT,UAAU;CACV,oBAAoB;CACpB,QAAQ;CACR,WAAW;CACX,iBAAiB;CACjB,iBAAiB;CACjB,uBAAuB;CACvB,qBAAqB;CAErB,eAAe;CACf,sBAAsB;CAEtB,mBAAmB;CACnB,eAAe;CACf,iBAAiB;CAGjB,aAAa;CACb,mBAAmB;CAEnB,+BAA+B;CAC/B,0BAA0B;CAC1B,wBAAwB;CACxB,oBAAoB;AACtB;;AAGA,MAAa,eAAe,SAA0B,QAAQ;AAE9D,MAAM,UAAU,YAAyC;CACvD,IAAI,YAAY,eAAe,MAAM,OAAO;CAC5C,IAAI,YAAY,eAAe,QAAQ,OAAO;CAC9C,IAAI,YAAY,eAAe,OAAO,OAAO;CAC7C,MAAM,IAAI,WAAW,yDAAyD;AAChF;AAEA,MAAM,eAAe,EAAE,SAA2B,EAAE,MAAM,aAAiC;CACzF;CACA;CACA,SAAS;EACP,GAAG;EACH,OAAO,OAAO,WAAW,OAAO,GAAG,CAAC;EACpC,OAAO,OAAO,WAAW,OAAO,GAAG,CAAC;CACtC;CAEA,OAAO,YAAY,KAAK;AAC1B;;;;;AAMA,MAAM,aAAa,UAA4C;CAC7D,IAAI,CAAC,SAAS,MAAM,SAAS,YAAY,OAAO;CAEhD,QAAQ,MAAM,QAAd;EACE,KAAK;EACL,KAAK,eACH,OAAO;EAET,KAAK,eACH,OAAO;EACT,KAAK;EACL,KAAK;EACL,KAAK,eACH,OAAO;EACT,SACE,OAAO;CACX;AACF;AAGA,MAAM,yBAAyB;AAC/B,MAAM,sBAAsB;AAE5B,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAG1C,MAAM,+BAA2C,IAAI,IAAI;CAAC;CAAY;CAAY;AAAQ,CAAC;AAG3F,MAAM,cAAuB;CAAE,GAAG;CAAM,GAAG;CAAK,GAAG;AAAI;AACvD,MAAMC,WAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAgB1C,MAAM,iBAAiD,EAAE,kBAAkB,MAAM;AAGjF,MAAM,mBACJ,SAEA,OAAO;CAAE,kBAAkB;CAAM,aAAa;AAAK,IAAI;;;;;;;AAQzD,MAAM,UAAU;;;;;;;;AAShB,MAAM,SACJ,MACA,MACA,MACA,UACA,SACS;CACT,MAAM,QAAc;EAAE,GAAG;EAAM,kBAAkB;CAAM;CAEvD,OAAO,MAAM;CACb,IAAI,QAAQ,KAAK,IAAI,GAAG,OAAO;CAE/B,MAAM,SAAS,KAAK,SAAS,SAAS,WAAW,KAAK;CAEtD,IAAI,SAAS,SAAS,OAAO;EAAE,GAAG;EAAO;CAAM;CAC/C,OAAO,QAAQ,IACX;EAAE,GAAG;EAAO;EAAO,OAAO;EAAM,gBAAgB;CAAuB,IACvE;EAAE,GAAG;EAAO;EAAO,OAAO;CAAM;AACtC;AAGA,MAAM,cAAc,SAAyB;CAC3C,MAAM,QAAQ,KAAK,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC;CAE/C,OAAO,KAAK,OAAO,KAAK,IAAI,IAAI,SAAS,QAAQ,SAAS,GAAG,IAAI;AACnE;AAGA,MAAM,eAAe;;;;;;;AAWrB,MAAM,gBACJ,MACA,MACA,UACA,UACW;CACX,MAAM,SAAS;EACb,MAAM;EACN,eAAe;EACf,OAAO;EACP,kBAAkB,MAAM,gBAAgB,KAAA;CAC1C;CAEA,IAAI,SAAS,aACX,OAAO,CACL;EACE,GAAG;EACH,kBAAkB;EAClB,OAAO;EACP,gBAAgB;EAChB,MAAM;GAAE,MAAM,SAAS;GAAa,MAAM,SAAS,YAAY;EAAa;CAC9E,CACF;CAGF,MAAM,SAAS,SAAS;CACxB,MAAM,QAAQ,SACV;EAAE,MAAM,SAAS;EAAc,MAAM,SAAS,YAAY;CAAa,IACvE;EAAE,MAAM,SAAS;EAAc,MAAM,SAAS,aAAa;CAAa;CAC5E,MAAM,SAAS,SACX,OACA;EAAE,MAAM,SAAS;EAAc,MAAM,SAAS,aAAa;CAAa;CAC5E,MAAM,OAAO;EACX,GAAG;EACH,OAAO;EACP,gBAAgB;EAChB,WAAW;EACX,MAAM;CACR;CAEA,IAAI,SAAS,SACX,OAAO,CAEL;EACE,GAAG;EACH,OAAO;EACP,gBAAgB;EAChB,eAAe;EACf,MAAM;CACR,GACA;EAAE,GAAG;EAAM,YAAY;EAAO,OAAO;CAAK,CAC5C;CAEF,OAAO,CACL;EAAE,GAAG;EAAQ,OAAO;EAAO,gBAAgB;EAAM,eAAe;EAAQ,MAAM;CAAM,GACpF,IACF;AACF;AAEA,MAAM,YACJ,MACA,MACA,UACA,OACA,EAAE,sBACS;CACX,IAAI,SAAS,eAAe,SAAS,YAAY,SAAS,SACxD,OAAO,aAAa,MAAM,MAAM,UAAU,KAAK;CAGjD,IAAI,SAAS,cACX,OAAO,CACL;EACE,MAAM;EACN,eAAe;EACf,OAAO;EACP,gBAAgB;EAChB,OAAO;EACP,YAAY;EACZ,WAAW;EACX,GAAG,gBAAgB,MAAM,WAAW;CACtC,CACF;CAGF,IAAI,SAAS,cAAc,SAAS,cAAc,SAAS,UAAU,SAAS,UAAU;EACtF,MAAM,QAAc;GAClB,MAAM;GACN,eAAe;GACf,OAAO,SAAS;GAChB,gBAAgB;GAChB,OAAO;GACP,GAAI,SAAS,aAAa,EAAE,WAAW,MAAe,IAAI,CAAC;GAC3D,GAAI,SAAS,WAAW,EAAE,WAAW,WAAoB,IAAI,CAAC;GAE9D,GAAI,SAAS,aACT;IAAE,WAAW;IAAqB,WAAW;GAAkB,IAC/D,CAAC;GACL,GAAG,gBAAgB,MAAM,WAAW;EACtC;EAEA,OAAO,KAAK,SAAS,KAAK,IACtB,CAAC,OAAO;GAAE,GAAG;GAAO,MAAM;GAAS,eAAe;EAAK,CAAC,IACxD,CAAC,KAAK;CACZ;CAEA,IAAI,SAAS,aAAa,SAAS,aAAa,SAAS,eAAe,SAAS,SAAS;EACxF,MAAM,QAAQ,SAAS,kBAAkB,MAAM,QAAQ,SAAS,eAAe,IAAI;EAEnF,MAAM,eAAe,SAAS,WAAW,KAAK,KAAK,UAAU,KAAK,IAAI;EAEtE,MAAM,WAAW,SAAS,aAAa,SAAS,cAAc,MAAM,UAAU,QAAQ,KAAA;EACtF,MAAM,QAAQ,YAAY,SAAS;EAEnC,OAAO,CACL;GAIE,MAAM;GACN,eAAe;GACf,OAAO,SAAS,eAAe,gBAAgB,YAAY,KAAK;GAChE,gBAAgB;GAChB,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;GAEvC,GAAI,SAAS,UAAU;IAAE,YAAY;IAAO,WAAW;GAAkB,IAAI,CAAC;GAC9E,GAAG,gBAAgB,MAAM,WAAW;EACtC,CACF;CACF;CAEA,IAAI,SAAS,SACX,OAAO,CACL;EAEE,MAAM;EACN,YAAY;EACZ,eAAe;EACf,OAAO;EACP,gBAAgB;EAKhB,OAAO,MAAM,eAAe,CAAC,MAAM,UAAU,IAAI,WAAW,MAAM,QAAQ,CAAC;EAC3E,GAAG;CACL,CACF;CAEF,MAAM,UAAU,SAAS,WAAW;CAEpC,IAAI,SAAS,SAAS;EAGpB,MAAM,SAAS;GAAE,eAAe;GAAO,gBAAgB;GAAwB,OADjE,KAAK,IAAI,SAAS,eACmD;EAAE;EAErF,OAAO,CACL;GAAE,GAAG;GAAQ,MAAM;GAAS,OAAO;GAAO,GAAG;EAAe,GAC5D;GACE,GAAG;GACH,MAAM;GACN,OAAO;GACP,GAAG,gBAAgB,MAAM,eAAe,aAAa;EACvD,CACF;CACF;CAEA,IAAI,SAAS,cAAc,SAAS,YAAY,SAAS,aAAa;EAGpE,MAAM,OAAO,SAAS,cAAc,CAAC,SAAS;EAC9C,MAAM,QAAc;GAClB,MAAM;GACN,eAAe;GACf,OAAO;GACP,gBAAgB;GAChB,GAAI,OAAO,gBAAgB,MAAM,WAAW,IAAI;EAClD;EAEA,IAAI,SAAS,YAAY,MAAM,QAAQ;EACvC,OAAO,SAAS,cACZ,CAAC,OAAO;GAAE,GAAG;GAAO,MAAM;GAAS,eAAe;EAAK,CAAC,IACxD,CAAC,KAAK;CACZ;CAEA,MAAM,QAAQ,SAAS,kBAAkB,MAAM,QAAQ,SAAS,eAAe,IAAI;CACnF,MAAM,OAAO,UAAU,KAAK;CAC5B,MAAM,QAAQ,UAAU,KAAK,OAAO;CACpC,MAAM,QAAc;EAClB,MAAM;EACN,eAAe;EACf;EAEA,gBAAgB,WAAW,KAAK,SAAS,IAAI,sBAAsB;EACnE,GAAI,CAAC,QAAQ,KAAK,IAAI,IAClB,gBAAgB,MAAM,WAAW,IACjC,EAAE,kBAAkB,CAAC,SAAS,MAAM,gBAAgB,KAAA,EAAU;CACpE;CACA,IAAI,SAAS,UAAU,OAAO,CAAC,KAAK;CAGpC,OAAO,CACL,OACA;EAAE,GAAG;EAAO,MAAM;EAAS,eAAe;EAAM,gBAAgB;CAAuB,CACzF;AACF;AAEA,MAAM,eACJ,MACA,MACA,OACA,WACA,EAAE,OAAO,QAAQ,KAAK,aACG;CACzB,IAAI,KAAK,SAAS,WAAW,CAAC,KAAK,MAAM,OAAO,KAAA;CAEhD,MAAM,SAAS,KAAK;CAEpB,IAAI,UAAU,KAAA,KAAa,QACzB,OAAO,QACL,QACA,YAAY,QAAQ,OAAO,WAAW,MAAM,GAC5C,UAAU,QAAQ,MAAM,KAAK,EAAE,OAAO,CAAC,CACzC,CAAC,EAAE;CAEL,IAAI,OAAO,SAAS,cAAc,OAAO,OAAO;CAChD,OAAO,OAAO,OAAO,KAAK,IAAI,SAAS,GAAG,OAAO,OAAO,SAAS,CAAC,EAAE,EAAE;AACxE;;AAGA,MAAa,cACX,MACA,WACA,UAAwB,CAAC,MACR;CAEjB,IAAI,KAAK,SAAS,YAAY;EAC5B,MAAM,YAAY,YAAY,MAAM,QAAQ,WAAW,WAAW,OAAO;EAEzE,OAAO,YAAY,CAAC;GAAE;GAAW,OAAO;EAAU,CAAC,IAAI,CAAC;CAC1D;CAEA,MAAM,QAAsB,CAAC;CAE7B,KAAK,MAAM,CAAC,MAAM,UAAU,eAAe,MAAM,WAAW,QAAQ,UAAU,GAAG;EAC/E,IAAI,QAAQ,WAAW,CAAC,QAAQ,QAAQ,IAAI,GAAG;EAE/C,MAAM,YAAY,YAAY,KAAK,MAAM,KAAK,MAAM,OAAO,WAAW,OAAO;EAC7E,IAAI,WAAW,MAAM,KAAK;GAAE;GAAW;EAAM,CAAC;CAChD;CAEA,OAAO;AACT;;;;;;AAeA,MAAM,WACJ,MACA,OACA,aACA,SACsB;CACtB,MAAM,QAAQ,MAAM,QAAQ,IAAI;CAChC,IAAI,SAAS,MAAM,SAAS,YAAY,OAAO;EAAE;EAAM;CAAM;CAE7D,MAAM,QAAQ,SAAS,WAAW,OAAO,cAAc,OAAO,MAAM,MAAM,GAAG,MAAM,OAAO;CAC1F,IAAI,OAAO,OAAO;CAClB,YAAY,IAAI,WAAW,MAAM;AAEnC;AAGA,MAAM,aAA+B;CAAE,MAAM;CAA4B,OAAO;AAAK;;AAGrF,MAAM,aACJ,EAAE,MAAM,QACR,YAC0B;CAC1B,IAAI,CAAC,MAAM,OAAO;EAAE,WAAW;EAAc;CAAK;CAElD,MAAM,QAAQ,QAAQ,KAAK,IAAI;CAC/B,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,OAAO;EAAE,WAAW;EAAc;EAAM,SAAS;GAAE,GAAG,YAAY,MAAM,KAAK;GAAG,OAAO;EAAE;CAAE;AAC7F;AAEA,MAAM,cAAc;;;;;AAMpB,MAAM,gBACJ,UACA,OACA,MACA,WACkD;CAClD,MAAM,QAAQ,SAAS,SAAA;CACvB,MAAM,OAAO,SAAS,QAAQ;CAE9B,MAAM,QAAQ,SAAS,SAAS;CAChC,MAAM,SAAS,QAAQ,eACrB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,GACnB,QAAQ,OAAO,QAAQ,SAAS,MAAM,KAAK,CAAC,CAC9C;CAGA,MAAM,SAAS,KAAK,MAAM,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC,KAAK;CAC3D,MAAM,SAAS,QAAQ,MAAM,SAAS;CACtC,MAAM,WAAW,SAAS;CAC1B,MAAM,SAAS,aAAa,QAAQ,IAAI,QAAQ,eAAe;CAC/D,MAAM,QAAQ,SAAS,SAAS;CAEhC,OAAO;EACL;EACA,YAAY;GACV,WAAW;IAAE,GAAG,OAAO,IAAI;IAAQ,GAAG,OAAO,IAAI;IAAQ,GAAG,OAAO,IAAI;GAAO;GAC9E,WAAW,SAAS;GACpB,MAAM,OAAO;GACb,GAAG,QAAQ,KAAM,KAAK,IAAI,SAAS,QAAQ,IAAI;EACjD;CACF;AACF;AAEA,MAAM,eACJ,MACA,EAAE,iBAAiB,eAAe,gBAClC,MACA,YAC0B;CAC1B,IAAI,SAAS,SAAS;EAEpB,MAAM,OAAO,gBAAgB;EAC7B,MAAM,QAAQ,QAAQ,KAAK,IAAI;EAC/B,IAAI,CAAC,OAAO,OAAO,KAAA;EACnB,OAAO;GAAE,WAAW;GAAO,SAAS;IAAE,GAAG,YAAY,MAAM,KAAK;IAAG,OAAO;GAAE;EAAE;CAChF;CAIA,IAAI,SAAS,cAAc,CAAC,iBAAiB,OAAO,KAAA;CACpD,IAAI,SAAS,cAAc,SAAS,YAAY,SAAS,aAAa,OAAO,KAAA;CAE7E,MAAM,YAAY,SAAS,aAAa,QAAQ;CAChD,MAAM,OAAO,SAAS,aAAa,kBAAkB;CACrD,IAAI,CAAC,MAAM,OAAO,EAAE,UAAU;CAE9B,MAAM,QAAQ,QAAQ,KAAK,IAAI;CAE/B,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,OAAO;EAAE;EAAW,SAAS,YAAY,MAAM,KAAK;CAAE;AACxD;;;;;;AAOA,MAAM,YACJ,KACA,OACA,QACA,QACA,EAAE,cAAc,mBACG;CACnB,YAAY;CACZ,WAAW;CACX,GAAI,QAAQ,aACR,EACE,YAAY,iBAAiB;EAAE,GAAG;EAAQ,MAAM;EAAc,KAAK;CAAY,GAAG,MAAM,EAC1F,IACA;EACE,OAAO,QAAQ,SAAS,QAAQ,YAAY,OAAO,QAAQ,GAAG,KAAK;EACnE,cAAcD;EACd,WAAW;CACb;AACN;;;;;;AAYA,MAAM,cACJ,MACA,WACA,OACA,SACW;CACX,MAAM,EAAE,GAAG,GAAG,GAAG,MAAM,QAAQ,SAAS,MAAM,KAAK;CACnD,MAAM,SAAS,iBAAiB,KAAK,MAAM;CAC3C,MAAM,QAAQ,IAAI,SAAS,KAAK,SAAS,QAAQ,KAAK,SAAS,UAAU;CACzE,IAAI,MAAM;CAEV,KAAK,IAAI,KAAK,GAAG,KAAK,UAAU,aAAa,MAAM;EACjD,MAAM,UAAU,UAAU,cAAc,MAAM;EAC9C,MAAM,KAAK,MAAM,WAAW,QAAQ,IAAI;EACxC,MAAM,KAAK,MAAM,WAAW,SAAS,GAAG,IAAI;EAC5C,MAAM,KAAK,MAAM,WAAW,SAAS,GAAG,IAAI;EAG5C,OAAO,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,EAAE;CAC5C;CAEA,OAAO,MAAM,UAAU;AACzB;;AAGA,MAAa,eAAe,QAAkB,UAAwB;CACpE,OAAO,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;CACvC,KAAK,MAAM,SAAS,QAAQ,MAAM,KAAK,GAAG,MAAM,KAAK;CACrD,OAAO,SAAS;AAClB;;AAGA,MAAa,gBACX,OACA,QACA,QACA,MACA,MACA,OAEA,QACA,aACA,cACA,SAAsB,qBAEtB,SAAS,OAET,aACS;CACT,MAAM,WAAoB,SAAS,QAAQ,MAAM,OAAO,aAAa,IAAI;CAEzE,KAAK,MAAM,QAAQ,MAAM,OAAO;EAC9B,MAAM,EACJ,WACA,OACA,MAAM,WACN,YAAY,cACZ,cACA,WACE;EACJ,MAAM,OAAO,aAAa,MAAM,KAAK,UAAU,MAAM;EAErD,IAAI,CAAC,MAAM;GACT,YAAY,IAAI,QAAQ,UAAU,QAAQ;GAC1C;EACF;EAIA,MAAM,SACJ,MAAM,QAAQ,eACV,QAAQ,SAAS,QAAQ,YAAY,OAAO,QAAQ,GAAG,KAAK,IAC5D;EACN,MAAM,EAAE,QAAQ,WAAW,UAAU;EACrC,MAAM,UACJ,UACA,gBACE,QAAQ,eAAe,QAAQ,QAAQ,SAAS,MAAM,MAAM,CAAC,IAC5D,SAAS,OAAQ,IAAI,UAAU,YAAY,KAAK,GACjD,QACA,QACA,QACF;EAEF,KAAK,MAAM,EAAE,YAAY,YAAY,kBAAkB,YAAY,MAAM,SAAS,GAAG;GACnF,MAAM,WAAW,MAAM,SAAS,gBAAgB,UAAU;GAE1D,IAAI,CAAC,UAAU;IACb,YAAY,IAAI,YAAY,gBAAgB,gBAAgB,YAAY;IACxE;GACF;GAEA,MAAM,OAAO,gBAAgB,UAAU,MAAM,WAAW;GAExD,IAAI,SAAS,gBAAgB;GAE7B,IAAI,CAAC,iBAAiB,IAAI,IAAI,GAAG;IAC/B,aAAa,IAAI,SAAS,IAAI;IAC9B;GACF;GAEA,MAAM,OAAO,QAAQ;GAErB,IAAI,CAAC,MAAM;IACT,YAAY,IAAI,SAAS,IAAI;IAC7B;GACF;GAEA,MAAM,EAAE,GAAG,GAAG,MAAM,SAAS,WAAWA;GAExC,MAAM,OACJ,SAAS,aACL,SAAS,kBACT,SAAS,SACP,KAAA,IACA,SAAS;GACjB,MAAM,QAAQ,QAAQ,QAAQ,KAAK,IAAI;GACvC,MAAM,SAAS,YAAY,MAAM,UAAU,MAAM,OAAO;GAExD,MAAM,QACH,SAAS,YAAY,SAAS,eAAe,SAAS,aAAa,SAAS,YAC7E,MAAM,qBACF,gBAAgB,MAAM,oBAAoB,SAAS,IAAI,IACvD,KAAA;GACN,MAAM,WACJ,SAAS,iBAAiB,KAAK,YAC3B;IAAE,QAAQ,KAAK;IAAW,OAAO,CAAC,GAAG,CAAC;GAAsB,IAC5D,QAAQ,kBAAkB,MAAM,IAAI;GAE1C,IAAI,CAAC,SAAS;GAGd,MAAM,SAAS,SAAS,MAAM,MAAM,UAAU,OAAO,MAAM,CAAC,CAAC,KAAK,SAChE,MAAM,WAAW,SAAS,UACtB,MAAM,MAAM,MAAM,MAAM,UAAU,MAAM,QAAQ,CAAC,IACjD,IACN;GACA,MAAM,SAAiB,CAAC;GAGxB,MAAM,aAAa,UAAU,CAAC,MAAM,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO,EAAE,CAAE;GAE5E,IAAI,YACF,OAAO,KAAK;IAAE,OAAO,WAAW,MAAM,WAAW,OAAO,IAAI;IAAG,OAAO;GAAO,CAAC;GAEhF,MAAM,QACJ,SAAS,eAAe,aAAa,UAAU,OAAO,MAAM,UAAU,CAAC,IAAI,KAAA;GAE7E,KAAK,MAAM,EACT,OACA,YACA,WACA,WACA,eACA,OACA,MACA,GAAG,UACA,QAAQ;IACX,MAAM,OAAO,KAAK,cAAc,QAAQ,KAAK,WAAW,CAAC,EAAE,QAAQ,KAAA;IACnE,MAAM,QAAQ,SAAS,KAAA,IAAY,SAAS,QAAQ,UAAU,MAAM,OAAO;IAC1E,CAAC,aAAa,SAAS,MAAA,CAAO,KAAK;KAClC;KACA;KACA,aAAa,aAAa,UAAU,cAAc,YAAY;KAC9D,OAAO;KAEP,OAAO,QAAQ,QAAQ,SAAS,OAAO,QAAQ,QAAQ,MAAM,KAAK,CAAC,IAAI;KACvE,cAAc,SAAS;KAEvB,SACE,SAAS,WAAW,aAAa,IAAI,IAAI,IACrC;MAAC;MAAG;MAAG;MAAG;KAAM,IAChB,SAAS,SACP;MAAC;MAAG;MAAG;MAAG;KAAC,IACX;MAAC;MAAG;MAAG;MAAG,SAAS,SAAS,WAAW;KAAC;KAEhD,SAAS,aAAa,IAAI,IAAI,IAC1BA,UACA,SAAS,SACPC,YACE,SAAS,aAAa,SAAS,cAC7B,MAAM,UAAU,UAChB,KAAA,MACJ,SAAS,WACT,SAAS,WACTD;KACN,UACE,SAAS,SACJ,SAAS,YAAY,cACrB,SAAS,cACR,SAAS,cACT,SAAS,YACT,SAAS,YACXC;KACN,cAAc,KAAK,SAAS,aAAa,aAAa;KACtD,OAAO,SAAS;KAChB,YAAY,cAAc;KAC1B,WAAW,aAAa;KACxB,WAAW,aAAa;KACxB,OAAO,UAAU,SAAS,cAAc,SAAS;KACjD,eAAe,iBAAiB;KAChC,GAAI,QAAQ,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;KAEhD,GAAI,SAAS,cAAc,EAAE,cAAcD,QAAM,IAAI,CAAC;KAEtD,GAAI,QAAQ,QAAQ,EAAE,SAAS,YAAY,MAAM,KAAK,EAAE,IAAI,CAAC;KAC7D,GAAI,QAAQ,EAAE,QAAQ,MAAM,IAAI,CAAC;KACjC,GAAI,WAAW,EAAE,aAAa,SAAS,IAAI,CAAC;KAC5C,GAAG;KACH,GAAI,MAAM,SAAS,SAAS,EAAE,oBAAoB,KAAK,IAAI,CAAC;KAC5D,GAAI,KAAK,OAAO,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;KACvC,GAAI,MAAM,MAAM,SAAS,MAAM,KAAK,OAAO,QAAQ,QAAQ,MAAM,IAAI,CAAC;IACxE,CAAC;GACH;EACF;CACF;AACF;AAEA,MAAa,mBAA4B;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAE5D,MAAa,WAAW,UAA+B;CAErD,MAAM,eAAe,MAAM,WAAW,EAAE,OAAO,gBAAgB,SAAS,cAAc,QAAQ;CAE9F,OAAO;EACL;GAAE,MAAM;GAAS,QAAQ;EAAE;EAC3B;GAAE,MAAM;GAAU,QAAQ,iBAAiB,KAAK,MAAM,SAAS;EAAa;EAC5E;GAAE,MAAM;GAAO,QAAQ,MAAM;EAAO;CACtC;AACF;AAEA,MAAa,gBAAgB,EAC3B,QACA,QACA,SACA,QACA,QACA,YACA,OAAO,GACP,UAAU,CAAC,GACX,aACkB;CAClB,MAAM,WAAW;EAAE,GAAG;EAAqB,GAAG;CAAO;CACrD,MAAM,QAAgB,CAAC;CACvB,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,SAAmB,CAAC;CAE1B,KAAK,MAAM,SAAS,QAClB,aACE,OACA,QACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,QACF;CAGF,YAAY,QAAQ,KAAK;CAEzB,MAAM,cAA4B,CAAC;CAEnC,KAAK,MAAM,EAAE,UAAU,SAAS,aAAa,SAC3C,cAAc,UAAU,MAAM,SAAS,aAAa,aAAa,OAAO;CAE1E,OAAO;EACL,YAAY,cAAc;EAC1B,OAAO,QAAQ,KAAK;EACpB;EACA,YAAY,iBAAiB,QAAQ,MAAM;EAC3C;EACA;EACA;EACA,SAAS;EACT,aAAa,CAAC,GAAG,WAAW;EAC5B,cAAc,CAAC,GAAG,YAAY;CAChC;AACF;;;;;;;ACnrCA,MAAME,WAAkB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;;;;;AAO3C,MAAM,aAAa,SAA4B;CAC7C,IAAI,KAAK,SAAS,UAAU,OAAO;EAAE,QAAQA;EAAQ,QAAQ,KAAK;CAAO;CACzE,IAAI,KAAK,SAAS,WAAW,CAAC,KAAK,MAAM,OAAO;EAAE,QAAQA;EAAQ,QAAQ;CAAE;CAE5E,MAAM,SAAS,KAAK;CACpB,MAAM,YAAY,OAAO,SAAS,eAAe,OAAO,OAAO,EAAE,EAAE,YAAY,OAAO;CAEtF,OAAO,YACH;EAAE,QAAQ,UAAU,eAAe;EAAQ,QAAQ,UAAU,eAAe;CAAO,IACnF;EAAE,QAAQA;EAAQ,QAAQ;CAAE;AAClC;AAEA,MAAM,YAAY,GAAY,MAC5B,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC;;AAGlE,MAAM,YAAY,KAAa,OAAgB,aAA+B;CAC5E,MAAM,SAAS,QAAQ,eAAe,IAAI,QAAQ,KAAK;CACvD,MAAM,OAAO;EAAC;EAAK;EAAK;CAAG;CAC3B,MAAM,QAAQ;EAAE,GAAG,OAAO,IAAI,IAAI;EAAQ,GAAG,OAAO,IAAI,IAAI;EAAQ,GAAG,OAAO,IAAI,IAAI;CAAO;CAC7F,MAAM,OAAO;EAAE,GAAG,OAAO,IAAI,IAAI;EAAQ,GAAG,OAAO,IAAI,IAAI;EAAQ,GAAG,OAAO,IAAI,IAAI;CAAO;CAE5F,KAAK,MAAM,SAAS,UAClB,KAAK,MAAM,QAAQ,MAAM;EACvB,MAAM,QAAQ,KAAK,IAAI,MAAM,OAAO,MAAM,OAAO,QAAQ,MAAM,MAAM;EACrE,KAAK,QAAQ,KAAK,IAAI,KAAK,OAAO,MAAM,OAAO,QAAQ,MAAM,MAAM;CACrE;CAEF,MAAM,SAAS;EACb,GAAG,KAAK,QAAQ,KAAK,IAAI,MAAM,KAAK,EAAG;EACvC,GAAG,KAAK,QAAQ,KAAK,IAAI,MAAM,KAAK,EAAG;EACvC,GAAG,KAAK,QAAQ,KAAK,IAAI,MAAM,KAAK,EAAG;CACzC;CACA,IAAI,SAAS,KAAK,IAAI,GAAG,KAAK,KAAK,SAAS,KAAK,QAAQ,MAAM,KAAK,CAAC,IAAI;CAEzE,SAAS,KAAK,IAAI,QAAQ,SAAS,QAAQ,MAAM,IAAI,IAAI,MAAM;CAE/D,KAAK,MAAM,SAAS,UAClB,SAAS,KAAK,IAAI,QAAQ,SAAS,MAAM,QAAQ,MAAM,IAAI,MAAM,MAAM;CAEzE,OAAO;EAAE,QAAQ;EAAQ,QAAQ,KAAK,OAAO,MAAM;CAAE;AACvD;;;;;;AAOA,MAAM,kBAAkB,SACtB,SAAS,UAAU,KAAK,IAAI,GAAG,QAAQ,UAAU,KAAK,SAAS,IAAI,cAAc,CAAC;;AAGpF,MAAa,kBAAkB,UAC7B,MAAM,SAAS,aACX,eAAe,KAAK,IACpB,SAAS,UAAU,KAAK,GAAG,QAAQ,UAAU,CAAC,CAAC;;ACtErD,MAAMC,OAAI,KAAK;AAUf,MAAMC,SAAO,GAAY,OAAyB;CAChD,GAAGD,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;AAChB;AAGA,MAAM,WAAW,EAAE,QAAe,OAAyB;CACzD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;CACxD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;CACxD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;AAC1D;;AAGA,MAAM,cAAc,OAAgB,KAAc,QAAiB,WAA4B;CAE7F,MAAM,IAAIC,MAAI,KAAK,KAAK;CACxB,MAAM,IAAIA,MAAI,OAAO,MAAM;CAC3B,MAAM,IAAID,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;CAC7C,MAAM,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAC1C,MAAM,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAC1C,MAAM,OAAOA,KAAE,IAAI,KAAK,IAAI,SAAS,UAAU,CAAC;CAChD,IAAI,EAAE,QAAQ,IAAI,OAAO;CAEzB,IAAI,EAAE,OAAO,IAAI;EACf,MAAM,IAAI,EAAE,IAAI;EAEhB,OAAO,KAAK,KAAKA,KAAE,CAAC,KAAK;CAC3B;CAEA,MAAM,OAAO,KAAK,KAAK,IAAI;CAC3B,MAAM,KAAKA,MAAG,CAAC,IAAI,SAAS,IAAI,EAAE;CAClC,MAAM,KAAKA,MAAG,OAAO,MAAM,IAAI,EAAE;CAGjC,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK;AAC7B;;AAGA,MAAM,YACJ,GACA,GACA,MACA,IACA,IACA,MACA,SACW;CACX,MAAM,UAAU,MAAc,QAAQ,KAAK,KAAK,GAAG,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC;CAEvE,IAAI,OAAO,GAAG;EACZ,MAAM,OAAO,KAAK,KAAK,IAAI;EAC3B,MAAM,OAAO,IAAI;EACjB,MAAM,KAAKA,MAAG,CAAC,IAAI,QAAQ,IAAI;EAC/B,MAAM,KAAKA,MAAG,OAAO,KAAK,IAAI;EAE9B,IAAI,MAAM,KAAK,MAAM,QAAQ,OAAO,EAAE,GAAG;GACvC,IAAI,MAAM,KAAK,MAAM,MAAM,QAAQ,KAAK,IAAIA,KAAE,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,OAAO;GAChF,OAAO;EACT;EAEA,IAAI,MAAM,KAAK,MAAM,QAAQ,OAAO,EAAE,GAAG,OAAO;EAChD,OAAO;CACT;CAEA,IAAI,SAAS,GAAG;EACd,MAAM,IAAI,CAAC,KAAK,IAAI;EACpB,IAAI,KAAK,KAAKA,KAAE,CAAC,KAAK,QAAQ,OAAOA,KAAE,CAAC,CAAC,GAAG,OAAOA,KAAE,CAAC;CACxD;CAEA,OAAO;AACT;;AAGA,MAAM,YACJ,OACA,OACA,KACA,OACA,OACA,WACY;CACZ,MAAM,KAAK,QAAQ,OAAOC,MAAI,OAAO,MAAM,QAAQ,CAAC;CACpD,MAAM,KAAK,QAAQ,OAAOA,MAAI,KAAK,MAAM,QAAQ,CAAC;CAClD,MAAM,OAAOD,KAAE,SAAS,EAAG;CAG3B,MAAM,KAAK,GAAG,IAAI,GAAG;CACrB,MAAM,KAAK,GAAG,IAAI,GAAG;CACrB,MAAM,IAAIA,KAAE,KAAK,KAAK,KAAK,EAAE;CAC7B,MAAM,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,IAAI;CAClC,MAAM,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG;CAClC,IAAI,OAAO,SAAS,GAAG,GAAG,IAAI,KAAK,IAAI,QAAQ,SAAS,IAAI,GAAG,IAAI,IAAI,MAAM,CAAC;CAE9E,IAAI,UAAU,KAAA,GACZ,OAAO,SAAS,GAAG,GAAG,IAAI,KAAK,IAAI,QAAQ,SAAS,IAAI,GAAG,IAAI,IAAI,MAAM,IAAI;CAE/E,MAAM,KAAK,QAAQ,OAAOC,MAAI,KAAK,KAAK,CAAC;CAEzC,KAAK,MAAM,OAAO,CAACD,KAAE,CAAC,OAAO,GAAG,CAAC,GAAGA,KAAE,OAAO,GAAG,CAAC,CAAC,GAAG;EACnD,IAAI,EAAG,GAAG,IAAI,KAAK,MAAM,KAAO,GAAG,IAAI,KAAK,MAAM,IAAK;EAEvD,MAAM,IAAI,MAAM,GAAG;EACnB,IAAI,EAAE,IAAI,MAAM,EAAEA,KAAE,CAAC,IAAI,OAAO;EAEhC,MAAM,IAAI,GAAG,IAAIA,KAAEA,KAAE,EAAE,IAAIA,KAAE,CAAC,CAAC;EAC/B,MAAM,IAAI,GAAG,IAAIA,KAAE,EAAE,IAAIA,KAAE,CAAC;EAC5B,MAAM,SAAS,IAAI,IAAI,IAAI;EAC3B,IAAI,SAAS,QAAQ,UAAU,UAAU,KAAA,KAAa,SAAS,QAAQ,QAAQ,OAAOA,KAAE,CAAC;CAC3F;CAEA,OAAO,QAAQ,KAAK,QAAQ;AAC9B;;AAGA,MAAM,WAAW,OAAc,OAAgB,KAAc,SAA2B;CACtF,MAAM,KAAK,QAAQ,OAAOC,MAAI,OAAO,MAAM,QAAQ,CAAC;CACpD,MAAM,KAAK,QAAQ,OAAOA,MAAI,KAAK,MAAM,QAAQ,CAAC;CAClD,MAAM,OAAO;EAACD,KAAE,KAAK,IAAI,EAAG;EAAGA,KAAE,KAAK,IAAI,EAAG;EAAGA,KAAE,KAAK,IAAI,EAAG;CAAC;CAE/D,IAAI,KAAK,IAAI,KAAM,KAAK,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,GACtF,OAAO;CAET,MAAM,KAAK,QAAQ,OAAOC,MAAI,KAAK,KAAK,CAAC;CACzC,MAAM,IAAI;EAAC,GAAG;EAAG,GAAG;EAAG,GAAG;CAAC;CAC3B,MAAM,IAAI;EAAC,GAAG;EAAG,GAAG;EAAG,GAAG;CAAC;CAC3B,MAAM,MAAM;EAAC,GAAG;EAAG,GAAG;EAAG,GAAG;CAAC;CAC7B,IAAI,OAAO;CAIX,KAAK,IAAI,OAAO,GAAG,OAAO,GAAG,QAAQ;EACnC,MAAM,QAAQ,IAAI;EAClB,MAAM,MAAM,QAAQ,IAAI,CAAC,KAAK,QAAS,EAAE,QAAS,QAAQ,IAAI,KAAK,QAAS,EAAE,QAAS;EACvF,IAAI,EAAE,QAAQ,IAAI,MAAM,IAAI,QAAQ,IAAI,MAAM,IAAI,QAAQ;EAE1D,MAAM,IAAI,MAAM;EAEhB,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO;EAE7B,MAAM,QAAQ,EAAE,KAAK,OAAO,OAAO,SAAS,EAAE,MAAO,SAASD,KAAE,CAAC,CAAC;EAElE,IAAI;GAAC;GAAG;GAAG;EAAC,CAAC,CAAC,OAAO,UAAU,UAAU,QAAQ,KAAK,SAAU,KAAK,IAAI,MAAM,MAAO,CAAC,GACrF,OAAOA,KAAE,CAAC;CACd;CAEA,OAAO,QAAQ;AACjB;;AAGA,MAAa,oBACX,MACA,OACA,OACA,QACY;CACZ,MAAM,EAAE,SAAS;CAEjB,QAAQ,MAAR;EACE,KAAK,aAAa;GAEhB,MAAM,QAAQ,UAAmB;IAC/B,MAAM,QAAQ,QAAQ,OAAOC,MAAI,OAAO,MAAM,QAAQ,CAAC;IAEvD,OAAO;KAAE,GAAGD,KAAE,MAAM,IAAI,KAAK,CAAC;KAAG,GAAGA,KAAE,MAAM,IAAI,KAAK,CAAC;KAAG,GAAGA,KAAE,MAAM,IAAI,KAAK,CAAC;IAAE;GAClF;GAEA,OAAO,WAAW,KAAK,KAAK,GAAG,KAAK,GAAG,GAAG;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE,GAAG,CAAC;EACnE;EACA,KAAK,OACH,OAAO,QAAQ,OAAO,OAAO,KAAK,IAAI;EACxC,KAAK,YACH,OAAO,SAAS,OAAO,OAAO,KAAK,KAAK,GAAG,KAAA,GAAW,KAAK,CAAC;EAC9D,KAAK,QACH,OAAO,SAAS,OAAO,OAAO,KAAK,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;EAC3D,KAAK,UACH,OAAO,WAAW,OAAO,KAAK,MAAM,UAAU,MAAM,MAAM;CAC9D;AACF;;AC3LA,MAAME,OAAI,KAAK;;AAGf,MAAaC,cAAY;;AAGzB,MAAaC,WAAS;AAEtB,MAAM,yBAAS,IAAI,aAAa,CAAC;AACjC,MAAMC,SAAO,IAAI,WAAW,OAAO,MAAM;;AAGzC,MAAa,eAAe,YAA4B;CACtD,OAAO,KAAK;CACZ,OAAK,KAAK,cAAcA,OAAK,MAAO;CAEpC,MAAM,WAAW,OAAO;CAExB,QAAQ,MAAM,WAAW,WAAW,UAAU,MAAO;AACvD;;AAGA,MAAa,gBAAgB,QAAgB,WAA4B;CACvE,MAAM,SAASH,KAAE,KAAK,IAAI,OAAO,IAAIC,aAAW,IAAI,CAAC,IAAI,MAAM;CAC/D,MAAM,MAAM,OAAO,IAAIA,cAAY,IAAI;CACvC,MAAM,MAAMD,KAAE,KAAK,IAAI,KAAK,KAAK,GAAG,CAAC,IAAI,MAAM;CAC/C,MAAM,MAAM,OAAO,IAAIC,cAAYC;CAEnC,OAAO;EAAE,GAAGF,KAAE,KAAK,IAAI,GAAG,IAAI,GAAG;EAAG,GAAGA,KAAEA,KAAE,GAAG,IAAI,MAAM;EAAG,GAAGA,KAAE,KAAK,IAAI,GAAG,IAAI,GAAG;CAAE;AACvF;;AAGA,MAAa,YAAY,WAA4B;CACnD,MAAM,KAAKA,KAAE,OAAO,IAAIC,WAAS;CACjC,MAAM,KAAKD,KAAE,OAAO,IAAIC,WAAS;CACjC,MAAM,MAAM,KAAK,IAAI,KAAK,IAAID,KAAE,KAAK,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC;CACpD,MAAM,QAAQ,KAAK,KAAK,GAAG;CAC3B,MAAM,MAAM,KAAKE;CACjB,MAAM,MAAM,KAAK,IAAI,KAAK;CAE1B,OAAO;EAAE,GAAGF,KAAE,KAAK,IAAI,GAAG,IAAI,GAAG;EAAG,GAAGA,KAAE,KAAK,IAAI,KAAK,CAAC;EAAG,GAAGA,KAAE,KAAK,IAAI,GAAG,IAAI,GAAG;CAAE;AACvF;;AAGA,MAAa,aAAa,UAA0B,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG;;AAGhG,MAAa,YAAY,UAA0B,UAAU,QAAQ,GAAG;;AAGxE,MAAa,mBAAmB,UAA0B,UAAUA,KAAE,QAAQ,GAAG,CAAC;;;;;;;ACqDlF,MAAa,uBAA+C;CAC1D,mBAAmB;CACnB,iBAAiB;CACjB,gBAAgB;CAChB,oBAAoB;AACtB;AAcA,MAAMI,OAAI,KAAK;AAEf,MAAMC,SAAO,GAAY,OAAyB;CAChD,GAAGD,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;AAChB;AAEA,MAAME,YAAU,EAAE,GAAG,GAAG,KAAc,QAAyB;CAC7D,GAAGF,KAAE,IAAI,EAAE;CACX,GAAGA,KAAE,IAAI,EAAE;CACX,GAAGA,KAAE,IAAI,EAAE;AACb;;AAGA,MAAM,eAAe,UAA0B;CAC7C,QAAQ,MAAM,MAAd;EACE,KAAK,UACH,OAAO;GAAE,GAAG,MAAM;GAAQ,GAAG;GAAG,GAAG;EAAE;EACvC,KAAK,aACH,OAAO,MAAM;EACf,KAAK,OACH,OAAO,MAAM;EACf,KAAK,YACH,OAAO;GAAE,GAAG,MAAM;GAAQ,GAAG,MAAM;GAAQ,GAAG;EAAE;EAClD,KAAK,QACH,OAAO;GAAE,GAAG,MAAM;GAAQ,GAAG,MAAM;GAAa,GAAG,MAAM;EAAO;CACpE;AACF;;;;;AAcA,MAAa,UAAU,OAAc,UAAuB,CAAC,MAAY;CACvE,MAAM,QAAQ,QAAQ,OAAO,OAAO;CACpC,MAAM,EAAE,UAAU,QAAQ,MAAM,SAAS;CAEzC,MAAM,WAAW,OAAyB;EACxC,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;EACxD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;EACxD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;CAC1D;CACA,MAAM,OAAO;EACX,GAAG;EACH,MAAM,MAAM;EACZ,QAAQ,OAAgB,QAAiB,iBAAiB,MAAM,MAAM,OAAO,OAAO,GAAG;EACvF,QAAQ,UAAmB,OAAO,MAAM,MAAM,OAAO,SAAS,KAAK;CACrE;CACA,MAAM,WAAW,OAAyB;EACxC,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;EACxD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;EACxD,GAAGA,KAAE,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC;CAC1D;CACA,MAAM,QAAQ,GAAY,OAAyB;EACjD,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CAChB;CAEA,IAAI,MAAM,SAAS,OAAO;EAGxB,MAAM,OAAO;GAACA,KAAE,KAAK,IAAI,EAAG;GAAGA,KAAE,KAAK,IAAI,EAAG;GAAGA,KAAE,KAAK,IAAI,EAAG;EAAC;EAE/D,OAAO;GACL,GAAG;GACH,eAAe,UAAU;IACvB,MAAM,QAAQ,QAAQC,MAAI,OAAO,MAAM,CAAC;IACxC,MAAM,SAAS;KAAC,MAAM;KAAG,MAAM;KAAG,MAAM;IAAC;IACzC,MAAM,OAAO,OAAO,KAAK,OAAO,SAASD,KAAE,KAAK,IAAI,KAAK,IAAI,KAAK,KAAM,CAAC;IACzE,IAAI,UAAU;IAEd,MAAM,MAAM,OAAO,KAAK,OAAO,SAAS;KACtC,IAAI,KAAK,QAAS,GAAG,OAAO;KAC5B,UAAU;KACV,OAAO,KAAK,KAAK,KAAK,IAAI,KAAK,OAAO,GAAG,OAAO,EAAE,IAAI,CAAC,KAAK,QAAS,KAAK;IAC5E,CAAC;IAED,IAAI,CAAC,SAAS;KACZ,IAAI,UAAU;KAEd,IAAI,KAAK,MAAO,KAAK,IACf;UAAA,KAAK,MAAO,KAAK,IAAK,UAAU;KAAA,OAC/B,IAAI,KAAK,MAAO,KAAK,IAAK,UAAU;KAE3C,MAAM,QAAQ,OAAO;KAErB,IAAI,WACF,KAAK,KAAK,KAAK,IAAI,KAAK,OAAO,GAAG,OAAO,EAAE,IAAI,CAAC,KAAK,WAAY,KAAK;IAC1E;IAEA,OAAO,KAAK,QAAQ;KAAE,GAAG,IAAI;KAAK,GAAG,IAAI;KAAK,GAAG,IAAI;IAAI,CAAC,GAAG,MAAM;GACrE;EACF;CACF;CAEA,IAAI,MAAM,SAAS,QAAQ;EAEzB,MAAM,SAASA,MAAG,KAAK,IAAI,KAAK,KAAK,EAAG;EACxC,MAAM,OAAO,KAAK,IAAI;EACtB,MAAM,SAAS,OAAO,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI;EAE7D,OAAO;GACL,GAAG;GACH,eAAe,UAAU;IACvB,MAAM,QAAQ,QAAQC,MAAI,OAAO,MAAM,CAAC;IACxC,MAAM,MAAMC,SAAO;KAAE,GAAG,MAAM;KAAG,GAAG;KAAG,GAAG,MAAM;IAAE,GAAG,SAAS,KAAK,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC;IAC1F,IAAI,OAAOD,MAAI,OAAO,GAAG;IACzB,MAAM,SAAS,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC;IAC5E,IAAI,EAAE,SAASD,KAAE,IAAI,IAAI,OAAOE,SAAO,MAAM,IAAI,MAAM;IAEvD,MAAM,IAAI,KAAK,IAAI,KAAK,CAAC;IACzB,MAAM,QACJ,IAAI,SACA,OAAO,KACL,KAAK,IAAI,KAAK,KAAK,KAAO,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC;IAE7E,OAAO,KAAK,QAAQ,QAAQ,KAAK,KAAKA,SAAO,MAAM,KAAK,CAAC,CAAC,CAAC;GAC7D;EACF;CACF;CAGA,OAAO;EACL,GAAG;EACH,eAAe,UAAU;GACvB,MAAM,QAAQD,MAAI,OAAO,MAAM;GAC/B,MAAM,SAAS,KAAK,KAAK,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,CAAC;GAClF,IAAI,SAASD,KAAE,IAAI,GAAG,OAAO;GAE7B,MAAM,OAAOE,SAAO,OAAO,IAAI,MAAM;GACrC,MAAM,QAAQF,KAAE,KAAK,YAAY,IAAI,CAAC;GAEtC,OAAO,KAAKE,SAAO,MAAM,KAAK,GAAG,MAAM;EACzC;CACF;AACF;;;;;;;AAQA,MAAM,UACJ,MACA,EAAE,UAAU,QAAQ,aAAa,QACjC,SACA,UACY;CACZ,MAAM,KAAKF,KAAE,MAAM,IAAI,SAAS,CAAC;CACjC,MAAM,KAAKA,KAAE,MAAM,IAAI,SAAS,CAAC;CACjC,MAAM,QAAQ,MAAM,IAAI,SAAS;CACjC,MAAM,KAAKA,KAAE,KAAK;CAClB,MAAM,UAAU,QAAQ,KAAK,KAAK,KAAK,KAAK;CAC5C,IAAI,UAAUA,KAAE,IAAI,GAAG,OAAO;CAE9B,MAAM,WAAWA,KAAE,OAAO;CAC1B,IAAI,EAAE,WAAW,SAAS,SAAS,OAAO;CAE1C,QAAQ,MAAR;EACE,KAAK,UACH,OAAO;EACT,KAAK,aAAa;GAChB,MAAM,SAASA,KAAE,KAAK,KAAK,QAAQ,CAAC;GACpC,MAAM,UAAU,IAAI;GAGpB,OAAO,YAAY;IAFJ,GAAGA,KAAE,KAAK,OAAO;IAAG,GAAGA,KAAE,KAAK,OAAO;IAAG,GAAGA,KAAE,KAAK,OAAO;GAElD,CAAC,KAAK;EAC9B;EACA,KAAK,OAAO;GAEV,MAAM,QAAQ,QAAQ;IAAE,GAAG;IAAI,GAAG;IAAI,GAAG;GAAG,CAAC;GAE7C,OACE,KAAK,IAAI,MAAM,CAAC,IAAIA,KAAE,KAAK,IAAI,EAAG,KAClC,KAAK,IAAI,MAAM,CAAC,IAAIA,KAAE,KAAK,IAAI,EAAG,KAClC,KAAK,IAAI,MAAM,CAAC,IAAIA,KAAE,KAAK,IAAI,EAAG;EAEtC;EACA,KAAK,YAAY;GACf,MAAM,QAAQ,QAAQ;IAAE,GAAG;IAAI,GAAG;IAAI,GAAG;GAAG,CAAC;GAC7C,IAAI,EAAE,KAAK,IAAI,MAAO,KAAK,IAAI,MAAM,CAAC,IAAI,OAAO;GACjD,OAAO,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI;EACnE;EACA,KAAK,QAAQ;GACX,MAAM,QAAQ,QAAQ;IAAE,GAAG;IAAI,GAAG;IAAI,GAAG;GAAG,CAAC;GAC7C,MAAM,QAAQA,KAAE,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,GAAI,CAAC;GAEnE,IAAI,EAAE,KAAK,IAAI,MAAO,KAAK,IAAI,MAAM,CAAC,IAAI,OAAO;GAEjD,MAAM,SAAS,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM;GACnD,IAAI,EAAE,SAAS,KAAK,IAAI,KAAK,KAAK,IAAI,OAAO;GAC7C,OAAO,WAAW,QAAQ,QAAQ,KAAK,KAAK,KAAK,IAAI,QAAQ,UAAU;EACzE;CACF;AACF;;AAGA,MAAM,WACJ,OACA,YAC4D;CAC5D,MAAM,WAAW,MAAM;CACvB,MAAM,OAAO,QAAQ,gBAAgB,MAAM,SAAS,WAAW,KAAK,WAAW,MAAM;CAErF,MAAM,QAAQ,cAAgC;EAC5C,MAAM,EAAE,GAAG,GAAG,MAAM,KAAK,UAAU,WAAW,IAAI;EAElD,OAAO;GAAE,GAAGA,KAAE,CAAC;GAAG,GAAGA,KAAE,CAAC;GAAG,GAAGA,KAAE,CAAC;EAAE;CACrC;CAEA,MAAM,OAAO,QAAQ,QAAQ,YAAY,KAAK;CAC9C,MAAM,MAAM;EACV,MAAM;GAAE,GAAGA,KAAE,KAAK,CAAC;GAAG,GAAGA,KAAE,KAAK,CAAC;GAAG,GAAGA,KAAE,KAAK,CAAC;EAAE;EACjD,MAAM;GACJ,KAAK;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE,CAAC;GACzB,KAAK;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE,CAAC;GACzB,KAAK;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE,CAAC;EAC3B;CACF;CAEA,IAAI,MAAM,SAAS,UAAU;EAC3B,MAAM,SAASA,KAAE,MAAM,MAAM;EAE7B,OAAO;GAAE;GAAU;GAAQ,mBAAmB;GAAQ,GAAG;EAAI;CAC/D;CAGA,MAAM,UAAU,KAAK,UAAU,MAAM,WAAW;CAChD,MAAM,SAAS,cAAuB,KAAK,UAAU,WAAW,OAAO;CAEvE,IAAI,MAAM,SAAS,aAAa;EAC9B,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;EAC1B,MAAM,IAAI,IAAI;EACd,MAAM,IAAI,IAAI;EACd,MAAM,IAAI,IAAI;EAEd,OAAO;GACL,GAAG;GACH;GACA,QAAQA,KAAE,KAAK,IAAI,GAAG,GAAG,CAAC,CAAC;GAG3B,cAAc,cAAc;IAC1B,MAAM,IAAI,MAAM,SAAS;IACzB,MAAM,MAAM,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI,IAAI,EAAE,IAAI,EAAE,IAAI,IAAI;IACpE,MAAM,UAAU,KAAK,IAAI,KAAK;IAE9B,OAAO,UAAU,OAAO,KAAK,KAAK,OAAO,IAAI,MAAM;GACrD;EACF;CACF;CAEA,IAAI,MAAM,SAAS,OAAO;EACxB,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;EAE1B,MAAM,SAAS,MAAc,cAAsB;GACjD,MAAM,YAAY,KAAK,IAAI,SAAS;GAEpC,OAAO,YAAYA,KAAE,IAAI,IAAI,OAAO,YAAYA,KAAE,IAAI;EACxD;EAEA,OAAO;GACL,GAAG;GACH;GACA,QAAQA,KAAE,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,EAAG;GAChD,cAAc,cAAc;IAC1B,MAAM,IAAI,MAAM,SAAS;IAEzB,OAAO,KAAK,IAAIA,KAAE,MAAM,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,GAAG,EAAE,CAAC,GAAGA,KAAE,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI;GACvE;EACF;CACF;CAGA,MAAM,EAAE,WAAW;CACnB,MAAM,OAAO,MAAM,SAAS;CAC5B,MAAM,SAAS,OAAO,KAAK,KAAK,SAAS,SAAS,OAAO,IAAI;CAE7D,OAAO;EACL,GAAG;EACH;EACA,QAAQA,KAAE,KAAK,KAAK,SAAS,SAAS,OAAO,IAAI,CAAC;EAClD,cAAc,cAAc;GAC1B,MAAM,IAAI,MAAM,SAAS;GACzB,MAAM,IAAI,KAAK,IAAI,EAAE,CAAC;GAEtB,OAAO,IAAI,SAAS,OAAO,IAAI,SAAS,KAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;EACzE;CACF;AACF;;AAGA,MAAa,kBAAkB,MAAY,UAAkB,UAA2B;CACtF,MAAM,SAASC,MAAI,OAAO,KAAK,QAAQ;CACvC,MAAM,UAAUD,KAAE,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;CACjF,IAAI,UAAU,KAAK,SAAS,KAAK,QAAQ,OAAO;CAChD,IAAI,UAAU,IAAK,OAAO;CAE1B,MAAM,SAAS,KAAK,KAAK,OAAO;CAChC,MAAM,OAAO,KAAK,YAAYE,SAAO,QAAQ,IAAI,MAAM,CAAC,IAAIF,KAAE,MAAM;CACpE,IAAI,OAAO,GAAG,OAAO;CACrB,IAAIA,KAAE,IAAI,IAAI,UAAU,OAAO;CAC/B,OAAOA,KAAEA,KAAE,IAAI,IAAI,QAAQ;AAC7B;;;;;AAMA,MAAa,aAAa,MAAY,cAAsB,UAA2B;CACrF,MAAM,SAASC,MAAI,OAAO,KAAK,QAAQ;CACvC,MAAM,UAAU,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO;CAC9E,IAAI,KAAK,SAAS,KAAK,SAAS,SAAS,OAAO;CAGhD,MAAM,SAAS,KAAK,KAAK,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;CACxF,IAAI,QAAQ;CAEZ,IAAI,EAAE,SAASD,KAAE,IAAI,IAAI;EACvB,MAAM,QAAQ,KAAK,YAAYE,SAAO,QAAQ,IAAIF,KAAE,MAAM,CAAC,CAAC;EAE5D,QAAQ,QAAQA,KAAE,IAAI,IAAIA,KAAE,MAAM,IAAI,QAAQ;CAChD;CAEA,IAAI,SAAS,GAAG,OAAO;CACvB,IAAI,IAAI,eAAeA,KAAE,KAAK,GAAG,OAAO;CACxC,IAAI,eAAe,MAAM,OAAO;CAChC,QAAQ,IAAIA,KAAE,KAAK,KAAK;AAC1B;AASA,MAAM,WAAW,EAAE,QAAyB,QAAyB;CACnE,MAAM,SAASC,MAAI,KAAK,KAAK,QAAQ;CAErC,MAAM,WADSD,KAAE,KAAK,KAAK,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,CACpE,IAAI,KAAK;CAE/B,OAAO,WAAW,IAAI,IAAIA,KAAE,WAAW,QAAQ;AACjD;;;;;;;;AASA,IAAa,iBAAb,MAA4B;CAC1B;CAEA,YAAY,YAAwC;EAClD,KAAK,UAAU,WAAW,KAAK,eAAe;GAAE;GAAW,KAAKA,KAAE,GAAG;EAAE,EAAE;CAC3E;;CAGA,KAAK,KAAoB;EACvB,KAAK,MAAM,SAAS,KAAK,SAAS,MAAM,MAAM,QAAQ,MAAM,WAAW,GAAG;EAC1E,KAAK,QAAQ,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;CAC3C;;CAGA,GAAG,OAAyC;EAC1C,KAAK,MAAM,EAAE,WAAW,SAAS,KAAK,SAAS;GAC7C,IAAI,MAAM,IAAI,OAAO,KAAA;GAErB,MAAM,QAAQ,UAAU,UAAU,MAAM,UAAU,gBAAgB,GAAG,KAAK;GAC1E,IAAI,QAAQA,KAAE,IAAI,GAAG,OAAO;IAAE;IAAW,WAAWA,KAAE,KAAK;GAAE;EAC/D;CAGF;AACF;;;;;;;AAQA,MAAa,eACX,YACA,KACA,QAAiB,QACW;CAC5B,MAAM,SAAS,WACZ,KAAK,eAAe;EAAE;EAAW,KAAK,QAAQ,WAAW,GAAG;CAAE,EAAE,CAAC,CACjE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;CAE/B,KAAK,MAAM,EAAE,WAAW,SAAS,QAAQ;EACvC,IAAI,MAAM,IAAI,OAAO,KAAA;EAErB,MAAM,QAAQ,UAAU,UAAU,MAAM,UAAU,gBAAgB,GAAG,KAAK;EAC1E,IAAI,QAAQA,KAAE,IAAI,GAAG,OAAO;GAAE;GAAW,WAAWA,KAAE,KAAK;EAAE;CAC/D;AAGF;;AAmBA,MAAa,eACX,QACA,KACA,SAAuB,yBACP;CAChB,MAAM,EAAE,MAAM,QAAQ;CACtB,MAAM,OAAOA,KAAE,IAAI,QAAQ,CAAC;CAC5B,MAAM,cAAcA,KAAE,IAAI,YAAY,OAAO,iBAAiB;CAC9D,MAAM,SAASC,MAAI,KAAK,KAAK,QAAQ;CACrC,MAAM,SAASD,KAAE,KAAK,KAAK,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC;CAC3F,MAAM,OAAOA,KAAE,cAAc,IAAI;CACjC,MAAM,UAAUA,KAAE,SAAS,KAAK,YAAYE,SAAO,QAAQ,IAAI,MAAM,CAAC,CAAC;CACvE,MAAM,QAAQ,UAAU,IAAI,IAAI,CAAC,UAAU,OAAO,IAAIF,KAAE,CAAC,UAAU,IAAI;CAEvE,IAAI,QAAQ,GAAG;EACb,MAAM,QAAqB;GAAE;GAAQ;GAAa;GAAO,OAAO;GAAM,KAAK;GAAM;EAAQ;EACzF,MAAM,cAAc,YAAY,OAAO,cAAc,CAAC,GAAG,GAAG;EAC5D,IAAI,CAAC,aAAa,OAAO;EAGzB,MAAM,EAAE,WAAW,WAAW,OAAO;EACrC,MAAM,MAAM,UAAU,UAAU;EAChC,MAAM,MAAM,KAAK,KAAK,MAAM,OAAOA,MAAG,IAAI,MAAM,OAAO,MAAM,EAAE,IAAI;EAEnE,OAAO;GAAE,GAAG;GAAO;GAAK;EAAY;CACtC;CAGA,MAAM,QAAQ,UAAU;CAExB,OAAO;EAAE;EAAQ;EAAa;EAAO,OAAOA,KAAE,KAAK;EAAG,KAAKA,KAAE,QAAQ,WAAW;EAAG;CAAQ;AAC7F;;AAGA,MAAa,UAAU,OAAoB,UAA2B;CACpE,IAAI,MAAM,aAAa;EAErB,MAAM,EAAE,MAAM,eAAe,MAAM,MAAM,YAAY;EACrD,MAAM,KAAK,UAAU,MAAM,cAAc,KAAK;EAC9C,MAAM,OAAOA,KAAEA,KAAE,MAAM,OAAO,IAAI,QAAQ,CAAC,IAAI,MAAM,WAAW;EAEhE,OAAOA,MAAG,IAAI,MAAM,OAAO,KAAK,MAAM,GAAG;CAC3C;CAEA,MAAM,SAAS,eAAe,MAAM,OAAO,MAAM,MAAM,aAAa,KAAK;CACzE,IAAI,EAAE,SAAS,IAAI,OAAO,MAAM;CAChC,OAAOA,KAAE,MAAM,MAAM,KAAK,IAAI,SAAS,QAAQA,KAAE,IAAI,CAAC,CAAC;AACzD;;AAGA,MAAa,UAAU,OAAoB,SAAuB,yBAAiC;CACjG,MAAM,MAAM,MAAM,MAAM,OAAO;CAC/B,MAAM,MAAM,MAAM,OAAO,iBAAiB,OAAO,iBAAiBA,KAAE,GAAG;CACvE,IAAI,CAAC,MAAM,aAAa,OAAO;CAG/B,MAAM,EAAE,WAAW,MAAM,YAAY,UAAU;CAC/C,MAAM,QAAQ,SAAS,SAAS,OAAO;CAEvC,OAAO,MAAM,QAAQ,MAAMA,KAAE,KAAK;AACpC;AAGA,MAAMG,UAAQ,UAAkB,SAAS,KAAK,IAAI;;AAGlD,MAAa,SAAS,OAAe,KAAa,WAAyB;CACzE,OAAO;EAAE,GAAGA,OAAK,MAAM,CAAC;EAAG,GAAGA,OAAK,MAAM,CAAC;EAAG,GAAGA,OAAK,MAAM,CAAC;CAAE;CAC9D;CACA;AACF;;AASA,MAAa,cACX,SACA,OACA,SACuB;CACvB,MAAM,SAAS,QAAQ,QAAQ,MAAM,UAAU,MAAM,WAAW,IAAI;CAEpE,KAAK,MAAM,SAAS,SAAS,CAAC,QAAQ,GAAG,OAAO,IAAI,SAAS;EAC3D,MAAM,SAAS,eAAe,MAAM,OAAO,MAAM,MAAM,aAAa,KAAK;EACzE,IAAI,SAAS,GAAG,OAAO;GAAE;GAAO;EAAO;CACzC;AAGF;AAUA,MAAM,eAAe,YAA4BH,KAAE,YAAY,OAAO,IAAI,OAAO;;;;;;;AAoBjF,MAAa,eACX,SACA,KACA,UACe;CACf,IAAI,OAAOA,KAAE,QAAQ,KAAK;CAC1B,IAAI;CACJ,MAAM,WAA6B,CAAC;CAEpC,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,EAAE,SAAS,MAAM;EACvB,MAAM,KAAK,KAAK,SAAS,IAAI,IAAI;EACjC,MAAM,KAAK,KAAK,SAAS,IAAI,IAAI;EACjC,MAAM,KAAK,KAAK,SAAS,IAAI,IAAI;EACjC,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK;EACzC,MAAM,WAAW,YAAY,OAAO;EACpC,MAAM,UAAUA,KAAE,IAAI,QAAQ;EAC9B,MAAM,MAAMA,KAAE,KAAK,YAAY;GAAE,GAAGA,KAAE,UAAU,EAAE;GAAG,GAAGA,KAAE,UAAU,EAAE;GAAG,GAAGA,KAAE,UAAU,EAAE;EAAE,CAAC,CAAC;EAC9F,MAAM,QAAQ,YAAY,MAAM,IAAIA,MAAG,WAAW,QAAQ,WAAW,IAAI;EAEzE,IAAI,SAAS,MAAM,cAAc,GAAG;GAClC,SAAS,KAAK;IAAE;IAAO,KAAK;GAAM,CAAC;GACnC;EACF;EAEA,MAAM,WAAW,eAAe,MAAM,MAAM,aAAa,GAAG;EAC5D,IAAI,YAAY,GAAG,OAAO;GAAE,OAAO;IAAE;IAAO,WAAW;GAAE;GAAG,UAAU,CAAC;EAAE;EAEzE,IAAI,WAAW,GAAG;GAChB,IAAI,OAAO,SAAS,KAAK;IAAE,OAAO,MAAM;IAAO,KAAK;GAAK,CAAC;GAC1D,QAAQ;IAAE;IAAO,WAAW;GAAE;EAChC,OAAO,IAAI,QAAQ,MAAM;GACvB,IAAI,OAAO,SAAS,KAAK;IAAE,OAAO,MAAM;IAAO,KAAK;GAAK,CAAC;GAC1D,OAAO;GACP,QAAQ;IAAE;IAAO,WAAW;GAAE;EAChC,OAAO,SAAS,KAAK;GAAE;GAAO,KAAK;EAAM,CAAC;CAC5C;CAEA,OAAO;EAAE,GAAI,SAAS,EAAE,MAAM;EAAI;CAAS;AAC7C;;AAGA,MAAa,aACX,SACA,KACA,UAC2B,YAAY,SAAS,KAAK,KAAK,CAAC,CAAC;;;;;;ACzrB9D,MAAM,OAAsF;CAC1F;EAAC;EAAG;EAAG;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CACrF;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAG;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CACtF;EAAC;EAAG;EAAG;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAG;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;CAAG;CAClF;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAC3F;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAC1F;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAC3F;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAG;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAC5F;EAAC;EAAK;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAG;EAAG;EAAK;CAAG;CAC5F;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAI;CACvF;EAAC;EAAK;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAI;EAAG;EAAK;CAAI;CAAG;EAAC;EAAG;EAAG;EAAG;EAAK;EAAG;EAAK;CAAG;CAC5F;EAAC;EAAG;EAAK;EAAG;EAAG;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAI;CAAG;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CACzF;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAM;CAAI;CAAG;EAAC;EAAG;EAAK;EAAG;EAAK;EAAG;EAAM;CAAI;CAAG;EAAC;EAAK;EAAK;EAAG;EAAK;EAAG;EAAK;CAAG;CAChG;EAAC;EAAG;EAAG;EAAG;EAAK;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAG;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAG;EAAG;EAAM;CAAI;CACtF;EAAC;EAAK;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAK;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAC3F;EAAC;EAAK;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAG;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAK;EAAG;EAAI;EAAG;EAAK;CAAG;CACvF;EAAC;EAAG;EAAG;EAAG;EAAI;EAAG;EAAK;CAAG;CAAG;EAAC;EAAG;EAAG;EAAG;EAAI;EAAG;EAAK;CAAG;AACvD;AAGA,MAAM,mCAAmB,IAAI,IAAI;CAAC;CAAG;CAAG;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;AAAE,CAAC;AAGvE,MAAM,8BAAc,IAAI,IAAI;CAC1B;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAAI;CAC5F;CAAI;CAAI;AACV,CAAC;;AAGD,MAAa,oBAAuC;CAClD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;AAMA,MAAa,mBAAmB,SAAqC;CACnE,MAAM,KAAK,kBAAkB,QAAQ,IAAI;CAEzC,OAAO,KAAK,IAAI,KAAA,IAAY;AAC9B;AAEA,MAAM,iBAAiB;CAAC;CAAS;CAAU;CAAS;CAAU;CAAS;AAAe;;;;;AAMtF,MAAa,iBAAiB,SAAqC;CACjE,MAAM,KAAK,eAAe,WAAW,QAAQ,WAAW,UAAU,KAAK,YAAY,CAAC;CAEpF,OAAO,KAAK,IAAI,KAAA,IAAY,KAAK;AACnC;;;;;AAMA,MAAa,gBAAgB,SAAqC;CAChE,MAAM,KAAK,eAAe,WAAW,QAAQ,YAAY,UAAU,KAAK,YAAY,CAAC;CAErF,OAAO,KAAK,IAAI,KAAA,IAAY,KAAK;AACnC;;AAGA,MAAa,sBAAuD,KAAK,KACtE,CAAC,UAAU,iBAAiB,SAAS,QAAQ,gBAAgB,MAAM,MAAM,WAAW;CACnF;CACA;CACA;CACA;CACA,gBAAgB,mBAAmB;CACnC,iBAAiB,iBAAiB,IAAI,KAAK;CAC3C,SAAS;EAAE;EAAM;CAAI;CACrB,SAAS,YAAY,IAAI,KAAK,IAAI,KAAK;AACzC,EACF;AAiDA,MAAM,YAAY,KAAqB,QAAgB,UAAkB,WAAmB;CAC1F,IAAI,WAAW,MAAM,OAAO;CAG5B,MAAM,OAAQ,SAAS,WAAY;CACnC,IAAI,EAAE,OAAO,IAAI,gBAAgB,OAAO,KAAA;CAExC,MAAM,SAAS,OAAO,IAAI,qBAAqB,IAAI,mBAAmB,IAAI;CAC1E,IAAI,QAAQ,GAAG,OAAO;CACtB,OAAO,KAAK,OAAO,QAAQ,IAAI,IAAI,KAAK;AAC1C;;;;;AAeA,MAAa,cACX,EAAE,MAAM,UAAU,UAAU,OAAO,WACnC,EAAE,QAAQ,QAAQ,MAAM,OAAO,WAC/B,EAAE,eAAe,GAAG,cAAc,CAAC,GAAG,aAAa,CAAC,GAAG,kBAAqC,CAAC,MAC9E;CACf,MAAM,OAAmB;EAAE,GAAG,oBAAoB;EAAQ,GAAG,YAAY;CAAM;CAC/E,MAAM,SAAqB;EAAE,MAAM,KAAK,iBAAiB,QAAQ;EAAO,KAAK;CAAE;CAC/E,MAAM,OAAO,KAAK,OAAO,IAAI,YAAY;CAEzC,IAAI,SAAS;EACX,KAAK,QAAQ,SAAS,MAAM,GAAG,OAAO;EAEtC,IAAI,OAAO;GACT,MAAM,SAAS,WAAW,SAAS,QAAQ,UAAU,QAAQ,MAAM;GAEnE,IAAI,CAAC,QACC;QAAA,MAAM,cAAc,GAAG,OAAO;GAAA,OAC7B;IACL,IAAI,OAAO,UAAU,MAAM,OAAO,OAAO;IAGzC,MAAM,SAAS,MAAM,cAAc,IAAI,IAAI,MAAM,MAAM;IACvD,MAAM,KAAK,KAAK,OAAO,SAAS,IAAI,OAAO,SAAS,CAAC;IACrD,MAAM,KAAK,KAAK,OAAO,SAAS,IAAI,OAAO,SAAS,CAAC;IACrD,MAAM,KAAK,KAAK,OAAO,SAAS,IAAI,OAAO,SAAS,CAAC;IACrD,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,OAAO,SAAS,MAAM,GAAG,OAAO;GACzE;EACF;CACF;CAEA,IAAI,GAAG,UAAU,KAAK,kBAAkB,KAAK,aAAa,OAAO,OAAO;CAExE,MAAM,EAAE,WAAW;CACnB,MAAM,KAAK,QAAQ,eAAe,UAAU,IAAI;CAChD,MAAM,QAAQ,KAAK,OAAO,CAAC,GAAG,CAAC;CAC/B,IAAI,EAAE,OAAO,OAAO,KAAK,OAAO,QAAQ,MAAM,IAAI,OAAO;CAEzD,MAAM,EAAE,MAAM,QAAQ,KAAK;CAC3B,IAAI,GAAG,MAAM,SAAS,IAAI,QAAQ,OAAO,QAAQ,SAAS,OAAO;CAEjE,IAAI,MAAM;CACV,MAAM,MAAM,KAAK,UAAU,KAAK,KAAK,UAAU,IAAI,WAAW,KAAK,WAAW,KAAA;CAE9E,IAAI,OAAO,kBAAkB,KAAA,GAAW;EAEtC,MAAM,SAAS,KAAK,OAAO,gBAAgB,IAAI,KAAK,IAAK,OAAO,OAAO,KAAK,KAAM,GAAG,CAAC;EACtF,MAAM,QAAQ,SAAS,KAAK,QAAQ,OAAO,MAAM;EACjD,IAAI,UAAU,KAAA,GAAW,OAAO;GAAE,GAAG;GAAQ,KAAK;EAAE;EACpD,MAAM;CACR;CAEA,OAAO,YAAY,IAAI,QAAQ,QAAQ,MAAM,IAAI;EAAE,MAAM;EAAQ;CAAI,IAAI;EAAE,GAAG;EAAQ;CAAI;AAC5F;;AAGA,MAAa,eACX,IACA,QACA,QACA,WACY;CACZ,MAAM,OAAO,KAAK,IAAK,OAAO,OAAO,KAAK,KAAM,GAAG;CACnD,MAAM,OAAO,OAAO;CACpB,MAAM,SAAS,KAAK,IAAI,GAAG,CAAC,IAAI,OAAO,GAAG,KAAK,KAAK,MAAM,GAAG,IAAI;CACjE,MAAM,SAAS,KAAK,IAAI,GAAG,CAAC,IAAI,OAAO,GAAG,KAAK,KAAK,MAAM,GAAG,IAAI;CAEjE,OAAO,SAAS,UAAU,SAAS;AACrC;;;;;;;ACtRA,MAAMI,OAAI,KAAK;AAYf,MAAM,WAAWA,KAAE,GAAI;;;;;AAMvB,MAAa,gBACX,SACA,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,QACV;CACjB,MAAM,QAAQA,KAAE,QAAQ,KAAK;CAC7B,MAAM,SAASA,KAAE,QAAQ,MAAM;CAE/B,IAAI,KAAK,KAAK,KAAK,GAAG;EACpB,IAAIA,KAAE,QAAQ,CAAC;EACf,IAAIA,KAAE,SAAS,CAAC;CAClB;CAEA,IAAI,MAAM,KAAK,MAAM,GAAG;EACtB,IAAI;EACJ,IAAI;CACN,OAAO,IAAI,KAAK,KAAK,KAAK,GAAG;EAC3B,IAAIA,KAAE,QAAQ,CAAC;EACf,IAAIA,KAAE,SAAS,CAAC;CAClB;CAEA,MAAM,QAAQA,KAAE,IAAI,CAAC;CACrB,MAAM,SAASA,KAAE,IAAI,CAAC;CAEtB,OAAO;EACL;EACA,IAAIA,KAAEA,KAAE,IAAI,QAAQ,IAAI,KAAK;EAC7B,IAAIA,KAAEA,KAAE,IAAI,QAAQ,IAAI,MAAM;EAC9B,IAAIA,KAAEA,KAAE,QAAQ,QAAQ,IAAI,KAAK;EACjC,IAAIA,KAAEA,KAAE,SAAS,QAAQ,IAAI,MAAM;CACrC;AACF;AA+CA,MAAMC,WAAS;AACf,MAAM,YAAYD,KAAE,IAAI;AACxB,MAAM,SAAS;AAGf,MAAME,YAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,YAAS;;AAGf,MAAM,iBAAiB,EAAE,QAAQ,kBAC/B,QAAQ,wBAAwB,QAAQ,eAAe,WAAW,GAAG,MAAM;;;;;;;AAQ7E,MAAa,aACX,UACA,MACA,EAAE,qBAAqB,MAAmB,CAAC,MAC5B;CACf,MAAM,WAAW,KAAK,MAAM,SAAS,YAAY,EAAE;CACnD,MAAM,EAAE,UAAU;CAClB,MAAM,SAAS,sBAAsB,KAAM,SAAS,SAAS,KAAA;CAE7D,MAAM,UAAUH,MACb,SAAS,WAAW,MAAM,WAAW,KAAA,MAAc,SAAS,SAAS,UAAU,KAAM,EACxF;CACA,MAAM,YAAY,cAAc,IAAI;CACpC,MAAM,QAAQA,KAAE,KAAK,MAAM;CAC3B,MAAM,QAAQA,KAAE,KAAK,WAAW;CAEhC,MAAM,QAAQ,WAAW;CACzB,MAAM,YAAuB,CAAC;CAC9B,MAAM,OAAOA,KAAEC,WAAS,QAAQ;CAChC,IAAI,QAAQ;CAEZ,KAAK,IAAI,UAAU,GAAG,UAAU,UAAU,WAAW;EACnD,MAAM,MAAM,KAAK,IAAI,KAAK;EAC1B,MAAM,MAAM,KAAK,IAAI,KAAK;EAE1B,MAAM,MAAM,WAAmB;GAC7B,MAAM,EAAE,GAAG,GAAG,MAAM,QAAQ,eAC1B;IAAE,GAAGD,KAAE,MAAM,MAAM;IAAG,GAAG;IAAG,GAAGA,KAAE,SAAS,GAAG;GAAE,GAC/C,SACF;GAEA,OAAO;IAAE,GAAGA,KAAE,CAAC;IAAG,GAAGA,KAAE,CAAC;IAAG,GAAGA,KAAE,CAAC;GAAE;EACrC;EAEA,UAAU,KAAK,GAAG,KAAK,GAAG,GAAG,KAAK,CAAC;EACnC,QAAQA,KAAE,QAAQ,IAAI;CACxB;CAGA,MAAM,UAAU,UAAkB,UAAU,SAAS,QAAQ,QAAQ,QAAQ;CAE7E,MAAM,QAAQ,SAAS,SAAS;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAEnD,MAAM,QAAQ;EAAC,MAAM;EAAG,MAAM;EAAG,MAAM;EAAG;CAAO,CAAC,CAAC,KAAK,MAAM,KAAK,MAAM,IAAI,GAAG,IAAI,GAAI;CACxF,MAAM,CAAC,OAAO,SAAS,CACrBA,KAAE,SAAS,aAAa,MAAM,EAAE,GAChC,KAAK,MAAM,SAAS,aAAa,MAAM,CAAC,CAC1C;CAEA,MAAM,OAAOA,KAAE,WAAW,MAAM;CAChC,IAAI,MAAM;CACV,IAAI,WAAW;CACf,MAAM,SAAsB,CAAC;CAE7B,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS;EAE3C,OAAO;EAEP,MAAM,QAAQ;EACd,MAAM,OAAO,KAAK,MAAM,YAAY,GAAG;EAEvC,WAAW;EAEX,MAAM,UAAU,MAAM,KAAK,EAAE,SAAS,OAAO,QAAQ,KAAK,EAAE,IAAI,GAAG,OACjE,OAAO,QAAQ,IAAI,EAAE,CACvB;EACA,MAAM,MAAM;GAAE,GAAG;GAAU,GAAG;GAAU,GAAG;EAAS;EACpD,MAAM,MAAM;GAAE,GAAG;GAAW,GAAG;GAAW,GAAG;EAAU;EAEvD,KAAK,MAAM,SAAS,SAClB,KAAK,MAAM,QAAQ;GAAC;GAAK;GAAK;EAAG,GAAY;GAC3C,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK;GAC3C,IAAI,QAAQ,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK;EAC7C;EAEF,MAAM,SAAS;GACb,GAAGA,MAAG,IAAI,IAAI,IAAI,KAAK,EAAG;GAC1B,GAAGA,MAAG,IAAI,IAAI,IAAI,KAAK,EAAG;GAC1B,GAAGA,MAAG,IAAI,IAAI,IAAI,KAAK,EAAG;EAC5B;EACA,MAAM,SAASA,KAAE,KAAK,MAAM,IAAI,IAAI,OAAO,GAAG,IAAI,IAAI,OAAO,GAAG,IAAI,IAAI,OAAO,CAAC,CAAC;EAEjF,MAAM,WAAW,IAAI,WAAW,QAAQ,SAASG,SAAM;EACvD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;EAI/C,QAAQ,SAAS,OAAO,OAAO;GAE7B,MAAM,OADU,SAAS,MAAM,KACR,OAAO;GAC9B,MAAM,aAAa,KAAK,OAAO;GAE/B,OAAO,IAAI;IAAC,MAAM;IAAG,MAAM;IAAG,MAAM;GAAC,GAAI,KAAKA,YAAU,CAAC;GACzD,SAAS,IAAI,OAAO,KAAKA,YAAS,EAAE;GACpC,OAAO,IACL;IACE,MAAO,OAAO,MAAM,IAAM,OAAO,MAAM;IACvC,YAAa,OAAO,MAAM,IAAM,OAAO,MAAM;IAC7C,MAAM,QAAQ;IACd,YAAY,IAAI;GAClB,IACC,KAAKA,YAAS,MAAM,CACvB;EACF,CAAC;EAED,MAAM,OAAkB;GACtB,MAAM,cAAc;GACpB,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IACE,YAAY;IACZ,aAAa;IACb,WAAW,QAAQ,SAAS;IAC5B,cAAc,QAAQ;IACtB,SAAS;GACX,CACF;GACA,SAAS,YAAY,KAAK,UAAU,GAAG,OAAO,EAAE;GAChD;EACF;EACA,MAAM,YAAsB;GAC1B,QAAQ;GACR,aAAa;GACb,aAAa,QAAQ;GACrB,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE;IAAK;GAAI;GACxB,gBAAgB;IAAE;IAAQ;GAAO;EACnC;EAEA,OAAO,KAAK;GAAE;GAAO;GAAM;GAAQ;GAAQ;GAAM;EAAU,CAAC;CAC9D;CAEA,OAAO;EACL;EACA;EACA,oBAAoBF,KAAE,SAAS,sBAAsB,GAAG;EACxD,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;EACzB,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;CAC7B;AACF;;;;;;AAOA,MAAa,iBACX,EAAE,MAAM,sBACR,UACW;CACX,MAAM,QAAQA,KAAE,KAAK,MAAM;CAC3B,MAAM,QAAQA,KAAE,KAAK,WAAW;CAChC,MAAM,OAAOA,KAAE,KAAK,MAAM;CAC1B,MAAM,eAAeA,KAAE,QAAQ,KAAK;CACpC,MAAM,eAAeA,KAAE,QAAQ,KAAK;CACpC,MAAM,YAAYA,MAAG,QAAQ,uBAAuB,QAAQ,mBAAmB;CAC/E,MAAM,YAAYA,MAAG,QAAQ,uBAAuB,QAAQ,mBAAmB;CAC/E,MAAM,QAAQ,QAAQ,eAAe,OAAO,QAAQ,OAAO,cAAc,IAAI,CAAC,CAAC;CAC/E,MAAM,IAAI,KAAK,IAAI,MAAM,CAAC;CAC1B,IAAI,SAAS;CAEb,IAAI,EAAE,IAAI,OAAO;EACf,MAAM,OAAO,KAAK,IAAI,QAAQ;EAE9B,SAASA,KAAE,IAAI;EACf,IAAI,EAAE,OAAO,IAAI,OAAO;CAC1B;CAEA,MAAM,SAAS,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM;CACnD,MAAM,UAAUA,KAAE,MAAM;CAExB,IAAI,SAAS,WAAW,OAAO;CAC/B,IAAI,UAAU,cAAc,QAAS,YAAY,YAAY,YAAY,gBAAiB;CAC1F,IAAI,UAAU,cAAc,OAAO;CACnC,IAAI,UAAU,WAAW,QAAS,UAAU,cAAc,eAAe,aAAc;CACvF,OAAO;AACT;AAKA,MAAM,eAA6B;CAAE,GAAG;CAAiB,OAAO;CAAU,OAAO;AAAS;AAE1F,MAAMI,WAAQ;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;;;;;;AAQjC,MAAa,iBAAiB,MAAkB,UAAuC;CACrF,MAAM,EAAE,OAAO,WAAW;CAC1B,IAAI,CAAC,OAAO,OAAO,KAAA;CACnB,OAAO;EACL,MAAM,MAAM;EACZ,WAAW,MAAM;EACjB,YAAY;EACZ,OAAO,MAAM,UAAU;EACvB,OAAO,QAAQ;EACf,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EACP,SAAS;GAAE,MAAM,MAAM,QAAQ;GAAM,OAAO,MAAM;GAAS,SAAS;GAAc,OAAO;EAAE;EAC3F,GAAI,SACA,EACE,QAAQ;GACN,WAAW;GACX,SAAS;IACP,MAAM,OAAO,QAAQ;IACrB,OAAO,OAAO;IACd,SAAS;IACT,OAAO;GACT;EACF,EACF,IACA,CAAC;EACL,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW;EACX,OAAO;EACP,gBAAgB;EAChB,eAAe;CACjB;AACF;;;;;;;;;ACvVA,MAAMC,OAAI,KAAK;;AAMf,MAAa,wBAAuC;CAAC;CAAG;CAAG;AAAC,CAAC,CAAC,UAAU;CACtE;CACAA,KAAE,SAAS;CACXA,KAAE,UAAU;CACZA,KAAE,UAAU;AACd,CAAC;AAGD,MAAMC,YAAUD,KAAE,UAAW;;AAG7B,MAAa,iBAAiB,YAC5B,QAAQ,KAAK,SAAS,KAAK,KAAK,UAAUA,KAAE,QAAQC,SAAO,CAAC,CAAC;;AAG/D,MAAM,SAAS,UAA0B,KAAK,MAAM,QAAQ,IAAI,QAAQD,KAAE,EAAG,IAAI,QAAQA,KAAE,EAAG,CAAC;;AAG/F,MAAM,aAAa,OAAe,SAAyB;CACzD,MAAM,OAAO,KAAK,OAAO,OAAO,KAAK,EAAG;CACxC,MAAM,OAAO,KAAK,MAAM,QAAQ,IAAI,IAAI;CAExC,OAAO,QAAQ,IAAI,OAAO,OAAO,OAAO;AAC1C;;AAGA,MAAa,uBAAuB,EAAE,GAAG,GAAG,KAAc,UAA2B;CACnF,GAAG,UAAU,MAAM,CAAC,GAAG,IAAI;CAC3B,GAAG,UAAU,MAAM,CAAC,GAAG,IAAI;CAC3B,GAAG,UAAU,MAAM,CAAC,GAAG,IAAI;AAC7B;;AAGA,MAAa,UAAU,EAAE,GAAG,GAAG,QAAyB;CACtD,MAAM,CAAC,IAAI,IAAI,MAAM;EAAC,MAAM,CAAC;EAAG,MAAM,CAAC;EAAG,MAAM,CAAC;CAAC;CAClD,IAAI,KAAK,KAAK,IAAI,EAAE,MAAM;CAC1B,IAAI,KAAK,KAAK,IAAI,EAAE,MAAM;CAC1B,IAAI,KAAK,KAAK,IAAI,EAAE,MAAM;CAC1B,IAAI,MAAM,QAAS,MAAM,OAAS,MAAM,MAAO,OAAO;CAEtD,IAAI,KAAK,GAAG,MAAM;CAClB,IAAI,KAAK,GAAG,MAAM;CAClB,IAAI,KAAK,GAAG,MAAM;CAClB,QAAS,MAAM,KAAM,KAAM,MAAM,QAAS;AAC5C;;AAGA,MAAME,gBAAc,IAAY,IAAY,OAAwB;CAClE,MAAM,KAAK,UAAkBF,KAAE,KAAK,IAAI,KAAK,CAAC;CAC9C,MAAM,IAAI,KAAK;CAEf,IAAI,OAAO;EACT;GAAC;GAAG;GAAG;EAAC;EACR;GAAC;GAAG;GAAG;EAAC;EACR;GAAC;GAAG;GAAG;EAAC;CACV;CAGA,MAAM,QAAQ,GAAW,GAAW,OAAe,SAAiB;EAClE,MAAM,CAAC,IAAI,MAAM,CAAC,EAAE,KAAK,GAAG,EAAE,KAAK,CAAC;EAEpC,OAAO,KAAK,KAAK,QAAQ,CAAC,GAAG,GAAG,CAAC;EAEjC,KAAK,IAAI,MAAM,GAAG,MAAM,GAAG,OAAO;GAChC,MAAM,IAAI,KAAK,EAAE,CAAE;GACnB,MAAM,IAAI,KAAK,EAAE,CAAE;GAEnB,KAAK,EAAE,CAAE,OAAOA,KAAE,IAAI,KAAK,OAAO,IAAI,EAAE;GACxC,KAAK,EAAE,CAAE,OAAOA,KAAE,IAAI,KAAK,OAAO,IAAI,EAAE;EAC1C;CACF;CAEA,KAAK,GAAG,GAAG,IAAI,CAAC;CAChB,KAAK,GAAG,GAAG,IAAI,EAAE;CACjB,KAAK,GAAG,GAAG,IAAI,CAAC;CAEhB,MAAM,CAAC,IAAI,IAAI,MAAM;CAErB,OAAO;EACL,GAAG;GAAE,GAAG,GAAG;GAAK,GAAG,GAAG;GAAK,GAAG,GAAG;GAAK,GAAG;EAAE;EAC3C,GAAG;GAAE,GAAG,GAAG;GAAK,GAAG,GAAG;GAAK,GAAG,GAAG;GAAK,GAAG;EAAE;EAC3C,GAAG;GAAE,GAAG,GAAG;GAAK,GAAG,GAAG;GAAK,GAAG,GAAG;GAAK,GAAG;EAAE;EAC3C,GAAG;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;CAC9B;AACF;;AAGA,MAAa,oBAAoB,GAAW,GAAW,MACrDE,aAAW,IAAID,WAAS,IAAIA,WAAS,IAAIA,SAAO;;;;;AAMlD,MAAa,mBACX,IACA,WACA,cACwB;CACxB,IAAI,QAAQ,OAAO;CAGnB,MAAM,aAAa;EACjB,QAAS,KAAK,KAAK,OAAO,MAAM,IAAI,YAAa;EACjD,OAAQ,UAAU,KAAM;CAC1B;CAGA,KAAK,IAAI,OAAQ,KAAK,KAAK,KAAM,GAAG,OAAO,GAAG,QAC5C,QAAS,KAAK,KAAK,OAAO,MAAM,IAAI,YAAa;CAEnD,IAAI,aAAa,KAAK,KAAK,IAAID,KAAE,IAAI,KAAK,IAAI,WAAW,OAAO,KAAA;CAEhE,MAAM,aAAa,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,KAAK,IAAIA,KAAE,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;CAC7E,MAAM,CAAC,GAAG,GAAG,KAAK;EAAC,KAAK;EAAG,KAAK;EAAG,KAAK;CAAC;CAEzC,OAAOE,aAAW,UAAU,EAAE,CAAC,IAAK,UAAU,EAAE,CAAC,IAAK,UAAU,EAAE,CAAC,EAAG;AACxE;;;;;;;AAiBA,MAAM,cAAc,cAAqD;CACvE,KAAK,MAAM,EAAE,UAAU,WACrB,IACE,EAAE,KAAK,SAAS,aAAa,WAC7B,CAAC,aAAa,KAAK,MAAM,CAAC,CAAC,WAAW,MAAM,EAAE,WAAW,SAAS,KAAK,GAEvE,MAAM,IAAI,MACR,uBAAuB,KAAK,OAAO,SAAS,EAAE,EAAE,8BAClD;CAEJ,MAAM,UAAU,UAAU,OAAO,EAAE,WAAW,KAAK,SAAS,aAAa,OAAO;CAEhF,OAAO,YACL,aAAa,WAAW,aAAa,UAAU,UAAU,aAAa,UAAU,IAChF,CACF;AACF;;;;;AAMA,MAAa,aACX,cACyD;CACzD,MAAM,QAAQ,UAAU;CACxB,IAAI,CAAC,OAAO,OAAO,KAAA;CAEnB,MAAM,SAAS,WAAW,SAAS;CACnC,MAAM,SAAS,iBAAiB,MAAM;CACtC,MAAM,SAAS,aAAa,MAAM;CAClC,MAAM,SAAS,OAAO,WAAW,MAAM,EAAE,WAAW,SAAS,QAAQ;CACrE,IAAI,cAAc;CAClB,KAAK,MAAM,EAAE,eAAe,WAAW,eAAe,UAAU;CAEhE,MAAM,WAAW,IAAI,WAAW,cAAc,MAAM;CACpD,MAAM,UAAoB,CAAC;CAC3B,IAAI,OAAO;CAEX,KAAK,MAAM,EAAE,MAAM,WAAW,QAAQ,iBAAiB,WAAW;EAChE,MAAM,SAAS,aAAa,KAAK,MAAM;EAGvC,MAAM,SAAS,OAAO,WAAW,KAAK,OAAO;GAG3C,OAAO;IAAE,MAFI,OAAO,WAAW,MAAM,EAAE,WAAW,SAAS,GAAG,IAE5C,CAAC,CAAC;IAAQ,IAAI,GAAG;IAAQ,OAAO,GAAG,kBAAkB,GAAG,OAAO,GAAG,OAAO;GAAE;EAC/F,CAAC;EAED,KAAK,IAAI,KAAK,GAAG,KAAK,UAAU,aAAa,MAAM;GACjD,MAAM,QAAQ,UAAU,cAAc,MAAM,OAAO;GACnD,MAAM,SAAS,OAAO,MAAM;GAE5B,KAAK,MAAM,EAAE,MAAM,IAAI,WAAW,QAChC,SAAS,IAAI,KAAK,SAAS,SAAS,OAAO,MAAM,OAAO,OAAO,KAAK,GAAG,QAAQ,EAAE;EACrF;EAGA,MAAM,OAAO,IAAI,SAAS,SAAS,QAAQ,OAAO,QAAQ,UAAU,cAAc,MAAM;EAExF,KAAK,IAAI,KAAK,GAAG,KAAK,UAAU,aAAa,MAAM;GACjD,MAAM,QAAQ,gBACZ;IAAC;IAAG;IAAG;GAAC,CAAC,CAAC,KAAK,MAAM,KAAK,WAAW,KAAK,SAAS,cAAc,GAAG,IAAI,CAAC;GAC3E,MAAM,SAAS,aAAqB,EAAE,GAAG,GAAG,QAC1C;IAAC;IAAG;IAAG;GAAC,CAAC,CAAC,SAAS,OAAO,MACxB,KAAK,WAAW,KAAK,SAAS,cAAc,IAAI,GAAG,OAAO,IAAI,CAChE;GACF,MAAM,CAAC,IAAI,IAAI,MAAM,KAAK,CAAC;GAC3B,MAAM,IAAI,QAAQ,mBAAmB;IAAE,GAAG;IAAI,GAAG;IAAI,GAAG;GAAG,GAAG,WAAW;GAEzE,MAAM,GAAG;IAAE,GAAGF,KAAE,OAAO,IAAIA,KAAE,EAAE,CAAC,CAAC;IAAG,GAAGA,KAAEA,KAAE,EAAE,CAAC,IAAI,OAAO,CAAC;IAAG,GAAGA,KAAEA,KAAE,EAAE,CAAC,IAAI,OAAO,CAAC;GAAE,CAAC;GAEtF,IAAI,QAAQ;IACV,MAAM,CAAC,IAAI,IAAI,MAAM,KAAK,OAAO,MAAM;IACvC,MAAM,IAAI,QAAQ,mBAAmB;KAAE,GAAG;KAAI,GAAG;KAAI,GAAG;IAAG,GAAG,WAAW;IAEzE,MAAM,OAAO,QAAQ;KAAE,GAAGA,KAAE,EAAE,CAAC;KAAG,GAAGA,KAAE,EAAE,CAAC;KAAG,GAAGA,KAAE,EAAE,CAAC;IAAE,CAAC;GAC1D;EACF;EAGA,KAAK,MAAM,EAAE,YAAY,cAAc,gBAAgB,YAAY,MAAM,SAAS,GAChF,KAAK,IAAI,KAAK,GAAG,KAAK,cAAc,MAClC,QAAQ,KAAK,KAAK,QAAQ,aAAa,MAAO,aAAa,UAAU,cAAc,IAAI;EAE3F,QAAQ,UAAU;CACpB;CAEA,MAAM,aAAa,MAAM,KAAK,OAAO,MAAM,UAAU,WAAW,EAAE,cAAc;CA8BhF,OAAO;EAAE,MAAA;GA5BP,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB;GACA,QAAQ,CACN;IACE;IACA,aAAa;IACb,WAAW,cAAc;IACzB,cAAc,QAAQ;IACtB,SAAS;GACX,CACF;GACA,SAAS,YAAY,KAAK,OAAO;GACjC;EAcU;EAAG,WAAA;GAXb,QAAQ;GACR,aAAa;GACb;GACA,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY;GACZ,aAAa,MAAM,UAAU;GAC7B,gBAAgB,MAAM,UAAU;EAGX;CAAE;AAC3B;;AAwDA,MAAa,aAAa,OAAkB,QAA0B;CACpE,MAAM,OAAO,KAAK,MAAM,MAAM,gBAAgB,MAAM,eAAe,EAAE;CACrE,MAAM,SAASA,MAAG,MAAM,WAAW,QAAQA,KAAE,IAAI,CAAC;CAClD,MAAM,EAAE,SAAS;CACjB,MAAM,IAAI;EACR,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;EAC5B,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;EAC5B,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;CAC9B;CACA,MAAM,QAAQ,KAAK,SAAS;CAC5B,MAAM,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAChD,IAAI,UAAU,QAAQ,OAAO,OAAO;CAEpC,MAAM,WAAW,KAAK,KAAKA,KAAE,OAAO,CAAC;CACrC,IAAI,SAAS;CAEb,IAAI,WAAWA,KAAE,IAAM,GAAG;EACxB,MAAM,SAASA,KAAE,QAAQ;EACzB,MAAM,UAAU,IAAI;EAEpB,SACE,SAAS,KAAK,YAAY;GAAE,GAAGA,KAAE,EAAE,IAAI,OAAO;GAAG,GAAGA,KAAE,EAAE,IAAI,OAAO;GAAG,GAAGA,KAAE,EAAE,IAAI,OAAO;EAAE,CAAC;CAC/F;CAEA,OAAO,UAAU;AACnB;;;;;AAMA,MAAa,qBACX,OACA,KACA,aACW;CACX,MAAM,UAAU,WAAW,IAAI,WAAWA,MAAG,MAAM,eAAe,MAAM,YAAYA,KAAE,GAAG,CAAC;CAC1F,MAAM,EAAE,SAAS;CACjB,MAAM,IAAI;EACR,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;EAC5B,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;EAC5B,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;CAC9B;CACA,MAAM,QAAQ,KAAK,SAAS;CAC5B,MAAM,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAChD,IAAI,UAAU,QAAQ,OAAO,OAAO;CAEpC,MAAM,OAAO,KAAK,KAAKA,KAAE,OAAO,CAAC;CACjC,MAAM,UAAU,IAAI;CACpB,MAAM,SACJA,KAAE,IAAI,IAAI,KAAK,YAAY;EAAE,GAAGA,KAAE,EAAE,IAAI,OAAO;EAAG,GAAGA,KAAE,EAAE,IAAI,OAAO;EAAG,GAAGA,KAAE,EAAE,IAAI,OAAO;CAAE,CAAC;CAC9F,IAAI,EAAE,UAAU,UAAU,OAAO;CACjC,OAAOA,KAAE,IAAI,SAAS,OAAO;AAC/B;;;;;;AAOA,MAAa,kBAAkB,EAAE,QAAuB,QAAyB;CAC/E,MAAM,KAAKA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;CACpC,MAAM,KAAKA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;CACpC,MAAM,KAAKA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;CACpC,IAAI;CACJ,IAAI;CAEJ,IAAI,KAAK,SAAS,UAAU;EAC1B,SAASA,KAAE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;EACjD,SAAS,KAAK;CAChB,OAAO,IAAI,KAAK,SAAS,aAAa;EAEpC,SAASA,KAAE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;EAEjD,MAAM,UAAU,IAAI;EAEpB,SAAS,KAAK,YAAY;GAAE,GAAGA,KAAE,KAAK,OAAO;GAAG,GAAGA,KAAE,KAAK,OAAO;GAAG,GAAGA,KAAE,KAAK,OAAO;EAAE,CAAC;CAC1F,OAAO,OAAO;CAEd,MAAM,WAAW,SAAS;CAG1B,OAAO,WAAW,IAAI,IAAIA,KAAE,WAAW,QAAQ;AACjD;;;;;AAMA,MAAM,YACJ,OACA,OACA,UAC2C;CAC3C,IAAI;CAEJ,KAAK,MAAM,EAAE,WAAW,SAAS,OAAO;EACtC,IAAI,MAAM,OAAO;EAEjB,IAAI,UAAU,UAAU,MAAM,UAAU,gBAAgB,GAAG,KAAK,MAAM,GAAG;GACvE,IAAI,GAAG,UAAU,kBAAkB,OAAO,IAAI,OAAO,EAAE,OAAO,KAAK;GACnE,YAAY,UAAU;EACxB;CACF;CAEA,OAAO,cAAc,KAAA,IAAY,EAAE,OAAO,MAAM,IAAI;EAAE,OAAO;EAAO;CAAU;AAChF;;;;;;;AAQA,MAAa,cACX,OACA,QACA,QAEA,YACe;CACf,MAAM,MAAM,OAAO;CACnB,IAAI,MAAM,iBAAiB,CAAC,UAAU,OAAO,GAAG,GAAG,OAAO,CAAC;CAE3D,MAAM,OAAO,MAAM;CACnB,MAAM,YAAY,MAAM,aAAa;CACrC,MAAM,WAAWA,KAAE,MAAM,YAAY,CAAC;CACtC,MAAM,QAAQ,QAAQ,wBAAwB,OAAO,aAAa;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,CAAC;CACtF,MAAM,OAAO;EAAE,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;CAAE;CACxD,MAAM,OAAO;EAAE,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;CAAE;CACxD,MAAM,OAAO;EAAE,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;CAAE;CACxD,MAAM,OAAO,GAAY,OAAgB;EAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CAAE;CAC7F,MAAM,OAAO,GAAY,OAAgB;EAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CAAE;CAC7F,MAAM,SAAS,GAAY,OAAe;EAAE,GAAGA,KAAE,EAAE,IAAI,CAAC;EAAG,GAAGA,KAAE,EAAE,IAAI,CAAC;EAAG,GAAGA,KAAE,EAAE,IAAI,CAAC;CAAE;CACxF,MAAM,OAAO,GAAY,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;CAIxE,MAAM,QAAQA,KAAG,OAAO,OAAO,KAAK,KAAM,GAAG;CAC7C,MAAM,OAAOA,KAAE,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,MAAM,CAAC;CAClD,MAAM,SAASA,KAAE,KAAK,KAAK,CAAC,IAAI;CAChC,MAAM,SAASA,KAAE,KAAK,KAAK,CAAC,IAAI;CAChC,MAAM,CAAC,MAAM,MAAM,MAAM,QAAQ;EAC/B,KAAK,IAAI,MAAM;EACf,KAAK,IAAI,MAAM;EACf,KAAK,IAAI,MAAM;EACf,KAAK,IAAI,MAAM;CACjB,CAAC,CAAC,IAAIA,IAAC;CACP,MAAM,QAAQ,MAAM,MAAM,IAAI;CAC9B,MAAM,KAAK,IAAI,MAAM,MAAM,CAAC,IAAI,GAAG,KAAK;CACxC,MAAM,KAAK,IAAI,MAAM,MAAM,IAAI,GAAG,KAAK;CACvC,MAAM,QAAQ,MAAM,MAAM,IAAI;CAC9B,MAAM,KAAK,IAAI,MAAM,MAAM,CAAC,IAAI,GAAG,KAAK;CACxC,MAAM,KAAK,IAAI,MAAM,MAAM,IAAI,GAAG,KAAK;CAEvC,MAAM,SAASA,KAAE,OAAOA,KAAE,IAAI,CAAC;CAC/B,MAAM,YAAY,IAAI,KAAK,MAAM,MAAM,MAAM,CAAC;CAC9C,MAAM,OAAOA,KAAE,KAAK,IAAI,KAAK,CAAC;CAC9B,MAAM,OAAOA,KAAE,KAAK,IAAI,IAAI,CAAC;CAC7B,MAAM,OAAO,KAAK,MAAM,MAAM,YAAY,IAAIA,KAAE,MAAM,eAAe,CAAC;CACtE,MAAM,OAAO,KAAK,MAAM,OAAO,IAAI;CACnC,MAAM,OAAO,KAAK,MAAM,OAAO,IAAI;CAGnC,MAAM,OAAO,oBAAoB,IAAI,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG,IAAI;CAClE,IAAI,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,QAAQ;EAAC,KAAK;EAAG,KAAK;EAAG,KAAK;EAAG,KAAK;EAAG,KAAK;EAAG,KAAK;CAAC;CAC1F,MAAM,OAAO;EAAE,GAAG,CAAC,KAAK;EAAG,GAAG,CAAC,KAAK;EAAG,GAAG,CAAC,KAAK;CAAE;CAClD,MAAM,YAAY,IAAI,MAAM,MAAM,IAAI,GAAG,GAAG;CAC5C,MAAM,OAAO,MAAM,MAAM,IAAI;CAC7B,MAAM,OAAO,MAAM,MAAM,IAAI;CAC7B,MAAM,QAAQ,IAAI,WAAW,IAAI;CACjC,MAAM,QAAQ,IAAI,WAAW,IAAI;CAEjC,KAAK,MAAM,UAAU;EAAC,IAAI,OAAO,IAAI;EAAG,IAAI,OAAO,IAAI;EAAG,IAAI,OAAO,IAAI;EAAG,IAAI,OAAO,IAAI;CAAC,GAAG;EAC7F,MAAM,UAAU,oBAAoB,QAAQ,IAAI;EAC/C,CAAC,MAAM,QAAQ,CAAC,KAAK,IAAI,MAAM,QAAQ,CAAC,GAAG,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC;EACpE,CAAC,MAAM,QAAQ,CAAC,KAAK,IAAI,MAAM,QAAQ,CAAC,GAAG,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC;EACpE,CAAC,MAAM,QAAQ,CAAC,KAAK,IAAI,MAAM,QAAQ,CAAC,GAAG,KAAK,IAAI,MAAM,QAAQ,CAAC,CAAC;CACvE;CAEA,MAAM,WAAWA,KAAE,OAAO,EAAG;CAC7B,MAAM,YAAY,OAAO;CACzB,MAAM,QAAQA,KAAE,SAAS;CACzB,MAAM,YAAYA,KAAE,YAAY,QAAQ;CACxC,MAAM,iBAAiBA,KACrB,KAAK,IAAI,KAAK,MAAM,MAAM,YAAY,KAAK,MAAM,eAAe,KAAK,MAAM,CAAC,CAC9E;CACA,MAAM,SAAS,MAAM,cAAc,CAAC,EAAA,CACjC,KAAK,eAAe;EAAE;EAAW,KAAK,eAAe,WAAW,GAAG;CAAE,EAAE,CAAC,CACxE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;CAC/B,MAAM,WAAW,OAAO,oBAAoB,KAAK,IAAI,CAAC;CACtD,IAAI,aAAa;;CAGjB,MAAM,QAAQ,UAAmB,OAAoC;EACnE,IAAI,EAAE,UAAU,MAAM,MAAM,MAAM,gBAAgB,GAAG,QAAQ,IAAIA,KAAE,IAAK,IAAI,OAAO,KAAA;EAEnF,MAAM,EAAE,OAAO,cAAc,SAAS,OAAO,gBAAgB,QAAQ;EACrE,IAAI,OAAO,KAAK,OAAO,OAAO,KAAA;EAC9B,OAAO,gBAAgB,IAAI,WAAW,aAAa,MAAM,kBAAkB,CAAC;CAC9E;CAEA,MAAM,QAAoB,CAAC;CAE3B,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK,MACjC,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK,MACjC,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,KAAK,MAAM;EACvC,MAAM,WAAW,oBAAoB;GAAE;GAAG;GAAG;EAAE,GAAG,IAAI;EACtD,MAAM,QAAQ,IAAI,UAAU,SAAS;EACrC,MAAM,QAAQ,KAAK,IAAI,IAAI,MAAM,KAAK,CAAC;EACvC,IAAI,QAAQ,OAAO;EAGnB,MAAM,UAAU,IAAI;EACpB,MAAM,SAAS,IAAI,OAAO,IAAI,IAAI;EAClC,IAAI,EAAE,QAAQ,KAAK,IAAI,MAAM,MAAM,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG;EAEzE,MAAM,SAAS,IAAI,OAAO,IAAI,IAAI;EAClC,IAAI,EAAE,QAAQ,KAAK,IAAI,MAAM,MAAM,IAAI,SAAS,IAAI,KAAK,IAAI,KAAK,IAAI,GAAG;EACzE,IAAI,SAAS,QAAQ;EACrB,IAAI,EAAE,UAAU,MAAM,MAAM,MAAM,gBAAgB,GAAG,QAAQ,IAAIA,KAAE,IAAK,IAAI;EAE5E,MAAM,KAAK,OAAO,QAAQ;EAC1B,MAAM,EAAE,OAAO,cAAc,SAAS,OAAO,gBAAgB,QAAQ;EACrE,IAAI,OAAO,KAAK,OAAO;EACvB,IAAI,OAAO,UAAU,aAAa;EAElC,MAAM,cAAc,gBAAgB,IAAI,WAAW,aAAa,MAAM,kBAAkB,CAAC;EACzF,IAAI,CAAC,aAAa;EAElB,IAAI,QAAQ;EAEZ,IAAI,YAAY,OAAO;GACrB,MAAM,QAAS,QAAQ,SAAS,WAAY;GAE5C,QAAQ,OAAO,WAAW,WAAW,OAAO,IAAI,IAAIA,KAAE,IAAI;GAC1D,IAAI,SAASA,KAAE,IAAK,GAAG;EACzB;EAEA,MAAM,KAAK;GAAE;GAAU;GAAa;EAAM,CAAC;CAC7C;CAEJ,IAAI,CAAC,cAAc,aAAa,GAAG;EACjC,MAAM,WAAW,oBAAoB,KAAK,IAAI;EAC9C,MAAM,cAAc,KAAK,UAAU,QAAQ;EAC3C,IAAI,aAAa,MAAM,KAAK;GAAE;GAAU;GAAa,OAAO;EAAS,CAAC;CACxE;CAEA,OAAO;AACT;;;;;;;ACnkBA,MAAMG,OAAI,KAAK;;AAwBf,MAAa,qBAA2C;CACtD,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC1B,WAAW;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC9B,UAAU;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC7B,UAAU;CACV,UAAU;CACV,UAAU;CACV,eAAe;AACjB;AAGA,MAAMC,cAAY;AAClB,MAAM,eAAe;AACrB,MAAM,cAAc;;;;;;AAOpB,IAAa,aAAb,MAAa,WAAW;CACtB,QAAQ;CACR,QAAQ;CACR;CACA,aAAa;CAEb,YACE,EAAE,UAAU,iBACZ,eAAuB,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,GACxD;EACA,MAAM,UAAU,OAAO,IAAIA,cAAY,eAAe,eAAeD,KAAE,QAAQ;EAE/E,IAAI,SAAS,GAAG;GACd,MAAM,OAAO,IAAIA,KAAE,MAAM;GAEzB,KAAK,QAAQA,KAAE,IAAI;GAEnB,MAAM,MAAMA,KAAE,aAAa,IAAIA,KAAE,MAAM,IAAIA,KAAE,MAAM,IAAIA,KAAE,aAAa;GAEtE,KAAK,QAAQA,KAAE,OAAO,GAAG;EAC3B;EAEA,KAAK,SAASA,KAAE,OAAO,IAAIC,WAAS;CACtC;;;;;CAMA,OAAO,MAAM,QAAgB,OAAe,eAAmC;EAC7E,MAAM,QAAQ,IAAI,WAAW;GAAE,UAAU;GAAG;EAAc,SAAS,CAAC;EAEpE,MAAM,SAASD,KAAE,KAAK;EAEtB,IAAIA,KAAE,MAAM,IAAI,GAAG;GACjB,MAAM,UAAU,IAAIA,KAAE,MAAM;GAE5B,MAAM,QAAQA,KAAE,OAAO;GAEvB,MAAM,MAAMA,KAAE,MAAM,IAAIA,KAAE,aAAa,IAAIA,KAAE,MAAM,IAAIA,KAAE,aAAa;GAEtE,MAAM,QAAQA,KAAE,UAAU,GAAG;EAC/B;EAEA,OAAO;CACT;;CAGA,IAAI,QAAgB;EAClB,OAAO,KAAK;CACd;;CAGA,KAAK,MAAoB;EACvB,IAAI,KAAK,UAAU,GAAG;EAEtB,MAAM,QAAQA,KAAE,IAAI,IAAI,KAAK,QAAQ,KAAK;EAE1C,KAAK,SAASA,KAAE,SAAS,IAAI,QAAQ,KAAK,MAAM,KAAK,IAAI,KAAK;EAE9D,IAAI,KAAK,SAAS,KAAK,OAAO;GAC5B,KAAK,aAAa;GAClB;EACF;EAEA,MAAM,OAAQ,IAAI,KAAK,QAAS,KAAK;EAErC,KAAK,aAAaA,KAAE,OAAO,IAAI,IAAI,OAAO,IAAI;CAChD;AACF;AA+BA,MAAM,QAAmB;CAAC;CAAG;CAAG;CAAG;AAAC;;;;;AAMpC,MAAM,QACJ,OACA,YACA,IACA,IACA,SACY;CACZ,IAAI,MAAM,KAAK,IAAI,OAAO;CAC1B,IAAI,MAAM,MAAM,IAAI,OAAO;CAE3B,MAAM,QAAQ,KAAK,MAAM;CAEzB,IAAI,QAAQ,GAAG;EACb,MAAM,KAAKA,KAAE,QAAQ,MAAM,EAAE;EAC7B,WAAW,KAAKA,MAAG,WAAW,KAAK,WAAW,OAAO,QAAQ,QAAQ,WAAW,EAAE;CACpF;CAEA,MAAM,QAAQ,KAAK,MAAM;CACzB,IAAI,EAAE,QAAQ,IAAI,OAAO;CACzB,MAAM,KAAKA,KAAE,QAAQ,MAAM,EAAE;CAC7B,WAAW,KAAKA,MAAG,WAAW,KAAK,WAAW,OAAO,QAAQ,QAAQ,WAAW,EAAE;CAClF,OAAO;AACT;;AAGA,MAAM,aACJ,MACA,OACA,OACA,SACA,SACA,GACA,GACA,GACA,QAC2B;CAC3B,IAAI,EAAE,UAAU,IAAI,OAAO,KAAA;CAG3B,MAAM,CAAC,GAAG,GAAG,KAAK;EAAC,MAAM;EAAG,MAAM;EAAG,MAAM;CAAC,CAAC,CAAC,KAAK,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC;CAC5E,IAAK,IAAK,IAAK,MAAQ,KAAK,GAAG,OAAO,KAAA;CAEtC,MAAM,KAAuB,CAACA,KAAE,IAAI,OAAO,GAAGA,KAAE,IAAI,OAAO,CAAC;CAC5D,MAAM,KAAuB,CAACA,KAAE,IAAI,OAAO,GAAGA,KAAE,IAAI,OAAO,CAAC;CAC5D,MAAM,KAAuB,CAAC,MAAM,IAAI,MAAM,EAAE;CAChD,MAAM,KAAuB,CAAC,MAAM,IAAI,MAAM,EAAE;CAEhD,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,UAAU,OAAO,GAAG,OAAO,KAAA;CAC/D,IAAI,CAAC,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,IAAI,UAAU,OAAO,GAAG,OAAO,KAAA;CAC/D,OAAO;EACL,IAAI,GAAG;EACP,IAAI,GAAG;EACP,IAAI,GAAG;EACP,IAAI,GAAG;EACP;EACA;EACA,IAAI,GAAG;EACP,IAAI,GAAG;EACP,IAAI,GAAG;EACP,IAAI,GAAG;EACP,QAAQ,cAAe,IAAK,QAAS,MAAQ,IAAK,QAAS,IAAM,IAAK,SAAW;CACnF;AACF;AAGA,MAAME,YAAUF,KAAE,UAAW;;AAG7B,MAAM,UAAU,EAAE,aAAyB,OAAgB,QAAyB;CAClF,IAAI,CAAC,WAAW,OAAO;CAEvB,MAAM,OAAOA,KAAE,KAAK,IAAI,UAAU,KAAKE,SAAO,CAAC;CAC/C,MAAM,OAAOF,KAAE,KAAK,IAAI,UAAU,KAAKE,SAAO,CAAC;CAC/C,IAAI,EAAE,OAAO,OAAO,OAAO;CAE3B,MAAM,IAAI;EAACF,KAAE,MAAM,EAAE,IAAI,IAAI,CAAC;EAAGA,KAAE,MAAM,EAAE,IAAI,IAAI,CAAC;EAAGA,KAAE,MAAM,EAAE,IAAI,IAAI,CAAC;CAAC;CAE3E,MAAM,UAAU,YAAYA,KAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;CACtE,MAAM,CAAC,GAAG,GAAG,KAAK,EAAE,KAAK,MAAMA,KAAE,IAAI,OAAO,CAAC;CAE7C,MAAM,MAAMA,KAAE,IAAI,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,CAAC;CAC3D,IAAI,MAAM,MAAM,OAAO;CACvB,IAAI,MAAM,MAAM,OAAOA,MAAG,MAAM,SAAS,OAAO,KAAK;CACrD,OAAO;AACT;;;;;;AAmBA,MAAa,cACX,OACA,OACA,YACA,EAAE,QAAQ,MAAM,QAAQ,OAAO,QAAQ,QAAQ,YAC9B;CAGjB,MAAM,OAAO;EAAC;EAAG;EAAG,QAAQ;EAAG,SAAS;CAAC;CACzC,MAAM,MAAM,IAAI,KAAK,IAAK,OAAO,OAAO,KAAK,KAAM,GAAG;CAEtD,MAAM,QAAQ;EAAE,GAAI,QAAQ,IAAK;EAAK,GAAG,EAAE,SAAS,KAAK,SAAS;CAAI;CACtE,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,QAAQ;CACjD,MAAM,EAAE,OAAO,WAAW,aAAa;CACvC,MAAM,OAAO;EACX,GAAG,aAAa,UAAU;EAC1B,GAAG,aAAa,UAAU;EAC1B,GAAG,aAAa,UAAU;CAC5B;CACA,MAAM,OAAO;EACX,GAAGA,KAAEA,KAAE,aAAaA,KAAE,MAAM,IAAI,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC;EACzD,GAAGA,KAAEA,KAAE,aAAaA,KAAE,MAAM,IAAI,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC;EACzD,GAAGA,KAAE,aAAaA,KAAE,MAAM,IAAI,SAAS,CAAC,IAAI,SAAS,CAAC;CACxD;CACA,MAAM,QAAQ;EAAE,GAAGA,KAAEA,KAAE,KAAK,CAAC,IAAI,IAAI;EAAG,GAAGA,KAAEA,KAAE,KAAK,CAAC,IAAI,IAAI;EAAG,GAAGA,KAAEA,KAAE,KAAK,CAAC,IAAI,IAAI;CAAE;CAEvF,MAAM,KAAK,QAAQ,eAAe;EAAE,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;CAAE,GAAG,IAAI;CACpF,MAAM,QAAQA,KAAEA,KAAE,GAAG,CAAC,IAAIA,KAAE,GAAG,CAAC,IAAI,IAAK;CACzC,IAAI,QAAQ,OAAO,QAAQ,GAAG,OAAO,CAAC;CAGtC,MAAM,MAAMA,KAAE,KAAK,KAAK;CACxB,MAAM,OAAOA,KAAE,MAAM,CAAC,IAAI;CAC1B,MAAM,OAAOA,KAAE,MAAM,CAAC,IAAI;CAC1B,MAAM,QAAQA,KAAE,MAAM,QAAQ,IAAI;CAClC,MAAM,QAAQA,KAAE,OAAOA,KAAE,MAAM,QAAQ,CAAC;CACxC,IAAI,QAAQ,KAAK,QAAQ,GAAG,OAAO,CAAC;CAEpC,MAAM,IAAIA,MAAG,KAAK,KAAK,KAAK,MAAM,KAAMA,KAAE,GAAG,CAAC,IAAIA,KAAE,MAAM,CAAC,IAAI,MAAM,KAAK,EAAE;CAC5E,MAAM,IAAIA,MAAG,KAAK,KAAK,KAAK,MAAM,KAAMA,KAAE,GAAG,CAAC,IAAIA,KAAE,MAAM,CAAC,IAAI,MAAM,KAAK,EAAE;CAC5E,MAAM,IAAIA,KAAE,IAAI,OAAO,OAAO,GAAG;CAMjC,OAAO,CAJL,UAAU,MAAM,OAAO,MAAMA,KAAE,KAAK,GAAGA,KAAE,KAAK,IAAIA,KAAE,MAAM,QAAQ,IAAI,IAAI,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,GAC1F,UAAU,MAAM,OAAO,OAAO,OAAOA,KAAE,KAAK,IAAI,OAAOA,KAAE,MAAM,QAAQ,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAG/E,CAAC,CAAC,QAAQ,SAAS,SAAS,KAAA,CAAS;AAClD;;;;;;;ACrSA,MAAMG,OAAI,KAAK;AAGf,MAAMC,YAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,YAAS;AACf,MAAMC,WAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAG1C,MAAMC,SAAO;;;;;AAMb,MAAM,0BAAU,IAAI,QAA8B;;;;;;;;AASlD,MAAa,kBACX,EAAE,QAAQ,SACV,MACA,aACqB;CACrB,IAAI,QAAQ,GAAG,QAAQ,IAAI,QAAQ,KAAK;CACxC,IAAI,EAAE,QAAQ,MAAM,QAAQ,IAAI,MAAM,GAAG,OAAO,KAAA;CAChD,IAAI,EAAE,QAAQ,IAAI,OAAO,KAAA;CACzB,IAAI,SAAS,GAAG,QAAQ,IAAI,QAAQ,IAAI;CAExC,MAAM,EAAE,UAAU,OAAO;CACzB,MAAM,QAAQ;EAACA,OAAK,MAAM,CAAC;EAAGA,OAAK,MAAM,CAAC;EAAGA,OAAK,MAAM,CAAC;EAAGA,OAAK,KAAK;CAAC;CAEvE,MAAM,QAAQ,WAAWJ,KAAEA,KAAE,SAAS,QAAQ,CAAC,KAAK,IAAI,SAAS,SAAS,CAAC,IAAI;CAC/E,MAAM,SAAS,WAAWA,KAAE,IAAIA,KAAE,SAAS,SAAS,CAAC,KAAK,IAAI,SAAS,OAAO,IAAI;CAClF,MAAM,UAAU;EACd,CAAC,IAAI,CAAC;EACN,CAAC,OAAO,CAAC;EACT,CAAC,OAAO,MAAM;EACd,CAAC,IAAI,MAAM;CACb;CACA,MAAM,WAAW,IAAI,WAAW,QAAQ,SAASE,SAAM;CACvD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;CAG/C,QAAQ,SAAS,CAAC,GAAG,IAAI,OAAO;EAC9B,OAAO,IAAI;GAAC;GAAI;GAAI;EAAC,GAAI,KAAKA,YAAU,CAAC;EACzC,SAAS,IAAI,OAAO,KAAKA,YAAS,EAAE;CACtC,CAAC;CAuBD,OAAO;EACL,MAAA;GArBA,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CAAC;IAAE,YAAY;IAAG,aAAa;IAAG,WAAW;IAAG,cAAc;IAAG,SAAS;GAAE,CAAC;GACrF,SAAS,IAAI,YAAY;IAAC;IAAG;IAAG;IAAG;IAAG;IAAG;GAAC,CAAC;GAC3C;EAeG;EACH,WAAA;GAbA,QAAQ;GACR,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAKE;IAAO,KAAKA;GAAM;GACtC,gBAAgB;IAAE,QAAQA;IAAO,QAAQ;GAAE;EAKnC;EACR,WAAW;EACX,YAAY;EACZ,OAAO;EAEP,OAAO,QAAQ,OAAO,IAAI;EAC1B,YAAY,QAAQ;EACpB,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EACP,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW;EACX,OAAO;EACP,gBAAgB;EAChB,eAAe;CACjB;AACF;;;;;;;;;AC9FA,MAAME,OAAI,KAAK;AA2Cf,MAAa,yBAAmD;CAC9D,WAAWA,KAAE,IAAK;CAClB,YAAYA,KAAE,GAAI;CAClB,cAAc;CACd,aAAa;AACf;AAWA,MAAMC,OAAKD,KAAE,KAAK,EAAE;AAGpB,MAAME,YAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,YAAS;AACf,MAAMC,WAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAG1C,MAAMC,SAAO;;;;;;AAOb,MAAa,mBAAmB,EAAE,aAChC,WAAW,eAAe,WAAW,eAAe,WAAW,eAAe,WAAW;AAE3F,IAAa,iBAAb,MAA4B;CAC1B;CACA;CACA,QAAe,CAAC;;CAEhB;;CAEA,eAAeL,KAAE,EAAG;;CAEpB,eAAe;;CAEf,aAAa;CAEb,YACE,UACA,MACA,EACE,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,GAChD,SAAS,GACT,SAAS,2BACwD,CAAC,GACpE;EACA,KAAK,WAAW;EAChB,KAAK,OAAO;EAEZ,MAAM,UAAUA,KAAE,SAAS,WAAW,GAAI;EAE1C,KAAK,WAAW;EAChB,IAAI,SAAS,OAAO,aAAa;EAEjC,MAAM,OAAO,IAAI;EACjB,MAAM,OAAO,IAAI,OAAO;EACxB,MAAM,QAAQA,MAAG,OAAO,aAAa,IAAI,QAAQ,QAAQA,KAAE,SAAS,SAAS,CAAC;EAC9E,MAAM,UAAUA,KAAE,OAAO,OAAO,aAAa,MAAM;EAEnD,KAAK,WAAWA,OAAI,IAAI,QAAQ,OAAO,eAAe,QAAQ,OAAO;EAErE,MAAM,cAAc,KAAK,OAAO,SAAS,WAAW,KAAK,UAAU,EAAG;EACtE,MAAM,WAAW,KAAK,OAAO,SAAS,WAAW,KAAK,UAAU,EAAG;EACnE,MAAM,SAAS,SAAS,eAAe;EACvC,IAAI,UAAU,GAAG;EAEjB,MAAM,UAAU,SAAS,OAAO,KAAK,GAAG,OAAO,SAAS,UAAU,OAAO,CAAC;EAC1E,MAAM,MAAM,QAAQ,QAAQ,OAAO,WAAW,QAAQ,QAAQ,CAAC;EAC/D,MAAM,SAAS,QAAQ,KAAK,WAAWA,KAAG,IAAI,MAAO,MAAM,CAAC;EAG5D,MAAM,MAAMA,MAAG,SAAS,KAAK,EAAG;EAChC,MAAM,aAAaA,KAAE,IAAI,GAAG;EAC5B,IAAI,QAAQ;EAEZ,IAAI,WAAW,GAAG;GAChB,QAAQ;GAER,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS;IAC3C,MAAM,IAAI,QAAQ,MAAM,KAAK,QAAQ,OAAO,aAAa,QAAQ;IAEjE,SAAS,KAAK,OAAO,IAAI,KAAK,WAAW,cAAc,IAAI,EAAG;GAChE;EACF;EAGA,MAAM,YAAY,KAAK,IAAI,KAAK,IAAI,SAAS,mBAAmB,GAAG,CAAC,GAAGA,KAAE,KAAM,CAAC;EAChF,MAAM,MAAMA,KAAE,IAAI,SAAS;EAC3B,MAAM,OAAOA,KAAE,YAAY,CAAC;EAE5B,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,GAAG,SAAS;GAC9C,MAAM,SAASA,MAAG,OAAO,IAAIM,eAAa,OAAO,OAAO,OAAO,KAAK;GACpE,MAAM,QAAQ,OAAO,IAAIA,cAAYC;GACrC,MAAM,OAAO;IAAE,GAAGP,KAAE,KAAK,IAAI,KAAK,CAAC;IAAG,GAAGA,KAAE,KAAK,IAAI,KAAK,CAAC;IAAG,GAAG;GAAE;GAClE,MAAM,OAAOA,KAAE,OAAO,IAAIM,WAAS;GACnC,IAAI,UAAU;GACd,IAAI;GAEJ,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM;IACzC,WAAW,OAAO;IAElB,IAAI,OAAO,SAAS;KAClB,QAAQ,SAAS,OAAO;KACxB;IACF;GACF;GAEA,KAAK,MAAM,KAAK;IAAE,UAAUF;IAAO;IAAQ;IAAO;GAAK,CAAC;EAC1D;EAGA,MAAM,SAAS,KAAK;EACpB,MAAM,SAASJ,KAAE,KAAK,SAAS,eAAe,EAAE;EAChD,MAAM,SAASA,KAAE,SAAS,kBAAkB,GAAI,IAAIA,KAAE,SAAS,SAAS;EAGxE,MAAM,SAAS,OAAe,UAAmB;GAC/C,MAAM,UAAU,KAAK,aAAa,KAAK;GACvC,MAAM,SAAS;IACb,GAAGA,KAAE,QAAQ,IAAI,OAAO,CAAC;IACzB,GAAGA,KAAE,QAAQ,IAAI,OAAO,CAAC;IACzB,GAAGA,KAAE,QAAQ,IAAI,OAAO,CAAC;GAC3B;GACA,MAAM,SAAS,KAAK,KAAK,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC;GACxF,MAAM,UAAU,SAAS,UAAU;GACnC,MAAM,MAAM,KAAK,MAAM;GAEvB,IAAI,KACF,IAAI,WAAW;IAAE,GAAGA,KAAE,SAAS,OAAO,CAAC;IAAG,GAAGA,KAAE,SAAS,OAAO,CAAC;IAAG,GAAGA,KAAE,SAAS,OAAO,CAAC;GAAE;EAC/F;EAEA,IAAI,QAAQ;EACZ,IAAI,QAAQ;EAEZ,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS;GAC3C,IAAI,QAAQ;GAEZ,IAAI,WAAW,GAAG;IAChB,MAAM,IAAI,QAAQ,MAAM,KAAK,QAAQ,OAAO,MAAM,QAAQ;IAE1D,QAAQ,KAAK,OAAO,IAAI,KAAK,WAAW,cAAc,IAAI,EAAG;IAC7D,IAAI,QAAQ,KAAK,QAAQA,KAAEC,OAAK,KAAK;GACvC;GAGA,MAAM,WAAW,KAAK,OAAQ,QAAQ,MAAM,SAAS,KAAM,IAAI,KAAK,MAAM;GAE1E,IAAI,SAAS,GAAG;GAEhB,MAAM,MAAMD,KAAE,KAAK,IAAI,QAAQ,CAAC;GAChC,MAAM,MAAM,KAAK,IAAI,QAAQ;GAC7B,MAAM,IAAIA,KAAE,OAAO,IAAI,GAAG;GAE1B,KAAK,IAAI,MAAM,GAAG,MAAM,OAAO,OAAO,SAAS;IAC7C,MAAM,QAAS,MAAMO,WAAU,QAAQ;IACvC,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI;IAC5B,MAAM,IAAIP,KAAE,KAAK,IAAI,KAAK,IAAI,GAAG;IAEjC,MAAM,OAAO;KAAE,GAAGA,KAAE,OAAO,IAAI,CAAC;KAAG;KAAG,GAAGA,KAAE,OAAO,IAAI,CAAC;IAAE,CAAC;GAC5D;EACF;EAEA,MAAM,SAAS;GAAE,GAAG,OAAO;GAAG,GAAGA,KAAE,OAAO,IAAI,CAAC;GAAG,GAAG,OAAO;EAAE,CAAC;EAC/D,MAAM,OAAO;GAAE,GAAG,OAAO;GAAG,GAAGA,KAAE,OAAO,IAAI,CAAC;GAAG,GAAG,OAAO;EAAE,CAAC;CAC/D;;CAGA,IAAI,OAAiC;EACnC,OAAO,KAAK;CACd;;;;;CAMA,OAAO,KAAc,MAAc,OAAe,MAAM,OAAa;EACnE,IAAI,KAAK,aAAa,MAAM,KAAK,eAAe,KAAK,MAAM;GACzD,KAAK,MAAM,GAAG;GACd,KAAK,eAAe;EACtB;EAEA,KAAK,aAAa;EAClB,KAAK,eAAeA,KAAE,OAAO,KAAK,YAAY;EAC9C,KAAK,eAAeA,KAAE,OAAO,KAAK,YAAY;CAChD;;CAGA,MAAM,KAAoB;EACxB,MAAM,SAAS,KAAK,KAAK;EACzB,MAAM,KAAKA,KAAE,IAAI,IAAI,OAAO,CAAC;EAC7B,MAAM,KAAKA,KAAE,IAAI,IAAI,OAAO,CAAC;EAC7B,MAAM,KAAKA,KAAE,IAAI,IAAI,OAAO,CAAC;EAI7B,KAAK,MAAM,OAAO,KAAK,OAAO;GAC5B,MAAM,IAAI,KAAK,IAAI,SAAS;GAC5B,MAAM,IAAI,KAAK,IAAI,SAAS;GAC5B,MAAM,IAAI,KAAK,IAAI,SAAS;GAC5B,MAAM,KAAKA,KAAE,CAAC;GACd,MAAM,UAAUA,KAAE,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,CAAC;GACvD,MAAM,KAAKA,KAAE,IAAI,OAAO;GACxB,MAAM,KAAK,IAAI;GACf,MAAM,QAAQ,KAAK;GACnB,MAAM,KAAKA,KAAE,KAAK;GAClB,MAAM,IAAI,IAAI;GACd,IAAI,EAAE,KAAK,IAAI,QAAQ,EAAE,IAAI,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC,IAAI,MAAO;GAE3D,MAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE;GAC7B,MAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE;GAC7B,MAAM,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE;GAC7B,MAAM,MAAMA,KAAE,EAAE;GAChB,MAAM,WAAWA,KAAE,IAAI,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,EAAE,CAAC;GAC9D,MAAM,KAAKA,KAAE,KAAK,QAAQ;GAC1B,MAAM,KAAK,KAAK;GAChB,MAAM,KAAK,MAAM;GAEjB,IAAI,OAAO;IAAE,GAAGA,KAAE,KAAK,KAAK,KAAK,EAAE;IAAG,GAAGA,KAAE,KAAK,KAAK,KAAK,EAAE;IAAG,GAAGA,KAAE,KAAK,KAAK,KAAK,EAAE;GAAE;EACzF;CACF;;;;;;;;;CAUA,KACE,EAAE,QAAQ,OAAO,OAAO,eACxB,QACA,MACA,QACA,YACkB;EAClB,IAAI,CAAC,KAAK,MAAM,UAAU,EAAE,QAAQ,IAAI,OAAO,KAAA;EAE/C,MAAM,SAAS,KAAK,KAAK;EACzB,MAAM,MAAM,OAAO;EAEnB,IAAI,eADW,QAAQ,eAAe,QAAQ,IAC3B,GAAQ,KAAK,KAAK,QAAQ,QAAQ,MAAM,IAAI,GAAG,OAAO,KAAA;EAEzE,IAAI,KAAK,eAAeA,KAAE,IAAI,GAAG;GAC/B,KAAK,MAAM,GAAG;GACd,KAAK,eAAe;EACtB;EAEA,MAAM,QAAQ,KAAK,SAAS,OAAO;EACnC,IAAI,CAAC,OAAO,OAAO,KAAA;EAEnB,MAAM,QAAQ,gBAAgB,MAAM,OAAO;EAE3C,IAAI,OAAO,KAAK;EAChB,IAAI,QAAQ,IAAK,OAAOA,MAAG,KAAK,QAAQ,MAAO,QAAQ,QAAS,IAAI;EAEpE,IAAI,KAAKA,KAAE,IAAI,IAAI,OAAO,CAAC;EAC3B,IAAI,KAAKA,KAAE,IAAI,IAAI,OAAO,CAAC;EAC3B,IAAI,KAAKA,KAAE,IAAI,IAAI,OAAO,CAAC;EAC3B,MAAM,WAAWA,KAAE,IAAIA,KAAE,KAAK,KAAKA,KAAEA,KAAE,KAAK,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;EAEtE,KAAKA,KAAE,KAAK,QAAQ;EACpB,KAAKA,KAAE,KAAK,QAAQ;EACpB,KAAKA,KAAE,KAAK,QAAQ;EAEpB,MAAM,EAAE,UAAU,KAAK;EACvB,MAAM,UAAqE,CAAC;EAE5E,KAAK,MAAM,EAAE,UAAU,GAAG,QAAQ,OAAO,UAAU,KAAK,OAAO;GAC7D,MAAM,IAAI;IAAE,GAAGA,KAAE,OAAO,IAAI,EAAE,CAAC;IAAG,GAAGA,KAAE,OAAO,IAAI,EAAE,CAAC;IAAG,GAAGA,KAAE,OAAO,IAAI,EAAE,CAAC;GAAE;GAC7E,MAAM,IAAI;IAAE,GAAGA,KAAE,EAAE,IAAI,IAAI,CAAC;IAAG,GAAGA,KAAE,EAAE,IAAI,IAAI,CAAC;IAAG,GAAGA,KAAE,EAAE,IAAI,IAAI,CAAC;GAAE;GACpE,MAAM,QAAQ,CAAC,QAAQ,eAAe,GAAG,IAAI,CAAC,CAAC;GAC/C,IAAI,SAAS,GAAG;GAGhB,IAAI,IAAI;GACR,MAAM,UAAUA,KAAE,IAAIA,KAAE,KAAK,KAAKA,KAAEA,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;GAC3E,MAAM,MAAMA,KAAEA,KAAE,KAAKA,KAAE,EAAE,IAAI,OAAO,IAAI,KAAKA,KAAE,EAAE,IAAI,OAAO,CAAC,IAAI,KAAKA,KAAE,EAAE,IAAI,OAAO,CAAC;GACtF,IAAI,MAAM,GAAG;GACb,IAAI,MAAM,KAAM,IAAIA,KAAE,MAAM,OAAO,EAAE;GAIrC,IAAI,KAAKA,KAAE,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,KAAK,CAAC;GACtC,IAAI,KAAKA,KAAE,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,KAAK,CAAC;GACtC,IAAI,KAAKA,KAAE,EAAE,IAAI,KAAK,IAAI,EAAE,IAAI,KAAK,CAAC;GACtC,MAAM,KAAKA,KAAE,SAASA,KAAE,KAAK,KAAKA,KAAEA,KAAE,KAAK,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;GAErE,KAAKA,KAAE,KAAK,EAAE;GACd,KAAKA,KAAE,KAAK,EAAE;GACd,KAAKA,KAAE,KAAK,EAAE;GAEd,IAAI,KAAKA,KAAE,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC;GAC9B,IAAI,KAAKA,KAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;GAC9B,IAAI,KAAKA,KAAE,EAAE,IAAI,KAAK,KAAK,EAAE,CAAC;GAC9B,MAAM,KAAKA,KAAE,SAASA,KAAE,KAAK,KAAKA,KAAEA,KAAE,KAAK,KAAK,KAAK,EAAE,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC;GAErE,KAAKA,KAAE,KAAK,EAAE;GACd,KAAKA,KAAE,KAAK,EAAE;GACd,KAAKA,KAAE,KAAK,EAAE;GAEd,IAAI,QAAQ,QAAQ,IAAIA,KAAEA,KAAE,QAAQ,MAAM,IAAI,CAAC;GAC/C,IAAI,IAAI,OAAQ,CAAC,OAAO;GAGxB,MAAM,QAAQ,QACV;IAACK,OAAK,MAAM,CAAC;IAAGA,OAAK,MAAM,CAAC;IAAGA,OAAK,MAAM,CAAC;IAAGA,OAAK,CAAC;GAAC,IACrD;IAACA,OAAK,MAAM,IAAI,CAAC;IAAGA,OAAK,MAAM,IAAI,CAAC;IAAGA,OAAK,MAAM,IAAI,CAAC;IAAG;GAAG;GACjE,MAAM,UAAU,GAAW,GAAW,OACpC,QAAQ,KAAK;IACX,IAAI;KACFL,KAAEA,KAAE,EAAE,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE;KAC1BA,KAAEA,KAAE,EAAE,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE;KAC1BA,KAAEA,KAAE,EAAE,IAAI,IAAI,EAAE,IAAI,IAAI,EAAE;IAC5B;IACA;IACA;GACF,CAAC;GAEH,OAAO,GAAG,GAAG,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;GACjC,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;GAClC,OAAO,IAAI,IAAI,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;GACnC,OAAO,IAAI,GAAG,CAAC,MAAM,IAAI,MAAM,EAAE,CAAC;EACpC;EAEA,IAAI,CAAC,QAAQ,QAAQ,OAAO,KAAA;EAE5B,MAAM,WAAW,IAAI,WAAW,QAAQ,SAASG,SAAM;EACvD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;EAE/C,QAAQ,SAAS,EAAE,IAAI,IAAI,SAAS,UAAU;GAC5C,OAAO,IAAI,IAAK,QAAQA,YAAU,CAAC;GACnC,SAAS,IAAI,OAAO,QAAQA,YAAS,EAAE;GACvC,OAAO,IAAI,KAAK,QAAQA,YAAS,MAAM,CAAC;EAC1C,CAAC;EAGD,MAAM,UAAU,IAAI,YAClB,MAAM,KAAK,EAAE,QAAQ,QAAQ,SAAS,EAAE,IAAI,GAAG,SAC7C;GAAC;GAAG;GAAG;GAAG;GAAG;GAAG;EAAC,CAAC,CAAC,KAAK,WAAW,OAAO,IAAI,MAAM,CACtD,CAAC,CAAC,KAAK,CACT;EACA,MAAM,OAAkB;GACtB,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IACE,YAAY;IACZ,aAAa;IACb,WAAW,QAAQ,SAAS;IAC5B,cAAc,QAAQ;IACtB,SAAS;GACX,CACF;GACA;GACA;EACF;EACA,MAAM,YAAsB;GAC1B,QAAQ;GACR,aAAa;GACb,aAAa,QAAQ;GACrB,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAKE;IAAO,KAAKA;GAAM;GACtC,gBAAgB;IAAE,QAAQA;IAAO,QAAQ;GAAE;EAC7C;EAEA,MAAM,OAAOJ,KAAE,OAAO,IAAI,QAAQ,CAAC;EACnC,MAAM,QAAQ,KAAK,KAAM,QAAQ,QAAQ,KAAM,aAAa,CAAC;EAC7D,MAAM,MAAMA,MAAG,QAAQ,KAAK,cAAc,KAAK;EAE/C,OAAO;GACL;GACA;GACA,WAAW;GACX,YAAY;GACZ,OAAO,QAAQ;GAEf,OAAO,QAAQ;GACf;GACA,cAAc;GACd,SAAS;IAAC;IAAG;IAAG;IAAG;GAAC;GACpB,SAASI;GACT,UAAUA;GACV,aAAa;GACb,OAAO;GACP,SAAS;IACP,MAAM,MAAM,QAAQ;IACpB,OAAO,MAAM;IACb,SAAS;IACT,OAAO;GACT;GACA,MAAM;GACN,YAAY;GACZ,WAAW;GACX,WAAW;GACX,eAAe;GACf,kBAAkB;GAClB,OAAO;GACP,WAAW,QAAQ,UAAU;GAC7B,OAAO;GACP,gBAAgB;GAChB,eAAe;GACf,KAAK,MAAM,OAAO,KAAK,OAAO,IAAI,KAAK;EACzC;CACF;;;;;;CAOA,MAAM,KAAoB;EACxB,MAAM,OAAO,KAAK;EAClB,MAAM,SAAS,KAAK,KAAK;EAEzB,MAAM,YAAY,EAAE,UAAU,QAAa;GACzC,MAAM,KAAKJ,KAAEA,KAAE,OAAO,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC;GACtC,MAAM,KAAKA,KAAEA,KAAE,OAAO,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC;GACtC,MAAM,KAAKA,KAAEA,KAAE,OAAO,IAAI,EAAE,CAAC,IAAI,IAAI,CAAC;GAEtC,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK;EAClC;EAEA,IAAI;EAEJ,GAAG;GACD,UAAU;GACV,IAAI,KAAK,UAAU,GAAG;GAEtB,IAAI,SAAS;GACb,IAAI,WAAW;GAEf,KAAK,IAAI,KAAK,GAAG,KAAK,KAAK,QAAQ,MAAM;IACvC,IAAI,CAAC,QAAQ,WAAW,SAAS,KAAK,KAAK,EAAG;IAE9C,MAAM,UAAU,SAAS,KAAK,GAAI;IAElC,IAAI,EAAE,WAAW,UAAU;KACzB,SAAS;KACT;IACF;IAEA,IAAI,EAAE,KAAK,IAAI,WAAW,OAAO,IAAI,KAAK;IAC1C;IACC,CAAC,KAAK,KAAK,IAAI,KAAK,OAAO,CAAC,KAAK,KAAM,KAAK,KAAK,EAAG;IACrD,SAAS;GACX;EACF,SAAS,UAAU;CACrB;AACF;;;;;;;;;AC5fA,MAAMQ,OAAI,KAAK;;AAgDf,MAAa,cAAc,EAAE,SAAS,KAAM,MAAM,aAA2B;CAC3E,MAAM,YAAYA,KAAE,MAAM,SAAS,CAAC;CACpC,MAAM,cAAcA,KAAE,SAAU,OAAO,SAAS,IAAK,CAAC;CAEtD,OAAOA,MAAG,cAAc,YAAY,cAAc,aAAaA,KAAE,MAAM,CAAC;AAC1E;AAGA,MAAMC,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAMC,WAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC1C,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAG1C,MAAMC,SAAO;AAEb,MAAMC,SAAO,GAAY,OAAyB;CAChD,GAAGN,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;AAChB;AACA,MAAMO,SAAO,GAAY,OAAyB;CAChD,GAAGP,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;CACd,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;AAChB;AACA,MAAMQ,YAAU,EAAE,GAAG,GAAG,KAAc,QAAyB;CAC7D,GAAGR,KAAE,IAAI,EAAE;CACX,GAAGA,KAAE,IAAI,EAAE;CACX,GAAGA,KAAE,IAAI,EAAE;AACb;;;;;;AAOA,MAAM,YACJ,EAAE,OAAO,QAAQ,GAAG,aAAaI,SAAO,aAAaA,WACrD,UACA,MACA,OACA,IACA,OACA,eACqB;CACrB,IAAI,CAAC,OAAO,OAAO,KAAA;CAEnB,MAAM,SAASI,SAAOA,SAAO,OAAO,IAAI,GAAGR,KAAE,KAAK,CAAC;CACnD,MAAM,OAAOQ,SAAOA,SAAO,IAAI,IAAI,GAAGR,KAAE,KAAK,CAAC;CAE9C,MAAM,KAAKM,MAAIC,MAAI,UAAU,MAAM,GAAG,IAAI;CAC1C,MAAM,KAAKD,MAAIA,MAAI,UAAU,MAAM,GAAG,IAAI;CAC1C,MAAM,KAAKC,MAAID,MAAI,UAAU,MAAM,GAAG,IAAI;CAC1C,MAAM,KAAKC,MAAIA,MAAI,UAAU,MAAM,GAAG,IAAI;CAC1C,MAAM,SAASC,SAAOF,MAAIA,MAAIA,MAAI,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,GAAI;CACzD,MAAM,QAAQ,GAAY,MAAeE,SAAOF,MAAI,GAAG,CAAC,GAAG,EAAG;CAC9D,MAAM,EAAE,IAAI,IAAI,IAAI,OAAO;CAC3B,MAAM,KAAKN,KAAEA,KAAE,KAAK,EAAE,IAAI,EAAG;CAC7B,MAAM,KAAKA,KAAEA,KAAE,KAAK,EAAE,IAAI,EAAG;CAE7B,MAAM,MAAmC;EACvC;GAAC;GAAQ;GAAI;EAAE;EACf;GAAC;GAAI;GAAI;EAAE;EACX;GAAC,KAAK,IAAI,EAAE;GAAG;GAAI;EAAE;EACrB;GAAC;GAAI;GAAI;EAAE;EACX;GAAC,KAAK,IAAI,EAAE;GAAG;GAAI;EAAE;EACrB;GAAC;GAAI;GAAI;EAAE;EACX;GAAC,KAAK,IAAI,EAAE;GAAG;GAAI;EAAE;EACrB;GAAC;GAAI;GAAI;EAAE;EACX;GAAC,KAAK,IAAI,EAAE;GAAG;GAAI;EAAE;EACrB;GAAC;GAAI;GAAI;EAAE;CACb;CACA,MAAM,IAAIK,OAAK,KAAK;CACpB,MAAM,QAAQ;EAACA,OAAK,WAAW,CAAC;EAAGA,OAAK,WAAW,CAAC;EAAGA,OAAK,WAAW,CAAC;EAAG;CAAC;CAC5E,MAAM,QAAQ;EAACA,OAAK,WAAW,CAAC;EAAGA,OAAK,WAAW,CAAC;EAAGA,OAAK,WAAW,CAAC;EAAG;CAAC;CAE5E,MAAM,WAAW,IAAI,WAAW,IAAI,SAASH,QAAM;CACnD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;CAE/C,IAAI,SAAS,CAAC,EAAE,GAAG,GAAG,KAAK,GAAG,IAAI,UAAU;EAC1C,OAAO,IAAI;GAAC;GAAG;GAAG;EAAC,GAAI,QAAQA,WAAU,CAAC;EAC1C,SAAS,IAAI,UAAU,IAAI,QAAQ,OAAO,QAAQA,WAAS,EAAE;EAC7D,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQA,WAAS,MAAM,CAAC;CAC9C,CAAC;CAED,MAAM,QAAQ,IAAI;CAwBlB,OAAO;EACL,MAAA;GAvBA,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IAAE,YAAY;IAAG,aAAa;IAAG,WAAW,QAAQ;IAAG,cAAc;IAAO,SAAS;GAAE,CACzF;GACA,SAAS,YAAY,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OAAO,EAAE;GAC1D;EAeG;EACH,WAAA;GAbA,QAAQ;GACR,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAKE;IAAO,KAAKA;GAAM;GACtC,gBAAgB;IAAE,QAAQA;IAAO,QAAQ;GAAE;EAKnC;EACR,WAAW;EACX,YAAY;EACZ;EAEA,OAAO,QAAQ;EACf;EACA,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EAEP,SAAS;GAAE,MAAM,MAAM,QAAQ;GAAM,OAAO,MAAM;GAAS,SAAS;GAAiB,OAAO;EAAE;EAC9F,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW,gBAAgB,MAAM,OAAO,IAAI,UAAU;EACtD,OAAO;EAEP,gBAAgB;EAChB,eAAe;CACjB;AACF;;;;;;;AAQA,MAAa,iBACX,MACA,UACA,QACA,YACA,QAAQ,GACR,OAAO,MACI;CACX,MAAM,EAAE,UAAU,KAAK,gBAAgB;CAEvC,MAAM,KAAK,SAAS,IAAI,IAAI;CAC5B,MAAM,KAAK,SAAS,IAAI,IAAI;CAC5B,MAAM,KAAK,SAAS,IAAI,IAAI;CAC5B,MAAM,MAAMH,KAAE,EAAE;CAChB,MAAM,UAAUA,KAAE,IAAI,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,EAAE,CAAC;CAC7D,MAAM,MAAM;EAAE,GAAGA,KAAE,KAAK,OAAO;EAAG,GAAGA,KAAE,KAAK,OAAO;EAAG,GAAGA,KAAE,MAAM,OAAO;CAAE;CAG1E,MAAM,MAAM,YAAY,EAAE;CAC1B,MAAM,MAAM,YAAY,EAAE;CAC1B,MAAM,MAAM,YAAY,EAAE;CAC1B,MAAM,KAAKA,KAAE,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC;CACtC,MAAM,KAAKA,KAAE,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC;CACtC,MAAM,KAAK,MAAM,IAAI,IAAI,IAAI,IAAI;CACjC,MAAM,SAAS,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE;CACxD,MAAM,QAAQ;EAAE,GAAGA,KAAE,KAAK,MAAM;EAAG,GAAGA,KAAE,KAAK,MAAM;EAAG,GAAGA,KAAE,KAAK,MAAM;CAAE;CAExE,MAAM,KAAK;EACT,GAAGA,KAAE,MAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;EACtC,GAAGA,KAAE,MAAM,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,CAAC;EACtC,GAAGA,KAAE,IAAI,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,CAAC;CACxC;CAEA,MAAM,QAAQA,MAAG,KAAK,UAAU,OAAQ,IAAI;CAC5C,MAAM,QAAgB,CAAC;CACvB,MAAM,OAAO,SAAS,KAAK,QAAQ,CAAC,GAAG,UAAU,OAAO,OAAO,IAAI,OAAO,UAAU;CACpF,IAAI,MAAM,MAAM,KAAK,IAAI;CAEzB,IAAI,KAAK,QAAQ;EACf,MAAM,SAAS,SAAS,KAAK,QAAQ,UAAU,OAAO,OAAO,IAAIA,KAAE,QAAQ,KAAK,GAAG,UAAU;EAC7F,IAAI,QAAQ,MAAM,KAAK,MAAM;CAC/B;CAEA,OAAO;AACT;;;;;;;;;AC7NA,MAAMS,aAAW,MAAY,KAAU,WAA4B;CACjE,MAAM,OAAO,IAAI,OAAO,KAAK,IAAI;CAEjC,OAAO,SAAS,KAAA,KAAa,KAAK,OAAO,UAAU,KAAK,OAAO;AACjE;;;;;;AAOA,MAAM,UACJ,MACA,QACA,KACA,WACuB;CACvB,MAAM,OAAO,IAAI,KAAK,KAAK,QAAQ,MAAM,IAAI,CAAC;CAE9C,OAAO,QAAQ,KAAK,OAAO,KAAK,KAAK,OAAO,SAAS,KAAK,MAAM,KAAA;AAClE;AAEA,UAAU,MAAM,EAAE,SAA6D;CAC7E,KAAK,MAAM,EAAE,YAAY,OAAO,MAAM;AACxC;;AAGA,MAAM,cAAc,QAAiB,QAAgB,KAAU,WAAmB;CAChF,MAAM,OAAO,IAAI,OAAO,KAAK;EAAE;EAAQ;CAAO,CAAC;CAE/C,OAAO,QAAQ,KAAK,MAAM,KAAK,KAAK,OAAO,SAAS,KAAK,MAAM,KAAA;AACjE;;AAGA,MAAM,cAAc,MAAe,OAA0D;CAC3F,MAAM,QAAQ,QAAQ,SAAS,IAAI,IAAI;CACvC,MAAM,SAAS,QAAQ,UAAU,KAAK;CACtC,IAAI,EAAE,SAAS,IAAI,OAAO,KAAA;CAC1B,OAAO;EAAE,KAAK;GAAE,QAAQ;GAAM,WAAW,QAAQ,aAAa,OAAO,MAAM;EAAE;EAAG;CAAO;AACzF;;;;;AAMA,MAAa,WACX,SACA,MACA,IACA,UACa;CACb,MAAM,QAA6C,CAAC;CACpD,MAAM,OAAO,WAAW,MAAM,EAAE;CAEhC,KAAK,MAAM,EAAE,QAAQ,UAAU,QAAQ,YAAY,SAAS;EAC1D,MAAM,MAAc;GAAE;GAAU;GAAQ,GAAI,WAAW,KAAA,KAAa,EAAE,OAAO;EAAG;EAEhF,IAAI,OAAO,SAAS,KAAA,KAAa,MAAM;GACrC,MAAM,WAAW,WAAW,UAAU,OAAO,MAAM,KAAK,KAAK,KAAK,MAAM;GACxE,IAAI,aAAa,KAAA,GAAW,MAAM,KAAK;IAAE;IAAU;GAAI,CAAC;EAC1D;EAEA,KAAK,MAAM,EAAE,SAAS,WAAW,OAAO,YAAY,CAAC,GAAG;GACtD,MAAM,UAAU,QAAQ,OAAO,KAAK;GACpC,MAAM,QAAQ,WACZ,QAAQ,eAAe,MAAM,OAAO,GACpC,QAAQ,eAAe,IAAI,OAAO,CACpC;GACA,IAAI,CAAC,OAAO;GAEZ,MAAM,EAAE,KAAK,WAAW;GAExB,MAAM,SAAS,SAAe;IAC5B,IAAI,CAACA,UAAQ,MAAM,KAAK,MAAM,GAAG;IAEjC,MAAM,EAAE,SAAS;IAEjB,IAAI,QAAQ,KAAK,SAAS,SAAS,SAAS;KAC1C,MAAM,WAAW,OAAO,MAAM,QAAQ,QAAQ,KAAK,MAAM;KAEzD,IAAI,aAAa,KAAA,GAAW;MAC1B,MAAM,SAAS,OAAO,SAAS,KAAK,EAAE,KAAK;MAE3C,MAAM,KAAK;OAAE;OAAU,KAAK,SAAS;QAAE,GAAG;QAAK;OAAO,IAAI;MAAI,CAAC;KACjE;IACF;IAEA,IAAI,KAAK,MAAM,MAAM,KAAK,IAAI;IAC9B,IAAI,KAAK,OAAO,MAAM,KAAK,KAAK;GAClC;GAEA,MAAM,QAAQ,IAAI;EACpB;CACF;CAEA,OAAO,MACJ,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,CACvC,MAAM,GAAG,KAAK,CAAC,CACf,KAAK,EAAE,UAAU,GAAG;AACzB;;;;;;;;;ACtHA,MAAMC,OAAI,KAAK;;;;;AA6Df,MAAa,oBAAoB,WAA2BA,KAAE,KAAK,IAAI,SAAS,SAAS,CAAC,CAAC;;;;;;AAO3F,MAAa,eAAe,SAAiB,SAAS,MACpD,KAAK,MAAM,UAAU,IAAI,WAAW,EAAG;AAqCzC,MAAM,yBAAS,IAAI,QAAyB;;AAG5C,MAAM,SAAS,EAAE,WAAW,eAAe,KAAK,YAAiC;CAC/E;CACA;CACA,GAAG,IAAI,KAAK,EAAE,YAAY,KAAK;CAC/B,GAAG,MAAM,KAAK,EAAE,YAAY,KAAK;AACnC;;AAGA,MAAM,WAAW,SAA0B;CACzC,IAAI,QAAQ,OAAO,IAAI,IAAI;CAC3B,IAAI,OAAO,OAAO;CAElB,MAAM,MAAc,CAAC;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;EAAK,GAAG;EAAK,OAAO;CAAE,CAAC;CAE7D,KAAK,IAAI,KAAK,GAAG,KAAK,IAAI,MAAM;EAC9B,MAAM,QAAQA,MAAG,KAAK,KAAKA,KAAE,iBAAkB,CAAC;EAChD,MAAM,IAAIA,KAAE,KAAK,IAAI,KAAK,CAAC;EAC3B,MAAM,IAAIA,KAAE,KAAK,IAAI,KAAK,CAAC;EAE3B,IAAI,KAAK;GAAE,GAAG;GAAG,GAAG,CAAC;GAAG,GAAGA,MAAG,IAAI,KAAK,EAAG;GAAG,GAAGA,KAAE,KAAM,IAAI,EAAG;GAAG,OAAO;EAAE,CAAC;CAC9E;CAEA,MAAM,QAAQA,KAAE,KAAK,UAAU,iBAAiB,EAAG;CACnD,MAAM,OAAOA,KAAE,IAAI,KAAK;CACxB,MAAM,SAAS,IAAI;CASnB,QAAQ;EACN,MAAM;EACN,WAAW;EACX,QAAQ;EACR,eAAe;EACf;EACA,OAdY,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,UAAU;GACxC,GAAGA,KAAE,OAAO,OAAO,IAAI,QAAQ,KAAK,CAAC;GACrC,GAAGA,KAAE,OAAO,OAAO,IAAI,QAAQ,KAAK,CAAC;GACrC,GAAGA,KAAE,OAAO,OAAO,IAAI,QAAQ,KAAK,CAAC;GACrC,GAAGA,KAAE,OAAO,OAAO,IAAI,QAAQ,KAAK,CAAC;GACrC,OAAO;EACT,EAQM;EACJ,WAAW,MAAM,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;EAC7C,KAAK;EACL,OAAO;EACP,GAAG;EACH,GAAG;EACH,YAAY;CACd;CACA,OAAO,IAAI,MAAM,KAAK;CACtB,OAAO;AACT;;AAGA,MAAM,YAAY,SAAiB,QAAgB,IAAY,SAAyB;CACtF,IAAI,SAAS,SAAS,OAAOA,KAAE,KAAK,IAAI,UAAU,IAAI,MAAM,CAAC;CAC7D,IAAI,SAAS,SAAS,OAAOA,KAAE,KAAK,IAAI,UAAU,MAAM,MAAM,CAAC;CAC/D,OAAO;AACT;;AAGA,MAAM,QAAQ,MAAY,QAAgB,IAAY,SAAiB;CACrE,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,SAAS,KAAK,OAAO,QAAQ,IAAI,IAAI,GAAG,CAAC,GAAG,CAAC;AAC9E;;AAGA,MAAM,cAAc,MAAY,IAAY,SAAiB;CAC3D,IAAI,IAAI,KAAK,OAAO;EAClB,MAAM,OAAO,KAAK,KAAK;EAEvB,KAAK,QAAQA,KAAE,IAAI;EACnB,IAAI,OAAO,GAAG,KAAK,QAAQ;CAC7B,OAAO,IAAI,IAAI,KAAK,OAAO;EACzB,MAAM,OAAO,KAAK,QAAQ;EAE1B,KAAK,QAAQA,KAAE,IAAI;EACnB,IAAI,OAAO,GAAG,KAAK,QAAQ;CAC7B;CAEA,KAAK,QAAQ,KAAK,IAAI,KAAK,IAAI,KAAK,OAAO,CAAC,GAAG,CAAC;AAClD;;;;;;AAOA,MAAa,cAAc,MAAY,SAAiB;CACtD,MAAM,QAAQ,QAAQ,IAAI;CAE1B,MAAM,QAAQ,MAAM,KAAK;CACzB,MAAM,OAAOA,KAAE,IAAI;CAEnB,MAAM,EAAE,SAAS,GAAG,UAAU,MAAM,KAAK,iBAAiB,CAAC;CAE3D,MAAM,YAAY,SAChB,MAAM,WACNA,KAAE,IAAI,MAAM,MAAM,GAClBA,KAAE,MAAM,OAAO,MAAM,GACrBA,KAAE,MAAM,OAAO,OAAO,CACxB;AACF;;;;;AAMA,MAAa,eAAe,SAAwB;CAClD,MAAM,QAAQ,OAAO,IAAI,IAAI;CAC7B,MAAM,QAAQ,OAAO;CACrB,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO;CAC7B,OAAO,MAAM,KAAK,CAAC,CAAC,OAAO,OAAO,OAAO,UAAU,MAAM,GAAG;AAC9D;;AAGA,MAAa,iBAAiB,SAA6D;CACzF,MAAM,EAAE,WAAW,kBAAkB,QAAQ,IAAI;CAEjD,OAAO;EAAE;EAAW;CAAc;AACpC;;;;;AAMA,MAAa,YAAY,SAAe;CACtC,QAAQ,IAAI,CAAC,CAAC,gBAAgB;AAChC;;AAGA,MAAM,SAAS,EAAE,KAAK,OAAO,UAA6B;CACxD,MAAM,SAAS,IAAI,EAAE,CAAE;CACvB,IAAI,QAAQ,GAAG,OAAO;CAEtB,IAAI,MAAM;CACV,KAAK,MAAM,EAAE,WAAW,IAAI,MAAM,CAAC,GAAG,MAAMA,KAAE,MAAM,KAAK;CACzD,IAAI,MAAM,GAAG,OAAOA,KAAE,SAASA,KAAE,EAAG,IAAI,MAAMA,KAAE,IAAI,EAAE,IAAIA,KAAE,EAAG,CAAC;CAChE,KAAK,MAAM,EAAE,WAAW,OAAO,MAAMA,KAAE,MAAM,KAAK;CAClD,OAAOA,KAAE,SAASA,KAAE,EAAG,IAAI,MAAMA,KAAE,IAAI,EAAE,IAAIA,KAAE,EAAG,CAAC;AACrD;;AAGA,MAAM,YAAY,EAAE,MAAM,QAAgB,OAAe,WAAmB;CAC1E,MAAM,SAASA,KAAE,QAAQ,MAAM;CAC/B,MAAM,YAAYA,KAAE,QAAQ,EAAG;CAC/B,MAAM,aAAa,SAAS;CAE5B,MAAM,OAAO,KAAK,IAAI,OAAOA,KAAE,KAAK,KAAK,GAAG,CAAC;CAC7C,MAAM,SAASA,KAAE,YAAY,IAAI;CACjC,MAAM,SAASA,KAAE,EAAE,aAAaA,KAAE,OAAO,MAAM,EAAE;CAEjD,OAAO;EAAE,SAAS;EAAW,SAASA,KAAE,UAAU;EAAG;EAAQ;EAAQ;CAAK;AAC5E;;AAKA,MAAM,WAAW,MAAe,IAAa,YAAoB,SAA8B;CAC7F,MAAM,EAAE,SAAS,KAAK,QAAQ,WAAW;CACzC,IAAI,CAAC,SAAS,OAAO;CAErB,MAAM,YAAYA,KAAE,aAAaA,KAAE,GAAI,CAAC;CACxC,MAAM,UAAUA,KAAE,OAAO,OAAOA,KAAE,SAAS,QAAQ,KAAK,OAAO,KAAK,MAAM,CAAC,CAAC,SAAS,OAAO,IAAI,CAAC;CAEjG,KAAK,MAAM,OAAO,QAAQ,MAAM,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,GAAG;EAClD,IAAI,IAAI,QAAQ;EAChB,IAAI,IAAI,WAAW,KAAA,MAAc,IAAI,WAAW,OAAO,IAAI,WAAW,SAAS;EAG/E,IAAI,IAAIA,KAAE,QAAQ,eAAe,IAAI,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC;EAC3D,IAAI,IAAIA,KAAE,GAAI,GAAG,IAAIA,KAAE,GAAI;EAC3B,IAAI,WAAW,KAAK,KAAK,IAAI,SAAS,WAAW,OAAO;CAC1D;CAEA,OAAO;AACT;;AAGA,MAAM,iBACJ,QACA,MACA,UACA,YACA,GACA,MACY;CACZ,MAAM,EAAE,WAAW;CAGnB,MAAM,QAAQ;EACZ,GAAGA,KAAEA,KAAE,IAAI,OAAO,OAAO,IAAIA,KAAE,OAAO,OAAO,OAAO,MAAM,CAAC;EAC3D,GAAGA,KAAEA,KAAE,IAAI,OAAO,OAAO,IAAIA,KAAE,OAAO,OAAO,OAAO,MAAM,CAAC;EAC3D,GAAG,CAAC,OAAO;CACb;CACA,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,OAAO;CACvC,MAAM,MAAM;EACV,GAAGA,KAAE,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;EACrD,GAAGA,KAAE,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;EACrD,GAAGA,KAAE,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,CAAC;CACvD;CACA,MAAM,UAAU,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;CAC3E,MAAM,MAAM,OAAO;CACnB,MAAM,SAASA,KAAEA,KAAE,IAAI,IAAI,OAAO,IAAI,QAAQ;CAC9C,MAAM,KAAK;EACT,GAAGA,KAAEA,KAAE,IAAI,IAAI,OAAO,IAAI,WAAW,IAAI,CAAC;EAC1C,GAAGA,KAAEA,KAAE,IAAI,IAAI,OAAO,IAAI,WAAW,IAAI,CAAC;EAC1C,GAAGA,KAAE,SAAS,IAAI,CAAC;CACrB;CAEA,OAAO,QAAQ,KAAK,IAAI,YAAY,IAAI;AAC1C;AAGA,MAAM,UAAkD;CACtD,CAAC,IAAI,EAAE;CACP,CAAC,GAAG,EAAE;CACN,CAAC,GAAG,EAAE;CACN,CAAC,GAAG,CAAC;CACL,CAAC,GAAG,CAAC;CACL,CAAC,GAAG,CAAC;AACP;AAEA,MAAM,aAAa;CAAC;CAAG;CAAI;CAAI;CAAI;AAAE;;AAGrC,MAAM,aAAa,KAAa,cAC9B,MAAM,YAAYA,KAAE,YAAY,KAAM,MAAM,EAAG,IAAIA,KAAE,YAAY,KAAM,MAAM,EAAG;;AAGlF,MAAM,UACJ,OACA,MACA,KACA,IACA,SACG;CACH,MAAM,EAAE,KAAK,UAAU;CACvB,MAAM,KAAKA,KAAE,MAAM,OAAOA,KAAE,KAAK,UAAU,GAAI,CAAC;CAChD,MAAM,OAAOA,KAAE,MAAM,OAAOA,KAAE,KAAK,WAAW,GAAI,CAAC;CACnD,MAAM,SAAS,SAAS,KAAK,QAAQ,KAAK,OAAO,KAAK,MAAM;CAC5D,MAAM,EAAE,OAAO,WAAW;CAC1B,MAAM,EAAE,GAAG,IAAI,GAAG,IAAI,eAAe;CAErC,IAAI,MAAM,WAAW,WAAW,UAAU,QAAQ,UAAU;CAC5D,IAAI,MAAM,GAAG,MAAM;CACnB,MAAM,OAAO,KAAK,WAAW,MAAM,KAAK,WAAW;CACnD,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,MAAM,KAAK,UAAU,CAAC,CAAC;CAEtD,MAAM,SAAS,KAAK,IAAI,aAAaA,KAAE,KAAK,eAAe,CAAC,GAAG,EAAE;CACjE,MAAM,YAAY,GAAW,MAC3B,IAAI,CAAC,UAAU,QAAQ,SAAS,KAAK,IAAI,CAAC,UAAU,SAAS,SAAS;CACxE,MAAM,MAAM,KAAK,OAAO;CACxB,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,MAAM,KAAK,IAAI,IAAI,IAAI;CACvB,MAAM,WAAWA,KAAE,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;CAEzD,MAAM,QAAQ,MAAY,GAAW,GAAW,OAAe;EAC7D,IAAI,CAAC,SAAS,GAAG,CAAC,GAAG,OAAO,KAAK,MAAM,KAAK,GAAG,IAAI,IAAI;EAEvD,MAAM,QAAQ,cAAc,QAAQ,MAAM,UAAU,YAAY,GAAG,CAAC,IAAI,IAAI;EAE5E,KAAK,MAAMA,KAAE,QAAQ,EAAE,GAAG,IAAI,IAAI;CACpC;CAEA,MAAM,SAAS,IAAI;CAEnB,KAAK,QAAQA,KAAE,aAAa,OAAO,IAAI,EAAE,GAAGA,KAAE,aAAa,OAAO,IAAI,EAAE,GAAG,CAAC;CAE5E,MAAM,CAAC,aAAa,eAAe,QAAQ,MAAM;CAEjD,IAAI,MAAM,MAAM,GAAG;EACjB,MAAM,KAAKA,MAAG,OAAO,QAAQ,KAAK,EAAG;EACrC,MAAM,SAASA,KAAE,KAAK,oBAAoB,CAAC;EAE3C,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS,aAAa;GACpD,MAAM,OAAO,MAAM;GAEnB,KAAK,MAAMA,KAAE,aAAa,KAAK,IAAI,SAAS,EAAE,GAAGA,KAAE,aAAa,KAAK,IAAI,SAAS,EAAE,GAAG,EAAE;EAC3F;CACF;CAEA,IAAI,MAAM,MAAM,GAAG;EACjB,IAAI,KAAKA,MAAG,OAAO,QAAQ,KAAK,EAAG;EAEnC,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS,aAAa;GACpD,MAAM,OAAO,IAAI;GAGjB,IAAI,MAAM,MAAM,GAAG,KAAKA,MAAG,MAAM,QAAQ,EAAE,CAAE,QAAQ,KAAK,EAAG;GAC7D,KAAK,MAAMA,KAAE,aAAa,KAAK,IAAI,EAAE,GAAGA,KAAE,aAAa,KAAK,IAAI,EAAE,GAAG,EAAE;EACzE;CACF;CAEA,IAAI,MAAM,QAAQ,GAAG;EACnB,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,GAAG,KAAK,QAAQ,OAAO;EACrD;CACF;CAGA,KAAK,IAAI,SAAS,aAAa,SAAS,IAAI;EAC1C,MAAM,OAAO,KAAK,MAAM,SAAS,EAAG;EAEpC,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS,QAAQ;GAC/C,MAAM,OAAO,QAAQ;GACrB,MAAM,YAAY,IAAI,OAAO,KAAK,OAAO,KAAK,KAAK,CAAE;GAErD,IAAI,QAAQ,KAAK,CAAE,QAAQ,UAAU,IAAI,MAAM,CAAE,OAAO,SAAS;EACnE;EAEA,SAAS;CACX;CAEA,IAAI,MAAM,QAAQ,GAChB,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS,GACvC,MAAM,MAAM,CAAE,QAAQA,MAAG,IAAI,QAAQ,EAAE,CAAE,QAAQ,OAAO,SAAS,EAAG;CAExE,IAAI,MAAM,OAAO,GAAG;CAEpB,KAAK,IAAI,SAAS,aAAa,SAAS,IAAI;EAC1C,MAAM,OAAO,KAAK,MAAM,SAAS,EAAG;EAEpC,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS,QAAQ;GAC/C,MAAM,OAAO,QAAQ;GACrB,MAAM,YAAY,MAAM,OAAO,KAAK,OAAO,KAAK,KAAK,CAAE;GAEvD,MAAM,QAAQ,KAAK,CAAE,QAAQ,UAAU,MAAM,MAAM,CAAE,OAAO,SAAS;EACvE;EAEA,SAAS;CACX;AACF;AAGA,MAAMC,SAAO;AAEb,MAAMC,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC1C,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;;;;;AAiB1C,MAAM,cACJ,MACA,WACA,UACA,OACA,WACA,SACS;CACT,MAAM,QAAQ,IAAI,WAAW,SAAS,SAASF,QAAM;CACrD,MAAM,SAAS,IAAI,aAAa,MAAM,MAAM;CAE5C,SAAS,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,OAAO,SAAS,UAAU;EACxD,OAAO,IAAI;GAAC;GAAG;GAAG;EAAC,GAAI,QAAQA,WAAU,CAAC;EAC1C,MAAM,IAAI;GAACF,OAAK,MAAM,CAAC;GAAGA,OAAK,MAAM,CAAC;GAAGA,OAAK,MAAM,CAAC;GAAGA,OAAK,KAAK;EAAC,GAAG,QAAQE,WAAS,EAAE;EACzF,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQA,WAAS,MAAM,CAAC;CAC9C,CAAC;CAED,MAAM,UACJ,cAAc,UACV,YAAY,KAAK,EAAE,QAAS,SAAS,SAAS,IAAK,EAAE,IAAI,GAAG,OAAO;EAGjE,OAFa,KAAK,MAAM,KAAK,CAAC,IAAI,IAEpB;GAAC;GAAG;GAAG;GAAG;GAAG;GAAG;EAAC,CAAC,CAAC,KAAK;CACxC,CAAC,IACD,YAAY,KAAK,EAAE,QAAQ,SAAS,OAAO,IAAI,GAAG,UAAU,KAAK;CAEvE,MAAM,QAAQ,QAAQ;CACtB,MAAM,OAAkB;EACtB;EACA,SAAS;EACT,WAAW,cAAc,UAAU,UAAU,eAAe;EAC5D,QAAQD;EACR,QAAQ,CACN;GACE,YAAY;GACZ,aAAa;GACb,WAAW,SAAS,SAAS;GAC7B,cAAc;GACd,SAAS;EACX,CACF;EACA;EACA,UAAU;CACZ;CACA,MAAM,YAAsB;EAC1B,QAAQ;EACR,aAAa;EACb,aAAa,SAAS;EACtB,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,YAAY;EACZ,aAAa;GAAE,KAAKE;GAAO,KAAKA;EAAM;EACtC,gBAAgB;GAAE,QAAQA;GAAO,QAAQ;EAAE;CAC7C;CACA,MAAM,EAAE,OAAO,WAAW;CAE1B,MAAM,aAAsB;EAC1B,GAAG;GAAE,GAAG,KAAK,QAAQ;GAAI,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAC1C,GAAG;GAAE,GAAG;GAAG,GAAG,MAAM,SAAS;GAAI,GAAG;GAAG,GAAG;EAAE;EAC5C,GAAG;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAC5B,GAAG;GAAE,GAAG;GAAI,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;CAC/B;CAEA,OAAO;EACL;EACA;EACA,WAAW;EACX,YAAY;EACZ;EACA,OAAO,QAAQ,OAAO,KAAK,IAAI;EAC/B;EACA,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EAEP,SAAS;GAAE,MAAM,MAAM,QAAQ;GAAM,OAAO,MAAM;GAAS,SAAS;GAAiB,OAAO;EAAE;EAC9F,MAAM;EAGN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP;EACA,OAAO;EAEP,gBAAgB;EAChB,eAAe;CACjB;AACF;;AAGA,MAAM,QAAQ,UAA2B,QAAQJ,KAAE,IAAK,IAAI,IAAI,QAAQA,KAAE,IAAK,IAAI,KAAK;;;;;;;AAQxF,MAAM,eACJ,OACA,MACA,IACA,SACW;CACX,MAAM,EAAE,UAAU;CAClB,IAAI,CAAC,OAAO,OAAO,CAAC;CAEpB,MAAM,QAAQ,KAAK,cAAcK;CACjC,MAAM,QAAQ,KAAK,cAAcA;CAEjC,MAAM,QAAQL,KAAE,KAAK,iBAAiB,EAAG;CACzC,MAAM,OAAOA,KAAE,IAAI,KAAK;CACxB,MAAM,SAAS;EACb,GAAGA,KAAE,OAAO,MAAM,IAAI,QAAQ,MAAM,CAAC;EACrC,GAAGA,KAAE,OAAO,MAAM,IAAI,QAAQ,MAAM,CAAC;EACrC,GAAGA,KAAE,OAAO,MAAM,IAAI,QAAQ,MAAM,CAAC;CACvC;CACA,MAAM,QAAQA,KAAEA,KAAE,KAAK,eAAe,CAAC,IAAI,GAAG,UAAU;CACxD,MAAM,QAAQ,MAAY,WAAkC;EAC1D,GAAGA,KAAE,QAAQ,KAAK,IAAI,GAAG,CAAC;EAC1B,GAAGA,KAAE,QAAQ,KAAK,IAAI,GAAG,CAAC;EAC1B,GAAG,KAAK;EACR,GAAG,KAAK;EACR;EACA,OAAOA,KAAE,KAAM,KAAK,QAAQ,KAAK,UAAU;CAC7C;CAEA,MAAM,YAAuB,gBAAgB,MAAM,OAAO,IAAI,aAAa;CAC3E,MAAM,QAAQ,WAAsB,aAClC,WAAW,UAAU,WAAW,UAAU,OAAO,WAAW,IAAI;CAClE,MAAM,EAAE,KAAK,OAAO,MAAM,cAAc;CACxC,MAAM,SAAS,KAAK,IAAI,IAAK,KAAK;CAElC,IAAI,MAAM,MAAM,GACd,OAAO,CACL,KAAK,UAAU,aAAa;EAC1B;EACA,GAAG,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,SAAS,KAAK,MAAM,KAAK,CAAC;EAC/C,KAAK,IAAI,IAAK,KAAK;CACrB,CAAC,CACH;CAEF,MAAM,YAA4B,CAAC;CAEnC,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS;EACvC,MAAM,QAAQ,QAAQ;EACtB,MAAM,MAAM,KAAK;EACjB,MAAM,OAAO,KAAK,SAAS,KAAK,QAAQ,QAAQ;EAChD,MAAM,OAAO,IAAI;EACjB,MAAM,OAAO,IAAI,QAAQ,KAAK,KAAK,QAAQ,IAAI,QAAQ,IAAI;EAC3D,IAAI,QAAQ,KAAK,IAAI,KAAK;EAC1B,IAAI,SAAS,KAAK,KAAK,KAAK;EAE5B,IAAI,UAAU,QAAQ;GACpB,QAAQ,KAAK,KAAK,KAAK;GACvB,SAAS,KAAK,KAAK,KAAK;EAC1B;EAEA,IAAI,UAAU,QACZ,UAAU,SAAS,UAAU,IAAI,IAAI,UAAU,KAAK,IAAI,WAAW,IAAI,IAAI;EAE7E,MAAM,KAAK,SAAe,KAAK,MAAM,MAAM;EAC3C,MAAM,KAAK,SAAe,KAAK,MAAM,KAAK;EAG1C,UAAU,KACR,GAAI,UAAU,WAAW,IACrB;GAAC,EAAE,IAAI;GAAG,EAAE,GAAG;GAAG,EAAE,IAAI;GAAG,EAAE,IAAI;GAAG,EAAE,IAAI;GAAG,EAAE,IAAI;EAAC,IACpD;GAAC,EAAE,IAAI;GAAG,EAAE,GAAG;GAAG,EAAE,IAAI;GAAG,EAAE,GAAG;GAAG,EAAE,IAAI;GAAG,EAAE,IAAI;EAAC,CACzD;CACF;CAEA,OAAO,CACL,KAAK,UAAU,cAAc,SAAS,GACtC,KAAK,UAAU,aAAa;EAC1B;EACA,GAAG,KAAK,KAAK,SAAS,KAAK,MAAM,MAAM,CAAC;EACxC,KAAK,KAAK,IAAK,MAAM;CACvB,CAAC,CACH;AACF;;AA+CA,MAAM,cAAc,EAAE,KAAK,OAAO,OAAkB,OAAe,UAA0B;CAC3F,MAAM,SAAS,OAAe,IAAI,GAAG,CAAE;CACvC,MAAM,QAAQ,OAAe,MAAM,GAAG,CAAE;CACxC,MAAM,aAAa,OAAgB,KAAK,KAAK,KAAK,KAAK;CACvD,MAAM,WAAW,OAAgB,KAAK,IAAI,KAAK,KAAK;CACpD,MAAM,YAAY,OAAgB,KAAK,KAAK,KAAK,KAAK;CAItD,QAAQ,OAAR;EACE,KAAK,IAAI;GACP,MAAM,MAAM,MAAM,UAAU,QAAQ,CAAC,CAAC;GAEtC,OAAO,OAAO,IAAI,OAAO,MAAM,KAAK,KAAK,KAAK;EAChD;EACA,KAAK;EACL,KAAK,GAAG;GAEN,MAAM,OAAO,UAAU,IAAI,QAAQ,IAAI,KAAK,MAAM,QAAQ,CAAC;GAC3D,IAAI,MAAM,MAAM,UAAU,OAAO,CAAC,CAAC;GAEnC,MAAM,MAAM,MAAM,MAAM,IAAI,IAAI,MAAM,UAAU,OAAO,CAAC,CAAC;GACzD,IAAI,OAAO,GAAG,OAAO,MAAM;GAC3B,MAAM,MAAM,KAAK,QAAQ,OAAO,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,OAAO,CAAC,CAAC;GAC9E,OAAO,MAAM;EACf;EACA,KAAK,GAAG;GACN,MAAM,OAAO,KAAK,MAAM,QAAQ,CAAC;GACjC,MAAM,QAAQ,OAAO,IAAI,IAAI,OAAO,IAAI,KAAK,OAAO;GACpD,MAAM,QAAQ,MAAM,IAAI,IAAI,MAAM,IAAI;GACtC,IAAI,MAAM,MAAM,KAAK,IAAI;GAEzB,MAAM,MAAM,MAAM,UAAU,OAAO,CAAC,CAAC,IAAI;GACzC,MAAM,OAAO,MAAM,UAAU,OAAO,CAAC,CAAC,IAAI,MAAM,UAAU,OAAO,CAAC,CAAC;GACnE,MAAM,MAAM,MAAM,UAAU,OAAO,CAAC,CAAC;GACrC,IAAI,OAAO,GAAG,OAAO,MAAM;GAC3B,MACE,MACA,KAAK,QAAQ,OAAO,CAAC,CAAC,IACtB,KAAK,QAAQ,OAAO,CAAC,CAAC,IAAI,IAC1B,KAAK,IAAI,IAAI,IACb,KAAK,SAAS,OAAO,CAAC,CAAC,IAAI,IAC3B,KAAK,SAAS,OAAO,CAAC,CAAC;GACzB,OAAO,MAAM;EACf;EACA,SACE,OAAO;CACX;AACF;AAGA,MAAM,cAAcA,KAAE,EAAG;;AAGzB,MAAM,eAAe,UAA4B;CAC/C,MAAM,OAAOA,KAAEA,KAAEA,KAAE,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK;CACxC,IAAI,QAAQ;CAEZ,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS;EACzC,MAAM,KAAK;EAEX,QAAQA,KAAE,QAAQ,IAAI;EACtB,OAAO;CACT,CAAC;AACH;;;;;AAMA,MAAM,cACJ,OACA,MACA,IACA,YACA,SACqB;CACrB,MAAM,WAAW,KAAK;CACtB,MAAM,QAAQ,UAAU;CACxB,IAAI,CAAC,YAAY,CAAC,OAAO,OAAO,KAAA;CAEhC,MAAM,EAAE,YAAY,GAAG,YAAY,KAAM,cAAc,MAAM;CAC7D,IAAI,QAAQ,GAAG;CAEf,IAAI,QAAQA,KAAE,SAAS,GAAG,QAAQA,KAAE,SAAS;MACxC,IAAI,QAAQA,KAAE,SAAS,GAAG,QAAQA,KAAE,SAAS;CAElD,MAAM,OAAO,KAAK,YAAY,CAAC;CAC/B,MAAM,QAAQA,KAAE,KAAK,iBAAiB,EAAG;CACzC,MAAM,YAAYA,KAAE,KAAK,eAAe,CAAC;CACzC,MAAM,SAASA,KAAE,QAAQ,YAAY,KAAK;CAC1C,MAAM,SAASA,KAAE,QAAQ,aAAa,QAAQ,KAAK,EAAG;CACtD,MAAM,cAAc,MAAM,IAAI,EAAE,CAAE;CAClC,MAAM,EAAE,GAAG,IAAI,GAAG,OAAO;CACzB,MAAM,EAAE,IAAI,IAAI,IAAI,OAAO;CAC3B,MAAM,QAAQ,SAAS,OAAO;CAC9B,MAAM,SAAS,YAAY,KAAK;CAChC,MAAM,WAA2B,CAAC;CAElC,SAAS,OAAO,SAAS,OAAO,UAAU;EACxC,MAAM,MAAMA,KAAE,KAAK,IAAI,OAAO,MAAO,CAAC;EACtC,MAAM,MAAMA,KAAE,KAAK,IAAI,OAAO,MAAO,CAAC;EACtC,MAAM,SAAS,QAAQA,KAAE,MAAM,SAASA,KAAE,WAAW,CAAC;EACtD,MAAM,YAAY,QAAQA,KAAE,MAAM,QAAQA,KAAE,WAAW,CAAC,IAAI;EAC5D,MAAM,KAAKA,KAAE,UAAU,IAAI,OAAO;EAClC,MAAM,KAAKA,KAAG,IAAI,SAAU,MAAM;EAElC,MAAM,SAAS,QAAgB,SAAiB;GAC9C,GAAGA,KAAE,SAAS,MAAM,KAAKA,KAAE,MAAM,GAAG,CAAC;GACrC,GAAGA,KAAE,SAAS,MAAMA,KAAE,MAAM,GAAG,IAAI,EAAE;EACvC;EACA,MAAM,QAAQA,OACV,IAAI,eAAe,MAAM,YAAY,WAAW,OAAO,OAAO,KAAK,IAAI,eACvE,MAAM,QACN,UACJ;EACA,MAAM,SAASA,KAAE,KAAK,KAAK,MAAM,IAAI,GAAG;EACxC,MAAM,SAASA,KAAE,KAAK,KAAK,MAAM,IAAI,GAAG;EACxC,MAAM,QAAQ,OAAwB;GACpC,GAAGA,MAAG,IAAI,KAAK,MAAM,WAAW,IAAI,IAAI,MAAM,WAAW,CAAC;GAC1D,GAAGA,MAAG,IAAI,KAAK,MAAM,WAAW,IAAI,IAAI,MAAM,WAAW,CAAC;GAC1D,GAAGA,MAAG,IAAI,KAAK,MAAM,WAAW,IAAI,IAAI,MAAM,WAAW,CAAC;EAC5D;EACA,MAAM,aAAa,KAAK,EAAE;EAC1B,MAAM,aAAa,KAAK,EAAE;EAC1B,MAAM,aAAaA,KAAE,QAAQ,WAAW;EACxC,MAAM,OAAO;GACX;IAAE,KAAK;IAAG,GAAG;IAAI,OAAO,MAAM;IAAY,OAAO;GAAE;GACnD;IAAE,KAAK;IAAQ,GAAG;IAAQ,OAAO;IAAY,OAAO;GAAW;GAC/D;IAAE,KAAK;IAAQ,GAAG;IAAQ,OAAO;IAAY;GAAM;GACnD;IAAE,KAAK;IAAQ,GAAG;IAAI,OAAO,MAAM;IAAY;GAAM;EACvD;EAEA,KAAK,IAAI,OAAO,GAAG,OAAO,GAAG,QAAQ;GACnC,MAAM,OAAO,KAAK;GAClB,MAAM,MAAM,KAAK,OAAO;GACxB,MAAM,UAAU,KAAkB,QAAgB,OAA6B;IAC7E,GAAG,MAAM,QAAQ,IAAI,GAAG;IACxB,GAAG,IAAI;IACP;IACA,OAAO,IAAI;IACX,OAAO,IAAI;GACb;GAEA,SAAS,KACP,OAAO,MAAM,CAAC,WAAW,EAAE,GAC3B,OAAO,KAAK,CAAC,WAAW,EAAE,GAC1B,OAAO,KAAK,WAAW,EAAE,GACzB,OAAO,MAAM,WAAW,EAAE,CAC5B;EACF;CACF,CAAC;CACD,IAAI,CAAC,SAAS,QAAQ,OAAO,KAAA;CAC7B,OAAO,WAAW,UAAU,SAAS,UAAU,OAAO,YAAY,IAAI;AACxE;;;;;;;AAQA,MAAa,cACX,MACA,UACA,aACA,SACW;CACX,MAAM,QAAQ,QAAQ,IAAI;CAC1B,MAAM,OAAO,KAAK,YAAY,CAAC;CAC/B,MAAM,EAAE,SAAS,GAAG,UAAU,MAAM,KAAK,qBAAqB,CAAC;CAE/D,MAAM,SAAS,cAAc,IAAI;CAEjC,IAAI,SAAS,MAAM,eAAe;EAChC,MAAM,OAAO,MAAM,OAAO,UAAU,MAAM;EAE1C,MAAM,gBAAgB,OAAO,SAAS,SAASA,KAAE,IAAI;CACvD,OAAO,IAAI,SAAS,MAAM,eAAe;EACvC,MAAM,OAAO,MAAM,gBAAgB,MAAM,OAAO;EAEhD,MAAM,gBAAgB,OAAO,SAAS,SAASA,KAAE,IAAI;CACvD;CAEA,IAAI,EAAE,MAAM,gBAAgB,IAAI,OAAO,CAAC;CAExC,MAAM,EAAE,QAAQ,OAAO,WAAW;CAClC,MAAM,SAAS,QAAQ,eAAe,UAAU,KAAK,IAAI;CAEzD,MAAM,QAAQA,KAAE,OAAO,CAAC;CACxB,MAAM,SAASA,KAAE,IAAI,MAAM,KAAK,CAAC;CAEjC,MAAM,MAAM,CAAC,GAAG,MAAM,KAAK,GAAG,MAAM,KAAK;CACzC,MAAM,KAAKA,KAAE,MAAM,OAAOA,KAAE,KAAK,UAAU,GAAI,CAAC;CAChD,MAAM,OAAOA,KAAE,MAAM,OAAOA,KAAE,KAAK,WAAW,GAAI,CAAC;CAEnD,MAAM,QAAQ;EAAE,GAAGA,KAAE,OAAO,CAAC;EAAG,GAAGA,KAAE,OAAO,CAAC;EAAG,GAAGA,KAAE,OAAO,CAAC;CAAE;CAE/D,IAAI,EAAE,CAAC,OAAO,QAAQ,MAAM,IAAI;EAC9B,IAAI,MAAM,SAAS,GAAG,KAAK,MAAM,QAAQ,KAAK,KAAK,MAAM,GAAG,IAAI,IAAI;EACpE,OAAO,CAAC;CACV;CAEA,MAAM,SAAS,SAAS,QAAQ,OAAO,MAAM;CAC7C,MAAM,OAAO,KAAK,MAAM;CAExB,MAAM,IAAIA,KAAE,MAAM,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO;CAC3D,MAAM,IAAIA,KAAE,MAAM,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO;CAE3D,MAAM,QAAQ,KAAK,IAAIA,KAAE,CAAC,MAAM,CAAC,GAAGA,KAAE,EAAG,CAAC;CAE1C,MAAM,aAAaA,KACjB,OAAO,OAAOA,KAAE,OAAO,SAAS,OAAO,IAAI,MAAM,KAAK,UAAU,OAAQ,MAC1E;CAEA,MAAM,EAAE,GAAG,GAAG,eAAe;CAE7B,IAAI,MAAM,KAAK,GAAG,OAAO,CAAC;CAE1B,MAAM,QAAQ,KAAK,IAAIA,KAAEA,KAAE,KAAK,eAAe,CAAC,IAAI,aAAa,CAAC,GAAG,EAAE;CACvE,MAAM,eAAe,IAAI,CAAC,SAAS,QAAQ,QAAQ,KAAK,IAAI,CAAC,SAAS,SAAS,QAAQ;CAEvF,MAAM,cAAcA,KAAE,KAAK,QAAQ,eAAe,CAAC;CACnD,MAAM,WAAW,KAAK,QAAQ,UAAU,CAAC,EAAA,CAAG,QACzC,MAAM,EAAE,aAAc,OAAOA,KAAE,SAAS,WAAW,IAAI,OAAOA,KAAE,SAAS,WAAW,GACrF,CACF;CACA,MAAM,aAAaA,KAAE,UAAU,UAAU;CACzC,MAAM,iBACJ,IAAI,CAAC,cAAc,QAAQ,aAAa,KAAK,IAAI,CAAC,cAAc,SAAS,aAAa;CACxF,MAAM,KAAK;EAAE;EAAG;EAAG;CAAW;CAE9B,IAAI,cAAc,OAAO,OAAO,MAAM,UAAU,IAAI;EAAE,GAAG;EAAM,YAAY;CAAE,CAAC;MACzE,IAAI,CAAC,gBAAgB;EACxB,IAAI,MAAM,SAAS,GAAG;GACpB,MAAM,SAAS,IAAIA,KAAE,KAAK,UAAU,GAAI;GACxC,MAAM,WAAW,IAAIA,KAAE,KAAK,WAAW,GAAI;GAC3C,KAAK,MAAM,QAAQ,KAAK,WAAW,MAAM,QAAQ,QAAQ;EAC3D;EAEA,OAAO,CAAC;CACV,OAAO,IAAI,MAAM,SAAS,GAAG,KAAK,MAAM,QAAQ,KAAK,WAAW,MAAM,IAAI,IAAI;CAE9E,MAAM,aAAaA,KAAE,IAAI,MAAM,aAAa;CAC5C,MAAM,QAAgB,CAAC;CAEvB,IAAI,gBAAgB;EAClB,MAAM,SAAS,WAAW,OAAO,MAAM,IAAI,YAAY;GAAE,GAAG;GAAM;EAAW,CAAC;EAC9E,IAAI,QAAQ,MAAM,KAAK,MAAM;CAC/B;CAEA,IAAI,cAAc,MAAM,KAAK,GAAG,YAAY,OAAO,MAAM,IAAI;EAAE,GAAG;EAAM;CAAW,CAAC,CAAC;CACrF,OAAO;AACT;;;;;;;AAQA,MAAa,aACX,MACA,SACqB;CACrB,MAAM,QAAQ,QAAQ,IAAI;CAE1B,MAAM,aAAaA,KAAE,IAAI,MAAM,aAAa;CAC5C,IAAI,EAAE,aAAa,MAAM,YAAY,IAAI,OAAO,KAAA;CAChD,IAAI,EAAE,MAAM,QAAQ,IAAI,OAAO,KAAA;CAE/B,MAAM,QAAQ,KAAK;CACnB,MAAM,QAAQ,OAAO;CACrB,IAAI,CAAC,SAAS,CAAC,OAAO,OAAO,KAAA;CAE7B,MAAM,EAAE,OAAO,WAAW;CAE1B,MAAM,QAAQ,QAAQ,KAAK;CAC3B,MAAM,OAAOA,MAAG,SAAS,KAAK,EAAG;CACjC,MAAM,SAAS,IAAI,MAAM;CACzB,MAAM,aAAa,IAAI,SAAS;CAChC,IAAI,QAAQ,MAAM;CAElB,IAAI,QAAQA,KAAE,MAAM,aAAa,GAAG,GAAG,QAAQA,KAAE,MAAM,aAAa,GAAG;MAClE,IAAI,QAAQA,KAAE,MAAM,aAAa,CAAC,GAAG,QAAQA,KAAE,MAAM,aAAa,CAAC;CAExE,MAAM,OAAOA,KAAE,QAAQ,aAAa,UAAU;CAG9C,MAAM,KAAK,OAAO,MAAM;CACxB,MAAM,KAAK,OAAO,MAAM;CACxB,MAAM,SAAS,QAAQ,KAAK;CAC5B,MAAM,QAAQA,KAAE,QAAQ,KAAK;CAC7B,MAAM,UAAU,KAAK,KAAK,KAAK;CAC/B,MAAM,OAAO,UAAU,QAAQA,KAAE,UAAU,KAAK,IAAI;CACpD,MAAM,QAAQA,KAAE,KAAK,CAAC;CACtB,MAAM,QAAQA,KAAE,KAAK,CAAC;CACtB,MAAM,WAA2B,CAAC;CAElC,KAAK,MAAM,EAAE,OAAO,MAAM,OAAO,WAAW,MAAM,OAAO;EACvD,MAAM,KAAKA,KAAE,QAAQ,QAAQ,MAAM,CAAC;EACpC,MAAM,KAAKA,KAAEA,KAAE,QAAQ,KAAK,IAAI,MAAM,CAAC;EACvC,MAAM,IAAIA,KAAE,OAAO,IAAI;EACvB,MAAM,KAAKA,KAAE,KAAK,CAAC;EACnB,MAAM,KAAKA,KAAE,KAAK,CAAC;EACnB,MAAM,KAAKA,KAAE,KAAK,CAAC;EACnB,MAAM,KAAKA,KAAE,KAAK,CAAC;EACnB,MAAM,IAAIA,KAAE,OAAO,KAAK;EAExB,SAAS,KACP;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;GAAG,GAAG;GAAG;GAAO,OAAO;EAAE,GAC5C;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;GAAG,GAAG;GAAG;GAAO,OAAO;EAAE,GAC5C;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;GAAG,GAAG;GAAG;GAAO,OAAO;EAAE,GAC5C;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;GAAG,GAAG;GAAG;GAAO,OAAO;EAAE,CAC9C;CACF;CAEA,IAAI,CAAC,SAAS,QAAQ,OAAO,KAAA;CAC7B,OAAO,WAAW,cAAc,SAAS,UAAU,OAAO,YAAY,IAAI;AAC5E;;;;;;;ACt/BA,MAAMM,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAM,SAAkB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAI3C,MAAM,oBAAkC;CAAE,GAAG;CAAiB,OAAO;CAAS,OAAO;AAAQ;;;;;;AAO7F,MAAa,iBACX,MACA,EAAE,OAAO,UAAU,OAAO,QAAQ,WAClC,SACA,QACqB;CACrB,IAAI,CAAC,QAAQ,QAAQ,OAAO,KAAA;CAE5B,MAAM,WAAW,IAAI,WAAW,QAAQA,QAAM;CAC9C,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;CAG/C,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,MAAM;EACjC,OAAO,IAAI,MAAM,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC,GAAI,KAAKA,WAAU,CAAC;EAC7D,SAAS,IAAI,OAAO,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC,GAAG,KAAKA,WAAS,EAAE;EAC/D,OAAO,IAAI,MAAM,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAKA,WAAS,MAAM,CAAC;CACxE;CA+BA,OAAO;EACL,MAAA;GA7BA;GACA,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IACE,YAAY;IACZ,aAAa;IACb,WAAW,QAAQ;IACnB,cAAc,QAAQ;IACtB,SAAS;GACX,CACF;GACA,SAAS,YAAY,KAAK,OAAO;GACjC;EAeG;EACH,WAAA;GAbA,QAAQ;GACR,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAK;IAAQ,KAAK;GAAO;GACxC,gBAAgB;IAAE,QAAQ;IAAQ,QAAQ;GAAE;EAKpC;EACR,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAAS;EACT,UAAU;EACV,aAAa;EACb,OAAO;EACP,SAAS;GAAE,MAAM,QAAQ;GAAM,OAAO;GAAS,SAAS;GAAmB,OAAO;EAAE;EACpF,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,GAAI,OAAO,EAAE,IAAI;EACjB,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW;EACX,OAAO;EACP,gBAAgB;EAChB,eAAe;CACjB;AACF;;;;;;;;AC9FA,MAAME,OAAI,KAAK;AAGf,MAAM,mBAAmB;AAYzB,MAAa,qBAA2C;CACtD,QAAQ;CACR,MAAMA,KAAE,EAAG;CACX,WAAW;AACb;AAiDA,MAAM,mBAAmBA,KAAE,GAAI;AAC/B,MAAMC,iBAAeD,KAAE,UAAW;AAGlC,MAAME,UAAQ,UACZ,QACI;CACE,GAAGF,KAAEA,KAAE,MAAM,CAAC,IAAIC,cAAY;CAC9B,GAAGD,KAAEA,KAAE,MAAM,CAAC,IAAIC,cAAY;CAC9B,GAAGD,KAAEA,KAAE,MAAM,CAAC,IAAIC,cAAY;AAChC,IACA;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAEzB,MAAM,cAAc,UAClB,QAAQ,mBAAmB,mBAAmB,QAAQ,IAAI,IAAI;;;;;;AAOhE,MAAa,iBAAiB,YAAwC;CACpE,MAAM,YAAYD,KAAE,QAAQ,aAAa,CAAC;CAC1C,MAAM,eAAeA,KAAE,QAAQ,gBAAgB,CAAC;CAEhD,OAAO;EACL,MAAM,QAAQ;EACd,UAAUE,OAAK,QAAQ,QAAQ;EAC/B,WAAWA,OAAK,QAAQ,SAAS;EACjC,WAAWA,OAAK,QAAQ,SAAS;EACjC,cAAcA,OAAK,QAAQ,YAAY;EACvC,YAAYA,OAAK,QAAQ,UAAU;EACnC,eAAeA,OAAK,QAAQ,aAAa;EACzC,gBAAgB,WAAWF,KAAE,QAAQ,kBAAkB,CAAC,CAAC;EACzD,iBAAiB,WAAWA,KAAE,QAAQ,mBAAmB,CAAC,CAAC;EAC3D,WAAW,KAAK,IAAIA,KAAE,QAAQ,aAAa,CAAC,GAAG,SAAS;EACxD,YAAY,KAAK,IACfA,KAAE,QAAQ,cAAc,CAAC,GACzB,QAAQ,SAAS,SAAS,eAAe,SAC3C;EACA,YAAYA,KAAE,QAAQ,cAAc,CAAC;EACrC;EACA;EACA,WAAW,KAAK,IAAIA,KAAE,QAAQ,aAAa,CAAC,GAAG,SAAS;EACxD,WAAWA,KAAE,QAAQ,aAAa,CAAC;EAEnC,UAAU,QAAQ,gBAAgB;EAClC,WAAW,QAAQ,iBAAiB;CACtC;AACF;;;;;;AAOA,MAAa,cAAc,EAAE,GAAG,GAAG,QAA0B;CAC3D,MAAM,SAAS,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;CAC9C,MAAM,UAAU,KAAK;CACrB,MAAM,QAAQ,SAAS,OAAOA,KAAE,UAAU,CAAC,IAAI;CAC/C,MAAM,QAAQ,SAAS,OAAOA,KAAE,UAAU,CAAC,IAAI;CAC/C,MAAM,QAAQ,SAAS,OAAOA,KAAE,UAAU,CAAC,IAAI;CAC/C,MAAM,WAAW,EAAE,KAAK,IAAI,KAAK,KAAK,QAAQ,KAAK,IAAI,KAAK,KAAK;CACjE,MAAM,QAAQ,WAAW,IAAI,CAAC;CAC9B,MAAM,QAAQ,WAAW,IAAI;CAC7B,MAAM,KAAKA,KAAE,QAAQ,IAAI,QAAQ,KAAK;CACtC,MAAM,KAAKA,KAAE,QAAQ,QAAQ,QAAQ,CAAC;CACtC,MAAM,KAAKA,KAAE,QAAQ,QAAQ,QAAQ,KAAK;CAC1C,MAAM,QAAQA,KAAE,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC;CAC1D,MAAM,MAAM,KAAK;CACjB,MAAM,MAAM,KAAK;CACjB,MAAM,MAAMA,KAAE,KAAK,KAAK;CAGxB,OAAO;EACL,GAAG;GACD,GAAGA,KAAE,QAAQ,MAAM,MAAM,KAAK;GAC9B,GAAGA,KAAE,MAAM,QAAQ,QAAQ,GAAG;GAC9B,GAAGA,KAAE,MAAM,QAAQ,MAAM,KAAK;EAChC;EACA,GAAG;GAAE,GAAGA,KAAE,GAAG;GAAG,GAAGA,KAAE,GAAG;GAAG,GAAG;EAAI;EAClC,GAAG;GAAE,GAAG;GAAO,GAAG;GAAO,GAAG;EAAM;CACpC;AACF;;;;;;;;AAsBA,IAAa,aAAb,MAAwB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA,MAAc;CACd,OAAe;CACf;CACA,OAAO;CAEP,YACE,WACA,EAAE,aAAa,UAAU,OAAO,OAAO,SACvC,SAA8B,CAAC,GAC/B;EACA,KAAK,YAAY;EACjB,KAAK,cAAc;EACnB,KAAK,WAAW;EAChB,KAAK,SAAS;GAAE,GAAG;GAAoB,GAAG;EAAO;EACjD,KAAK,OAAO;EAEZ,KAAK,SAASA,MACXA,KAAE,UAAU,UAAU,IAAIA,KAAE,UAAU,UAAU,IAAI,KAAK,OAAO,aAAa,KAChF;CACF;;CAGA,MAAM,aAAsB,UAAmB;EAC7C,IAAI,KAAK,UAAU;EACnB,KAAK,cAAc;EACnB,KAAK,WAAW;CAClB;;;;;CAMA,KAAK,UAAmB;EACtB,KAAK,aAAa;EAClB,IAAI,KAAK,OAAO,KAAK,KAAK,OAAO,KAAK,OAAO,MAAM,KAAK,OAAO,KAAK,OAAO;CAC7E;;;;;CAMA,KAAK,MAAc,MAAgB,OAAkB;EACnD,IAAI,KAAK,MAAM;EAEf,MAAM,EAAE,UAAU,aAAa;EAE/B,IAAI,UACF,KAAK,WAAW;GACd,GAAGA,KAAE,SAAS,IAAI,OAAO,SAAS,CAAC;GACnC,GAAGA,KAAE,SAAS,IAAI,OAAO,SAAS,CAAC;GACnC,GAAGA,KAAE,SAAS,IAAI,OAAO,SAAS,CAAC;EACrC;EAEF,MAAM,OAAO,KAAK,KAAK,UAAU,KAAK,OAAO,MAAM;EAEnD,IAAI,SAAS,OAAO;GAClB,KAAK,OAAO;GACZ;EACF;EAEA,KAAK,MAAM,KAAK,OAAO,IAAIA,KAAE,KAAK,MAAM,IAAI,IAAI;EAEhD,IAAI,KAAK,OAAO,GAAG;GACjB,KAAK,OAAOA,KAAE,KAAK,OAAO,IAAI;GAE9B,IAAI,KAAK,QAAQ,GAAG;IAClB,KAAK,OAAO;IACZ;GACF;EACF;EAEA,IAAI,SAAS,QAAQ,KAAK,MAAM,KAAK;CACvC;CAIA,MAAc,OAAkB;EAC9B,MAAM,EAAE,WAAW,KAAK,QAAQ,MAAM,QAAQ,SAAS;EACvD,MAAM,IAAI,MAAM,SAASA,KAAE,MAAM,MAAM,IAAI;EAC3C,MAAM,YAAY,OAAO,IAAIA,KAAE,OAAO,OAAO,IAAI,IAAI;EAErD,IAAI,MAAM,KAAK,UAAU,SAAS,SAChC,WAAW,WAAW,MAAM,GAAG,WAAW,QAAQ,MAAM,KAAK,CAAC,MAAM,aAAa,KAAK;OACnF,UAAU,WAAW,MAAM,GAAG,WAAW,KAAK;CACrD;AACF;;;;;;;AAWA,MAAa,YACX,QACA,QACA,MACA,EAAE,eAAe,GAAG,cAAc,CAAC,MAAyB,CAAC,MAChD;CACb,MAAM,OAAmB;EACvB,GAAG,oBAAoB;EACvB,GAAG,YAAY;CACjB;CACA,MAAM,OAAOA,KAAE,IAAI,YAAY;CAC/B,MAAM,EAAE,MAAM,QAAQ,KAAK;CAC3B,MAAM,QAAQA,KAAEA,KAAE,MAAM,IAAI,IAAIA,KAAE,IAAI,IAAI,IAAI,IAAI;CAClD,MAAM,SAAS,KAAK,iBAAiB,QAAQ;CAE7C,QAAQ,UAAU,WAAW;EAC3B,IAAI,EAAE,KAAK,YAAY,OAAO,OAAO;EAErC,MAAM,KAAK,QAAQ,eAAe,UAAU,IAAI;EAChD,MAAM,QAAQA,KAAE,CAAC,GAAG,CAAC;EACrB,IAAI,EAAE,OAAO,OAAOA,KAAE,QAAQ,MAAM,IAAI,OAAO;EAC/C,IAAI,EAAE,QAAQA,KAAE,QAAQ,MAAM,IAAI,OAAO;EACzC,OAAO,YAAY,IAAI,QAAQ,QAAQ,MAAM,IAAI,SAAS;CAC5D;AACF;AAOA,MAAa,aAAa,cAAc,WAAsB;CAC5D;CACA,UAAU,CAAC;CACX,QAAQ,CAAC;CACT,SAAS,CAAC;CACV,OAAO;AACT;AAGA,MAAM,WAAW,UAA0B,KAAK,MAAM,KAAK,IAAI;AAE/D,MAAM,UAAU,OAAe,EAAE,GAAG,GAAG,QAAoD;CACzF,QAAQ,QAAQ,IAAI,GAAG;CACvB,QAAQ,QAAQ,IAAI,GAAG;CACvB,QAAQ,QAAQ,IAAI,GAAG;AACzB;AAEA,MAAMG,SACJ,OACA,EAAE,GAAG,GAAG,KACR,CAAC,GAAG,GAAG,IACP,GACA,MACW;CACX,MAAM,SAAS,KAAK,GAAG,GAAG,GAAG,GAAG,CAAC;CACjC,MAAM,OAAO,KAAK,GAAG,GAAG,GAAG,GAAI;CAC/B,OAAO,MAAM;AACf;AAEA,MAAM,YAAY,OAAkB,GAAW,GAAW,MAAc;CACtE,MAAM,QAAQ,KAAK,GAAG,GAAG,CAAC;AAC5B;AAGA,MAAMC,UAAQ,OAAkB,GAAW,GAAW,GAAW,MAAc;CAC7E,MAAM,QAAQ,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AACrC;AAGA,MAAM,UAAU,EAAE,aAAa,GAAG,UAAU,KAAa,GAAW,GAAW,OAAe;CAC5F,GAAGJ,KAAE,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC;CAC5C,GAAGA,KAAE,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC;CAC5C,GAAGA,KAAE,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC;AAC9C;AAIA,MAAM,UAAU;AAChB,MAAM,UAAU;AAChB,MAAM,SAAS;AACf,MAAM,UAAUA,KAAE,GAAI;AACtB,MAAM,UAAUA,KAAE,GAAI;AAEtB,MAAM,SAAS,EAAE,eACf,WAAY;CAAC;CAAG;CAAS;AAAI,IAAe;CAAC;CAAS;CAAG;AAAI;AAC/D,MAAM,UAAU,EAAE,gBAChB,YAAa,CAAC,GAAG,OAAO,IAAe,CAAC,SAAS,CAAC;AAIpD,MAAM,cACJ,MACA,IACA,GACA,WACA,OACA,UACG;CACH,MAAM,OAAO,QAAQ,KAAK,YAAY,KAAK;CAC3C,MAAM,OAAO,KAAK,YAAY,OAAO,OAAO,KAAK;CACjD,MAAM,MAAMA,KAAEA,KAAE,KAAK,aAAa,IAAI,IAAI,IAAI,IAAI;CAClD,MAAM,QAAQA,KAAE,EAAEA,KAAE,KAAK,YAAY,IAAI,IAAI,IAAI,KAAK;CACtD,MAAM,CAAC,IAAI,IAAI,QAAQ,MAAM,IAAI;CACjC,MAAM,CAAC,IAAI,MAAM,OAAO,IAAI;CAC5B,MAAM,SAASA,KAAE,YAAY,KAAK,cAAc;CAChD,MAAM,SAASA,KAAE,YAAY,KAAK,eAAe;CACjD,MAAM,SAAS,GAAG;CAElB,MAAM,QAAQ,OAAO,QAAQ,KAAK,SAAS;CAC3C,MAAM,SAAS,OAAO,QAAQ,KAAK,UAAU;CAC7C,MAAM,KAAKG,MAAI,OAAO,QAAQ,OAAO,SAAS,IAAI;CAClD,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,MAAM,GAAG,CAAC,GAAG,QAAQ,SAAS,EAAE;CACjE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,MAAM,CAAC,GAAG,QAAQ,SAAS,EAAE;CACjE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,GAAG,EAAE;CAC5D,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,QAAQ,GAAG,EAAE;CAE5D,MAAM,KAAKA,MAAI,OAAO,QAAQ,OAAO,QAAQ,KAAK,SAAS,GAAG,GAAG,EAAE;CACnE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,GAAG,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,GAAG,QAAQ,EAAE;CACxF,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,OAAO,QAAQ,KAAK,SAAS,GAAG,QAAQ,EAAE;CACvF,MAAM,SAAS,OAAO,QAAQ,KAAK,UAAU;CAC7C,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,MAAM,GAAG,CAAC,GAAG,QAAQ,QAAQ,EAAE;CAChE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,QAAQ,EAAE;CACjE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,MAAM,CAAC,GAAG,QAAQ,QAAQ,EAAE;CAChE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,QAAQ,QAAQ,EAAE;CAEjE,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,SAAS,OAAO,IAAI,IAAI,EAAE;CAE1B,KAAK,MAAM,SAAS,CAAC,IAAI,EAAE,GACzB,KAAK,MAAM,QAAQ;EAAC;EAAI;EAAI;EAAI;CAAE,GAAG,SAAS,OAAO,IAAI,OAAO,IAAI;AACxE;AAIA,MAAM,aACJ,MACA,IACA,GACA,WACA,UACG;CACH,MAAM,OAAO,KAAK;CAClB,MAAM,OAAO,KAAK,YAAY,OAAO,OAAO,KAAK;CACjD,MAAM,MAAM,KAAK,IAAIH,KAAE,KAAK,YAAY,IAAI,GAAG,CAAC;CAChD,MAAM,OAAO,KAAK,IAAIA,KAAE,KAAK,aAAa,IAAI,GAAG,CAAC;CAClD,MAAM,MAAMA,KAAE,KAAK,IAAI,KAAK,YAAY,CAAC,IAAI,CAAC;CAC9C,MAAM,QAAQA,KAAE,EAAE,MAAM,IAAI,KAAK;CACjC,MAAM,MAAMA,KAAE,OAAO,IAAI,IAAI;CAC7B,MAAM,CAAC,IAAI,MAAM,MAAM,IAAI;CAC3B,MAAM,OAAOA,MAAG,KAAK,MAAM,EAAG;CAC9B,MAAM,CAAC,IAAI,MAAM,OAAO,IAAI;CAC5B,MAAM,SAASA,KAAE,YAAY,KAAK,cAAc;CAChD,MAAM,SAASA,KAAE,YAAY,KAAK,eAAe;CACjD,MAAM,SAAS,GAAG;CAElB,MAAM,SAAS,OAAO,QAAQ,KAAK,UAAU;CAC7C,MAAM,KAAKG,MAAI,OAAO,QAAQ,OAAO,QAAQ,KAAK,SAAS,GAAG,SAAS,IAAI;CAC3E,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,MAAM,GAAG,CAAC,GAAG,QAAQ,SAAS,EAAE;CACjE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,MAAM,CAAC,GAAG,QAAQ,GAAG,EAAE;CAC3D,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,GAAG,EAAE;CAC5D,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,QAAQ,SAAS,EAAE;CAElE,MAAM,KAAKA,MAAI,OAAO,QAAQ,OAAO,QAAQ,KAAK,SAAS,GAAG,GAAG,EAAE;CACnE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,GAAG,KAAK,GAAG,OAAO,QAAQ,KAAK,QAAQ,GAAG,QAAQ,EAAE;CACxF,MAAM,SAAS,OAAO,QAAQ,KAAK,UAAU;CAC7C,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,MAAM,GAAG,CAAC,GAAG,QAAQ,QAAQ,EAAE;CAChE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,QAAQ,QAAQ,EAAE;CACjE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,MAAM,CAAC,GAAG,QAAQ,QAAQ,EAAE;CAChE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,QAAQ,QAAQ,EAAE;CACjE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,GAAG,GAAG,GAAG,OAAO,QAAQ,KAAK,YAAY,GAAG,GAAG,EAAE;CACrF,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,GAAGH,KAAE,MAAM,GAAG,CAAC,GAAG,OAAO,QAAQ,KAAK,SAAS,GAAG,QAAQ,EAAE;CAEhG,MAAM,EAAE,eAAe,aAAa;CACpC,MAAM,YAAY;EAChB,QAAQA,KAAE,SAAS,SAAS,CAAC,IAAI,GAAG;EACpC,QAAQA,KAAE,SAAS,SAAS,CAAC,IAAI,GAAG;EACpC,QAAQA,KAAE,SAAS,SAAS,CAAC,IAAI,GAAG;CACtC;CACA,MAAM,KAAKG,MAAI,OAAO,OAAO,IAAI,MAAM,GAAG,GAAG,GAAG,WAAW,QAAQ,EAAE;CACrE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,CAAC,MAAM,GAAG,GAAG,GAAG,WAAW,QAAQ,EAAE;CACtE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,MAAM,GAAG,GAAG,WAAW,QAAQ,EAAE;CACrE,MAAM,KAAKA,MAAI,OAAO,OAAO,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,WAAW,QAAQ,EAAE;CAEtE,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,SAAS,OAAO,IAAI,IAAI,EAAE;CAC1B,KAAK,MAAM,QAAQ;EAAC;EAAI;EAAI;EAAI;CAAE,GAAG,SAAS,OAAO,IAAI,IAAI,IAAI;CACjE,OAAK,OAAO,IAAI,IAAI,IAAI,EAAE;CAC1B,OAAK,OAAO,IAAI,IAAI,IAAI,EAAE;CAC1B,OAAK,OAAO,IAAI,IAAI,IAAI,EAAE;CAC1B,OAAK,OAAO,IAAI,IAAI,IAAI,EAAE;CAC1B,KAAK,MAAM,QAAQ;EAAC;EAAI;EAAI;EAAI;CAAE,GAAG,SAAS,OAAO,IAAI,IAAI,IAAI;AACnE;;;;;AAMA,MAAa,YAAY,OAAkB,SAAkB,QAC3D,cAAc,aAAa,OAAO,SAAS,GAAG;;;;;;;;;AClehD,MAAME,OAAI,KAAK;AA4Bf,MAAa,wBAAiD;CAC5D,MAAM;CACN,OAAO;CACP,QAAQA,KAAE,EAAG;CACb,WAAW;CACX,WAAW;CACX,QAAQ;CACR,YAAY;CACZ,aAAa;CACb,eAAeA,KAAE,EAAG;CACpB,UAAU;CACV,SAASA,KAAE,GAAG;AAChB;AAmCA,MAAM,eAAeA,KAAE,IAAI,GAAG;AAC9B,MAAMC,cAAYD,KAAE,IAAI,KAAK;AAG7B,MAAME,SAAO;AAGb,MAAa,cAAc,EAAE,GAAG,GAAG,QAAmD;CACpF,MAAM,QAAQ,UAAkBA,OAAKF,MAAG,KAAK,MAAM,KAAK,IAAI,OAAQ,YAAY,CAAC;CAEjF,OAAO;EAAC,KAAK,CAAC;EAAG,KAAK,CAAC;EAAG,KAAK,CAAC;EAAG;CAAI;AACzC;AAIA,MAAM,OAAO,GAAM,MAAY;CAACA,KAAE,EAAE,KAAK,EAAE,EAAE;CAAGA,KAAE,EAAE,KAAK,EAAE,EAAE;CAAGA,KAAE,EAAE,KAAK,EAAE,EAAE;AAAC;AAC9E,MAAM,OAAO,GAAM,MAAY;CAACA,KAAE,EAAE,KAAK,EAAE,EAAE;CAAGA,KAAE,EAAE,KAAK,EAAE,EAAE;CAAGA,KAAE,EAAE,KAAK,EAAE,EAAE;AAAC;AAC9E,MAAMG,WAAS,GAAM,OAAkB;CAACH,KAAE,EAAE,KAAK,EAAE;CAAGA,KAAE,EAAE,KAAK,EAAE;CAAGA,KAAE,EAAE,KAAK,EAAE;AAAC;AAChF,MAAMI,YAAU,CAAC,GAAG,GAAG,OAAU,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;AAChE,MAAM,WAAW,GAAM,WAAsBD,QAAM,GAAG,SAASC,SAAO,CAAC,CAAC;AACxE,MAAMC,WAAS,GAAM,MAAY;CAC/BL,KAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;CAC3BA,KAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;CAC3BA,KAAE,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;AAC7B;AACA,MAAM,UAAU,EAAE,GAAG,GAAG,QAAoB;CAAC;CAAG;CAAG;AAAC;AAGpD,MAAM,gBAAgB,QAAgB,WAAsB;CAC1D,MAAM,IAAIA,KAAE,OAAO,IAAI,KAAM;CAC7B,MAAM,IAAIA,KAAE,OAAO,IAAI,KAAM;CAC7B,MAAM,IAAI,OAAO,IAAI;CACrB,MAAM,KAAK,SAAS,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;CAEnD,OAAO;EAACA,KAAE,IAAI,EAAE;EAAGA,KAAE,IAAI,EAAE;EAAGA,KAAE,KAAK,CAAC;CAAC;AACzC;AASA,MAAM,oBAAoC;CAAE,UAAU,CAAC;CAAG,QAAQ,CAAC;CAAG,SAAS,CAAC;CAAG,OAAO;AAAE;AAG5F,MAAM,gBAAgB;AAEtB,MAAM,WAAW;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;;;;;AAOxC,MAAa,kBACX,KACA,MACA,KACA,WACA,WACiB;CACjB,MAAM,OAAOK,QAAM,IAAI,MAAM,GAAG,GAAG,IAAI,KAAK,GAAG,CAAC;CAChD,MAAM,MAAM,IAAI,KAAKF,QAAM,IAAI,MAAM,GAAG,GAAG,EAAG,CAAC;CAC/C,MAAM,OAAOC,SAAO,IAAI,KAAK,GAAG,CAAC;CACjC,MAAM,QAAQD,QAAM,IAAI,KAAK,GAAG,GAAG,SAAS;CAC5C,MAAM,SAASA,QAAM,QAAQ,MAAMH,KAAE,SAAS,OAAO,KAAM,IAAI,CAAC,GAAG,SAAS;CAE5E,OAAO;EAAC,IAAI,KAAK,KAAK;EAAG,IAAI,KAAK,MAAM;EAAG,IAAI,KAAK,KAAK;EAAG,IAAI,KAAK,MAAM;CAAC;AAC9E;AAIA,MAAM,QAAQ,OAAc,YAA0B;CACpD,IAAI,CAAC,QAAQ,OAAO,WAAW,OAAO,MAAM,OAAO,QAAQ,CAAC,GAAG;CAE/D,IAAI,QAAQ,MAAM,QAAQ,GAAG,EAAE;CAC/B,IAAI,MAAM,QAAQ,IAAI,eAAe,MAAM,QAAQ,KAAM,QAAQ,WAAW,CAAE;CAE9E,MAAM,QAAQ,MAAM;CAEpB,QAAQ,SAAS,QAAQ,OAAO;EAC9B,MAAM,SAAS,KAAK,GAAG,QAAQ,SAAS,KAAK,IAAK,SAAS,KAAK,IAAI,EAAG;EACvE,MAAM,OAAO,KAAK,GAAG,MAAM,KAAK;CAClC,CAAC;CACD,MAAM,SAAS;CACf,MAAM,QAAQ,KAAK,OAAO,QAAQ,GAAG,QAAQ,GAAG,OAAO,QAAQ,GAAG,QAAQ,CAAC;AAC7E;AAEA,MAAM,WAAW,OAAc,KAAQ,MAAS,WAAmB,WACjE,KAAK,OAAO,eAAe,KAAK,MAAM,MAAM,KAAK,WAAW,MAAM,CAAC;AAIrE,MAAM,aACJ,OACA,QACA,OACA,KACA,OACA,EAAE,QAAQ,eACP;CACH,MAAM,MAAM,IAAI,KAAK,KAAK;CAC1B,MAAM,QAAQI,SAAO,GAAG;CACxB,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,IAAI;CAC1C,MAAM,OAAO,QAAQ,KAAKJ,KAAEA,KAAE,KAAK,IAAI,KAAK,CAAC;CAC7C,MAAM,QAAQA,KAAE,SAAS,KAAK;CAC9B,IAAI,MAAM;CAEV,KAAK,IAAI,KAAK,GAAG,MAAM,OAAO,MAAM;EAClC,MAAM,OAAO,OAAO,QAAQ,MAAM,IAAI,IAAI,OAAOG,QAAM,MAAM,EAAE,CAAC,GAAG,aAAa,QAAQ,KAAK,CAAC;EAE9F,QAAQ,OAAO,KAAK,MAAM,UAAU,IAAI;EACxC,MAAM;CACR;AACF;AAIA,MAAM,YACJ,OACA,QACA,OACA,KACA,QACA,OACA,EAAE,QAAQ,cACP;CACH,MAAM,OAAO,IAAI,OAAO,MAAM;CAC9B,MAAM,WAAWC,SAAO,IAAI;CAC5B,MAAM,SAASJ,KAAE,QAAQ;CAEzB,IAAI,WAAW,MAAO;CAEtB,MAAM,WAAW,IAAI,KAAK,MAAM;CAChC,IAAII,SAAO,QAAQ,IAAI,MAAO;CAE9B,MAAM,QAAQJ,KAAE,SAAS,KAAK;CAC9B,MAAM,QAAQ,QAAQ,UAAU,MAAM;CACtC,MAAM,WAAWA,KAAE,SAAS,MAAM;CAClC,MAAM,aAAa,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,KAAK,KAAK,MAAM;CACnF,IAAI,SAASA,KAAE,SAAS;CAExB,IAAI,YAAY,IAAI,SAAS;MACxB,IAAI,SAAS,GAAG,SAAS;CAE9B,MAAM,QAAQA,KAAE,KAAK,KAAK,MAAM,CAAC;CAEjC,IAAI,QAAQA,KAAE,IAAK,QAAQ,SAAU,WAAW,SAAS;CAEzD,IAAI,QAAQ,IAAI,QAAQ;MACnB,IAAI,QAAQ,GAAG,QAAQ;CAE5B,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,KAAK,KAAK,CAAC,IAAI;CACrD,MAAM,OAAOA,KAAE,QAAQ,KAAK;CAC5B,MAAM,OAAOK,QAAM,MAAM,KAAK;CAC9B,MAAM,aAAaD,SAAO,IAAI;CAC9B,MAAM,WAAc;EAAC,KAAK,KAAK;EAAY,KAAK,KAAK;EAAY,KAAK,KAAK;CAAU;CACrF,IAAI,MAAM;CAEV,KAAK,IAAI,KAAK,GAAG,MAAM,OAAO,MAAM;EAClC,MAAM,OACJ,OAAO,QACH,IAAI,QAAQ,KAAK,IACjB,IAAI,IAAI,QAAQE,SAAO,MAAM,UAAU,KAAK,IAAI,CAAC,GAAG,aAAa,QAAQ,KAAK,CAAC;EAErF,QAAQ,OAAO,KAAK,MAAM,SAAS,KAAK;EACxC,MAAM;CACR;AACF;;;;;AAMA,MAAaA,YAAU,GAAM,CAAC,IAAI,IAAI,KAAQ,UAAqB;CACjE,MAAM,IAAI,KAAK,IAAI,KAAK;CACxB,MAAM,IAAI,KAAK,IAAI,KAAK;CACxB,MAAM,OAAO,KAAK,EAAE,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,OAAO,IAAI;CAEvD,OAAO;EACLN,KAAE,EAAE,KAAK,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,IAAI,KAAK,GAAG;EACnDA,KAAE,EAAE,KAAK,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,IAAI,KAAK,GAAG;EACnDA,KAAE,EAAE,KAAK,KAAK,KAAK,EAAE,KAAK,KAAK,EAAE,MAAM,IAAI,KAAK,GAAG;CACrD;AACF;;;;;AAMA,MAAa,iBAAiB,CAAC,GAAG,GAAG,OAAqB;CACxD,MAAM,WAAW,IAAI,IAAI,IAAI,IAAI,IAAI;CACrC,MAAM,UAAU,KAAK,KAAK,KAAK,QAAQ;CACvC,MAAM,OAAU,WAAW,OAAO;EAACA,KAAE,UAAU,CAAC;EAAGA,KAAE,UAAU,CAAC;EAAGA,KAAE,UAAU,CAAC;CAAC,IAAI;EAAC;EAAG;EAAG;CAAE;CAC9F,MAAM,CAAC,IAAI,IAAI,MAAM;CACrB,MAAM,WAAW,KAAK,IAAI,EAAE,IAAI,QAAQ,KAAK,IAAI,EAAE,IAAI;CACvD,MAAM,OAAO,WAAW,IAAI,CAAC;CAC7B,MAAM,OAAO,WAAW,IAAI;CAC5B,MAAM,MAAMA,KAAE,OAAO,KAAK,KAAK,CAAC;CAChC,MAAM,MAAMA,KAAE,OAAO,KAAK,OAAO,EAAE;CACnC,MAAM,MAAMA,KAAE,KAAK,IAAI,KAAK,IAAI;CAChC,MAAM,YAAYA,KAAE,IAAI,KAAK,KAAK,MAAM,MAAM,MAAM,MAAM,MAAM,GAAG,CAAC;CACpE,MAAM,KAAK,MAAM;CACjB,MAAM,KAAK,MAAM;CACjB,MAAM,KAAKA,KAAE,MAAM,SAAS;CAE5B,OAAO;EACL;GAACA,KAAE,KAAK,KAAK,KAAK,EAAE;GAAGA,KAAE,KAAK,KAAK,KAAK,EAAE;GAAGA,KAAE,KAAK,KAAK,KAAK,EAAE;EAAC;EACjE;GAACA,KAAE,EAAE;GAAGA,KAAE,EAAE;GAAG;EAAE;EACjB;CACF;AACF;AAIA,MAAM,OACJ,OACA,QACA,QACA,EAAE,KAAK,OAAO,MAAM,QAAQ,QAAQ,YACpC,WACG;CACH,MAAM,MAAM,OAAO,KAAK;CACxB,MAAM,OAAO,OAAO,MAAM;CAC1B,MAAM,QAAQ,IAAI,KAAK,MAAM;CAC7B,MAAM,cAAcA,KAAEI,SAAO,KAAK,CAAC;CACnC,MAAM,SAASD,QAAM,OAAO,IAAI,WAAW;CAC3C,MAAM,SAAS,IAAI,MAAM,MAAM;CAC/B,MAAM,eAAeH,KAAEI,SAAO,MAAM,CAAC;CACrC,MAAM,SAASJ,KAAE,WAAW,OAAO,SAAS;CAC5C,MAAM,QAAQA,KAAE,eAAe,MAAM;CACrC,MAAM,SAASA,KAAE,cAAc,KAAK;CACpC,IAAI,MAAS;CAEb,IAAI,SAAS,GAAG;EACd,MAAM,aAAaI,SAAO,MAAM;EAChC,MAAM,QAAQ,eAAe,IAAID,QAAM,QAAQ,QAAQ,UAAU,IAAI;EAErE,MAAM,IAAI,OAAO,MAAM;CACzB;CAEA,MAAM,SAASH,KAAE,OAAO,IAAI,OAAO,YAAYC,WAAS;CACxD,MAAM,SAAS,OAAO,IAAI,OAAO,YAAYA;CAE7C,MAAM;EAACD,KAAE,IAAI,KAAK,MAAM;EAAGA,KAAE,IAAI,KAAK,MAAM;EAAG,IAAI;CAAE;CACrD,UAAU,OAAO,QAAQ,QAAQ,KAAK,OAAO,OAAO,MAAM;CAC1D,IAAI,EAAE,SAAS,IAAI;CAEnB,MAAM,SAASA,KAAG,SAAS,SAAU,OAAO,WAAW;CACvD,MAAM,CAAC,SAAS,SAAS,WAAW,cAAc,MAAM;CACxD,MAAM,SAAS,IAAI,MAAMG,QAAM,QAAQ,OAAO,aAAa,CAAC;CAC5D,MAAM,YAAY,KAAK,IAAI,MAAM;CACjC,MAAM,YAAYH,KAAE,KAAK,IAAI,MAAM,CAAC;CAEpC,KAAK,IAAI,KAAK,GAAG,KAAK,OAAO,QAAQ,MAAM;EACzC,MAAM,QAAQ,OAAO,IAAIA,KAAE,IAAI,KAAK,EAAE,IAAIC;EAG1C,MAAM,OAAU;GAACD,KAAE,KAAK,IAAI,KAAK,IAAI,SAAS;GAAGA,KAAE,KAAK,IAAI,KAAK,IAAI,SAAS;GAAG;EAAS;EAC1F,MAAM,SAAY;GAAC;GAAG;GAAG;EAAC,CAAC,CAAC,KAAK,QAC/BA,KAAE,QAAQ,OAAQ,KAAK,KAAK,QAAQ,OAAQ,KAAK,KAAK,QAAQ,OAAQ,KAAK,EAAE,CAC/E;EAEA,SAAS,OAAO,QAAQ,KAAK,IAAI,QAAQ,MAAM,GAAG,QAAQ,OAAO,YAAY,MAAM;CACrF;AACF;AAEA,MAAM,uBAA+B,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM;;;;;;;;;AAUtE,MAAa,gBACX,UACA,SACA,EAAE,QAAQ,QAAQ,MAAM,SAAS,gBAAgB,QAAQ,QAAQ,CAAC,KAClE,QACW;CACX,MAAM,SAAS;EAAE,GAAG;EAAuB,GAAG;CAAM;CACpD,MAAM,MAAM,OAAO,OAAO,QAAQ;CAClC,MAAM,QAAgB,CAAC;CAEvB,KAAK,MAAM,EAAE,QAAQ,WAAW,OAAO,UAAU,UAAU;EAEzD,IAAI,eADO,QAAQ,eAAe,QAAQ,IACvB,GAAIA,KAAE,SAAS,GAAG,QAAQ,MAAM,IAAI,GAAG;EAE1D,MAAM,QAAe;GAAE,SAAS,CAAC,WAAW,CAAC;GAAG,OAAO,WAAW,KAAK;GAAG;EAAI;EAC9E,KAAK,MAAM,QAAQ,KAAK,MAAM,GAAG,OAAO,IAAI,GAAG,IAAI,OAAO,QAAQ,OAAO,MAAM,GAAG,MAAM,MAAM;EAE9F,KAAK,MAAM,SAAS,MAAM,SAAS;GACjC,MAAM,OAAO,cAAc,QAAQ,OAAO,SAAS,GAAG;GACtD,IAAI,MAAM,MAAM,KAAK,IAAI;EAC3B;CACF;CAEA,OAAO;AACT;;;;;;;;ACvXA,MAAMO,OAAI,KAAK;AAGf,MAAMC,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC1C,MAAM,QAAQH,KAAE,IAAI;AAGpB,MAAMI,SAAO;AAEb,MAAMC,SAAO,GAAY,MAAuB,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAEhF,MAAM,SAAS,GAAY,OAAyB;CAClD,GAAGL,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;CAC1B,GAAGA,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;CAC1B,GAAGA,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAC5B;AAEA,MAAMM,WAAS,EAAE,GAAG,GAAG,KAAc,QAAyB;CAC5D,GAAGN,KAAE,IAAI,EAAE;CACX,GAAGA,KAAE,IAAI,EAAE;CACX,GAAGA,KAAE,IAAI,EAAE;AACb;;AAGA,MAAM,UAAU,MAAY,SAA2B;CACrD,MAAM,OAAOM,QAAM,MAAM,YAAYN,KAAE,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC,CAAC;CAC5F,MAAM,QAAQA,KAAEA,KAAE,KAAK,YAAY,IAAI,CAAC,IAAI,KAAK;CAEjD,OAAOM,QAAM,MAAM,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,CAAC;AAC3F;;AAGA,MAAM,UAAU,MAAe,MAAe,IAAY,UAA0B;CAClF,MAAM,OAAO,IAAI,KAAK,IAAID,MAAI,MAAM,IAAI,CAAC,IAAIL,KAAE,EAAE,KAAKA,KAAE,KAAK;CAC7D,IAAI,MAAM,GAAG,OAAO;CACpB,OAAOA,KAAE,GAAG,IAAI,IAAI,IAAIA,KAAE,GAAG;AAC/B;;;;;;;;;;;;AAaA,MAAa,kBACX,EAAE,QAAQ,SACV,KACA,eACqB;CACrB,MAAM,EAAE,MAAM,SAAS;CACvB,IAAI,EAAE,QAAQ,MAAM,CAAC,MAAM,OAAO,KAAA;CAElC,MAAM,EAAE,MAAM,UAAU,WAAW;CACnC,MAAM,CAAC,GAAG,GAAG,KAAK,KAAK;CACvB,MAAM,OAAO,KAAK,IAAI,KAAK;CAC3B,IAAI,QAAQ,OAAO,IAAI;CACvB,MAAM,QAAQ,OAAO,IAAI;CAIzB,MAAM,SAAS;EAAE,GAAGA,KAAE,OAAO,IAAI,IAAI,CAAC;EAAG,GAAGA,KAAE,OAAO,IAAI,IAAI,CAAC;EAAG,GAAGA,KAAE,OAAO,IAAI,IAAI,CAAC;CAAE;CACxF,MAAM,OAAOM,QACX,QACA,YAAYN,KAAE,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,CAAC,CAChF;CAEA,MAAM,QAAQ,OAAO,OAAO,MAAM,MAAQ,SAAS;CACnD,MAAM,QAAQ,OAAO,MAAM,MAAM,MAAM,KAAK,CAAC;CAE7C,QAAQM,QAAM,QAAQ,OAAO,KAAK,IAAI,KAAK,KAAK,KAAK;CAErD,IAAI,QAAQ,OAAO,GAAG,MAAM,IAAK,CAAC;CAGlC,IAAI,QAAQ,GAAG;EACb,MAAM,WAAW,IAAI,KAAK,IAAID,MAAI,OAAO,IAAI,CAAC,IAAIL,KAAE,EAAG,KAAK,QAAQ;EAEpE,QAAQ,UAAU,IAAI,IAAIA,KAAE,OAAO;CACrC;CAEA,MAAM,QAAQ,OAAO,MAAM,MAAM,MAAM,CAAC,CAAC;CACzC,MAAM,QAAQM,QAAM,GAAGN,KAAE,KAAK,IAAI,KAAK,CAAC;CAExC,MAAM,EAAE,UAAU,OAAO;CACzB,MAAM,EAAE,IAAI,IAAI,IAAI,OAAO;CAC3B,MAAM,UAAmF,CAAC;CAG1F,MAAM,SAAS,MAAe,MAAe,OAAe,YAAqB;EAC/E,MAAM,OAAO;GAAE,GAAGA,KAAE,OAAO,IAAI,KAAK,CAAC;GAAG,GAAGA,KAAE,OAAO,IAAI,KAAK,CAAC;GAAG,GAAGA,KAAE,OAAO,IAAI,KAAK,CAAC;EAAE;EACzF,MAAM,MAAM;GAAE,GAAGA,KAAE,OAAO,IAAI,KAAK,CAAC;GAAG,GAAGA,KAAE,OAAO,IAAI,KAAK,CAAC;GAAG,GAAGA,KAAE,OAAO,IAAI,KAAK,CAAC;EAAE;EAExF,MAAM,QAAQ,UAAUA,KAAE,IAAI,IAAI,KAAK,CAAC,IAAIA,KAAE,OAAO,IAAI,KAAK,IAAI,KAAK,CAAC;EACxE,MAAM,QAAQ,UAAUA,KAAE,IAAI,IAAI,KAAK,CAAC,IAAIA,KAAE,OAAO,IAAI,KAAK,IAAI,KAAK,CAAC;EAExE,QAAQ,KACN;GAAE,IAAI;IAACA,KAAE,KAAK,IAAI,KAAK,CAAC;IAAGA,KAAE,KAAK,IAAI,KAAK,CAAC;IAAGA,KAAE,KAAK,IAAI,KAAK,CAAC;GAAC;GAAG,IAAI,CAAC,IAAI,EAAE;GAAG;EAAM,GACxF;GAAE,IAAI;IAACA,KAAE,KAAK,IAAI,KAAK,CAAC;IAAGA,KAAE,KAAK,IAAI,KAAK,CAAC;IAAGA,KAAE,KAAK,IAAI,KAAK,CAAC;GAAC;GAAG,IAAI,CAAC,IAAI,EAAE;GAAG;EAAM,GACxF;GAAE,IAAI;IAACA,KAAE,IAAI,IAAI,KAAK,CAAC;IAAGA,KAAE,IAAI,IAAI,KAAK,CAAC;IAAGA,KAAE,IAAI,IAAI,KAAK,CAAC;GAAC;GAAG,IAAI,CAAC,IAAI,EAAE;GAAG;EAAM,GACrF;GAAE,IAAI;IAAC;IAAO;IAAOA,KAAE,IAAI,IAAI,KAAK,CAAC;GAAC;GAAG,IAAI,CAAC,IAAI,EAAE;GAAG;EAAM,CAC/D;CACF;CACA,IAAI,QAAQ,GAAG,MAAM,OAAO,OAAO,OAAO,IAAI;CAC9C,IAAI,QAAQ,GAAG,MAAM,OAAO,OAAO,OAAO,KAAK;CAC/C,IAAI,CAAC,QAAQ,QAAQ,OAAO,KAAA;CAE5B,MAAM,WAAW,IAAI,WAAW,QAAQ,SAASE,QAAM;CACvD,MAAM,OAAO,IAAI,aAAa,SAAS,MAAM;CAE7C,QAAQ,SAAS,EAAE,IAAI,IAAI,SAAS,UAAU;EAC5C,KAAK,IAAI,IAAK,QAAQA,WAAU,CAAC;EACjC,SAAS,IAAI;GAACE,OAAK,MAAM,CAAC;GAAGA,OAAK,MAAM,CAAC;GAAGA,OAAK,MAAM,CAAC;GAAGA,OAAK,KAAK;EAAC,GAAG,QAAQF,WAAS,EAAE;EAC5F,KAAK,IAAI,KAAK,QAAQA,WAAS,MAAM,CAAC;CACxC,CAAC;CAGD,MAAM,UAAU,IAAI,YAClB,MAAM,KAAK,EAAE,QAAQ,QAAQ,SAAS,EAAE,IAAI,GAAG,SAC7C;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;CAAC,CAAC,CAAC,KAAK,WAAW,OAAO,IAAI,MAAM,CACtD,CAAC,CAAC,KAAK,CACT;CA8BA,OAAO;EACL,MAAA;GA7BA,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IACE,YAAY;IACZ,aAAa;IACb,WAAW,QAAQ,SAAS;IAC5B,cAAc,QAAQ;IACtB,SAAS;GACX,CACF;GACA;GACA;EAeG;EACH,WAAA;GAbA,QAAQ;GACR,aAAa;GACb,aAAa,QAAQ;GACrB,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAKE;IAAO,KAAKA;GAAM;GACtC,gBAAgB;IAAE,QAAQA;IAAO,QAAQ;GAAE;EAKnC;EACR,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ;EAEf,OAAO,QAAQ;EACf;EACA,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EAEP,SAAS;GAAE,MAAM,KAAK,QAAQ;GAAM,OAAO,KAAK;GAAS,SAAS;GAAiB,OAAO;EAAE;EAC5F,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW;EACX,OAAO;EACP,gBAAgB;EAChB,eAAe;CACjB;AACF;;;;;;;;;;AC3JA,MAAa,kBAAkB,EAC7B,OACA,OACA,WACA,OAAO,UACqC;CAC5C,IAAI,EAAE,YAAY,IAAI,OAAO,KAAA;CAG7B,MAAM,QAAQ,UAAkB,KAAK,MAAM,KAAK,OAAO,KAAK,IAAI,MAAM,EAAG,IAAI;CAC7E,MAAM,WAAW,QAAQ,eAAe;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,GAAG,KAAK;CACnE,MAAM,OAAO,QAAQ,mBAAmB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAG,GAAG,KAAK;CACpE,MAAM,QAAoB;EACxB,MAAM,OAAO,MAAM,SAAS;EAC5B;EACA,WAAW,KAAK,IAAI;EACpB,OAAO;GAAE,GAAG,KAAK,MAAM,CAAC;GAAG,GAAG,KAAK,MAAM,CAAC;GAAG,GAAG,KAAK,MAAM,CAAC;EAAE;EAC9D,OAAO;EACP,aAAa;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG,KAAK,OAAO,MAAM,YAAY,UAAU;EAAE;CAC1E;CAGA,IAAI,OAAO,KAAK;EACd,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,KAAK,KAAK,GAAG,CAAC;EAEtE,MAAM,OAAO;GAAE;GAAK,OAAO,KAAK,OAAO,MAAM,EAAG;GAAG,SAAS;EAAE;CAChE;CAEA,OAAO;AACT;AA0BA,MAAM,SACJ,EAAE,MAAM,OAAO,aACf,WACA,mBACG;CACH,MAAM,QAAQ,UAAkB,KAAK,MAAM,KAAK,IAAI;CAEpD,OAAO;EACL,MAAM,KAAK,OAAO,KAAK,OAAO,IAAI,IAAI,SAAS;EAC/C,OAAO;GAAE,GAAG,KAAK,MAAM,CAAC;GAAG,GAAG,KAAK,MAAM,CAAC;GAAG,GAAG,KAAK,MAAM,CAAC;EAAE;EAC9D,WAAW,KAAK,QACb,aAAa,IAAI,KAAK,OAAO,GAAI,IAAI,KAAK,OAAO,SAAS,KAAK,cAClE;CACF;AACF;;AAGA,MAAM,iBAAiB,UAAmB,OAAgB,WAA+B;CACvF,MAAM,QAAQ,KAAK,OAAO,MAAM;CAEhC,OAAO;EACL,MAAM;EACN;EACA;EACA;EACA,aAAa;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG,KAAK,OAAO,MAAM,QAAQ,MAAM;EAAE;CAClE;AACF;;;;;AAMA,MAAa,eAAe,EAC1B,UACA,QACA,OACA,WACA,aAAa,GACb,YAAY,GACZ,cACyC;CACzC,IAAI,EAAE,SAAS,IAAI,OAAO,KAAA;CAE1B,MAAM,SAAS,WAAW,UAAU,CAAC;CAErC,IAAI,CAAC,OAAO,UAAU,EAAE,UAAU,IAAI,OAAO,cAAc,UAAU,OAAO,MAAM;CAElF,MAAM,OAAO,OAAO,KAAK,UAAU,MAAM,OAAO,KAAK,OAAO,SAAS,GAAG,KAAK,OAAO,UAAU,CAAC,CAAC;CAEhG,IAAI,WAAW,KAAK,KAAK,SAAS,EAAE,CAAE,MAAM,OAAO,KAAA;CAGnD,IAAI,KAAK;CACT,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS,IAAI,UAAU,KAAK,MAAM,CAAE,MAAM,KAAK;CAExF,MAAM,OAAO,KAAK;CAElB,MAAM,KAAK,KAAK,KAAK,MAAM;CAC3B,MAAM,OAAO,GAAG,OAAO,KAAK;CAC5B,MAAM,QAAQ,OAAO,KAAK,QAAQ,UAAU,KAAK,QAAQ,IAAI,IAAI;CACjE,MAAM,WAAW,GAAW,MAAc,KAAK,OAAO,IAAI,KAAK,QAAQ,CAAC,IAAI;CAC5E,MAAM,MAAM;EACV,GAAG,QAAQ,KAAK,MAAM,GAAG,GAAG,MAAM,CAAC;EACnC,GAAG,QAAQ,KAAK,MAAM,GAAG,GAAG,MAAM,CAAC;EACnC,GAAG,QAAQ,KAAK,MAAM,GAAG,GAAG,MAAM,CAAC;CACrC;CACA,MAAM,aAAa,GAAG,YAAY,KAAK,aAAa,QAAQ,KAAK;CAEjE,OAAO,cAAc,UAAU,KAAK,KAAK,OAAO,YAAY,KAAK,OAAO,MAAM,CAAC,CAAC;AAClF;AAUA,MAAMI,iBAAe,QAAyB,MAAwC;CACpF,IAAI,KAAK;CACT,IAAI,KAAK,OAAO,SAAS;CAEzB,IAAI,KAAK,OAAO,EAAE,CAAE,IAAI,KAAK;MACxB,IAAI,KAAK,OAAO,GAAG,CAAE,IAAI,KAAK;MAEjC,OAAO,KAAK,KAAK,GAAG;EAClB,MAAM,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC;EAEpC,IAAI,EAAE,IAAI,OAAO,IAAI,CAAE,KAAK,KAAK;OAC5B,KAAK;CACZ;CAEF,MAAM,OAAO,OAAO,GAAG,CAAE,KAAK,OAAO,GAAG,CAAE;CAE1C,OAAO;EAAC;EAAI;EAAI;CAAI;AACtB;AAGA,MAAM,UAAU,EAAE,UAAiB,GAAW,KAAa,UAA2B;CACpF,IAAI;CAEJ,IAAI,OAAO;EAET,MAAM,QAAQ,IAAI,IAAI,IAAI;EAE1B,KAAK,KAAK,OAAO,QAAQ,MAAM,OAAQ,QAAQ,MAAM,IAAK;CAC5D,OAAO;EACL,MAAM,WAAW,IAAI,KAAK,OAAO,GAAG;EAEpC,KAAK,KAAK,OAAO,KAAK,IAAI,WAAW,KAAK,MAAM,QAAQ,CAAC,IAAI,KAAK,OAAO,GAAG,CAAC;CAC/E;CAEA,IAAI,QAAQ,OAAO,EAAE,CAAE;CACvB,IAAI,OAAO;CAEX,KAAK,MAAM,CAAC,MAAM,QAAQ;EACxB,QAAQ,KAAK,IAAI,OAAO,CAAC;EACzB,OAAO,KAAK,IAAI,MAAM,CAAC;CACzB;CAEA,OAAQ,KAAK,OAAQ,OAAO,SAAS;AACvC;;AAGA,MAAa,iBAAiB,OAAc,GAAW,QAAwB;CAC7E,MAAM,IAAI,OAAO,OAAO,GAAG,KAAK,IAAI;CACpC,MAAM,CAAC,IAAI,IAAI,QAAQA,cAAY,MAAM,QAAQ,CAAC;CAClD,MAAM,SAAS,OAAO,KAAK,MAAM,OAAO,GAAG,CAAE,KAAK,KAAK,OAAO;CAE9D,QAAQ,IAAI,UAAU,MAAM,OAAO,GAAG,CAAE,KAAK,MAAM,OAAO,GAAG,CAAE,KAAK;AACtE;;;;;;AAOA,MAAa,sBAAsB,OAAc,GAAW,WAA4B;CACtF,MAAM,IAAI,OAAO,OAAO,GAAG,QAAQ,KAAK;CACxC,MAAM,CAAC,IAAI,IAAI,QAAQA,cAAY,MAAM,QAAQ,CAAC;CAClD,MAAM,SAAS,OAAO,KAAK,IAAI,MAAM,OAAO,GAAG,CAAE,MAAM,OAAO;CAC9D,MAAM,OAAO,MAAM,OAAO,GAAG,CAAE,OAAO;CACtC,MAAM,MAAM,MAAM,OAAO,GAAG,CAAE,OAAO;CACrC,MAAM,WAAW,UACf,KAAK,OAAQ,SAAS,QAAS,QAAS,IAAI,WAAY,QAAQ,QAAS,OAAQ,MAAM,IAAI;CAE7F,OAAO;EAAE,GAAG,QAAQ,EAAE;EAAG,GAAG,QAAQ,CAAC;EAAG,GAAG,QAAQ,CAAC;CAAE;AACxD;AAmBA,MAAM,YAAY;AAClB,MAAM,OAAO;;;;;AAMb,IAAM,YAAN,MAAgB;CACd,OAAsB,KAAK,KAAK,GAAG,GAAG,SAAS;CAC/C,QAAgB;CAChB,UAAkB;CAElB,YAAY,QAA+B;EACzC,OAAO,SAAS,OAAO,UACrB,KAAK,OAAO,KAAK,MAAM;GACrB,OAAO;GACP,GAAG,KAAK,MAAM,MAAM,SAAS,CAAC;GAC9B,GAAG,KAAK,MAAM,MAAM,SAAS,CAAC;GAC9B,OAAO,KAAK,MAAM,MAAM,KAAK;EAC/B,CAAC,CACH;CACF;CAEA,KAAa,GAAW,GAAW,MAAoB;EACrD,OAAO;GAAE;GAAG;GAAG;GAAM,UAAU;IAAC,KAAA;IAAW,KAAA;IAAW,KAAA;IAAW,KAAA;GAAS;GAAG,SAAS,CAAC;EAAE;CAC3F;CAGA,MAAc,QAAc,MAAc,IAAY,IAA8B;EAClF,MAAM,WAAW,OAAO,SAAS;EACjC,IAAI,UAAU,OAAO;EACrB,IAAI,KAAK,SAAS,MAAM,OAAO,KAAA;EAC/B,KAAK;EAEL,MAAM,OAAO,KAAK,MAAM,OAAO,OAAO,CAAC;EACvC,MAAM,OAAO,KAAK,KAAK,OAAO,IAAI,KAAK,MAAM,OAAO,IAAI,KAAK,MAAM,IAAI;EAEvE,OAAO,SAAS,QAAQ;EACxB,OAAO;CACT;;CAGA,OAAe,OAAa,OAAoB;EAC9C,MAAM,EAAE,UAAU;EAClB,IAAI,OAAyB;EAG7B,OAAO,SAAS,KAAK,MAAM;GACzB,MAAM,IAAI,MAAM,IAAI,KAAK;GACzB,MAAM,IAAI,MAAM,IAAI,KAAK;GAEzB,IAAI,IAAI,OAAO;IACb,IAAI,IAAI,OAAO,KAAK,QAAQ,MAAM,GAAG,IAAI,IAAI,KAAK;IAClD,IAAI,CAAC,IAAI,OAAO,KAAK,QAAQ,MAAM,GAAG,IAAI,GAAG,KAAK;GACpD;GAEA,IAAI,SAAS,CAAC,GAAG;GACjB,IAAI,IAAI,OAAO,KAAK,QAAQ,MAAM,GAAG,GAAG,IAAI,KAAK;GACjD,IAAI,SAAS,CAAC,GAAG;GACjB,OAAO,KAAK,MAAM,MAAM,GAAG,GAAG,CAAC;GAC/B,IAAI,CAAC,MAAM;EACb;EAEA,IAAI,KAAK,WAAW,MAAM;EAC1B,KAAK;EACL,KAAK,QAAQ,QAAQ,KAAK;CAC5B;CAEA,QAAgB,MAAY,MAAc,IAAY,IAAY,OAAoB;EACpF,MAAM,QAAQ,KAAK,MAAM,MAAM,MAAM,IAAI,EAAE;EAC3C,IAAI,OAAO,KAAK,OAAO,OAAO,KAAK;CACrC;;CAGA,QAAQ,MAAwB,GAAW,GAAW,QAAgB,MAAoB;EACxF,IAAI,CAAC,MAAM;EACX,IAAI,KAAK,QAAQ,QAAQ,KAAK,KAAK,IAAI;EAEvC,MAAM,KAAK,IAAI,KAAK;EACpB,MAAM,KAAK,IAAI,KAAK;EAEpB,IAAI,KAAK,QAAQ;GACf,IAAI,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG,GAAG,QAAQ,IAAI;GAClE,IAAI,CAAC,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG,GAAG,QAAQ,IAAI;EACrE;EAEA,IAAI,CAAC,KAAK,QAAQ;GAChB,IAAI,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG,GAAG,QAAQ,IAAI;GAClE,IAAI,CAAC,KAAK,QAAQ,KAAK,QAAQ,KAAK,SAAS,IAAI,GAAG,GAAG,QAAQ,IAAI;EACrE;CACF;AACF;AAGA,MAAM,cAAc;AACpB,MAAM,eAAe;AAGrB,MAAM,SAAS,UACb,MAAM,qBAAqB,KAAA,KAC3B,MAAM,iBAAiB,KAAA,KACvB,MAAM,eAAe,KAAA;;AAGvB,MAAM,WAAW,OAAmB,OAAgB,WAA4B;CAC9E,IAAI,MAAM,SAAS,iBAAiB,CAAC,MAAM,KAAK,GAAG,OAAO;CAE1D,MAAM,KAAK,MAAM,IAAI,MAAM,SAAS;CACpC,MAAM,KAAK,MAAM,IAAI,MAAM,SAAS;CACpC,MAAM,KAAK,MAAM,IAAI,MAAM,SAAS;CACpC,MAAM,QAAQ,MAAM,QAAQ;CAE5B,OAAO,QAAQ,QAAQ,KAAK,KAAK,KAAK,KAAK,KAAK;AAClD;;AAGA,MAAM,iBACJ,MACA,UACA,QACA,SACa;CACb,MAAM,QAAgB,CAAC;CAEvB,KAAK,QAAQ,KAAK,MAAM,KAAK,MAAM,SAAS,CAAC,GAAG,KAAK,MAAM,SAAS,CAAC,GAAG,KAAK,MAAM,MAAM,GAAG,KAAK;CAGjG,MAAM,SAAkB,CAAC;CAEzB,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,SAAS,KAAK,SAAS;EAChC,IAAI,OAAO,MAAM,EAAE,YAAY,UAAU,MAAM,KAAK,GAAG;EAEvD,IAAI,KAAK;EACT,IAAI,KAAK,OAAO;EAEhB,OAAO,KAAK,IAAI;GACd,MAAM,MAAM,KAAK,OAAO,KAAK,MAAM,CAAC;GAEpC,IAAI,MAAM,QAAQ,OAAO,IAAI,CAAE,OAAO,KAAK,MAAM;QAC5C,KAAK;EACZ;EAEA,IAAI,MAAM,cAAc;EACxB,OAAO,OAAO,IAAI,GAAG,KAAK;EAC1B,OAAO,SAAS,KAAK,IAAI,OAAO,QAAQ,YAAY;CACtD;CAEF,MAAM,OAAiB,CAAC;CAExB,KAAK,MAAM,EAAE,OAAO,GAAG,GAAG,WAAW,QAAQ;EAC3C,IAAI,KAAK,UAAU,MAAM;EAEzB,MAAM,KAAK,SAAS,IAAI;EACxB,MAAM,KAAK,SAAS,IAAI;EACxB,MAAM,QAAQ,QAAQ;EACtB,IAAI,QAAQ,QAAQ,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK;CACxD;CAEA,OAAO;AACT;;AAGA,MAAM,gBACJ,MACA,QACA,UACA,WAEA,cAAc,MAAM,UAAU,QAAQ,WAAW,CAAC,CAAC,QAAQ,UACzD,QAAQ,OAAO,QAAS,UAAU,MAAM,CAC1C;AAGF,MAAM,UAAmB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAG;AAG7C,MAAM,YAAY,UAA0B,UAAU,KAAK,IAAI;AAE/D,MAAM,QAAQ,EAAE,GAAG,GAAG,QAA0B;CAC9C,MAAM,SAAS,KAAK,MAAM,GAAG,GAAG,CAAC;CAEjC,OAAO;EAAE,GAAG,IAAI;EAAQ,GAAG,IAAI;EAAQ,GAAG,IAAI;CAAO;AACvD;AAEA,MAAMC,WAAS,EAAE,GAAG,GAAG,KAAc,QAAyB;CAAE,GAAG,IAAI;CAAI,GAAG,IAAI;CAAI,GAAG,IAAI;AAAG;;AAGhG,MAAM,kBAAkB,OAAmB,UAAkB,SAA0B;CACrF,IAAI,QAAQ;EACV,GAAG,SAAS,MAAM,MAAM,CAAC;EACzB,GAAG,SAAS,MAAM,MAAM,CAAC;EACzB,GAAG,SAAS,MAAM,MAAM,CAAC;CAC3B;CAEA,IAAI,MAAM,YAAY;EACpB,MAAM,EAAE,OAAO,WAAW,MAAM;EAChC,MAAM,OAAO,mBAAmB,OAAO,KAAK,OAAO,IAAI,GAAG,MAAM;EAEhE,QAAQ;GACN,GAAI,KAAK,IAAI,MAAO,MAAM;GAC1B,GAAI,KAAK,IAAI,MAAO,MAAM;GAC1B,GAAI,KAAK,IAAI,MAAO,MAAM;EAC5B;CACF;CAEA,IAAI,MAAM,oBAAoB,MAAM,SAAS,WAC3C,QAAQA,QAAM,OAAO,cAAc,MAAM,kBAAkB,UAAU,MAAM,KAAK,CAAC;CAEnF,OAAO;AACT;;;;;;AAOA,MAAa,uBACX,EAAE,QAAQ,QACV,UACA,SAC4C;CAC5C,MAAM,QAAQ,cAAc,MAAM,UAAU,KAAK,EAAE;CACnD,MAAM,MAAoB,CAAC;CAE3B,KAAK,MAAM,SAAS,OAAO;EACzB,IAAI,IAAI,UAAU,aAAa;EAE/B,MAAM,QAAQ,OAAO;EACrB,IAAI,MAAM,SAAS,eAAe;EAElC,MAAM,KAAK,SAAS,IAAI,MAAM,SAAS;EACvC,MAAM,KAAK,SAAS,IAAI,MAAM,SAAS;EACvC,MAAM,KAAK,SAAS,IAAI,MAAM,SAAS;EACvC,MAAM,WAAW,KAAK,OAAO,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC;EACnD,MAAM,YAAY,MAAM,KAAK,IACzB,KAAK;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;EAAG,CAAC,IAC5B,KAAK,MAAM,aAAa,OAAO;EAEnC,IAAI,KAAK;GAAE,OAAO,eAAe,OAAO,UAAU,IAAI;GAAG;EAAU,CAAC;CACtE;CAEA,OAAO;EAAE,OAAO,MAAM;EAAQ,QAAQ;CAAI;AAC5C;;AAGA,MAAa,iBAAiB,EAAE,GAAG,GAAG,SAA2B;CAC/D,GAAG,SAAS,CAAC;CACb,GAAG,SAAS,CAAC;CACb,GAAG,SAAS,CAAC;AACf;AAQA,MAAa,YAAY,YAA6C;CACpE;CACA,MAAM,IAAI,UAAU,MAAM;AAC5B;AASA,MAAM,WAAW,MAAc,IAAY,QACxC,KAAK,OAAO,KAAK,QAAQ,KAAK,OAAO,EAAG,IAAI,OAAQ;;;;;AAMvD,MAAa,eACX,EAAE,QAAQ,QACV,UACA,QACA,SACA,MACA,WACmB;CAEnB,MAAM,MAAM,cAAc,OAAO;CAEjC,IAAI,QAAQ;EACV,MAAM,EAAE,SAAS,IAAI,WAAW;EAChC,MAAM,QAAQ,UAAkB,KAAK,MAAM,KAAK,IAAI;EAEpD,IAAI,IAAI,QAAQ,KAAK,MAAM,IAAI,IAAI,GAAG,GAAG,KAAK,GAAG,CAAC,GAAG,MAAM;EAC3D,IAAI,IAAI,QAAQ,KAAK,MAAM,IAAI,IAAI,GAAG,GAAG,KAAK,GAAG,CAAC,GAAG,MAAM;EAC3D,IAAI,IAAI,QAAQ,KAAK,MAAM,IAAI,IAAI,GAAG,GAAG,KAAK,GAAG,CAAC,GAAG,MAAM;CAC7D;CAEA,MAAM,MAAoB,CAAC;CAE3B,KAAK,MAAM,SAAS,aAAa,MAAM,QAAQ,UAAU,MAAM,GAAG;EAChE,MAAM,QAAQ,OAAO;EAErB,MAAM,KAAK,SAAS,IAAI,MAAM,SAAS;EACvC,MAAM,KAAK,SAAS,IAAI,MAAM,SAAS;EACvC,MAAM,KAAK,SAAS,IAAI,MAAM,SAAS;EACvC,MAAM,WAAW,KAAK,OAAO,KAAK,MAAM,IAAI,IAAI,EAAE,CAAC;EACnD,MAAM,QAAQ,eAAe,OAAO,UAAU,IAAI;EAElD,IAAI,MAAM,SAAS,WAAW;GAC5B,MAAM,QAAQ,MAAM,gBAAgB,MAAM;GAC1C,MAAM,KAAK,QAAQ,KAAK,OAAO,cAAc,OAAO,UAAU,MAAM,KAAK,CAAC,IAAI;GAE9E,IAAI,KAAK,MAAM,IAAI;GACnB,IAAI,KAAK,MAAM,IAAI;GACnB,IAAI,KAAK,MAAM,IAAI;GAEnB;EACF;EAGA,IAAI,MAAM,IAAI,MAAM,IAAI,MAAM,IAAI,IAAI,KAAK;EAE3C,IAAI,MAAM,SAAS,UAAU,CAAC,MAAM,MAAM;EAG1C,MAAM,YAAY,MAAM,KAAK,IACzB,KAAK;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;EAAG,CAAC,IAC5B,KAAK,MAAM,aAAa,OAAO;EAEnC,IAAI,MAAM,SAAS,eAAe,IAAI,KAAK;GAAE;GAAO;EAAU,CAAC;OAE7D,IAAI,KAAK;GACP;GACA,WAAW,MAAM,SAAS,SAAS,YAAY;GAC/C,UAAU,MAAM;GAChB,OAAO,MAAM;GACb,aAAa,MAAM,eAAe;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAE;GACrD,GAAI,MAAM,SAAS,UAAU,EAAE,MAAM,MAAM,KAAK;EAClD,CAAC;CACL;CAEA,MAAM,QAAQ,UAAkB,SAAS,KAAK,IAAI;CAElD,OAAO;EAAE,QAAQ;EAAK,SAAS;GAAE,GAAG,KAAK,IAAI,CAAC;GAAG,GAAG,KAAK,IAAI,CAAC;GAAG,GAAG,KAAK,IAAI,CAAC;EAAE;CAAE;AACpF;;;;;;;ACxUA,MAAa,wBAAiD;CAC5D,MAAM;CACN,KAAK;CACL,YAAY,CAAC,KAAM,CAAC;CACpB,iBAAiB,CAAC,GAAG,GAAI;AAC3B;;;;;AAwBA,MAAa,aAAa,WACxB,SAAS,MACL,CAAC,WAAW,SAAS,IACrB,SAAS,KACP,CAAC,SAAS,SAAS,IACnB,SAAS,OACP,CAAC,SAAS,IACV,CAAC;AAwBX,MAAa,sBAA6C;CACxD,GAAG;CACH,GAAG;CACH,SAAS;CACT,cAAc;CACd,aAAa;CACb,cAAc;CACd,iBAAiB;CACjB,cAAc;CACd,iBAAiB;CACjB,eAAe;CACf,eAAe,KAAK,OAAO,EAAG;AAChC;AAEA,MAAM,OAAO;AACb,MAAM,QAAQ;AACd,MAAMC,QAAM;AACZ,MAAM,eAAe;AACrB,MAAM,aAAa;AAInB,MAAM,gBAAgB;CAACA;CAAK;CAAO;CAAM;AAAmB;AAC5D,MAAM,eAAe;CAACA;CAAK;CAAM;CAAqB;CAAO;AAAoB;AAGjF,MAAM,sBAAsB;AAE5B,MAAM,sBAAsB,CAAC,IAAM,EAAI;;AASvC,MAAM,QACJ,EAAE,QAAQ,iBAAiB,IAAI,WAAW,MAC1C,MACA,QACA,WACuB;CACvB,MAAM,SAAS,QAAQ,eAAe,OAAO,QAAQ,IAAI;CACzD,MAAM,OAAO,eAAe,QAAQ,OAAO,QAAQ,QAAQ,MAAM;CACjE,IAAI,SAAS,GAAG,OAAO,KAAA;CAEvB,MAAM,UAAU,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO;CAC9E,IAAI,iBAAiB,KAAK,UAAU,iBAAiB,gBAAgB,OAAO;EAAE;EAAM,MAAM;CAAE;CAC5F,IAAI,WAAW,KAAK,UAAU,WAAW,UAAU,OAAO,KAAA;CAC1D,OAAO;EAAE;EAAM,MAAM,iBAAiB,IAAI,IAAI;CAAE;AAClD;;;;;AAMA,MAAM,aACJ,QACA,SACA,OACA,oBACuB;CACvB,IAAI,CAAC,OAAO,OAAO;CAEnB,MAAM,MAAM,QAAQ,UAAU,MAAM;CACpC,MAAM,QAAQ,QAAQ,UAAU;CAChC,IAAI,CAAC,OAAO,QAAQ,iBAAiB,OAAO,KAAA;CAI5C,MAAM,YAAY,MAAM,QAAQ;CAChC,IAAI,MAAM,cAAc,KAAK,aAAa,GAAG,OAAO,KAAA;CACpD,IAAI,MAAM,cAAc,KAAK,aAAa,GAAG,OAAO,KAAA;CAGpD,MAAM,SAAS,MAAM,MAAM;CAE3B,IAAI,MAAM,cAAc,KAAK,aAAa,KAAK,UAAU,KAAK,OAAO,SAAS,MAAM,GAClF,OAAO,KAAA;CAET,OAAO,YAAY,IAAI,QAAQ;AACjC;AA6BA,MAAMC,OAAI,KAAK;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAa1C,MAAM,yBAAS,IAAI,QAAkC;AAErD,MAAM,eAAe,WAAqC;CACxD,IAAI,QAAQ,OAAO,IAAI,MAAM;CAE7B,IAAI,CAAC,OAAO;EACV,QAAQ;GACN,OAAO,IAAI,eAAe,OAAO,cAAc,CAAC,CAAC;GACjD,OAAO;GACP,OAAOD,KAAE,EAAG;GACZ,aAAaA,KAAE,EAAG;EACpB;EACA,OAAO,IAAI,QAAQ,KAAK;CAC1B;CAEA,OAAO;AACT;;;;;AAMA,MAAM,kBAAkB,MAAY,KAAc,gBAAgC;CAChF,MAAM,IAAI,KAAK;CACf,MAAM,KAAK,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC;CACpC,MAAM,KAAK,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC;CACpC,MAAM,KAAK,EAAE,KAAK,SAAS,IAAI,IAAI,CAAC;CACpC,MAAM,MAAM,KAAK,KAAK,KAAK,KAAK,KAAK;CACrC,MAAM,SAAS,EAAE,YAAY,GAAG,IAAI,GAAG;CACvC,MAAM,UAAU,IAAI;CACpB,MAAM,UAAU,KAAK,YAAY;EAAE,GAAG,EAAE,KAAK,OAAO;EAAG,GAAG,EAAE,KAAK,OAAO;EAAG,GAAG,EAAE,KAAK,OAAO;CAAE,CAAC;CAC/F,MAAM,MAAM,UAAU,UAAU,cAAc,GAAG,SAAS,YAAY,SAAS,QAAQ;CAEvF,OAAO,MAAM,cAAc,cAAc;AAC3C;AAEA,MAAM,sBAAsB,EAAE,aAAa,GAAG,GAAG,YAAoC;;;;;AAMrF,MAAM,YACH,WACA,EAAE,aAAa,GAAG,GAAG,YAAoC;CACxD,MAAM,EAAE,gBAAgB;CACxB,IAAI,CAAC,aAAa,OAAO;CAEzB,MAAM,SAAS,YAAY,YAAY;CAEvC,OAAO;EACL,GAAG;EACH;EACA,UAAU,SACR,KAAK,YAAY,MAAM,SAAS,MAAM,QAAQ,IAAI,IAAI,MAAM,QAAQ,IAAI;CAC5E;AACF;;AAGF,MAAM,eAAe,SAA6B,WAChD,YAAY,KAAA,IAAY,OAAO,UAAU,KAAK,IAAI,SAAS,OAAO,YAAY;AAEhF,MAAM,WACJ,QACA,OACA,YAEA,OAAO,SAAS,uBAAuB,CAAC,OAAO,WAC3C,KAAA,IACA,WAAW;CAAE,GAAG;CAAQ,UAAU,OAAO;AAAS,GAAG,OAAO,OAAO;AAwBzE,MAAa,qBAAqB,EAChC,QAAQ,OACR,QACA,SACA,QACA,SACA,MAAM,CAAC,GACP,SACA,QACA,UAAU,CAAC,GACX,UAAU,CAAC,GACX,YACA,OAAO,GACP,OAAO,GACP,aAAa,MACb,YACA,UACA,OACA,WACA,SACA,QACA,QAAQ,CAAC,GACT,MAAM,OACN,OAAO,OACP,YAAY,CAAC,GACb,MACA,YAAY,CAAC,GACb,aACA,QAAQ,CAAC,GACT,aACA,WAAW,CAAC,GACZ,aACA,eACA,eACA,cAAc,OACd,MAAM,OACN,SACA,eACA,aAAa,OACb,WAC4B;CAC5B,MAAM,WAAW;EAAE,GAAG;EAAqB,GAAG;CAAO;CACrD,MAAM,EACJ,aACA,cACA,iBACA,cACA,iBACA,kBACE;CACJ,MAAM,YAAY,YAAY,SAAS,QAAQ;CAE/C,IAAI,MACF,OAAO,iBAAiB,MAAM;EAAE,GAAG;EAAO,KAAK;CAAU,GAAG,QAAQ,MAAM,SAAS;EACjF;EACA,QAAQ;EACR;EACA;EACA,SAAS,cAAc,UAAU,KAAA;EACjC;EACA,eAAe;GAAE,GAAG;GAAuB,GAAG;EAAc;CAC9D,CAAC;CAEH,MAAM,QAAQ,YAAY;CAC1B,MAAM,EAAE,UAAU,QAAQ;CAC1B,MAAM,SAAS,QAAQ,KAAK,WAAW,YAAY,QAAQ,KAAK,QAAQ,CAAC;CACzE,MAAM,EAAE,OAAO,aAAa,YAAY,QAAQ,KAAK,KAAK;CAE1D,MAAM,UAAwB,CAAC;CAE/B,MAAM,WAAW,YAAyB,UACxC,UAAU,OAAO,MAAM,OAAO,gBAAgB,GAAG,KAAK;CACxD,MAAM,cAAc,YAAyB,UAC3C,YAAY,MAAM,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,EAAE,aAAa;CAGpD,KAAK,MAAM,EAAE,UAAU,SAAS,IAAI,MAAM,WAAW,MAAM,UAAU;CAErE,KAAK,MAAM,EAAE,QAAQ,OAAO,aAAa,QAAQ;EAC/C,OAAO,UAAU,OAAO,KAAK,YAAY,OAAO,GAAG;EAKnD,MAAM,QAAQ,YAAY,MAAM;EAChC,IAAI,MAAM,QAAQ,MAAM,MAAM,cAAc,KAAK,MAAM,MAAM,cAAc;EAE3E,IAAI,MAAM,QAAQ,MAAM,OAAQ,MAAM,QAAQA,KAAE,GAAI,KAAK,MAAM,gBAAgB,IAC7E,MAAM,MAAM,KAAK,GAAG;EAGtB,IAAI,UAAU,KACZ,KAAK,MAAM,UAAU,OAAO,UAAU,CAAC,GACrC,OAAO,OAAO,OAAO,MAAM,OAAO,QAAQ,MAAM,GAAG,WAAW,MAAM,CAAC;EAEzE,MAAM,QAAQA,KAAE,aAAa,MAAM,KAAK;EACxC,MAAM,cAAcA,KAAE,aAAa,MAAM,WAAW;EACpD,MAAM,QAAQ;EACd,OAAO,WAAW,OAAO,MAAM,OAAO,GAAG;EAEzC,MAAM,QAAQ,OAAO,WAAW;EAChC,IAAI,OAAO,QAAQ,KAAK,KAAK;CAC/B;CAEA,MAAM,SAAS,OAAO,cAAc;CACpC,MAAM,MAAM,SAAS,KAAK,IAAI,OAAO,MAAM,OAAO,QAAQ,GAAG,SAAS,IAAI;CAC1E,MAAM,SAAiB;EAAE,GAAG;EAAO;CAAI;CACvC,MAAM,YAAoB;EAAE,GAAG;EAAO,KAAK;CAAa;CACxD,MAAM,OAAO,WAAW,MAAM;CAG9B,MAAM,QAAgE,MAAM,KAC1E,EAAE,QAAQ,WAAW,IACpB,GAAG,OAAQ,OAAOD,QAAM,SAAS,KAAK,EAAE,OAAO,WAAW;EAAE,QAAQ;EAAO;CAAI,EAAE,IAAI,CAAC,CACzF;CAEA,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,KAAK,OAAO,SAAS,IAAI,IAAI;EACnC,MAAM,KAAK,OAAO,SAAS,IAAI,IAAI;EACnC,MAAM,KAAK,OAAO,SAAS,IAAI,IAAI;EACnC,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK;EAIzC,IAAI,OAAO,SAAS,CAAC,OAAO,MAAM,OAAO;GAEvC,MAAM,SAAS,OAAO,MAAM,UAAU,OAAO,OAAO,UAAU;GAC9D,IAAI,WAAW,QAAQ,OAAO;EAChC;EAEA,MAAM,SACJ,OAAO,WAAW,OAAO,KAAA,IAAY,WAAW,QAAQ,OAAO,UAAU,OAAO,MAAM;EAExF,IAAI,WAAW,QAAQ,OAAO;GAE5B,IAAI,CAAC,OAAO,SAAS,UAAU,QAAQ;GAEvC,MAAM,SAAS,KAAK,QAAQ,MAAM,WAAW,MAAM;GACnD,IAAI,QAAQ,MAAMA,MAAI,CAAE,KAAK;IAAE;IAAQ,KAAK;IAAS;GAAO,CAAC;GAC7D;EACF;EAEA,MAAM,SAAS,OAAO,OAAO,SAAS,OAAO,OAAO,SAAS;EAC7D,MAAM,MAAM,UAAU,SAAS;EAC/B,IAAI,OAAO,UAAU,QAAQ,KAAK,OAAO,eAAe;EACxD,IAAI,SAAS,KAAA,GAAW;EAExB,MAAM,SAAS,KAAK,QAAQ,MAAM,QAAQ,MAAM;EAChD,IAAI,CAAC,QAAQ;EACb,IAAI,MAAM,eAAe,cAAc,OAAO,SAAS,MAAM,cAAc,IAAI,QAAQ;EACvF,MAAM,OAAO,QAAQ,OAAO,eAAe,KAAK,CAAE,KAAK;GAAE;GAAQ;GAAK;GAAQ;EAAO,CAAC;CACxF;CAGA,MAAM,iBAAiB,MAAM,KAAK,SAAS;EACzC,MAAM,aAAa,KAAK,OAAO,cAAc,MAAM,GAAG,CAAC;EAEvD,KAAK,MAAM,UAAU,KAAK,UAAU,CAAC,GACnC,OAAO,OAAO,OAAO,MAAM,aAAa,UAAU,cAAc,MAAM,KAAK,CAAC;EAE9E,OAAO;CACT,CAAC;CAMD,MAAM,YAAY,KAAK,QAAQ,QAAQ,kBAAkB,QAAQ,cAAc;CAE/E,KAAK,MAAM,QAAQ,SAAS,CAAC,IAAI,OAC/B,KAAK,MAAM,SAAS,KAAK,QAAQ;EAE/B,IAAI,eADW,QAAQ,eAAe,MAAM,QAAQ,IACjC,GAAQ,MAAM,QAAQ,QAAQ,MAAM,IAAI,GAAG;EAE9D,MAAM,KAAK,MAAM,OAAO,IAAI,IAAI;EAChC,MAAM,KAAK,MAAM,OAAO,IAAI,IAAI;EAChC,MAAM,KAAK,MAAM,OAAO,IAAI,IAAI;EAChC,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK;EAEzC,IAAI,UAAU,WAAW;GACvB,MAAMA,MAAI,CAAE,KAAK;IAAE;IAAM;IAAO,KAAK,KAAK,OAAO,OAAO;GAAE,CAAC;GAC3D;EACF;EAEA,MAAM,SAAS,MAAM,SAAS,MAAM;EAEpC,MAAM,KAAK,CAAE,KAAK;GAAE;GAAM;GAAO,KAAK,KAAK,OAAO,UAAU,SAAS,IAAI,UAAU,MAAM;EAAE,CAAC;CAC9F;CAMF,MAAM,WAAW,SAAS,QAAQ,SAAS,CAAC,GAAG,QAAQ,GAAG,OAAO,IAAI,MAAM;CAC3E,MAAM,eAAe,KAAK,OAAO,QAAQ,KAAK;CAC9C,MAAM,UAAU,QAAQ;CACxB,MAAM,cAAc,KAAK,OAAO,UAAU,OAAO;CAEjD,KAAK,MAAM,YAAY,WAAW;EAChC,MAAM,EAAE,MAAM,iBAAiB,CAAC,GAAG,SAAS;EAC5C,IAAI,MAAM,KAAK,OAAO,GAAG;EAGzB,MAAM,WAAW,eAAe,SAAS,kBAAkB,UAAU,KAAK,GAAI,IAAI;EAClF,KAAK,MAAM,aAAa,gBAAgB,UAAU,OAAO,KAAK,QAAQ;EAGtE,KAAK,MAAM,EAAE,WAAW,SAAS,WAAW,CAAC,GAC3C,MAAM,OAAO,OAAO,MAAM;GACxB,SAAS;GACT,YAAY,KAAK,IAAI,MAAM,SAAS,aAAa;EACnD,CAAC;EAGH,MAAM,WAAW,CAAC,GAAI,OAAO,CAAC,IAAI,IAAI,CAAC,GAAI,GAAG,cAAc,CAAC,CAAC,SAAS,UACrE,MAAM,OAAO,KAAK,OAAO,QAAQ;GAAE;GAAO;GAAO;EAAG,EAAE,CACxD;EAEA,KAAK,MAAM,EAAE,WAAW,UACtB,IAAI,CAAC,MAAM,SACT,MAAM,KAAK;GAAE;GAAS,GAAG,oBAAoB,UAAU,MAAM,UAAU,IAAI;EAAE,CAAC;EAElF,IAAI,QAAQ;EAEZ,IAAI,SAAS,WAAW,GAAG;GACzB,MAAM,MAAM,eAAe,MAAM,KAAK,WAAW;GAEjD,MAAM,MAAM,eAAe,OAAOA,MAAI,CAAE,KAAK;IAAE,MAAM,SAAS,EAAE,CAAE;IAAO,OAAO;IAAG;GAAI,CAAC;GACxF;EACF;EAEA,KAAK,MAAM,EACT,OACA,OAAO,EAAE,QAAQ,UACjB,QACG,UAAU;GACb,IAAI,eAAe,QAAQ,eAAe,QAAQ,IAAI,GAAG,QAAQ,QAAQ,MAAM,IAAI,GAAG;GAEtF,MAAM,KAAK,OAAO,IAAI,IAAI;GAC1B,MAAM,KAAK,OAAO,IAAI,IAAI;GAC1B,MAAM,KAAK,OAAO,IAAI,IAAI;GAC1B,IAAI,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK;GAEvC,IAAI,eAAe,SAAS;IAC1B,MAAMA,MAAI,CAAE,KAAK;KAAE,MAAM;KAAO,OAAO;KAAI,KAAK,KAAK,OAAO,OAAO;IAAE,CAAC;IACtE;GACF;GAGA,IAAI,cAAc,SAAS,WAAW,cAAc,WAAW,KAAK,OAAO,GAAI,IAAI;GACnF,MAAM,KAAK,CAAE,KAAK;IAAE,MAAM;IAAO,OAAO;IAAI,KAAK,KAAK,OAAO,OAAO;GAAE,CAAC;EACzE;CACF;CAGA,KAAK,MAAM,QAAQ,OAAO,KAAK,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;CAE3D,MAAM,QAAgB,CAAC;CACvB,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,SAAmB,CAAC;CAG1B,IAAI,CAAC,QACH,KAAK,MAAM,SAAS,KAAK;EACvB,aACE,OACA,QACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,QACF;EACA,YAAY,QAAQ,KAAK;CAC3B;CAEF,MAAM,SAAuB,CAAC;CAC9B,MAAM,gBAAgB,UAAU,WAAW;EAAE,OAAO;EAAG,QAAQ;CAAE,EAAE;CACnE,MAAM,gBAAgB,iBAAiB,WAAW,MAAM;;;;;;;CAQxD,MAAM,aAAa,UAA8B,UAAkB;EACjE,MAAM,UAAU,EAAE,QAAQ,EAAE;EAC5B,MAAM,QAAQ,WAAW,UAAU,OAAO,QAAQ,OAAO;EAEzD,cAAc,SAAS;GAAE,OAAO,MAAM;GAAQ,QAAQ,QAAQ;EAAO;EACrE,MAAM,WAAW,SAAS,WAAW,CAAC,EAAA,CAAG,KAAK,EAAE,OAAO,aAAa;GAClE;GACA;GACA,OAAO,MAAM,MAAM;EACrB,EAAE;EACF,IAAI,CAAC,MAAM,UAAU,CAAC,SAAS,cAAc,CAAC,QAAQ,MAAM,EAAE,YAAY,MAAM,MAAM,GAAG;EAEzF,MAAM,QAAQ,QAAQ,wBAAwB,MAAM,aAAa,GAAG;EACpE,MAAM,QAAQ,QAAQ,eAAe;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAI,GAAG,KAAK;EAIlE,MAAM,oBAAwC;GAC5C,IAAI,SAAS,iBACX,OAAO,SAAS,MAAM,cAAc,IAChC;IAAE,OAAO,MAAM;IAAO,QAAQ,MAAM,MAAM;GAAM,IAChD,KAAA;GAEN,MAAM,QAAQ,WAAW,QAAQ,SAAS,KAAK,QAAQ;GACvD,OAAO,SAAS;IAAE,OAAO,MAAM;IAAO,QAAQ;GAAE;EAClD;EACA,MAAM,MAAM,YAAY;EACxB,MAAM,SAAS,KAAK;EACpB,MAAM,MAAM,YACV,UACA;GAAE,GAAG,KAAK,OAAO,MAAM,CAAC;GAAG,GAAG,KAAK,OAAO,MAAM,CAAC;GAAG,GAAG,KAAK,OAAO,MAAM,CAAC;EAAE,GAC5E,KACA,SACA,MACA,OAAO,QAAQ,OAAO,WAAW;GAAE,SAAS,OAAO,OAAO;GAAS,QAAQ,IAAI;EAAO,CACxF;EACA,MAAM,QAAQ,SAAS,mBAAmB;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAE7D,MAAM,QAAQ,OAAe,aAC3B,KAAK,IAAI,KAAK,MAAM,QAAQ,GAAG,IAAI,KAAK,MAAM,QAAQ,GAAG,GAAG,IAAI;EAClE,MAAM,eAAe;GACnB,GAAG,KAAK,IAAI,QAAQ,GAAG,MAAM,CAAC;GAC9B,GAAG,KAAK,IAAI,QAAQ,GAAG,MAAM,CAAC;GAC9B,GAAG,KAAK,IAAI,QAAQ,GAAG,MAAM,CAAC;EAChC;EACA,MAAM,MAAM,UAAU,MAAM,OAAO,OAAO,OAAO,QAAQ,KAAK,GAAG,OAAO,OAAO,IAAI,KAAK;EAIxF,IAAI,SAAS,YACX,MAAM,KACJ,GAAG,SAAS,WAAW,KACrB,OACA;GACE,SAAS;GACT,QAAQ,oBAAoB,UAAU,KAAK,IAAI,CAAC,CAAC;GACjD,GAAI,OAAO,EAAE,IAAI;EACnB,GACA,GACF,CACF;EAEF,MAAM,UAAU,SAAS,YAAY,KAAK;EAC1C,MAAM,EAAE,SAAS,SAAS,SAAS;EAGnC,MAAM,aACJ,EAAE,MAAM,WAAW,GAAG,WACtB,UACG;GACH,MAAM,QAAQ,MAAM;GAEpB,aACE;IAAE,GAAG;IAAS,YAAY;IAAM,OAAO,CAAC;KAAE;KAAW;KAAO;IAAK,CAAC;GAAE,GACpE,QACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,UACA,IACF;GACA,OAAO;EACT;EAEA,KAAK,MAAM,EAAE,UAAU,aAAa,WAAW,OAAO;GACpD,MAAM,QAAQ,QAAQ,SAAS,QAAQ,YAAY,QAAQ,GAAG,WAAW;GACzE,MAAM,QAAQ,UAAU,SAAS,MAAM,KAAK;GAE5C,KAAK,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAAS;IACrD,MAAM,UAAU,QAAQ;IAExB,MAAM,SAAS;KACb,GAAG,MAAM;KACT,SAAS;MAAC,QAAQ;MAAG,QAAQ;MAAG,QAAQ;MAAG;KAAK;KAEhD,SAAS,SAAS,UAAU;KAC5B,UAAU;MAAE,GAAG;MAAG,GAAG;MAAG,GAAG;KAAE;KAE7B,QAAQ,SAAS,CAAC,IAAI,IAAI;KAC1B,cAAc,SAAS;MAAE,GAAG;MAAG,GAAG;MAAG,GAAG;KAAE,IAAI;KAC9C,WAAW;KACX,YAAY,CAAC;KACb,OAAO;KACP,WAAW;KACX,eAAe;KACf,gBAAgB,UAAU,IAAI;KAC9B,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;IACvB;GACF;EACF;;;;;;;EAQA,KAAK,MAAM,EAAE,OAAO,OAAO,OAAO,YAAY,SAC5C,KAAK,MAAM,EAAE,OAAO,WAAW,QAAQ;GACrC,MAAM,QAAQ,UAAU,OAAO,KAAK;GAEpC,KAAK,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAAS;IACrD,MAAM,UAAU,QAAQ;IAExB,MAAM,SAAS;KACb,GAAG,MAAM;KACT,SAAS;MAAC,MAAM,QAAQ;MAAG,MAAM,QAAQ;MAAG,MAAM,QAAQ;MAAG;KAAK;KAClE,SAAS,MAAM;KACf,UAAU;MAAE,GAAG;MAAG,GAAG;MAAG,GAAG;KAAE;KAC7B,QAAQ,IAAI;KACZ;KACA,WAAW;KACX,OAAO;KACP,WAAW;KACX,eAAe;KACf,gBAAgB,UAAU,IAAI;KAC9B,GAAI,MAAM,EAAE,IAAI,IAAI,CAAC;IACvB;GACF;EACF;CACJ;;;;;;;;CASA,MAAM,aAAa,UAAuB;EACxC,MAAM,SAAS,MAAM;EACrB,MAAM,QAAQ,QAAQ,UAAU;EAChC,IAAI,CAAC,UAAU,CAAC,OAAO;EAEvB,MAAM,QAAQ,OAAO,YAAY,KAAK,OAAO,EAAG,KAAK,KAAK,OAAO,IAAI;EACrE,MAAM,QAAQ,KAAK,QAAQ,OAAO,IAAI,IAAI,OAAO,IAAI,IAAI,SAAS,MAAM,YAAY,EAAE;EACtF,MAAM,QAAQ,KAAK,OACjB,OAAO,UAAU,KAAK,UAAU,MAAM,UAAU,KAAK,KAAK,OAAO,IAAK,CACxE;EACA,MAAM,QAAQ,QAAQ,SAAS,MAAM,WAAW,QAAQ,QAAQ,KAAK,CAAC;EACtE,MAAM,QAAQ,MAAM;EAEpB,aACE,MAAM,MAAM,KAAK,GACjB,QACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,QACF;EACA,YAAY,QAAQ,KAAK;EAEzB,KAAK,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAAS;GACrD,MAAM,OAAO,MAAM;GAEnB,MAAM,SAAS;IACb,GAAG;IACH,SAAS;KAAC,KAAK,QAAQ;KAAI,KAAK,QAAQ;KAAI,KAAK,QAAQ;KAAI;IAAK;IAClE,SAAS,MAAM;IACf,QAAQ,CAAC;IACT,cAAc;KAAE,GAAG;KAAG,GAAG;KAAG,GAAG;IAAE;IACjC,OAAO;IACP,WAAW;IACX,YAAY;IACZ,WAAW;IACX,MAAM;IACN,gBAAgB;IAChB,eAAe;GACjB;EACF;CACF;CAGA,MAAM,gBAAgB,UAAuB;EAC3C,MAAM,OAAO,MAAM,OAAO,UAAU,KAAK,OAAO,WAAW,MAAM,QAAQ,aAAa;EACtF,IAAI,MAAM,MAAM,KAAK,IAAI;CAC3B;CAEA,KAAK,MAAM,MAAM,CAAC,SAAS,MAAM,cAAc,IAAI,gBAAgB,cAAc;EAC/E,MAAM,YAAY,OAAOA;EACzB,MAAM,aAAa,YAAY,YAAY;EAI3C,IAAI,OAAO,SAAS,OAAO,cAAc,GAAG;GAC1C,MAAM,SAAS,eAAe,MAAM,OAAO,KAAK,aAAa;GAC7D,IAAI,QAAQ,MAAM,KAAK,MAAM;EAC/B;EAEA,KAAK,MAAM,UAAU,MAAM,KAAM;GAC/B,MAAM,QAAQ,MAAM;GAGpB,IAAI,YAAY,QAAQ;IACtB,MAAM,SAAS,eAAe,OAAO,QAAQ,KAAK,aAAa;IAC/D,IAAI,QAAQ,MAAM,KAAK,MAAM;IAC7B,aAAa,OAAO,MAAM;IAC1B;GACF;GAEA,IAAI,UAAU,QAAQ;IACpB,MAAM,OAAO,OAAO,KAAK,UAAU,OAAO,KAAK;IAC/C,IAAI,MAAM,MAAM,KAAK;KAAE,GAAG;KAAM,YAAY;IAAc,CAAC;IAC3D;GACF;GAEA,IAAI,UAAU,QAAQ;IACpB,MAAM,OAAO,cAAc,OAAO,MAAM,OAAO,KAAK;IACpD,IAAI,CAAC,MAAM;IACX,MAAM,KACJ,YACI;KAAE,GAAG;KAAM,WAAW;KAAU,YAAY;KAAO,YAAY;IAAc,IAC7E,IACN;IACA;GACF;GAEA,MAAM,EAAE,QAAQ,QAAQ,WAAW;GAInC,IAAI,OAAO,MACT,MAAM,KAAK,GAAG,cAAc,OAAO,MAAM,OAAO,UAAU,OAAO,aAAa,CAAC;QAC5E;IACH,IAAI,OAAO,SAAS,OAAO,SAAS,GAClC,aACE,OAAO,OACP,YACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,QACF;IAGF,IAAI,OAAO,SAAS,KAAK,OAAO,QAAQ,OAAO,QAAQ,GAAG,CAAC,GAAG,OAAO,MAAM,CAAC,CAAC,QAAQ,CAAC;IAItF,KAAK,MAAM,SAAS,CAAC,OAAO,OAAO,IAAI,OAAO,YAAY,CAAC,EAAA,CAAG,IAAI,SAAS,OAAO,KAAK,CAAC,CAAC,GACvF,aACE,OAAO,SAAS,IAAI,QAAQ,mBAAmB,KAAK,GACpD,YACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,UACA,OAAO,SAAS,KAAK,OAAO,SAAS,CACvC;IAEF,YAAY,QAAQ,KAAK;GAC3B;GAIA,MAAM,SAAS,QAAQ,MAAM;GAC7B,MAAM,MAAM,YACV,UACA,OAAO,UACP,OAAO,OAAO,QACd,SACA,MACA,QAAQ,WAAW;IAAE,SAAS,OAAO;IAAS,QAAQ,OAAQ;GAAO,CACvE;GAEA,MAAM,MACJ,UACA,MAAM,OAAO,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,QAAQ,GAAG,OAAQ,IAAI,KAAK;GAIpF,IAAI,CAAC,OAAO,MACV,KAAK,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAAS;IACrD,MAAM,OAAO,MAAM;IAEnB,MAAM,SAAS;KACb,GAAG;KACH,QAAQ,IAAI;KACZ,cAAc,KAAK,gBAAgB,IAAI;KACvC,GAAI,OAAO,EAAE,IAAI;IACnB;GACF;GAIF,IAAI,CAAC,WACE;SAAA,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAC5C,IAAI,MAAM,MAAM,CAAE,cAAc,QAC9B,MAAM,SAAS;KAAE,GAAG,MAAM;KAAS,WAAW;IAAS;GAAA;GAG7D,IAAI,WACF,KAAK,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAC5C,MAAM,SAAS;IACb,GAAG,MAAM;IACT,WAAW;IACX,YAAY;IACZ,YAAY;GACd;EACN;EAIA,IAAI,OAAO,KAAuB,OAAO,cAAc,GAAG;GACxD,MAAM,SAAS,eAAe,MAAM,OAAO,KAAK,aAAa;GAC7D,IAAI,QAAQ,MAAM,KAAK,MAAM;EAC/B;EAEA,IAAI,OAAO,KAAuB,SAAS,MAAM,cAAc,GAAG;GAChE,MAAM,UAAU,eAAe,MAAM,OAAO,MAAM,QAAQ;GAC1D,IAAI,SAAS,MAAM,KAAK,OAAO;GAK/B,MAAM,EAAE,gBAAgB,MAAM,MAAM;GACpC,MAAM,QAAQC,KAAE,MAAM,MAAM,QAAQA,KAAE,aAAa,aAAa,EAAG,CAAC;GACpE,MAAM,OAAOA,KAAE,aAAa,UAAU,IAAI;GAE1C,KAAK,MAAM,EAAE,MAAM,cAAc,SAC/B,IAAI,MAAM,MAAM,KAAK,GAAG,cAAc,MAAM,UAAU,OAAO,eAAe,OAAO,IAAI,CAAC;EAC5F;EAIA,IACG,OAAO,SAAS,OAAO,cAAc,KACrC,OAAO,KAAuB,OAAO,cAAc,GAEpD,aAAa,MAAM,KAAK;EAI1B,IAAI,OAAO,SAAS,SAAS,MAAM,cAAc,GAAG,UAAU,MAAM,KAAK;EAEzE,IACG,OAAO,SAAS,CAAC,SAAS,MAAM,cAAc,MAC9C,OAAO,SAAS,SAAS,MAAM,cAAc,GAE9C,UAAU,QAAQ,SAAS;EAG7B,IAAI,OAAO,KAAwB,SAAS,MAAM,cAAc,GAAG;GACjE,MAAM,EAAE,QAAQ,OAAO,QAAQ,MAAM;GAErC,KAAK,MAAM,UAAU,OAAO,UAAU,CAAC,GAAG;IACxC,MAAM,OAAO,OAAO,KAAK,OAAO;KAC9B;KACA,OAAO,QAAQ,MAAM;KACrB,UAAU,WAAW,MAAM;IAC7B,CAAC;IACD,IAAI,MAAM,MAAM,KAAK;KAAE,GAAG;KAAM,KAAK,MAAM,OAAO,KAAK,OAAO,IAAI,KAAK;KAAG,MAAM;IAAO,CAAC;GAC1F;EACF;EAIA,IAAI,OAAO,SAAS,CAAC,SAAS,MAAM,cAAc,IAChD,MAAM,SAAS,MAAM,UAAU;GAC7B,IAAI,EAAE,eAAe,SAAU,IAAI;GAEnC,KAAK,MAAM,UAAU,KAAK,UAAU,CAAC,GAAG;IACtC,MAAM,OAAO,OAAO,KAAK,OAAO;KAAE;KAAK,QAAQ,UAAU,cAAc,MAAM,KAAK;IAAE,CAAC;IACrF,IAAI,MAAM,MAAM,KAAK,IAAI;GAC3B;EACF,CAAC;CACL;CAIA,MAAM,QAAsB,CAAC;CAE7B,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,YAAY,IAAI,eAAe;CAExE,MAAM,YAAY,KAAK,IAAI,KAAK,OAAO,IAAI,GAAG,KAAK,OAAO,EAAG,CAAC;CAE9D,KAAK,MAAM,EAAE,OAAO,OAAO,WAAW,QAAQ;EAC5C,OAAO,KAAK,SAAS;EAErB,MAAM,aAAa,OAAO,cAAc;EACxC,IAAI,aAAa,KAAK,CAAC,YAAY,CAAC,OAAO;EAC3C,MAAM,KACJ,GAAG,WAAW,OAAO,OAAO,YAAY;GACtC;GACA;GACA;GACA,GAAG;GACH,GAAI,MAAM,QAAQ,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;EAC9C,CAAC,CACH;CACF;CAKA,MAAM,eAAuB,CAAC;CAC9B,MAAM,UAAU,cAAc,KAAA,IAAY,IAAI,iBAAiB,SAAS;CAExE,MAAM,WAAW,QAAQ,SAAS,WAChC,OAAO,SACH,CACE;EACE;EACA,UAAU,OAAO;EACjB,QAAQ,OAAO,OAAO,UAAU,OAAO,OAAO;EAC9C,QAAQ,OAAO;CACjB,CACF,IACA,CAAC,CACP;CACA,MAAM,WACJ,YACC,SAAS,UAAU,MAAM,IAAI,UAAU,QAAQ,UAAU,MAAM,IAAI,KAAK,IAAI,KAAA;CAE/E,IAAI,UAAU,KAAK,UACjB,KAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,EAAE,MAAM,aAAa;EAC3B,IAAI,CAAC,MAAM;EAEX,IAAI,OAAO,cAAc,GAAG;GAC1B,SAAS,IAAI;GACb;EACF;EAGA,MAAM,QAAQ,CAAC,GAAG,QAAQ,KAAK,EAAE,WAAW,IAAI,GAAG,GAAG,UAAU,KAAK,EAAE,WAAW,IAAI,CAAC;EACvF,MAAM,cAAc,QAAQ,MAAM,MAAM,SAAS,KAAK,MAAM,KAAK,QAAQ,CAAC;EAE1E,aAAa,KACX,GAAG,WAAW,MAAM,UAAU,aAAa;GACzC,QAAQ;GACR;GACA,GAAG;GACH,GAAI,YAAY,EAAE,SAAS,SAAS;GACpC,KAAK;GACL,GAAI,WAAW,KAAA,KAAa,EAAE,OAAO;GACrC,UAAU,YAAY,OAAO;EAC/B,CAAC,CACH;CACF;CAEF,MAAM,mBAAmB;EACvB,MAAM,EAAE,QAAQ,WAAW;EAC3B,MAAM,SAAS,QAAQ,MAAM;EAC7B,MAAM,MAAM,YACV,UACA,OAAO,QACP,OAAO,QACP,SACA,MACA,QAAQ,WAAW;GAAE,SAAS,OAAO;GAAS,QAAQ,OAAQ;EAAO,CACvE;EACA,MAAM,MACJ,UACA,UACA,MAAM,OAAO,MAAM,OAAO,OAAO,OAAO,OAAO,OAAO,MAAM,GAAG,OAAO,IAAI,KAAK;EAEjF,OAAO,aACL,SACA,QACA,QACA,MACA,MACA,KACA,YACA;GAAE,GAAG;GAAuB,GAAG;EAAc,GAC7C,aACA,cACA,UACA;GAAE,QAAQ,IAAI;GAAQ,SAAS,IAAI;GAAS,GAAI,OAAO,EAAE,IAAI;EAAG,CAClE;CACF;CAGA,MAAM,SAAiB,CAAC;CAExB,IAAI,UAAU,KAAK,UACjB,KAAK,MAAM,EAAE,UAAU,SAAS;EAC9B,MAAM,QAAQ,QAAQ,UAAU,MAAM;GAAE;GAAM,GAAG;EAAS,CAAC;EAC3D,IAAI,OAAO,OAAO,KAAK,KAAK;CAC9B;CAGF,MAAM,eAAe,eAAe,UAAU,WAAW,IAAI,KAAA;CAE7D,aAAa,KAAK,GAAI,cAAc,SAAS,CAAC,GAAI,GAAG,MAAM;CAE3D,MAAM,cAA4B,CAAC;CAGnC,MAAM,UAAU,UAAU,SAAS,EAAE,UAAU,CAAC,QAC9C,QAAQ,KAAK,EAAE,aAAa;EAAE;EAAO,SAAS,MAAM,QAAQ;CAAE,EAAE,CAClE;CAEA,MAAM,cAAc,QACjB,SAAS,EAAE,cAAc,OAAO,CAAC,CACjC,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CACnC,KAAK,EAAE,aAAa,MAAM;CAG7B,IAAI,MAAM;EACR,MAAM,QAAQ,YAAY,eAAe,CAAC;EAC1C,MAAM,WAAW,oBAAoB,KAAK,KAAK,OAAO,MAAM,GAAG,EAAE,WAAW,IAAI,OAAO;EAEvF,KAAK,OAAO,OAAO,MAAM,WAAW;GAAE,GAAG;GAAa;EAAS,CAAC;CAClE;CAEA,MAAM,cAAc,OAAO,KAAK,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,MAAM,IAAI,CAAC;CACzE,MAAM,MAAM;EAAC,GAAG;EAAS,GAAG;EAAa,GAAG;CAAW;CACvD,MAAM,cAAc;EAAE;EAAQ;EAAQ;EAAM;EAAO,SAAS;CAAO;CACnE,MAAM,UAAU,IAAI,KAAK,WAAW,QAAQ,QAAQ,aAAa,UAAU,CAAC;CAC5E,MAAM,QAAQ,QAAQ,MAAM,GAAG,QAAQ,MAAM;CAC7C,MAAM,SAAS,IAAI,IAAI,YAAY,KAAK,QAAQ,OAAO,CAAC,QAAQ,QAAQ,QAAQ,SAAS,GAAG,CAAC,CAAC;CAE9F,KAAK,MAAM,EAAE,OAAO,SAAS,YAAY,SACvC,MAAM,OAAO,OAAO,KAAK,EAAE,aAAa,OAAO,IAAI,MAAM,CAAC,CAAC;CAE7D,MAAM,OAAO,QAAQ,MAAM,QAAQ,SAAS,YAAY,MAAM,CAAC;CAG/D,MAAM,SAAS,IACZ,KAAK,QAAQ,QAAQ;EAAE;EAAQ;CAAG,EAAE,CAAC,CACrC,QACE,EAAE,QAAQ,SACT,OAAO,SAAS,wBAAwB,QAAQ,GAAG,EAAE,QAAQ,YAAY,MAC7E,CAAC,CACA,MAAM,GAAG,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,QAAQ,EAAE,KAAK,EAAE,EAAE;CAE9D,KAAK,MAAM,EAAE,YAAY,QACvB,cAAc,OAAO,UAAU,MAAM,OAAO,SAAS,aAAa,aAAa,OAAO,OAAO;CAG/F,MAAM,YACJ,SAAS,MAAM,cAAc,IACzB,MAAM,MAAM,MAAM,OAAO,OAAO,MAAM,OAAO,GAAG,GAAGC,OAAK,IACxD,KAAA;CAIN,IAAI,MAAM,UAAU,CAAC,aAAa,YAAY,IAAI,mBAAmB;CAErE,MAAM,QAAQ,UAAU,WAAW;CAEnC,IAAI,aAAa;EACf,MAAM,OAAO,SAAS,QAAQ,QAAQ,MAAM,UAAU;EACtD,KAAK,MAAM,QAAQ,OAAO,KAAK,KAAK,WAAW,MAAM,KAAK;CAC5D;CAIA,IAAI,SAAS,UAAU,CAAC,aAAa,YAAY,IAAI,cAAc;CAEnE,MAAM,gBAAgB,cAClB,aACE,UACA,aACA;EACE;EACA;EACA;EACA,GAAI,iBAAiB,EAAE,QAAQ,cAAc;EAC7C,GAAI,iBAAiB,EAAE,QAAQ,cAAc;CAC/C,GACA,SACF,IACA,CAAC;CACL,MAAM,YAAY,eAAe,SAAS,OAAO,aAAa,SAAS;CAGvE,MAAM,OAAO,SAAS,MAAM,MAAM,SAAS,IAAI,MAAM,MAAM,SAAS,KAAA;CACpE,MAAM,SAAS,SAAS,KAAK,WAAW,SAAS,KAAK,IAAI,KAAK,KAAK,KAAK,IAAI;CAE7E,OAAO;EACL,YAAY,SAAS,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,QAAS,cAAc;EAChE,OAAO,QAAQ,KAAK;EACpB;EACA,YAAY,iBAAiB,QAAQ,MAAM;EAE3C,SAAS,cAAc,OAAO;EAC9B,QAAQ,CAAC;EACT;EACA,SAAS;EACT,GAAI,aAAa,EAAE,UAAU;EAE7B,iBAAiB;EACjB,aAAa;EACb;EACA,GAAI,cAAc,UAAU,EAAE,UAAU,cAAc;EACtD,GAAI,aAAa,EAAE,OAAO,UAAU;EACpC,GAAI,MAAM,UAAU,SAAS,EAAE,aAAa,CAAC;GAAE,SAAS,MAAM;GAAS;EAAM,CAAC,EAAE;EAChF,GAAI,gBAAgB,OAAO,YAAY,EAAE,YAAY,KAAK;EAC1D,GAAI,aAAa,UAAU,EAAE,aAAa;EAC1C,GAAI,cAAc,MAAM,UAAU,EAAE,OAAO,aAAa,MAAM;EAC9D,aAAa,CAAC,GAAG,WAAW;EAC5B,cAAc,CAAC,GAAG,YAAY;CAChC;AACF;;;;;;;;;;AAWA,MAAM,gBACJ,EAAE,SACF,OACA,QACA,MACA,MACA,KACA,YACA,EAAE,MAAM,KAAK,YAAY,mBACzB,aACA,cACA,QACA,QACqC;CACrC,MAAM,SAAS;EAAE,GAAG;EAAO;EAAM;CAAI;CACrC,MAAM,aAAa,iBAAiB,QAAQ,MAAM;CAClD,MAAM,QAAgB,CAAC;CACvB,MAAM,SAA+B,aAAa,CAAC,IAAI,KAAA;CAEvD,aAAa,OAAO,QAAQ,QAAQ,MAAM,MAAM,OAAO,QAAQ,aAAa,cAAc,MAAM;CAEhG,MAAM,QAAgB,CAAC;CACvB,IAAI,QAAQ,YAAY,QAAQ,KAAK;CAGrC,MAAM,WAAW,UAAsB;EACrC,GAAG;EACH,QAAQ,IAAI;EACZ,cAAc,KAAK,gBAAgB,IAAI;EACvC,GAAI,IAAI,OAAO,EAAE,KAAK,IAAI,IAAI;EAC9B,GAAI,KAAK,cAAc,UAAU,EAAE,WAAW,SAAkB;CAClE;CAEA,OAAO;EACL,OAAO,MAAM,KAAK,UAAU;GAAE,GAAG,QAAQ,IAAI;GAAG;GAAY;EAAW,EAAE;EACzE,OAAO,MAAM,KAAK,UAAU;GAC1B,GAAG,QAAQ,IAAI;GACf,YAAY;GACZ,GAAI,CAAC,OAAO,EAAE,WAAW;EAC3B,EAAE;CACJ;AACF;;;;;;;;;;AAWA,MAAM,oBACJ,EAAE,MAAM,QAAQ,SAAS,cACzB,QACA,QACA,MACA,SACA,EACE,YACA,QACA,aACA,KACA,YACA,SACA,oBAUa;CACf,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,QAAgB,QAAQ,MAAM,KAAK,CAAC;CAC1C,MAAM,SAAmB,CAAC;CAC1B,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,QAAQ,MAAM;CACpB,MAAM,SAAS,CAAC,KAAK,OAAO,IAAI,KAAK,YAAY,CAAC,EAAA,CAAG,IAAI,SAAS,KAAK,KAAK,CAAC,CAAC;CAE9E,KAAK,MAAM,SAAS,QAClB,aACE,OACA,QACA,QACA,MACA,MACA,OACA,QACA,aACA,cACA,MACF;CAEF,YAAY,QAAQ,KAAK;CAIzB,MAAM,QAAQ,QAAQ;CACtB,MAAM,cAAc,cAAc,OAAO;CAEzC,KAAK,IAAI,QAAQ,OAAO,QAAQ,MAAM,QAAQ,SAAS;EACrD,MAAM,OAAO,MAAM;EAEnB,MAAM,SAAS;GACb,GAAG;GACH,QAAQ,QAAQ,CAAC,KAAK,IAAI,CAAC;GAC3B,cAAc,KAAK,gBAAgB;GACnC,GAAI,KAAK,cAAc,UAAU,EAAE,WAAW,SAAkB;EAClE;CACF;CAGA,MAAM,QAAQ,QAAQ,KAAK,WAAmC;EAC5D,IAAI,CAAC,oBAAoB,SAAS,OAAO,IAAI,GAAG,OAAO;GAAE,MAAM;GAAQ,KAAK;EAAE;EAC9E,IAAI,CAAC,OAAO,UAAU,OAAO,KAAA;EAE7B,MAAM,SAAS;GAAE,GAAG;GAAQ,UAAU,OAAO;EAAS;EAEtD,OAAO,WAAW,QAAQ;GAAE;GAAQ;GAAQ;GAAM,SAAS,CAAC;EAAE,GAAG,UAAU;CAC7E,CAAC;CAED,MAAM,cAA4B,CAAC;CAEnC,KAAK,MAAM,QAAQ,qBACjB,QAAQ,SAAS,QAAQ,OAAO;EAC9B,IAAI,OAAO,SAAS,SAAS,MAAM,GAAG,EAAE,QAAQ,YAAY,QAAQ;EACpE,cAAc,OAAO,UAAU,MAAM,OAAO,SAAS,aAAa,aAAa,OAAO,OAAO;CAC/F,CAAC;CAGH,MAAM,eACJ,WACA,aACE,SACA,QACA,QACA,MACA,MACA,KACA,YACA,eACA,aACA,cACA,QACA;EAAE,QAAQ,CAAC;EAAG,SAAS;CAAY,CACrC;CAEF,OAAO;EACL,YAAY;GAAE,GAAG,WAAW,IAAI;GAAK,GAAG,WAAW,IAAI;GAAK,GAAG,WAAW,IAAI;EAAI;EAClF,OAAO,QAAQ,KAAK;EACpB;EACA,YAAY,iBAAiB,QAAQ,MAAM;EAC3C,SAAS;EACT,QAAQ,CAAC;EACT;EACA,SAAS;EACT,iBAAiB;EACjB,aAAa;EACb,eAAe,CAAC;EAChB,GAAI,gBAAgB,OAAO,YAAY,EAAE,YAAY,KAAK;EAC1D,GAAI,cAAc,MAAM,UAAU,EAAE,cAAc,aAAa,MAAM;EACrE,GAAI,cAAc,MAAM,UAAU,EAAE,OAAO,aAAa,MAAM;EAC9D,aAAa,CAAC,GAAG,WAAW;EAC5B,cAAc,CAAC,GAAG,YAAY;CAChC;AACF;;;;;;;ACvnDA,MAAMC,OAAI,KAAK;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC1C,MAAM,UAAUD,KAAE,UAAW;;AAiB7B,IAAa,aAAb,MAAa,WAAW;CACtB;CACA;CACA;CACA;;CAEA;CACA;;CAEA,QAAiB,QAAQ;;CAEzB;CACA;CAEA,YACE,OACA,UACA,UACA,UACA,MACA,OACA;EACA,KAAK,QAAQ;EACb,KAAK,WAAW;EAChB,KAAK,WAAW;EAChB,KAAK,WAAW;EAChB,KAAK,OAAO;EACZ,KAAK,QAAQ;EACb,KAAK,YAAY;EACjB,KAAK,YAAY;CACnB;;;;;CAMA,OAAO,UAAU,OAAmB,QAA6B;EAC/D,MAAM,CAAC,OAAO,UAAU,MAAM,aAAa,CAAC;EAE5C,MAAM,OAAO,YACX,YAAY,KAAA,IAAY,KAAKA,KAAE,KAAK,IAAIA,KAAE,OAAO,IAAI,OAAO,CAAC;EAE/D,OAAO,IAAI,WACT,MAAM,OACN,MAAM,UACNA,KAAE,MAAM,QAAQ,GAChBA,KAAE,MAAM,QAAQ,GAChB;GAAE,OAAO,IAAI,KAAK;GAAG,OAAO,IAAI,MAAM;EAAE,GACxC,IAAI,WAAW,OAAO,MAAM,CAC9B;CACF;;CAGA,OAAO,MAAM,EAAE,OAAO,OAAO,KAAK,OAAO,YAA2B,QAA4B;EAC9F,MAAM,QAAQ,OAAO;EACrB,MAAM,SAASA,MAAG,QAAQ,KAAKA,KAAE,GAAG,IAAIA,KAAE,QAAQ,CAAC;EACnD,MAAM,OAAO,SAAS,IAAIA,KAAEA,KAAE,GAAG,IAAI,MAAM,IAAI;EAE/C,OAAO,OAAO,KAAK,OAAO,UAAU;GAClC,MAAM,QAAQ,IAAI,WAChB,OACAC,SACAD,KAAEA,KAAE,KAAK,IAAI,GAAI,GACjBA,KAAE,KAAK,GACP;IAAE,OAAO;IAAG,OAAO;GAAE,GACrB,WAAW,MAAM,QAAQ,EAAE,QAAQ,OAAO,KAAK,CACjD;GAEA,MAAM,QAAQ;GACd,OAAO;EACT,CAAC;CACH;;CAGA,OAAO,MAAoB;EACzB,KAAK,MAAM,KAAK,IAAI;EAEpB,MAAM,QAAQ,KAAK,MAAM;EACzB,MAAM,EAAE,OAAO,aAAa;EAE5B,KAAK,YAAY;GAAE,GAAGA,KAAE,QAAQ,MAAM,CAAC;GAAG,GAAGA,KAAE,QAAQ,MAAM,CAAC;GAAG,GAAGA,KAAE,QAAQ,MAAM,CAAC;EAAE;EACvF,KAAK,YAAY;GACf,GAAGA,KAAEA,KAAE,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,SAAS,CAAC;GACjD,GAAGA,KAAEA,KAAE,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,SAAS,CAAC;GACjD,GAAGA,KAAEA,KAAE,MAAM,IAAI,SAAS,CAAC,IAAI,QAAQ,SAAS,CAAC;EACnD;CACF;AACF;AAGA,MAAM,iBAAiB,EAAE,GAAG,GAAG,QAA0B;CACvD,MAAM,QAAQ,YAAYA,KAAE,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;CAElD,OAAO;EAAE,GAAGA,KAAE,QAAQ,CAAC;EAAG,GAAGA,KAAE,QAAQ,CAAC;EAAG,GAAGA,KAAE,QAAQ,CAAC;CAAE;AAC7D;;AAGA,MAAa,aAAa,OAAmB,QAAyB;CACpE,MAAM,EAAE,OAAO,UAAU,MAAM;CAC/B,IAAI,EAAE,QAAQ,QAAQ,OAAO;CAE7B,MAAM,EAAE,GAAG,MAAM,GAAG,aAAa,MAAM;CACvC,MAAM,MAAM,cAAc;EACxB,GAAGA,KAAE,SAAS,IAAI,IAAI,CAAC;EACvB,GAAGA,KAAE,SAAS,IAAI,IAAI,CAAC;EACvB,GAAGA,KAAE,SAAS,IAAI,IAAI,CAAC;CACzB,CAAC;CACD,MAAM,OAAO,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK;CAC5D,IAAI,OAAO,OAAO,OAAO;CAEzB,MAAM,MAAMA,KAAE,IAAI;CAElB,OAAO,MAAM,SAAS,MAAM,UAAU,QAAQ,SAAS;AACzD;AAGA,MAAM,eAAe,EAAE,GAAG,GAAG,QAA2B;CACtD,MAAM,OAAO;CAEb,OAAO;EAAC,KAAK,CAAC;EAAG,KAAK,CAAC;EAAG,KAAK,CAAC;EAAG;CAAG;AACxC;AAGA,MAAME,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AAEf,MAAMC,UAAQ;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAC/B,MAAM,MAAM;CACV,CAAC,GAAG,CAAC;CACL,CAAC,GAAG,CAAC;CACL,CAAC,GAAG,CAAC;CACL,CAAC,GAAG,CAAC;AACP;AAQA,MAAM,WAAW,EAAE,GAAG,GAAG,QAAiB,MAAM,KAAK,MAAM,KAAK,MAAM;AAGtE,MAAM,YAAY,MAAc,QAAiB,OAAgB,IAAa,YAAqB;CACjG,MAAM,QAAQ,OAAO,SAASA,QAAM;CACpC,MAAM,WAAW,IAAI,WAAW,QAAQD,QAAM;CAC9C,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;CAE/C,OAAO,SAAS,EAAE,QAAQ,GAAG,MAAM,SAAS,UAAU;EACpD,MAAM,IAAI;GAAE,GAAGH,KAAE,MAAM,IAAI,IAAI;GAAG,GAAGA,KAAE,MAAM,IAAI,IAAI;GAAG,GAAGA,KAAE,MAAM,IAAI,IAAI;EAAE;EAC7E,MAAM,IAAI;GAAE,GAAGA,KAAE,GAAG,IAAI,IAAI;GAAG,GAAGA,KAAE,GAAG,IAAI,IAAI;GAAG,GAAGA,KAAE,GAAG,IAAI,IAAI;EAAE;EACpE,MAAM,OAAO;GAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;GAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;GAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EAAE;EACjE,MAAM,OAAO;GAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;GAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;GAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;EAAE;EACjE,MAAM,UAAU;GACd;IAACA,KAAE,KAAK,IAAI,EAAE,CAAC;IAAGA,KAAE,KAAK,IAAI,EAAE,CAAC;IAAGA,KAAE,KAAK,IAAI,EAAE,CAAC;GAAC;GAClD;IAACA,KAAE,EAAE,IAAI,KAAK,CAAC;IAAGA,KAAE,EAAE,IAAI,KAAK,CAAC;IAAGA,KAAE,EAAE,IAAI,KAAK,CAAC;GAAC;GAClD;IAACA,KAAE,KAAK,IAAI,EAAE,CAAC;IAAGA,KAAE,KAAK,IAAI,EAAE,CAAC;IAAGA,KAAE,KAAK,IAAI,EAAE,CAAC;GAAC;GAClD;IAACA,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAAGA,KAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAAGA,KAAE,KAAK,IAAI,EAAE,CAAC;GAAC;EAC1D;EACA,MAAM,QAAQ,YAAY,KAAK;EAE/B,QAAM,SAAS,QAAQ,OAAO;GAC5B,MAAM,UAAU,QAAQI,QAAM,SAAS,MAAMD;GAE7C,OAAO,IAAI,QAAQ,SAAU,SAAS,CAAC;GACvC,SAAS,IAAI,OAAO,SAAS,EAAE;GAC/B,OAAO,IAAI,IAAI,UAAW,SAAS,MAAM,CAAC;EAC5C,CAAC;CACH,CAAC;CAmDD,OAAO;EArCL,MAAA;GAXA;GACA,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IAAE,YAAY;IAAG,aAAa;IAAG,WAAW,QAAQ;IAAG,cAAc;IAAO,SAAS;GAAE,CACzF;GACA,SAAS,YAAY,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OAAO,EAAE;GAC1D;EAGG;EACH,WAAW;GACT,QAAQ;GACR,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAKD;IAAO,KAAKA;GAAM;GACtC,gBAAgB;IAAE,QAAQA;IAAO,QAAQ;GAAE;EAC7C;EACA,WAAW;EACX,YAAY;EACZ;EACA,OAAO,QAAQ;EACf,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EACP,SAAS;GAAE;GAAM,OAAO;GAAS,SAAS;GAAiB,OAAO;EAAE;EACpE,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW;EACX,OAAO;EAEP,gBAAgB;EAChB,eAAe;CAGP;AACZ;;AASA,MAAa,sBAAsB;;;;;AAMnC,MAAa,mBACX,QACA,QACA,EAAE,OAAO,WACE;CACX,IAAI,OAAO,WAAW,GAAG,OAAO,CAAC;CAEjC,MAAM,EAAE,GAAG,OAAO,GAAG,OAAO,QAAQ,wBAAwB,OAAO,WAAW;CAC9E,MAAM,UAAU,UAAsB,MAAM,MAAM;CAClD,MAAM,QAAiB,CAAC;CACxB,MAAM,QAAiB,CAAC;CAExB,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,CAAC,QAAQ,MAAM,SAAS,GAAG;GAC7B,MAAM,QAAQD,KAAE,UAAU,OAAO,OAAO,QAAQ,CAAC;GACjD,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;GAE1B,MAAM,KAAK;IACT,QAAQ,OAAO,KAAK;IACpB,MAAM,MAAM;IACZ,OAAO;KAAE,GAAGA,KAAE,IAAI,KAAK;KAAG,GAAGA,KAAE,IAAI,KAAK;KAAG,GAAGA,KAAE,IAAI,KAAK;IAAE;GAC7D,CAAC;EACH;EAEA,IAAI,CAAC,QAAQ,MAAM,SAAS,GAC1B,MAAM,KAAK;GAAE,QAAQ,OAAO,KAAK;GAAG,MAAM,MAAM;GAAU,OAAO,MAAM;EAAU,CAAC;CACtF;CAEA,OAAO,CACL,GAAI,MAAM,SAAS,CAAC,SAAS,SAAS,OAAO,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,GACnE,GAAI,MAAM,SAAS,CAAC,SAAS,QAAQ,OAAO,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,CACnE;AACF;;;;;;;AC5PA,MAAa,uBAA+C;CAC1D,SAAS;CACT,SAAS;CACT,MAAM;CACN,QAAQ;CACR,WAAW;CACX,UAAU;CACV,WAAW;CACX,WAAW;CACX,YAAY;AACd;AAQA,MAAMK,OAAI,KAAK;;;;;AAMf,MAAa,cACX,EAAE,QAAQ,OAAO,OAAO,UACxB,OACA,SAAuB,yBACkB;CACzC,MAAM,EAAE,GAAG,MAAM,GAAG,aAAa;CACjC,IAAI,IAAI,SAAS;CACjB,IAAI,IAAI,SAAS;CACjB,IAAI,IAAI,SAAS;CAEjB,IAAI;CAEJ,IAAI,UAAU,QAAQ;EACpB,MAAM,EAAE,KAAK,QAAQ;EAErB,UAAU;GAAC,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,IAAI;GAAG,IAAI;EAAC;CACrD,OAAO;EACL,MAAM,EAAE,SAAS,SAAS,MAAM,WAAW;EAE3C,UAAU;GAACA,KAAE,OAAO;GAAGA,KAAE,CAAC,OAAO;GAAG;GAAGA,KAAE,IAAI;GAAGA,KAAE,OAAO;GAAGA,KAAE,CAAC,OAAO;EAAC;EACvE,IAAIA,KAAEA,KAAEA,KAAE,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC;EAC/B,IAAIA,KAAEA,KAAEA,KAAE,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC;EAC/B,IAAIA,KAAEA,KAAEA,KAAE,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC;CACjC;CAGA,MAAM,SAAS,SAASA,KAAE,KAAK,IAAIA,KAAE,QAAQ,QAAQ,EAAG;CACxD,IAAI,OAAO,IAAI;CACf,IAAI,OAAO,GAAG,OAAO;CAErB,MAAM,QAAQA,KAAE,OAAO,SAAS;CAChC,IAAI,OAAO,OAAO,OAAO,EAAE,MAAM;CACjC,QAAQ;CACR,IAAI,QAAQ,QAAQA,KAAE,OAAO,OAAOA,KAAE,OAAO,QAAQ,IAAI,OAAO,SAAS;CAEzE,IAAI,QAAQA,KAAE,OAAO,UAAU;CAE/B,IAAI,QAAQ;EACV,QAAQA,KAAE,OAAO,SAAS,IAAI;EAC9B,IAAI,QAAQ,GAAG,OAAO,EAAE,MAAM;EAC9B,IAAI,QAAQ,GAAG,QAAQ;CACzB;CAEA,IAAI,EAAE,QAAQ,IAAI,OAAO,EAAE,MAAM;CAIjC,MAAM,QAAQ,KAAK,MAAM,KAAK,GAAG,KAAK,CAAC;CACvC,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI;CAC9B,MAAM,MAAM,KAAK,IAAI,KAAK,IAAI;CAE9B,MAAM,SAAS,QAAQ,KAAM,QAAQ;CACrC,MAAM,SAASA,KAAE,QAAQ,KAAM,QAAQ,EAAG;CAC1C,MAAM,UAAUA,KAAE,KAAM,SAAS,QAAQ,KAAM,CAAC;CAChD,MAAM,UAAUA,KAAE,SAAS,KAAM,QAAQ,KAAM,CAAC;CAChD,MAAM,KAAKA,KAAE,SAAS,GAAG;CACzB,MAAM,KAAKA,KAAE,SAAS,GAAG;CACzB,MAAM,KAAKA,KAAE,SAAS,GAAG;CACzB,MAAM,KAAKA,KAAE,SAAS,GAAG;CACzB,MAAM,OAAOA,KAAE,UAAU,EAAE;CAC3B,MAAM,OAAO,UAAU;CAEvB,OAAO;EACL;EACA,MAAM;GACJ,OAAO,KAAK,MAAM,QAAQ,QAAQ,GAAG;GACrC,SAAS;IACP;KAACA,KAAE,OAAO,EAAE;KAAG;KAAQA,KAAE,KAAK,KAAK,OAAO;KAAG;KAAG;IAAC;IACjD;KAACA,KAAE,OAAO,EAAE;KAAG;KAAQA,KAAE,KAAK,UAAU,EAAE;KAAG;KAAG;IAAC;IACjD;KAACA,KAAE,KAAK,UAAU,EAAE;KAAG;KAAQA,KAAE,OAAO,EAAE;KAAG;KAAG;IAAC;IACjD;KAACA,KAAE,KAAK,KAAK,OAAO;KAAG;KAAQA,KAAEA,KAAE,IAAI,IAAI,EAAE;KAAG;KAAG;IAAC;GACtD;EACF;CACF;AACF;AAGA,MAAMC,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAE1C,MAAM,QAAQ;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;;;;;;AAO/B,MAAa,cAAc,EAAE,SAAS,SAAqB,SAAkB,QAAoB;CAC/F,MAAM,WAAW,IAAI,WAAW,MAAM,SAASD,QAAM;CACrD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;CAE/C,MAAM,SAAS,QAAQ,OAAO;EAC5B,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,KAAK,QAAQ;EAEhC,OAAO,IAAI;GAAC;GAAG;GAAG;EAAC,GAAI,KAAKA,WAAU,CAAC;EACvC,SAAS,IAAI;GAAC;GAAK;GAAK;GAAK;EAAK,GAAG,KAAKA,WAAS,EAAE;EACrD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,KAAKA,WAAS,MAAM,CAAC;CAC3C,CAAC;CAED,MAAM,QAAQ,MAAM;CAapB,OAAO;EACL,MAAA;GAZA,MAAM;GACN,SAAS;GACT,WAAW,UAAU;GACrB,QAAQD;GACR,QAAQ,CACN;IAAE,YAAY;IAAG,aAAa;IAAG,WAAW,QAAQ;IAAG,cAAc;IAAO,SAAS;GAAE,CACzF;GACA,SAAS,YAAY,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OAAO,EAAE;GAC1D;EAIG;EACH,WAAW;GACT,QAAQ;GACR,aAAa;GACb,aAAa;GACb,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,YAAY;GACZ,aAAa;IAAE,KAAKE;IAAO,KAAKA;GAAM;GACtC,gBAAgB;IAAE,QAAQA;IAAO,QAAQ;GAAE;EAC7C;EACA,WAAW;EACX,YAAY;EACZ;EACA,OAAO,QAAQ;EACf,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EACP,SAAS;GAAE,MAAM;GAAa,OAAO;GAAS,SAAS;GAAiB,OAAO;EAAE;EACjF,MAAM;EACN,YAAY;EACZ,WAAW;EACX,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW;EACX,OAAO;EACP,gBAAgB;EAChB,eAAe;EACf,GAAI,OAAO,EAAE,IAAI;CACnB;AACF;;;ACtFA,MAAa,yBAAyB;AAEtC,MAAMC,OAAI,KAAK;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAK,GAAG;CAAK,GAAG;AAAI;AAChD,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;;;;;AAO1C,MAAa,cAAc,OAAmB,aAA0C;CACtF,IAAI,CAAC,MAAM,UAAU,OAAO;CAE5B,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,UAAU,QAAQ;CACxB,IAAI,YAAY,GAAG,OAAO,KAAA;CAG1B,MAAM,KAAKF,KAAE,SAAS,IAAI,MAAM,SAAS,CAAC;CAC1C,MAAM,KAAKA,KAAE,SAAS,IAAI,MAAM,SAAS,CAAC;CAC1C,MAAM,SAAS,SAAS,IAAI,MAAM,SAAS;CAC3C,MAAM,KAAKA,KAAE,MAAM;CACnB,MAAM,SAAS,SAAS,KAAK,KAAK,KAAK,KAAK;CAC5C,IAAI,OAAO;CAEX,IAAI,MAAM,QAAQ,EAAE,SAAS,OAAO;EAClC,MAAM,EAAE,GAAG,GAAG,MAAM,MAAM;EAC1B,MAAM,OAAO,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM;EACzD,IAAI,EAAE,MAAM,KAAK,IAAIA,KAAE,MAAM,KAAK,GAAG,IAAI,EAAG,IAAI,OAAOA,KAAE,GAAG;CAC9D;CAEA,OAAOA,KAAE,OAAO,SAAS,OAAO;AAClC;;;;;AAMA,MAAa,kBACX,QACA,UACA,UACiB;CACjB,MAAM,SAAgD,CAAC;CAEvD,KAAK,MAAM,SAAS,QAAQ;EAC1B,IAAI,MAAM,UAAU,OAAO;EAE3B,MAAM,QAAQ,WAAW,OAAO,QAAQ;EACxC,IAAI,UAAU,KAAA,GAAW;EAEzB,IAAI,OAAO;EAEX,OAAO,OAAO,OAAO,UAAU,QAAQ,OAAO,KAAK,CAAE,OAAO;EAC5D,OAAO,OAAO,MAAM,GAAG;GAAE;GAAO;EAAM,CAAC;CACzC;CAMA,OAAO,OAAO,MAAM,GAAA,CAAyB,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,GAAG,cAAc,KAAK;AACjG;AAKA,MAAM,eAAe,WAClB,KAAK,MAAMA,KAAE,SAAS,IAAI,IAAI,IAAI,MAAM,EAAG,IAAI,OAAQ;AAE1D,MAAM,aAAa,EAAE,GAAG,GAAG,SAA2B;CACpD,GAAG,YAAY,CAAC;CAChB,GAAG,YAAY,CAAC;CAChB,GAAG,YAAY,CAAC;AAClB;;AAGA,MAAa,mBACX,EAAE,QAAQ,UAAUC,SAAO,OAC3B,YAC2D;CAC3D,QACE,OAAO,QAAQ,QAAQ,CAAC,IAAI,eAAe,QAAQ,OAAO,UAAU,OAAO,cAAc,CAAC;CAC5F,SAAS,UAAU,OAAO,YAAY,QAAQC,UAAS,OAAO,WAAW,OAAQ;CACjF,GAAI,OAAO,OAAO,QAAQ,SAAS,EAAE,IAAI;AAC3C;AAGA,MAAM,eAAe,EAAE,QAAQ,QAA6B,SAAS,MAAO;AAE5E,MAAM,YAAY,YAChB,CAAC,GAAG,IAAI,IAAI,QAAQ,IAAI,WAAW,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;AAE7D,MAAa,oBAAoB,UAAgC;CAC/D,MAAM,EAAE,QAAQ,QAAQ,SAAS,YAAY,OAAO,GAAG,UAAU,CAAC,GAAG,QAAQ,YAAY;CACzF,MAAM,eAAe;EAAE,GAAG;EAAsB,GAAG,SAAS;CAAO;CACnE,IAAI,cAAc,SAAS,SAAS;CAEpC,IAAI,YAAY,MAAM;CACtB,MAAM,WAAW;EAAE,GAAG;EAAqB,GAAG;CAAO;CACrD,MAAM,QAAgB,CAAC;CACvB,MAAM,8BAAc,IAAI,IAAY;CACpC,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,OAAO,WAAW,MAAM;CAC9B,MAAM,SAAmB,CAAC;CAC1B,MAAM,SAAS,SAAS,OAAO;CAI/B,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,UAAU,SAAS;EAC5B,IAAI,YAAY,MAAM,MAAM,OAAO;EAEnC,IAAI,WAAW,OAAO,QAAQ;GAC5B,MAAM,EAAE,MAAM,UAAU,WAAW,OAAO,QAAQ,aAAa,YAAY;GAE3E,cAAc;GACd,IAAI,MAAM,MAAM,KAAK,WAAW,MAAM,QAAQ,SAAS,SAAS,CAAC;EACnE;EAEA,MAAM,MAAc,CAAC;EACrB,MAAM,OAAiB,CAAC;EAExB,aACE,OAAO,OACP,QACA,QACA,MACA,MACA,KACA,MACA,aACA,cACA,UACA,OACA,MAAM,QACR;EAEA,MAAM,MAAM,gBAAgB,OAAO,MAAM;EAEzC,YAAY,IAAI;EAEhB,MAAM,SAAS,UAAsB;GACnC,GAAG;GACH,QAAQ,IAAI;GAEZ,cAAc,KAAK,gBAAgB,IAAI;GACvC,GAAI,IAAI,OAAO,EAAE,KAAK,IAAI,IAAI;EAChC;EAEA,MAAM,KAAK,GAAG,IAAI,IAAI,KAAK,CAAC;EAC5B,KAAK,MAAM,SAAS,MAAM,OAAO,KAAK;GAAE,GAAG;GAAO,OAAO,MAAM,MAAM,IAAI,KAAK;EAAE,CAAC;CACnF;CAGF,YAAY,QAAQ,KAAK;CAGzB,MAAM,WAAW,MAAM;CAEvB,IAAI,UAAU;EACZ,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,UAAU,SACnB,IAAI,YAAY,MAAM,MAAM,SAAS,OAAO,aAC1C,MAAM,KACJ,GAAG,gBAAgB,OAAO,YAAY,MAAM,GAAA,EAAsB,GAAG,QAAQ,QAAQ,CACvF;EAEN,IAAI,MAAM,aAAa,MAAM,KAAK,GAAG,gBAAgB,MAAM,aAAa,QAAQ,QAAQ,CAAC;CAC3F;CAIA,MAAM,cAA4B,CAAC;CACnC,MAAM,WAAW,EAAE,UAAU,SAAS,cACpC,cAAc,UAAU,MAAM,SAAS,aAAa,aAAa,OAAO;CAE1E,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,UAAU,SACnB,IAAI,YAAY,MAAM,MAAM,OAAO,OAAO,SAAS,QAAQ,OAAO;CAEtE,QAAQ,QAAQ,OAAO;CAEvB,OAAO;EACL,YAAY,cAAc;EAC1B,OAAO,QAAQ,KAAK;EACpB;EACA,YAAY,iBAAiB,QAAQ,MAAM;EAC3C,SAAS;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAC5B,QAAQ,CAAC;EACT;EACA,SAAS;EACT,aAAa,CAAC,GAAG,WAAW;EAC5B,cAAc,CAAC,GAAG,YAAY;EAC9B;CACF;AACF;;;;;;;;;AClUA,MAAMC,OAAI,KAAK;AA8Cf,MAAa,qBAA2C;CACtD,QAAQ;CACR,iBAAiBA,KAAE,GAAI;CACvB,sBAAsBA,KAAE,IAAK;CAC7B,sBAAsB;CACtB,YAAY;CACZ,iBAAiB;EAAE,MAAM;EAAI,MAAM;CAAG;CACtC,4BAA4B;CAC5B,SAASA,KAAE,EAAG;AAChB;AA2BA,IAAI,cAAc;;;;;;AAalB,MAAa,oBACX,OACA,UACyB;CACzB,IAAI;CACJ,IAAI,QAAQ;CAEZ,KAAK,MAAM,aAAa,OAAO;EAC7B,MAAM,EAAE,WAAW,UAAU;EAC7B,IAAI,EAAE,SAAS,UAAU,CAAC,UAAU,KAAK,MAAM,KAAK,GAAG;EACvD,OAAO;EACP,QAAQ;CACV;CAEA,OAAO;AACT;;AAGA,MAAMC,SAAO,SAAqB;CAChC,KAAK,OAAO;CACZ,KAAK,OAAO,SAAS,QAAQ;AAC/B;AAEA,IAAa,YAAb,MAAuB;;CAErB;;CAEA;CACA;CACA;;CAEA;;CAEA,YAAY;CACZ;CACA,iBAAiB;CACjB;CACA,mBAAmB;;CAEnB,UAAkB,CAAC;;;;;CAMnB,YACE,QACA,OACA,SAA8B,CAAC,GAC/B;EACA,KAAK,SAAS,UAAU;EACxB,KAAK,QAAQ;EACb,KAAK,SAAS;GAAE,GAAG;GAAoB,GAAG;EAAO;EACjD,KAAK,mBACH,WAAW,KAAA,IAAY;GAAE,MAAM;GAAG,MAAM;EAAE,IAAI,EAAE,GAAG,KAAK,OAAO,gBAAgB;CACnF;;CAGA,QAAQ,MAAc,UAAqD;EACzE,MAAM,SAAS,KAAK,MAAM,IAAI;EAC9B,IAAI,CAAC,QAAQ,OAAO,KAAA;EACpB,OAAO;GACL;GACA,WAAW;GACX,QAAQ;GACR,MAAM;GACN,SAAS,WAAW,OAAO,SAAS;GACpC,KAAK;GACL,QAAQ;EACV;CACF;;;;;;CAOA,MAAM,MAA8B;EAClC,IAAI,CAAC,QAAQ,KAAK,MAAM;EACxB,IAAI,CAAC,KAAK,WAAW,OAAOA,MAAI,IAAI;EACpC,KAAK,OAAO,SAAS,KAAK;EAC1B,IAAI,KAAK,UAAU,KAAK,KAAK,UAAU,GAAG,KAAK,UAAU;EACzD,KAAK,MAAM,IAAI;EACf,KAAK,QAAQ,KAAK,IAAI;CACxB;;CAGA,MAAM,MAAkB;EACtB,IAAI,KAAK,UAAU,KAAK,MAAM;EAC9B,KAAK,SAAS;EACd,KAAK,SAAS,EAAE;CAClB;;CAGA,OAAO,MAAY,WAAsB,WAAyB;EAChE,KAAK,YAAY;EACjB,KAAK,YAAY,YAAY,IAAI,IAAI,YAAY,IAAI,IAAI;EACzD,KAAK,MAAM,IAAI;CACjB;CAEA,aAAmB;EACjB,KAAK,MAAM,KAAK,OAAO;EACvB,KAAK,UAAU,KAAA;EACf,KAAK,MAAM,KAAK,KAAK;EACrB,KAAK,QAAQ,KAAA;EACb,KAAK,YAAY;EACjB,KAAK,iBAAiB;EACtB,KAAK,mBAAmB;CAC1B;;CAGA,UAAgB;EACd,KAAK,MAAM,QAAQ;GAAC,KAAK;GAAS,KAAK;GAAO,KAAK;GAAS,GAAG,KAAK;EAAO,GACzE,IAAI,QAAQ,CAAC,KAAK,MAAM,MAAI,IAAI;EAElC,KAAK,UAAU,KAAK,QAAQ,KAAK,UAAU,KAAA;EAC3C,KAAK,UAAU,CAAC;CAClB;;;;;CAMA,MAAM,EAAE,UAAU,eAAkC;EAClD,MAAM,QAAQ,KAAK,OAAO;EAC1B,MAAM,QAAQ;GACZ,GAAGD,KAAEA,KAAE,YAAY,EAAE,IAAI,KAAK,IAAI,SAAS,CAAC;GAC5C,GAAGA,KAAEA,KAAE,YAAY,EAAE,IAAI,KAAK,IAAI,SAAS,CAAC;GAC5C,GAAGA,KAAEA,KAAE,YAAY,EAAE,IAAI,KAAK,IAAI,SAAS,CAAC;EAC9C;EAEA,OAAO;GAAE,OAAO,QAAQ,wBAAwB,aAAa,KAAK;GAAG,UAAU;EAAM;CACvF;;;;;;;;;CAUA,OACE,QACA,MACA,OACA,EAAE,SAAS,GAAG,aAAa,MAAM,aAA0B,CAAC,GACtD;EACN,MAAM,SAAS,KAAK;EAGpB,IAAI,CAAC,eAAe,KAAK,WAAW,KAAK,SAAS,KAAK,UAAU;GAC/D,KAAK,WAAW;GAChB,KAAK,MAAM,KAAK,OAAO;GACvB,KAAK,UAAU,KAAA;EACjB;EAEA,MAAM,YAAY,KAAK,MAAM,MAAM;EACnC,MAAM,QAAQ,UAAU;EAExB,IAAI,SAAS,OAAO,iBAAiB;GACnC,MAAM,QAAQ,iBAAiB,OAAO,KAAK;GAC3C,MAAM,OAAO,OAAO,QAAQ;GAC5B,MAAM,YAAY,QAAQ,MAAM,gBAAgB,OAAO,uBAAuB;GAC9E,MAAM,QAAQ,QAAQA,KAAE,UAAU,MAAM,MAAM,MAAM,gBAAgB,GAAG,KAAK,CAAC,IAAI;GAGjF,IAAI,KAAK,YAAY,MAAM,KAAK,UAAU,YAAY,GAAG;IACvD,KAAK,YAAY;IACjB,KAAK,MAAM,KAAK,OAAO;IACvB,KAAK,UAAU,KAAK;IACpB,KAAK,mBAAmB,KAAK;IAC7B,KAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM,QAAQ,IAAI,KAAA;GACrD;GAEA,KAAK,iBAAiB;GAEtB,IAAI,KAAK,SAAS;IAChB,MAAM,OAAO,KAAK,mBAAmB,OAAO,wBAAwB,IAAI;IAExE,IAAI,EAAE,QAAQ,OAAO,aAAa,KAAK,OAAO,KAAK,SAAS,WAAWA,KAAE,IAAI,CAAC;SACzE;KACH,KAAK,MAAM,KAAK,OAAO;KACvB,KAAK,UAAU,KAAA;IACjB;GACF;GAEA,IAAI,KAAK,OAAO;IACd,MAAM,QAAQ,KAAK,iBAAiB,OAAO,uBAAuB;IAElE,KAAK,OAAO,KAAK,OAAO,WAAWA,KAAE,KAAK,CAAC;GAC7C;EACF,OAAO,KAAK,WAAW;EAEvB,IAAI,KAAK,SAAS;GAChB,MAAM,EAAE,MAAM,SAAS,KAAK;GAC5B,MAAM,UAAU,IAAI,UAAU,OAAO,OAAO,UAAU,OAAO;GAE7D,KAAK,OAAO,KAAK,SAAS,WAAWA,KAAE,KAAK,CAAC;EAC/C,OAAO,IAAI,KAAK,QAAQ,KAAK,UAAU,KAAK,QAAQ,KAAK,QAAQ,QAAQ;EAEzE,KAAK,KAAK,QAAQ,IAAI;CACxB;;CAGA,UAAkB;EAGhB,OAAO;GAFO,KAAK;GAAS,KAAK;GAAO,KAAK;GAAS,GAAG,KAAK;EAEpD,CAAC,CAAC,QAAQ,SAAuB,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,KAAK,IAAI;CAChF;;;;;;CAOA,KAAK,QAAgB,MAAoB;EACvC,MAAM,KAAK,OAAO,KAAK,OAAO,UAAU,KAAK,OAAO,UAAU;EAC9D,MAAM,OAAO,WAAW,MAAM;EAE9B,KAAK,MAAM,QAAQ,KAAK,QAAQ,GAAG;GACjC,IAAI,KAAK,UAAU,GAAG;IACpB,KAAK,UAAUA,KAAE,KAAK,UAAU,EAAE;IAElC,IAAI,KAAK,WAAW,GAAG;KACrB,MAAI,IAAI;KACR;IACF;GACF;GAEA,KAAK,OAAO,SAAS,QAAQ,IAAI;IAC/B,QAAQ,KAAK;IACb,KAAK,KAAK;IACV,GAAI,KAAK,aAAa,EAAE,WAAW,KAAK,UAAU,MAAM;IACxD;GACF,CAAC;GACD,IAAI,KAAK,OAAO,SAAS,UAAU,MAAI,IAAI;EAC7C;EAEA,KAAK,UAAU,KAAK,QAAQ,QAAQ,EAAE,WAAW,CAAC,IAAI;CACxD;;CAGA,UAA0B;EACxB,OAAO,KAAK,QAAQ,CAAC,CAClB,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CACnC,KAAK,UAAU;GACd,QAAQ;IACN,GAAG,KAAK;IACR,GAAI,KAAK,aAAa,EAAE,UAAU,KAAK,UAAU,SAAS;GAC5D;GACA,QAAQ,KAAK;EACf,EAAE;CACN;;;;;CAMA,OAAO,OAAkD;EACvD,KAAK,QAAQ,CAAC,CACX,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CACnC,SAAS,MAAM,OAAO;GACrB,MAAM,OAAO,MAAM;GACnB,IAAI,CAAC,MAAM;GACX,KAAK,MAAM,KAAK;GAChB,IAAI,KAAK,SAAS,OAAO,MAAI,IAAI;EACnC,CAAC;EACH,KAAK,UAAU,KAAK,QAAQ,QAAQ,EAAE,WAAW,CAAC,IAAI;CACxD;AACF;;;;;;;;;ACjWA,MAAME,OAAI,KAAK;AAgEf,MAAM,MAAM,KAAK,IAAI,iBAAkB;AAGvC,MAAMC,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAE1C,MAAMC,cAAY,EAAE,GAAG,GAAG,SAA2B;CACnD,GAAG,IAAI,IAAI,IAAI;CACf,GAAG,IAAI,IAAI,IAAI;CACf,GAAG,IAAI,IAAI,IAAI;AACjB;AAGA,MAAM,WAAW,OAAe,EAAE,GAAG,GAAG,QAA2B;CACjE,KAAK,MAAM,IAAI,GAAG,IAAI;CACtB,KAAK,MAAM,IAAI,GAAG,IAAI;CACtB,KAAK,MAAM,IAAI,GAAG,IAAI;CACtB,KAAK,MAAM,QAAQ,GAAG,IAAI;AAC5B;AAEA,IAAa,qBAAb,MAAgC;CAC9B;CACA;CACA;CACA,SAAiB,CAAC;;CAElB;;CAEA;;CAEA;;CAEA;;CAEA;;CAEA;CACA;CACA;;CAEA,MAAe;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAElC,YACE,UACA,OACA,EACE,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,GAChD,SAAS,MAC+B,CAAC,GAC3C;EACA,KAAK,WAAW;EAChB,KAAK,QAAQ;EACb,KAAK,SAAS;EAGd,MAAM,WAAWJ,MAAG,IAAI,UAAU,MAAO,MAAM;EAC/C,MAAM,SAAS,SAAS;EACxB,MAAM,WAAWA,MAAG,IAAI,UAAU,MAAO,MAAM;EAG/C,MAAM,aAAa,MAAM,cAAc,CAAC;EACxC,IAAI,QAAQ,KAAK,MAAM,SAAS,SAAS,GAAG;EAC5C,IAAI,UAAU;EACd,MAAM,SAAS,WAAW,KAAK,EAAE,qBAC/B,mBAAmB,KAAA,IAAY,KAAA,IAAY,KAAK,MAAM,cAAc,CACtE;EAEA,IAAI,WAAW,QAAQ;GACrB,MAAM,OAAO,KAAK,IAChB,IACA,GAAG,OAAO,KAAK,UAAW,UAAU,KAAA,KAAa,QAAQ,IAAI,QAAQ,EAAG,CAC1E;GACA,MAAM,OAAO,KAAK,IAAI,OAAO,IAAI;GAEjC,UAAUA,KAAE,QAAQ,IAAI;GACxB,QAAQ;EACV;EAEA,KAAK,UAAU;EAEf,MAAM,UAAUA,KAAE,IAAI,KAAK;EAE3B,KAAK,aAAa,OAAO,KAAK,UAC5B,UAAU,KAAA,KAAa,QAAQ,IAAIA,KAAE,QAAQ,OAAO,IAAI,KAC1D;EAEA,MAAM,CAAC,KAAK,QAAQ,SAAS,QAAQ,CAAC,KAAK,GAAG;EAC9C,MAAM,QAAQA,KAAE,OAAO,GAAG;EAC1B,MAAM,YAAY,KAAK,MAAM,QAAQ,QAAQ;EAC7C,MAAM,OAAOA,KAAE,IAAI,SAAS;EAC5B,MAAM,aAAa,OAAO,IAAIK,cAAY;EAE1C,KAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,SAAS;GAC9C,MAAM,OAAOL,MAAG,OAAO,IAAI,QAAQK,cAAY,OAAO,EAAG;GAEzD,KAAK,OAAO,KAAK;IACf,UAAUF;IACV;IACA,OAAO;IACP,SAAS;IACT,OAAO,KAAK;IACZ,OAAO,KAAK;IACZ,MAAM,KAAK;IACX,QAAQ,KAAK;IACb,OAAOH,KAAE,QAAQ,IAAI;GACvB,CAAC;EACH;EAEA,MAAM,QAAQ,SAAS,iBAAiB;EACxC,MAAM,UAAU,KAAK,IAAI,KAAK,IAAI,SAAS,eAAe,IAAK,CAAC,GAAG,CAAC;EAGpE,IAAI,QAAQ,GAAG;GACb,MAAM,IAAI,WAAW;GACrB,MAAM,IAAK,IAAI,OAAQ,IAAI;GAE3B,KAAK,SAASA,KAAE,CAAC;GACjB,KAAK,QAAQA,KAAE,IAAI,CAAC;GACpB,KAAK,OAAOA,KAAE,IAAIA,KAAE,OAAO,CAAC;EAC9B,OAAO;GACL,KAAK,SAAS;GACd,KAAK,QAAQ;GACb,KAAK,OAAO;EACd;EAGA,MAAM,OAAOA,KAAE,KAAK,MAAM,MAAM,YAAY,KAAK,MAAM,eAAe,EAAE;EACxE,MAAM,MAAMA,KAAE,MAAM,WAAW,OAAO,IAAI;EAE1C,KAAK,WAAW,OAAO,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,GAAG;EAGrD,MAAM,QAAQ,SAAS,cAAc;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAExD,KAAK,WAAWI,WAAS;GACvB,GAAGJ,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;GAC9B,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;GAC9B,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;EAChC,CAAC;EACD,KAAK,WAAWI,WAAS,MAAM,OAAO;CACxC;CAEA,IAAI,QAAmC;EACrC,OAAO,KAAK;CACd;;;;;CAMA,KAAK,KAAuB;EAC1B,MAAM,EAAE,SAAS,KAAK;EACtB,MAAM,SAASJ,MAAG,KAAK,QAAQ,KAAK,UAAU,IAAI;EAClD,MAAM,IAAI;GACR,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;GAC5B,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;GAC5B,GAAGA,KAAE,IAAI,IAAI,KAAK,SAAS,CAAC;EAC9B;EACA,MAAM,QAAQ,KAAK,SAAS;EAC5B,MAAM,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;EAChD,IAAI,UAAU,QAAQ,OAAO,OAAO;EAEpC,MAAM,WAAWA,KAAE,KAAK,KAAKA,KAAE,OAAO,CAAC,CAAC;EACxC,MAAM,UAAU,IAAI;EAOpB,OAAO,WANO,KAAK,YAAY;GAC7B,GAAGA,KAAE,EAAE,IAAI,OAAO;GAClB,GAAGA,KAAE,EAAE,IAAI,OAAO;GAClB,GAAGA,KAAE,EAAE,IAAI,OAAO;EACpB,CAEsB,KAAK;CAC7B;;;;;CAMA,UAAU,OAA0B,OAAoD;EACtF,MAAM,aAAa,KAAK,MAAM,cAAc,CAAC;EAC7C,IAAI;EAEJ,KAAK,MAAM,MAAM,OAAO;GACtB,MAAM,YAAY,WAAW;GAC7B,MAAM,SAAS,UAAU,UAAU,MAAM,UAAU,gBAAgB,GAAG,KAAK,MAAM;GAEjF,IAAI,UAAU,mBAAmB;IAC/B,IAAI,QAAQ,OAAO,EAAE,KAAK,KAAK;IAC/B;GACF;GAEA,MAAM,QAAQ,KAAK,WAAW;GAC9B,IAAI,YAAY,KAAA,KAAa,EAAE,UAAU,KAAA,KAAa,QAAQ,IAAI;GAClE,IAAI,QAAQ,UAAU;EACxB;EAEA,OAAO;GAAE,KAAK;GAAO,GAAI,YAAY,KAAA,KAAa,EAAE,QAAQ;EAAG;CACjE;;CAGA,QAAQ,MAAY,OAA+C;EACjE,MAAM,EAAE,MAAM,eAAe,MAAM,KAAK;EACxC,IAAI,UAAU,MAAM,cAAc,KAAK,QAAQ,MAAM,GAAG,OAAO;EAC/D,IAAI,CAAC,OAAO,OAAO;EAEnB,MAAM,EAAE,KAAK,YAAY,KAAK,UAAU,OAAO,KAAK,QAAQ;EAC5D,IAAI,KAAK,OAAO;EAChB,OAAO,EAAE,KAAK,SAAS,YAAY,KAAA,KAAa,UAAU,IAAI,UAAU,KAAK;CAC/E;;;;;;;;CASA,KAAK,QAAgB,UAA6B,MAAM,OAAe;EACrE,MAAM,QAAQ,KAAK,SAAS;EAC5B,MAAM,MAAM,OAAO;EACnB,IAAI,CAAC,KAAK,KAAK,GAAG,GAAG,OAAO,CAAC;EAE7B,MAAM,EAAE,SAAS,OAAO,IAAI,WAAW,KAAK,MAAM,MAAM;EAExD,KAAK,MAAM;EAEX,MAAM,UAAU,KAAK,SAAS,UAAU,SAAS,OAAO,EAAE;EAE1D,IAAI,CAAC,OAAO,OAAO,CAAC;EAEpB,MAAM,gBAAgB,KAAK,SAAS,KAAK;EACzC,MAAM,aAAa,KAAK,MAAM,cAAc,CAAC;EAC7C,MAAM,QAAQ,WAAW,SACrB,WACG,KAAK,WAAW,QAAQ;GAAE;GAAI,KAAK,eAAe,WAAW,GAAG;EAAE,EAAE,CAAC,CACrE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAC7B,KAAK,EAAE,SAAS,EAAE,IACrB,KAAA;EACJ,MAAM,EAAE,WAAW;EAEnB,MAAM,QAAQ,SAAe;GAC3B,MAAM,KAAK,KAAK,SAAS,IAAI,OAAO;GACpC,MAAM,KAAK,KAAK,SAAS,IAAI,OAAO;GACpC,MAAM,KAAK,KAAK,SAAS,IAAI,OAAO;GAEpC,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK;EAClC;EAEA,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI;GAEJ,IAAI,KAAK;IACP,MAAM,SAAS,aAAa,QAAQ,KAAK,MAAM;IAE/C,KAAK,WAAW;KACd,GAAGA,KAAE,OAAO,IAAI,OAAO,CAAC;KACxB,GAAGA,KAAE,OAAO,IAAI,OAAO,CAAC;KACxB,GAAGA,KAAE,OAAO,IAAI,OAAO,CAAC;IAC1B;IACA,KAAK,UAAU,KAAK,QAAQ,MAAM,KAAK;IACvC,IAAI,CAAC,KAAK,SAAS;IACnB,UAAU,KAAK,IAAI;GACrB,OAAO;IACL,UAAU,KAAK,IAAI;IAEnB,IAAI,UAAU,gBAAgB,IAAI;KAEhC,MAAM,KAAK,SAAS,MAAM;KAE1B,KAAK,WAAW;MACd,GAAGA,KAAE,KAAK,SAAS,GAAG,IAAI,OAAO,CAAC;MAClC,GAAGA,KAAE,KAAK,SAAS,GAAG,IAAI,OAAO,CAAC;MAClC,GAAGA,KAAEA,KAAE,KAAK,SAAS,GAAG,CAAC,IAAI,OAAO,CAAC;KACvC;KACA,KAAK,QAAQ;KACb,KAAK,UAAU,KAAK,QAAQ,MAAM,KAAK;KACvC;IACF;GACF;GAEA,IAAI,CAAC,KAAK,SAAS;GAEnB,KAAK,QAAQ,KAAK,MAAM,KAAK,UAAU,SAAS,KAAK,OAAO;EAC9D;EAEA,MAAM,QAAQ,KAAK,OAAO;EAE1B,MAAM,QAAQ,UAAkB;GAC9B,MAAM,WAAW,IAAI,WAAW,MAAM,SAAS,IAAIE,QAAM;GACzD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;GAE/C,MAAM,SAAS,MAAM,OAAO;IAC1B,MAAM,OAAOF,KAAE,KAAK,OAAO,KAAK,IAAI;IACpC,MAAM,IAAI;KAAE,GAAGA,KAAE,MAAM,IAAI,IAAI;KAAG,GAAGA,KAAE,MAAM,IAAI,IAAI;KAAG,GAAGA,KAAE,MAAM,IAAI,IAAI;IAAE;IAC7E,MAAM,IAAI;KAAE,GAAGA,KAAE,GAAG,IAAI,IAAI;KAAG,GAAGA,KAAE,GAAG,IAAI,IAAI;KAAG,GAAGA,KAAE,GAAG,IAAI,IAAI;IAAE;IAEpE,MAAM,SAAS,OAAO,KAAK,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI;IACzD,MAAM,CAAC,IAAI,IAAI,IAAI,MACjB,WAAW,IACP;KAAC;KAAG;KAAG;KAAG;IAAC,IACX,WAAW,IACT;KAAC;KAAG;KAAG;KAAG;IAAC,IACX,WAAW,IACT;KAAC;KAAG;KAAG;KAAG;IAAC,IACX;KAAC;KAAG;KAAG;KAAG;IAAC;IACrB,MAAM,IAAI,KAAK,OAAO,IAAI;IAC1B,IAAI,IAAI,KAAK,OAAO,IAAI;IACxB,IAAI,KAAK,QAAQ,IAAI;KAAE,GAAG,CAAC,EAAE;KAAG,GAAG,CAAC,EAAE;KAAG,GAAG,CAAC,EAAE;IAAE;IAEjD,MAAM,IAAI,KAAK;IAEf,MAAM,OAAO,OAAO,MAAO,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI;IACzD,MAAM,eAAe,QAAQ,QAAQ;IAOrC;KALE;MAAC;OAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;OAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;OAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;MAAE;MAAG,CAAC,IAAK,EAAG;MAAG;KAAY;KAChF;MAAC;OAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;OAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;OAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;MAAE;MAAG,CAAC,IAAK,EAAG;MAAG;KAAY;KAChF;MAAC;OAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;OAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;OAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,CAAC;MAAE;MAAG,CAAC,IAAK,EAAG;MAAG,QAAQ;KAAM;IAG7E,CAAC,CAAC,SAAS,CAAC,UAAU,IAAI,SAAS,MAAM;KAC9C,MAAM,QAAQ,KAAK,IAAI;KAEvB,OAAO,IAAI;MAAC,SAAS;MAAG,SAAS;MAAG,SAAS;KAAC,GAAI,QAAQE,WAAU,CAAC;KACrE,SAAS,IAAI,QAAQ,KAAK,OAAO,MAAM,GAAG,QAAQA,WAAS,EAAE;KAC7D,OAAO,IAAI,KAAK,QAAQA,WAAS,MAAM,CAAC;IAC1C,CAAC;GACH,CAAC;GACD,OAAO;EACT;EAEA,MAAM,SAAS,KAAK,OAAO,QACxB,SAAS,KAAK,WAAW,KAAK,SAAS,KAAK,KAAK,SAASF,KAAE,GAAI,CACnE;EACA,MAAM,QAAQ,KAAK,OAAO,QACvB,SAAS,KAAK,WAAW,KAAK,QAAQ,KAAK,KAAK,QAAQA,KAAE,GAAI,CACjE;EACA,MAAM,QAAgB,CAAC;EAEvB,IAAI,OAAO,QACT,MAAM,KAAK,KAAK,QAAQ,KAAK,MAAM,GAAG,OAAO,SAAS,GAAG,OAAO,OAAO,SAAS,GAAG,CAAC;EAEtF,IAAI,MAAM,QACR,MAAM,KAAK,KAAK,QAAQ,KAAK,KAAK,GAAG,MAAM,SAAS,GAAG,MAAM,OAAO,SAAS,GAAG,CAAC;EAEnF,OAAO;CACT;;;;;CAMA,MAAM,QAAoF;EACxF,MAAM,MAAM,OAAO;EACnB,MAAM,QAAQ,QAAQ,wBAAwB,OAAO,aAAa,GAAG;EACrE,MAAM,OAAO,QAAQ,mBAAmB;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAG,GAAG,KAAK;EACpE,MAAM,UAAU;GAAE,GAAGA,KAAE,KAAK,CAAC;GAAG,GAAGA,KAAE,KAAK,CAAC;GAAG,GAAGA,KAAE,KAAK,CAAC;EAAE;EAC3D,MAAM,SAAS;GACb,GAAGA,KAAE,QAAQ,IAAI,KAAK,QAAQ,IAAI,CAAC;GACnC,GAAGA,KAAE,QAAQ,IAAI,KAAK,QAAQ,IAAI,CAAC;GACnC,GAAGA,KAAE,QAAQ,IAAI,KAAK,QAAQ,IAAI,CAAC;EACrC;EAEA,MAAM,OAAO,KAAK;EAClB,MAAM,KAAK,QAAQ,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK;EACjD,MAAM,KAAK,QAAQ,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK;EACjD,MAAM,KAAKA,KAAE,QAAQ,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,CAAC;EAEpD,MAAM,eAAeA,KAAE,YAAYA,KAAE,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC;EAClE,MAAM,QAAQ;GAAE,GAAGA,KAAE,KAAK,YAAY;GAAG,GAAGA,KAAE,KAAK,YAAY;GAAG,GAAGA,KAAE,KAAK,YAAY;EAAE;EAC1F,MAAM,SAAS;GACb,GAAGA,KAAE,MAAM,IAAI,QAAQ,IAAI,MAAM,IAAI,QAAQ,CAAC;GAC9C,GAAGA,KAAE,MAAM,IAAI,QAAQ,IAAI,QAAQ,IAAI,MAAM,CAAC;GAC9C,GAAGA,KAAE,QAAQ,IAAI,MAAM,IAAI,MAAM,IAAI,QAAQ,CAAC;EAChD;EACA,MAAM,YAAY,YAChBA,KAAE,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,IAAI,OAAO,CAAC,CACnE;EAOA,OAAO;GAAE;GAAS;GAAO,IAAA;IALvB,GAAGA,KAAE,YAAY,OAAO,CAAC;IACzB,GAAGA,KAAE,YAAY,OAAO,CAAC;IACzB,GAAGA,KAAE,YAAY,OAAO,CAAC;GAGD;GAAG;EAAO;CACtC;;;;;;CAOA,MAAM,OAAgB,SAAiB,KAAc,SAA0B;EAC7E,MAAM,gBAAgB,KAAK,SAAS,KAAK;EACzC,MAAM,UAAUA,KAAE,KAAK,IAAI,KAAK,IAAI,KAAK,SAAS,eAAe,IAAK,CAAC,GAAG,CAAC,CAAC;EAC5E,MAAM,CAAC,UAAU,WAAW,KAAK;EACjC,MAAM,QAAQA,MACX,MAAM,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,KAAK,MAAM,IAAI,IAAI,KAAK,QAAQ,CAC9F;EACA,IAAI;EAEJ,IAAI,QAAQ,KAAK,OAAO;GACtB,MAAM,IAAI,KAAK,IAAI,KAAK,KAAK,UAAU,QAAQ,KAAK,UAAU,KAAK,QAAQ,CAAC;GAC5E,MAAM,SAAS,IAAI,WAAW,IAAI,KAAM,WAAW,KAAK;GACxD,MAAM,cAAc,OAAO;GAE3B,QAAQ,UAAU,gBAAgB,cAAcA,MAAG,gBAAgB,WAAW,WAAW,IAAI;EAC/F,OAAO;GACL,MAAM,cAAc,KAAK,OAAO,KAAK;GAErC,QAAQ,UAAU,gBAAgB,cAAcA,MAAG,gBAAgB,WAAW,WAAW,IAAI;EAC/F;EAEA,IAAI,QAAQA,KAAE,GAAI,KAAK,SAAS,UAAU,OAAO;EACjD,OAAO,QAAQ,UAAU,IAAIA,MAAI,QAAQ,YAAY,WAAW,WAAY,KAAK;CACnF;;CAGA,QAAQ,QAAgB,OAAwB;EAC9C,MAAM,EAAE,SAAS,WAAW,KAAK,MAAM,MAAM;EAC7C,MAAM,KAAK,MAAM,IAAI,OAAO;EAC5B,MAAM,KAAK,MAAM,IAAI,OAAO;EAC5B,MAAM,KAAK,MAAM,IAAI,OAAO;EAE5B,OAAO,KAAK,MAAM,OAAO,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,OAAO,UAAU,OAAO;CAChF;;;;;CAMA,UAAU,QAAgB,UAAsE;EAC9F,MAAM,EAAE,SAAS,OAAO,OAAO,KAAK,MAAM,MAAM;EAEhD,OAAO,KAAK,SAAS,UAAU,SAAS,OAAO,EAAE;CACnD;;;;;;CAOA,SACE,EAAE,SAAS,QAAQ,MAAM,QACzB,SACA,OACA,IACyC;EACzC,IAAI,CAAC,KAAK,OAAO;GAAE,SAAS;IAAC;IAAG;IAAG;IAAG;GAAC,CAAC,CAAC,UAAU,KAAK,QAAQ;GAAG,QAAQ,KAAK;EAAS;EAEzF,MAAM,QAAQA,KAAEA,KAAE,KAAK,SAAS,oBAAoB,CAAC,IAAIA,KAAE,IAAI,GAAG,CAAC;EACnE,MAAM,QAAQ,KAAK,SAAS,cAAc;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAC7D,MAAM,OAAO,KAAK;EAClB,MAAM,OAAO;GACX,GAAGA,KAAEA,KAAEA,KAAE,KAAK,MAAM,QAAQ,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,CAAC,IAAIA,KAAE,MAAM,CAAC,CAAC;GACpE,GAAGA,KAAEA,KAAEA,KAAE,KAAK,MAAM,QAAQ,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,CAAC,IAAIA,KAAE,MAAM,CAAC,CAAC;GACpE,GAAGA,KAAEA,KAAEA,KAAE,KAAK,MAAM,QAAQ,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK,CAAC,IAAIA,KAAE,MAAM,CAAC,CAAC;EACtE;EACA,MAAM,QAAQ;GACZ;GACA;IAAE,GAAG,CAAC,MAAM;IAAG,GAAG,CAAC,MAAM;IAAG,GAAG,CAAC,MAAM;GAAE;GACxC;GACA;IAAE,GAAG,CAAC,GAAG;IAAG,GAAG,CAAC,GAAG;IAAG,GAAG,CAAC,GAAG;GAAE;GAC/BG;EACF;EACA,MAAM,UAAU,MAAM,WAAW,EAAE,GAAG,KAAK,EAAE;EAE7C,KAAK,MAAM,SAAS,OAAO,MAAM,GAAG,CAAC,GAAG;GACtC,MAAM,SAAS;IACb,GAAGH,KAAE,MAAM,MAAM,IAAI,KAAK,SAAS,CAAC;IACpC,GAAGA,KAAE,MAAM,MAAM,IAAI,KAAK,SAAS,CAAC;IACpC,GAAGA,KAAE,MAAM,MAAM,IAAI,KAAK,SAAS,CAAC;GACtC;GAEA,MAAM,SAAS,MAAM,OAAO;IAC1B,IAAI,IAAI;KAAE,GAAGA,KAAE,QAAQ,IAAI,KAAK,CAAC;KAAG,GAAGA,KAAE,QAAQ,IAAI,KAAK,CAAC;KAAG,GAAGA,KAAE,QAAQ,IAAI,KAAK,CAAC;IAAE;IACvF,MAAM,UAAU,IAAI,KAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAE/D,IAAI;KAAE,GAAGA,KAAE,UAAU,EAAE,CAAC;KAAG,GAAGA,KAAE,UAAU,EAAE,CAAC;KAAG,GAAGA,KAAE,UAAU,EAAE,CAAC;IAAE;IAGpE,MAAM,MAAM,EAAE,IAAI,MAAM,UAAU,IAAI,EAAE,IAAI,MAAM,UAAU,IAAI,EAAE,IAAI,MAAM,UAAU;IACtF,MAAM,SAAS,MAAM,MAAO,IAAIA,MAAG,MAAM,MAAO,GAAG;IACnD,MAAM,MAAM,QAAQ;IAEpB,IAAI,IAAIA,KAAE,IAAI,IAAIA,KAAE,OAAO,IAAI,MAAM,CAAC;IACtC,IAAI,IAAIA,KAAE,IAAI,IAAIA,KAAE,OAAO,IAAI,MAAM,CAAC;IACtC,IAAI,IAAIA,KAAE,IAAI,IAAIA,KAAE,OAAO,IAAI,MAAM,CAAC;GACxC,CAAC;EACH;EAEA,MAAM,UAAU,QAAQ,IAAII,UAAQ;EAEpC,OAAO;GAAE,SAAS,QAAQ,MAAM,GAAG,CAAC;GAAG,QAAQ,QAAQ;EAAI;CAC7D;CAEA,QACE,UACA,OACA,SACA,OACA,KACM;EAwBN,OAAO;GACL,MAAA;IAvBA,MAAM;IACN,SAAS;IACT,WAAW,UAAU;IACrB,QAAQH;IACR,QAAQ,CACN;KAAE,YAAY;KAAG,aAAa;KAAG,WAAW,QAAQ;KAAG,cAAc;KAAO,SAAS;IAAE,CACzF;IACA,SAAS,YAAY,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OAAO,EAAE;IAC1D;GAeG;GACH,WAAA;IAbA,QAAQ;IACR,aAAa;IACb,aAAa;IACb,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,aAAa;KAAE,KAAKE;KAAO,KAAKA;IAAM;IACtC,gBAAgB;KAAE,QAAQA;KAAO,QAAQ;IAAE;GAKnC;GACR,WAAW;GACX,YAAY;GACZ;GACA,OAAO,QAAQ;GACf,cAAc;GACd,SAAS;IAAC;IAAG;IAAG;IAAG;GAAC;GACpB,SAASA;GACT,UAAUA;GACV,aAAa;GACb,OAAO;GACP,SAAS;IACP,MAAM,MAAM,QAAQ;IACpB,OAAO,MAAM;IACb,SAAS;IACT,OAAO;GACT;GACA,MAAM;GACN,YAAY,CAAC;GACb,WAAW;GACX,WAAW;GACX,eAAe;GACf,kBAAkB;GAClB,OAAO;GACP,WAAW;GACX,OAAO;GACP,gBAAgB,UAAU,IAAI;GAC9B,eAAe;GACf,GAAI,OAAO,EAAE,IAAI;EACnB;CACF;AACF;;;;;;;;;;ACtnBA,MAAMG,OAAI,KAAK;AAmEf,IAAI,UAAU;AAEd,MAAM,aAAa;AAEnB,MAAM,MAAMA,KAAE,IAAI;AAClB,MAAM,OAAOA,KAAE,GAAI;AAEnB,MAAM,UAAUA,KAAE,IAAK;AAEvB,MAAM,WAAWA,KAAE,IAAK;;;;;AAKxB,MAAM,kBAAkB;;AAGxB,MAAM,QAAQ,MAAe,UAC3B,QAAQ,UAAU,QAAQ,UAAU,MAAM,KAAK,CAAC;AAElD,MAAM,YAAY,EAAE,GAAG,GAAG,SAA2B;CACnD,GAAG,IAAI,IAAI,IAAI;CACf,GAAG,IAAI,IAAI,IAAI;CACf,GAAG,IAAI,IAAI,IAAI;AACjB;AAEA,IAAa,mBAAb,MAA8B;CAC5B;CACA;CACA;;CAEA;;CAEA;CACA;;CAEA;CACA;;CAEA;CACA;CAEA,YACE,UACA,OACA,EACE,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,GAChD,SAAS,GACT,WACsE,CAAC,GACzE;EACA,KAAK,WAAW;EAChB,KAAK,QAAQ;EACb,KAAK,SAAS;EACd,KAAK,SAAS;EAGd,MAAM,QAAQA,MAAG,IAAI,UAAU,KAAM,MAAM;EAE3C,KAAK,QAAQ,KAAK,MAAM,KAAK,MAAM,SAAS,SAAS,EAAE,IAAI,QAAQ,EAAG;EACtE,KAAK,SAAS,MAAM,KAAK,EAAE,QAAQ,KAAK,MAAM,SAAS,KAAA,CAAS;EAEhE,MAAM,SAAS,SAAS;EAExB,KAAK,SAASA,KAAE,UAAU,GAAG;EAC7B,KAAK,QAAQ,WAAW,KAAA,IAAY,KAAKA,KAAE,SAAS,EAAG;EAGvD,MAAM,QAAQ,SAAS,cAAc;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAExD,KAAK,UAAU,SAAS;GACtB,GAAGA,KAAE,MAAM,QAAQ,IAAI,MAAM,CAAC;GAC9B,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;GAC9B,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;EAChC,CAAC;EACD,KAAK,UAAU,SAAS;GACtB,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;GAC9B,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;GAC9B,GAAGA,KAAE,MAAM,IAAI,MAAM,QAAQ,CAAC;EAChC,CAAC;CACH;CAEA,IAAI,QAAiD;EACnD,OAAO,KAAK;CACd;;CAGA,OAAO,EAAE,UAAU,eAAgC;EACjD,MAAM,OAAO,CAAC,KAAK;EAEnB,OAAO;GACL,GAAGA,KAAEA,KAAE,YAAY,EAAE,IAAI,IAAI,IAAI,SAAS,CAAC;GAC3C,GAAGA,KAAEA,KAAE,YAAY,EAAE,IAAI,IAAI,IAAI,SAAS,CAAC;GAC3C,GAAGA,KAAEA,KAAE,YAAY,EAAE,IAAI,IAAI,IAAI,SAAS,CAAC;EAC7C;CACF;;CAGA,SAAS,QAAiB,KAAuB;EAC/C,MAAM,EAAE,MAAM,eAAe,GAAG,aAAa,CAAC,MAAM,KAAK;EACzD,IAAI,QAAQ,EAAE,UAAU,MAAM,cAAc,MAAM,IAAI,WAAW,OAAO;EAGxE,MAAM,QAAQ,WACX,KAAK,eAAe;GAAE;GAAW,KAAK,eAAe,WAAW,GAAG;EAAE,EAAE,CAAC,CACxE,MAAM,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG;EAE/B,KAAK,MAAM,EAAE,WAAW,SAAS,OAAO;GACtC,IAAI,MAAM,iBAAiB;GAE3B,IACE,UAAU,2BACV,UAAU,UAAU,MAAM,UAAU,gBAAgB,GAAG,MAAM,MAAM,GAEnE,OAAO;EACX;EAEA,OAAO;CACT;;;;;CAMA,MAAM,QAAiB,EAAE,GAAG,GAAG,KAAkC;EAC/D,MAAM,UAAU,KAAK,SAAS,KAAK;EACnC,MAAM,MAAM,MAAM;EAClB,MAAM,OAAO,UAAU;EACvB,MAAM,KAAKA,KAAE,IAAI,OAAO,CAAC;EACzB,MAAM,KAAKA,KAAE,IAAI,OAAO,CAAC;EACzB,MAAM,KAAKA,KAAE,IAAI,OAAO,CAAC;EACzB,MAAM,WAAWA,KAAE,KAAK,KAAK,KAAK,KAAK,KAAK,EAAE;EAC9C,IAAI,WAAW,KAAK,OAAO,KAAA;EAC3B,OAAOA,KAAE,WAAW,MAAM,QAAQ,MAAM,YAAY,OAAO,CAAC;CAC9D;;CAGA,QAAQ,QAAgB,OAAoC;EAC1D,OAAO,KAAK,MAAM,KAAK,OAAO,MAAM,GAAG,KAAK;CAC9C;;CAGA,OAAO,MAAY,UAAyB;EAC1C,MAAM,EAAE,WAAW;EACnB,MAAM,OAAOA,KAAE,KAAK,SAAS,eAAe,EAAE;EAC9C,MAAM,OAAOA,KAAE,KAAK,SAAS,sBAAsB,CAAC;EAGpD,MAAM,aAAa;GACjB,MAAM,QAAQA,KAAE,OAAO,IAAI,aAAa,CAAC;GACzC,MAAM,SAASA,KAAE,QAAQ,KAAK;GAE9B,OAAOA,MAAG,QAAQ,IAAI,SAAS,CAAC,UAAU,IAAI;EAChD;EAEA,MAAM,CAAC,IAAI,IAAI,MAAM;GAAC,KAAK;GAAG,KAAK;GAAG,KAAK;EAAC;EAE5C,MAAM,QAAQA,KAAE,OAAO,IAAIC,WAAS;EACpC,MAAM,SAASD,KAAE,OAAO,IAAIC,cAAY,IAAI;EAC5C,MAAM,QAAQD,KAAE,OAAO,IAAI,OAAO,aAAa,IAAI;EACnD,MAAM,cAAcA,KAAE,QAAQ,IAAI;EAElC,KAAK,WAAW;EAChB,KAAK,cAAc,QAAQ;EAC3B,KAAK,WAAW;GAAE,GAAG;GAAI,GAAG;GAAI,GAAG;EAAG;EACtC,KAAK,OAAO;GAAE,GAAGA,KAAE,SAAS,SAAS,IAAI;GAAG,GAAGA,KAAE,cAAc,cAAc,IAAI;GAAG,GAAG;EAAM;CAC/F;;;;;;;CAQA,MAAM,MAAoB;EACxB,IAAI,EAAE,OAAO,IAAI;EAEjB,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,CAAC,MAAM,QAAQ;GAEnB,MAAM,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,MAAM;GAE9C,KAAK,WAAW;IAAE,GAAGA,KAAE,EAAE,IAAI,EAAE,IAAI,IAAI;IAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,IAAI,IAAI;IAAG,GAAGA,KAAE,EAAE,IAAI,EAAE,IAAI,IAAI;GAAE;GAEzF,MAAM,OAAO,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;GAErC,IAAI,OAAO,GACT,KAAK,cAAc,QAAQ,SACzB,KAAK,aACL,KAAK;IAAE,GAAG,EAAE,IAAI;IAAM,GAAG,EAAE,IAAI;IAAM,GAAG,EAAE,IAAI;GAAK,GAAG,OAAO,IAAI,CACnE;EACJ;CACF;;;;;;;;CASA,OACE,QACA,OAAO,GACP,EAAE,UAAU,OAAO,aAAa,SAAqD,CAAC,GAChF;EACN,KAAK,MAAM,IAAI;EACf,KAAK,SAAS,QAAQ,OAAO;EAC7B,KAAK,KAAK,QAAQ,UAAU;CAC9B;CAEA,SAAS,QAAgB,SAAwB;EAC/C,MAAM,SAAS,KAAK,OAAO,MAAM;EACjC,MAAM,UAAU,CAAC,WAAW,KAAK,SAAS,QAAQ,OAAO,QAAQ;EAEjE,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,OAAO,SAAS;GAC/C,IAAI,OAAO,KAAK,OAAO;GAEvB,IAAI,MAAM,QAAQ;IAChB,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,QAAQ;IAE9C,IAAI,UAAU,KAAA,GAAW;KACvB,KAAK,QAAQ;KACb;IACF;IAEA,KAAK,SAAS;GAChB;GAEA,IAAI,CAAC,SAAS;IACZ,KAAK,OAAO,SAAS,KAAA;IACrB;GACF;GAGA,SAAS;IACP,UAAU;IACV,aAAa,QAAQ;IACrB,UAAU;KAAE,GAAG;KAAG,GAAG;KAAG,GAAG;IAAE;IAC7B,MAAM;KAAE,GAAG;KAAG,GAAG;KAAG,GAAG;IAAE;IACzB,OAAO;IACP,QAAQ;IACR,WAAW;IACX,KAAK;IACL,QAAQ;GACV;GACA,KAAK,OAAO,SAAS;GAErB,MAAM,OAAO,SAAS,KAAK,MAAM;GAEjC,KAAK,OAAO,MAAM;IAChB,GAAGA,KAAE,KAAK,SAAS,KAAK,IAAI,OAAO,CAAC;IACpC,GAAGA,KAAE,KAAK,SAAS,KAAK,IAAI,OAAO,CAAC;IACpC,GAAGA,KAAE,KAAK,SAAS,KAAK,IAAI,OAAO,CAAC;GACtC,CAAC;GAGD,IAAI,KAAK,QAAQ;IACf,KAAK,QAAQ,SAAS,QAAQ;IAC9B,KAAK,SAAS,KAAK,OAAO;IAC1B,KAAK,SAAS,EAAE;IAChB,KAAK,YAAY;IACjB,KAAK,MAAM;GACb;GAEA,KAAK,SAAS;EAChB;CACF;;;;;;CAOA,KAAK,QAAgB,MAAoB;EACvC,IAAI,CAAC,KAAK,QAAQ;EAElB,MAAM,OAAO,WAAW,MAAM;EAE9B,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,CAAC,MAAM,QAAQ;GACnB,KAAK,OAAO,SAAS,QAAQ,MAAM;IACjC,QAAQ,KAAK;IACb,KAAK,KAAK;IACV,WAAW,QAAQ,wBAAwB,KAAK,aAAa,KAAK,QAAQ;IAC1E;GACF,CAAC;GAED,IAAI,KAAK,OAAO,SAAS,UAAU;IACjC,KAAK,OAAO,SAAS,QAAQ;IAC7B,OAAO,KAAK;GACd;EACF;CACF;;;;;CAMA,UAA6B;EAC3B,MAAM,UAA6B,CAAC;EAEpC,KAAK,MAAM,QAAQ,KAAK,QACtB,IAAI,MAAM,QACR,QAAQ,KAAK;GACX,QAAQ;IACN,GAAG,KAAK;IACR,UAAU,KAAK;IACf,SAAS,EAAE,UAAU,KAAK,SAAS;GACrC;GACA,QAAQ,KAAK;EACf,CAAC;EAEL,OAAO;CACT;;CAGA,OAAO,OAAkD;EACvD,IAAI,KAAK;EACT,KAAK,MAAM,QAAQ,KAAK,QAAQ,IAAI,MAAM,QAAQ,KAAK,MAAM,MAAM,KAAK,EAAE,OAAO,KAAK;CACxF;;;;;;CAOA,QAAuB;EACrB,MAAM,QAAuB,CAAC;EAE9B,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,CAAC,QAAQ,EAAE,KAAK,QAAQ,UAAU;GACtC,KAAK,YAAY,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK;GAChE,MAAM,KAAK;IACT,OAAO,QAAQ,wBAAwB,KAAK,aAAa,KAAK,QAAQ;IACtE,OAAO,KAAK;GACd,CAAC;EACH;EAEA,OAAO;CACT;AACF;;;ACtYA,MAAa,8BAAqE;CAChF,KAAK;CACL,UAAU;CACV,OAAO;EAAE,GAAG;EAAM,GAAG;EAAM,GAAG;CAAK;CACnC,WAAW;AACb;;AAGA,MAAa,2BAA+D;CAC1E,KAAK;CACL,UAAU;CACV,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC1B,kBAAkB;CAClB,mBAAmB;AACrB;;AAGA,MAAM,gBAAgB;AAYtB,MAAM,aAAa,KAAK,OAAO,eAAe;AAC9C,MAAME,OAAI,KAAK;AAGf,MAAM,SAAS,UAAmB,QAAQ,IAAI,QAAQ;AACtD,MAAMC,SAAO;;;;;;;AAQb,IAAa,kBAAb,MAA6B;CAC3B;CACA;CACA;CAEA,QAAQ;CAER;CAEA,YAAY;CAEZ,gBAAgB;CAChB;CACA,YAAqB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAExC,YACE,WAGI,CAAC,GACL,eAAuB,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,GACxD;EACA,KAAK,aAAa;GAAE,GAAG;GAA6B,GAAG,SAAS;EAAW;EAC3E,KAAK,UAAU;GAAE,GAAG;GAA0B,GAAG,SAAS;EAAQ;EAClE,KAAK,SAAS;EAGd,MAAM,MAAM,SAAS,YAAY;EAEjC,KAAK,mBAAmB,QAAQ,KAAA,IAAY,KAAK,CAAC;EAGlD,IAAI,KAAK,QAAQ,WAAW,GAC1B,KAAK,SAAS;GACZ,WAAW;IAAE,GAAG;IAAG,GAAG;IAAG,GAAG;GAAG;GAC/B,OAAO;IAAE,GAAG;IAAK,GAAG;IAAK,GAAG;GAAI;GAChC,IAAI;EACN;CACJ;;CAGA,KAAK,MAAsC;EACzC,IAAI,SAAS,cAAc,KAAK,mBAAmB;OAC9C,KAAK,gBAAgB;CAC5B;;CAGA,OAAO,MAAc,OAAe,KAAoB;EACtD,KAAK,QAAQ;EAEb,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO;EAEZ,IAAI,EAAE,QAAQ,IAAI,MAAM,KAAK;EAC7B,IAAI,EAAE,SAAS,IAAI;EACnB,KAAK,YAAY;EACjB,KAAK,MAAM,KAAK;CAClB;CAGA,MAAM,OAAyB;EAC7B,MAAM,EAAE,KAAK,UAAU,OAAO,kBAAkB,sBAAsB,KAAK;EAC3E,MAAM,WAAW,KAAK;EACtB,MAAM,QAAQ,KAAK,QAAQ;EAE3B,KAAK,gBAAgBD,KAAE,KAAK;EAE5B,IAAI,EAAE,WAAW,IACX;OAAA,EAAE,QAAQ,IAAI;EAAA,OACb,IAAI,QAAQ,UAAU;GAE3B,KAAK,gBAAgBA,MAAG,KAAK,OAAO,IAAI,aAAaA,KAAE,EAAG,IAAI,OAAOA,KAAE,GAAG,CAAC;GAE3E,MAAM,QAAQ,KAAK,OAAO,IAAI;GAC9B,MAAM,SAAS,KAAK,OAAO,IAAI;GAC/B,MAAM,QAAQ,KAAK,OAAO,IAAI;GAC9B,MAAM,IAAI,QAAQ,QAAQ;GAC1B,MAAM,IAAI,SAAS,SAAS;GAC5B,MAAM,IAAI,QAAQ,QAAQ;GAC1B,MAAM,UAAUA,KAAE,IAAI,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;GAEtD,MAAM,YAAY;IAAE,GAAGA,KAAE,IAAI,OAAO;IAAG,GAAGA,KAAE,IAAI,OAAO;IAAG,GAAGA,KAAEA,KAAE,CAAC,IAAI,OAAO;GAAE;GAC/E,MAAM,KAAK;GACX;EACF;EAEA,MAAM,YAAY,KAAK,YACnBA,KAAEA,KAAE,gBAAgB,IAAIA,KAAE,iBAAiB,CAAC,IAC5CA,KAAE,gBAAgB;EACtB,MAAM,QAAQA,KAAE,KAAK,OAAO,IAAI,UAAU;EAC1C,MAAM,UAAU,KAAK,OAAO,IAAI,QAAQ,YAAY;EACpD,MAAM,MAAM,MAAMA,KAAE,UAAUA,KAAE,MAAM,CAAC,CAAC,CAAC;EACzC,MAAM,QAAQ,MAAMA,KAAE,UAAUA,KAAE,MAAM,CAAC,CAAC,CAAC;EAC3C,MAAM,OAAO,MAAM,UAAUA,KAAE,MAAM,CAAC,CAAC;EAEvC,MAAM,QAAQ;GACZ,GAAGC,OAAKD,KAAE,MAAM,GAAG,CAAC;GACpB,GAAGC,OAAKD,KAAE,QAAQ,GAAG,CAAC;GACtB,GAAGC,OAAK,OAAO,GAAG;EACpB;EACA,MAAM,KAAK;CACb;;CAGA,IAAI,QAAgC;EAClC,MAAM,QAAQ,KAAK;EACnB,IAAI,CAAC,OAAO,IAAI,OAAO,KAAA;EACvB,OAAO;GACL,MAAM;GACN,UAAU,KAAK;GACf,WAAW,MAAM;GACjB,OAAO,MAAM;GACb,OAAO;EACT;CACF;;CAGA,SAAS,MAAwB;EAC/B,MAAM,EAAE,KAAK,UAAU,OAAO,cAAc,KAAK;EACjD,IAAI,YAAY,GAAG,OAAO;EAE1B,MAAM,WAAW,KAAK;EACtB,MAAM,QAAQ,KAAK,QAAQ;EAE3B,KAAK,mBAAmBD,KAAE,KAAK;EAC/B,KAAK,YAAY;EAEjB,IAAI,WAAW,GAAG;GAChB,KAAK,YAAY;GAEjB,IAAI,QAAQ,UACV,KAAK,mBAAmBA,MAAG,KAAK,OAAO,IAAI,aAAaA,KAAE,EAAG,IAAI,OAAOA,KAAE,GAAG,CAAC;EAClF,OAAO,IAAI,QAAQ,GAAG,KAAK,YAAY;EAEvC,IAAI,CAAC,KAAK,WAAW,OAAO;EAE5B,MAAM,QAAQA,KAAE,KAAK,OAAO,IAAI,UAAU;EAC1C,MAAM,QAAQ,KAAK,OAAO,IAAIA,KAAE,SAAS,IAAI,QAAQ;EAErD,OAAO;GACL,GAAG,MAAMA,KAAE,QAAQA,KAAE,MAAM,CAAC,IAAI,KAAK,CAAC,CAAC;GACvC,GAAG,MAAMA,KAAEA,KAAE,QAAQA,KAAE,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC;GAC1C,GAAG,MAAMA,KAAEA,KAAE,QAAQA,KAAE,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC;EAC5C;CACF;AACF;;;;;;;;;ACzMA,MAAME,OAAI,KAAK;AAGf,MAAMC,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AACf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAG1C,MAAM,YAAYH,KAAE,IAAI,KAAK;AAC7B,MAAM,iBAAiBA,KAAE,IAAI,KAAK;AAClC,MAAMI,WAASJ,KAAE,SAAS;AAE1B,MAAM,aAAa;AAEnB,MAAM,cAAc;AAEpB,MAAM,aAAa;AACnB,MAAM,SAAS;AAEf,MAAM,eAAe;AACrB,MAAM,aAAaA,KAAE,GAAI;AACzB,MAAM,cAAcA,KAAE,GAAG;AACzB,MAAM,aAAaA,KAAE,GAAI;AAEzB,MAAM,eAAeA,KAAE,EAAG;AAC1B,MAAM,gBAAgBA,KAAE,IAAK;;AAwB7B,MAAa,sBAA6C;CACxD,OAAO;EAAE,GAAG;EAAK,GAAG;EAAK,GAAG;CAAI;CAChC,WAAW;CACX,UAAU;CACV,cAAc;CACd,SAAS;CACT,SAAS;CACT,IAAIA,KAAE,GAAI;CACV,IAAIA,KAAE,GAAI;CACV,QAAQ;AACV;;AAkCA,MAAa,gBAA0C;CACrD,YAAY;CACZ,eAAe;CACf,OAAOG;CACP,WAAW;CACX,WAAW;CACX,iBAAiB;CACjB,UAAUH,KAAE,IAAI;CAChB,UAAUA,KAAE,GAAI;CAChB,gBAAgB;CAChB,QAAQ;CACR,QAAQ;CACR,aAAaA,KAAE,CAAC,KAAK,EAAE;CACvB,aAAaA,KAAE,KAAK,EAAE;CACtB,QAAQG;CACR,QAAQA;CACR,QAAQ,CAAC;AACX;;;;;AASA,MAAa,eAAe,GAAsB,MAA8B;CAC9E,MAAM,QAAQ,IAAI,MAAc,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;CAC7C,MAAM,QAAQ,IAAI,MAAc,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;CAC7C,MAAM,IAAI,IAAI,MAAc,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;CAIzC,MAAM,KAAK;CACX,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK,MAAM,KAAKH,KAAE,KAAK,IAAI,MAAM,IAAI,GAAI;CAChE,MAAM,KAAKA,KAAE,KAAK,IAAI,MAAM,IAAI,GAAI;CACpC,MAAM,KAAKA,MAAG,EAAE,KAAM,EAAE,MAAO,MAAM,KAAM,CAAC;CAE5C,KAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KACrB,MAAM,KAAKA,OAAI,EAAE,IAAI,KAAM,EAAE,IAAI,MAAO,IAAI,MAAM,IAAI,MAAO,MAAM,EAAG;CAExE,MAAM,KAAKA,OAAI,EAAE,KAAM,EAAE,IAAI,MAAO,IAAI,MAAM,IAAI,MAAO,MAAM,EAAG;CAClE,EAAE,KAAK,MAAM;CACb,KAAK,IAAI,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK,EAAE,KAAKA,KAAE,MAAM,KAAM,EAAE,IAAI,KAAM,MAAM,EAAG;CAC3E,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,IAAI,GAAG,OAAO;EAC1C,IAAI,EAAE;EACN,IAAI,EAAE;EACN,IAAIA,MAAG,EAAE,IAAI,KAAM,EAAE,MAAO,KAAK,EAAE,KAAM,EAAE,MAAO,EAAE,IAAI,EAAG;EAC3D,IAAIA,MAAG,EAAE,KAAM,EAAE,IAAI,MAAO,IAAI,EAAE,KAAM,EAAE,IAAI,EAAG;CACnD,EAAE;AACJ;;AAGA,IAAa,cAAb,MAAyB;CAMM;CAL7B,UAAoB,CAAC;CACrB,WAA2B,CAAC;CAC5B,UAAU;CACV,UAAU;CAEV,YAAY,QAAiC;EAAhB,KAAA,SAAA;CAAiB;CAG9C,OAAe;EACb,OAAOA,KAAE,KAAK,OAAO,IAAI,aAAa,KAAK,UAAU,KAAK,WAAW,KAAK,OAAO;CACnF;;CAGA,OAAO,GAAmB;EACxB,MAAM,QAAQ,KAAK,SAAS;EAC5B,IAAI,MAAM,GAAG,OAAO,KAAK,QAAQ;EAEjC,MAAM,SAAS,QAAQ;EACvB,MAAM,QAAQ,KAAK,MAAM,MAAM;EAE/B,OAAO,QAAQ,KAAK,SAAS,QAAS,SAAS,KAAK;CACtD;;CAGA,cAAc,GAAmB;EAC/B,MAAM,QAAQ,KAAK,SAAS;EAC5B,IAAI,MAAM,GAAG,OAAO,KAAK,QAAQ;EAEjC,MAAM,SAAS,QAAQ;EACvB,MAAM,QAAQ,KAAK,MAAM,MAAM;EAE/B,OAAO,QAAQ,KAAK,SAAS,QAASA,KAAE,SAAS,KAAK,CAAC;CACzD;;CAGA,UAAU,OAAe,SAAiB,SAAiB,MAAc,MAAoB;EAC3F,KAAK,UAAU;EACf,KAAK,UAAU;EAEf,MAAM,SAAS,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,KAAK,KAAK,CAAC;EAC9D,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,IAAI,OAAO,KAAK,OAAO,KAAK;EACxD,KAAK,IAAI,IAAI,KAAK,IAAI,QAAQ,MAAM,CAAC,GAAG,IAAI,OAAO,KAAK,OAAO,KAAK;EACpE,KAAK,IAAI,MAAM;CACjB;;CAGA,OAAO,OAAqB;EAC1B,MAAM,QAAQ,KAAK,QAAQ;EAC3B,IAAI,QAAQ,KAAK,QAAQ,GAAG;EAE5B,MAAM,SAAS,KAAK;EACpB,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,KAAK,OAAO,KAAK,OAAO,QAAQ,QAAQ;EACnE,KAAK,IAAI,IAAI,OAAO,IAAI,OAAO,KAAK,OAAO,KAAK,KAAK,KAAK;EAC1D,KAAK,WAAW,YAAY,QAAQ,QAAQ,CAAC;CAC/C;;CAGA,IAAI,QAAiC;EACnC,KAAK,UAAU,CAAC,GAAG,MAAM;EACzB,KAAK,WAAW,YAAY,KAAK,SAAS,KAAK,QAAQ,SAAS,CAAC;CACnE;AACF;AASA,MAAM,SAAS,EAAE,GAAG,GAAG,SAA2B;CAAE,GAAGA,KAAE,CAAC;CAAG,GAAGA,KAAE,CAAC;CAAG,GAAGA,KAAE,CAAC;AAAE;AAC9E,MAAM,UAAU,EAAE,GAAG,GAAG,QAAyB,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;;AAGhF,MAAMK,SAAO;AAGb,MAAM,aAAa,GAAY,YAA6B;CAC1D,MAAM,UAAU,IAAI,KAAK,KAAK,OAAO;CAErC,OAAO;EAAE,GAAGL,KAAE,UAAU,EAAE,CAAC;EAAG,GAAGA,KAAE,UAAU,EAAE,CAAC;EAAG,GAAGA,KAAE,UAAU,EAAE,CAAC;CAAE;AACzE;;;;;;AAOA,IAAa,aAAb,MAAwB;;CAEtB,QAAiB,QAAQ;CACzB,QAAqB;;CAErB,QAAQ;;CAER;CAEA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,aAAqB;CACrB,UAAkB;CAClB;CAEA,YACE,WAAoC,CAAC,GACrC,EAAE,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,MAA2B,CAAC,GAC9E;EACA,KAAK,WAAW;GAAE,GAAG;GAAe,GAAG;EAAS;EAEhD,KAAK,SAAS,KAAK,SAAS,OAAO,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,WAAW,EAAE,GAAG,MAAM,EAAE;EAC5E,KAAK,SAAS;EAEd,MAAM,cAAc,IAAI,YAAY,MAAM;EAE1C,KAAK,QAAQ,MAAM;EACnB,KAAK,QAAQ,MAAM;EACnB,KAAK,QAAQ,MAAM;EACnB,KAAK,SAAS,MAAM;EACpB,KAAK,WAAW,MAAM;EACtB,KAAK,aAAa,MAAM;EACxB,KAAK,UAAU,MAAM;EACrB,KAAK,UAAU,MAAM;EACrB,KAAK,UAAU,MAAM;EACrB,KAAK,MAAM;CACb;;;;;;;CAQA,IAAI,QAAgC;EAClC,IAAI,CAAC,KAAK,KAAK,OAAO,KAAA;EAEtB,MAAM,EAAE,OAAO,cAAc,KAAK;EAElC,OAAO;GAAE,OAAO;IAAE,GAAG,MAAM,IAAI;IAAK,GAAG,MAAM,IAAI;IAAK,GAAG,MAAM,IAAI;GAAI;GAAG;EAAU;CACtF;;CAGA,SAAS,OAA0B;EACjC,KAAK,QAAQ;EAEb,IAAI,UAAU,GAAG;GACf,KAAK,UAAU;GACf,KAAK,QAAQ;GACb,KAAK,aAAa;GAClB,KAAK,OAAO,KAAA;EACd,OAAO,IAAI,UAAU,GAAG;GACtB,KAAK,aAAa;GAClB,KAAK,MAAM;GACX,KAAK,UAAU;EACjB,OAAO,IAAI,UAAU,GAAG,KAAK,aAAa;OACrC,KAAK,MAAM,KAAA;CAClB;;CAGA,OAAO,MAAoB;EACzB,IAAI,KAAK,UAAU,GAAG;EAEtB,MAAM,EAAE,eAAe,UAAU,UAAU,mBAAmB,KAAK;EAEnE,IAAI,KAAK,UAAU,KAAK,KAAK,UAAU,GAAG;GACxC,MAAM,QAAQ,OAAO,KAAK;GAE1B,KAAK,aAAaA,KAAE,KAAK;GAEzB,IAAI,QAAQ,QAAQ;GACpB,IAAI,IAAI,OAAO,QAAQ;GAGvB,MAAM,SAAS,SAAS,WAAW,YAAY,YAAY,OAAO,KAAK;GAEvE,KAAK,QAAQA,KAAE,KAAK;GACpB,KAAK,UAAU,KAAK,OAAO,gBAAgB,KAAK,KAAK;GAGrD,MAAM,QAAQ,gBAAgB,aAAa,cAAc;GAEzD,IAAI,KAAK,WAAW,OAAO;IACzB,KAAK,MAAM,OAAO,MAAM;IACxB,KAAK,MAAM,OAAO,MAAM;IACxB,KAAK,SAAS,OAAO,MAAM;IAC3B,KAAK,OAAO,OAAO,MAAM;IACzB,KAAK,QAAQ,OAAO,MAAM;IAC1B,KAAK,QAAQ,OAAO,MAAM;IAC1B,KAAK,QAAQ,OAAO,MAAM;IAC1B,KAAK,WAAW,OAAO,MAAM;IAG7B,MAAM,WAAW,gBAAgB;IAEjC,KAAK,UAAU;IACf,KAAK,QAAQA,KAAE,KAAK,QAAQ,QAAQ,WAAW,IAAI,QAAQ;GAC7D;GAEA,MAAM,OAAO,KAAK,UAAU,KAAK,KAAK;GACtC,MAAM,QAAQ,KAAK,UAAUA,KAAE,aAAa,KAAK,KAAK,CAAC;GACvD,MAAM,MAAM,MAAM;IAAE,GAAG,MAAM,IAAI,KAAK;IAAG,GAAG,MAAM,IAAI,KAAK;IAAG,GAAG,MAAM,IAAI,KAAK;GAAE,CAAC;GACnF,MAAM,UAAU,IAAI,OAAO,GAAG;GAC9B,MAAM,OAAO;IAAE,GAAG,CAACA,KAAE,IAAI,IAAI,OAAO;IAAG,GAAG,CAACA,KAAE,IAAI,IAAI,OAAO;IAAG,GAAG,CAACA,KAAE,IAAI,IAAI,OAAO;GAAE;GAEtF,MAAM,QAAQ;IAAE,GAAG,CAACA,KAAE,KAAK,IAAI,IAAI,KAAK,CAAC;IAAG,GAAG,CAACA,KAAE,KAAK,IAAI,IAAI,KAAK,IAAI,CAAC;IAAG,GAAG,CAACA,KAAE,KAAK,CAAC;GAAE;GAC1F,MAAM,KAAK,MAAM;IACf,GAAG,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI,KAAK;IACrC,GAAG,KAAK,IAAI,MAAM,IAAI,MAAM,IAAI,KAAK;IACrC,GAAG,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM;GACvC,CAAC;GAED,MAAM,QAAQ,MAAe;IAC3B,MAAM,KAAK,IAAI,OAAO,CAAC;IAEvB,OAAO;KAAE,GAAGA,KAAE,EAAE,IAAI,EAAE;KAAG,GAAGA,KAAE,EAAE,IAAI,EAAE;KAAG,GAAGA,KAAE,EAAE,IAAI,EAAE;KAAG,GAAG;IAAE;GAChE;GAEA,KAAK,OAAO;IAAE,GAAG,KAAK,KAAK;IAAG,GAAG,KAAK,EAAE;IAAG,GAAG,KAAK,IAAI;IAAG,GAAG;KAAE,GAAG;KAAM,GAAG;IAAE;GAAE;EACjF;EAGA,MAAM,MAAM,KAAK;EAEjB,IAAI,KAAK,SAAS;GAChB,MAAM,IAAIA,KAAE,KAAK,OAAO,IAAI,cAAc;GAC1C,MAAM,MAAM,IAAI,KAAK,OAAO,IAAI,IAAI;GAEpC,MAAM,UAAU,UAAkB,UAAUA,KAAEA,KAAE,QAAQ,GAAG,IAAI,GAAG,CAAC;GAEnE,IAAI,QAAQ;IAAE,GAAG,OAAOA,KAAE,EAAG,CAAC;IAAG,GAAG,OAAOA,KAAE,EAAG,CAAC;IAAG,GAAG,OAAO,CAAC;GAAE;GAEjE,MAAM,IAAI,IAAI;GACd,MAAM,WAAW;IACf,GAAGA,KAAE,eAAe,EAAE,CAAC;IACvB,GAAGA,KAAE,eAAe,EAAE,CAAC;IACvB,GAAGA,KAAE,eAAe,EAAE,CAAC;GACzB;GACA,MAAM,QAAQ,KAAK,OAAO,IAAI;GAC9B,MAAM,QAAQ,KAAK,OAAO,IAAI;GAC9B,MAAM,UAAU,KAAK,OAAO,IAAI,iBAAiB,IAAI;GACrD,MAAM,WAAW;IACf,GAAGA,KAAE,UAAU,SAAS,CAAC;IACzB,GAAGA,KAAE,QAAQ,IAAI,IAAI,SAAS,CAAC;IAC/B,GAAGA,KAAEA,KAAE,QAAQ,IAAI,CAAC,IAAI,SAAS,CAAC;GACpC;GAEA,IAAI,YAAY,UACd,UACA,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS,IAAI,SAAS,CAC5E;EACF;EAEA,KAAK,MAAM,SAAS,KAAK,QAAQ;GAC/B,MAAM,UAAUA,KAAE,OAAO,MAAM,KAAK,MAAM,OAAO;GACjD,MAAM,UAAUA,KAAE,OAAO,MAAM,KAAK,MAAM,OAAO;EACnD;CACF;;;;;;;;;;CAWA,QAAgB;EACd,IAAI,KAAK,UAAU,GAAG,OAAO,CAAC;EAC9B,IAAI,KAAK,KAAK,KAAK,IAAI,UAAU;EAEjC,MAAM,QAAgB,CAAC;EAEvB,KAAK,OAAO,SAAS,OAAO,UAAU,KAAK,UAAU,OAAO,OAAO,KAAK,CAAC;EACzE,OAAO;CACT;CAGA,QAAsB;EACpB,MAAM,EACJ,eAAe,OACf,OACA,WACA,WACA,aACA,gBACE,KAAK;EACT,MAAM,EAAE,QAAQ,WAAW,KAAK;EAEhC,IAAI,QAAQ,GAAG;EAEf,KAAK,MAAM,UAAUA,KAAE,MAAM,IAAI,GAAI;EACrC,KAAK,MAAM,UAAUA,KAAE,MAAM,IAAI,EAAG;EAEpC,MAAM,KAAK,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,KAAK,MAAM,KAAK,CAAC;EAChE,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,IAAI,OAAO,KAAK,GAAG,KAAK;EACjD,KAAK,MAAM,IAAI,EAAE;EACjB,KAAK,MAAM,UAAU,OAAOA,KAAE,MAAM,IAAI,GAAI,GAAGA,KAAE,MAAM,IAAI,EAAG,GAAG,GAAG,CAAC;EACrE,KAAK,MAAM,IAAI,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,MAAMA,KAAE,EAAG,IAAI,MAAM,IAAK,SAAS,CAAC,CAAC,CAAC;EACvF,KAAK,OAAO,UAAU,OAAO,WAAW,WAAW,GAAG,CAAC;EACvD,KAAK,SAAS,UAAU,OAAO,aAAa,aAAa,GAAG,CAAC;EAC7D,KAAK,QAAQ,UAAU,OAAO,OAAO,GAAG,OAAO,GAAG,GAAG,CAAC;EACtD,KAAK,QAAQ,UAAU,OAAO,OAAO,GAAG,OAAO,GAAG,GAAG,CAAC;EACtD,KAAK,QAAQ,UAAU,OAAO,OAAO,GAAG,OAAO,GAAG,GAAG,CAAC;EACtD,KAAK,WAAW,UAAU,OAAO,IAAK,GAAG,GAAG,CAAC;CAC/C;CAGA,YAA0B;EACxB,MAAM,QAAQ,KAAK,OAAO,IAAI;EAC9B,MAAM,IAAIA,KAAE,KAAK,OAAO,IAAI,iBAAiB,IAAI,CAAC;EAClD,MAAM,IAAIA,KAAE,QAAQ,IAAI,CAAC;EACzB,MAAM,YAAY,UAAU;GAAE;GAAG,GAAG;GAAI;EAAE,GAAG,KAAK,IAAI,IAAI,IAAI,CAAC;EAE/D,KAAK,MAAM;GAAE,OAAO;IAAE,GAAG;IAAK,GAAG;IAAK,GAAG;GAAI;GAAG;GAAW,SAAS;EAAM;CAC5E;CAGA,UAAkB,GAAoB;EACpC,MAAM,QAAQ;GACZ,GAAGA,KAAE,KAAK,MAAM,OAAO,CAAC,CAAC;GACzB,GAAGA,KAAE,KAAK,MAAM,OAAO,CAAC,CAAC;GACzB,GAAGA,KAAE,KAAK,MAAM,OAAO,CAAC,CAAC;EAC3B;EAEA,OAAO,MAAM,QAAQ,eAAe,OAAO,KAAK,KAAK,CAAC;CACxD;CAEA,UAAkB,GAAsB;EACtC,MAAM,WAAW,IAAI;EACrB,MAAM,QAAQ,WAAW,IAAIA,KAAE,IAAI,UAAU,IAAIA,KAAE,QAAQ;EAC3D,MAAM,QAAQ,KAAK,UAAU,CAAC;EAC9B,MAAM,OAAO,KAAK,UAAU,KAAK;EACjC,MAAM,QAAQ,MAAM;GAAE,GAAG,KAAK,IAAI,MAAM;GAAG,GAAG,KAAK,IAAI,MAAM;GAAG,GAAG,KAAK,IAAI,MAAM;EAAE,CAAC;EACrF,MAAM,UAAU,IAAI,OAAO,KAAK;EAChC,MAAM,UAAU;GACd,GAAGA,KAAE,EAAE,MAAM,IAAI,QAAQ;GACzB,GAAGA,KAAE,EAAE,MAAM,IAAI,QAAQ;GACzB,GAAGA,KAAE,EAAE,MAAM,IAAI,QAAQ;EAC3B;EAEA,MAAM,OAAO;GACX,GAAG,CAACA,KAAE,QAAQ,IAAI,IAAI,QAAQ,CAAC;GAC/B,GAAG,CAACA,KAAE,QAAQ,IAAI,IAAI,QAAQ,IAAI,CAAC;GACnC,GAAG,CAACA,KAAE,QAAQ,CAAC;EACjB;EAOA,OAAO;GAAE;GAAM,IANJ,MAAM;IACf,GAAG,KAAK,IAAI,QAAQ,IAAI,KAAK,IAAI,QAAQ;IACzC,GAAG,QAAQ,IAAI,KAAK,IAAI,KAAK,IAAI,QAAQ;IACzC,GAAG,KAAK,IAAI,QAAQ,IAAI,QAAQ,IAAI,KAAK;GAC3C,CAEgB;GAAG;EAAM;CAC3B;CAGA,UAAkB,OAAoB,OAAe,OAAqB;EACxE,MAAM,EAAE,QAAQ,QAAQ,iBAAiB,eAAe,KAAK;EAC7D,IAAI,OAAOA,KAAE,IAAI,CAAC,MAAM;EACxB,MAAM,WAAWA,KAAE,IAAI,MAAM;EAC7B,MAAM,QAAQ,KAAK;EACnB,MAAM,SAAS,UAAmB,IAAI,QAAQ,IAAI,IAAI,QAAQ,IAAI;EAClE,MAAM,WAAW,MAAM,eAAe,KAAK;EAC3C,MAAM,QAAQA,KAAE,QAAQ;EACxB,MAAM,MAAMA,KAAE,MAAM,gBAAgB,KAAK,CAAC;EAC1C,MAAM,OAAOA,KAAE,KAAK,IAAI,MAAM,QAAQ,CAAC;EACvC,MAAM,QAAQ,MAAM;EAEpB,IAAI,IAAI;EAER,SAAS;GACP,IAAI,OAAO,IAAI,EAAE,IAAI,OAAO,EAAE,IAAI,MAAM;GAExC,MAAM,QAAQ,cAAc;GAE5B,OAAOA,KAAE,KAAK;GAEd,MAAM,YAAYA,KAAE,IAAI,KAAK;GAC7B,IAAI,OAAO,IAAI,YAAY,IAAI;GAC/B,IAAI,QAAQ,IAAI,MAAM,OAAO,MAAM,MAAM,OAAO;GAEhD,MAAM,YAAY,OAAeA,KAAE,MAAM,KAAK,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC;GAGrE,MAAM,QAAQ,OAAe;IAC3B,MAAM,SAAS,KAAK,OAAO,OAAO,EAAE,IAAI,MAAM;IAE9C,OAAOA,MAAG,SAAS,kBAAkB,UAAU,SAAS,EAAE,IAAI,MAAM;GACtE;GAEA,MAAM,QAAQ,KAAK,CAAC;GACpB,MAAM,QAAQ,KAAK,IAAI;GACvB,MAAM,SAAS,KAAK,UAAU,CAAC;GAC/B,MAAM,SAAS,KAAK,UAAU,IAAI;GAGlC,MAAM,CAAC,MAAM,MACX,OAAO,IAAI,CAAC,MAAM,UAAU,MAAM,SAAS,IAAI,CAAC,MAAM,WAAW,MAAM,QAAQ;GAEjF,MAAM,YAAY,OAAe;IAC/B,MAAM,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI,OAAO;IAExC,OAAO,IAAI,IAAI,IAAI;GACrB;GAEA,MAAM,aAAa,KAAK;GACxB,MAAM,QAAQA,KAAE,aAAa,SAAS,CAAC,IAAI,IAAI;GAC/C,MAAM,SAASA,KAAE,QAAQ,QAAQ,KAAK;GACtC,MAAM,QAAQ,SAAS,IAAI,IAAIA,KAAE,UAAU,IAAI;GAC/C,MAAM,SAASA,KAAE,QAAQ,QAAQ,KAAK;GAItC,MAAM,QAAQ,IAAY,SAAkB;IAC1C,MAAM,IAAIA,KAAE,KAAK,QAAQ,OAAO,EAAE,CAAC;IACnC,MAAM,IAAIA,KAAE,KAAK,QAAQ,OAAO,EAAE,CAAC;IACnC,MAAM,IAAI,OAAO,KAAK,QAAQ,OAAO,EAAE,IAAIA,KAAE,KAAK,QAAQ,OAAO,EAAE,CAAC;IACpE,MAAM,QAAQ,KAAK,WAAW,cAAc,EAAE;IAE9C,OAAO;KACLA,KAAEA,KAAE,MAAM,IAAI,CAAC,IAAI,KAAK;KACxBA,KAAEA,KAAE,MAAM,IAAI,CAAC,IAAI,KAAK;KACxBA,KAAE,QAAQA,KAAE,MAAM,IAAI,CAAC,CAAC;IAC1B;GACF;GAEA,MAAM,QAAQ,KAAK,GAAG,KAAK;GAC3B,MAAM,QAAQ,KAAK,MAAM,IAAI;GAE7B,MAAM,WAAuB,CAAC;GAC9B,MAAM,SAAqB,CAAC;GAG5B,MAAM,SAAS,EAAE,MAAM,IAAI,SAAoB,QAAgB,KAAa,QAAgB;IAC1F,MAAM,IAAIA,KAAE,SAAS,GAAG;IACxB,MAAM,IAAIA,KAAE,SAAS,GAAG;IACxB,MAAM,SAAS,MAAM;KACnB,GAAG,KAAK,IAAI,IAAI,GAAG,IAAI;KACvB,GAAG,KAAK,IAAI,IAAI,GAAG,IAAI;KACvB,GAAG,KAAK,IAAI,IAAI,GAAG,IAAI;IACzB,CAAC;IAED,OAAO;KAACA,KAAE,MAAM,IAAI,OAAO,CAAC;KAAGA,KAAE,MAAM,IAAI,OAAO,CAAC;KAAGA,KAAE,MAAM,IAAI,OAAO,CAAC;IAAC;GAC7E;GAIA,IAAI,QAAQ;GAEZ,SAAS;IACP,MAAM,UAAU,QAAQI;IACxB,MAAM,MAAM,KAAK,IAAI,OAAO;IAC5B,MAAM,MAAM,KAAK,IAAI,OAAO;IAC5B,MAAM,IAAIJ,KAAE,QAAQ,MAAM,OAAO;IAEjC,SAAS,KAAK;KAAC,GAAG,MAAM,QAAQ,OAAO,KAAK,GAAG;KAAG;KAAGA,KAAE,IAAI,MAAM,SAAS,MAAM,OAAO;IAAC,CAAC;IACzF,OAAO,KAAK,CAAC,GAAG,OAAO,MAAM,CAAC;IAC9B,SAAS,KAAK;KACZ,GAAG,MAAM,QAAQ,OAAO,KAAK,GAAG;KAChC;KACAA,KAAE,OAAO,MAAM,SAAS,MAAM,OAAO;IACvC,CAAC;IACD,OAAO,KAAK,CAAC,GAAG,OAAO,MAAM,CAAC;IAE9B,MAAM,MAAM,QAAQ;IAEpB,QAAQA,KAAE,GAAG;IACb,IAAI,EAAE,OAAO,IAAI;GACnB;GAEA,MAAM,KAAK,UAAU,OAAO,OAAO,UAAU,QAAQ,UAAU,CAAC;GAChE,IAAI;EACN;CACF;AACF;AAGA,MAAM,aACJ,OACA,OACA,SACA,QACA,eACS;CACT,MAAM,WAAW,IAAI,WAAW,QAAQ,SAASE,QAAM;CACvD,MAAM,OAAO,IAAI,aAAa,SAAS,MAAM;CAE7C,QAAQ,SAAS,CAAC,GAAG,GAAG,GAAG,GAAG,IAAI,OAAO;EACvC,MAAM,CAAC,GAAG,GAAG,GAAG,KAAK,OAAO;EAE5B,KAAK,IAAI;GAAC;GAAI;GAAI;EAAE,GAAI,KAAKA,WAAU,CAAC;EACxC,SAAS,IAAI;GAACG,OAAK,CAAE;GAAGA,OAAK,CAAE;GAAGA,OAAK,CAAE;GAAGA,OAAK,CAAE;EAAC,GAAG,KAAKH,WAAS,EAAE;EACvE,KAAK,IAAI,CAAC,GAAI,CAAE,IAAI,KAAKA,WAAS,MAAM,CAAC;CAC3C,CAAC;CAED,MAAM,OAAkB;EACtB,MAAM;EACN,SAAS;EACT,WAAW,UAAU;EACrB,QAAQD;EACR,QAAQ,CACN;GACE,YAAY;GACZ,aAAa;GACb,WAAW,QAAQ,SAAS;GAC5B,cAAc,QAAQ;GACtB,SAAS;EACX,CACF;EACA,SAAS,YAAY,KAAK,UAAU,GAAG,OAAO,EAAE;EAChD;CACF;CACA,MAAM,YAAsB;EAC1B,QAAQ;EACR,aAAa;EACb,aAAa,QAAQ;EACrB,YAAY;EACZ,YAAY,QAAQ;EACpB,YAAY;EACZ,YAAY;EACZ,aAAa;GAAE,KAAKE;GAAO,KAAKA;EAAM;EACtC,gBAAgB;GAAE,QAAQA;GAAO,QAAQ;EAAE;CAC7C;CACA,MAAM,EAAE,YAAY;CAEpB,OAAO;EACL;EACA;EACA,WAAW;EACX,YAAY;EACZ,OAAO,QAAQ;EACf,OAAO,QAAQ;EACf,cAAc;EACd,SAAS;GAAC;GAAG;GAAG;GAAG;EAAC;EACpB,SAASA;EACT,UAAUA;EACV,aAAa;EACb,OAAO;EAEP,GAAI,WAAW,EACb,SAAS;GAAE,MAAM,QAAQ;GAAM,OAAO;GAAS,SAAS;GAAiB,OAAO;EAAE,EACpF;EACA,MAAM;EACN;EACA,WAAW;EACX,WAAW;EACX,eAAe;EACf,kBAAkB;EAClB,OAAO;EACP,WAAW,UAAU,IAAI,UAAU;EACnC,OAAO;EACP,gBAAgB;EAChB,eAAe;CACjB;AACF;;AC/sBA,MAAMG,OAAI,KAAK;;AAqCf,MAAM,OAAO,SAAqB;CAChC,KAAK,QAAQ;CACb,KAAK,OAAO,SAAS,QAAQ;AAC/B;AAEA,IAAa,gBAAb,MAA2B;CACzB,wBAAQ,IAAI,IAAmB;CAC/B,sBAAe,IAAI,QAA2B;CAC9C,UAAU;;;;;;CAOV,MACE,YACA,EAAE,cAAc,CAAC,MAAyB,CAAC,GAC5B;EACf,MAAM,uBAAO,IAAI,IAAmB;EACpC,MAAM,SAAiB,CAAC;EAExB,KAAK,MAAM,EAAE,KAAK,OAAO,OAAO,SAAS,GAAG,SAAS,SAAS,cAAc,YAAY;GACtF,IAAI,OAAO,KAAK,MAAM,IAAI,GAAG,KAAK,KAAK,IAAI,GAAG;GAE9C,IAAI,CAAC,MAAM;IACT,MAAM,SAAS,MAAM;IAIrB,OAAO;KACL;KACA;KACA;KACA,KAAK;KACL,SAPA,YAAY,OAAO,KAAK,EAAE,WAAW,oBAAoB,OAAO,KAAK,EAAE,WAOnD;KACpB,QAAQ,KAAK;KACb,UAAU;KACV,OAAO;IACT;GACF;GAEA,KAAK,IAAI,KAAK,IAAI;GAClB,IAAI,KAAK,OAAO;GAChB,KAAK,QAAQ;GACb,KAAK,SAAS;GAEd,IAAI,YAAY,CAAC,KAAK,UAAU;IAC9B,KAAK,WAAW;IAChB,KAAK,OAAO,SAAS,KAAK;IAE1B,IAAI,KAAK,UAAU,KAAK,KAAK,UAAU,GAAG,KAAK,UAAU;GAC3D;GAEA,MAAM,EAAE,UAAU,SAAS,MAAM,YAAY,KAAK;GAElD,KAAK,SAAS;IACZ;IACA;IACA;IACA,GAAI,WAAW,EAAE,QAAQ;IACzB,UAAU;KAAE,GAAG,MAAM,EAAE;KAAG,GAAG,MAAM,EAAE;KAAG,GAAG,MAAM,EAAE;IAAE;IACrD,GAAI,WAAW,EAAE,QAAQ;IACzB,GAAI,WAAW,EAAE,QAAQ;GAC3B;GACA,KAAK,IAAI,IAAI,KAAK,QAAQ,IAAI;GAC9B,OAAO,KAAK,IAAI;EAClB;EAGA,KAAK,MAAM,CAAC,KAAK,SAAS,KAAK,OAC7B,IAAI,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,KAAK,OAAO,KAAK,OAAO,SAAS,QAAQ;EAElE,KAAK,QAAQ;EACb,OAAO,OAAO,MAAM,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,aAAa,MAAM;CAC9E;;;;;;;CAQA,KAAK,OAAmB,EAAE,eAAsD;EAC9E,MAAM,EAAE,UAAU,CAAC,GAAG,QAAQ,YAAY,WAAW;EACrD,MAAM,OAAO,QAAQ,iBAAiB,oBAAoB;EAC1D,MAAM,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,IAAI;EACzC,MAAM,OAAO,WAAW,MAAM;EAC9B,MAAM,QAAQ,YAAY,eAAe,CAAC;EAE1C,QAAQ,SAAS,QAAQ,OAAO;GAC9B,MAAM,OAAO,KAAK,IAAI,IAAI,MAAM;GAChC,IAAI,CAAC,QAAQ,KAAK,OAAO;GAEzB,MAAM,OAAO,YAAY;GACzB,IAAI,MAAM,SAAS,QAAQ;GAC3B,IAAI,MAAM,SAAS,OAAO,OAAO,IAAI,IAAI;GAEzC,IAAI,KAAK,UAAU,GAAG;IACpB,KAAK,UAAUA,KAAE,KAAK,UAAU,EAAE;IAClC,IAAI,KAAK,WAAW,GAAG,OAAO,IAAI,IAAI;GACxC;GAEA,IAAI,KAAK,OAAO,SAAS,UAAU,OAAO,IAAI,IAAI;GAClD,IAAI,MAAM,KAAK,MAAM,KAAK;GAE1B,MAAM,UACJ,MAAM,OAAO,KAAK,EAAE,mBAAmB,oBAAoB,OAAO,KAAK,EAAE;GAC3E,IAAI,MAAM,SAAS,SAAS,CAAC,SAAS;GACtC,KAAK,OAAO,SAAS,QAAQ,IAAI;IAC/B,WAAW,KAAK;IAChB;IACA,QAAQ,KAAK;IACb,KAAK,KAAK;GACZ,CAAC;EACH,CAAC;CACH;;CAGA,UAAgB;EACd,KAAK,MAAM,QAAQ,KAAK,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,OAAO,IAAI,IAAI;EACjE,KAAK,MAAM,MAAM;CACnB;;CAGA,MAAM,KAAmC;EACvC,OAAO,KAAK,MAAM,IAAI,GAAG,CAAC,EAAE;CAC9B;AACF;;;;;;;;;AC7JA,MAAMC,MAAI,KAAK;AAyDf,MAAM,OAAO;AAEb,MAAM,cAAcA,IAAE,EAAG;AACzB,MAAM,aAAa;AACnB,MAAM,aAAa;AAEnB,MAAM,cAAcA,IAAE,GAAI;AAC1B,MAAM,SAASA,IAAE,UAAU;AAC3B,MAAMC,OAAKD,IAAE,UAAU;AAGvB,MAAME,WAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAMC,WAAS;AAEf,MAAMC,UAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC1C,MAAM,QAAiB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAG1C,MAAM,OAAO;AAGb,MAAM,QAAQ,UAA2B,QAAQ,IAAI,QAAQ;;AAG7D,MAAM,QAAQ,OAAwB,IAAI,OAAO;AAEjD,IAAa,eAAb,MAA0B;CACxB;;CAEA;;;;;CAKA,WAAmB;;CAEnB;CACA;CACA;;CAEA;CACA;CACA;CACA;;CAEA;CACA;;CAEA;CACA;CACA,QAAgB;CAEhB,YAAY,UAAwB,OAAkB;EACpD,KAAK,WAAW;EAChB,KAAK,WAAW,MAAM;EAEtB,MAAM,QAAQ,SAAS,cAAc;EAGrC,KAAK,UAAU;GACb,GAAG,KAAKJ,IAAE,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;GACpC,GAAG,KAAKA,IAAE,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;GACpC,GAAG,KAAKA,IAAE,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;EACtC;EACA,KAAK,UAAU;GACb,GAAG,KAAKA,IAAE,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;GACpC,GAAG,KAAKA,IAAE,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;GACpC,GAAG,KAAKA,IAAE,MAAM,IAAI,MAAM,QAAQ,CAAC,CAAC;EACtC;EAEA,MAAM,QAAQ,MAAM,mBAAmBI;EAEvC,KAAK,WAAW;GAAE,GAAGJ,IAAE,MAAM,IAAI,GAAG;GAAG,GAAGA,IAAE,MAAM,IAAI,GAAG;GAAG,GAAGA,IAAE,MAAM,IAAI,GAAG;EAAE;EAEhF,MAAM,QAAQA,IAAE,MAAM,KAAK,CAAC;EAC5B,MAAM,QAAQ,MAAM,KAAK,IAAI,KAAM,QAAQA,IAAE,MAAM,KAAK,CAAC;EACzD,MAAM,SAASA,KAAG,SAAS,iBAAiB,KAAK,IAAI;EACrD,MAAM,SAASA,IAAE,SAAS,UAAU,GAAI;EACxC,MAAM,eAAe,KAAK,IAAI,KAAK,MAAM,SAAS,gBAAgB,CAAC,GAAG,CAAC;EAEvE,MAAM,QACJ,KAAK,MAAMA,IAAEA,IAAEA,IAAEA,IAAE,QAAQ,KAAK,IAAIC,IAAE,IAAID,IAAE,SAAS,MAAM,CAAC,IAAI,EAAG,CAAC,IAAI;EAC1E,MAAM,CAAC,OAAO,MAAM,KAAK,UAAU,SAAS,QAAQ;GAAC;GAAM;GAAM;GAAQ;EAAM,EAAA,CAAG,KAAK,MACrFA,IAAEA,IAAE,IAAI,MAAM,IAAIA,IAAE,IAAI,MAAM,CAAC,CACjC;EAEA,KAAK,QAAQ;GAAC;GAAO;GAAM;GAAK;EAAK;EACrC,KAAK,aAAaA,IAAE,SAAS,EAAG;EAEhC,MAAM,SAAS,SAAS,UAAU,EAAE,UAAU,EAAE;EAChD,MAAM,CAAC,SAAS,WACd,cAAc,SACV,CAACA,IAAE,QAAQ,OAAO,QAAQ,GAAGA,IAAE,QAAQ,OAAO,QAAQ,CAAC,IACvD,CAACA,IAAE,QAAQ,OAAO,OAAO,GAAGA,IAAE,QAAQ,OAAO,OAAO,CAAC;EAI3D,MAAM,YAAY,MAAM,KAAK,EAAE,QAAQ,MAAM,IAAI,GAAG,OAAO;GACzD,MAAM,QAAQA,IAAEA,IAAE,KAAK,KAAK,IAAI,MAAM;GACtC,MAAM,QAAQ;IAAE,GAAGA,IAAE,KAAK,IAAI,KAAK,IAAI,OAAO;IAAG,GAAG;IAAG,GAAGA,IAAE,KAAK,IAAI,KAAK,IAAI,OAAO;GAAE;GACvF,MAAM,SAAS,KAAK,UAAU,OAAO,MAAM,WAAW;GAEtD,OAAO;IACL,GAAGA,IAAEA,IAAE,OAAO,CAAC,IAAI,MAAM,SAAS,CAAC;IACnC,GAAGA,IAAEA,IAAE,OAAO,CAAC,IAAI,MAAM,SAAS,CAAC;IACnC,GAAGA,IAAEA,IAAE,OAAO,CAAC,IAAI,MAAM,SAAS,CAAC;GACrC;EACF,CAAC;EAGD,MAAM,WAAW,MAAe,OAAyB;GACvD,MAAM,KAAKA,IAAE,GAAG,IAAI,KAAK,CAAC;GAC1B,MAAM,KAAKA,IAAE,GAAG,IAAI,KAAK,CAAC;GAC1B,MAAM,SAASA,IAAE,KAAK,KAAKA,IAAE,KAAK,KAAK,KAAK,EAAE,CAAC,CAAC;GAEhD,OAAO;IAAE,GAAGA,IAAE,KAAK,MAAM;IAAG,GAAG;IAAG,GAAGA,IAAE,CAAC,KAAK,MAAM;GAAE;EACvD;EAEA,KAAK,SAAS,UAAU,KAAK,UAAU,OAAO;GAC5C,MAAM,WAAW,WAAW,KAAK,IAAI,SAAS;GAC9C,MAAM,OAAO,WAAW,KAAK,KAAK;GAClC,MAAM,IAAI,QAAQ,UAAU,IAAI;GAChC,MAAM,IAAI,QAAQ,UAAU,QAAQ;GACpC,MAAM,MAAM;IAAE,GAAGA,IAAE,EAAE,IAAI,EAAE,CAAC;IAAG,GAAGA,IAAE,EAAE,IAAI,EAAE,CAAC;GAAE;GAC/C,MAAM,SAAS,KAAK,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC;GAEtD,OAAO;IAAE;IAAU,QAAQ;KAAE,GAAGA,IAAE,IAAI,IAAI,MAAM;KAAG,GAAG;KAAG,GAAGA,IAAE,IAAI,IAAI,MAAM;IAAE;GAAE;EAClF,CAAC;EAID,IAAI,QAAQ,KAAK,IAAI,KAAK,MAAM,SAAS,eAAe,CAAC,GAAG,CAAC;EAC7D,IAAI,QAAQA,IAAE,QAAQ,EAAG,GAAG,QAAQ,KAAK,MAAMA,IAAE,QAAQ,EAAG,CAAC;EAE7D,MAAM,OAAOA,IAAE,QAAQ,KAAK;EAC5B,IAAI,QAAQ;EACZ,IAAI,QAAQ;EACZ,MAAM,SAAsB,CAAC;EAE7B,KAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,GAAG,SAAS;GACvD,QAAQA,IAAE,QAAQ,IAAI;GAEtB,MAAM,MAAM,KAAK,MAAMA,IAAE,QAAQA,IAAE,IAAM,CAAC,CAAC;GAC3C,MAAM,OAAO,MAAM;GACnB,IAAI,SAAS,QAAQ,KAAK,MAAMA,IAAE,OAAO,GAAI,CAAC;GAC9C,IAAI,UAAU,OAAO,UAAU;GAE/B,MAAM,IAAI,UAAU;GAIpB,MAAM,SAAS,KAAK,IAAI,WACb;IACL,MAAM,IAAI,UAAU,SAAS,KAAK,QAAQ,SAAS,IAAI,QAAQ,SAAS;IAExE,OAAO;KAAE,GAAGA,IAAEA,IAAE,EAAE,IAAI,EAAE,CAAC,IAAI,EAAG;KAAG,GAAGA,IAAEA,IAAE,EAAE,IAAI,EAAE,CAAC,IAAI,EAAG;KAAG,GAAGA,IAAEA,IAAE,EAAE,IAAI,EAAE,CAAC,IAAI,EAAG;IAAE;GACxF,EAAA,CAAG,IACH;GAEJ,MAAM,SAAS,UACbA,IAAE,KAAK,MAAMA,IAAE,OAAO,IAAI,MAAM,CAAC,GAAGA,IAAE,OAAO,IAAI,MAAM,CAAC,GAAGA,IAAE,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC;GACnF,MAAM,SAAS,KAAK,IAClB,MAAM,UAAU,SAAS,QAAQ,QAAQ,QAAQ,MAAO,GACxD,MAAM,UAAU,OAAO,QAAQ,MAAM,QAAQ,IAAK,CACpD;GAEA,OAAO,KAAK;IAAE,OAAO;IAAO,MAAM;IAAK;IAAQ;GAAO,CAAC;GACvD,QAAQ;EACV;EAEA,KAAK,SAAS;EAEd,KAAK,OAAO,IAAI,aAAa,KAAK,CAAC,CAAC,KAAK,CAAC;EAC1C,KAAK,SAAS,IAAI,WAAW,KAAK,CAAC,CAAC,KAAK,CAAC;EAC1C,KAAK,QAAQ,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,KAAK;EACtD,KAAK,OAAO,MAAM,KAAK,EAAE,QAAQ,MAAM,UAAU;GAAE,GAAGA,IAAE,EAAG;GAAG,GAAGA,IAAE,EAAG;GAAG,GAAGA,IAAE,EAAG;EAAE,EAAE;CACvF;;;;;;CAOA,OAAO,KAAc,WAAW,GAAS;EACvC,KAAK,WAAW;EAChB,IAAI,WAAW,MAAO;EAEtB,MAAM,CAAC,OAAO,MAAM,KAAK,SAAS,KAAK;EAEvC,KAAK,OAAO,SAAS,EAAE,UAAU,UAAU,OAAO;GAChD,MAAM,KAAKA,IAAE,IAAI,IAAI,SAAS,CAAC;GAC/B,MAAM,KAAKA,IAAE,IAAI,IAAI,SAAS,CAAC;GAC/B,MAAM,KAAKA,IAAE,IAAI,IAAI,SAAS,CAAC;GAC/B,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK;GACzC,IAAI;GACJ,IAAI,SAAS;GAEb,IAAI,UAAU,MAAM;IAClB,IAAI,UAAU,KAAK,OAAO;SACrB,IAAI,UAAU,OAAO,OAAO;SAC5B,OAAOA,KAAG,QAAQ,YAAY,QAAQ,IAAI;GACjD,OAAO,IAAI,UAAU,OAAO;IAC1B,OAAO;IACP,SAAS;GACX,OAAO,OAAOA,KAAG,UAAU,UAAU,OAAO,MAAM;GAElD,KAAK,KAAK,MAAM;GAChB,IAAI,EAAE,OAAO,MAAM,CAAC,QAAQ;GAE5B,MAAM,UAAU,IAAI,KAAK,KAAK,OAAO;GACrC,MAAM,MAAM,KAAK,UAAU,OAAO,IAAI,KAAK,UAAU,OAAO,IAAI,KAAK,UAAU,OAAO;GAEtF,KAAK,OAAO,MAAM,MAAM,IAAI,IAAI;GAEhC,MAAM,OAAOA,IAAE,KAAK,IAAI,GAAG,CAAC;GAE5B,IAAI,OAAO,aAAa,KAAK,KAAK,MAAM;QACnC,IAAI,OAAO,YAAY,KAAK,KAAK,MAAMA,IAAEA,IAAEA,IAAE,OAAO,WAAW,IAAI,IAAI,IAAI,UAAU;EAC5F,CAAC;CACH;;CAGA,IAAI,UAAmB;EACrB,OAAO,KAAK;CACd;;;;;;CAOA,KAAK,EAAE,SAAS,OAAO,UAA8B;EACnD,IAAI,SAAS,GAAG;EAEhB,MAAM,YAAYA,IAAE,KAAK,SAAS,oBAAoB,CAAC;EACvD,MAAM,UAAU,UAAkBA,IAAE,UAAU,KAAK,IAAI,UAAW;EAClE,MAAM,OAAO;GACX,GAAGA,IAAEA,IAAEA,IAAE,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,SAAS;GAC3E,GAAGA,IAAEA,IAAEA,IAAE,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,SAAS;GAC3E,GAAGA,IAAEA,IAAEA,IAAE,OAAO,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,SAAS;EAC7E;EACA,MAAM,EAAE,YAAY;EAGpB,MAAM,QAAQ,KAAK,OAAO,KAAK,EAAE,aAAa;GAC5C,MAAM,IAAI,EAAE,GAAG,KAAK;GACpB,MAAM,IAAI,EAAE,GAAG,KAAK;GAEpB,KAAK,MAAM,EAAE,WAAW,WAAW,QAAQ;IACzC,MAAM,MAAM,UAAU,IAAI,OAAO,IAAI,UAAU,IAAI,OAAO,IAAI,UAAU,IAAI,OAAO;IAGnF,IAAI,OAAQ,KAAK;KACf,MAAM,KAAK,OAAO,OAAQ;KAE1B,EAAE,IAAIA,IAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC;KACrC,EAAE,IAAIA,IAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC;KACrC,EAAE,IAAIA,IAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC;IACvC;IAEA,IAAI,OAAQ,CAAC,KAAK;KAChB,MAAM,KAAK,OAAO,OAAQ;KAE1B,EAAE,IAAIA,IAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC;KACrC,EAAE,IAAIA,IAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC;KACrC,EAAE,IAAIA,IAAE,EAAE,IAAI,MAAM,IAAI,QAAQ,IAAI,CAAC;IACvC;GACF;GAEA,MAAM,QAAQ,EAAE,GAAG,GAAG,SAAkB;IACtC,GAAG,KAAK,IAAI,GAAG,CAAC;IAChB,GAAG,KAAK,IAAI,GAAG,CAAC;IAChB,GAAG,KAAK,IAAI,GAAG,CAAC;GAClB;GAEA,OAAO;IAAE,OAAO,KAAK,CAAC;IAAG,MAAM,KAAK,CAAC;GAAE;EACzC,CAAC;EAED,KAAK,QAAQ,MAAM,KAAK,EAAE,YAAY,KAAK;EAC3C,KAAK,OAAO,MAAM,KAAK,EAAE,WAAW,IAAI;EACxC,KAAK,QAAQ;CACf;;;;;;;CAQA,UAAU,OAAiC;EACzC,MAAM,EAAE,aAAa;EACrB,MAAM,EAAE,UAAU,KAAK;EACvB,IAAI,CAAC,SAAS,WAAW,aAAa,OAAO,KAAA;EAE7C,MAAM,QAAQ,KAAK,OAAO,UAAU,KAAK,OAAO;EAChD,IAAI,CAAC,OAAO,OAAO,KAAA;EAEnB,MAAM,QAAQ,KAAK,OAAO;EAC1B,MAAM,eAAe,KAAK,IAAI,KAAK,MAAM,KAAK,SAAS,gBAAgB,CAAC,GAAG,CAAC;EAC5E,MAAM,UAAUA,IAAE,IAAI,YAAY;EAClC,MAAM,OAAO,KAAK,SAAS,YAAY;EACvC,MAAM,UAAoB,CAAC;EAC3B,MAAM,UAAoB,CAAC;EAC3B,IAAI,SAAS;EACb,IAAI,OAAO;EAEX,KAAK,IAAI,OAAO,GAAG,OAAO,GAAG,QAAQ;GACnC,IAAI,OAAO,MAAM,QAAQ,MAAM,SAAS,MAAM,MAAM;GAEpD,KAAK,IAAI,KAAK,MAAM,OAAO,KAAK,MAAM,MAAM,MAAM;IAEhD,IAAI,OAAO,cAAc;KACvB,UAAU;KACV,QAAQ;IACV;IAEA,MAAM,QAAQ,KAAK,KAAK,QAAQ,KAAK,IAAI,QAAQ,KAAK;IACtD,MAAM,CAAC,QAAQ,UAAU,CAAC,KAAK,OAAO,KAAM,KAAK,OAAO,MAAO;IAG/D,IAFc,SAAS,IAAI,WAAW,KAAK,WAAW,IAAI,WAAW,KAAK,WAAW,GAE1E;KACT,MAAM,OAAO,OAAe,UAAkB;MAC5C,IAAI,QAAQ,KAAK,KAAK;MACtB,IAAK,UAAU,KAAK,SAAS,KAAO,UAAU,KAAK,SAAS,GAAI,QAAQ;MACxE,OAAO;OAAE;OAAO,OAAO,UAAU,IAAI,KAAK,KAAK,SAAU,KAAK,MAAM;MAAQ;KAC9E;KAEA,MAAM,IAAI,IAAI,IAAI,MAAM;KACxB,MAAM,IAAI,IAAI,OAAO,MAAM;KAE3B,IAAI,EAAE,EAAE,QAAQ,gBAAgB,EAAE,EAAE,QAAQ,cAAc;MACxD,MAAM,KAAKA,IAAE,SAAS,OAAO;MAC7B,MAAM,KAAKA,IAAE,OAAO,OAAO;MAC3B,MAAM,OAAO,KAAK;MAClB,MAAM,KAAK,KAAK,OAAO,GAAG,CAAE;MAC5B,MAAM,KAAK,KAAK,OAAO,MAAM,CAAE;MAC/B,MAAM,YAAY,EAAE,SAAmB,UAAkB;OACvD,KAAK,MAAM,CAAC;OACZ,KAAK,MAAM,CAAC;OACZ,KAAK,MAAM,CAAC;OACZ,KAAK,KAAK;MACZ;MACA,MAAM,KAAK,SAAS,GAAG,WAAW,EAAE,QAAQ,WAAW,EAAE,KAAK;MAC9D,MAAM,KAAK,SAAS,GAAG,WAAW,EAAE,QAAQ,WAAW,EAAE,KAAK;MAC9D,MAAM,OAAO,MAAe;OAAC,EAAE;OAAGA,IAAE,EAAE,IAAI,IAAI;OAAG,EAAE;MAAC;MACpD,MAAM,UAAU,MAAe;OAAC,EAAE;OAAGA,IAAE,EAAE,IAAI,IAAI;OAAG,EAAE;MAAC;MAGvD,KAAK,MAAM,CAAC,QAAQ,QAAQ,GAAG,MAAM;OACnC;QAAC,IAAI,EAAE;QAAG;QAAI;QAAI;OAAC;OACnB;QAAC,OAAO,EAAE;QAAG;QAAI;QAAI;OAAC;OACtB;QAAC,OAAO,EAAE;QAAG;QAAI;QAAI;OAAC;OACtB;QAAC,OAAO,EAAE;QAAG;QAAI;QAAI;OAAC;OACtB;QAAC,IAAI,EAAE;QAAG;QAAI;QAAI;OAAC;OACnB;QAAC,IAAI,EAAE;QAAG;QAAI;QAAI;OAAC;MACrB,GAAY;OACV,QAAQ,KAAK,GAAG,QAAQ,GAAG,CAAC;OAC5B,QAAQ,KAAK,GAAG,MAAM;MACxB;KACF;IACF;IAEA;IACA;GACF;EACF;EAEA,MAAM,cAAc,QAAQ,SAAS;EACrC,IAAI,gBAAgB,GAAG,OAAO,KAAA;EAE9B,MAAM,WAAW,IAAI,WAAW,cAAcG,QAAM;EACpD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;EAG/C,KAAK,IAAI,KAAK,GAAG,KAAK,aAAa,MAAM;GACvC,OAAO,IAAI,QAAQ,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC,GAAI,KAAKA,WAAU,CAAC;GAC/D,SAAS,IAAI,QAAQ,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC,GAAG,KAAKA,WAAS,EAAE;GAChE,OAAO,IAAI,QAAQ,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,CAAC,IAAI,KAAKA,WAAS,MAAM,CAAC;EAC1E;EA+BA,OAAO;GACL,MAAA;IA7BA,MAAM;IACN,SAAS;IACT,WAAW,UAAU;IACrB,QAAQD;IACR,QAAQ,CACN;KACE,YAAY;KACZ,aAAa;KACb,WAAW,cAAc;KACzB,cAAc;KACd,SAAS;IACX,CACF;IACA,SAAS,YAAY,KAAK,EAAE,QAAQ,YAAY,IAAI,GAAG,OAAO,EAAE;IAChE;GAeG;GACH,WAAA;IAbA,QAAQ;IACR,aAAa;IACb;IACA,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,aAAa;KAAE,KAAK,MAAM;KAAQ,KAAK,MAAM;IAAO;IACpD,gBAAgB;KAAE,QAAQ,MAAM;KAAQ,QAAQ,MAAM;IAAO;GAKrD;GACR,WAAW;GACX,YAAY;GACZ,OAAO;GACP,OAAO,QAAQ;GACf,cAAc;GACd,SAAS;IAAC;IAAG;IAAG;IAAG;GAAC;GACpB,SAASE;GACT,UAAUA;GACV,aAAa;GACb,OAAO;GACP,SAAS;IACP,MAAM,MAAM,QAAQ;IACpB,OAAO,MAAM;IACb,SAAS;IACT,OAAO;GACT;GACA,MAAM;GACN,YAAY;GAEZ,WAAW;GACX,WAAW;GACX,eAAe;GACf,kBAAkB;GAClB,OAAO;GACP,WAAW;GACX,OAAO;GAEP,gBAAgB;GAChB,eAAe;EACjB;CACF;AACF;;;;;;;;ACnfA,MAAMC,MAAI,KAAK;AAwCf,MAAa,0BAAqD;CAChE,MAAMA,IAAE,EAAG;CACX,QAAQA,IAAE,EAAG;CACb,OAAOA,IAAE,EAAG;AACd;;AAGA,MAAa,wBAAmD;CAC9D,MAAM;CACN,QAAQA,IAAE,EAAG;CACb,OAAOA,IAAE,GAAG;AACd;AAmBA,MAAM,SAAS,YAAY,aAAa,WAAW,aAAa,SAAS,CAAC;AAC1E,MAAM,SAAS;AAEf,MAAM,QAAQ;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAYjC,MAAM,WAAWA,IAAE,EAAG;AAEtB,IAAa,SAAb,MAAoB;CAClB;CACA;CACA;CACA,SAAiB,CAAC;;CAElB;;CAEA;CACA,QAAQ;CACR,UAAU;CACV,UAAU;;CAEV,UAAmB;;CAEnB;CAEA,YACE,UACA,EACE,aAAa,yBACb,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAM,GAChD,SAAS,MAC6D,CAAC,GACzE;EACA,KAAK,WAAW;EAChB,KAAK,aAAa;EAClB,KAAK,SAAS;EAEd,MAAM,IAAI,IAAI,KAAK;EAEnB,KAAK,MAAM;GAAE,GAAGA,IAAE,CAAC;GAAG,GAAGA,IAAE,CAAC;GAAG,GAAG;EAAE;EAEpC,MAAM,aAAaA,IAAE,SAAS,cAAc,EAAE;EAC9C,MAAM,cAAcA,IAAE,SAAS,eAAe,IAAI;EAElD,KAAK,SAASA,IAAE,cAAc,KAAM,UAAU;EAG9C,MAAM,CAAC,QAAQ,SAAS,YAAY,CAAC,IAAI,GAAG;EAE5C,IAAI,OAAO,GAAG;GACZ,MAAM,MAAM,KAAK,IAAI,iBAAkB;GACvC,MAAM,IAAIA,IAAG,KAAK,SAASA,IAAE,EAAG,IAAK,MAAM,IAAI;GAC/C,MAAM,KAAK,MAAM,OAAO,aAAaA,IAAE,GAAG,KAAK;GAC/C,IAAI,IAAI,IAAI,KAAK,SAAS,IAAI,KAAK,KAAK,KAAK,SAAS,KAAK,SAAS,IAAI,CAAC;GACzE,IAAI,IAAI,GAAG,IAAI;GAEf,MAAM,SAAS,IAAI,OAAO,KAAK;GAE/B,KAAK,QAAQ,SAAS,IAAI,IAAIA,IAAE,MAAM;EACxC,OAAO,KAAK,QAAQ;EAGpB,MAAM,IAAI,IAAI;EACd,MAAM,aAAaA,IAAE,KAAM,IAAI,MAAM;EACrC,MAAM,OAAO,IAAI,IAAI;EACrB,MAAM,YAAYA,KAAG,IAAI,QAAQA,IAAE,IAAK,IAAI,IAAI;EAGhD,MAAM,QAAQ,KAAK,MAAM,SAAS,YAAY,aAAa,EAAG;EAC9D,MAAM,UAAU,KAAK,SAAS;EAC9B,MAAM,SAAS,SAAS,UAAU;EAClC,MAAM,SAAS,SAAS,UAAU;EAElC,KAAK,IAAI,QAAQ,GAAG,QAAQ,OAAO,SAAS;GAC1C,MAAM,WAAW,aAAa,QAAQ,KAAK,MAAM;GACjD,MAAM,OAAOA,KACV,OAAO,IAAIC,cAAY,qBAAsBD,IAAE,EAAG,KAAKA,IAAE,aAAa,SAAS,CAClF;GACA,MAAM,IAAI,OAAO,IAAIC;GACrB,MAAM,QAAQ;IACZ,GAAGD,IAAEA,IAAE,OAAO,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC;IAC1C,GAAGA,IAAEA,IAAEA,IAAE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;IAC7C,GAAGA,IAAEA,IAAEA,IAAE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC;GAC/C;GAEA,IAAI,QAAQ,KAAK,MAAO,OAAO,IAAI,QAAQ,SAAU,KAAK;GAC1D,MAAM,OAAOA,IAAE,OAAO,IAAIC,WAAS;GACnC,IAAI,UAAU;GAEd,KAAK,IAAI,KAAK,GAAG,KAAK,QAAQ,QAAQ,MAAM;IAC1C,WAAW,QAAQ;IAEnB,IAAI,OAAO,SAAS;KAClB,QAAQ;KACR;IACF;GACF;GAEA,MAAM,WAAW,aAAa,QAAQD,IAAE,SAAS,SAAS,CAAC,CAAC;GAC5D,MAAM,YAAY,SAAS;GAC3B,MAAM,QACJ,aAAa,UAAU,WAAW,IAC9BA,KAAG,oBAAqB,OAAO,IAAIC,cAAY,oBAAqB,UAAU,GAAG,IACjF;GAEN,KAAK,OAAO,KAAK;IACf;IACA;IACA;IACA;IACA;IACA;IACA,OAAO;IACP,QAAQ;IACR,QAAQ;IACR,OAAO;GACT,CAAC;EACH;CACF;;;;;CAMA,YAAY,OAAoC,UAA6C;EAC3F,MAAM,EAAE,QAAQ,aAAa;EAE7B,KAAK,OAAO,SAAS,MAAM,UAAU;GACnC,IAAI,SAAS,KAAK,SAAS;IACzB,KAAK,SAAS;IACd,KAAK,SAAS;IACd;GACF;GAEA,MAAM,SAAS,aAAa,QAAQ,KAAK,MAAM;GAE/C,KAAK,WAAW;IACd,GAAGD,IAAE,KAAK,QAAQ,IAAI,OAAO,CAAC;IAC9B,GAAGA,IAAE,KAAK,QAAQ,IAAI,OAAO,CAAC;IAC9B,GAAGA,IAAE,KAAK,QAAQ,IAAI,OAAO,CAAC;GAChC;GACA,KAAK,WAAW,aAAa,QAAQA,IAAE,SAAS,SAAS,CAAC,CAAC;GAE3D,MAAM,SAAS,UAAU,KAAA,KAAa,MAAM,KAAK,QAAQ,IAAI;GAE7D,KAAK,SAAS;GACd,KAAK,SAAS,CAAC,UAAW,aAAa,KAAA,KAAa,SAAS,KAAK,QAAQ,IAAI;EAChF,CAAC;CACH;;CAGA,WAAqB;EACnB,MAAM,EAAE,QAAQ,UAAU,CAAC,MAAM,KAAK;EACtC,MAAM,MAAM,OAAO,KAAK,GAAG,OAAO,QAAQ,OAAO,CAAC;EAClD,MAAM,MAAM,IAAI,QAAQ,OAAO,WAAW,QAAQ,QAAQ,CAAC;EAE3D,OAAO,IAAI,KAAK,WAAWA,IAAE,SAAS,GAAG,CAAC;CAC5C;;CAGA,IAAI,SAAiB;EACnB,OAAO,KAAK;CACd;CAEA,IAAI,QAAmC;EACrC,OAAO,KAAK;CACd;;CAGA,OAAa;EACX,MAAM,OAAO,KAAK,OAAO,MAAM,EAAE,QAAQ,aAAa,UAAU,CAAC,MAAM;EAEvE,IAAI,MAAM,KAAK,QAAQ;CACzB;;;;;;CAOA,OACE,QACA,MACA,YACA,OACA,UACM;EACN,MAAM,EAAE,UAAU,WAAW;EAC7B,MAAM,QAAQ,KAAK,OAAO;EAE1B,KAAK,UAAU,KAAK,IAClB,KAAK,IAAI,KAAK,MAAO,aAAa,KAAK,WAAW,SAAU,KAAK,GAAG,CAAC,GACrE,KACF;EACA,KAAK,QACH,aAAa,KAAK,WAAW,OACzB,IACA,cAAc,IACZ,IACA,aAAa,KAAK,WAAW;EAErC,MAAM,QAAQA,IAAE,KAAK,QAAQ,KAAK,MAAM;EACxC,MAAM,OAAOA,IAAE,KAAK,SAAS,KAAK,SAASA,IAAE,IAAI,CAAC;EAClD,MAAM,QAAQ,QAAQ,wBAAwB,OAAO,aAAa,OAAO,QAAQ;EACjF,MAAM,EAAE,GAAG,GAAG,MAAM,QAAQ,eAAe;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG,CAAC;EAAM,GAAG,KAAK;EAE3E,KAAK,UAAU;GAAE,GAAGA,IAAE,CAAC;GAAG,GAAGA,IAAE,CAAC;GAAG,GAAGA,IAAE,CAAC;EAAE;EAE3C,IAAI,SAAS;EAEb,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,KAAK,SAAS,GAAG;IACnB,KAAK,SAAS;IACd,KAAK,SAAS;GAChB;GAEA,IAAI,CAAC,KAAK,QAAQ;GAElB,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,SAAS;GAC1C,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,SAAS;GAC1C,MAAM,KAAK,KAAK,QAAQ,IAAI,KAAK,SAAS;GAE1C,IAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM;IACtC,KAAK,SAAS;IACd,KAAK,SAAS;GAChB,OAAO;EACT;EAGA,KAAK,OAAO,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;EAE5C,MAAM,YAAY,SAAS;EAE3B,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,CAAC,KAAK,UAAU,SAAS,KAAK,SAAS;IACzC,MAAM,KAAK,SAAS,MAAM;IAC1B,MAAM,WAAW;KACf,GAAGA,IAAE,KAAK,SAAS,GAAG,IAAI,KAAK,QAAQ,CAAC;KACxC,GAAGA,IAAE,KAAK,SAAS,GAAG,IAAI,KAAK,QAAQ,CAAC;KACxC,GAAGA,IAAEA,IAAE,KAAK,SAAS,GAAG,CAAC,IAAI,KAAK,QAAQ,CAAC;IAC7C;IAEA,KAAK,WAAW;IAChB,KAAK,WAAW,aAAa,QAAQA,IAAE,SAAS,SAAS,CAAC,CAAC;IAE3D,IAAI,cAAc,KAAK,WAAW,SAAU,SAAS,MAAM,QAAQ,IAAI,GAAI;KACzE;KACA,KAAK,SAAS;KACd,KAAK,SAAS,aAAa,KAAA,KAAa,SAAS,QAAQ,IAAI;IAC/D;GACF;GAEA,IAAI,CAAC,KAAK,UAAU,KAAK,QAAQ;GAEjC,IAAI,aAAa,UAAU,WAAW,GAAG;IACvC,MAAM,MAAM,KAAK;IAEjB,KAAK,QAAQA,IAAE,OAAO,GAAG;IAEzB,IAAI,OAAO,GACL;SAAA,KAAK,QAAQ,UAAU,UACzB,KAAK,QAAQA,KACV,oBAAqB,OAAO,IAAIC,cAAY,oBAAqB,UAAU,GAC9E;IAAA,OACG,IAAI,KAAK,SAAS,GAAG;KAG1B,OAAO;KACP,OAAO;IACT;IAEA,IAAI,KAAK,SAAS,GAAG;KACnB,MAAM,IAAID,IAAE,OAAO,IAAIC,WAAS;KAEhC,KAAK,QAAQD,IAAE,OAAO,IAAI,IAAIC,WAAS;IACzC;GACF;GAEA,MAAM,IAAI,KAAK;GAEf,KAAK,WAAW;IACd,GAAGD,IAAE,OAAO,KAAK,SAAS,IAAI,EAAE,CAAC;IACjC,GAAGA,IAAE,OAAO,KAAK,SAAS,IAAI,EAAE,CAAC;IACjC,GAAGA,IAAEA,IAAE,OAAO,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;GACtC;EACF;EAEA,KAAK,UAAU;CACjB;;;;;;;CAQA,KAAK,QAAgB,EAAE,MAAM,OAAO,OAAO,aAA+B,CAAC,GAAqB;EAC9F,MAAM,EAAE,aAAa;EAErB,IAAI,KAAK,KAAK,YAAY,OAAO,QAAQ;EAEzC,MAAM,QAAQ,SAAS,OAAO;EAC9B,IAAI,KAAK,YAAY,KAAK,CAAC,OAAO,OAAO,KAAA;EAEzC,MAAM,OAAO,WAAW,MAAM;EAC9B,MAAM,QAAQ,QAAQ,OAAO,IAAI;EAGjC,MAAM,IAAI,QAAQ,mBAAmB;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE,GAAG,KAAK;EAChE,MAAM,IAAI,KAAK;EACf,MAAM,KAAK;GACT,GAAGA,IAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;GAC1B,GAAGA,IAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;GAC1B,GAAGA,IAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;EAC5B;EACA,IAAI,KAAK;GACP,GAAGA,IAAE,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC;GAC5B,GAAGA,IAAE,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC;GAC5B,GAAGA,IAAE,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,CAAC;EAC9B;EACA,MAAM,UAAU,YAAYA,IAAE,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC;EAEtE,KAAK;GAAE,GAAGA,IAAE,UAAU,GAAG,CAAC;GAAG,GAAGA,IAAE,UAAU,GAAG,CAAC;GAAG,GAAGA,IAAE,UAAU,GAAG,CAAC;EAAE;EACxE,KAAK,MAAM;EAGX,MAAM,IAAI,QAAQ,mBAAmB,IAAI,IAAI;EAC7C,MAAM,KAAK,YAAYA,IAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;EAC/C,MAAM,IAAI;GAAE,GAAGA,IAAE,EAAE,IAAI,EAAE;GAAG,GAAGA,IAAE,EAAE,IAAI,EAAE;GAAG,GAAG;EAAE;EACjD,IAAI,IAAI;GAAE,GAAG,EAAE;GAAG,GAAG,CAAC,EAAE;GAAG,GAAG;EAAE;EAChC,MAAM,KAAK,YAAYA,IAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;EAE3D,IAAI;GAAE,GAAGA,IAAE,EAAE,IAAI,EAAE;GAAG,GAAGA,IAAE,EAAE,IAAI,EAAE;GAAG,GAAG;EAAE;EAE3C,MAAM,gBAAgBA,IAAE,KAAK,SAAS,KAAK,MAAM;EACjD,MAAM,QAAQA,IAAE,KAAK,SAASA,IAAE,EAAG,CAAC;EACpC,MAAM,eAAeA,IAAE,QAAQ,KAAK;EACpC,MAAM,OAAOA,IAAE,KAAK,gBAAgB,aAAa;EACjD,MAAM,CAAC,SAAS,aAAa,SAAS,YAAY,CAAC,IAAI,GAAG,EAAA,CAAG,IAAIA,GAAC;EAClE,MAAM,WAAWA,IAAE,KAAK,WAAW,QAAQ;EAC3C,MAAM,QAAQA,IAAE,KAAK,QAAQ,KAAK,MAAM;EACxC,MAAM,YAAYA,IAAE,QAAQA,IAAE,EAAG,CAAC;EAClC,MAAM,YAAY,SAAS;EAC3B,MAAM,YAAY,WAAW,aAAa;EAE1C,MAAM,UAAoB,CAAC;EAC3B,MAAM,UAAoB,CAAC;EAE3B,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,IAAI,QAAQA,IAAEA,IAAE,SAAS,YAAY,GAAI,IAAI,KAAK,KAAK;GAEvD,IAAI,CAAC,KAAK,UAAU,KAAK,QAAQ;GAEjC,MAAM,KAAK,QAAQ,eAAe,KAAK,UAAU,IAAI;GACrD,MAAM,QAAQ,CAAC,GAAG;GAElB,KAAK,QAAQA,IAAE,KAAK;GACpB,IAAI,QAAQ,SAAS;GAIrB,IAAI,QAAQ,WAAW;IACrB,MAAM,KAAK,IAAI,GAAG;IAClB,MAAM,KAAK,IAAI,GAAG;IAClB,MAAM,KAAK,CAAC,QAAQ,GAAG;IACvB,MAAM,UAAU,KAAK,KAAK,KAAK,KAAK,KAAK;IACzC,IAAI,UAAU,eAAe;IAC7B,IAAIA,IAAE,OAAO,IAAI,cAAc,QAAQA,KAAG,gBAAgBA,IAAE,OAAO,KAAK,QAAQ,IAAI;GACtF;GAEA,IAAI,QAAQ,KAAM;GAElB,IAAI,OAAO;GAEX,IAAI,KAAK,SAAS,SAAS;GAC3B,IAAI,KAAK,QAAQ,UAAU,OAAOA,KAAG,KAAK,QAAQ,WAAW,QAAQ,QAAQ;GAC7E,IAAI,OAAO,KAAM;GAEjB,IAAI,QAAQ,KAAK;GAEjB,IAAI,aAAa,CAAC,SAAS,gBAAgB,YAAY,KAAK,KAAK,SAAS,GAAG;IAC3E,MAAM,SAAS,MAAcA,IAAEA,IAAE,IAAI,KAAK,KAAK,IAAI,SAAS;IAC5D,MAAM,MAAM;KACV,GAAGA,IAAE,MAAM,IAAI,MAAM,UAAU,MAAM,CAAC,CAAC;KACvC,GAAGA,IAAE,MAAM,IAAI,MAAM,UAAU,MAAM,CAAC,CAAC;KACvC,GAAGA,IAAE,MAAM,IAAI,MAAM,UAAU,MAAM,CAAC,CAAC;IACzC;IAEA,QAAQ;KAAE,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC;KAAG,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC;KAAG,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC;IAAE;GAChF;GAEA,MAAM,QAAQ,SAAS,OAAO,KAAK;GACnC,IAAI,CAAC,OAAO;GAGZ,MAAM,QAAQ,UAAkB,KAAK,MAAM,QAAQ,GAAG,IAAI;GAC1D,MAAM,UAAU;IAAC,KAAK,MAAM,CAAC;IAAG,KAAK,MAAM,CAAC;IAAG,KAAK,MAAM,CAAC;IAAG,KAAK,IAAI;GAAC;GAGxE,MAAM,KAAK;IAAE,GAAGA,IAAE,EAAE,IAAI,KAAK,IAAI;IAAG,GAAGA,IAAE,EAAE,IAAI,KAAK,IAAI;GAAE;GAC1D,MAAM,KAAK;IAAE,GAAGA,IAAE,EAAE,IAAI,KAAK,IAAI;IAAG,GAAGA,IAAE,EAAE,IAAI,KAAK,IAAI;GAAE;GAC1D,MAAM,IAAIA,IAAE,GAAG,CAAC;GAChB,MAAM,KAAKA,IAAE,GAAG,CAAC;GACjB,MAAM,KAAKA,IAAE,GAAG,CAAC;GACjB,MAAM,KAAK;IAACA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAGA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAG;GAAC;GAC7D,MAAM,MAAM;IAACA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAGA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAG;GAAC;GAC9D,MAAM,KAAK;IAACA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAGA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAG;GAAC;GAC7D,MAAM,KAAK;IAACA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAGA,IAAEA,IAAE,KAAK,GAAG,CAAC,IAAI,GAAG,CAAC;IAAG;GAAC;GAC7D,MAAM,KAAK;IACT,CAAC,MAAM,IAAI,MAAM,EAAE;IACnB,CAAC,MAAM,IAAI,MAAM,EAAE;IACnB,CAAC,MAAM,IAAI,MAAM,EAAE;IACnB,CAAC,MAAM,IAAI,MAAM,EAAE;IACnB,CAAC,MAAM,IAAI,MAAM,EAAE;IACnB,CAAC,MAAM,IAAI,MAAM,EAAE;GACrB;GACC;IAAC;IAAI;IAAK;IAAI;IAAI;IAAI;GAAE,CAAC,CAAC,SAAS,QAAQ,MAAM;IAChD,QAAQ,KAAK,GAAG,QAAQ,GAAG,GAAG,EAAG;IACjC,QAAQ,KAAK,GAAG,OAAO;GACzB,CAAC;EACH;EAEA,MAAM,cAAc,QAAQ,SAAS;EACrC,IAAI,gBAAgB,GAAG,OAAO,KAAA;EAE9B,MAAM,WAAW,IAAI,WAAW,cAAc,MAAM;EACpD,MAAM,SAAS,IAAI,aAAa,SAAS,MAAM;EAE/C,KAAK,IAAI,KAAK,GAAG,KAAK,aAAa,MAAM;GACvC,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,KAAK,QAAQ,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC;GAExD,OAAO,IAAI;IAAC;IAAI;IAAI;GAAE,GAAI,KAAK,SAAU,CAAC;GAC1C,SAAS,IAAI,QAAQ,MAAM,KAAK,GAAG,KAAK,IAAI,CAAC,GAAG,KAAK,SAAS,EAAE;GAChE,OAAO,IAAI,CAAC,GAAI,CAAE,IAAI,KAAK,SAAS,MAAM,CAAC;EAC7C;EA+BA,OAAO;GACL,MAAA;IA7BA,MAAM;IACN,SAAS;IACT,WAAW,UAAU;IACrB,QAAQ;IACR,QAAQ,CACN;KACE,YAAY;KACZ,aAAa;KACb,WAAW,cAAc;KACzB,cAAc;KACd,SAAS;IACX,CACF;IACA,SAAS,YAAY,KAAK,EAAE,QAAQ,YAAY,IAAI,GAAG,OAAO,EAAE;IAChE;GAeG;GACH,WAAA;IAbA,QAAQ;IACR,aAAa;IACb;IACA,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,aAAa;KAAE,KAAK;KAAO,KAAK;IAAM;IACtC,gBAAgB;KAAE,QAAQ;KAAO,QAAQ;IAAE;GAKnC;GACR,WAAW;GACX,YAAY;GACZ,OAAO;GAEP,OAAO;GACP,cAAc;GACd,SAAS;IAAC;IAAG;IAAG;IAAG;GAAC;GACpB,SAAS;GACT,UAAU;GACV,aAAa;GACb,OAAO;GACP,SAAS;IACP,MAAM,MAAM,QAAQ;IACpB,OAAO,MAAM;IACb,SAAS;IACT,OAAO;GACT;GACA,MAAM;GACN,YAAY;GACZ,WAAW;GACX,WAAW;GACX,eAAe;GACf,kBAAkB;GAGlB,OAAO;GACP,WAAW;GACX,OAAO;GACP,gBAAgB;GAChB,eAAe;EACjB;CACF;AACF;;;ACzYA,MAAa,gBAAgB,SAA2C;CAEtE,MAAM,QAAQ,SAAuB,KAAK,WAAW,QAAQ,QAAQ,IAAI,SAAS,IAAI,CAAC,CAAC,GAAG,EAAE;CAE7F,MAAM,QAAQ,MAAoB,WAAW,UAAU;EACrD,MAAM,QAAQ,KAAK,IAAI;EAEvB,OAAO,OAAO,SAAS,YAAY,MAAM,QAAQ;CACnD;CAEA,MAAM,UAAU,MAAoB,aAAqB;EACvD,MAAM,QAAQ,KAAK,IAAI;EAEvB,OAAO,OAAO,SAAS,WAAW,OAAO,SAAS,YAAY,MAAM,QAAQ;CAC9E;CAEA,MAAM,QAAQ,SAAuB;EACnC,MAAM,QAAQ,KAAK,IAAI;EAEvB,OAAO,OAAO,SAAS,WAAW,MAAM,QAAQ,KAAA;CAClD;CAEA,MAAM,SAAS,SAAuB;EACpC,MAAM,QAAQ,KAAK,IAAI;EAEvB,OAAO,OAAO,SAAS,kBAAkB,MAAM,QAAQ,KAAA;CACzD;CAEA,MAAM,SAAS,SAAuB;EACpC,MAAM,QAAQ,KAAK,IAAI;EAEvB,OAAO,OAAO,SAAS,kBAAkB,MAAM,QAAQ,KAAA;CACzD;CAEA,MAAM,cAAc;EAClB,MAAM,QAAQ,KAAK,gBAAgB;EAEnC,OAAO,OAAO,SAAS,kBAAkB,MAAM,QAAQ,KAAA;CACzD;CAEA,MAAM,cAAc;EAClB,MAAM,QAAQ,KAAK,oBAAoB;EAEvC,OAAO,OAAO,SAAS,aAAa,MAAM,QAAQ,KAAA;CACpD;CAEA,MAAM,eAAe,SAAuB;EAC1C,MAAM,QAAQ,KAAK,IAAI;EAEvB,OAAO,OAAO,SAAS,cAAc,MAAM,QAAQ,KAAA;CACrD;CAEA,MAAM,SAAiB;EACrB,MAAM,KAAK,WAAW,KAAK;EAC3B,UAAU,OAAO,iBAAiB,CAAC;EACnC,WAAW,YAAY,gBAAgB;CACzC;CACA,MAAM,iBAAgC;EACpC,GAAG;EACH,UAAU;EACV,UAAU,MAAM,kBAAkB;EAClC,kBAAkB,OAAO,4BAA4B,CAAC;EACtD,WAAW,MAAM,mBAAmB;EACpC,cAAc,MAAM,sBAAsB;EAC1C,cAAc,MAAM,sBAAsB;EAC1C,UAAU,MAAM,kBAAkB;EAClC,WAAW,MAAM,mBAAmB;EACpC,kBAAkB,MAAM,0BAA0B;CACpD;CACA,MAAM,oBAAsC;EAC1C,GAAG;EACH,UAAU;EACV,UAAU,MAAM,qBAAqB;CACvC;CACA,MAAM,gBAAwB;EAC5B,OAAO,MAAM;EACb,OAAO,MAAM,gBAAgB;EAC7B,SAAS,KAAK,kBAAkB;EAChC,OAAO,MAAM;EACb,UAAU,MAAM,mBAAmB;EACnC,gBAAgB,MAAM,yBAAyB;EAC/C,mBAAmB,KAAK,4BAA4B;EACpD,OAAO,KAAK,mBAAmB;EAC/B,OAAO,KAAK,mBAAmB;CACjC;CACA,MAAM,eAA4B;EAAE,GAAG;EAAQ,UAAU;CAAQ;CAEjE,QAAQ,KAAK,MAAb;EACE,KAAK,iBACH,OAAO;GACL,GAAG,QAAQ;GACX,MAAM;GACN,OAAO,MAAM,mBAAmB;GAChC,QAAQ,MAAM,oBAAoB;GAClC,OAAO,MAAM,mBAAmB;GAChC,WAAW,MAAM,uBAAuB;GACxC,WAAW,MAAM,uBAAuB;EAC1C;EACF,KAAK,mBACH,OAAO;GACL,GAAG,QAAQ;GACX,MAAM;GACN,WAAW,MAAM,yBAAyB;GAC1C,WAAW,MAAM,yBAAyB;EAC5C;EACF,KAAK,iBACH,OAAO;GACL,GAAG,QAAQ;GACX,MAAM;GACN,WAAW,MAAM,uBAAuB;GACxC,WAAW,MAAM,uBAAuB;GACxC,WAAW,MAAM,uBAAuB;GACxC,WAAW,MAAM,uBAAuB;EAC1C;EACF,KAAK,qBACH,OAAO;GACL,GAAG,WAAW;GACd,GAAG,OAAO;GACV,MAAM;GACN,YAAY,KAAK,qBAAqB;GACtC,aAAa,KAAK,sBAAsB;GACxC,YAAY,KAAK,qBAAqB;GACtC,MAAM,MAAM,eAAe;GAC3B,QAAQ,MAAM,iBAAiB;GAC/B,QAAQ,MAAM,qBAAqB;EACrC;EACF,KAAK,oBACH,OAAO;GAAE,GAAG,WAAW;GAAG,GAAG,OAAO;GAAG,MAAM;GAAmB,MAAM,MAAM,eAAe;EAAE;EAC/F,KAAK,oBACH,OAAO;GACL,GAAG,WAAW;GACd,GAAG,OAAO;GACV,MAAM;GACN,MAAM,MAAM,eAAe;GAC3B,kBAAkB,KAAK,0BAA0B;EACnD;EACF,KAAK,oBACH,OAAO;GACL,GAAG,WAAW;GACd,GAAG,OAAO;GACV,MAAM;GACN,YAAY,KAAK,qBAAqB;GACtC,aAAa,KAAK,qBAAqB;GACvC,kBAAkB,KAAK,0BAA0B;GACjD,OAAO,MAAM,eAAe;GAC5B,QAAQ,MAAM,gBAAgB;GAC9B,OAAO,MAAM,eAAe;EAC9B;EACF,KAAK,oBACH,OAAO;GACL,GAAG,WAAW;GACd,GAAG,OAAO;GACV,MAAM;GAEN,aAAa,KAAK,wBAAwB,IAAI;GAC9C,oBAAoB,KAAK,4BAA4B;GACrD,mBAAmB,KAAK,2BAA2B;GACnD,OAAO,MAAM,eAAe;GAC5B,OAAO,MAAM,eAAe;EAC9B;EACF,KAAK,wBACH,OAAO;GACL,GAAG,WAAW;GACd,GAAG,OAAO;GACV,MAAM;GACN,OAAO,MAAM,eAAe;GAC5B,OAAO,MAAM,mBAAmB;GAChC,QAAQ,MAAM,oBAAoB;GAClC,kBAAkB,KAAK,0BAA0B;GACjD,mBAAmB,YAAY,2BAA2B;EAC5D;EACF,KAAK,wBACH,OAAO;GACL,GAAG,WAAW;GACd,MAAM;GACN,UAAU,KAAK,sBAAsB;GACrC,WAAW,KAAK,uBAAuB;GACvC,oBAAoB,KAAK,gCAAgC;GACzD,gBAAgB,KAAK,4BAA4B;EACnD;EACF,KAAK,oBACH,OAAO;GAAE,GAAG,WAAW;GAAG,MAAM;EAAkB;EACpD,KAAK,iBACH,OAAO;GACL,GAAG,MAAM;GACT,MAAM;GACN,QAAQ,MAAM,oBAAoB;GAClC,aAAa,MAAM,yBAAyB;GAC5C,WAAW,MAAM,uBAAuB;GACxC,UAAU,MAAM,sBAAsB;EACxC;EACF,KAAK,kBACH,OAAO;GACL,GAAG,MAAM;GACT,MAAM;GACN,cAAc,MAAM,2BAA2B;EACjD;EACF,KAAK,qBACH,OAAO;GACL,GAAG,MAAM;GACT,MAAM;GACN,WAAW,MAAM,2BAA2B;GAC5C,UAAU,MAAM,0BAA0B;EAC5C;EACF,KAAK,cACH,OAAO;GACL,GAAG,MAAM;GACT,MAAM;GACN,WAAW,MAAM,oBAAoB;GACrC,UAAU,MAAM,mBAAmB;EACrC;EACF,KAAK,kBACH,OAAO;GAAE,GAAG,MAAM;GAAG,MAAM;GAAiB,SAAS,MAAM,sBAAsB;EAAE;EAErF,KAAK,eACH,OAAO;GAAE,GAAG,MAAM;GAAG,MAAM;GAAc,WAAW,MAAM,yBAAyB;EAAE;EACvF,KAAK,eACH,OAAO;GAAE,GAAG,MAAM;GAAG,MAAM;EAAa;EAC1C,KAAK,UACH,OAAO;GAAE,GAAG;GAAQ,UAAU;GAAU,MAAM;EAAS;EACzD,SACE;CACJ;AACF;;;ACrYA,MAAM,YAAY;CAAE,YAAY;CAAK,OAAO;CAAK,SAAS;CAAK,QAAQ;AAAI;AAE3E,MAAa,eAAe,QAAgB,YAAsC;CAChF,MAAM,QAAqB;EAAE,MAAM,OAAO;EAAM,OAAO,CAAC;EAAG,KAAK,CAAC;CAAE;CACnE,MAAM,0BAAU,IAAI,IAA0B;CAC9C,MAAM,OAAuB,CAAC;CAE9B,MAAM,UAAU,aAA2B;EACzC,KAAK,KAAK,QAAQ;EAClB,KAAK,MAAM,SAAS,SAAS,UAAU,OAAO,KAAK;CACrD;CACA,KAAK,MAAM,YAAY,OAAO,UAAU,OAAO,QAAQ;CAGvD,MAAM,SAAS,KACZ,KAAK,UAAU,YAAY;EAAE;EAAU,OAAO,SAAS,QAAQ,KAAK,SAAS;CAAO,EAAE,CAAC,CACvF,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CACjC,KAAK,EAAE,eAAe,QAAQ;CAEjC,KAAK,MAAM,YAAY,QAAQ;EAC7B,QAAQ,IAAI,UAAU,MAAM,MAAM,MAAM;EAExC,MAAM,OAAO,SAAS,QAAQ,KAAA,IAAY,QAAQ,SAAS,GAAG;EAC9D,MAAM,aAAyC,SAAS,QACpD;GAAE,MAAM;GAAI,UAAU;GAAG,UAAU;GAAU,MAAM;EAAS,IAC5D,QAAQ,aAAa,IAAI;EAE7B,MAAM,MAAM,KAAK;GACf;GACA;GACA,SAAS,aAAa,KAAA,IAAY,MAAM,SAAS,QAAQ,EAAA,CAAG,SAAS,EAAE;GACvE,QAAQ;GACR,UAAU,CAAC;GACX,SAAS,CAAC;GACV,KAAK,UAAU,YAAY,YAAY;EACzC,CAAC;EAED,IAAI,SAAS,SAAS,SAAS,QAAQ,iBAAiB,MAAM,OAAO,MAAM,MAAM,SAAS;CAC5F;CAEA,OAAO,SAAS,UAAU,UAAU;EAClC,MAAM,OAAO,MAAM,MAAM;EAEzB,KAAK,MAAM,SAAS,SAAS,UAAU;GACrC,MAAM,KAAK,QAAQ,IAAI,KAAK;GAE5B,MAAM,MAAM,GAAG,CAAE,SAAS;GAC1B,KAAK,SAAS,KAAK,EAAE;EACvB;EAEA,KAAK,SAAS,MAAM,GAAG,MAAM,IAAI,CAAC;EAElC,KAAK,MAAM,UAAU,SAAS,SAAS;GACrC,MAAM,KAAK,QAAQ,IAAI,MAAM;GAC7B,IAAI,OAAO,KAAA,GAAW,KAAK,QAAQ,KAAK,EAAE;EAC5C;CACF,CAAC;CACD,MAAM,MAAM,SAAS,MAAM,UAAU;EACnC,IAAI,KAAK,SAAS,GAAG,MAAM,IAAI,KAAK,KAAK;CAC3C,CAAC;CACD,OAAO;AACT;;AAGA,MAAa,cAAc,SAA4B,YAAuC;CAC5F,MAAM,yBAAS,IAAI,IAAoB;CACvC,KAAK,MAAM,UAAU,SAAS,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,GAAG,OAAO,IAAI,OAAO,MAAM,MAAM;CAE1F,MAAM,wBAAQ,IAAI,IAAyB;CAE3C,QAAQ,SAAS;EACf,MAAM,QAAQ,MAAM,IAAI,IAAI;EAC5B,IAAI,OAAO,OAAO;EAElB,MAAM,SAAS,OAAO,IAAI,IAAI;EAC9B,IAAI,CAAC,QAAQ,OAAO,KAAA;EAEpB,MAAM,QAAQ,YAAY,QAAQ,OAAO;EAEzC,MAAM,IAAI,MAAM,KAAK;EACrB,OAAO;CACT;AACF;;;AC7GA,MAAM,gBAAgB;AAGtB,MAAM,gBAAgB;;;;;AAMtB,MAAM,iBAAiB,QAAgB,OAAe,QAA+B;CACnF,MAAM,OAAO,MAAM,IAAI,QAAQ,IAAI,QAAQ;CAC3C,MAAM,OAAiB,CAAC;CAExB,KAAK,IAAI,MAAM,GAAG,MAAM,MAAM,OAAO;EACnC,MAAM,IAAI,OAAO,OAAO;EACxB,MAAM,UAAU,OAAO,MAAM,MAAM;EACnC,MAAM,UAAU,UAAU,QAAQ,QAAQ;EAE1C,KAAK,IAAI,SAAS,GAAG,SAAS,SAAS,UAAU;GAC/C,MAAM,KAAK,UAAU,SAAS,KAAM,UAAU;GAC9C,MAAM,IAAI,IAAI,IAAI;GAClB,MAAM,IAAI,IAAI,IAAI;GAClB,MAAM,QAAQ,IAAI,KAAK,MAAM,GAAG,GAAG,CAAC;GACpC,MAAM,KAAK,KAAK,OAAO,IAAI,KAAK;GAChC,MAAM,KAAK,KAAK,OAAO,IAAI,KAAK;GAChC,MAAM,KAAK,KAAK,OAAO,KAAK;GAE5B,KAAK,KAAK,KAAK,QAAQ,KAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI,IAAI,GAAG,CAAC;EACnE;CACF;CAEA,OAAO,IAAI,aAAa,IAAI;AAC9B;;AAGA,MAAM,eAAe,UAA4B;CAC/C,MAAM,QAAQ,QAAQ;CACtB,MAAM,UAAoB,CAAC;CAE3B,KAAK,IAAI,MAAM,GAAG,MAAM,OAAO,OAC7B,KAAK,IAAI,SAAS,GAAG,SAAS,OAAO,UAAU;EAC7C,MAAM,IAAI,MAAM,QAAQ;EACxB,MAAM,IAAI,IAAI;EAEd,KAAK,MAAM,UAAU,MAAM,GAAG,QAAQ,KAAK,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,CAAC;OAClE,QAAQ,KAAK,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC;CAChD;CAEF,OAAO;AACT;;AAGA,MAAM,cAAc,UAA4B;CAC9C,MAAM,QAAQ,QAAQ;CACtB,MAAM,SAAS,IAAI,QAAQ;CAC3B,MAAM,UAAoB,CAAC;CAE3B,KAAK,IAAI,MAAM,GAAG,MAAM,OAAO,OAC7B,KAAK,IAAI,SAAS,GAAG,SAAS,OAAO,UAAU;EAG7C,MAAM,IAAI,MAAM,SAAS;EACzB,MAAM,IAAI,IAAI;EACd,MAAM,IAAI,IAAI;EAEd,QAAQ,KAAK,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACjE;CAEF,OAAO;AACT;AAEA,MAAM,cAAc,QAAgB,UAA+B;CAEjE,MAAM,QAAQ,MAAM,SAAS;CAC7B,MAAM,MAAM,QAAQ,MAAM;CAC1B,MAAM,WAAW,cAAc,QAAQ,OAAO,GAAG;CACjD,MAAM,UAAU,MAAM,WAAW,KAAK,IAAI,YAAY,KAAK;CAC3D,MAAM,cAAc,SAAS,SAAS;CACtC,MAAM,SAAS,SAAS,KAAK;CAE7B,OAAO;EACL,MAAM;GACJ,MAAM,UAAU,OAAO,GAAG;GAC1B,SAAS;GACT,WAAW,UAAU;GACrB,QAAQ;GACR,QAAQ,CACN;IACE,YAAY;IACZ,aAAa;IACb,WAAW,cAAc;IACzB,cAAc,QAAQ;IACtB,SAAS;GACX,CACF;GACA,SAAS,IAAI,YAAY,OAAO;GAChC,UAAU,IAAI,WAAW,SAAS,MAAM;EAC1C;EACA,WAAW;GACT,QAAQ;GACR,aAAa;GACb;GACA,YAAY;GACZ,YAAY,QAAQ;GACpB,YAAY;GACZ,YAAY;GACZ,aAAa;IACX,KAAK;KAAE,GAAG,CAAC;KAAQ,GAAG,CAAC;KAAQ,GAAG,SAAS,KAAK,KAAK,IAAI,CAAC;IAAE;IAC5D,KAAK;KAAE,GAAG;KAAQ,GAAG;KAAQ,GAAG;IAAO;GACzC;GACA,gBAAgB;IAAE,QAAQ;KAAE,GAAG;KAAG,GAAG;KAAG,GAAG;IAAE;IAAG;GAAO;EACzD;CACF;AACF;AAEA,MAAM,0BAAU,IAAI,IAAyB;;;;;AAM7C,MAAa,eAAe,QAAgB,UAA+B;CACzE,IAAI,CAAC,OAAO,UAAU,KAAK,KAAK,QAAQ,KAAK,QAAQ,eACnD,MAAM,IAAI,WAAW,yCAAyC,cAAc,QAAQ,OAAO;CAE7F,MAAM,MAAM,GAAG,OAAO,GAAG;CACzB,IAAI,QAAQ,QAAQ,IAAI,GAAG;CAE3B,IAAI,CAAC,OAAO;EACV,QAAQ,WAAW,QAAQ,KAAK;EAChC,QAAQ,IAAI,KAAK,KAAK;CACxB;CAEA,OAAO;AACT;;;AClHA,MAAa,uBAA+C;CAAE,SAAS;CAAG,SAAS;CAAG,MAAM;AAAI;;;;;;;AAQhG,MAAa,qBAAqB,WAA2D;CAC3F,MAAM,EAAE,UAAU,SAAS,MAAM;CACjC,MAAM,IAAI,KAAK,IAAI,KAAK,IAAI,QAAQ,QAAQ,GAAG,CAAC,GAAG,CAAC;CAEpD,OAAO;EAAE,SAAS,KAAK,MAAM,IAAI,IAAI,CAAC;EAAG,MAAM,KAAK,MAAM,OAAO,IAAI,EAAE;CAAE;AAC3E;AAEA,MAAM,IAAI,KAAK,KAAK,IAAI,CAAC;AAEzB,MAAM,QAAQ,GAAY,GAAY,OAAyB;CAC7D,GAAG;EAAE,GAAG;EAAG,GAAG;CAAE;CAChB,GAAG;EAAE,GAAG;EAAG,GAAG;CAAE;CAChB,GAAG;EAAE,GAAG;EAAG,GAAG;CAAE;CAChB,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;AAC9B;AAEA,MAAM,IAAI;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC7B,MAAM,IAAI;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC7B,MAAM,IAAI;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;AAC7B,MAAM,aAAa;CAAE,GAAG;CAAI,GAAG;CAAG,GAAG;AAAE;AACvC,MAAM,aAAa;CAAE,GAAG;CAAG,GAAG;CAAI,GAAG;AAAE;AACvC,MAAM,aAAa;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;AAAG;AAGvC,MAAM,QAA4B;CAChC,KAAK,GAAG,GAAG,CAAC;CACZ,KAAK,YAAY,GAAG,CAAC;CACrB,KAAK,YAAY,GAAG,UAAU;CAC9B,KAAK,GAAG,GAAG,UAAU;CACrB,KAAK,GAAG,YAAY,CAAC;CACrB,KAAK,GAAG,GAAG,UAAU;AACvB;AAIA,MAAM,eAA+C;CACnD;EAAC;EAAG;EAAG;EAAG;CAAC;CACX;EAAC;EAAG;EAAG;EAAG;CAAC;CACX;EAAC;EAAG;EAAG;EAAG;CAAC;CACX;EAAC;EAAG;EAAG;EAAG;CAAC;CACX;EAAC;EAAG;EAAG;EAAG;CAAC;CACX;EAAC;EAAG;EAAG;EAAG;CAAC;AACb;AACA,MAAM,UAA8B;CAClC;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CACnB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG,CAAC;CAAE;CACpB;EAAE,GAAG,CAAC;EAAG,GAAG;EAAG,GAAG,CAAC;CAAE;CACrB;EAAE,GAAG,CAAC;EAAG,GAAG;EAAG,GAAG;CAAE;CACpB;EAAE,GAAG;EAAG,GAAG,CAAC;EAAG,GAAG;CAAE;CACpB;EAAE,GAAG;EAAG,GAAG,CAAC;EAAG,GAAG,CAAC;CAAE;CACrB;EAAE,GAAG,CAAC;EAAG,GAAG,CAAC;EAAG,GAAG,CAAC;CAAE;CACtB;EAAE,GAAG,CAAC;EAAG,GAAG,CAAC;EAAG,GAAG;CAAE;AACvB;AAEA,MAAM,OAAO,GAAY,MAAuB,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;;;;;AAMhF,MAAa,eACX,QACA,QACA,EAAE,SAAS,YAAuD,yBACvD;CAGX,MAAM,QAAQ,KAAK,KAAK,IAAI,KAAK,KAAK,IAAI,SAAS,MAAM;CACzD,MAAM,QAAQ,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,IAAI,EAAG;CACnD,IAAI,CAAC,OAAO,SAAS,KAAK,GAAG,OAAO;CACpC,OAAO,KAAK,IAAI,SAAS,KAAK,IAAI,SAAS,KAAK,CAAC;AACnD;;AAGA,MAAM,gBAAgB,QAAgB,OAAgB,aAAgC;CACpF,MAAM,QAAQ,EAAE,GAAG,GAAG,SAA2B;EAC/C,GAAG,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI;EAC/C,GAAG,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI;EAC/C,GAAG,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI,IAAI,MAAM,EAAE,IAAI;CACjD;CACA,MAAM,OAAO;EAAE,GAAG,SAAS,IAAI,MAAM,EAAE;EAAG,GAAG,SAAS,IAAI,MAAM,EAAE;EAAG,GAAG,SAAS,IAAI,MAAM,EAAE;CAAE;CAC/F,MAAM,WAAW,KAAK,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;CAClD,MAAM,WAAW;EAAE,GAAG,KAAK,IAAI;EAAU,GAAG,KAAK,IAAI;EAAU,GAAG,KAAK,IAAI;CAAS;CAEpF,IAAI,OAAO;CACX,IAAI,OAAO;CAEX,MAAM,SAAS,EAAE,GAAG,UAAU,SAAS;EACrC,MAAM,SAAS,IAAI,UAAU,KAAK,MAAM,CAAC;EAEzC,IAAI,SAAS,MAAM;GACjB,OAAO;GACP,OAAO;EACT;CACF,CAAC;CAGD,MAAM,YAAY,KAAK,IAAI,SAAS,UAAU,CAAC;CAC/C,MAAM,UAAU,aAAa,KAAK,CAAE,QACjC,WAAW,IAAI,UAAU,KAAK,QAAQ,OAAQ,CAAC,IAAI,SACtD;CAEA,OAAO,MAAM,SAAS,GAAG,SACvB,SAAS,QAAQ,aAAa,KAAK,CAAE,MAAM,WAAW,QAAQ,SAAS,MAAM,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,CAC9F;AACF;;;;;AAMA,MAAa,eACX,EAAE,QAAQ,SACV,OACA,EAAE,QAAQ,OAAO,OAAO,UAAU,aAAa,aAC9B;CACjB,MAAM,EAAE,GAAG,GAAG,MAAM,OAAO;CAC3B,MAAM,WAAW,KAAK,MAAM,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,GAAG,IAAI,MAAM,EAAE,CAAC;CAEvE,MAAM,QAAS,KAAK,IAAK,OAAO,OAAO,KAAK,KAAM,GAAG,KAAK,QAAQ,KAAM;CACxE,MAAM,SAAS;EAAE,GAAG;EAAsB,GAAG;CAAO;CACpD,MAAM,EAAE,MAAM,cAAc,YAC1B,QACA,SAAS,YAAY,QAAQ,QAAQ,OAAO,MAAM,MAAM,CAC1D;CACA,MAAM,QAAQ,MAAc,UAA8B;EACxD;EACA;EACA,OAAO,QAAQ,SAAS,OAAO,MAAM,KAAM;EAC3C,YAAY,cAAc,IAAI;EAC9B,cAAc;CAChB;CACA,MAAM,QAAQ,aAAa,QAAQ,OAAO,OAAO,QAAQ,CAAC,CAAC,KAAK,SAC9D,KAAK,MAAM,MAAM,OAAO,MAAM,OAAQ,CACxC;CACA,MAAM,QAAQ,MAAM,MAAM;CAC1B,IAAI,UAAU,KAAA,GAAW,OAAO;CAGhC,MAAM,QAAQ,WAAW,cAAc,KAAK,CAAC;CAK7C,MAAM,SAAS,UAHb,SAAS,gBAAgB,OAAO,WAAW,MAAM,uBAC5C,MAAM,SAAA,QACP;CAGN,OAAO,CACL,GAAG,OACH,GAAG,aAAa,QAAQ,OAAO,OAAO,QAAQ,CAAC,CAAC,KAAK,UAAU;EAC7D,GAAG,KAAK,MAAM,KAAK;EACnB;CACF,EAAE,CACJ;AACF;;;;;;AC5LA,MAAME,MAAI,KAAK;;AAmBf,MAAM,QAGF;CACF,kBAAkB,EAAE,MAAM,aAAa;CACvC,iBAAiB;EAAE,MAAM;EAAc,OAAO;CAAK;CACnD,cAAc,EAAE,MAAM,SAAS;CAC/B,cAAc;EAAE,MAAM;EAAU,OAAO;CAAK;CAC5C,cAAc;EAAE,MAAM;EAAW,MAAM;CAAS;CAChD,YAAY;EAAE,MAAM;EAAW,MAAM;CAAO;CAC5C,cAAc;EAAE,MAAM;EAAW,MAAM;CAAS;CAChD,gBAAgB;EAAE,MAAM;EAAW,MAAM;CAAW;CACpD,eAAe;EAAE,MAAM;EAAW,MAAM;CAAU;CAClD,cAAc;EAAE,MAAM;EAAW,MAAM;CAAS;CAChD,gBAAgB;EAAE,MAAM;EAAW,MAAM;CAAO;AAClD;;AAGA,MAAM,UAAU,SACd,OAAO,QAAQ,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,IAAI,YAAY,MAAM,KAAK,YAAY,CAAC;;;;;AAMhF,MAAM,UAAU,WAAkD;CAChE,MAAM,OAAc,CAClB;EAAE,GAAG;EAAG,GAAG;EAAG,IAAI;EAAG,KAAK;CAAE,GAC5B;EAAE,GAAG;EAAG,GAAG;EAAG,IAAI;EAAG,KAAK;CAAE,CAC9B;CAEA,KAAK,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,UAAU,GAAG,WAAW,MAAM,QAAQ;EAC9D,MAAM,MAAM;GAAE,GAAGA,IAAE,CAAC;GAAG,GAAGA,IAAE,CAAC;GAAG,IAAIA,IAAE,OAAO;GAAG,KAAKA,IAAE,QAAQ;EAAE;EACjE,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG;EAE5B,IAAI,IAAI,MAAM,GAAG,KAAK,KAAK;OACtB,IAAI,IAAI,MAAM,GAAG,KAAK,KAAK;OAC3B,KAAK,KAAK,GAAG;CACpB;CAEA,OAAO;AACT;;AAGA,MAAM,UAAU,SAAgC,KAAK,MAAM,CAAC,CAAC,MAAM,GAAG,MAAM,EAAE,IAAI,EAAE,CAAC;;AAGrF,MAAM,WAAW,SAAuB;CACtC,IAAI,QAAQ;CAEZ,OAAO,KAAK,KAAK,QAAQ;EACvB,MAAM,IAAI,IAAI,IAAI,QAAQ,QAAQ,IAAI;EAEtC,QAAQ;EACR,OAAO;GAAE,GAAG;GAAK;EAAE;CACrB,CAAC;AACH;;AAGA,MAAM,OAAO;;AAGb,MAAM,gBAAgB,OAAc,SAAqB;CACvD,KAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,MAAM,QAAQ,SAAS;EACrD,MAAM,IAAI,MAAM;EAChB,MAAM,IAAI,MAAM,QAAQ;EACxB,MAAM,KAAKA,IAAE,EAAE,IAAI,EAAE,CAAC,IAAIA,IAAE,IAAI,IAAIA,IAAE,IAAI,IAAIA,IAAE,EAAE,IAAI,EAAE,CAAC;EACzD,MAAM,KAAKA,IAAE,EAAE,IAAI,EAAE,CAAC;EACtB,MAAM,QAAQA,IAAE,KAAK,EAAE;EACvB,MAAM,SAASA,IAAE,KAAKA,IAAE,KAAK,EAAG,CAAC;EAEjC,IAAI,SAAS,QAAQ,EAAE,MAAM;OACxB,IAAI,SAAS,UAAU,EAAI,MAAM,OAAS,EAAE,KAAK;OACjD,IAAI,SAAS,UAAU,EAAI,MAAM,GAAK,EAAE,KAAK;OAC7C,IAAI,SAAS,UAAU,EAAI,MAAM,GAAK,EAAE,KAAK;OAC7C,IAAI,SAAS,YAAY,EAAI,MAAM,QAAU,EAAE,KAAK;OACpD,IAAI,SAAS,WAChB,IAAI,EAAE,KAAK,EAAE,GAAG,EAAI,MAAM,QAAU,EAAE,KAAK;OACtC,EAAI,MAAM,GAAK,EAAE,KAAK;OACxB,IAAI,SAAS,UAChB,IAAI,EAAE,IAAI,EAAE,GAAG,EAAI,MAAM,GAAK,EAAE,KAAK;OAChC,EAAI,MAAM,QAAU,EAAE,KAAK;CACpC;AACF;;;;;AAMA,MAAM,WAAW,MAAsB,SAAsB;CAC3D,MAAM,QAAe,CAAC;CAEtB,KAAK,MAAM,OAAO,MAAM;EACtB,MAAM,KAAK,MAAM,WAAW,SAAS,KAAK,KAAK,IAAI,CAAC;EAEpD,MAAM,OAAO,KAAK,IAAI,MAAM,SAAS,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC;EACtD,aAAa,OAAO,IAAI;CAC1B;CAEA,OAAO;AACT;;AAGA,MAAM,WAAW,GAAQ,GAAQ,MAAsB;CACrD,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE;CACxB,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE;CAExB,MAAM,KAAK,EAAE,IAAI,EAAE;CACnB,MAAM,IAAIA,KAAG,IAAI,EAAE,KAAK,EAAE;CAE1B,IAAI,OAAO,MAAM,EAAE,GAAG,GAAG,OAAO,EAAE;CAElC,MAAM,KAAK,IAAI;CACf,MAAM,KAAK,KAAK;CAGhB,QACG,KAAK,IAAI,KAAK,KAAK,EAAE,MAAM,MAC3B,KAAK,MAAM,EAAE,KAAK,MAClB,IAAI,KAAK,IAAI,KAAK,KAAK,EAAE,KACzB,IAAI,KAAK,IAAI,MAAM,EAAE;AAE1B;;;;;AAMA,MAAM,mBAAmB,OAAuB,MAAsB;CACpE,MAAM,QAAQ,MAAM;CACpB,MAAM,OAAO,MAAM,MAAM,SAAS;CAElC,IAAI,MAAM,WAAW,KAAK,IAAI,MAAM,GAAG,OAAO,MAAM;CACpD,IAAI,IAAI,KAAK,GAAG,OAAO,KAAK;CAE5B,IAAI,KAAK,KAAK,MAAMA,KAAG,IAAI,MAAM,MAAM,KAAK,IAAI,MAAM,EAAE,KAAK,MAAM,SAAS,EAAE;CAE9E,IAAI,MAAM,GAAG,CAAE,KAAK,GAAG;EACrB,OAAO,KAAK,MAAM,UAAU,MAAM,GAAG,CAAE,KAAK,GAAG;EAE/C,OAAO,MAAM,MAAM,QAAQ,MAAM,KAAK,IAAK,MAAM,KAAM,CAAC,IAAI,MAAM,KAAK,EAAE,CAAE;CAC7E;CAEA,OAAO,KAAK,KAAK,EAAE,MAAM,GAAG,CAAE,IAAI,IAAI;CACtC,OAAO,QAAQ,MAAM,KAAM,MAAM,KAAK,IAAK,CAAC;AAC9C;;AAGA,MAAM,sBAAsB,MAAsB,MAAsB;CACtE,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;EAChD,MAAM,MAAM,KAAK;EAEjB,IAAI,IAAI,IAAI,GAAG;GACb,IAAI,UAAU,GAAG,OAAO;GAExB,MAAM,IAAI,KAAK,QAAQ;GACvB,MAAM,IAAIA,KAAG,IAAI,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE;GACrC,MAAM,KAAK,KAAK,QAAQ,EAAE,EAAE,KAAK,EAAE;GACnC,MAAM,KAAK,KAAK,QAAQ,EAAE,EAAE,KAAK,IAAI;GAGrC,OAAO,WAAW,IAAI,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;EACzC;EAEA,IAAI,IAAI,MAAM,GAAG,OAAO,IAAI;CAC9B;CAEA,OAAO;AACT;;AAGA,MAAM,kBAAkB,MAAsB,MAAsB;CAClE,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;EAChD,MAAM,IAAI,KAAK;EAEf,IAAI,EAAE,IAAI,GAAG;GACX,MAAM,IAAI,KAAK,QAAQ;GACvB,IAAI,CAAC,GAAG,OAAO;GACf,OAAO,EAAE,KAAM,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAO,EAAE,IAAI,EAAE;EACpD;CACF;CAEA,OAAO;AACT;;AAGA,MAAa,eAAe,UAAyC;CACnE,MAAM,QAAQ,MAAM,UAAU,KAAA,IAAY,KAAA,IAAY,OAAO,MAAM,KAAK;CACxE,IAAI,CAAC,OAAO,OAAO,KAAA;CAEnB,MAAM,CAAC,MAAM,EAAE,MAAM,MAAM,WAAW;CACtC,MAAM,OAAO,OAAO,MAAM,UAAU,CAAC,CAAC;CACtC,MAAM,OAAO,QAAQ,QAAQ,OAAO,IAAI,CAAC,IAAI,OAAO,IAAI;CACxD,IAAI,SAAS,cAAc,OAAO;EAAE;EAAM,WAAW,MAAM,mBAAmB,MAAMA,IAAE,CAAC,CAAC;CAAE;CAC1F,IAAI,SAAS,UAAU,OAAO;EAAE;EAAM,WAAW,MAAM,eAAe,MAAMA,IAAE,CAAC,CAAC;CAAE;CAElF,MAAM,QAAQ,QAAQ,MAAM,QAAQ,MAAM;CAE1C,OAAO;EAAE;EAAM,WAAW,MAAM,gBAAgB,OAAOA,IAAE,CAAC,CAAC;CAAE;AAC/D;;;;;AAgBA,MAAa,YAAY,EAAE,OAAO,UAAU,OAAO,UAAkB,QAAwB;CAC3F,IAAI,aAAa,GAAG,OAAO;CAE3B,MAAM,UAAU,MAAM;CACtB,IAAI,SAAS,SAAS,GAAG,OAAO,MAAM,SAASA,IAAG,UAAU,SAAU,MAAM,CAAC;CAE7E,MAAM,QAAQA,IAAE,UAAU,QAAQ;CAElC,OAAO,QAAQ,MAAM,SAAS,KAAK,IAAI;AACzC;;ACpPA,MAAMC,MAAI,KAAK;;AAiBf,MAAa,gBAA4B;CACvC,aAAa;CACb,KAAK;CACL,MAAM;CACN,MAAM;CACN,KAAK;CACL,MAAM;CACN,OAAO;CACP,MAAM;AACR;;AAGA,MAAa,uBAAmC;CAAE,GAAG;CAAe,MAAM;CAAI,MAAM;AAAK;AAEzF,MAAM,OAAO;CAAC;CAAe;CAAO;CAAQ;CAAQ;CAAO;CAAQ;CAAS;AAAM;;AAGlF,MAAa,aACX,OACA,SACwC;CACxC,MAAM,QAAQ,EAAE,GAAG,KAAK;CACxB,IAAI,OAAO;CAEX,KAAK,SAAS,KAAK,QAAQ;EACzB,MAAM,QAAQ,MAAM;EACpB,IAAI,UAAU,KAAA,GAAW;EACzB,MAAM,OAAO,QAAQ,SAAS,QAAQ,SAAS,KAAK,MAAM,KAAK,IAAIA,IAAE,KAAK;EAC1E,QAAQ,KAAK;CACf,CAAC;CACD,OAAO;EAAE;EAAO;CAAK;AACvB;;AAGA,MAAa,cACX,SACA,MACA,IACA,MACA,MACe;CACf,MAAM,MAAM,EAAE,GAAG,QAAQ;CAEzB,KAAK,SAAS,KAAK,QAAQ;EACzB,IAAI,EAAE,OAAQ,KAAK,MAAO;EAE1B,MAAM,QAAQ,KAAK,QAAQ,GAAG,OAAO,KAAK,QAAQ;EAElD,IAAI,OAAO,QAAQ,SAAS,QAAQ,SAAS,KAAK,MAAM,KAAK,IAAIA,IAAE,KAAK;CAC1E,CAAC;CACD,OAAO;AACT;;;;;;AAwBA,MAAa,cACX,WACA,EAAE,aAAa,OACf,OAAO,MAC6B;CACpC,MAAM,SAAS,OAAe,KAAa,SAAiB,KAAK,IAAI,MAAM,KAAK,IAAI,KAAK,KAAK,CAAC;CAE/F,OAAO;EACL,QAAQ,MAAM,YAAY,MAAM,OAAO,aAAa,KAAK,CAAC,GAAG,KAAK,CAAC;EACnE,KAAK,MAAM,MAAM,KAAK,MAAQ,GAAK;CACrC;AACF;;;;;;;;ACjGA,MAAMC,MAAI,KAAK;;AAGf,MAAa,aAAa,KAAe,WACvC,QAAQ,wBAAwB,UAAU,QAAQ,UAAU,OAAO,QAAQ,IAAI;AAEjF,MAAa,cAAc,EAAE,SAAyB;CAAE,GAAG,EAAE;CAAG,GAAG,EAAE;CAAG,GAAG,EAAE;AAAE;AAE/E,MAAa,gBAAgB,OAAc,EAAE,GAAG,GAAG,SAAyB;CAC1E,GAAG;CACH,GAAG;EAAE;EAAG;EAAG;EAAG,GAAG;CAAE;AACrB;;AAGA,MAAa,gBAAgB,OAAc,cAA4B;CACrE,GAAG,SAAS;CACZ,GAAG,SAAS;CACZ,GAAG,SAAS;CACZ,GAAG,MAAM;AACX;;AAGA,MAAa,UAAU,OAAc,MAAwB,QAAQ,mBAAmB,GAAG,KAAK;;AAGhG,MAAa,WAAW,UAAwB;CAC9C,MAAM,EAAE,GAAG,GAAG,MAAM;CACpB,MAAM,WAAkB;EACtB,GAAG;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,GAAG;EAAE;EAClC,GAAG;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,GAAG;EAAE;EAClC,GAAG;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,GAAG,EAAE;GAAG,GAAG;EAAE;EAClC,GAAG;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;CAC9B;CAEA,OAAO,aAAa,UAAU,QAAQ,eAAe,OAAO,UAAU,WAAW,KAAK,CAAC,GAAG,EAAE,CAAC;AAC/F;;AAGA,MAAa,aAAa,GAAY,GAAY,OAAuB;CACvE,GAAG;EAAE,GAAG;EAAG,GAAG;CAAE;CAChB,GAAG;EAAE,GAAG;EAAG,GAAG;CAAE;CAChB,GAAG;EAAE,GAAG;EAAG,GAAG;CAAE;CAChB,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;AAC9B;;AAGA,MAAa,cAAc,EAAE,GAAG,GAAG,GAAG,QAA2B;CAC/D,MAAM,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;CAE3C,OAAO,UACL;EAAE,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI;EAAI,GAAG,KAAK,IAAI,IAAI,IAAI;EAAI,GAAG,KAAK,IAAI,IAAI,IAAI;CAAG,GAC7E;EAAE,GAAG,KAAK,IAAI,IAAI,IAAI;EAAI,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI;EAAI,GAAG,KAAK,IAAI,IAAI,IAAI;CAAG,GAC7E;EAAE,GAAG,KAAK,IAAI,IAAI,IAAI;EAAI,GAAG,KAAK,IAAI,IAAI,IAAI;EAAI,GAAG,IAAI,KAAK,IAAI,IAAI,IAAI;CAAG,CAC/E;AACF;;AAGA,MAAa,gBAAgB,UAA6B;CAExD,MAAM,IAAI;EACR;GAAC,MAAM,EAAE;GAAG,MAAM,EAAE;GAAG,MAAM,EAAE;EAAC;EAChC;GAAC,MAAM,EAAE;GAAG,MAAM,EAAE;GAAG,MAAM,EAAE;EAAC;EAChC;GAAC,MAAM,EAAE;GAAG,MAAM,EAAE;GAAG,MAAM,EAAE;EAAC;CAClC;CACA,MAAM,QAAQ,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;CAEvC,IAAI,QAAQ,GAAG;EACb,MAAM,IAAI,KAAK,KAAK,QAAQ,CAAC;EAC7B,MAAM,IAAI,KAAM;EAEhB,OAAO;GACL,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM;GACzB,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM;GACzB,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM;GACzB,GAAG,IAAI;EACT;CACF;CAGA,IAAI,IAAI;CACR,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,IAAI;CAC3B,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAE,IAAK,IAAI;CAE7B,MAAM,KAAK,IAAI,KAAK;CACpB,MAAM,KAAK,IAAI,KAAK;CACpB,MAAM,IAAI,KAAK,KAAK,EAAE,EAAE,CAAE,KAAM,EAAE,EAAE,CAAE,KAAM,EAAE,EAAE,CAAE,KAAM,CAAC;CACzD,MAAM,IAAI,KAAM;CAChB,MAAM,IAAI;EAAC;EAAG;EAAG;CAAC;CAElB,EAAE,KAAK,IAAI;CACX,EAAE,MAAM,EAAE,EAAE,CAAE,KAAM,EAAE,EAAE,CAAE,MAAO;CACjC,EAAE,MAAM,EAAE,EAAE,CAAE,KAAM,EAAE,EAAE,CAAE,MAAO;CACjC,OAAO;EAAE,GAAG,EAAE;EAAK,GAAG,EAAE;EAAK,GAAG,EAAE;EAAK,IAAI,EAAE,EAAE,CAAE,KAAM,EAAE,EAAE,CAAE,MAAO;CAAE;AACxE;;;;;AAMA,MAAa,SAAS,GAAe,GAAe,MAA0B;CAE5E,MAAM,IADM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IACxC,IAAI,KAAK;CACzB,MAAM,IAAI;EACR,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,KAAK;EAC3B,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,KAAK;EAC3B,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,KAAK;EAC3B,GAAG,EAAE,KAAK,IAAI,EAAE,IAAI,EAAE,KAAK;CAC7B;CACA,MAAM,IAAI,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;CAEvC,OAAO;EAAE,GAAG,EAAE,IAAI;EAAG,GAAG,EAAE,IAAI;EAAG,GAAG,EAAE,IAAI;EAAG,GAAG,EAAE,IAAI;CAAE;AAC1D;;AAGA,MAAa,aAAa,MAA4B,aACpD,SAAS,KAAA,IAAY,WAAW,KAAK,KAAK;AAE5C,MAAM,OAA2B;CAC/B;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CACnB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CACnB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CACnB;EAAE,GAAG;EAAI,GAAG;EAAG,GAAG;CAAE;CACpB;EAAE,GAAG;EAAG,GAAG;EAAI,GAAG;CAAE;CACpB;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAG;AACtB;AAEA,MAAM,OAAO;;;;;;;AAQb,MAAa,UACX,GACA,OACA,IACA,UAAU,GACV,aAAa,MACH;CAEV,MAAM,IAAI,KAAK,YAAY,IAAI,IAAI,YAAY,KAAK;CACpD,MAAM,IAAI,KAAK,YAAY,KAAK,eAAe,IAAI,IAAI,eAAe,KAAK;CAC3E,MAAM,OAAO,QAAQ,MAAM,GAAG,CAAC;CAC/B,IAAI,MAAM,QAAQ,UAAU,CAAC;CAC7B,IAAI,OAAO;CAEX,IAAI,QAAQ,GAAG,MAAM,QAAQ,eAAe,KAAK,EAAE;CACnD,IAAI,KAAK,GAAG,OAAO,QAAQ,eAAe,MAAM,EAAE;CAElD,MAAM,QACJ,KAAK,IAAI,QAAQ,IAAI,MAAM,GAAG,CAAC,IAAI,OAC/B,QAAQ,UAAU,QAAQ,MAAM,KAAK,IAAI,CAAC,IAC1C,QAAQ,UAAU,QAAQ,MAAM,KAAK,QAAQ,UAAU,QAAQ,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC;CACvF,MAAM,MAA+B;EAAC,KAAA;EAAW,KAAA;EAAW,KAAA;CAAS;CAErE,IAAI,QAAQ,KAAK;CACjB,IAAI,KAAK,KAAK;CAGd,MAAM,CAAC,GAAG,GAAG,KAAK,IAAI,KAAK,MAAM,UAAU,QAAQ,KAAK,MAAO;CAC/D,IAAI,IAAI,OAAO,KAAA,GAAW,OAAO,UAAU,QAAQ,UAAU,QAAQ,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC;CAEvF,IAAI,IAAI,OAAO,KAAA,GAAW;EACxB,IAAI,IAAI,OAAO,KAAA,GAAW,OAAO,UAAU,GAAG,GAAG,QAAQ,UAAU,QAAQ,MAAM,GAAG,CAAC,CAAC,CAAC;EACvF,OAAO,UAAU,GAAG,GAAG,CAAC;CAC1B;CAEA,OAAO,UAAU,GAAG,QAAQ,UAAU,QAAQ,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC;AAC/D;;;;;AAMA,MAAa,YAAY,MAAa,MAAc,YAA2B;CAC7E,IAAI,OAAO,KAAK,OAAO,GAAG,OAAO;CAEjC,MAAM,UAAU,UAAUA,IAAE,UAAW;CACvC,MAAM,IAAIA,IAAE,KAAK,IAAI,OAAO,CAAC;CAC7B,MAAM,IAAI,KAAK,IAAI,OAAO;CAE1B,MAAM,OACJ,OAAO,MAAM,IACT,UAAU;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,GAAG;EAAE,GAAG;EAAG,GAAG,CAAC;EAAG,GAAG;CAAE,CAAC,IAC3E,OAAO,MAAM,IACX,UAAU;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG,CAAC;CAAE,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,CAAC,IAC3E,UAAU;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,GAAG;EAAE,GAAG,CAAC;EAAG,GAAG;EAAG,GAAG;CAAE,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE,CAAC;CAEnF,OAAO,QAAQ,IAAI,QAAQ,SAAS,MAAM,IAAI,IAAI,QAAQ,SAAS,MAAM,IAAI;AAC/E;;;;;;;AChMA,MAAMC,MAAI,KAAK;AACf,MAAM,UAAU,KAAK,KAAK;;AAG1B,MAAa,aAAa;CACxB,OAAO;CACP,WAAW;CACX,OAAO;CACP,QAAQ;CACR,IAAI;CACJ,UAAU;CACV,OAAO;CACP,OAAO;CACP,MAAM;CACN,UAAU;CACV,SAAS;CACT,SAAS;AACX;;AAuBA,MAAa,gBAA4B;CACvC,IAAI;CACJ,UAAU;CACV,OAAO;EAAE,GAAG;EAAK,GAAG;EAAK,GAAG;CAAI;CAChC,WAAW;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC9B,MAAM;CACN,SAAS;EAAE,GAAG;EAAG,GAAG;EAAG,GAAG;CAAE;CAC5B,UAAU,QAAQ;CAClB,SAAS,QAAQ;CACjB,OAAO;CACP,OAAO;EAAE,GAAG;EAAG,GAAG;EAAG,GAAGA,IAAE,IAAM;CAAE;CAClC,OAAOA,IAAE,SAAS;CAClB,KAAKA,IAAE,KAAK,EAAE;AAChB;AAEA,MAAM,SAAS,SAA6B,SAAS;AAErD,MAAM,QAAQ,EAAE,GAAG,GAAG,SAA2B;CAC/C,GAAG,KAAK,MAAM,CAAC;CACf,GAAG,KAAK,MAAM,CAAC;CACf,GAAG,KAAK,MAAM,CAAC;AACjB;;AAGA,MAAa,aACX,OACA,SACwC;CACxC,MAAM,QAAQ,EAAE,GAAG,KAAK;CACxB,IAAI,OAAO;CACX,IAAI,MAAM,OAAO,KAAA,GAAW,MAAQ,KAAK,MAAM,MAAM,EAAE,GAAK,QAAQ,WAAW;CAC/E,IAAI,MAAM,OAAO,MAAQ,QAAQ,KAAK,MAAM,KAAK,GAAK,QAAQ,WAAW;CACzE,IAAI,MAAM,SAAS,MAAQ,UAAU,MAAM,SAAW,QAAQ,WAAW;CACzE,IAAI,MAAM,UAAU,MAAQ,WAAW,MAAM,UAAY,QAAQ,WAAW;CAC5E,IAAI,MAAM,SAAS,MAAQ,UAAU,MAAM,SAAW,QAAQ,WAAW;CACzE,IAAI,MAAM,WAAW,MAAQ,YAAY,MAAM,WAAa,QAAQ,WAAW;CAC/E,IAAI,MAAM,OAAO,MAAQ,QAAQ,MAAM,OAAS,QAAQ,WAAW;CACnE,IAAI,MAAM,MAAM,MAAQ,OAAO,KAAK,YAAY,MAAM,OAAS,QAAQ,WAAW;CAClF,IAAI,MAAM,UAAU,KAAA,GAAW,MAAQ,QAAQA,IAAE,MAAM,KAAK,GAAK,QAAQ,WAAW;CAEpF,IAAI,MAAM,WAAW,KAAA,GACnB,MAAQ,MAAMA,IAAE,MAAM,SAAS,OAAO,GAAK,QAAQ,WAAW;CAEhE,IAAI,MAAM,UAAU,KAAA,GAClB,MAAQ,QAAQA,IAAE,MAAM,QAAQ,OAAO,GAAK,QAAQ,WAAW;CAEjE,OAAO;EAAE;EAAO;CAAK;AACvB;;;;;;;AAQA,MAAa,WAAW,UAA8C;CACpE,MAAM,EAAE,OAAO,SAAS,UAAU,SAAS,CAAC,GAAG,aAAa;CAC5D,IAAI,OAAO,WAAW,MAAM,OAAO;CAEnC,MAAM,SAAS,MAAM,MAAM;CAC3B,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,KAAK,EAAE;CAEzC,OAAO;EACL,GAAG;EACH,MAAM,MAAM,WAAW,IAAI,SAAS,IAAI,IAAI;EAC5C,SAAS,QAAQ,eAAe,MAAM,OAAO,IAAI,GAAG;EACpD,UAAU,QAAQ;EAClB,SAAS,QAAQ;EACjB,OAAO;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG,KAAK,MAAM,QAAQ,MAAM;EAAO;EACxD,OAAO,IAAI,MAAM;EACjB;EACA,KAAK,KAAK,IAAI,MAAM,OAAO,KAAK,EAAE;CACpC;AACF;;;;;AAMA,MAAa,mBAAmB,UAA2D;CACzF,MAAM,EAAE,OAAO,SAAS,UAAU,OAAO,aAAa;CACtD,IAAI,MAAM;CAEV,IAAI,MAAM,WAAW,OAAO;EAC1B,MAAM,UAAU,QAAQ,eAAe,MAAM,OAAOA,IAAE,IAAI,GAAG,CAAC;EAC9D,OAAO,WAAW;CACpB;CAEA,IAAI,MAAM,WAAW,UAAU,MAAM,MAAM,GAAG;EAC5C,MAAM,OAAO;EACb,MAAM,MAAM;EACZ,MAAM,QAAQ;EACd,OAAO,WAAW;CACpB;CAEA,OAAO;EAAE;EAAO,MAAM;CAAI;AAC5B;AAEA,MAAM,QAAQ,GAAW,GAAW,MAAcA,IAAE,KAAK,IAAI,KAAK,CAAC;AACnE,MAAM,SAAS,GAAY,GAAY,OAAwB;CAC7D,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;CACnB,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;CACnB,GAAG,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC;AACrB;;;;;;AAOA,MAAa,cACX,SACA,MACA,IACA,MACA,MACe;CACf,MAAM,MAAM,EAAE,GAAG,QAAQ;CACzB,MAAM,OAAO,KAAK;CAElB,IAAI,OAAO,WAAW,OAAO,IAAI,QAAQ,KAAK,KAAK,OAAO,GAAG,OAAO,CAAC;CACrE,IAAI,OAAO,WAAW,QAAQ,IAAI,MAAM,KAAK,KAAK,KAAK,GAAG,KAAK,CAAC;CAChE,IAAI,OAAO,WAAW,QAAQ,MAAM,IAAI,OAAO,GAAG;CAClD,IAAI,OAAO,WAAW,OAAO,IAAI,QAAQ,KAAK,KAAK,OAAO,GAAG,OAAO,CAAC;CACrE,IAAI,OAAO,WAAW,UAAU,IAAI,WAAW,MAAM,KAAK,UAAU,GAAG,UAAU,CAAC;CAClF,IAAI,OAAO,WAAW,SAAS,IAAI,UAAU,MAAM,KAAK,SAAS,GAAG,SAAS,CAAC;CAC9E,IAAI,OAAO,WAAW,SAAS,IAAI,UAAU,MAAM,KAAK,SAAS,GAAG,SAAS,CAAC;CAC9E,IAAI,OAAO,WAAW,OAAO,IAAI,QAAQ,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC;CACtE,IAAI,OAAO,WAAW,OAAO,IAAI,QAAQ,KAAK,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC;CAC5E,IAAI,OAAO,WAAW,YAAY,MAAM,IAAI,WAAW,GAAG;CAC1D,IAAI,OAAO,WAAW,WAAW,IAAI,YAAY,MAAM,KAAK,WAAW,GAAG,WAAW,CAAC;CACtF,IAAI,OAAO,WAAW,MAAM,MAAM,IAAI,KAAK,GAAG;CAC9C,OAAO;AACT;;;;;;;AAQA,MAAa,eACX,OACA,QACA,OACA,UACc;CACd,MAAM,YAAY,QAAQ,UAAU,OAAO,OAAO,MAAM,SAAS,CAAC;CAClE,MAAM,OAAO,MAAM,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM,KAAK,MAAM,MAAM,MAAM;CAC7E,MAAM,QAAQ,WAAW;CAEzB,OAAO;EACL;EACA,OAAO,MAAM;EACb;EACA,GAAI,MAAM,QAAQ,KAAK,MAAM,QAAQ,KAAK,MAAM,QAAQ,IAAI,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;EAC1F,GAAI,WAAW,KAAK;GAClB,UAAU;IAAE,GAAG,MAAM,EAAE;IAAG,GAAG,MAAM,EAAE;IAAG,GAAG,MAAM,EAAE;GAAE;GACrD,OAAO,MAAM;GACb,aAAa,OAAO;IAAE,GAAGA,IAAE,EAAG;IAAG,GAAG;IAAG,GAAG;GAAE,IAAI,MAAM;GACtD,GAAI,CAAC,SAAS,EACZ,MAAM;IAAE,OAAO,MAAM;IAAO,KAAK,KAAK,IAAI,MAAM,KAAKA,IAAE,KAAK,EAAE,CAAC;IAAG,SAAS;GAAE,EAC/E;EACF;CACF;AACF;AAgBA,MAAa,SAAmB;CAC9B,IAAI;CACJ,OAAO;CACP,OAAO,QAAQ;CACf,MAAM;CACN,OAAO;CACP,KAAK;CACL,SAAS;AACX;;AAGA,MAAa,WAAW,UAAqD;CAC3E,MAAM,MAAM,EAAE,GAAG,OAAO;CACxB,IAAI,OAAO;CACX,IAAI,MAAM,UAAU,KAAA,GAAW,IAAM,KAAK,MAAM,MAAM,KAAK,GAAK,QAAQ;CACxE,IAAI,MAAM,aAAa,KAAA,GAAW,IAAM,QAAQ,MAAM,MAAM,QAAQ,GAAK,QAAQ;CACjF,IAAI,MAAM,UAAU,IAAM,QAAQ,KAAK,MAAM,QAAQ,GAAK,QAAQ;CAClE,IAAI,MAAM,SAAS,IAAM,OAAO,KAAK,UAAU,MAAM,UAAY,QAAQ;CACzE,IAAI,MAAM,aAAa,KAAA,GAAW,IAAM,QAAQA,IAAE,MAAM,QAAQ,GAAK,QAAQ;CAC7E,IAAI,MAAM,WAAW,KAAA,GAAW,IAAM,MAAMA,IAAE,MAAM,MAAM,GAAK,QAAQ;CACvE,IAAI,MAAM,eAAe,KAAA,GAAW,IAAM,UAAUA,IAAE,MAAM,UAAU,GAAK,QAAQ;CACnF,OAAO;EAAE;EAAK;CAAK;AACrB;;AAGA,MAAa,YACX,SACA,MACA,IACA,MACA,MACa;CACb,MAAM,MAAM,EAAE,GAAG,QAAQ;CAEzB,IAAI,KAAK,GAAG;EACV,IAAI,OAAO,GAAG,IAAI,KAAK,GAAG;EAC1B,IAAI,OAAO,GAAG,IAAI,QAAQ,GAAG;EAC7B,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG;CAC9B;CAEA,IAAI,OAAO,IAAM,IAAI,QAAQ,KAAK,KAAK,OAAO,GAAG,OAAO,CAAC;CACzD,IAAI,OAAO,IAAM,IAAI,MAAM,KAAK,KAAK,KAAK,GAAG,KAAK,CAAC;CACnD,IAAI,OAAO,IAAM,IAAI,UAAU,KAAK,KAAK,SAAS,GAAG,SAAS,CAAC;CAC/D,IAAI,OAAO,GAAG,IAAI,QAAQ,KAAK,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC;CAC7D,OAAO;AACT;AAEA,MAAM,QAAQ;CAAE,GAAG;CAAO,GAAG;CAAQ,GAAG;AAAS;;;;;AAMjD,MAAa,aAAa,KAAe,UAAU,SAA0B;CAC3E,MAAM,OAAO,MAAM,IAAI;CACvB,IAAI,CAAC,IAAI,MAAM,CAAC,WAAW,CAAC,MAAM,OAAO,KAAA;CACzC,OAAO;EACL,OAAO,QAAQ,eAAe,IAAI,OAAO,IAAI,GAAG;EAChD,OAAO,IAAI;EACX,KAAK,IAAI;EACT;EACA,SAAS,IAAI;CACf;AACF;;;;;;ACtQA,MAAMC,MAAI,KAAK;;AAGf,MAAa,QAAQ;CACnB,qBAAqB;CACrB,eAAe;CACf,GAAG,KAAK;CACR,GAAG,KAAK;AACV;;;;;AAkIA,MAAa,gBAAgB,YAA4B,KAAK,MAAMA,IAAE,UAAU,GAAI,CAAC;;AAGrF,MAAM,aAAa,UAAyD;CAC1E,IAAI,WAAW,SAAS,MAAM,OAAO,OAAO,MAAM;CAElD,MAAM,MAAyB,MAAM,UAAU;CAC/C,IAAI,KAAK,SAAS,cAAc,OAAO,IAAI;CAC3C,IAAI,KAAK,SAAS,UAAU,OAAO,OAAO,IAAI,OAAO;AAEvD;;;;;AAMA,MAAa,YAAY,UAAyB;CAChD,MAAM,QAAQ,UAAU,KAAK;CAC7B,IAAI,UAAU,KAAA,GAAW,OAAO,MAAM,aAAa,KAAA,IAAY,MAAM,sBAAsB;CAC3F,IAAI,OAAO,UAAU,UAAU,OAAO;CAEtC,IAAI,OAAO;CACX,KAAK,MAAM,QAAQ,OAAO,QAAS,MAAiC,SAAS;CAC7E,OAAO;AACT;AAEA,MAAM,iBAAiB,UAAiB;CACtC,MAAM,OAAO,MAAM,UAAU;CAC7B,MAAM,OAAO,MAAM,UAAU;CAC7B,MAAM,QAAQ,KAAK;CAEnB,OAAO;EACL,MACE,MAAM,SAAS,gBAAgB,KAAK,MAAM,WAAW,IACjD,MAAM,KAAK,MAAM,MACjB,MAAM,SAAS,WACb,OAAO,KAAK,OAAO,IACnB,KAAA;EACR,MAAM,MAAM,SAAS,WAAW,KAAK,QAAQ,KAAA;CAC/C;AACF;;AAGA,MAAM,YAAY,UAA6D;CAC7E,MAAM,MAAM,cAAc,KAAK;CAC/B,MAAM,QACJ,iBAAiB,SAAS,MAAM,gBAAgB,KAAA,IAC5C,KAAK,aAAa,MAAM,eACxB,KAAA;CACN,MAAM,OAAO,iBAAiB,QAAQ,MAAM,cAAc,KAAA;CAE1D,OAAO;EAAE,MAAM,SAAS,IAAI,QAAQ;EAAG,MAAM,QAAQ,IAAI;CAAK;AAChE;AAEA,MAAM,YAAY,OAAc,OAAe,cAA8B;CAC3E;CACA;CACA,GAAI,MAAM,eAAe,EAAE,OAAO,YAAY,MAAM,WAAW,EAAE;CAEjE,QAAQ,MAAM,kBAAkB,KAAA,IAAY,KAAK,KAAK,MAAM,MAAM,aAAa;AACjF;;AAGA,MAAM,SAAS,OAAe,OAAe,aAC3C,QAAQ,MAAM,sBAAsB,KAAM,QAAQ,WAAY;;AAGhE,MAAM,YAAY,OAAc,QAAgB,MAAc,SAC5D,SAAS,KAAA,KAAa,SAAS,KAAK,MAAM,SAAS,MAAM;;AAG3D,MAAM,eAAe,OAAc,QAAgB,MAAc,SAC9D,SAAS,OAAO,QAAQ,MAAM,IAAI,KAAK,MAAM,KAAK,QAAQ,MAAM,IAAK,KAAM,MAAM,MAAM,MAAM;;AAGhG,MAAM,UAAU,MAAY,UAA6B;CACvD,MAAM,EAAE,MAAM,SAAS,SAAS,KAAK;CACrC,MAAM,SAAU,YAAY,SAAS,MAAM,UAAW,QAAQ;CAC9D,MAAM,QAAQ,UAAU,WAAW,QAAQ,MAAM,QAAQ,KAAA,GAAW,CAAC;CACrE,MAAM,KAAK,UAAU,QAAQ,QAAQ,MAAM,KAAK,KAAA,GAAW,CAAC;CAC5D,MAAM,OAAO,SAAiB,KAAK,QAAQ,SAAS;CACpD,IAAI,MAAa,QAAQ;CAEzB,OAAO;EACL,GAAG;EACH,QAAQ;EACR,MAAM,KAAK,YAAY;EACvB,MAAM,OAAO;GACX,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GAGtD,MAAM,IAAI,YAAY,OAAO,KAAK,WAAW,MAAM,IAAI;GAGvD,MAAM,QAAQ,SAAS,QAAQ,CAAC,GAAG,MAAM,MAAM,KAAK,OAAO,CAAC;GAC5D,OAAO;EACT;EACA,OAAO,OAAO;GACZ,MAAM,IAAI,YAAY,OAAO,KAAK,WAAW,MAAM,IAAI;GACvD,MAAM,QAAQ,KAAK;GAEnB,IAAI,IAAI,MAAM,YAAY,GAAG;IAC3B,MAAM,OAAO,QAAQ,SAAS,GAAG,GAAG;IACpC,IAAI,IAAI,MAAM,QAAQ,GAAG,MAAM,YAAY,OAAO,WAAW,IAAI,CAAC;IAClE,IAAI,IAAI,MAAM,WAAW,GAAG,MAAM,eAAe,OAAO,IAAI;IAC5D;GACF;GAEA,MAAM,IAAI,IAAI,MAAM,eAAe,IAAI,OAAO,GAAG,MAAM,IAAI;GAC3D,MAAM,SAAS,QAAQ,IAAI,WAAW,CAAC,GAAG,CAAC;GAC3C,IAAI,IAAI,MAAM,QAAQ,GAAG,MAAM,YAAY,OAAO,MAAM;GAExD,IAAI,IAAI,MAAM,WAAW,GACvB,MAAM,eAAe,OAAO,IAAI,MAAM,oBAAoB,IAAI,QAAQ,SAAS,GAAG,GAAG,IAAI,CAAC;QACvF,IAAI,IAAI,MAAM,OAAO,GAAG;IAE3B,MAAM,IAAI,QAAQ,SAAS,QAAQ,WAAW,MAAM,MAAM,KAAK,CAAC,CAAC;IAEjE,IAAI,QAAQ,IAAI,GAAG,CAAC,MAAM,GACxB,MAAM,eAAe,OAAO,OAAO,GAAG,OAAO,IAAI,MAAM,SAAS,MAAM,UAAU,CAAC;GACrF;EACF;CACF;AACF;;;;;AAMA,MAAM,iBACJ,MACA,UACe;CACf,MAAM,OAAO,MAAM,iBAAiB;CACpC,MAAM,QAAQA,KAAG,MAAM,gBAAgB,KAAK,IAAI;CAChD,MAAM,SAAS,MAAM,UAAU,QAAQ;CACvC,MAAM,QAAQ,UAAU,MAAM,OAAO,CAAC;CACtC,MAAM,KAAK,UAAU,MAAM,IAAI,CAAC;CAChC,MAAM,OAAO,SAAiB,KAAK,QAAQ,SAAS;;CAGpD,MAAM,WAAW,QAAwB;EACvC,IAAI,UAAU,GAAG,OAAO;EAExB,MAAM,EAAE,OAAO,QAAQ,OAAO,aAAa,KAAK;EAChD,MAAM,UAAU,MAAM;EAKtB,QAJc,QACV,MAAM,SAAS,SAAS,IAAIA,IAAG,UAAU,SAAU,MAAM,IAAIA,IAAE,UAAU,QAAQ,CAAC,IAClF,UAAU,YAEC,QAAQ;CACzB;CAEA,OAAO;EACL,GAAG;EACH,QAAQ;GACN,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,MAAM,OAAO,MAAM,KAAK,KAAK,SAAS;GACtC,IAAI,CAAC,MAAM;GAEX,MAAM,IAAI,QAAQ,GAAG;GACrB,MAAM,SAAS,MAAM,MAAM,KAAK,OAAO;GACvC,MAAM,IAAI,MAAM,MAAM,KAAK,SAAS;GACpC,IAAI,WAAW,WAAW,MAAM;GAChC,IAAI,cAAqB;GACzB,MAAM,KAAK,IAAI,MAAM,QAAQ,IAAI,KAAK,SAAS,CAAC,IAAI,KAAA;GACpD,IAAI,IAAI,WAAW,QAAQ,eAAe,QAAQ,IAAI,IAAI,MAAM,GAAG,CAAC;GAEpE,IAAI,IAAI,MAAM,WAAW,GACvB,IAAI,IAAI,MAAM,OAAO,GAAG;IACtB,MAAM,UAAU,KAAK,QAAQ,CAAC;IAE9B,IAAI,SACF,cAAc,OAAO,OAAO,GAAG,OAAO,GAAG,OAAO,IAAI,MAAM,SAAS,MAAM,UAAU;GACvF,OAAO;IACL,MAAM,IAAI,KAAK,YAAY,CAAC;IAC5B,IAAI,GAAG,cAAc,QAAQ,SAAS,GAAG,WAAW,CAAC,CAAC;GACxD;GAEF,MAAM,eAAe,KAAK,SAAS,WAAW;GAC9C,MAAM,YAAY,KAAK,SAAS,QAAQ;EAC1C;CACF;AACF;;;;;AAMA,MAAM,oBACJ,MACA,UACe;CACf,MAAM,QAAQ,MAAM,gBAAgB,CAAC;CACrC,MAAM,QACH,MAAM,MAAM,IAAI,MAAM,MAAM,YAAY,MAAM,SAAS,IAAI,MAAM,MAAM,UAAU,IAAI;CACxF,MAAM,EAAE,MAAM,SAAS,SAAS,KAAK;CACrC,MAAM,aAAa,MAAM,OAAO,QAAQ;CACxC,MAAM,eACJ,MAAM,YAAY,aAAa,UAAU,KAAA,GAAW,MAAM,MAAM,CAAC;CACnE,MAAM,CAAC,QAAQ,GAAG,YAAY,MAAM,WAAW,CAAC;CAChD,MAAM,OAAO,UAAU,UAAU,CAAC;CAClC,IAAI,OAAO;CACX,IAAI,UAAU;CAEd,OAAO;EACL,GAAG;EACH,QAAQ;GACN,UAAU;GACV,OAAO;GACP,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,IAAI,SAAS,GAAG;GAEhB,MAAM,IAAIA,IAAE,SAAS,KAAK,QAAQ,GAAG,CAAC;GAEtC,MAAM,QAAQA,IAAE,IAAI,IAAI;GACxB,IAAI;GAEJ,IAAI,UAAU,GAAG,QAAQ;QACpB,IAAI,KAAK,GAAG,QAAQ;QACpB,IAAIA,IAAE,IAAI,IAAI,MAAM,GAAG,QAAU,GAAK,OAAO;QAC7C,QAAUA,IAAE,SAAS,IAAI,KAAK,GAAK,OAAO;GAE/C,MAAM,UAAU,MAAM,MAAM,KAAK,OAAO;GACxC,MAAM,OAAO,WAAW,OAAO;GAC/B,MAAM,iBAAiB,aAAa,OAAO;GAC3C,IAAI,SAAS;IAAE,UAAU;IAAY,YAAY;GAAa;GAE9D,IAAI,KAAK,cAAc,IAAI;IAEzB,MAAM,QAAQ,SAAS,OAAO,KAAK,WAAW,MAAM,IAAI,IACnD,MAAM,KAAK,KAAK,WAAW,MAAM,IAAK,KAAK,QAAQ,WACpD,MAAM,MAAM,KAAK,SAAS;IAE9B,SAAS;KAAE,UAAU,WAAW,KAAK;KAAG,YAAY,aAAa,KAAK;IAAE;GAC1E;GAEA,IAAI,OAAO,GACT,MAAM,YACJ,KAAK,SACL,QAAQ,IAAI,MAAM,QAAQ,eAAe,QAAQ,SAAS,OAAO,UAAU,IAAI,GAAG,KAAK,CAAC,CAC1F;GAEF,IAAI,OAAO,GACT,MAAM,eACJ,KAAK,SACL,WAAW,MAAM,gBAAgB,OAAO,YAAY,KAAK,CAAC,CAC5D;GAEF,IAAI,OAAO,GAAG;IAEZ,MAAM,OAAOA,IAAE,IAAI,QAAQ,OAAO;IAElC,UAAUA,IAAE,IAAI,KAAK;IAErB,MAAM,eAAe,KAAK,SAAS,SAAS,WAAW,cAAc,GAAG,MAAM,IAAI,CAAC;GACrF;EACF;CACF;AACF;;;;;AAMA,MAAM,cAAc,UAA4B;CAC9C,GAAG;CACH,MAAM,OAAO;EACX,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;EACtD,IAAI,CAAC,MAAM,SAAS,KAAK,OAAO,GAAG,OAAO;EAC1C,MAAM,QAAQ,IAAI;EAClB,OAAO;CACT;CACA,SAAS,CAAC;CACV,OAAO,OAAO;EACZ,MAAM,WAAW,IAAI;CACvB;AACF;;;;;AAMA,MAAM,aAAa,UAA4B;CAC7C,GAAG;CACH,MAAM,OAAO;EACX,MAAM,IAAI,KAAK,SAAS,KAAK,SAAS;EACtC,OAAO;CACT;CACA,SAAS,CAAC;AACZ;;;;;;AAOA,MAAM,mBACJ,MACA,UACe;CACf,MAAM,OAAO,MAAM,eAAe,CAAC;CACnC,MAAM,SAAS;EAAC,KAAK;EAAM,KAAK;EAAQ,KAAK;EAAM,KAAK;CAAG;CAC3D,MAAM,OAAO,OAAO,QACjB,MAAM,OAAO,SAAU,UAAU,KAAA,IAAY,OAAO,OAAQ,KAAK,MAClE,CACF;CACA,MAAM,KAAK,OAAO,KAAK,UAAUA,IAAE,SAAS,CAAC,CAAC;CAC9C,IAAI,OAA0B;EAAC;EAAG;EAAG;EAAG;CAAC;CAEzC,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,IAAI,MAAM,OAAO,KAAK,OAAO,GAAG,OAAO,MAAM,YAAY,KAAK,OAAO;GACrE,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,IAAI,SAAS,GAAG;GAEhB,MAAM,SACJ,KAAK,cAAc,MAAM,MAAM,OAAO,KAAK,SAAS,IAChD,MAAM,YAAY,KAAK,SAAS,IAChC;GACN,MAAM,IAAI,SAAS,KAAK,QAAQ,GAAG;GACnC,MAAM,MAAM,CAAC,GAAG,MAAM,YAAY,KAAK,OAAO,CAAC;GAE/C,KAAK,IAAI,OAAO,GAAG,OAAO,GAAG,QAC3B,IAAI,OAAQ,KAAK,MAAO,IAAI,QAAQA,IAAE,KAAK,SAAU,OAAO,QAAS,KAAK,SAAU,CAAC;GAEvF,MAAM,eAAe,KAAK,SAAS,GAA6B;EAClE;CACF;AACF;;;;;;AAOA,MAAM,kBACJ,MACA,UACe;CACf,MAAM,EAAE,OAAO,IAAI,SAAS,gBAAgB,MAAM,cAAc,CAAC,CAAC;CAClE,IAAI;CAEJ,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,OAAO,MAAM,MAAM,KAAK,OAAO;GAC/B,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,IAAI,SAAS,GAAG;GAEhB,MAAM,SAAU,KAAK,cAAc,MAAM,MAAM,MAAM,KAAK,SAAS,KAAM;GACzE,MAAM,UAAU,MAAM,MAAM,KAAK,OAAO;GACxC,IAAI,CAAC,WAAW,CAAC,MAAM;GACvB,MAAM,SACJ,KAAK,SACL,WAAW,SAAS,MAAM,QAAQ,MAAM,SAAS,KAAK,QAAQ,GAAG,CAAC,CACpE;EACF;CACF;AACF;;AAGA,MAAM,gBAAgB,MAAY,UAAiE;CACjG,MAAM,EAAE,KAAK,IAAI,SAAS,QAAQ,MAAM,YAAY,CAAC,CAAC;CACtD,IAAI;CAEJ,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,IAAI,MAAM,KAAK,KAAK,OAAO,MAAM,SAAS,OAAO,MAAM,IAAI;GAC3D,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,IAAI,SAAS,KAAK,CAAC,QAAQ,MAAM,KAAK,KAAK,OAAO,MAAM,SAAS;GAEjE,MAAM,IAAIA,IAAE,SAAS,KAAK,QAAQ,GAAG,CAAC;GAEtC,MAAM,OAAO,SAAS,MAAM,IAAI,GAAG,MAAM,IAAI,MAAM,CAAC,GAAG,IAAI;EAC7D;CACF;AACF;;;;;AAMA,MAAM,aAAa,UAA4B;CAC7C,GAAG;CACH,MAAM,OAAO;EACX,KAAK,MAAO,KAAK,QAAQ,KAAK,WAAY;EAC1C,OAAO,MAAM,KAAK,KAAK,OAAO,MAAM,UAAU,MAAM,UAAU,KAAK,OAAO;CAC5E;CACA,SAAS,CAAC;CACV,OAAO,OAAO;EACZ,MAAM,SAAS,KAAK,OAAO;CAC7B;AACF;;;;;AAMA,MAAM,iBACJ,MACA,UACe;CACf,MAAM,KAAK,MAAM,WAAW;CAC5B,IAAI,OAAO;CAEX,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,IAAI,MAAM,KAAK,KAAK,OAAO,MAAM,QAAQ,OAAO,MAAM,OAAO,KAAK,OAAO;GACzE,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,IAAI,OAAO,KAAA,KAAa,MAAM,KAAK,KAAK,OAAO,MAAM,QAAQ;GAE7D,MAAM,SACJ,KAAK,cAAc,MAAM,MAAM,KAAK,KAAK,SAAS,MAAM,SACpD,MAAM,OAAO,KAAK,SAAS,IAC3BA,IAAE,EAAE;GACV,MAAM,IAAIA,IAAE,SAAS,KAAK,QAAQ,GAAG,CAAC;GAEtC,MAAM,UAAU,KAAK,SAASA,IAAE,QAAQ,SAAS,QAAQ,CAAC,CAAC;EAC7D;CACF;AACF;;;;;AAMA,MAAM,cACJ,MACA,OAEA,YACe;CACf,MAAM,SAAS,KAAK,MAAM,MAAM,cAAc,CAAC;CAE/C,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,IAAI,MAAM,KAAK,KAAK,OAAO,MAAM,SAAS,OAAO;GACjD,OAAO,MAAM,WAAW,KAAK,SAAS;IACpC,QAAQ,UAAU,MAAM,MAAM,KAAK;IACnC,OAAO,KAAK,QAAQ,MAAM,UAAU;IACpC;GACF,CAAC;EACH;EACA,SAAS,CAAC;EACV,OAAO,OAAO;GACZ,MAAM,UAAU,KAAK,OAAO;EAC9B;CACF;AACF;;AAGA,MAAM,kBACJ,MACA,UACe;CACf,MAAM,EAAE,OAAO,IAAI,SAAS,UAAU,MAAM,cAAc,CAAC,GAAG,oBAAoB;CAClF,IAAI;CAEJ,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,OAAO,MAAM,MAAM,KAAK,OAAO,KAAK;GACpC,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,MAAM,UAAU,MAAM,MAAM,KAAK,OAAO;GACxC,IAAI,SAAS,KAAK,CAAC,WAAW,CAAC,MAAM;GAErC,MAAM,SAAU,KAAK,cAAc,MAAM,MAAM,MAAM,KAAK,SAAS,KAAM;GAEzE,MAAM,SACJ,KAAK,SACL,WAAW,SAAS,MAAM,QAAQ,MAAM,SAAS,KAAK,QAAQ,GAAG,CAAC,CACpE;EACF;CACF;AACF;;AAGA,MAAM,eACJ,MACA,OACA,aACe;CACf,MAAM,SAAuB;EAC3B;EACA,WAAW,MAAM,aAAa;EAC9B,WAAWA,IAAE,MAAM,cAAc,CAAC;EAClC,WAAWA,IAAE,MAAM,cAAc,CAAC;EAClC,WAAWA,IAAE,MAAM,cAAc,CAAC;EAClC,QAAQA,IAAE,MAAM,UAAU,CAAC;EAC3B,SAAS,WAAW,KAAKA,IAAE,MAAM,WAAW,EAAE;EAC9C,YAAY,WAAWA,IAAE,MAAM,eAAe,CAAC,IAAI;EACnD,YAAY,MAAM;EAClB,YAAY,MAAM,eAAe;CACnC;CAEA,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO,MAAM,SAAS,KAAK,OAAO,KAAK,MAAM,YAAY,KAAK,SAAS,MAAM;EAC/E;EACA,SAAS,CAAC;EACV,OAAO,OAAO;GACZ,MAAM,WAAW,KAAK,SAAS,MAAM;EACvC;CACF;AACF;;;;;;AAOA,MAAM,WAAW,MAAY,UAAsD;CACjF,MAAM,EAAE,MAAM,SAAS,SAAS,KAAK;CACrC,MAAM,QAAQ,UAAU,MAAM,OAAO,CAAC;CACtC,MAAM,KAAK,UAAU,MAAM,IAAI,CAAC;CAEhC,MAAM,OAAO,UAA4B;EACvC,MAAM,WACJ,MAAM,KAAK,KAAK,SAAS,KAAK,aAAa,MAAM,MAAM,gBAAgB,EAAE,KAAK,QAAQ;EACxF,IAAI,SAAS,WAAW,MAAM,MAAM,KAAK,SAAS,CAAC;EAEnD,IAAI,SAAS,KAAA,KAAa,SAAS,KAAK,MAAM,SAAS,KAAK,SAAS,GAAG;GACtE,MAAM,QAAQ,MAAM,KAAK,KAAK,WAAW,MAAM,IAAI;GAEnD,IAAI,OAAO,SAAS,WAAW,KAAK;EACtC;EAEA,OAAO;GACL;GACA,aAAa,MAAM,gBAAgB;GACnC,aAAa,MAAM,iBAAiB;GACpC,SAASA,IAAE,MAAM,WAAW,CAAC;GAC7B,UAAU,MAAM,YAAY,OAAO;GACnC,SAAS,MAAM,WAAW,OAAO;GACjC,oBAAoBA,IAAE,MAAM,uBAAuB,CAAC;GACpD,YAAY,MAAM,eAAe;GACjC;GACA,UAAU,OACR,QAAQ,SAAS,QAAQ,WAAW,QAAQ,CAAC,GAC7C,OACA,IACA,MAAM,SACN,MAAM,UACR;EACF;CACF;CAEA,IAAI;CAEJ,OAAO;EACL,GAAG;EACH,MAAM,OAAO;GACX,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,IAAI,MAAM,KAAK,KAAK,OAAO,MAAM,cAAc,OAAO;GACtD,UAAU,IAAI,KAAK;GACnB,OAAO,MAAM,SAAS,KAAK,SAAS,OAAO;EAC7C;EACA,OAAO,OAAO;GACZ,IAAI,MAAM,KAAK,KAAK,OAAO,MAAM,cAAc;GAC/C,UAAU,IAAI,KAAK;GACnB,MAAM,UAAU,KAAK,SAAS,OAAO;EACvC;EACA,OAAO,OAAO;GACZ,IAAI,SAAS,MAAM,QAAQ,KAAK,SAAS,OAAO;EAClD;CACF;AACF;;;;;;AAOA,MAAM,kBACJ,MACA,UACe;CACf,MAAM,EAAE,MAAM,SAAS,SAAS,KAAK;CACrC,MAAM,SAASA,IAAE,MAAM,gBAAgB,CAAC;CACxC,IAAI,OAAO;CAEX,OAAO;EACL,GAAG;EACH,QAAQ;GACN,OAAO;GACP,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;GACtD,OAAO;EACT;EACA,OAAO,OAAO,KAAK;GACjB,MAAM,UAAU,MAAM,MAAM,KAAK,OAAO;GACxC,IAAI,YAAY,KAAA,GAAW;GAE3B,MAAM,IAAIA,IAAE,SAAS,KAAK,QAAQ,GAAG,CAAC;GACtC,MAAM,QAAQA,IAAE,IAAI,IAAI;GACxB,IAAI;GAEJ,IAAI,UAAU,GAAG,QAAQ;QACpB,IAAI,KAAK,GAAG,QAAQ;QACpB,IAAIA,IAAE,IAAI,IAAI,MAAM,GAAG,QAAU,GAAK,OAAO;QAC7C,QAAUA,IAAE,SAAS,IAAI,KAAK,GAAK,OAAO;GAE/C,IAAI,SAAS;GAEb,IAAI,KAAK,cAAc,IAAI;IACzB,SAAS,WAAW,MAAM,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC;IAEjD,IAAI,SAAS,KAAA,KAAa,SAAS,KAAK,MAAM,SAAS,KAAK,SAAS,GAAG;KACtE,MAAM,QAAQ,MAAM,KAAK,KAAK,WAAW,MAAM,IAAI;KACnD,IAAI,OAAO,SAAS,MAAM,EAAE;IAC9B;GACF;GAEA,MAAM,SAAS,KAAK,SAASA,IAAE,WAAW,SAAS,WAAW,KAAK,CAAC;EACtE;CACF;AACF;;AAGA,MAAM,SAAS,UAA4B;CACzC,GAAG;CACH,QAAQ;EACN,QAAQ,KAAK,QAAb;GACE;IAEE,KAAK,MAAM,MAAM,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ;IACtD,OAAO;EACX;CACF;CACA,SAAS,CAAC;AACZ;;AAKA,MAAa,sBAAkC,IAAI,IAAI;CACrD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;;AAGD,MAAM,+BAA2C,IAAI,IAAI;CACvD;CACA;CACA;CACA;CACA;AACF,CAAC;;;;;AAMD,MAAa,YAAY,WAAiC;CACxD,MAAM,sBAAM,IAAI,IAAoB;CAEpC,OAAO,SAAS,SAAS,QAAQ,UAAU;EACzC,IAAI,CAAC,IAAI,IAAI,OAAO,WAAW,GAAG,IAAI,IAAI,OAAO,aAAa,KAAK;CACrE,CAAC;CAED,MAAM,MAAoB,CAAC;CAE3B,MAAM,UAAU,IAAI,IAClB,OAAO,OAAO,SAAS,WACrB,OAAO,WAAW,iBAAiB,SAAS,MAAM,IAAI,IAClD,CAAC,IAAI,IAAI,OAAO,QAAQ,MAAM,EAAE,CAAC,IACjC,CAAC,CACP,CACF;CAEA,KAAK,MAAM,UAAU,OAAO,QAAQ;EAClC,MAAM,CAAC,OAAO,UAAU,OAAO;EAC/B,MAAM,UAAU,UAAU,KAAA,IAAY,KAAA,IAAY,IAAI,IAAI,KAAK;EAC/D,MAAM,YAAY,WAAW,KAAA,IAAY,KAAM,IAAI,IAAI,MAAM,KAAK;EAClE,IAAI,YAAY,KAAA,KAAa,cAAc,IAAI;EAE/C,IAAI,SAAwB,OAAO;EAGnC,IAAI,WAAW,0BAA0B,aAAa,GAAG;GACvD,MAAM,OAAO,KAAK,aAAa,OAAO,SAAS,UAAU,CAAE;GAC3D,IAAI,QAAQ,KAAK,QAAQ,GAAG,SAAS;EACvC;EAEA,IAAI,cAAc,MAAM,aAAa,IAAI,MAAM,GAAG;EAElD,IAAI,QAAQ,aAAa,OAAO,IAAI;EAEpC,IAAI,WAAW,cAAc,UAAU,GAAG,QAAQ;EAElD,MAAM,WAAW,OAAO,aAAa,KAAA,IAAY,IAAI,aAAa,OAAO,QAAQ;EACjF,MAAM,OAAa;GACjB;GACA,MAAM,KAAK,YAAY;GACvB;GACA;GACA;GACA,OAAO,SAAS,MAAM;GACtB;GACA;GACA,KAAK;GACL,QAAQ,SAAS,QAAQ,OAAO,QAAQ;EAC1C;EAEA,IAAI,WAAW,iBAAiB,IAAI,KAAK,OAAO,MAAM,MAAM,CAAC;OACxD,IAAI,OAAO,WAAW,wBAAwB,IAAI,KAAK,cAAc,MAAM,MAAM,CAAC;OAClF,IAAI,OAAO,WAAW,2BAA2B,IAAI,KAAK,iBAAiB,MAAM,MAAM,CAAC;OACxF,IAAI,WAAW,sBAAsB,IAAI,KAAK,WAAW,IAAI,CAAC;OAC9D,IAAI,WAAW,cAAc,IAAI,KAAK,UAAU,IAAI,CAAC;OACrD,IAAI,OAAO,WAAW,0BAA0B,IAAI,KAAK,gBAAgB,MAAM,MAAM,CAAC;OACtF,IAAI,OAAO,WAAW,yBAAyB,IAAI,KAAK,eAAe,MAAM,MAAM,CAAC;OACpF,IAAI,OAAO,WAAW,uBAAuB,IAAI,KAAK,aAAa,MAAM,MAAM,CAAC;OAChF,IAAI,WAAW,cAAc,IAAI,KAAK,UAAU,IAAI,CAAC;OACrD,IAAI,OAAO,WAAW,wBAAwB,IAAI,KAAK,cAAc,MAAM,MAAM,CAAC;OAClF,IAAI,OAAO,WAAW,eACzB,IAAI,KAAK,WAAW,MAAM,QAAQ,QAAQ,IAAI,OAAO,CAAC,CAAC;OACpD,IAAI,OAAO,WAAW,yBAAyB,IAAI,KAAK,eAAe,MAAM,MAAM,CAAC;OACpF,IAAI,OAAO,WAAW,gBACzB,IAAI,KAAK,YAAY,MAAM,QAAQ,OAAO,SAAS,QAAQ,CAAE,SAAS,UAAU,CAAC;OAC9E,IAAI,OAAO,WAAW,YAAY,IAAI,KAAK,QAAQ,MAAM,MAAM,CAAC;OAChE,IAAI,OAAO,WAAW,yBAAyB,IAAI,KAAK,eAAe,MAAM,MAAM,CAAC;OACpF,IAAI,KAAK,MAAM,IAAI,CAAC;CAC3B;CAEA,OAAO;AACT;;;;;;;ACh6BA,MAAMC,MAAI,KAAK;AACf,MAAM,UAAU;AAChB,MAAM,WAAuB;CAAE,GAAG;CAAG,GAAG;CAAG,GAAG;CAAG,GAAG;AAAE;;AAYtD,MAAM,aAAa,IAAa,IAAa,IAAa,IAAa,MAAuB;CAC5F,MAAM,IAAI,QAAQ,kBAAkB,IAAI,IAAI,IAAI,IAAI,CAAC;CAErD,OAAO,QAAQ,eAAe,GAAG,IAAI,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,CAAC,CAAC;AACnE;AAEA,MAAM,QAAQ,QAAQ;;AAGtB,MAAM,OAAO,MAA8B;CACzC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,IAAI,OAAO;EAAE,GAAG;EAAG,GAAG;CAAE;CAE9C,MAAM,QAAQ,KAAK,KAAK,EAAE,CAAC;CAC3B,MAAM,MAAM,KAAK,IAAI,KAAK;CAC1B,IAAI,MAAMA,IAAE,IAAK,GAAG,OAAO;EAAE,GAAG;EAAG,GAAG;CAAE;CACxC,OAAO;EAAE,GAAG,MAAM,GAAG,QAAQ,GAAG;EAAG,GAAG;CAAE;AAC1C;;AAGA,MAAM,OAAO,MAA8B;CACzC,MAAM,IAAI,KAAK,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;CAClC,MAAM,MAAM,KAAK,IAAI,CAAC;CACtB,MAAM,IAAI,MAAMA,IAAE,IAAK,IAAI,IAAI,MAAM,GAAG,MAAM,CAAC;CAE/C,OAAO;EAAE,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,GAAG,KAAK,IAAI,CAAC;CAAE;AAClD;;AAGA,MAAM,WAAW,MAAkB,GAAe,SAAiC;CACjF,MAAM,UAAU,KAAK,OAAO,CAAC;CAC7B,MAAM,IAAI,IAAI,KAAK,SAAS,SAAS,IAAI,CAAC;CAC1C,MAAM,IAAI,IAAI,KAAK,SAAS,SAAS,IAAI,CAAC;CAE1C,OAAO,KAAK,SAAS,GAAG,IAAI,MAAM,QAAQ,IAAI,GAAG,CAAC,GAAG,IAAK,CAAC,CAAC;AAC9D;;AAGA,MAAM,SAAS,IAAgB,IAAgB,IAAgB,IAAgB,MAC7E,MAAM,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,QAAQ,IAAI,IAAI,EAAE,GAAG,QAAQ,IAAI,IAAI,EAAE,GAAG,CAAC,GAAGA,KAAG,IAAI,KAAK,IAAI,CAAC,CAAC;;;;;AAMhG,MAAa,cAAc,UAAmD;CAC5E,IAAI,CAAC,SAAS,MAAM,cAAc,QAAQ,OAAO,KAAA;CAEjD,MAAM,OACJ,MAAM,cAAc,+BAChB,MAAM,OAAO,KAAK,EAAE,UAAU,mBAAmB;EAAE;EAAU;CAAY,EAAE,IAC3E,MAAM,OAAO,KAAK,cAAc,EAAE,SAAS,EAAE;CACnD,MAAM,IAAI,KAAK;CACf,IAAI,IAAI,GAAG,OAAO,KAAA;CAElB,MAAM,SAAS,MAAM,SAAS;CAE9B,MAAM,SAAS;EACb,SAAS,KAAK,IAAI,EAAE,CAAE,WAAW,KAAK,EAAE,CAAE;EAC1C,GAAG,KAAK,KAAK,QAAQ,IAAI,QAAQ;EACjC,SAAS,KAAK,EAAE,CAAE,WAAW,KAAK,IAAI,EAAE,CAAE;EAC1C,GAAI,SAAS,CAAC,KAAK,EAAE,CAAE,QAAQ,IAAI,CAAC;CACtC;CAEA,MAAM,QAAQ;EACZ,KAAK,EAAE,CAAE,eAAe;EACxB,GAAG,KAAK,KAAK,QAAQ,IAAI,eAAe,QAAQ;EAChD,KAAK,IAAI,EAAE,CAAE,eAAe;EAC5B;CACF;CACA,MAAM,OAAO,SAAS,IAAI,IAAI;CAC9B,MAAM,cAAiB,MAAoB,MACzC;EAAC,KAAK,IAAI;EAAK,KAAK;EAAK,KAAK,IAAI;EAAK,KAAK,IAAI;CAAG;CAGrD,MAAM,SAAqB,CAAC;CAG5B,MAAM,QAAkB,CAAC,GAAG,CAAC;CAC7B,IAAI,QAAQ;CAEZ,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,KAAK;EAC7B,MAAM,CAAC,IAAI,IAAI,IAAI,MAAM,WAAW,QAAQ,CAAC;EAC7C,MAAM,QAAQ,CAAC,KAAK;EAEpB,IAAI,WAAW,QAAQ,WAAW,IAAI,IAAI,IAAI,IAAI,CAAC;EACnD,IAAI,SAAS;EAEb,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS,KAAK;GACjC,MAAM,UAAU,QAAQ,WAAW,IAAI,IAAI,IAAI,IAAIA,IAAE,IAAI,KAAM,CAAC;GAEhE,SAASA,IAAE,SAAS,QAAQ,SAAS,UAAU,OAAO,CAAC;GACvD,MAAM,KAAKA,IAAE,QAAQ,MAAM,CAAC;GAC5B,WAAW;EACb;EAEA,OAAO,KAAK;EACZ,QAAQA,IAAE,QAAQ,MAAM;EACxB,MAAM,IAAI,KAAK;CACjB;CAEA,KAAK,MAAM,SAAS,QAAQ,IAAI,OAAO,MAAM,SAAS,OAAO,MAAO,MAAM,KAAKA,IAAE,QAAQ,KAAK,CAAE;CAChG,MAAM,KAAK;CACX,MAAM,OAAO,KAAK;CAClB,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK,MAAM,KAAKA,IAAE,MAAM,KAAM,KAAK;;CAGrE,MAAM,aAAa,MAAkC;EACnD,IAAI,IAAI;EAER,OAAO,IAAI,QAAQ,EAAE,MAAM,KAAM,IAAI;EAErC,MAAM,UAAU,IAAI;EAEpB,OAAO,WAAW,KAAK,UAAU,OAAO,UAAU,KAAA;CACpD;;CAGA,MAAM,YAAY,GAAW,MAAgC;EAC3D,MAAM,QAAQ,OAAO;EACrB,IAAI,KAAK;EAGT,KAAK,IAAI,OAAO,GAAG,OAAO,IAAI;GAC5B,OAAO,KAAK,MAAM,OAAO,CAAC;GAC1B,MAAM,IAAI,MAAM,MAAO,CAAC,OAAO;EACjC;EAEA,IAAI,EAAE,IAAI,MAAM,MAAO;EACvB,OAAO,CAAC,IAAIA,KAAG,IAAI,MAAM,QAAS,MAAM,KAAK,KAAM,MAAM,IAAK,CAAC;CACjE;CAEA,MAAM,SACJ,GACA,UACwB;EACxB,MAAM,IAAI,UAAU,CAAC;EACrB,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;EAE5B,MAAM,CAAC,GAAG,YAAY,SAAS,GAAG,CAAC;EACnC,MAAM,CAAC,IAAI,IAAI,IAAI,MAAM,WAAW,QAAQ,CAAC;EAC7C,MAAM,IAAI,MAAM,IAAI,IAAI,IAAI,IAAIA,IAAE,IAAI,KAAM,CAAC;EAC7C,MAAM,IAAI,MAAM,IAAI,IAAI,IAAI,IAAIA,KAAG,IAAI,KAAK,KAAM,CAAC;EAEnD,OAAO,QAAQ,KAAK,GAAG,GAAG,QAAQ;CACpC;CAEA,MAAM,WAAW,MAAM,cAAc;CAErC,OAAO;EACL,WAAW,MAAO,KAAK,IAAI,OAAO,KAAK,KAAK,IAAI,OAAO,QAAQ,MAAM,GAAG,QAAQ,UAAU;EAC1F,UAAU,MAAM,MAAM,GAAG,SAAS;EAClC,cAAc,MAAM;GAClB,IAAI,CAAC,UAAU;IAGb,MAAM,IAAI,MAAM,GAAG,SAAS;IAC5B,IAAI,CAAC,GAAG,OAAO,KAAA;IAEf,MAAM,IAAI,QAAQ,eAAe,QAAQ,UAAU,CAAC,GAAG,EAAE;IACzD,MAAM,IAAI,QAAQ,UAAU,QAAQ,MAAM;KAAE,GAAG;KAAG,GAAG;KAAG,GAAG;IAAE,GAAG,CAAC,CAAC;IAElE,OAAO,aAAa,UAAU,GAAG,QAAQ,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC;GAC1D;GAEA,IAAI,KAAK,GAAG,OAAO,MAAM;GACzB,IAAI,KAAK,GAAG,OAAO,MAAM;GAEzB,MAAM,IAAI,UAAU,CAAC;GACrB,IAAI,MAAM,KAAA,GAAW,OAAO,KAAA;GAE5B,MAAM,CAAC,GAAG,YAAY,SAAS,GAAG,CAAC;GACnC,MAAM,CAAC,IAAI,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;GAC5C,MAAM,IAAI,MAAM,IAAI,IAAI,IAAI,IAAIA,IAAE,IAAI,KAAM,CAAC;GAC7C,MAAM,IAAI,MAAM,IAAI,IAAI,IAAI,IAAIA,KAAG,IAAI,KAAK,KAAM,CAAC;GAEnD,OAAO,MAAM,GAAG,GAAG,QAAQ;EAC7B;CACF;AACF;;;;;;ACnLA,MAAa,cACX,UACA,QACA,SACY;CACZ,MAAM,UAAU,SAAS,MAAM,SAAS,KAAK,KAAK,YAAY,MAAM,KAAK,YAAY,CAAC;CACtF,IAAI,CAAC,SAAS,OAAO;CACrB,OAAO,QAAQ,OAAO,SAAS,QAAQ,YAAY,QAAQ,aAAa;AAC1E;;AAGA,MAAa,YAAY,QAAgB,QAAoC;CAC3E,MAAM,QAAQ,OAAO,aAAa,CAAC;CACnC,MAAM,QAAQ,OAAO,KAAK,KAAK,CAAC,CAAC,MAAM,SAAS,KAAK,YAAY,MAAM,IAAI,YAAY,CAAC;CAExF,OAAO,UAAU,KAAA,IAAY,KAAA,IAAY,MAAM;AACjD;;;;;AAaA,MAAa,UAAU,QAAgB,EAAE,MAAM,CAAC,GAAG,SAAS,MAAoB,CAAC,MAAe;CAC9F,MAAM,WAAW,SAAS,QAAQ,UAAU;CAC5C,IAAI,aAAa,KAAA,KAAa,CAAC,WAAW,KAAK,QAAQ,QAAQ,GAAG,OAAO;CAEzE,IAAI,OAAO,SAAS,UAAU,aAAa,KAAA,GACzC,OAAO,WAAW,KAAK,QAAQ,kBAAkB;CAEnD,OAAO;AACT;;AAGA,MAAa,gBAAgB,WAA0D;CACrF,MAAM,QAAQ,OAAO,WAAW;CAEhC,OAAO,QAAQ,IAAI,aAAa,QAAQ,IAAI,eAAe,KAAA;AAC7D;AAmBA,MAAM,OAAO,QAAgB,SAC3B,WAAW,WAAW,OAAO,OAAO,SAAS,IAAI,KAAK;;;;;;;AAQxD,MAAa,gBAAgB,UAAoB,UAAwB,CAAC,MAAoB;CAC5F,MAAM,UAA+B,SAAS;CAE9C,OAAO,SAAS,OAAO,SAAS,SAAS,WAAW;EAClD,IAAI,OAAO,SAAS,cAAc,OAAO,SAAS,cAAc,OAAO,CAAC;EACxE,IAAI,IAAI,QAAQ,WAAW,KAAK,CAAC,OAAO,QAAQ,OAAO,GAAG,OAAO,CAAC;EAElE,MAAM,QAAQ,SAAS,MAAM,OAAO,WAAW;EAC/C,IAAI,CAAC,OAAO,OAAO,CAAC;EAEpB,MAAM,WACJ,OAAO,kBAAkB,SAAS,KAAM,OAAO,iBAAiB,OAAO;EACzE,MAAM,WAAW,SAAS,QAAQ,UAAU;EAE5C,MAAM,aAAa,aAAa,eAAe,aAAa;EAE5D,OAAO,CACL;GACE;GACA;GACA;GACA;GAEA,KAAK,OAAO,SAAS,aAAa,aAAa,MAAM,IAAI,KAAA;GACzD,eAAe,SAAS,QAAQ,gBAAgB,MAAM,KAAA;GACtD,QAAQ;IACN,UAAU;KAAE,GAAG,MAAM,EAAE;KAAG,GAAG,MAAM,EAAE;KAAG,GAAG,MAAM,EAAE;IAAE;IACrD,OAAO,OAAO,WAAW;IACzB,YAAY,OAAO,UAAU;IAC7B,SAAS,IAAI,QAAQ,aAAa,KAAK,CAAC;IACxC,KAAK,IAAI,QAAQ,aAAa;IAC9B,KAAK,SAAS,QAAQ,OAAO,MAAM,KAAA;IACnC,GAAI,WAAW,EAAE,QAAQ;GAC3B;EACF,CACF;CACF,CAAC;AACH;;;;;;;;;;;;;;;AC1BA,MAAa,kBACX,YACA,iBACA,mBACU,QAAQ,SAAS,QAAQ,SAAS,YAAY,eAAe,GAAG,QAAQ,cAAc,CAAC;;;;;AAMnG,MAAa,UACX,QACA,cACA,YACa;CACb,MAAM,WAAW,IAAI,SAAS,QAAQ,OAAO;CAE7C,SAAS,MAAM,CAAC;CAChB,SAAS,KAAK,CAAC;CACf,SAAS,KAAK,YAAY;CAC1B,OAAO;AACT;;AAcA,MAAM,iBAA8B;CAAC;CAAI;CAAK;CAAQ;AAAM;AAE5D,MAAM,iBAAiB,WAAgC;CACrD,IAAI,OAAO,SAAS,UAAU,OAAO;CAErC,MAAM,EAAE,MAAM,WAAW,UAAU,aAAa,OAAO,eAAe,CAAC;CACvE,MAAM,CAAC,GAAG,GAAG,GAAG,KAAK;CAErB,OAAO;EAAC,QAAQ;EAAG,aAAa;EAAG,YAAY;EAAG,YAAY;CAAC,CAAC,CAAC,IAC/D,KAAK,MACP;AACF;;AAMA,MAAM,8BAA2C,IAAI,IAAI;CACvD;CACA;CACA;CACA;CACA;AACF,CAAC;;AAuBD,MAAM,4BAAyC,IAAI,IAAI;CAAC;CAAU;CAAU;CAAS;AAAO,CAAC;;AAG7F,MAAM,2BAAwC,IAAI,IAAI;CAAC;CAAY;CAAc;AAAM,CAAC;;;;;;AAOxF,MAAa,cAAiB,OAAY,QAAkC;CAC1E,MAAM,KAAK,UAAkB,IAAI,MAAM,MAAO;CAE9C,MAAM,aAAa,OAAe,QAAgB;EAChD,OAAO,MAAM,QAAQ,IAAI;GACvB,MAAM,IAAI,EAAE,KAAK;GACjB,MAAM,IAAI,EAAE,QAAQ,KAAK,OAAO,MAAM,SAAS,CAAC,CAAC;GACjD,MAAM,IAAI,EAAE,MAAM,CAAC;GACnB,MAAM,QAAQ,IAAI,IAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;GAC7E,IAAI,OAAO;GACX,IAAI,QAAQ;GAGZ,SAAS;IACP,OAAO,EAAE,IAAI,IAAI,OAAO;IAExB;KAAG;WACI,QAAQ,EAAE,KAAK;IAEtB,IAAI,SAAS,MAAM;IAEnB,MAAM,OAAO,MAAM;IAEnB,MAAM,QAAQ,MAAM;IACpB,MAAM,SAAS;IACf;GACF;GAGA,IAAI,MAAM,QAAQ,OAAO,OAAO;IAC9B,UAAU,MAAM,GAAG;IACnB,MAAM;GACR,OAAO;IACL,UAAU,OAAO,IAAI;IACrB,QAAQ;GACV;EACF;CACF;CACA,IAAI,MAAM,SAAS,IAAI,UAAU,GAAG,MAAM,MAAM;CAEhD,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS;EACjD,MAAM,OAAO,MAAM;EACnB,IAAI,KAAK;EAET,OAAO,KAAK,KAAK,IAAI,IAAI,IAAI,EAAE,KAAK,CAAC,GAAG;GACtC,MAAM,MAAM,MAAM,KAAK;GACvB;EACF;EAEA,MAAM,MAAM;CACd;CAEA,OAAO;AACT;AAmBA,IAAa,WAAb,MAAuC;CACrC;;CAEA;CACA;CACA;;CAEA;CACA;CACA;;CAEA;CAEA,SAAwB;CACxB,SAAS;CACT;CACA,uBAAgB,IAAI,IAAoB;CACxC;CACA,WAAyB,CAAC;CAC1B,UAAwB,CAAC;;CAEzB,SAAmB,CAAC;CACpB,eAA6B,CAAC;CAC9B;CACA,0BAAmB,IAAI,IAAyB;CAChD,WAAgE,CAAC;CACjE,wBAAiB,IAAI,IAAuB;CAC5C,0BAAmB,IAAI,IAAoB;CAC3C;CACA,OAAO;CACP,2BAAoB,IAAI,IAA2D;CACnF;CACA;CACA;CAEA,YAAY,QAAgB,UAA2B,CAAC,GAAG;EACzD,MAAM,EAAE,OAAO,OAAO,QAAQ,QAAQ,UAAU,OAAO,CAAC,MAAM;EAE9D,KAAK,SAAS;EACd,KAAK,WAAW,aAAa,OAAO,QAAQ;EAC5C,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,KAAK,aAAa;EAClB,KAAK,OAAO,QAAQ,OAAO,EAAE,OAAO,OAAO;EAC3C,KAAK,cAAc,QAAQ,cAAc;EACzC,KAAK,gBAAgB,QAAQ;EAC7B,KAAK,SAAS,QAAQ,SAAS,CAAC;EAChC,KAAK,cAAc,QAAQ,cAAc,CAAC;EAE1C,OAAO,SAAS,SAAS,QAAQ,OAAO;GACtC,IAAI,OAAO,SAAS,cAClB,KAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,OAAO,eAAe,gBAAgB,CAAC,CAAC;EAC7E,CAAC;EAGD,MAAM,QAAQ,OAAO,SAAS,MAAM,WAAW,OAAO,SAAS,OAAO;EAEtE,KAAK,UAAU,OAAO,SAAS,UAAU,UAAU,MAAM,IAAI,CAAC,IAAI;EAClE,KAAK,aAAa,OAAO,SAAS,UAAU,UAAU,MAAM,OAAO,CAAC,IAAI;EAExE,KAAK,YAAY,OAAO,SAAS,KAAK,YAAY;GAChD;GACA,QAAQ,KAAA;GACR,OACE,kBAAkB,SACd,UAAU,OAAO,cAAc,KAAK,OAAO,cAAc,MAAM,IAC/D,QAAQ;GACd,MAAM,OAAO,SAAS,gBAAgB,WAAW,OAAO,SAAS,IAAI,KAAA;GACrE,OAAO,cAAc,MAAM;GAC3B,OAAO,OAAO,SAAS,UAAU,QAAQ,OAAO,UAAU,IAAI,KAAA;GAC9D,OACE,OAAO,SAAS,UACZ,KAAA,IACA,OAAO,OAAO,SAAS,WAAW,IAChC,gBACA,UAAU,OAAO,cAAc,CAAC,GAAG,aAAa,CAAC,CAAC;GAC1D,QAAQ,OAAO,SAAS,UAAU,QAAQ,OAAO,UAAU,CAAC,CAAC,OAAO;GACpE,OAAO,CAAC;EACV,EAAE;EACF,OAAO,SAAS,SAAS,EAAE,eAAe,UAAU;GAClD,IAAI,CAAC,KAAK,KAAK,IAAI,WAAW,GAAG,KAAK,KAAK,IAAI,aAAa,KAAK;EACnE,CAAC;EAED,KAAK,UAAU,SAAS,UAAU;GAChC,MAAM,EAAE,WAAW;GACnB,IAAI,CAAC,OAAO,OAAO,SAAS,WAAW,KAAK,CAAC,UAAU,IAAI,OAAO,IAAI,GAAG;GAEzE,MAAM,QAAQ,QAAQ,UAAU,OAAO,MAAM,OAAO,WAAW;GAC/D,IAAI,CAAC,OAAO;GAEZ,IAAI,WAAW,OAAO,MAAM,QAAQ,MAAM;QACrC;IACH,MAAM,KAAK,MAAM,SAAS,KAAK,IAAI,MAAM,IAAI;IAC7C,IAAI,OAAO,KAAA,GAAW,MAAM,SAAS;KAAE,UAAU,MAAM;KAAU;IAAG;GACtE;EACF,CAAC;EAED,KAAK,UAAU,WACb,SAAS,MAAM,CAAC,CAAC,MAAM,GAAG,OAAO,EAAE,UAAU,MAAM,EAAE,UAAU,EAAE,IAChE,UAAU,MAAM,UAAU,CAC7B;EACA,KAAK,UAAU,CACb,GAAG,IAAI,IAAI,KAAK,QAAQ,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC,QAAQ,WAAW,CAAC,IAAI,IAAI,MAAM,CAAC,CAAC,CAC3F;CACF;CAEA,IAAI,QAAuB;EACzB,OAAO,KAAK;CACd;;CAGA,IAAI,QAAgB;EAClB,OAAO,KAAK;CACd;;CAGA,IAAI,SAAgC;EAClC,OAAO,KAAK;CACd;;CAGA,IAAI,cAAqC;EACvC,OAAO,KAAK;CACd;;CAGA,QAAQ,MAAiC;EACvC,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI;EAE7B,OAAO,OAAO,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU,GAAG,CAAE;CAC5D;;;;;;CAOA,MAAM,MAAiC;EACrC,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI;EAC7B,IAAI,OAAO,KAAA,GAAW,OAAO,KAAA;EAE7B,MAAM,EAAE,WAAW,KAAK,UAAU;EAClC,MAAM,QAAQ,KAAK,aAAa,EAAE;EAElC,OAAO,YAAY,IAAI,OAAO,IAAI,IAAI,QAAQ,SAAS,KAAK,YAAY,KAAK,IAAI;CACnF;;CAGA,MAAM,eAAe,GAAS;EAC5B,IAAI,KAAK,WAAW,YAAY,KAAK,WAAW,aAAa,KAAK,WAAW,QAAQ;GACnF,KAAK,SAAS;GACd,KAAK,WAAW,KAAK,QAAQ,MAAM;EACrC,OAAO,IAAI,KAAK,WAAW,WAAW,KAAK,WAAW,KAAK,QAAQ,MAAM;EAEzE,KAAK,SAAS,KAAK,OAAO,YAAY;EACtC,KAAK,KAAK,YAAY;CACxB;;CAGA,OAAa;EACX,KAAK,SAAS;EACd,KAAK,WAAW,KAAK,QAAQ,MAAM;EACnC,KAAK,SAAS;EACd,KAAK,SAAS;CAChB;;;;;;CAOA,KAAK,cAA4B;EAE/B,IAAI,OAAQ,KAAK,SAAS,KAAK,MAAM,YAAY,IAAK;EAEtD,IAAI,eAAe,GAAG;GACpB,IAAI,OAAO,GAAG,OAAO;GACrB,KAAK,SAAS;GACd,KAAK,SAAS;GACd,KAAK,WAAW,KAAK,QAAQ,MAAM;EACrC;EAEA,MAAM,OAAO,KAAK;EAElB,KAAK,OAAO;EACZ,IAAI,SAAS,IAAI,SAAS,GAAG;EAC7B,IAAI,KAAK,WAAW,aAAa,KAAK,WAAW,WAAW;EAE5D,KAAK,UAAU,MAAM,IAAI;EACzB,KAAK,OAAO,IAAI;EAChB,KAAK,QAAQ,IAAI;EAEjB,IAAI,KAAK,WAAW,GAAG,KAAK,SAAS,KAAK,MAAM;EAEhD,IAAI,SAAS,IAAI,KAAK,aAAa,GAAG;GACpC,IAAI,KAAK,MAAM;IACb,KAAK,KAAK;IACV,KAAK,MAAM,CAAC;IACZ;GACF;GAEA,KAAK,SAAS;GACd,KAAK,SAAS;EAChB;CACF;CAIA,MAAM,QAAuB;EAC3B,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,OAAO,QAAQ,OAAO,MAAM,OAAO,SAAS,MAAM,MAAM,OAAO,EAAE;EAErE,IAAI,OAAO,OAAO,SAAS,cAAc;GACvC,MAAM,OAAO,KAAK,YAAY,OAAO,MAAM,OAAO,WAAW;GAC7D,IAAI,MAAM,OAAO;EACnB;EAEA,OAAO,OAAO,SAAS,QAAQ;CACjC;;;;;;;;CASA,aAAa,QAAgB,QAAQ,GAAU;EAC7C,MAAM,QAAQ,KAAK,UAAU;EAC7B,MAAM,OAAO,OAAO,OAAO;EAC3B,MAAM,OACJ,QAAQ,KAAK,CAAC,OAAO,SACjB,KAAK,aAAa,QAAQ,eAAe,WAAW,UAAU,IAAI,CAAC,CAAC,GAAG,EAAE,IACzE,KAAA;EACN,MAAM,SAAS,QAAQ,KAAK,KAAK,IAAI,KAAK,MAAM;EAChD,MAAM,kBAAkB,QAAQ,KAAK,KAAK,YAAY,KAAK,QAAQ,KAAK,eAAe;EACvF,MAAM,iBAAiB,QAAQ,KAAK,KAAK,YAAY,KAAK,OAAO,KAAK,SAAS;EAE/E,IAAI,WAAW,KAAA,KAAa,CAAC,mBAAmB,CAAC,gBAAgB,OAAO,KAAK,MAAM,MAAM;EAEzF,OAAO,eAAe,KAAK,aAAa,QAAQ,QAAQ,CAAC,GAAG,iBAAiB,cAAc;CAC7F;;CAGA,YAAY,QAAgB,UAAyB;EACnD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,OAAO;EAEZ,IAAI,MAAM,QAAQ,OAAO,MAAM,OAAO,SAAS,YAAY,MAAM,OAAO,IAAI,QAAQ;EACpF,MAAM,QAAQ,aAAa,MAAM,OAAO,QAAQ;EAEhD,IAAI,MAAM,OAAO,SAAS,cACxB,KAAK,YAAY,cAAc,MAAM,OAAO,aAAa,QAAQ;EAEnE,IAAI,MAAM,OAAO,SAAS,UACxB,KAAK,MAAM,QAAQ,MAAM,OAAO,KAAK,YAAY,MAAM,QAAQ;CACnE;CAEA,eAAe,QAAgB,aAA0B;EACvD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,OAAO;EACZ,IAAI,MAAM,QAAQ,OAAO,MAAM,OAAO,SAAS,eAAe,MAAM,OAAO,IAAI,WAAW;EAC1F,MAAM,QAAQ,aAAa,MAAM,OAAO,WAAW;EAEnD,IAAI,MAAM,OAAO,SAAS,cACxB,KAAK,YAAY,iBAAiB,MAAM,OAAO,aAAa,WAAW;EAEzE,IAAI,MAAM,OAAO,SAAS,UACxB,KAAK,MAAM,QAAQ,MAAM,OAAO,KAAK,eAAe,MAAM,WAAW;CACzE;CAEA,YAAY,QAA6B;EACvC,OAAO,KAAK,UAAU,OAAO,EAAE,SAAS;CAC1C;CAEA,eAAe,QAAgB,OAA0B;EACvD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,OAAO;EACZ,MAAM,QAAQ;EAEd,IAAI,MAAM,OAAO,SAAS,WACxB,KAAK,MAAM,QAAQ,MAAM,OAAO,KAAK,eAAe,MAAM,KAAK;CACnE;CAEA,MAAM,QAAwC;EAC5C,OAAO,KAAK,UAAU,OAAO,EAAE;CACjC;CAEA,SAAS,QAAgB,OAAyB;EAChD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,OAAO,OAAO,MAAM,QAAQ;CAClC;CAEA,MAAgB;EACd,MAAM,EAAE,UAAU,KAAK;EAEvB,OAAO;GAAE,GAAG;GAAO,IAAI,MAAM,MAAM,KAAK;EAAY;CACtD;CAEA,OAAO,KAAe,MAAoB;EACxC,MAAM,QAAQ,EAAE,GAAG,KAAK,KAAK,MAAM;EACnC,IAAI,OAAO,GAAG,MAAM,KAAK,IAAI,MAAM,KAAK;EACxC,IAAI,OAAO,IAAK,MAAQ,QAAQ,IAAI,OAAS,MAAM,OAAO,IAAI;EAE9D,IAAI,OAAO,KACT,MAAQ,QAAQ,IAAI,OAAS,MAAM,MAAM,IAAI,KAAO,MAAM,UAAU,IAAI;EAE1E,IAAI,OAAO,GAAG,MAAM,QAAQ,IAAI;EAChC,KAAK,KAAK,QAAQ;CACpB;CAEA,UAAU,QAAyB;EACjC,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,SAAS,CAAC,OAAO,MAAM,QAAQ,KAAK,MAAM,GAAG,OAAO;EAEzD,MAAM,EAAE,aAAa,kBAAkB,MAAM;EAC7C,MAAM,WAAW,kBAAkB,SAAS,KAAM,iBAAiB;EACnE,MAAM,SAAS,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,QAAQ,EAAE;EAGxD,OAAO,WAAW,KAAK,gBAAgB,aAAa,QAAQ;EAC5D,KAAK,SAAS,IAAI,QAAQ,MAAM;EAChC,OAAO;CACT;CAEA,SAAS,QAAsB;EAC7B,MAAM,SAAS,KAAK,SAAS,IAAI,MAAM;EACvC,IAAI,QAAQ,OAAO,WAAW,KAAA;CAChC;CAEA,OAAO,QAAwB;EAC7B,OAAO,KAAK,SAAS,IAAI,MAAM,CAAC,EAAE,UAAU;CAC9C;CAEA,UAAU,QAAgB,OAAqB;EAC7C,MAAM,SAAS,KAAK,SAAS,IAAI,MAAM,KAAK,EAAE,QAAQ,EAAE;EAExD,OAAO,SAAS;EAChB,KAAK,SAAS,IAAI,QAAQ,MAAM;EAChC,IAAI,OAAO,UAAU,OAAO,SAAS,QAAQ,SAAS;CACxD;;CAGA,IAAI,UAA0D;EAC5D,OAAO,CAAC,GAAG,KAAK,SAAS,QAAQ,CAAC,CAAC,CAChC,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CACzB,SAAS,CAAC,IAAI,EAAE,gBACf,WAAW,CAAC;GAAE,QAAQ,KAAK,UAAU,GAAG,CAAE,OAAO;GAAa;EAAS,CAAC,IAAI,CAAC,CAC/E;CACJ;CAEA,YAAY,QAAgB,QAA+B;EACzD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,SAAS,CAAC,OAAO,MAAM,QAAQ,KAAK,MAAM,GAAG,OAAO;EACzD,IAAI,KAAK,YAAY,cAAc,MAAM,OAAO,aAAa,MAAM,MAAM,OAAO,OAAO;EACvF,KAAK,SAAS,KAAK;GAAE;GAAQ;EAAO,CAAC;EACrC,OAAO;CACT;CAEA,WAAW,QAAgB,QAA4B;EACrD,MAAM,KAAK,KAAK,SAAS,WAAW,SAAS,KAAK,WAAW,MAAM;EACnE,IAAI,MAAM,GAAG,KAAK,SAAS,OAAO,IAAI,CAAC;EACvC,KAAK,YAAY,aAAa,KAAK,UAAU,OAAO,CAAE,OAAO,aAAa,MAAM;CAClF;CAEA,SAAS,QAAgB,KAAyB;EAChD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,SAAS,CAAC,OAAO,MAAM,QAAQ,KAAK,MAAM,GAAG,OAAO;EACzD,IAAI,KAAK,YAAY,WAAW,MAAM,OAAO,aAAa,GAAG,MAAM,OAAO,OAAO;EACjF,KAAK,MAAM,IAAI,QAAQ,GAAG;EAC1B,OAAO;CACT;CAEA,UAAU,QAAgB,KAAsB;EAC9C,KAAK,MAAM,IAAI,QAAQ,GAAG;EAC1B,KAAK,YAAY,YAAY,KAAK,UAAU,OAAO,CAAE,OAAO,aAAa,GAAG;CAC9E;CAEA,QAAQ,QAAgB,KAAsB;EAC5C,IAAI,KAAK,MAAM,IAAI,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM;EAC5D,KAAK,YAAY,UAAU,KAAK,UAAU,OAAO,CAAE,OAAO,aAAa,GAAG;CAC5E;CAEA,MAAM,QAAoC;EACxC,OAAO,KAAK,QAAQ,IAAI,MAAM;CAChC;CAEA,SAAS,QAAgB,QAAsB;EAC7C,IAAI,CAAC,KAAK,QAAQ,IAAI,MAAM,GAAG;EAC/B,KAAK,QAAQ,IAAI,QAAQ,MAAM;EAC/B,KAAK,YAAY,WAAW,KAAK,UAAU,OAAO,CAAE,OAAO,aAAa,MAAM;CAChF;;CAGA,IAAI,UAAsD;EACxD,OAAO,KAAK,SAAS,KAAK,EAAE,QAAQ,cAAc;GAChD,QAAQ,KAAK,UAAU,OAAO,CAAE,OAAO;GACvC;EACF,EAAE;CACJ;;CAGA,IAAI,OAA6C;EAC/C,OAAO,CAAC,GAAG,KAAK,MAAM,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,UAAU;GACnD,QAAQ,KAAK,UAAU,GAAG,CAAE,OAAO;GACnC;EACF,EAAE;CACJ;;CAGA,QAAQ,MAAkC;EACxC,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI;EAE7B,OAAO,OAAO,KAAA,IAAY,KAAA,IAAY,KAAK,QAAQ,IAAI,EAAE;CAC3D;CAEA,IAAI,MAAc;EAChB,OAAO,KAAK;CACd;CAEA,WACE,QACA,EAAE,QAAQ,MAAM,WACP;EACT,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,SAAS,CAAC,OAAO,MAAM,QAAQ,KAAK,MAAM,GAAG,OAAO;EAEzD,MAAM,EAAE,aAAa,kBAAkB,MAAM;EAE7C,KAAK,QAAQ,IAAI,QAAQ;GACvB,QAAQ;GACR,UAAU,kBAAkB,SAAS,KAAM,iBAAiB;GAC5D;GACA;GACA,SAAS,YAAY,MAAM,OAAO,OAAO,SAAS,SAAS,KAAK;GAChE,SAAS,KAAK;EAChB,CAAC;EACD,OAAO;CACT;CAEA,UAAU,QAAsB;EAC9B,KAAK,QAAQ,OAAO,MAAM;CAC5B;CAEA,MAAM,QAAwC;EAC5C,OAAO,KAAK,UAAU,OAAO,EAAE;CACjC;CAEA,SAAS,QAAgB,OAAyB;EAChD,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,OAAO,OAAO,MAAM,QAAQ;CAClC;;;;;CAMA,IAAI,SAAqE;EACvE,OAAO,CAAC,GAAG,KAAK,QAAQ,QAAQ,CAAC,CAAC,CAC/B,MAAM,CAAC,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,CACzB,KAAK,CAAC,IAAI,YAAY;GACrB,MAAM,EAAE,OAAO,UAAU,KAAK,UAAU;GAExC,OAAO;IAAE,GAAG;IAAQ,OAAO,SAAS;IAAe,UAAU,WAAW,KAAK;GAAE;EACjF,CAAC;CACL;CAEA,KAAK,QAAoC;EACvC,OAAO,KAAK,UAAU,OAAO,EAAE,OAAO;CACxC;;CAGA,IAAI,UAA2B;EAC7B,OAAO,UAAU,KAAK,KAAK,KAAK;CAClC;;CAGA,IAAI,UAA+B;EACjC,MAAM,QAAQ,KAAK,OAAO,SAAS,MAAM,WAAW,OAAO,SAAS,OAAO;EAE3E,OAAO,OAAO,SAAS,UAAU,MAAM,UAAU,KAAA;CACnD;;;;;CAMA,WAAW,UAAwB,CAAC,GAAgB;EAClD,OAAO,KAAK,UAAU,SAAS,EAAE,QAAQ,OAAO,QAAQ,YACtD,OAAO,MAAM,CAAC,OAAO,OAAO,SAAS,WAAW,KAAK,OAAO,QAAQ,OAAO,IACvE,CAAC,YAAY,OAAO,QAAQ,OAAO,OAAO,UAAU,CAAC,CAAC,IACtD,CAAC,CACP;CACF;CAEA,OAAO,QAAyB;EAC9B,OAAO,KAAK,UAAU,OAAO,EAAE,OAAO,SAAS;CACjD;CAEA,IAAI,SAAiB,QAAsB;EACzC,MAAM,KAAK,KAAK,UAAU;EAC1B,MAAM,OAAO,KAAK,UAAU;EAC5B,IAAI,CAAC,MAAM,CAAC,MAAM;EAElB,IAAI,CAAC,KAAK,MAAM,SAAS,OAAO,GAAG;GACjC,KAAK,MAAM,KAAK,OAAO;GAGvB,MAAM,OAAiB,CAAC;GAExB,GAAG,MAAM,SAAS,MAAM,UAAU;IAChC,IAAI,QAAQ,MAAM,GAAG,OAAO,KAAK,KAAK,IAAI;IAE1C,MAAM,QAAQ,KAAK,UAAU;IAC7B,IAAI,OAAO,MAAM,QAAQ,MAAM,MAAM,QAAQ,SAAS,SAAS,OAAO;GACxE,CAAC;GACD,GAAG,QAAQ;GACX,IAAI,CAAC,GAAG,MAAM,SAAS,MAAM,GAAG,GAAG,MAAM,KAAK,MAAM;EACtD;EAEA,KAAK,eAAe,SAAS,KAAK,KAAK;EACvC,KAAK,YAAY,SAAS,WAAW,KAAK,KAAK,CAAC;EAChD,KAAK,eAAe,SAAS,KAAK,KAAK;CACzC;;CAGA,KAAK,MAAsC;EACzC,MAAM,KAAK,KAAK,KAAK,IAAI,IAAI;EAC7B,MAAM,QAAQ,OAAO,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU;EAE5D,IAAI,CAAC,SAAU,MAAM,OAAO,SAAS,YAAY,MAAM,OAAO,SAAS,WACrE,OAAO,KAAA;EAET,MAAM,CAAC,MAAM,MAAM,KAAK,UAAU,MAAM;EAExC,OAAO;GAAE,OAAO,QAAQ,SAAS,KAAK,YAAY,MAAM,KAAK;GAAG;GAAM;GAAM;GAAK;EAAO;CAC1F;;CAGA,aAAa,SAAqC;EAChD,MAAM,KAAK,KAAK,KAAK,IAAI,OAAO;EAChC,MAAM,QAAQ,OAAO,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU;EAC5D,MAAM,OAAO,OAAO,OAAO,SAAS,YAAY,MAAM,MAAM,KAAK,KAAA;EAEjE,OAAO,SAAS,KAAA,IAAY,KAAA,IAAY,KAAK,UAAU,KAAK,EAAE,OAAO;CACvE;CAEA,SAAS,QAAyB;EAChC,MAAM,OAAO,KAAK,UAAU,OAAO,EAAE,OAAO;EAE5C,OAAO,SAAS,cAAc,SAAS;CACzC;;;;;;CAOA,KAAK,QAAgB,MAAc,MAAiC;EAClE,MAAM,QAAQ,KAAK,UAAU;EAC7B,IAAI,CAAC,OAAO,OAAO,KAAA;EAEnB,MAAM,EAAE,aAAa,MAAM,SAAS,MAAM;EAC1C,MAAM,OAAO,UACX,SAAS,QAAQ,SAAS,KAAK,aAAa,MAAM,GAAG,KAAK;EAE5D,IAAI,SAAS,YAAY;GACvB,MAAM,QACJ,SAAS,KAAK,aAAa,YACvB,IAAI,KAAK,KAAK,YAAY,aAAa,IAAI,CAAC,IAC5C,SAAS,MAAM,KAAK,YAAY,MAAM,SACpC,MAAM,QACN,KAAA;GAER,OAAO,SAAS,QAAQ,SAAS,KAAK,YAAY,KAAK;EACzD;EAEA,IAAI,SAAS,cACX,OAAO,IACL,SAAS,KAAK,aAAa,YACvB,KAAK,KAAK,YAAY,aAAa,IAAI,IACvC,KAAK,KAAK,OAAO,aAAa,IAAI,CACxC;CAGJ;CAEA,KAAK,QAAkC;EACrC,OAAO,KAAK,UAAU,OAAO,EAAE;CACjC;CAEA,QAAQ,OAAyB;EAC/B,IAAI,MAAM,OAAO,WAAW,sBAAsB;EAElD,MAAM,CAAC,QAAQ,IAAI,SAAS,MAAM,MAAM,OAAO;EAE/C,KAAK,aAAa,KAAK;GACrB;GACA;GACA,WAAW,MAAM,OAAO,aAAa;GACrC;GACA,iBAAiB,MAAM,OAAO,oBAAoB;EACpD,CAAC;CACH;CAEA,WAAW,OAAyB;EAClC,KAAK,eAAe,KAAK,aAAa,QAAQ,eAAe,WAAW,UAAU,KAAK;CACzF;;CAKA,SAAS,KAAmB;EAC1B,MAAM,UAAW,MAAM,KAAK,SAAU;EAEtC,KAAK,UAAU,SAAS,EAAE,QAAQ,SAAS,OAAO;GAChD,IAAI,CAAC,SAAS,IAAI,OAAO,IAAI,GAAG;GAChC,KAAK,KAAK,UAAU,OAAO,aAAa,OAAO;GAC/C,IAAI,OAAO,SAAS,QAAQ,KAAK,YAAY,UAAU,OAAO,aAAa,OAAO;GAIlF,MAAM,WAAW,KAAK,SAAS,IAAI,EAAE,CAAC,EAAE;GACxC,IAAI,UACF,SAAS,QAAQ,KAAK,OAAO,UAAU,IAAK,GAAG;IAAE,WAAW;IAAO,SAAS;GAAW,CAAC;EAC5F,CAAC;EACD,KAAK,SAAS;CAChB;;CAGA,QAAQ,KAAmB;EACzB,KAAK,SAAS,GAAG;EAEjB,KAAK,IAAI,QAAQ,GAAG,QAAQ,KAAK,QAAQ,SAAS;GAChD,MAAM,QAAQ,KAAK,QAAQ;GAE3B,MAAM,OAAO,MAAM,GAAG;GAEtB,IAAI,QAAQ,IAAI,MAAM,QAAQ,KAAK,MAAM,MAAM,GAAG;QAC7C;IACH,KAAK,QAAQ,OAAO,OAAO,CAAC;IAC5B,MAAM,SAAS,IAAI;GACrB;EACF;CACF;;CAGA,WAAiB;EACf,KAAK,SAAS,CAAC;EACf,KAAK,MAAM,SAAS,KAAK,QAAQ,OAAO,CAAC,GAAG,MAAM,SAAS,IAAI;CACjE;;CAGA,OAAO,KAAmB;EACxB,OAAO,KAAK,OAAO,UAAU,KAAK,OAAO,KAAM,KAAK,KAAK,QAAQ,KAAK,OAAO,MAAM,CAAE;CACvF;;;;;;CAOA,UAAU,MAAc,IAAkB;EACxC,MAAM,QAAQ,KAAK,SAAS,WAAW,UAAU,MAAM,UAAU,KAAK,SAAS,CAAC;EAChF,IAAI,QAAQ,KAAK,KAAK,SAAS,MAAM,CAAE,UAAU,IAAI,OAAO,GAAG;EAE/D,IAAI,OAAO;EAEX,OAAO,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS,KAAK,CAAE,UAAU,KAAK,OAAO,GAAG;EAEpF,MAAM,0BAAU,IAAI,IAAY;EAEhC,KAAK,MAAM,SAAS,KAAK,SAAS,MAAM,OAAO,IAAI,GAAG;GACpD,OAAO,KAAK,OAAO,UAAU,KAAK,OAAO,OAAQ,IAAI,MAAM,UAAU,GAAG;IACtE,MAAM,OAAO,KAAK,OAAO,MAAM;IAE/B,KAAK,QAAQ,IAAI;IACjB,QAAQ,IAAI,IAAI;GAClB;GAEA,IAAI,CAAC,QAAQ,IAAI,MAAM,KAAK,GAAG;IAC7B,KAAK,QAAQ,MAAM,KAAK;IACxB,QAAQ,IAAI,MAAM,KAAK;GACzB;GAEA,IAAI,MAAM,MAAM,IAAI,GAAG;IACrB,KAAK,QAAQ,KAAK,KAAK;IAEvB,IAAI,MAAM,OAAO,GAAG;KAClB,KAAK,SAAS,KAAK,OAAO,QAAQ,SAAS,SAAS,MAAM,GAAG;KAC7D,KAAK,OAAO,KAAK,MAAM,GAAG;KAC1B,KAAK,OAAO,MAAM,GAAG,MAAM,IAAI,CAAC;IAClC;GACF;GAEA,KAAK,SAAS;EAChB;EAEA,KAAK,SAAS,OAAO,OAAO,OAAO,KAAK;CAC1C;;;;;;CAOA,WAAiB;EACf,MAAM,yBAAS,IAAI,IAAwD;EAE3E,KAAK,MAAM,SAAS,KAAK,SAAS;GAChC,MAAM,QAAQ,OAAO,IAAI,MAAM,OAAO;GAEtC,IAAI,OAAO,MAAM,OAAO,KAAK,KAAK;QAC7B,OAAO,IAAI,MAAM,SAAS;IAAE,QAAQ,CAAC,KAAK;IAAG,SAAS;GAAM,CAAC;EACpE;EAEA,MAAM,MAAoB,CAAC;EAE3B,MAAM,QAAQ,UAAsD;GAClE,IAAI,MAAM,SAAS;GACnB,MAAM,UAAU;GAChB,WAAW,MAAM,SAAS,UAAU,MAAM,IAAI;GAE9C,KAAK,MAAM,SAAS,MAAM,QAAQ;IAChC,MAAM,SAAS,MAAM,cAAc,KAAK,KAAA,IAAY,OAAO,IAAI,MAAM,SAAS;IAC9E,IAAI,QAAQ,KAAK,MAAM;IACvB,IAAI,KAAK,KAAK;GAChB;EACF;EACA,KAAK,MAAM,MAAM,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC,GAAG,KAAK,OAAO,IAAI,EAAE,CAAE;EAC/E,KAAK,UAAU;CACjB;AACF;;AAGA,MAAa,cAAc,UAAoB,MAAsB,SACnE,SAAS,OAAO,SAAS,MACtB,WACC,OAAO,SAAS,QAAQ,OAAO,gBAAgB,QAAQ,CAAC,OAAO,OAAO,SAAS,WAAW,CAC9F;;ACz+BF,MAAMC,MAAI,KAAK;;;;;AAYf,MAAa,qBAAqB,OAAe,YAAuC;CACtF,MAAM,MAAMA,IAAE,QAAQ,OAAO;CAC7B,MAAM,eAAe,KAAK,MAAMA,IAAE,MAAM,GAAI,CAAC;CAE7C,OAAO;EAAE;EAAc,OAAOA,IAAE,MAAMA,IAAE,eAAe,IAAK,CAAC;CAAE;AACjE;;;;;;AAOA,IAAa,YAAb,MAAuB;CACrB;CACA,YAAY;CACZ,YAAY;CAEZ,YAAY,UAAoB;EAC9B,KAAK,WAAW;EAEhB,SAAS,MAAM,CAAC;EAChB,SAAS,KAAK,CAAC;CACjB;CAEA,IAAI,WAAoB;EACtB,OAAO,KAAK;CACd;;CAGA,OAAa;EACX,KAAK,YAAY;CACnB;;;;;CAMA,OAAO,cAAsB,UAAU,GAAY;EACjD,MAAM,EAAE,aAAa;EAErB,IAAI,CAAC,KAAK,WACR,IAAI,CAAC,KAAK,WAAW;GACnB,SAAS,KAAK,UAAU,YAAY;GACpC,IAAI,CAAC,SAAS,QAAQ,SAAS,UAAU,KAAK,SAAS,aAAa,GAAG,KAAK,YAAY;EAC1F,OAAO;GACL,SAAS,KAAK,SAAS,WAAW,SAAS,KAAK;GAChD,KAAK,YAAY;GACjB,KAAK,YAAY;EACnB;EAEF,IAAI,KAAK,WAAW,SAAS,KAAK,GAAG;EACrC,OAAO,KAAK;CACd;AACF;;AC9DA,MAAM,IAAI,KAAK;;AAGf,MAAa,UAAU,EAAE,GAAG,GAAG,SAAyB;CACtD,GAAG;EAAE,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,GAAG,EAAE;CAAE;CAC5B,GAAG;EAAE,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,GAAG,EAAE;CAAE;CAC5B,GAAG;EAAE,GAAG,EAAE;EAAG,GAAG,EAAE;EAAG,GAAG,EAAE;CAAE;AAC9B;;AAGA,MAAa,YAAY,EAAE,OAAO,MAAM,MAAM,WAA+B;CAC3E,UAAU;EAAE,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;EAAG,GAAG,MAAM,EAAE;CAAE;CACrD,aAAa,OAAO,KAAK;CACzB;CACA;CACA;AACF;;;;;;;AAQA,IAAa,YAAb,MAAuB;CACrB,SAA6E,CAAC;CAC9E,UAAU;;CAGV,IAAI,SAA6B;EAC/B,OAAO,KAAK,YAAY,KAAK,KAAA,IAAY,KAAK;CAChD;;CAGA,SAAS,UAAkB,YAAyC;EAClE,IAAI,OAAO;EAEX,OAAO,OAAO,OAAO,KAAK,OAAO,OAAO;EACxC,IAAI,SAAS,KAAK,OAAO,KAAA;EACzB,KAAK,OAAO,QAAQ;GAAE;GAAU;EAAW;EAE3C,MAAM,QAAQ,KAAK,YAAY,KAAK,OAAS,KAAK,OAAO,KAAK,QAAQ,CAAE;EACxE,IAAI,cAAc,WAAW,OAAO,KAAK,UAAU;EACnD,OAAO;CACT;CAEA,QAAQ,MAAoB;EAC1B,KAAK,OAAO,QAAQ,KAAA;EACpB,IAAI,SAAS,KAAK,SAAS;EAE3B,IAAI,OAAO;EACX,IAAI,WAAW;EAEf,KAAK,OAAO,SAAS,MAAM,UAAU;GACnC,IAAI,MAAM,cAAc,KAAK,WAAW,UAAU;IAChD,WAAW,KAAK;IAChB,OAAO;GACT;EACF,CAAC;EACD,KAAK,UAAU;CACjB;AACF;;;;;AAMA,IAAa,YAAb,MAAuB;CACrB,SAAS;CACT,SAAS;CACT,QAAQ;CACR,YAAY;;CAGZ,IAAI,QAAgB,QAAQ,GAAG,QAAQ,OAAa;EAClD,IAAI,OAAO,KAAK,SAAS;EACzB,KAAK,SAAS;EACd,KAAK,QAAQ;EACb,KAAK,YAAY;CACnB;;CAGA,KAAK,SAA0B;EAC7B,IAAI,CAAC,KAAK,WAAW,OAAO;EAE5B,IAAI,KAAK,SAAS,KAAK,QAAQ;GAC7B,MAAM,MAAM,KAAK,QAAQ,UAAU,KAAK;GAExC,KAAK,SAAS,EAAE,GAAG;GACnB,IAAI,EAAE,OAAO,KAAK,SAAS,OAAO;GAClC,KAAK,SAAS,KAAK;EACrB,OAAO,IAAI,KAAK,SAAS,KAAK,QAAQ;GACpC,MAAM,aAAa,KAAK,SAAS,KAAK,QAAQ;GAE9C,KAAK,SAAS,EAAE,UAAU;GAC1B,IAAI,EAAE,cAAc,KAAK,SAAS,OAAO;GACzC,KAAK,SAAS,KAAK;EACrB;EAEA,KAAK,YAAY;EACjB,OAAO;CACT;;CAGA,IAAI,EAAE,OAAO,UAA4B;EACvC,MAAM,UAAU,QAAQ;EAExB,MAAM,UAAU,EAAE,IAAI,IAAI,WAAW,KAAK,SAAS;EAEnD,OAAO,KAAK,OAAO,SAAS,QAAQ,UAAU,KAAM,EAAG;CACzD;;;;;CAMA,KAAK,SAAwE;EAC3E,MAAM,MAAM,KAAK,IAAI,OAAO;EAC5B,MAAM,WAAW;GAAE,OAAO,QAAQ;GAAO,QAAQ,QAAQ,SAAS,IAAI;EAAI;EAE1E,OAAO;GAAE,KAAK;GAAK;GAAU,QAAQ,SAAS,QAAQ,SAAS;EAAO;CACxE;AACF;;;;;;;;;AC1FA,MAAM,eACJ,OACA,SACA,YACG;CACH,KAAK,IAAI,SAAS,GAAG,UAAU,SAAS,QAAQ,QAAQ,UACtD,IAAI,MAAM,SAAS,QAAQ,UAAU,OAAO,CAAE,QAAQ,CAAC,GAAG,OAAO;CAEnE,OAAO,QAAQ,SAAS;AAC1B;AAEA,IAAa,WAAb,MAAsB;CACpB;CACA;;CAEA,UAAU;CACV;;CAEA;CACA,aAAa;CACb,QAAQ;CACR;CAEA,YACE,SACA,QAAuB,CAAC,GACxB,WAA0D,UAAW,QAAQ,EAAE,MAAM,IAAI,CAAC,GAC1F;EACA,KAAK,UAAU;EACf,KAAK,QAAQ;EACb,KAAK,WAAW;CAClB;;CAGA,OAAa;EACX,KAAK,OAAO,CAAC;CACf;CAEA,IAAI,OAAgB;EAClB,OAAO,KAAK,YAAY;CAC1B;CAEA,IAAI,WAAiC;EACnC,OAAO,KAAK,KAAK;CACnB;;CAGA,OAAa;EACX,IAAI,KAAK,MAAM,aAAa,KAAK,MAAM,aAAa,CAAC,KAAK,MAAM,KAAK,QAAQ;CAC/E;CAEA,OAAO,OAAqB;EAC1B,KAAK,UAAU;EAEf,MAAM,QAAQ,KAAK,QAAQ;EAC3B,MAAM,UAAU,KAAK,SAAS,MAAM,KAAK;EAEzC,KAAK,MAAM,IAAI,UACb,IAAI,SAAS,MAAM,QAAQ;GAAE,GAAG;GAAS,MAAM,KAAK,MAAM,QAAQ;EAAM,CAAC,CAC3E;EACA,IAAI,MAAM,SAAS,GAAG,KAAK,WAAW,KAAA;CACxC;;CAGA,OAAO,UAAyB;EAC9B,KAAK,WAAW;EAChB,KAAK,KAAK,KAAK;CACjB;;CAGA,OAAe;EACb,MAAM,OAAO,KAAK,QAAQ,KAAK,QAAQ,EAAE,QAAQ;EACjD,MAAM,QAAQ,UAAuB,YAAY,OAAO,KAAK,SAAS,KAAK,OAAO;EAElF,QAAQ,MAAR;GACE,KAAK,GACH,OAAO,KAAK,UAAU;GACxB,KAAK,GACH,OACE,KAAK,WACJ,KAAK,aAAa,KAAA,IAAY,IAAI,KAAK,KAAK,WAAW;IAAC;IAAG;IAAG;GAAC,IAAI,CAAC,GAAG,CAAC,CAAC;GAE9E,KAAK,GACH,OAAO,KAAK,UAAU,KAAK;IAAC;IAAG;IAAG;GAAC,CAAC;GACtC,KAAK,GACH,OAAO,KAAK,UAAU,KAAK,CAAC,GAAG,CAAC,CAAC;GACnC,KAAK,GACH,OAAO,KAAK,WAAW,KAAK,aAAa,KAAK;IAAC;IAAG;IAAG;GAAC,CAAC,IAAI;GAC7D,KAAK,GACH,OAAO,KAAK,UAAU,KAAK,CAAC,GAAG,CAAC,CAAC;GACnC,SAEE,OAAO,KAAK;EAChB;CACF;;;;;;CAOA,OAAO,cAAsB,UAAU,GAAY;EACjD,IAAI,KAAK,MAAM,OAAO;EAEtB,OAAO,KAAK,OAAO;GACjB,KAAK,IAAK,KAAK;GACf,KAAK,IAAK,OAAO,CAAC;GAElB,MAAM,OAAO,KAAK,KAAK;GAEvB,IAAI,QAAQ,KAAK,QAAQ,QAAQ;IAC/B,KAAK,UAAU;IACf,KAAK,MAAM,KAAA;IACX,OAAO;GACT;GAEA,MAAM,OAAO,KAAK,QAAQ,KAAK,CAAE,QAAQ;GACzC,IAAI,SAAS,KAAK,SAAS,GAAG,KAAK,QAAQ;GAC3C,KAAK,OAAO,IAAI;EAClB;EAEA,IAAI,CAAC,KAAK,IAAK,OAAO,cAAc,OAAO,GAAG,OAAO;EAErD,MAAM,OAAO,KAAK,KAAK;EAEvB,IAAI,OAAO,KAAK,QAAQ,QAAQ;GAE9B,KAAK,OAAO,IAAI;GAChB,OAAO;EACT;EAEA,KAAK,UAAU;EACf,KAAK,MAAM,KAAA;EACX,OAAO;CACT;AACF;;AAGA,IAAa,kBAAb,MAA6B;CAC3B,YAAiC,CAAC;CAElC,IAAI,UAA8B;EAChC,KAAK,UAAU,KAAK,QAAQ;EAC5B,SAAS,KAAK;EACd,OAAO;CACT;;CAGA,OAAO,cAA4B;EACjC,KAAK,MAAM,YAAY,KAAK,UAAU,MAAM,GAC1C,IAAI,SAAS,OAAO,YAAY,GAAG,KAAK,UAAU,OAAO,KAAK,UAAU,QAAQ,QAAQ,GAAG,CAAC;CAChG;CAEA,OAAa;EACX,KAAK,MAAM,YAAY,KAAK,WAAW,SAAS,KAAK;CACvD;;;;;CAMA,KAAK,MAAsB,MAAgE;EACzF,KAAK,MAAM,YAAY,KAAK,WAAW;GACrC,MAAM,WAAW,SAAS;GAE1B,IAAI,SAAS,MAAM,YAAY,YAAY,WAAW,UAAU,MAAM,IAAI,GACxE,OAAO;IAAE;IAAU;GAAK;EAC5B;CAGF;AACF;;;;;;AAwDA,MAAa,iBAAiB,WAA8B;CAC1D,MAAM,MAAiB;EAAE,OAAO,CAAC;EAAG,SAAS,CAAC;EAAG,WAAW,CAAC;EAAG,QAAQ,CAAC;CAAE;CAE3E,KAAK,MAAM,UAAU,OAAO,UAAU;EACpC,MAAM,QACJ,kBAAkB,SACd,UAAU,OAAO,cAAc,KAAK,OAAO,cAAc,MAAM,IAC/D,QAAQ;EACd,MAAM,QAAQ,WAAW,SAAU,OAAO,SAAS,CAAC,IAAK,CAAC;EAC1D,MAAM,OAAO,OAAO;EAEpB,IAAI,OAAO,SAAS,YAAY;GAC9B,MAAM,WAAW,SAAS,QAAQ,UAAU;GAE5C,IAAI,aAAa,KAAA,GAAW;GAC5B,IAAI,MAAM,KAAK;IACb;IACA,UAAU,OAAO,kBAAkB,SAAS,KAAM,OAAO,iBAAiB;IAC1E;IACA;IACA,SAAS,MAAM,SAAS,aAAa;IACrC,KAAK,MAAM,SAAS,aAAa;IACjC,KAAK,SAAS,QAAQ,OAAO,MAAM,KAAA;IACnC,MAAM,aAAa,UAAU,SAAS,QAAQ,WAAW,MAAM,KAAA;IAC/D,YAAY,OAAO,UAAU;IAC7B,OAAO,OAAO,WAAW;IACzB,KAAK,aAAa,MAAM;IACxB,SAAS,SAAS,QAAQ,SAAS,KAAK;IACxC,UAAU,SAAS,QAAQ,UAAU;IACrC,eAAe,SAAS,QAAQ,gBAAgB,MAAM,KAAA;GACxD,CAAC;EACH,OAAO,IAAI,OAAO,SAAS,UAAU;GACnC,MAAM,EAAE,OAAO,IAAI,YAAY,IAAK,WAAW,QAAW,OAAO,eAAe,CAAC;GAEjF,IAAI,QAAQ,KAAK;IAAE;IAAM;IAAO;IAAM,MAAM;IAAW,KAAK;GAAS,CAAC;GACtE,IAAI,UAAU,KAAK;IAAE;IAAM;GAAM,CAAC;EACpC,OAAO,IAAI,OAAO,SAAS,UAAU,IAAI,UAAU,KAAK;GAAE;GAAM;EAAM,CAAC;OAClE,IAAI,OAAO,SAAS,SAAS;GAChC,MAAM,QAAQ,QAAQ,OAAO,UAAU;GACvC,MAAM,eACJ,MAAM,SAAS,IACX;IAAE,WAAW,QAAQ,mBAAmB,MAAM,WAAW,KAAK;IAAG,OAAO,MAAM;GAAQ,IACtF;IAAE,UAAU,WAAW,KAAK;IAAG,OAAO,MAAM;GAAQ;GAE1D,IAAI,KAAK,YAAY,MAAM,kBAAkB,IAAI,SAAS,OAAO;QAC5D,IAAI,KAAK,YAAY,MAAM,iBAAiB,IAAI,QAAQ,OAAO;QAC/D,IAAI,MAAM,IAAI,IAAI,OAAO,KAAK,YAAY,OAAO,MAAM,MAAM,OAAO,OAAO,UAAU,CAAC,CAAC;EAC9F,OAAO,IAAI,OAAO,SAAS,WAAW,OAAO,SAAS,IAAI,UAAU,OAAO;CAC7E;CAEA,OAAO;AACT;;;;;AAMA,MAAa,gBAAgB,WAA0B;CACrD,MAAM,QAAQ,OAAO,SAAS,MAC3B,WACC,OAAO,SAAS,gBAAgB,SAAS,QAAQ,OAAO,CAAC,EAAE,YAAY,MAAM,QACjF;CACA,IAAI,OAAO,SAAS,cAAc,OAAO,QAAQ;CAEjD,MAAM,EAAE,KAAK,WAAW,MAAM,gBAAgB,CAAC;CAC/C,MAAM,QAAQ,UAAU,KAAK,MAAM;CAEnC,OAAO;EACL,GAAG;EACH,GAAG;GAAE,GAAG,MAAM,EAAE;GAAG,GAAG,MAAM,eAAe,gBAAgB;GAAG,GAAG,MAAM,EAAE;GAAG,GAAG;EAAE;CACnF;AACF;;;;;AAMA,MAAa,iBAAiB,UAAiB,WAC7C,QAAQ,SAAS,UAAU,QAAQ,aAAa,MAAM,CAAC,CAAC;;;;;AAM1D,MAAa,mBACX,QACA,YACa,IAAI,SAAS,CAAC,EAAE,OAAO,CAAC,GAAG;CAAE,MAAM;CAAM,UAAU;CAAM,UAAU;AAAE,GAAG,OAAO;;;;;;;;ACvU9F,MAAa,mBAAmB,EAC9B,OACA,gBAMG;CACH,MAAM,0BAAU,IAAI,IAA0B;CAC9C,MAAM,uBAAO,IAAI,IAAgC;;CAEjD,MAAM,yBAAS,IAAI,IAAkB;CAErC,OAAO;EACL,YAAY,QAAQ,QAAQ;GAC1B,MAAM,YAAY,MAAM,MAAM;GAC9B,MAAM,SAAS,UAAU,OAAO,SAAS;GACzC,IAAI,CAAC,aAAa,CAAC,QAAQ,OAAO;GAElC,MAAM,SAAS,UAAU,MAAM,QAAQ;IACrC,WAAW,OAAO;IAClB,WAAW,OAAO;IAClB,QAAQ,OAAO;IACf,WAAW,OAAO;IAClB,YAAY,OAAO;IACnB,SAAS,OAAO;GAClB,CAAC;GACD,IAAI,WAAW,KAAA,GAAW,QAAQ,IAAI,QAAQ,MAAM;GAEpD,IAAI,OAAO,YAAY;IACrB,UAAU,KAAK,OAAO,UAAU;IAChC,OAAO,IAAI,MAAM;GACnB;GACA,OAAO;EACT;EACA,WAAW,QAAQ,QAAQ;GACzB,MAAM,YAAY,MAAM,MAAM;GAC9B,MAAM,SAAS,QAAQ,IAAI,MAAM;GAEjC,QAAQ,OAAO,MAAM;GACrB,IAAI,CAAC,WAAW;GAChB,IAAI,WAAW,KAAA,GAAW,UAAU,KAAK,MAAM;GAC/C,IAAI,OAAO,cAAc,OAAO,OAAO,MAAM,GAAG,UAAU,OAAO,OAAO,UAAU;EACpF;EACA,SAAS,QAAQ,KAAK;GACpB,MAAM,YAAY,MAAM,MAAM;GAE9B,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,IAAI,gBAAgB,GAAG,OAAO;GAEhE,MAAM,SAAS,UAAU,IAAI,IAAI,aAAa;IAC5C,QAAQ,aAAa,IAAI,QAAQ;IACjC,oBAAoB,IAAI;IACxB,YAAY,IAAI;GAClB,CAAC;GACD,IAAI,WAAW,KAAA,GAAW,KAAK,IAAI,IAAI,OAAO,MAAM;GACpD,OAAO;EACT;EACA,UAAU,QAAQ,KAAK;GACrB,MAAM,SAAS,KAAK,IAAI,IAAI,KAAK;GACjC,IAAI,WAAW,KAAA,GAAW,MAAM,MAAM,CAAC,EAAE,aAAa,QAAQ,aAAa,IAAI,QAAQ,CAAC;EAC1F;EACA,QAAQ,QAAQ,KAAK;GACnB,MAAM,SAAS,KAAK,IAAI,IAAI,KAAK;GAEjC,KAAK,OAAO,IAAI,KAAK;GACrB,IAAI,WAAW,KAAA,GAAW,MAAM,MAAM,CAAC,EAAE,QAAQ,MAAM;EACzD;EACA,SAAS,QAAQ,QAAQ;GACvB,MAAM,MAAM,CAAC,EAAE,SAAS,MAAM;EAChC;EACA,YAAY,QAAQ,UAAU;GAC5B,MAAM,MAAM,CAAC,EAAE,gBAAgB,QAAQ;EACzC;EACA,eAAe,QAAQ,aAAa;GAClC,MAAM,MAAM,CAAC,EAAE,mBAAmB,aAAa,WAAW,CAAS;EACrE;EACA,QAAQ,QAAQ,cAAc;GAC5B,MAAM,MAAM,CAAC,EAAE,QAAQ,KAAK,OAAO,eAAe,IAAK,CAAC;EAC1D;EACA,KAAK,QAAQ;GACX,MAAM,YAAY,MAAM,MAAM;GAC9B,IAAI,CAAC,WAAW,OAAO,KAAA;GAEvB,MAAM,EAAE,UAAU,gBAAgB,UAAU;GAE5C,OAAO,QAAQ,QAAQ,UAAU,aAAa,CAAC;EACjD;CACF;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AEjCA,MAAM,WAAW;AACjB,MAAM,uBAAO,IAAI,yBAAS,IAAI,YAAY,CAAC,CAAC;AAE5C,MAAM,SAAS,UAA2B;CACxC,KAAK,WAAW,GAAG,KAAK;CACxB,OAAO,KAAK,UAAU,CAAC,MAAM;AAC/B;AAEA,MAAM,KAAK,KAAK,OAAO,KAAK,EAAE;AAC9B,MAAM,MAAM,KAAK,OAAO,KAAK,KAAK,CAAC;;;;AAKnC,MAAM,aAAa,aAAmB,UACpC,MAAM,KAAK,IAAI,cAAc,KAAK,MAAM,KAAK,UAAU,aAAa,KAAK;AAE3E,MAAa,YAAY,EAAE,cACzB,UAAU,KAAK,OAAO,mBAAmB,OAAO,CAAC,IAAI;AAEvD,MAAa,gBACX,OACA,EACE,SACA,WAAW,OACX,OAAO,aAEG;CACZ,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;CAC7B;CACA;CACA;CACA,MAAM;CACN,MAAM;CACN,OAAO;CACP,OAAO;CACP,YAAY;CACZ,MAAM;CACN,OAAO;CACP,SAAS,KAAK,KAAK;CACnB,WAAW;EAAE,UAAU,KAAK;EAAU,UAAU,QAAQ;CAAK;AAC/D;;AAGA,MAAa,QAAQ,UAA6B;CAChD,QAAQ,OAAR;EACE,KAAK,SACH,OAAO,EAAE,OAAO,EAAE;EACpB,KAAK,YACH,OAAO,EAAE,UAAU,QAAQ,KAAK;EAClC,KAAK,eACH,OAAO,EAAE,aAAa,KAAK,SAAS;EACtC,KAAK,QACH,OAAO;GAAE,UAAU,QAAQ;GAAM,aAAa,KAAK;EAAS;CAChE;AACF;;AAGA,MAAa,gBAAgB,YAAwC;CACnE,IAAI,QAAQ,SAAS,SAAS,OAAO;CACrC,IAAI,QAAQ,YAAY,QAAQ,aAAa,OAAO;CACpD,IAAI,QAAQ,UAAU,OAAO;CAC7B,IAAI,QAAQ,aAAa,OAAO;AAElC;;;;;AAMA,MAAM,eAAe,QAAgB,SAA6B;CAChE,MAAM,EAAE,SAAS,OAAO,OAAO,eAAe;CAC9C,IAAI,CAAC,SAAS,OAAO,OAAO;CAE5B,MAAM,SAAS,cAAc,SAAS,MAAM,OAAO,QAAQ;CAE3D,QAAQ,OAAR;EACE,KAAK,SACH,OAAO,EAAE,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO,OAAO,SAAS,CAAC,CAAC,EAAE;EACtE,KAAK,YACH,OAAO,EACL,UAAU,QAAQ,eAAe,OAAO,YAAY,QAAQ,MAAM,aAAa,KAAK,EACtF;EACF,KAAK,eACH,OAAO,EAAE,aAAa,UAAU,OAAO,eAAe,KAAK,UAAU,KAAK,EAAE;EAC9E,KAAK,QACH,OAAO;GACL,UAAU,OAAO,YAAY,QAAQ;GACrC,aAAa,UAAU,OAAO,eAAe,KAAK,UAAU,KAAK;EACnE;CACJ;AACF;;AAGA,MAAM,UAAU,QAAgB,SAC9B,QAAQ,eACN,YAAY,QAAQ,IAAI,CAAC,CAAC,YAAY,QAAQ,MAC9C,OAAO,aAAa,OAAO,KAC7B;;;;;AAMF,MAAa,SAAS,QAAgB,SAAuB;CAC3D,MAAM,SAAS,YAAY,QAAQ,IAAI;CAEvC,IAAI,CAAC,OAAO,MAAM;EAChB,OAAO,UAAU;EACjB;CACF;CAEA,MAAM,EAAE,UAAU,aAAa,OAAO;CAGtC,OAAO,UAAU;EACf,UAAU,QAAQ,IAAI,KAAK,UAAU,OAAO,QAAQ,IAAI,GAAG,QAAQ,GAAG,QAAQ;EAC9E,aAAa,KAAK,SAAS,UAAU,OAAO,eAAe,KAAK,QAAQ;CAC1E;AACF;;AAGA,MAAa,YAAY,QAAgB,UAA2B;CAClE,IAAI,UAAU,MAAM,UAAU,KAAK,UAAU,IAAI,OAAO;CACxD,OAAO,SAAS,SAAS,MAAM,KAAK,SAAS;AAC/C;;AAGA,MAAM,WAAW,QAAgB,UAAwB;CACvD,IAAI,UAAU,IAAI,OAAO,OAAO,SAAS,MAAM;MAC1C,IAAI,UAAU,IAAI;MAClB,IAAI,SAAS,GAAG,OAAO,OAAO,KAAK,OAAO,KAAK;AACtD;;;;;;AAOA,MAAa,QAAQ,QAAgB,QAAgB,SAA0B;CAC7E,OAAO,QAAQ,OAAO;CACtB,OAAO,OAAO,KAAK,OAAO,OAAO,IAAI;CACrC,OAAO,QAAQ,KAAK,OAAO,OAAO,KAAK;CACvC,OAAO,aAAa,KAAK,OAAO,OAAO,UAAU;CACjD,QAAQ,QAAQ,OAAO,KAAK;CAC5B,OAAO,OAAO;CACd,OAAO,QAAQ;CACf,IAAI,CAAC,OAAO,MAAM;CAElB,MAAM,EAAE,UAAU;CAElB,IAAI,OAAO,UAAU,KAAK,OAAO,QAAA,IAAkB;EACjD,OAAO,YAAY,SAAS;EAC5B;CACF;CAGA,MAAM,WAAW,OAAO,QAAQ,OAAO,IAAI;CAC3C,MAAM,WAAW,QACb,MAAM,WACN,KAAK,SACH,KAAK,UACL,KAAK,UAAU,YAAY,QAAQ,OAAO,IAAI,CAAC,CAAC,eAAe,KAAK,QAAQ,CAC9E;CACJ,MAAM,SAAS,QAAQ,MAAM,WAAW,KAAK;CAE7C,OAAO,YAAY;EACjB;EACA,UAAU,QAAQ,SAAS,QAAQ,KAAK,UAAU,UAAU,QAAQ,CAAC;CACvE;AACF;;;;;AAMA,MAAa,QAAQ,WAAyB;CAC5C,OAAO,OAAO;CACd,IAAI,CAAC,OAAO,SAAS;CAErB,MAAM,OAAO,OAAO,QAAS,OAAO,OAAO,IAAI,IAAI,SAAS,MAAM,IAAK,OAAO;CAE9E,MAAM,QAAQ,IAAI;AACpB;;AAGA,MAAM,WAAW,WAA4B,OAAO,OAAO,IAAI,IAAI,SAAS,MAAM;;AAGlF,MAAa,OAAO,gBAA4B;CAC9C,MAAM,QAAQ,KAAK,UAAU,QAAQ,GAAG,WAAW;CAEnD,OAAO,MAAM,KAAK,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC;AAC3C;;AAGA,MAAa,SAAS,UAAwB,KAAK,UAAU;CAAE,MAAM,QAAQ;CAAG;AAAM,CAAC;;;;;;;AAQvF,MAAa,QAAQ,QAAgB,IAAY,YAAoC;CACnF,IAAI,OAAO,QAAQ,OAAO,OAAO,OAAO;CACxC,OAAO,OAAO,KAAK,OAAO,KAAK,OAAO,OAAO,OAAO,IAAI;CAExD,IAAI,CAAC,OAAO,SAAS;EACnB,MAAM,EAAE,OAAO,YAAY,QAAQ,IAAI,MAAM;EAE7C,OAAO,UAAU;EACjB,OAAO;CACT;CAEA,IAAI,MAAM;CACV,MAAM,SAAS,SAAS,MAAM;CAC9B,MAAM,YAAY,OAAO,OAAO,IAAI,OAAO,OAAO,SAAS,OAAO;CAIlE,IAAI,aAAa,GAAG;EAClB,MAAM,QAAQ,WAAW,IAAI,KAAK,IAAI,KAAK,MAAM,YAAY,MAAM,CAAC,IAAI;EACxE,MAAM,YAAY,KAAK,OAAO,KAAK,IAAI,SAAS,IAAI,QAAQ,MAAM;EAClE,MAAM,SAAS;GACb,OAAO,OAAO;GACd,MAAM,OAAO;GACb,OAAO,OAAO;GACd,YAAY,OAAO;EACrB;EAEA,IAAI,OAAO,QAAA,GAAc;GACvB,IAAI;GAEJ,IAAI,OAAO,MAAM;IACf,MAAM,QAAQ,QAAQ,MAAM,CAAC;IAE7B,MAAM,EAAE,WAAW,QAAQ,MAAM,cAAc,KAAK,aAAa,OAAO;IAExE,QAAQ;KACN,UAAU,IAAI,WAAW;KACzB,UAAU;MAAE,GAAG,SAAS;MAAG,GAAG,QAAQ,WAAW,MAAM;MAAG,GAAG,SAAS;KAAE;IAC1E;GACF;GAEA,MAAM,QAAQ,OAAO,OAAO,IAAI,SAAS;GAEzC,KAAK,QAAQ;IAAE,GAAG;IAAQ;IAAO,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC;GAAG,GAAG,QAAQ,IAAI;GAC5E,IAAI,WAAW,GAAG,OAAO,OAAO,KAAK,OAAO,OAAO,OAAO,IAAI,SAAS,YAAY,SAAS;EAC9F,OAAO,IAAI,OAAO,QAAA,GAAgB;GAEhC,MAAM,OAAO,QAAQ,MAAM,IAAI,CAAC,OAAO,OAAO,OAAO;GACrD,MAAM,QAAQ,OAAO,IAAI,KAAK,OAAO,SAAS,SAAS,IAAI;GAE3D,KAAK,QAAQ;IAAE,GAAG;IAAQ;IAAO;GAAK,GAAG,QAAQ,IAAI;EACvD,OAAO;GACL,OAAO,OAAO,QAAQ,MAAM;GAC5B,OAAO,QAAQ;GACf,MAAM,CAAC,OAAO;EAChB;CACF;CAEA,MAAM,QAAQ,OAAO,IAAI;CACzB,OAAO;AACT;;;;;;AAOA,MAAa,OAAO,QAAgB,GAAe,GAAe,MAA0B;CAC1F,QAAQ,OAAO,OAAf;EACE,KAAK,SAAS;GACZ,MAAM,OAAO,EAAE,SAAS;GACxB,IAAI,KAAK,EAAE,SAAS;GAEpB,IAAI,OAAO,UAAU;IACnB,MAAM,IAAI,KAAK;IAEf,IAAI,IAAI,CAAC,IAAI,MAAM;SACd,IAAI,IAAI,IAAI,MAAM;GACzB;GAEA,OAAO,EAAE,OAAO,KAAK,OAAO,OAAO,QAAQ,KAAK,QAAQ,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE;EAClF;EACA,KAAK,YACH,OAAO,EACL,UAAU,QAAQ,eAChB,QAAQ,KAAK,EAAE,YAAY,QAAQ,MAAM,EAAE,YAAY,QAAQ,MAAM,CAAC,GACtE,OAAO,aAAa,OAAO,KAC7B,EACF;EACF,KAAK,eACH,OAAO,EACL,aAAa,UACX,KAAK,MAAM,EAAE,eAAe,KAAK,UAAU,EAAE,eAAe,KAAK,UAAU,CAAC,GAC5E,OAAO,KACT,EACF;EACF,KAAK,QACH,OAAO,UAAU,GAAG,GAAG,CAAC;CAC5B;AACF;;;;AAKA,MAAa,aAAa,GAAe,GAAe,OAA2B;CACjF,UAAU,QAAQ,KAAK,EAAE,YAAY,QAAQ,MAAM,EAAE,YAAY,QAAQ,MAAM,CAAC;CAChF,aAAa,KAAK,MAAM,EAAE,eAAe,KAAK,UAAU,EAAE,eAAe,KAAK,UAAU,CAAC;AAC3F;;AAGA,MAAa,iBACX,OACA,GACA,GACA,MACe;CACf,QAAQ,OAAR;EACE,KAAK,SAAS;GACZ,MAAM,OAAO,EAAE,SAAS;GAExB,OAAO,EAAE,OAAO,KAAK,SAAS,EAAE,SAAS,KAAK,QAAQ,IAAI,IAAI,EAAE;EAClE;EACA,KAAK,YACH,OAAO,EAAE,UAAU,QAAQ,KAAK,EAAE,YAAY,QAAQ,MAAM,EAAE,YAAY,QAAQ,MAAM,CAAC,EAAE;EAC7F,KAAK,eACH,OAAO,EACL,aAAa,KAAK,MAAM,EAAE,eAAe,KAAK,UAAU,EAAE,eAAe,KAAK,UAAU,CAAC,EAC3F;EACF,KAAK,QACH,OAAO,UAAU,GAAG,GAAG,CAAC;CAC5B;AACF;;AAGA,MAAa,UAAU,WAAyD;CAC9E,IAAI,OAAO,UAAU,QAAQ,OAAO;EAAE,QAAQ,QAAQ;EAAM,QAAQ,QAAQ;CAAK;CAEjF,MAAM,OAAO,OAAO,QAAQ,QAAQ,MAAM,IAAI,OAAO;CACrD,MAAM,SAAS,YAAY,QAAQ,IAAI,CAAC,CAAC,YAAY,QAAQ;CAC7D,MAAM,EAAE,UAAU,aAAa,OAAO;CAEtC,OAAO;EAAE;EAAQ,QAAQ,QAAQ,IAAI,KAAK,UAAU,QAAQ,QAAQ,GAAG,QAAQ;CAAE;AACnF;;;;AAKA,MAAa,WAAW,QAAgB,WAA0B;CAChE,IAAI,CAAC,OAAO,MAAM;CAElB,MAAM,EAAE,aAAa,OAAO;CAE5B,OAAO,YAAY;EACjB;EACA,UAAU,QAAQ,SAAS,QAAQ,KAAK,UAAU,OAAO,QAAQ,OAAO,IAAI,GAAG,QAAQ,CAAC;CAC1F;CACA,OAAO,UAAU;EAAE,GAAG,OAAO;EAAS,UAAU;CAAO;AACzD;;;;;;AAOA,MAAa,UAAU,QAAgB,aAAmB,YAAwB;CAChF,IAAI,CAAC,OAAO,MAAM;CAElB,MAAM,SAAS,YAAY,QAAQ,OAAO,IAAI;CAC9C,MAAM,SAAS,OAAO,YAAY,QAAQ;CAC1C,MAAM,EAAE,UAAU,aAAa,OAAO;CAMtC,MAAM,QAAQ,MAAY,QAAQ,UAAU,CAAC;CAC7C,MAAM,SAAS,KACb,KAAK,SAAS,KAAK,SAAS,aAAa,KAAK,UAAU,KAAK,OAAO,CAAC,CAAC,GAAG,QAAQ,CACnF;CACA,MAAM,QAAQ,QAAQ,IAAI,KAAK,UAAU,QAAQ,QAAQ,GAAG,QAAQ;CAGpE,OAAO,YAAY;EAAE,UAAU;EAAQ,UAFxB,QAAQ,SAAS,OAAO,KAAK,UAAU,QAAQ,MAAM,CAEd;CAAE;CACxD,OAAO,UAAU;EACf,UAAU;EACV,aAAa,KAAK,SAAS,QAAQ,OAAO,eAAe,KAAK,QAAQ;CACxE;AACF;;AAGA,MAAa,SAAS,QAAgB,UAAyB;CAC7D,IAAI,OAAO,UAAU,QAAQ;CAE7B,MAAM,EAAE,UAAU,aAAa,OAAO;CAEtC,OAAO,YAAY;EAAE;EAAU,UAAU,QAAQ,IAAI,UAAU,KAAK;CAAE;CACtE,IAAI,OAAO,MAAM,KAAK,MAAM;AAC9B;;;AC3bA,MAAa,aAAa;CACxB,WAAW;CACX,MAAM;CACN,QAAQ;;CAER,aAAa;AACf;AAIA,MAAM,YAAY,UAAU;;AAG5B,MAAa,OAAqB,aAAa,KAAK,EAAE,QAAQ,IAAM,IAAI,GAAG,SACzE,KAAK,QAAQ,IAAI,KAAK,IAAI,OAAO,SAAS,KAAK,EAAG,CACpD;;;;;AAMA,MAAa,cAAc,MAAc,aAA6B;CACpE,IAAI,EAAE,WAAW,IAAI,OAAO,KAAK;CAEjC,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,QAAQ,IAAI,OAAO,GAAG;CAE9D,OAAO,KAAK,SAAS,KAAK;AAC5B;AA4FA,MAAM,SAAgD;CACpD,UAAU;CACV,WAAW;CACX,eAAe;CACf,QAAQ;CACR,OAAO;AACT;AAGA,MAAM,gBAAgB;AAEtB,MAAM,eAAe,EAAE,UAAU,mBAA0C;CACzE,UAAU,YAAY,QAAQ;CAC9B,UAAU,eAAe,KAAK;AAChC;AAEA,MAAM,YAAY,MAAY,WAC5B,KAAK,SAAS,UAAU,KAAK,WAAW;AAE1C,MAAM,UAAU,OAAe,SAAqB;CAClD,MAAM,KAAK,MAAM,QAAQ,IAAI;CAC7B,IAAI,MAAM,GAAG,MAAM,OAAO,IAAI,CAAC;AACjC;;AAGA,MAAM,QAAQ,OAAe,SAAqB;CAChD,IAAI,KAAK,SAAS,QAAQ,KAAK,OAAO,QAAQ;CAC9C,OAAO,OAAO,IAAI;AACpB;;;;;AAMA,MAAM,UAAU,OAAe,OAAa,UAAyB;CACnE,MAAM,KAAK,MAAM,QAAQ,KAAK;CAC9B,MAAM,KAAK,MAAM,KAAK;CACtB,MAAM,OAAO,MAAM,KAAK;CAExB,IAAI,MAAM,SAAS,SAAS,OAAO,OAAO,MAAM,IAAI;MAC/C,IAAI,MAAM,KAAK,OAAO,IAAI;CAE/B,IAAI,SAAS,IAAI,KAAK,OAAO,EAAE;CAC/B,OAAO,OAAO,KAAK;AACrB;;AAGA,MAAM,eAAe,OAAe,SAAiC;CACnE,IAAI,MAAM,SAAS,SAAS,OAAO,OAAO,MAAM,IAAI;MAC/C,IAAI,MAAM,KAAK,OAAO,IAAI;AACjC;AAEA,IAAa,QAAb,MAAmB;CACjB;CACA;CACA,0BAAmB,IAAI,IAA+D;CACtF,yBAAkB,IAAI,IAAY;;CAElC,WAA6B,CAAC;CAC9B,QAAQ;;CAER,SAAS;;;;;CAKT,QAAQ;CAER,YAAY,EACV,MACA,QACA,WAAW,QAAQ,MACnB,cAAc,KAAK,YACJ;EACf,KAAK,YAAY;EACjB,KAAK,QAAQ;GAAE,OAAO;GAAQ,UAAU;GAAO,OAAO;IAAE;IAAU;GAAY;EAAE;EAEhF,KAAK,MAAM,EAAE,MAAM,QAAQ,WAAW,QAAQ;GAE5C,MAAM,QAAQ,OAAO,MAAM;GAC3B,MAAM,SAA6B,SAAS;IAC1C;IACA;IACA,UAAU,MAAM,SAAS;IACzB,OAAO,KAAK,KAAK;GACnB;GAEA,KAAK,QAAQ,IAAI,MAAM;IAAE;IAAQ;IAAO,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;GAAG,CAAC;EACzE;CACF;;CAGA,IAAI,OAAiD;EACnD,MAAM,EAAE,UAAU,aAAa,YAAY,KAAK,MAAM,KAAK;EAE3D,OAAO;GAAE;GAAU,aAAa;EAAS;CAC3C;;CAGA,IAAI,QAAgB;EAClB,OAAO,KAAK;CACd;;CAGA,WAAW,MAAsC;EAC/C,OAAO,KAAK,QAAQ,IAAI,IAAI,CAAC,EAAE,QAAQ;CACzC;;;;CAKA,KAAK,MAAoB;EACvB,KAAK,OAAO,IAAI,IAAI;CACtB;;CAGA,OAAO,MAAoB;EACzB,KAAK,OAAO,OAAO,IAAI;CACzB;;;;;;CAOA,MAAM,QAAyB,UAAyB,CAAC,GAAuB;EAC9E,MAAM,EACJ,YAAY,GACZ,YAAY,GACZ,SAAS,GACT,YAAY,GACZ,aAAa,GACb,UAAU,OACR;EAEJ,KAAK,OAAO;EAEZ,MAAM,UAAU,KAAK,UAAU,MAAM;EACrC,MAAM,KAAK,KAAK,OAAO,SAAS;EAChC,MAAM,SAAiB;GACrB,OAAO;GACP,OAAO,aAAa;GACpB,MAAM,KAAK,IAAI,KAAK,OAAO,SAAS,CAAC,KAAK,aAAa,WAAW,YAAY,KAAK;GACnF,OAAO;GACP,YAAY;EACd;EAEA,IAAI,CAAC,QAAQ,OAAO,EAAE,aAAa,SAAS,QAAQ,EAAE,CAAC,GAAG,OAAO,KAAA;EAEjE,MAAM,OAAO,YAAY,KAAK,MAAM,KAAK;EAGzC,IAAI,OAAO;EAEX,IAAI,KAAK,GAAG;GACV,KAAK,MAAM,EAAE,YAAY,SAAS,KAAK,QAAQ,QAAQ,IAAI;GAE3D,MAAM,QAAQ,QAAQ,MACnB,EAAE,aAAa,OAAO,UAAU,cAAc,OAAO,UAAU,MAClE;GACA,IAAI,OAAO,OAAO,OAAO,MAAM,MAAM,CAAC,CAAC,OAAO;EAChD;EAEA,MAAM,UAAU,OAAO,UAAU,KAAK,SAAS,KAAK;EACpD,MAAM,QAAmB;GACvB,UAAU,UAAU,IAAI,IAAI,KAAK,QAAQ,IAAI,MAAM,OAAO;GAC1D,UAAU;IAAE,GAAG,KAAK,SAAS;IAAG,GAAG,OAAO;IAAQ,GAAG,KAAK,SAAS;GAAE;EACvE;EACA,KAAK,MAAM,EAAE,YAAY,SAAS,KAAK,QAAQ;GAAE,GAAG;GAAQ;EAAM,GAAG,IAAI;EACzE,KAAK,MAAM,EAAE,QAAQ,YAAY,SAAS,KAAK,QAAQ,QAAQ,QAAQ,WAAW,UAAU;EAE5F,MAAM,SAAS,KAAK;EAEpB,KAAK,SAAS,KAAK;GACjB,MAAM;GACN;GACA;GACA,GAAI,OAAO,WAAW,KAAA,IAAY,CAAC,IAAI,EAAE,QAAQ,OAAO,OAAO;EACjE,CAAC;EACD,OAAO;CACT;;;;;CAMA,KAAK,QAAsB;EACzB,MAAM,SAAS,KAAK,SAAS,MAAM,WAAW,OAAO,WAAW,MAAM;EACtE,IAAI,QAAQ,SAAS,UAAU;EAC/B,KAAK,MAAM,EAAE,QAAQ,YAAY,OAAO,SAAS,KAAK,QAAQ,QAAQ,MAAM;EAC5E,KAAK,WAAW,KAAK,SAAS,QAAQ,UAAU,UAAU,MAAM;CAClE;;CAGA,QAAQ,QAAyB;EAC/B,MAAM,SAAS,KAAK,SAAS,MAAM,WAAW,OAAO,WAAW,MAAM;EACtE,IAAI,CAAC,QAAQ,OAAO;EACpB,OAAO,OAAO,SAAS,WACnB,OAAO,QAAQ,MAAM,EAAE,QAAQ,aAAa,KAAK,SAAS,QAAQ,MAAM,CAAC,IACzE,KAAK,SAAS,OAAO,QAAQ,OAAO,MAAM;CAChD;;;;;;;CAQA,IACE,OACA,EAAE,QAAQ,qBAAqB,GAAG,aAAa,KAC3B;EACpB,MAAM,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE;EACvC,IAAI,OAAO,UAAU,eAAe,OAAO,KAAA;EAC3C,IAAI,KAAK,OAAO,IAAI,KAAK,GAAG,OAAO,KAAA;EACnC,KAAK,OAAO,IAAI,KAAK;EAMrB,MAAM,QADQ,aAAa,OAAe,aAAa,MAAO,MAAQ,OAC/C,IAAK,WAAW;EACvC,MAAM,SAAS,aAAa,eAAe,CAAC,CAAC;EAE7C,KACE,QACA;GAAE,OAAO;GAAG,OAAO;GAAM,MAAM;GAAG,OAAO;GAAG,YAAY;EAAE,GAC1D,YAAY,KAAK,MAAM,KAAK,CAC9B;EACA,KAAK,QAAQ,OAAO,QAAQ,KAAK,OAAO,kBAAkB,GAAG,IAAI;EAEjE,MAAM,SAAS,KAAK;EAEpB,KAAK,SAAS,KAAK;GACjB,MAAM;GACN;GACA;GACA,QAAQ;GACR;GACA,MAAM;GACN,SAAS;EACX,CAAC;EACD,OAAO;CACT;;CAGA,aAAa,QAAgB,QAAoB;EAC/C,MAAM,SAAS,KAAK,SAAS,MAAM,WAAW,OAAO,WAAW,MAAM;EACtE,IAAI,QAAQ,SAAS,OAAO,OAAO,OAAO;CAC5C;;;;;CAMA,QAAQ,QAAsB;EAC5B,MAAM,SAAS,KAAK,SAAS,MAAM,WAAW,OAAO,WAAW,MAAM;EACtE,IAAI,QAAQ,SAAS,SAAS,OAAO,SAAS;EAC9C,OAAO,UAAU;EACjB,KAAK,OAAO,OAAO,OAAO,KAAK;CACjC;;;;;CAMA,QAAQ,IAAkB;EACxB,MAAM,OAAO,KAAK,OAAO,EAAE;EAE3B,MAAM,UAAyB;GAC7B,MAAM,YAAY,KAAK,MAAM,KAAK;GAClC,aAAa,WAAW;IAMtB,QALe,KAAK,SAAS,MAC1B,WACC,OAAO,SAAS,YAAY,OAAO,QAAQ,MAAM,UAAU,MAAM,WAAW,MAAM,CAGzE,CAAC,EAAE,UAAU,KAAK,SAAS,KAAK;GAC/C;GACA,MAAM,WAAW;IACf,MAAM,SAAS,KAAK,SAAS,MAC1B,WAA0B,OAAO,SAAS,SAAS,OAAO,WAAW,MACxE;IAEA,IAAI,CAAC,UAAU,OAAO,SACpB,OAAO;KAAE,OAAO,QAAQ,OAAO,SAAS,OAAO;KAAS,SAAS;IAAK;IAExE,OAAO;KAAE,OAAO,EAAE,aAAa,KAAK,aAAa,MAAM,EAAE;KAAG,SAAS;IAAM;GAC7E;EACF;EAEA,KAAK,MAAM,EAAE,YAAY,KAAK,QAAQ,OAAO,GAAG;GAC9C,IAAI,CAAC,QAAQ;GACb,QAAQ,OAAO,YAAY,KAAK,MAAM,KAAK;GAC3C,KAAK,MAAM,QAAQ,MAAM,OAAO;EAClC;EAEA,QAAQ,OAAO,YAAY,KAAK,MAAM,KAAK;EAC3C,KAAK,MAAM,KAAK,OAAO,MAAM,OAAO;CACtC;;;;;;CAOA,gBAAgB,UAAyB;EACvC,KAAK,OAAO;EAEZ,IAAI;EAEJ,KAAK,MAAM,UAAU,KAAK,UAAU;GAClC,IAAI,OAAO,SAAS,UAAU;GAO9B,KAJE,OAAO,WAAW,KAAA,IACd,KAAK,QACL,OAAO,UAAU,KAAK,aAAa,MAAM,CAAC,EAAE,OAAO,KAAK,MAEjD,KAAK;GAElB,MAAM,SAAS;IAAE,GAAG,SAAS;IAAG;IAAG,GAAG,SAAS;GAAE;GAEjD,IAAI,CAAC,KAAK,UAAU,GAAG;GAEvB,KAAK,MAAM,EAAE,YAAY,OAAO,SAAS,QAAQ,QAAQ,MAAM;GAE/D,IAAI,OAAO,QAAQ,MAAM,EAAE,aAAa,OAAO,IAAI,GACjD,KAAK,UAAU,KAAK,QAAQ,WAAW;IAAE,GAAG;IAAO,UAAU;GAAO,EAAE;EAC1E;EAEA,KAAK,MAAM,QAAQ;GACjB,GAAG,KAAK,MAAM;GACd,UAAU;IAAE,GAAG,SAAS;IAAG,GAAG,KAAK,KAAK,QAAQ,KAAK;IAAQ,GAAG,SAAS;GAAE;EAC7E;CACF;;;;;CAMA,mBAAmB,aAAyB;EAC1C,MAAM,UAAU,YAAY,KAAK,MAAM,KAAK,CAAC,CAAC;EAE9C,IAAI,KAAK,UAAU,GACjB,KAAK,MAAM,UAAU,KAAK,UAAU;GAClC,IAAI,OAAO,SAAS,UAAU;GAE9B,KAAK,MAAM,EAAE,YAAY,OAAO,SAAS,OAAO,QAAQ,aAAa,OAAO;GAE5E,IAAI,OAAO,QAAQ,MAAM,EAAE,aAAa,OAAO,IAAI,GACjD,KAAK,UAAU,KAAK,QAAQ,WAAW;IAAE,GAAG;IAAO;GAAY,EAAE;EACrE;EAEF,KAAK,MAAM,QAAQ;GAAE,GAAG,KAAK,MAAM;GAAO;EAAY;CACxD;;;;;CAMA,SAAS,QAAsB;EAC7B,KAAK,SAAS,KAAK,OAAO,MAAM;EAChC,KAAK,OAAO;EAEZ,KAAK,MAAM,UAAU,KAAK,UAAU;GAClC,IAAI,OAAO,SAAS,UAAU;GAE9B,IAAI;GAEJ,IAAI,OAAO,WAAW,KAAA,GACpB,QAAQ,KAAK,QAAQ,KAAK,SAAS,YAAY,KAAK,MAAM,KAAK,CAAC,CAAC,SAAS;QACrE;IACL,MAAM,EAAE,QAAQ,WAAW,KAAK,aAAa,MAAM,KAAK;KACtD,QAAQ,QAAQ;KAChB,QAAQ,QAAQ;IAClB;IAEA,QAAQ,OAAO,SAAS,OAAO,IAAI,KAAK,SAAS,OAAO;GAC1D;GAEA,IAAI,EAAE,KAAK,IAAI,KAAK,IAAI,kBAAkB,CAAC,KAAK,UAAU,GAAG;GAG7D,MAAM,OAAO;IAAE,GAAG;IAAG,GAAG;IAAO,GAAG;GAAE;GACpC,KAAK,MAAM,EAAE,YAAY,OAAO,SAAS,MAAM,QAAQ,IAAI;GAE3D,IAAI,OAAO,QAAQ,MAAM,EAAE,aAAa,OAAO,IAAI,GACjD,KAAK,UAAU,KAAK,QAAQ,WAAW;IACrC,GAAG;IACH,UAAU,QAAQ,IAAI,MAAM,YAAY,QAAQ,MAAM,IAAI;GAC5D,EAAE;EACN;CACF;;;;;CAMA,UAAU,EAAE,QAA4C;EACtD,MAAM,UAA6B,CAAC;EAEpC,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,QAAQ,aAAa,IAAI,OAAO;GAEtC,IAAI,IAAI,SAAS,SAAS;IACxB,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI,KAAK;IACxC,MAAM,SAAS,OAAO;IACtB,IAAI,CAAC,UAAU,KAAK,OAAO,IAAI,IAAI,KAAK,GAAG;IAC3C,IAAI,MAAM,WAAW,IAAI,UAAU,UAAU,OAAO,OAAO;IAE3D,MAAM,EAAE,YAAY;IAEpB,QAAQ,KAAK;KACX,QAAQ,aAAa,OAAO;MAAE;MAAS,UAAU,OAAO;KAAS,CAAC;KAClE;IACF,CAAC;GACH,OAAO;IAKL,IAAI,KAAK,QAAQ,IAAI,IAAI,MAAM,KAAK,KAAK,OAAO,IAAI,KAAK,SAAS,GAAG;IACrE,IAAI,UAAU,QAAQ;IACtB,QAAQ,KAAK;KACX,QAAQ,aAAa,QAAQ;MAAE,SAAS,IAAI;MAAS,MAAM;KAAK,CAAC;KACjE,QAAQ,KAAK;IACf,CAAC;GACH;EACF;EAEA,OAAO;CACT;;CAGA,QAAQ,QAAgB,QAAgB,UAAkB,OAAqB;EAC7E,OAAO,UAAU;GAAE,OAAO,CAAC;GAAG,MAAM;EAAE;EAEtC,MAAM,QAAQ,OAAO;EACrB,MAAM,EAAE,UAAU;EAClB,IAAI,MAAM,MAAM,SAAS,SAAS,MAAM,MAAM,CAAC,GAAG;EAElD,MAAM,QAAQ,WAAW;EAEzB,IAAI,OAEE;OAAA,CAAC,MAAM,QAAQ;IACjB,SAAS,CAAC,WAAW;IACrB,MAAM,KAAK;KAAE,MAAM;KAAW,OAAO,OAAO;IAAM,CAAC;GACrD;SACK;GACL,KAAK,MAAM,QAAQ,OAAO,IAAI,KAAK,SAAS,QAAQ,KAAK,OAAO,QAAQ;GACxE,MAAM,SAAS;EACjB;EAGA,MAAM,KAAK;GAAE,MAAM;GAAQ;EAAO,CAAC;EACnC,IAAI,CAAC,OAAO;EACZ,MAAM,KAAK;GACT,MAAM;GACN,MAAM;GACN;GACA,aAAa,EAAE,QAAQ,WAAW;EACpC,CAAC;EACD,MAAM,OAAO;CACf;;;;;CAMA,QAAQ,QAAgB,QAAsB;EAC5C,MAAM,QAAQ,OAAO,OAAO;EAC5B,IAAI,CAAC,OAAO;EAEZ,MAAM,OAAO,MAAM,MAAM,SAAS,SAAS,MAAM,MAAM,CAAC;EAExD,IAAI,MAAM;GACR,MAAM,KAAK,MAAM,QAAQ,IAAI;GAC7B,MAAM,QAAQ,MAAM,KAAK;GAEzB,IAAI,SAAS,MAAM,KAAK,EAAE,EAAE,SAAS,SAAS;IAC5C,MAAM,OAAO,KAAK,GAAG,GAAG;KAAE,MAAM;KAAW,OAAO,OAAO;IAAM,CAAC;IAEhE,MAAM,QAAQ,MAAM,KAAK;IACzB,IAAI,OAAO,SAAS,SAAS,MAAM,cAAc;GACnD,OAAO,IAAI,OAAO,SAAS,SAAS;IAGlC,IAFa,MAAM,KAAK,MAEZ,MAAM,KAAK,EAAE,EAAE,SAAS,SAClC,MAAM,OAAO,KAAK,GAAG,GAAG;KAAE,MAAM;KAAW,OAAO,OAAO;IAAM,CAAC;IAElE,YAAY,OAAO,MAAM,KAAK,EAAE;IAChC,OAAO,OAAO,KAAK;GACrB;GAEA,OAAO,OAAO,IAAI;EACpB;EAEA,IAAI,CAAC,MAAM,QAAQ,OAAO,OAAO;CACnC;;;;;CAMA,MAAM,QAAgB,IAAY,SAA8B;EAC9D,MAAM,QAAQ,OAAO;EACrB,IAAI,CAAC,OAAO;EAEZ,MAAM,EAAE,UAAU;EAElB,KAAK,MAAM,QAAQ,CAAC,GAAG,KAAK,GAAG;GAC7B,MAAM,KAAK,MAAM,QAAQ,IAAI;GAC7B,IAAI,KAAK,GAAG;GAEZ,IAAI,KAAK,SAAS,SAAS;IAEzB,MAAM,MAAM,KAAK,KAAK;IAEtB,KAAK,OAAO,KAAK,OAAO,GAAG;IAC3B,IAAI,EAAE,OAAO,KAAK,WAAW;IAC7B,IAAI,KAAK,aAAa,YAAY,OAAO,MAAM,KAAK,EAAE;IACtD,OAAO,OAAO,IAAI;GACpB,OAAO,IAAI,KAAK,SAAS,QAAQ;IAC/B,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,OAAO,GAAG;IAErC,MAAM,OAAO,MAAM,KAAK;IACxB,MAAM,SAAS,MAAM,KAAK;IAE1B,IAAI,MAAM;KAER,IAAI,KAAK,SAAS,WAAW,MAAM,KAAK,EAAE,EAAE,SAAS,SAAS,KAAK,KAAK,MAAM;UACzE,OAAO,OAAO,IAAI;IACzB,OAAO,IAAI,CAAC,QAAQ;KAClB,KAAK,KAAK,MAAM;KAChB,KAAK,SAAS;IAChB,OAAO;KAGL,KAAK,KAAK,MAAM;KAChB,OAAO,OAAO,IAAI;KAClB,MAAM,OAAO,MAAM,QAAQ,MAAM,GAAG,GAAG,IAAI;KAC3C,MAAM,KAAK;MAAE,MAAM;MAAS,MAAM;MAAG,UAAU,MAAM;MAAM,aAAa;KAAK,CAAC;IAChF;GACF;EACF;EAEA,MAAM,QAAQ,CAAC,GAAG,KAAK;EACvB,MAAM,MAAM,MAAM,IAAI;EACtB,MAAM,QAAQ,OAAO,KAAK,UAAU,KAAK,OAAO,MAAM;EACtD,IAAI,OAAO,OAAO,QAAQ;EAE1B,MAAM,QAAQ,MAAM,QAAQ,SAAS,EAAE,KAAK,SAAS,UAAU,KAAK,OAAO;EAC3E,IAAI,CAAC,MAAM,MAAM,QAAQ,OAAO,OAAO;CACzC;;CAGA,UAAU,MAAY,OAAe,QAAwC;EAC3E,IAAI,KAAK,SAAS,QAAQ,OAAO,KAAK,OAAO;EAC7C,IAAI,KAAK,SAAS,WAAW,OAAO,KAAK;EAEzC,MAAM,KAAK,MAAM,IAAI;EACrB,MAAM,OAAO,MAAM,IAAI;EAEvB,IAAI,CAAC,MAAM,CAAC,MAAM,OAAO,KAAA;EAEzB,MAAM,IAAI,KAAK,UAAU,MAAM,OAAO,MAAM,KAAK,OAAO;EACxD,MAAM,IAAI,KAAK,UAAU,IAAI,OAAO,MAAM,KAAK,OAAO;EACtD,MAAM,IAAI,WAAW,KAAK,MAAM,KAAK,QAAQ;EAE7C,MAAM,OAAO,GAAG,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,OAAO,KAAA;EACrE,IAAI,MAAM,OAAO,IAAI,KAAK,QAAQ,GAAG,GAAG,CAAC;EAEzC,IAAI,GAAG,SAAS,aAAa,KAAK,SAAS,WACzC,OAAO,cAAc,OAAO,OAAO,GAAG,GAAG,CAAC;CAI9C;;;;;;;CAQA,aAAa,EAAE,OAAO,QAAmB;EACvC,MAAM,SAAS,KAAK,QAAQ,IAAI,KAAK,CAAC,EAAE;EACxC,MAAM,QAAQ,WAAW,KAAA,IAAY,QAAQ,WAAW,KAAK,OAAO,MAAM;EAE1E,OAAO,KAAK,SAAS,KAAK,UAAU,QAAQ,UAAU,KAAK,CAAC,CAAC,WAAW,GAAG,IAAI;CACjF;;;;;CAMA,OAAO,MAAuB;EAC5B,IAAI,SAAS,KAAK,WAAW;GAC3B,MAAM,EAAE,UAAU,aAAa,YAAY,KAAK,MAAM,KAAK;GAE3D,OAAO,QAAQ,wBAAwB,QAAQ,eAAe,QAAQ,GAAG,QAAQ;EACnF;EAEA,MAAM,QAAQ,KAAK,QAAQ,IAAI,IAAI;EACnC,IAAI,CAAC,OAAO,OAAO,QAAQ;EAC3B,OAAO,QAAQ,SACb,KAAK,OAAO,MAAM,MAAM,GACxB,eAAe,MAAM,OAAO,MAAM,QAAQ,KAAK,CACjD;CACF;;;;;CAMA,SAAe;EACb,KAAK,WAAW,KAAK,SAAS,QAAQ,WACpC,OAAO,SAAS,QACZ,CAAC,OAAO,WAAW,KAAK,SAAS,OAAO,QAAQ,OAAO,MAAM,IAC7D,OAAO,QAAQ,MAAM,EAAE,QAAQ,aAAa,KAAK,SAAS,QAAQ,MAAM,CAAC,CAC/E;EAEA,IAAI,CAAC,KAAK,SAAS,QACjB,KAAK,QAAQ,KAAK,OAAO,YAAY,KAAK,MAAM,KAAK,CAAC,CAAC,SAAS,IAAI,KAAK,MAAM;CACnF;CAEA,SAAS,QAAgB,QAAyB;EAChD,OAAO,CAAC,CAAC,OAAO,OAAO,MAAM,MAAM,SAAS,SAAS,MAAM,MAAM,CAAC;CACpE;;;;;CAMA,YAAqB;EACnB,IAAI,KAAK,MAAM,OAAO,OAAO;EAC7B,KAAK,MAAM,EAAE,YAAY,KAAK,QAAQ,OAAO,GAAG,IAAI,QAAQ,OAAO,OAAO;EAC1E,OAAO;CACT;;;;;CAMA,aAAa,QAAuD;EAClE,MAAM,QAAQ,OAAO,QAAQ,MAC1B,EAAE,aAAa,OAAO,UAAU,cAAc,OAAO,UAAU,MAClE;EAEA,OAAO,SAAS,OAAO,MAAM,MAAM;CACrC;CAEA,UAAU,QAAgB,QAAiD;EACzE,KAAK,MAAM,QAAQ,OAAO,OAAO,SAAS,CAAC,GACzC,IAAI,KAAK,SAAS,WAAW,KAAK,QAAQ,OAAO,KAAK,KAAK;CAC/D;AACF"}