@operato/scene-storage 10.0.0-beta.57 → 10.0.0-beta.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/crane.js +13 -7
- package/dist/crane.js.map +1 -1
- package/dist/rack-grid.js +3 -3
- package/dist/rack-grid.js.map +1 -1
- package/dist/spot.js +2 -0
- package/dist/spot.js.map +1 -1
- package/dist/stockpile-grid.js +3 -3
- package/dist/stockpile-grid.js.map +1 -1
- package/dist/stockpile.d.ts +11 -0
- package/dist/stockpile.js +13 -3
- package/dist/stockpile.js.map +1 -1
- package/dist/storage-rack.js +3 -3
- package/dist/storage-rack.js.map +1 -1
- package/package.json +3 -3
- package/src/crane.ts +14 -7
- package/src/rack-grid.ts +3 -3
- package/src/spot.ts +2 -0
- package/src/stockpile-grid.ts +3 -3
- package/src/stockpile.ts +24 -4
- package/src/storage-rack.ts +3 -3
- package/tsconfig.tsbuildinfo +1 -1
package/dist/storage-rack.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage-rack.js","sourceRoot":"","sources":["../src/storage-rack.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport * as THREE from 'three'\nimport {\n CellContainer,\n CellMap,\n CarrierHolder,\n Placeable,\n RecordStorage,\n SlotTarget,\n componentBoundingBox,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype,\n type SlotRecord,\n type SlottedHolder\n} from '@operato/scene-base'\n\nimport { StorageRack3D } from './storage-rack-3d.js'\nimport { rackAcceptsMoverTool } from './rack-capability.js'\n\n/** Rack 컴포넌트 state */\nexport interface StorageRackState extends State {\n // ── 토폴로지 ──\n bays?: number\n levels?: number\n\n /**\n * Level 1 (첫 shelf) 의 *시작 높이* (mm, rack 의 3D Y 축, 바닥부터). 미명시 0\n * (바닥 = 첫 shelf). 양수 시 그만큼 위로 올라가 stocker port / conveyor 같은\n * 컴포넌트가 들어갈 *빈 공간* 확보. Frame uprights 는 바닥 ~ 천장 그대로.\n */\n shelfBaseHeight?: number\n\n /**\n * 적재 시각화 데이터. 배열의 각 record 는 최소 `cellId` 필드가 필요. cellMap 에\n * 존재하는 cellId 만 InstancedMesh 의 instance 로 렌더링됨 (한 박스 = 한 cell).\n * Plan A: 이 record 들이 *\"매트릭스 안\"* 의 carrier — obtainCarrier 가 materialize\n * 시 record 빠짐, receiveAt 시 record push. pickAndPlace 와 양방향 atomic sync.\n */\n data?: Array<{ cellId: string; [key: string]: any }>\n\n /**\n * RackCell 컴포넌트의 eager 생성 여부.\n * - `undefined` (default): state.data 있으면 false (batched, 메모리 절약),\n * 없으면 true (legacy non-batched, RackCell-based Mover 호환).\n * - `true`: 명시적 eager — 모든 cell 을 RackCell 로 생성.\n * - `false`: 명시적 skip — Plan A 의 slot API 만 사용 (obtainCarrier / slotTargetAt).\n */\n eagerCells?: boolean\n\n /**\n * Legend 컴포넌트의 id. legend 의 `state.status = {field, ranges:[{value|min,max, color}], defaultColor}`\n * 를 사용해 각 record 의 `field` 값을 색상으로 매핑. 미명시 시 scene-wide auto-discovery\n * (type='legend' 인 첫 번째 컴포넌트).\n */\n legendTarget?: string\n\n /**\n * Cell 클릭 시 invoke 할 things-scene `Popup` 컴포넌트의 id. Popup 컴포넌트는 scene\n * 어딘가에 일반 컴포넌트로 배치되어 있고, 그 자체의 state (board / modal / closable /\n * draggable / tether / billboard 등) 가 popup 동작을 정의. rack 은 *anchor 만 동적으로*\n * override 해 호출 — 클릭된 cell 위에 popup 이 뜸.\n *\n * 미명시 시 popup 비활성 (rack-cell-click 이벤트는 여전히 발사 — 외부 consumer 가\n * 직접 처리 가능).\n */\n popupRef?: string\n\n /** 가로 frame (beam) 만 숨김 — uprights 는 유지. */\n hideHorizontalFrame?: boolean\n\n // ── 디버그 ──\n debugCells?: boolean\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'number',\n label: 'levels',\n name: 'levels',\n placeholder: '# of vertical levels (default 4)'\n },\n {\n type: 'number',\n label: 'bays',\n name: 'bays',\n placeholder: '# of horizontal bays (default 5)'\n },\n {\n type: 'number',\n label: 'shelf-base-height',\n name: 'shelfBaseHeight',\n placeholder: 'mm — level 1 시작 높이 (바닥부터). stocker port / conveyor 공간.'\n },\n {\n type: 'id-input',\n label: 'legend-target',\n name: 'legendTarget',\n property: { component: 'legend' },\n placeholder: '미명시 시 scene 의 legend 자동 발견'\n },\n {\n type: 'id-input',\n label: 'popup-ref',\n name: 'popupRef',\n property: { component: 'popup' },\n placeholder: 'click 시 invoke 할 Popup 컴포넌트 id (anchor 는 클릭된 cell 로 override)'\n },\n {\n type: 'checkbox',\n label: 'hide-horizontal-frame',\n name: 'hideHorizontalFrame'\n }\n ],\n help: 'scene/component/rack'\n}\n\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Rack lives only in the 3D scene graph.\n//\n// Mixin chain: CellContainer → CarrierHolder → Placeable → ContainerAbstract\n// CellContainer: cell topology (cellMap, cell(), findAvailableCell(), occupiedCellIds())\n// CarrierHolder: 3D attach-point protocol (attachPointFor, containable gates)\n// Placeable: floor-archetype positioning\n// ContainerAbstract: child component management\n\n// Transient carrier refid generator — load 시 root._addTraverse 가 자식 부터 처리\n// 하면서 cell.model.refid 가 비어있으면 root.getNewRefid() = 1,2,3... 작은 값 부여\n// → *부모 Rack + 모델 안 다른 컴포넌트* refid 와 충돌 (\"Refid Index replaced\" 경고).\n// transient materialize 시 *큰 시작값 + monotonic counter* 로 자체 부여 → 충돌 0.\n// hierarchy override / state.data 만 저장 → 모델 파일엔 refid 안 새겨짐.\nlet _carrierRefidCounter = 200_000_000\nfunction _nextCarrierRefid(): number {\n return _carrierRefidCounter++\n}\n/**\n * Rack — a multi-level storage shelf system. A *Storage* whose role is to hold\n * carriers in a (bay × level) grid of cells.\n *\n * `levels` × `bays` cells form a vertical grid. Each cell holds one logistics\n * package (Pallet / Box / Parcel). A picker (Crane / Forklift / robot arm)\n * accesses individual cells via the Plan A slot API — the picker interacts\n * with `SlotTarget` (no explicit cell-component required).\n *\n * **Plan A**: carriers are direct children of the rack, addressed by\n * `state.cellId`. Stock visualization uses InstancedMesh (batched). Slot\n * lookup / pick / place via `obtainCarrier` / `receiveAt` / `slotTargetAt`.\n *\n * **Placement**: `floor` archetype, full ceiling depth by default.\n *\n * **Mobility**: this Rack is stationary. A `MobileRack = Mover(Rack)` mixin\n * extension can be added later for AGV-mounted or cart-mounted variants —\n * the cell topology and pickable contract stay the same.\n */\n@sceneComponent('storage-rack')\nexport default class Rack\n extends RecordStorage<{ cellId: string; [key: string]: any }>()(\n CellContainer(CarrierHolder(Placeable(ContainerAbstract)))\n )\n implements SlottedHolder\n{\n declare state: StorageRackState\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (h: Heights) => h.ceiling - h.floor\n\n // ── RecordStorage mixin hook overrides ────────────────────────────────\n // record.cellId 가 slotId (mixin default 의 r.id 가 아닌 r.cellId).\n _recordToSlotId(record: { cellId: string }): string {\n return record.cellId ?? ''\n }\n // 3D rebuild 가 _realObject.rebuildStockMesh (mixin default 와 동일이지만 명시).\n _rebuildVisual(): void {\n ;(this._realObject as any)?.rebuildStockMesh?.()\n }\n\n // Phase Auto-Nav (AN-PR-2) — Obstacle 자격.\n get isObstacle(): boolean {\n return (this.state as any)?.isObstacle !== false\n }\n obstacleBoundingBox(): { left: number; top: number; width: number; height: number; y?: number; zHeight?: number } | null {\n // scene-base 의 componentBoundingBox 위임 — rotation 적용된 AABB.\n return componentBoundingBox(this)\n }\n\n /**\n * 이 rack 에 *_놓으려는 mover_* 의 능력을 수용하는가. canAccept(carrier) 는 carrier\n * 타입만 보지만, 이건 *_적재 mover 의 물리 능력_* 을 본다.\n *\n * rack 선반 적재는 *_높이 도달_* mover (crane / stacker / forklift) 의 몫이다.\n * 평탄 데크 차량(agv-deck)은 바닥 운반 전용 — 선반에 직접 못 올린다. 따라서\n * agv-deck 류는 거부 → transfer planner 가 자동으로 in-port 경유(환승)를 택한다.\n *\n * 거부 목록은 state.blockedTools 로 override (default ['agv-deck']). 향후 선반\n * 높이(level) vs mover liftHeight 비교로 정교화 가능.\n */\n canAcceptFromMover(mover: any): boolean {\n const toolType = mover?.toolType ?? mover?.state?.toolType\n const blocked = (this.state as any)?.blockedTools ?? ['agv-deck']\n return rackAcceptsMoverTool(toolType, blocked)\n }\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /**\n * Runtime — bays / levels 변경 시 anchor 캐시 무효화. cell 위치가 바뀌므로 다음\n * `_ensureSlotAttachObject3d` 호출이 새 좌표로 갱신.\n */\n onchange(after: Record<string, unknown>, _before: Record<string, unknown>): void {\n super.onchange?.(after, _before)\n if (\n 'bays' in after ||\n 'levels' in after ||\n 'shelfBaseHeight' in after ||\n 'width' in after ||\n 'height' in after ||\n 'depth' in after\n ) {\n this._attachAnchorBySlot.clear()\n }\n if ('hideHorizontalFrame' in after) {\n ;(this._realObject as any)?.applyFrameVisibility?.()\n }\n }\n\n // ── CellContainer ─────────────────────────────────────────────────────────\n\n /**\n * Derive the cell topology from the rack's current dimensions and bay/level\n * counts. The CellMap is rebuilt fresh each time (state changes trigger\n * re-reads via things-scene's invalidation pipeline).\n *\n * Coordinate convention (matches things-scene 3D):\n * X = bay axis (left → right)\n * Y = level axis (floor → ceiling, the rack's `depth` state property)\n * Z = row axis (front → back, the rack's `height` state property)\n */\n get cellMap(): CellMap {\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const levels = Math.max(1, Math.floor((this.state.levels as number) || 4))\n const width = (this.state.width as number) || 1000\n const rackDepth = (this.state.depth as number) || 3000 // Y: floor→ceiling\n const rackHeight = (this.state.height as number) || 600 // Z: front→back\n const shelfBase = Math.max(0, Math.min(\n (this.state.shelfBaseHeight as number) || 0,\n rackDepth * 0.9 // clamp ≤ 90% — 최소 shelf zone\n ))\n const shelfZone = rackDepth - shelfBase // 실제 shelf 가 차지하는 Y 영역\n\n return CellMap.grid({\n bays,\n rows: 1,\n levels,\n bayWidth: width / bays,\n rowDepth: rackHeight,\n levelHeight: shelfZone / levels,\n origin: { x: 0, y: shelfBase, z: 0 } // 첫 cell 의 Y = shelfBase\n })\n }\n\n // ── Container gates ───────────────────────────────────────────────────────\n\n /**\n * Allow:\n * - Carriable components (pallets, boxes, parcels) — direct children, operation archetype.\n *\n * Block:\n * - Everything else (sensors, labels, etc. can be siblings of the rack, not children).\n */\n containable(component: Component): boolean {\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this)\n }\n\n // ── CarrierHolder — attach frame for direct carrier children ─────────────\n\n /**\n * Attach frame for direct-child carriers — Plan A 의 모든 carrier 가 rack 의\n * 직접 자식이므로 매번 호출됨. carrier 의 state.cellId 에 해당하는 *cell-local\n * anchor object3d* 를 반환 → carrier 의 object3d 가 자동으로 셀 위치에 정렬됨.\n */\n attachPointFor(carrier: Component): AttachFrame | null {\n // Plan A: rack 의 직접 자식 carrier 는 *state.cellId* 로 슬롯 위치를 표시 (매트릭스\n // 내 주소). attachPointFor 는 그 cellId 의 *셀-로컬 anchor object3d* 를 반환 →\n // carrier 의 object3d 가 자동으로 셀 위치에 정렬됨.\n //\n // localPosition: {0,0,0} 명시 — Carriable.applyHolderAttachPoint 가 Three.js\n // attach() 후 *world pose 보존* 만 하고 local 을 reset 하지 않는 결함 우회.\n // 명시 시 (Carriable + CarrierHolder.reparent 모두) 그대로 anchor origin 에 snap.\n const cellId = (carrier as any)?.state?.cellId as string | undefined\n if (cellId) {\n const obj = this._ensureSlotAttachObject3d(cellId)\n if (obj) return { attach: obj, localPosition: { x: 0, y: 0, z: 0 } }\n }\n // Fallback — cellId 없는 (legacy) 호출 시 rack root.\n const root = this._realObject?.object3d\n if (!root) return null\n return { attach: root, localPosition: { x: 0, y: 0, z: 0 } }\n }\n\n // ── Plan A — Slot API (LoopSorter-style; \"rack 안 = 데이터, 밖 = 컴포넌트\") ───\n //\n // Conceptual model:\n // - rack 안의 carrier 는 *state.data 의 한 record* (데이터)\n // - rack 밖의 carrier 는 *Component* (실재)\n // - 경계 통과 시 transient materialize / atomic absorb\n //\n // 불변식: 동일 cellId 가 state.data 의 record 와 rack-child carrier 양쪽에 동시\n // 존재하지 않음. obtainCarrier 와 receiveAt 가 atomic 하게 전환.\n //\n // 호출 흐름:\n // - Pick: const c = rack.obtainCarrier('A-0-0') → c 는 rack child, record 빠짐\n // await crane.pick(c) → c.parent = crane (rack child 에서도 빠짐)\n // - Place: await crane.place(c, destRack.slotTargetAt('B-0-0'))\n // SlotTarget.receive → destRack.receiveAt → c dispose + record push\n\n // `records` getter — RecordStorage mixin 제공.\n\n /**\n * 1-based (bay, row, level) → 0-based cellId 문자열.\n *\n * rack.slotIdOf(1, 1, 6) → '0-0-5'\n * rack.slotIdOf(3, 1, 4) → '2-0-3'\n */\n slotIdOf(bay: number, row: number = 1, level: number = 1): string {\n return `${bay - 1}-${row - 1}-${level - 1}`\n }\n\n /**\n * 모든 slot id 의 목록 (Plan A 의 *cell* = slot 통일). bays × rows × levels 전 조합.\n * storage-rack 의 rows 는 항상 1 (단일 row) 이므로 실제론 bays × levels.\n *\n * SlottedHolder.slotIds — capability 기반 enumeration entry point.\n */\n slotIds(): ReadonlyArray<string> {\n const bays = Math.max(1, Math.floor((this.state as any)?.bays ?? 5))\n const levels = Math.max(1, Math.floor((this.state as any)?.levels ?? 4))\n const ids: string[] = []\n for (let bay = 1; bay <= bays; bay++) {\n for (let level = 1; level <= levels; level++) {\n ids.push(this.slotIdOf(bay, 1, level))\n }\n }\n return ids\n }\n\n /**\n * 점유된 slot 의 id 목록 — state.data record + *carrier* children 둘 다.\n * RackCell (시각 proxy) 같은 *carrier 아닌 자식* 은 제외 (isCarriable 검사).\n *\n * @param filter predicate — 통과하는 slotId 만. sweep 중 즉시 reject.\n */\n occupiedSlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n const set = new Set<string>()\n for (const r of this.records) {\n const cid = r?.cellId\n if (typeof cid === 'string' && (!filter || filter(cid))) set.add(cid)\n }\n for (const c of (this as any).components ?? []) {\n if (!(c as any)?.isCarriable) continue\n const cid = (c as any)?.state?.cellId\n if (typeof cid === 'string' && (!filter || filter(cid))) set.add(cid)\n }\n return Array.from(set)\n }\n\n /** 비어있는 slot 의 id 목록 — slotIds() - occupiedSlotIds(). filter 도 동일. */\n emptySlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n const occ = new Set(this.occupiedSlotIds())\n const result: string[] = []\n for (const id of this.slotIds()) {\n if (occ.has(id)) continue\n if (filter && !filter(id)) continue\n result.push(id)\n }\n return result\n }\n\n /**\n * slot 의 *world position* — anchor object3d *생성 없이* 직접 계산. crane 의\n * reach 검사 등 *match 전 단계* 에서 *anchor 생성 0* 으로 사용.\n */\n slotWorldPosition(cellId: string): { x: number; y: number; z: number } | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return undefined\n\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackDepth = rs?.depth || 3000\n const rackHeight = rs?.height || 600\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, rackDepth * 0.9))\n const shelfZone = rackDepth - shelfBase\n const bayWidth = rackWidth / bays\n const levelHeight = shelfZone / levels\n const stockD = levelHeight * 0.7\n const rowDepth = rackHeight\n\n const x = cell.localPosition.x + bayWidth / 2 - rackWidth / 2\n const y = cell.localPosition.y - rackDepth / 2 + stockD / 2\n const z = cell.localPosition.z + rowDepth / 2 - rackHeight / 2\n\n const v = new THREE.Vector3(x, y, z)\n ro.object3d.localToWorld(v)\n return { x: v.x, y: v.y, z: v.z }\n }\n\n /** cellId 에 carrier 가 있는가 — child carrier 또는 state.data record 어느 쪽이든. */\n hasCarrierAt(cellId: string): boolean {\n if (this._carrierChildAt(cellId)) return true\n return this.records.some((r: any) => r.cellId === cellId)\n }\n\n /** cellId 매칭되는 rack 의 직접 자식 carrier (operation archetype). */\n private _carrierChildAt(cellId: string): Component | undefined {\n const children = (this.components as Component[] | undefined) ?? []\n return children.find(c => {\n const placement = (c.constructor as any).placement\n return placement === 'operation' && (c.state as any)?.cellId === cellId\n })\n }\n\n /**\n * carrier 를 obtain — 이미 child 면 그대로, 아니면 state.data record 로 transient\n * materialize 후 rack 의 직접 자식으로 add 하고 state.data 에서 그 record 제거.\n * record 도 child 도 없으면 null.\n *\n * Signature overloads:\n * obtainCarrier('0-0-5') — string cellId 직접\n * obtainCarrier(1, 1, 6) — 1-based (bay, row, level)\n * obtainCarrier(1) ≡ obtainCarrier(1,1,1)\n */\n obtainCarrier(idOrBay: string | number, row?: number, level?: number): Component | null {\n const cellId = typeof idOrBay === 'string'\n ? idOrBay\n : this.slotIdOf(idOrBay, row ?? 1, level ?? 1)\n const existing = this._carrierChildAt(cellId)\n if (existing) return existing\n\n const records = this.records as Array<any>\n const idx = records.findIndex(r => r?.cellId === cellId)\n if (idx === -1) return null\n const record = records[idx]\n\n const carrierType = (record.type as string) || 'parcel'\n const CarrierClass = (Component as any).register(carrierType) as\n | (new (...args: any[]) => Component) | undefined\n if (!CarrierClass) {\n console.warn(`[storage-rack] obtainCarrier(\"${cellId}\"): carrier type \"${carrierType}\" 미등록`)\n return null\n }\n\n // 크기 기본값 — rack 기하에서 derive (record 가 명시 안 한 경우)\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackDepth = rs?.depth || 3000\n const rackHeight = rs?.height || 600\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, rackDepth * 0.9))\n const shelfZone = rackDepth - shelfBase\n const bayWidth = rackWidth / bays\n const levelHeight = shelfZone / levels\n\n // record 에서 id / refid / transform 류는 *제외* — id 가 들어가면 scene 안 기존\n // component 와 충돌해 parent 가 잘못 잡힘 (model-layer 의 원본을 재사용 등).\n const { id: _id, refid: _refid, transform: _tf, ...recordCopy } = record as any\n const carrierW = record.width ?? bayWidth * 0.85\n const carrierH = record.height ?? rackHeight * 0.85\n // cell 의 *rack-inner 좌표* (= carrier 의 parent=rack 의 inner 좌표계 의 점).\n // carrier.center = carrier.state.left + carrierW/2 가 *rack-inner 좌표 의 cell center*\n // 이어야 Crane.moveTo (target.center → target.toScene) 가 정확한 layer 좌표로 변환.\n // 이전엔 left=0, top=0 → center=(carrierW/2, carrierH/2) = bay 0 의 좌상단 근처 → fork 어긋남.\n const cellInfo = this.cellMap?.findById(cellId)\n const bayIdx = (cellInfo?.bay ?? 1) - 1\n const cellCenterInnerX = bayIdx * bayWidth + bayWidth / 2\n const cellCenterInnerY = rackHeight / 2\n const carrierState: any = {\n ...recordCopy,\n type: carrierType,\n cellId, // 슬롯 주소\n refid: _nextCarrierRefid(), // refid 충돌 회피\n width: carrierW,\n height: carrierH,\n depth: record.depth ?? levelHeight * 0.7,\n left: cellCenterInnerX - carrierW / 2,\n top: cellCenterInnerY - carrierH / 2\n }\n\n const carrier = new CarrierClass(carrierState, (this as any)._app)\n // *silent: true* — Plan A 의 transient materialize 는 사용자가 직접 컴포넌트\n // 만든 게 아니라 *내부적으로 잠시 빌리는 것*. 새 컴포넌트 추가 → root.onadded\n // → refreshMappings (1s debounce) → 모든 컴포넌트 매핑 재실행 의 cascade 차단.\n // (silent 모드: _silentAdd 플래그 set → refreshMappings skip)\n ;(this as any).addComponent(carrier, { silent: true })\n\n // 3D 강제 빌드 + attach (pipeline tick 없이도 즉시 표시 — Mover 가 곧 pick).\n void (carrier as any).realObject\n ;(carrier as any).applyHolderAttachPoint?.()\n\n // record 제거 — atomic: child 추가 직후. 동일 cellId 의 *모든* record 정리.\n // *silent* 갱신 — mapping cascade (onchangeData → executeMappings → script fire)\n // 회피. external (WMS push) 호출은 setState 거치므로 그쪽 mapping 은 정상 발사.\n this._setDataSilently(records.filter(r => r?.cellId !== cellId))\n\n return carrier\n }\n\n // _setDataSilently — RecordStorage mixin 제공 (_rebuildVisual hook 통해\n // rebuildStockMesh 호출). 동등 동작 + cachedState invalidate.\n\n /**\n * cell 이 carrier 를 받을 수 있는가.\n *\n * 규칙:\n * - state.data 에 record 가 있으면 점유 → false\n * - carrier-child 가 있고 *그 child 가 들여오려는 carrier 자기 자신이 아니면* → false\n * - 들여오려는 carrier 가 *바로 그 cell 의 child 자기 자신* 이면 → true (idempotent —\n * obtain('A') 직후 receive('A', sameCarrier) 가 *자기 자리 복귀* 로 동작)\n */\n canReceiveAt(cellId: string, carrier?: Component): boolean {\n const records = this.records as Array<any>\n if (records.some(r => r?.cellId === cellId)) return false\n const existingChild = this._carrierChildAt(cellId)\n if (existingChild && existingChild !== carrier) return false\n return true\n }\n\n /**\n * Carrier 가 rack 의 slot 으로 들어옴 — \"매트릭스 진입\": 즉시 dispose + state.data 에\n * record 로 환원. 결과: InstancedMesh 가 다시 그 자리에 instance 표시, rack 의 자식\n * 컴포넌트 트리는 깨끗.\n */\n async receiveAt(cellId: string, carrier: Component, _options?: any): Promise<void> {\n // R18 guard — disposed carrier 의 재처리 차단.\n if ((carrier as any)?._disposed) {\n throw new Error(\n `Rack.receiveAt(\"${cellId}\"): carrier is already disposed. ` +\n 'After a successful pickAndPlace the carrier becomes a state.data record — ' +\n 'use rack.obtainCarrier(cellId) to get a fresh transient carrier instead.'\n )\n }\n if (!this.canReceiveAt(cellId, carrier)) {\n ;(this as any).trigger?.('transfer-rejected', {\n type: 'transfer-rejected',\n component: carrier, container: this, reason: 'slot-occupied', cellId\n })\n return\n }\n\n const record = this.recordFromCarrier(carrier, cellId)\n\n // Carrier 의 parent 에서 떼고 dispose. parent 는 보통 mover (crane) 이거나 rack 자신.\n const carrierParent: any = (carrier as any).parent\n if (carrierParent && typeof carrierParent.removeComponent === 'function') {\n carrierParent.removeComponent(carrier)\n }\n\n // 명시적 Three.js detach — RealObject.dispose() 의 clear() 는 *object3d 의 children*\n // 만 정리하고 *object3d 자체* 는 scene graph 의 parent 에서 *떼지 않음*. 결과:\n // crane fork 또는 slot anchor 에 attach 됐던 object3d 가 빈 상태로 남아 ghost.\n // dispose 호출 *전* 에 명시적으로 parent.remove. (geometry/material dispose 는\n // RealObject.dispose() 의 clear() 에 위임 — 공유 material 정책 framework 책임.)\n const carrierObj3d: any = (carrier as any)._realObject?.object3d\n if (carrierObj3d?.parent && typeof carrierObj3d.parent.remove === 'function') {\n carrierObj3d.parent.remove(carrierObj3d)\n }\n\n ;(carrier as any).dispose?.()\n\n // state.data 에 push — *silent* 갱신 (mapping cascade 회피, 위 _setDataSilently 주석 참조).\n // 중복 방어: 동일 cellId 의 기존 record 가 있으면 제거 후 새 record 단일 추가.\n const currentRecords = (this.records as any[]).filter(r => r?.cellId !== cellId)\n this._setDataSilently([...currentRecords, record])\n\n ;(this as any).trigger?.('transfer-received', {\n type: 'transfer-received',\n component: carrier, container: this, slotId: cellId, record\n })\n }\n\n /**\n * Carrier 의 state 를 state.data record 로 추출. application 이 carrier subclass 별\n * 추가 필드 인코딩 원하면 override. transform/position 관련은 record 와 무관해 skip.\n */\n recordFromCarrier(carrier: Component, cellId: string): { cellId: string; [key: string]: any } {\n const state: any = (carrier as any).state ?? {}\n const SKIP_KEYS = new Set([\n 'left', 'top', 'zPos',\n 'transform', 'rotation', 'scale',\n '_transferSlotId',\n 'cellId', // 새로 override\n 'id', // 다음 materialize 시 충돌 방지 (id 는 component-instance 의 것, record 의 것 아님)\n 'refid'\n ])\n const record: any = { cellId, type: state.type }\n for (const key of Object.keys(state)) {\n if (SKIP_KEYS.has(key)) continue\n record[key] = state[key]\n }\n return record\n }\n\n /**\n * SlottedHolder 컨트랙 — slot 의 attach object3d 반환. SlotTarget 이 자기\n * `_realObject.object3d` proxy 로 사용하고, Carriable.applyHolderAttachPoint 도\n * 이걸 attach frame 으로 사용 (transit 중 carrier 가 slot 위치에 정렬).\n */\n getSlotAttachObject3d(cellId: string): THREE.Object3D | undefined {\n return this._ensureSlotAttachObject3d(cellId)\n }\n\n /**\n * SlottedHolder 컨트랙 — slot 의 *expected carrier* 의 3D 크기 (slot 자체의 기하 크기가\n * 아님). Crane 의 `resolveCarrierBottomY = centerY - depth/2` 에서 *carrier 가 놓일 때\n * 예상되는 carrier depth* 를 써야 fork 가 *carrier 바닥 = shelf* 에 정확히 진입.\n *\n * 즉:\n * depth = stockD (= levelHeight * 0.7) — *carrier 의 vertical extent*. 전체 셀 높이\n * (levelHeight) 가 아닌 *실제 stock 박스 깊이*. anchor 가 stock 시각 중심 (\n * shelf + stockD/2) 에 위치하므로 depth = stockD 여야 bottom 계산이 shelf.\n * width = bayWidth — 그대로\n * height = rowDepth — 그대로 (2D 의 Z 축 폭)\n */\n getSlotSize(cellId: string): { width: number; height: number; depth: number } | undefined {\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return undefined\n const stockD = cell.size.height * 0.7 // matches _ensureSlotAttachObject3d + storage-rack-3d.rebuildStockMesh\n return {\n width: cell.size.width,\n height: cell.size.depth, // 2D height = Z extent (front-back)\n depth: stockD // 3D depth = carrier Y extent (NOT full level)\n }\n }\n\n /**\n * SlottedHolder 컨트랙 — cellId 에 대한 SlotTarget. Mover.pickAndPlace 의 dest 로 넘김.\n *\n * Signature overloads:\n * slotTargetAt('0-0-5') — string cellId 직접\n * slotTargetAt(1, 1, 6) — 1-based (bay, row, level)\n */\n slotTargetAt(idOrBay: string | number, row?: number, level?: number): SlotTarget {\n const cellId = typeof idOrBay === 'string'\n ? idOrBay\n : this.slotIdOf(idOrBay, row ?? 1, level ?? 1)\n return new SlotTarget(this, cellId)\n }\n\n /**\n * SlotTarget 의 2D center 위임 — Mover.moveTo 의 2D path 계산에 사용.\n *\n * 반환값은 *rack 자체의 local frame* (rack 의 left/top 미포함) — 즉 cell 의 위치를\n * rack 의 *내부 좌표계로* 표현. SlotTarget.toScene 이 rack.toScene 을 위임해 *rack 의\n * rotation / 부모 chain 변환 포함* 한 절대 좌표로 변환.\n *\n * 이전 결함: rack.left/top 을 포함해 model-layer 프레임 좌표 반환 + toScene 미구현 →\n * rack 이 rotated 또는 nested 일 때 X 가 어긋났음.\n */\n cellCenter2D(cellId: string): { x: number; y: number } | null {\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return null\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackHeight = rs?.height || 100\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const bayWidth = rackWidth / bays\n const bayIdx = cell.bay - 1\n // things-scene 컨벤션: 컴포넌트의 `center` 는 *parent 좌표계 의 center*\n // (= bounds.left + width/2). 즉 *layer 좌표* — rack 의 left/top 포함, *rack 의\n // rotation 미적용*. toScene 가 rotation 처리. parcel.center 등 모든 실제\n // 컴포넌트가 이 컨벤션이므로 SlotTarget.center 도 동일해야 *pick 과 place 의\n // 좌표 변환 체인 일관성* 유지.\n return {\n x: (rs?.left ?? 0) + bayIdx * bayWidth + bayWidth / 2,\n y: (rs?.top ?? 0) + rackHeight / 2\n }\n }\n\n /**\n * SlotTarget 의 toScene 위임 — *rack-local* 좌표를 *scene-absolute* 로 변환.\n * rack.toScene 이 rack 의 rotation / translation / parent chain 모두 처리.\n */\n cellToScene(localX: number, localY: number): { x: number; y: number } {\n const f = (this as any).toScene\n if (typeof f === 'function') return f.call(this, localX, localY)\n return { x: localX, y: localY }\n }\n\n /** cellId 별 attach anchor object3d cache (rack.object3d 의 자식). */\n private _attachAnchorBySlot: Map<string, THREE.Object3D> = new Map()\n\n /**\n * cellId 위치에 lightweight anchor object3d 를 *singleton 으로* 보장 + 갱신.\n * 이 anchor 가:\n * - Carriable.applyHolderAttachPoint 가 attach 하는 frame\n * - SlotTarget._realObject.object3d 의 proxy\n * - 두 용도가 *같은 object3d* 를 공유해 carrier 가 transient 동안 SlotTarget 의\n * pose 와 정확히 동기화.\n */\n private _ensureSlotAttachObject3d(cellId: string): THREE.Object3D | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n\n let obj = this._attachAnchorBySlot.get(cellId)\n if (!obj) {\n obj = new THREE.Object3D()\n obj.name = `rack-slot-anchor:${cellId}`\n ro.object3d.add(obj)\n this._attachAnchorBySlot.set(cellId, obj)\n }\n\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return undefined\n\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackDepth = rs?.depth || 3000\n const rackHeight = rs?.height || 600\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, rackDepth * 0.9))\n const shelfZone = rackDepth - shelfBase\n const bayWidth = rackWidth / bays\n const levelHeight = shelfZone / levels\n const stockD = levelHeight * 0.7 // ← storage-rack-3d.rebuildStockMesh 의 stockD 와 동일\n const rowDepth = rackHeight\n\n // Anchor Y = *stock 시각 중심* (shelf + stockD/2). InstancedMesh 의 stock 박스 중심과\n // 일치 → carrier (depth = stockD) 가 attach 시 정확히 stock 위치에 올라 앉음. Crane\n // 의 resolveCarrierBottomY = centerY - depth/2 = shelf 라 fork 가 정확히 shelf 진입.\n const x = cell.localPosition.x + bayWidth / 2 - rackWidth / 2\n const y = cell.localPosition.y - rackDepth / 2 + stockD / 2\n const z = cell.localPosition.z + rowDepth / 2 - rackHeight / 2\n obj.position.set(x, y, z)\n obj.updateMatrixWorld(true)\n return obj\n }\n\n // ── 2D rendering ─────────────────────────────────────────────────────────\n\n /**\n * 2D — top-down rectangle showing the rack footprint with bay subdivisions.\n * 편집/배치 가 가능하도록 *명시 fill + stroke* — pipeline 분기 무관하게 항상\n * 보임. fill 은 반투명 (carrier / cell 위 overlay).\n */\n render(ctx: CanvasRenderingContext2D) {\n const left = (this.state.left as number) ?? 0\n const top = (this.state.top as number) ?? 0\n const width = (this.state.width as number) ?? 400\n const height = (this.state.height as number) ?? 100\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const fill = (this.state.fillStyle as string) || '#a0a0a8'\n const stroke = (this.state.strokeStyle as string) || '#555'\n const lineWidth = (this.state.lineWidth as number) || 1\n\n // Fill (반투명)\n ctx.save()\n ctx.fillStyle = fill\n ctx.globalAlpha = 0.2\n ctx.fillRect(left, top, width, height)\n ctx.restore()\n\n // Stroke — outer + bay subdivisions\n ctx.strokeStyle = stroke\n ctx.lineWidth = lineWidth\n ctx.strokeRect(left, top, width, height)\n ctx.beginPath()\n for (let i = 1; i < bays; i++) {\n const x = left + (width * i) / bays\n ctx.moveTo(x, top)\n ctx.lineTo(x, top + height)\n }\n ctx.stroke()\n }\n\n get fillStyle() {\n return '#a0a0a8'\n }\n\n // ── Data binding — state.data 변경 시 InstancedMesh 재구성 ───────────────\n\n onchangeData(): void {\n ;(this._realObject as any)?.rebuildStockMesh?.()\n }\n\n // legendTarget / _onLegendChanged / resolveLegendColor — RecordStorage mixin 제공.\n\n // ── Click event — rack-cell-click 발사 ────────────────────────────────────\n //\n // 사용자가 *어떤 셀*을 클릭하든 (stock 가시화된 셀이든, 빈 셀이든) rack 이 다음\n // payload 로 `rack-cell-click` 을 emit:\n // { cellId, record?, hitPoint, instanceId?, isStock }\n //\n // 외부 consumer 등록:\n // rack.on('rack-cell-click', ({ cellId, record, isStock }) => { ... })\n //\n // 분기:\n // - InstancedMesh (stock) hit → cellId/record 는 records[instanceId] 에서 직접 추출, isStock=true\n // - 그 외 rack mesh (shelf/frame) hit → hit.point 를 rack-local 좌표로 변환 후\n // (bay, level) 역산, record 는 state.data 검색, isStock=false\n // edit mode 클릭은 framework 의 선택 로직 우선이라 emit 하지 않음.\n\n /**\n * things-scene EventManager3D 가 raycast → object3d.userData.context.component 의\n * `trigger(\"click\", mouseEvent)` 을 호출 → eventMap 으로 receive.\n * `(self).(self).click` 으로 등록해 *우리 rack 의 어떤 mesh 든 클릭됐을 때* 발사.\n */\n get eventMap() {\n return {\n '(self)': {\n '(self)': {\n click: this._onRackClick\n }\n }\n }\n }\n\n private _onRackClick = (mouseEvent: MouseEvent) => {\n // view mode 에서만 동작 (modeling 중 클릭은 framework 의 선택 로직 우선).\n if (!(this as any).app?.isViewMode) return\n\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return\n\n const hit = this._raycastRackHit(mouseEvent)\n if (!hit) return\n\n const stockMesh: THREE.InstancedMesh | undefined = ro.stockMesh\n let cellId: string | undefined\n let record: any\n let isStock = false\n let instanceId: number | undefined\n\n if (hit.object === stockMesh) {\n // (A) Stock instance 직접 hit — records 에서 정확한 record 추출.\n const records: any[] | undefined = (stockMesh as any).userData?._records\n record = records?.[hit.instanceId ?? -1]\n cellId = record?.cellId\n isStock = true\n instanceId = hit.instanceId\n } else {\n // (B) 빈 cell / shelf / frame hit — world point → cellId 역산.\n const cid = this._cellIdFromWorldPoint(hit.point)\n if (!cid || cid.startsWith('out-of-bounds')) return\n cellId = cid\n const data = this.state.data as Array<any> | undefined\n record = Array.isArray(data) ? data.find(r => r?.cellId === cid) : undefined\n }\n\n const payload = { cellId, record, hitPoint: hit.point, instanceId, isStock }\n this.trigger('rack-cell-click', payload)\n\n // Popup 호출 — 일반 mechanism (Popup 컴포넌트) 활용, anchor 만 클릭된 cell 로 override.\n if (cellId) this._invokePopup(cellId, record ?? { cellId })\n }\n\n // _invokePopup — RecordStorage mixin 제공 (cellId=slotId, record=payload).\n\n /**\n * 클릭 시 framework 의 mouse NDC (이미 InteractionManager 가 set 한 상태) 를 재사용해\n * raycast → *우리 rack* 의 어떤 mesh 가 closest hit 인지 반환. 다른 object 가 더 가까우면\n * undefined (다른 rack 또는 무관 mesh 의 hit).\n *\n * 접근 경로:\n * 1. ThreeCapability — ModelLayer 는 `_threeCapability`, ThreeContainer 는 `_capability`.\n * capability 의 `getObjectsByRaycast()` 가 *동일한* mouse NDC 로 framework 가 click\n * 처리 직전에 쓴 그 raycaster 를 재사용 (가장 정확).\n * 2. capability 가 없는 컨테이너 — public scene3d / renderer3d / camera + mouseEvent\n * 좌표로 자체 ndc 변환 후 fresh raycaster.\n */\n private _raycastRackHit(mouseEvent: MouseEvent): THREE.Intersection | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n\n const tc: any = ro.threeContainer\n if (!tc) return undefined\n\n const cap: any = tc._threeCapability ?? tc._capability\n let intersects: THREE.Intersection[] | undefined\n if (cap?.getObjectsByRaycast) {\n intersects = cap.getObjectsByRaycast() as THREE.Intersection[] | undefined\n }\n\n if (!intersects || intersects.length === 0) {\n const scene = tc.scene3d as THREE.Scene | undefined\n const renderer = tc.renderer3d as THREE.WebGLRenderer | undefined\n const camera =\n (tc.activeCamera3d as THREE.Camera | undefined) ??\n (cap?.activeCamera as THREE.Camera | undefined) ??\n (cap?.camera as THREE.Camera | undefined)\n const canvas = renderer?.domElement\n if (!scene || !canvas || !camera) return undefined\n const rect = canvas.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return undefined\n const ndc = new THREE.Vector2(\n ((mouseEvent.clientX - rect.left) / rect.width) * 2 - 1,\n -((mouseEvent.clientY - rect.top) / rect.height) * 2 + 1\n )\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(ndc, camera)\n intersects = raycaster.intersectObjects(scene.children, true)\n }\n\n if (!intersects || intersects.length === 0) return undefined\n\n // Three.js intersectObjects 는 distance 오름차순 정렬. 첫 hit 이 *우리 rack* 의 descendant\n // 인지 확인 (userData.context walk-up 으로). 다른 object 가 더 가까우면 (다른 rack 또는\n // 무관 mesh 가 사이에 있음) — 무시.\n const closest = intersects[0]\n let obj: THREE.Object3D | null = closest.object\n while (obj) {\n if (obj.userData?.context === ro) return closest\n obj = obj.parent\n }\n return undefined\n }\n\n /**\n * world point → cellId 역산.\n *\n * 1. rack 의 `matrixWorld.invert()` 로 world → rack-local 변환 (rack 의 회전·이동\n * 반영)\n * 2. rack-local point 의 `(x, y)` 를 (bay, level) 격자에 매핑\n *\n * 범위 밖이면 `\"out-of-bounds(...)\"` 문자열 반환 (caller 가 무시).\n */\n private _cellIdFromWorldPoint(worldPoint: THREE.Vector3): string | null {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return null\n\n const local = new THREE.Vector3().copy(worldPoint)\n const mInv = new THREE.Matrix4().copy(ro.object3d.matrixWorld).invert()\n local.applyMatrix4(mInv)\n\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const levels = Math.max(1, Math.floor((this.state.levels as number) || 4))\n const width = (this.state.width as number) || 1000\n const depth = (this.state.depth as number) || 3000\n const shelfBase = (this.state.shelfBaseHeight as number) || 0\n const shelfZone = depth - shelfBase\n\n const bayWidth = width / bays\n const levelHeight = shelfZone / levels\n\n // rack 의 3D origin = rack center. X: [-width/2,+width/2], Y: [-depth/2,+depth/2]\n const bayIdx = Math.floor((local.x + width / 2) / bayWidth)\n const yFromBottom = local.y + depth / 2 - shelfBase\n const levelIdx = Math.floor(yFromBottom / levelHeight)\n const rowIdx = 0 // storage-rack 은 rows=1\n\n if (bayIdx < 0 || bayIdx >= bays || levelIdx < 0 || levelIdx >= levels) {\n return `out-of-bounds(bay=${bayIdx}, level=${levelIdx})`\n }\n return `${bayIdx}-${rowIdx}-${levelIdx}`\n }\n\n /**\n * Cell-precise approach point — mover 가 *_cell 정면 외부 stand-off_* 까지만.\n *\n * cellId format: `${bay - 1}-${row - 1}-${level - 1}` (0-based).\n *\n * **사용자 의도**: rack 은 *_전면_* 만 포크질 가능. front face = state.top 쪽\n * (작은 z, 3D 의 -Z forward). back face 사용 금지 — forklift 가 rack 후면에\n * 정차하는 동작은 잘못. navigation 의 obstacle avoidance 가 rack 우회 path 계산.\n *\n * forkLen — fork blade tip 부터 mover center 까지 거리. mover 가 그 거리만큼\n * cell face 앞에서 정차 → 정확히 fork blade 가 cell face 정렬.\n *\n * (rotation 지원 V11 — 현재 axis-aligned rack 만, facing default = top.)\n */\n slotApproachWorldPosition(\n slotId: string,\n _fromPos?: { x: number; y: number; z: number }\n ): { x: number; y: number; z: number } {\n const parts = slotId.split('-')\n const s: any = this.state\n const left = s?.left ?? 0\n const top = s?.top ?? 0\n const width = s?.width ?? 0\n\n if (parts.length !== 3) {\n // fallback — front face center\n return { x: left + width / 2, y: 0, z: top - (s.depth ?? 100) * 0.5 }\n }\n const col = Number(parts[0])\n const bays = Math.max(1, Math.floor((s.bays as number) ?? 5))\n\n const cellX = left + (col + 0.5) * (width / bays)\n\n // fork 진입 거리 — rack.depth 의 절반 (mover 정차 점이 fork blade 가 cell 정면에\n // 정렬되는 거리). _fromPos 무시 — *_항상 front face_* (사용자 의도: 전면만 포크질).\n const forkLen = (s.depth ?? 100) * 0.5\n\n return { x: cellX, y: 0, z: top - forkLen }\n }\n\n // ── 3D ───────────────────────────────────────────────────────────────────\n\n buildRealObject(): RealObject | undefined {\n return new StorageRack3D(this)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"storage-rack.js","sourceRoot":"","sources":["../src/storage-rack.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAO,EAAE,SAAS,EAAmB,iBAAiB,EAAE,QAAQ,EAAc,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAE5H,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EACL,aAAa,EACb,OAAO,EACP,aAAa,EACb,SAAS,EACT,aAAa,EACb,UAAU,EACV,oBAAoB,EAOrB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAA;AA4D3D,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,kCAAkC;SAChD;QACD;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,kCAAkC;SAChD;QACD;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,mBAAmB;YAC1B,IAAI,EAAE,iBAAiB;YACvB,WAAW,EAAE,wDAAwD;SACtE;QACD;YACE,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,eAAe;YACtB,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE;YACjC,WAAW,EAAE,4BAA4B;SAC1C;QACD;YACE,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,WAAW;YAClB,IAAI,EAAE,UAAU;YAChB,QAAQ,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE;YAChC,WAAW,EAAE,+DAA+D;SAC7E;QACD;YACE,IAAI,EAAE,UAAU;YAChB,KAAK,EAAE,uBAAuB;YAC9B,IAAI,EAAE,qBAAqB;SAC5B;KACF;IACD,IAAI,EAAE,sBAAsB;CAC7B,CAAA;AAED,2FAA2F;AAC3F,mEAAmE;AACnE,kEAAkE;AAClE,EAAE;AACF,6EAA6E;AAC7E,2FAA2F;AAC3F,gFAAgF;AAChF,+CAA+C;AAC/C,kDAAkD;AAElD,0EAA0E;AAC1E,qEAAqE;AACrE,qEAAqE;AACrE,sEAAsE;AACtE,6DAA6D;AAC7D,IAAI,oBAAoB,GAAG,WAAW,CAAA;AACtC,SAAS,iBAAiB;IACxB,OAAO,oBAAoB,EAAE,CAAA;AAC/B,CAAC;AACD;;;;;;;;;;;;;;;;;;GAkBG;AAEY,IAAM,IAAI,GAAV,MAAM,IACnB,SAAQ,aAAa,EAA0C,CAC7D,aAAa,CAAC,QAAQ,CAAC,aAAa,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CACrE;IAKD,MAAM,CAAC,SAAS,GAAuB,OAAO,CAAA;IAC9C,MAAM,CAAC,KAAK,GAAc,QAAQ,CAAA;IAClC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAA;IAEzD,yEAAyE;IACzE,+DAA+D;IAC/D,eAAe,CAAC,MAA0B;QACxC,OAAO,MAAM,CAAC,MAAM,IAAI,EAAE,CAAA;IAC5B,CAAC;IACD,wEAAwE;IACxE,cAAc;QACZ,CAAC;QAAC,IAAI,CAAC,WAAmB,EAAE,gBAAgB,EAAE,EAAE,CAAA;IAClD,CAAC;IAED,0CAA0C;IAC1C,IAAI,UAAU;QACZ,OAAQ,IAAI,CAAC,KAAa,EAAE,UAAU,KAAK,KAAK,CAAA;IAClD,CAAC;IACD,mBAAmB;QACjB,4DAA4D;QAC5D,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAA;IACnC,CAAC;IAED;;;;;;;;;;OAUG;IACH,kBAAkB,CAAC,KAAU;QAC3B,MAAM,QAAQ,GAAG,KAAK,EAAE,QAAQ,IAAI,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAA;QAC1D,MAAM,OAAO,GAAI,IAAI,CAAC,KAAa,EAAE,YAAY,IAAI,CAAC,UAAU,CAAC,CAAA;QACjE,OAAO,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAChD,CAAC;IAED,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED;;;OAGG;IACH,QAAQ,CAAC,KAA8B,EAAE,OAAgC;QACvE,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;QAChC,IACE,MAAM,IAAI,KAAK;YACf,QAAQ,IAAI,KAAK;YACjB,iBAAiB,IAAI,KAAK;YAC1B,OAAO,IAAI,KAAK;YAChB,QAAQ,IAAI,KAAK;YACjB,OAAO,IAAI,KAAK,EAChB,CAAC;YACD,IAAI,CAAC,mBAAmB,CAAC,KAAK,EAAE,CAAA;QAClC,CAAC;QACD,IAAI,qBAAqB,IAAI,KAAK,EAAE,CAAC;YACnC,CAAC;YAAC,IAAI,CAAC,WAAmB,EAAE,oBAAoB,EAAE,EAAE,CAAA;QACtD,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E;;;;;;;;;OASG;IACH,IAAI,OAAO;QACT,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,MAAiB,IAAI,CAAC,CAAC,CAAC,CAAA;QAC1E,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,IAAI,CAAA;QAClD,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,IAAI,CAAA,CAAG,mBAAmB;QAC5E,MAAM,UAAU,GAAI,IAAI,CAAC,KAAK,CAAC,MAAiB,IAAI,GAAG,CAAA,CAAE,gBAAgB;QACzE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CACnC,IAAI,CAAC,KAAK,CAAC,eAA0B,IAAI,CAAC,EAC3C,SAAS,GAAG,GAAG,CAAwC,8BAA8B;SACtF,CAAC,CAAA;QACF,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA,CAAkB,uBAAuB;QAEhF,OAAO,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI;YACJ,IAAI,EAAE,CAAC;YACP,MAAM;YACN,QAAQ,EAAE,KAAK,GAAG,IAAI;YACtB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,SAAS,GAAG,MAAM;YAC/B,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAmB,yBAAyB;SACjF,CAAC,CAAA;IACJ,CAAC;IAED,6EAA6E;IAE7E;;;;;;OAMG;IACH,WAAW,CAAC,SAAoB;QAC9B,MAAM,SAAS,GAAI,SAAS,CAAC,WAAmB,CAAC,SAAS,CAAA;QAC1D,IAAI,SAAS,KAAK,WAAW;YAAE,OAAO,IAAI,CAAA;QAC1C,OAAO,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,4EAA4E;IAE5E;;;;OAIG;IACH,cAAc,CAAC,OAAkB;QAC/B,kEAAkE;QAClE,mEAAmE;QACnE,uCAAuC;QACvC,EAAE;QACF,0EAA0E;QAC1E,6DAA6D;QAC7D,yEAAyE;QACzE,MAAM,MAAM,GAAI,OAAe,EAAE,KAAK,EAAE,MAA4B,CAAA;QACpE,IAAI,MAAM,EAAE,CAAC;YACX,MAAM,GAAG,GAAG,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAA;YAClD,IAAI,GAAG;gBAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAA;QACtE,CAAC;QACD,gDAAgD;QAChD,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAA;QACvC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACtB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAA;IAC9D,CAAC;IAED,wEAAwE;IACxE,EAAE;IACF,oBAAoB;IACpB,sDAAsD;IACtD,yCAAyC;IACzC,oDAAoD;IACpD,EAAE;IACF,mEAAmE;IACnE,uDAAuD;IACvD,EAAE;IACF,SAAS;IACT,gFAAgF;IAChF,wEAAwE;IACxE,kEAAkE;IAClE,+EAA+E;IAE/E,6CAA6C;IAE7C;;;;;OAKG;IACH,QAAQ,CAAC,GAAW,EAAE,MAAc,CAAC,EAAE,QAAgB,CAAC;QACtD,OAAO,GAAG,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,GAAG,CAAC,EAAE,CAAA;IAC7C,CAAC;IAED;;;;;OAKG;IACH,OAAO;QACL,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAa,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACpE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAa,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAA;QACxE,MAAM,GAAG,GAAa,EAAE,CAAA;QACxB,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACrC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;gBAC7C,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;YACxC,CAAC;QACH,CAAC;QACD,OAAO,GAAG,CAAA;IACZ,CAAC;IAED;;;;;OAKG;IACH,eAAe,CAAC,MAAoC;QAClD,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAA;QAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,CAAC,EAAE,MAAM,CAAA;YACrB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACvE,CAAC;QACD,KAAK,MAAM,CAAC,IAAK,IAAY,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;YAC/C,IAAI,CAAE,CAAS,EAAE,WAAW;gBAAE,SAAQ;YACtC,MAAM,GAAG,GAAI,CAAS,EAAE,KAAK,EAAE,MAAM,CAAA;YACrC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACvE,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IAED,sEAAsE;IACtE,YAAY,CAAC,MAAoC;QAC/C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAA;QAC3C,MAAM,MAAM,GAAa,EAAE,CAAA;QAC3B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YAChC,IAAI,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,SAAQ;YACzB,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;gBAAE,SAAQ;YACnC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;QACjB,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,MAAc;QAC9B,MAAM,EAAE,GAAS,IAAY,CAAC,WAAW,CAAA;QACzC,IAAI,CAAC,EAAE,EAAE,QAAQ;YAAE,OAAO,SAAS,CAAA;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAA;QAE3B,MAAM,EAAE,GAAQ,IAAI,CAAC,KAAK,CAAA;QAC1B,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,UAAU,GAAG,EAAE,EAAE,MAAM,IAAI,GAAG,CAAA;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAA;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC,CAAA;QAClF,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;QACvC,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAA;QACjC,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;QACtC,MAAM,MAAM,GAAG,WAAW,GAAG,GAAG,CAAA;QAChC,MAAM,QAAQ,GAAG,UAAU,CAAA;QAE3B,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,UAAU,GAAG,CAAC,CAAA;QAE9D,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACpC,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;QAC3B,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACnC,CAAC;IAED,0EAA0E;IAC1E,YAAY,CAAC,MAAc;QACzB,IAAI,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAA;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAA;IAC3D,CAAC;IAED,8DAA8D;IACtD,eAAe,CAAC,MAAc;QACpC,MAAM,QAAQ,GAAI,IAAI,CAAC,UAAsC,IAAI,EAAE,CAAA;QACnE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;YACvB,MAAM,SAAS,GAAI,CAAC,CAAC,WAAmB,CAAC,SAAS,CAAA;YAClD,OAAO,SAAS,KAAK,WAAW,IAAK,CAAC,CAAC,KAAa,EAAE,MAAM,KAAK,MAAM,CAAA;QACzE,CAAC,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;;;OASG;IACH,aAAa,CAAC,OAAwB,EAAE,GAAY,EAAE,KAAc;QAClE,MAAM,MAAM,GAAG,OAAO,OAAO,KAAK,QAAQ;YACxC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAA;QAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAC7C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAA;QAE7B,MAAM,OAAO,GAAG,IAAI,CAAC,OAAqB,CAAA;QAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;QACxD,IAAI,GAAG,KAAK,CAAC,CAAC;YAAE,OAAO,IAAI,CAAA;QAC3B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;QAE3B,MAAM,WAAW,GAAI,MAAM,CAAC,IAAe,IAAI,QAAQ,CAAA;QACvD,MAAM,YAAY,GAAI,SAAiB,CAAC,QAAQ,CAAC,WAAW,CACT,CAAA;QACnD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,OAAO,CAAC,IAAI,CAAC,iCAAiC,MAAM,qBAAqB,WAAW,OAAO,CAAC,CAAA;YAC5F,OAAO,IAAI,CAAA;QACb,CAAC;QAED,iDAAiD;QACjD,MAAM,EAAE,GAAQ,IAAI,CAAC,KAAK,CAAA;QAC1B,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,UAAU,GAAG,EAAE,EAAE,MAAM,IAAI,GAAG,CAAA;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAA;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC,CAAA;QAClF,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;QACvC,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAA;QACjC,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;QAEtC,kEAAkE;QAClE,4DAA4D;QAC5D,MAAM,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,MAAa,CAAA;QAC/E,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,IAAI,QAAQ,GAAG,IAAI,CAAA;QAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,IAAI,UAAU,GAAG,IAAI,CAAA;QACnD,oEAAoE;QACpE,mFAAmF;QACnF,wEAAwE;QACxE,mFAAmF;QACnF,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC/C,MAAM,MAAM,GAAG,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAA;QACvC,MAAM,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAA;QACzD,MAAM,gBAAgB,GAAG,UAAU,GAAG,CAAC,CAAA;QACvC,MAAM,YAAY,GAAQ;YACxB,GAAG,UAAU;YACb,IAAI,EAAE,WAAW;YACjB,MAAM,EAA2C,QAAQ;YACzD,KAAK,EAAE,iBAAiB,EAAE,EAAuB,cAAc;YAC/D,KAAK,EAAE,QAAQ;YACf,MAAM,EAAE,QAAQ;YAChB,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,WAAW,GAAG,GAAG;YACxC,IAAI,EAAE,gBAAgB,GAAG,QAAQ,GAAG,CAAC;YACrC,GAAG,EAAE,gBAAgB,GAAG,QAAQ,GAAG,CAAC;SACrC,CAAA;QAED,MAAM,OAAO,GAAG,IAAI,YAAY,CAAC,YAAY,EAAG,IAAY,CAAC,IAAI,CAAC,CAKjE;QAAC,IAAY,CAAC,UAAU,CAAC,OAAO,CAAC,CAAA,CAAE,uCAAuC;QAE3E,gEAAgE;QAChE,KAAM,OAAe,CAAC,UAAU,CAC/B;QAAC,OAAe,CAAC,sBAAsB,EAAE,EAAE,CAAA;QAE5C,+DAA+D;QAC/D,+EAA+E;QAC/E,gEAAgE;QAChE,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAC,CAAA;QAEhE,OAAO,OAAO,CAAA;IAChB,CAAC;IAED,oEAAoE;IACpE,wDAAwD;IAExD;;;;;;;;OAQG;IACH,YAAY,CAAC,MAAc,EAAE,OAAmB;QAC9C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAqB,CAAA;QAC1C,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;YAAE,OAAO,KAAK,CAAA;QACzD,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;QAClD,IAAI,aAAa,IAAI,aAAa,KAAK,OAAO;YAAE,OAAO,KAAK,CAAA;QAC5D,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,SAAS,CAAC,MAAc,EAAE,OAAkB,EAAE,QAAc;QAChE,yCAAyC;QACzC,IAAK,OAAe,EAAE,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,KAAK,CACb,mBAAmB,MAAM,mCAAmC;gBAC5D,4EAA4E;gBAC5E,0EAA0E,CAC3E,CAAA;QACH,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;YACxC,CAAC;YAAC,IAAY,CAAC,OAAO,EAAE,CAAC,mBAAmB,EAAE;gBAC5C,IAAI,EAAE,mBAAmB;gBACzB,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM;aACrE,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAEtD,yEAAyE;QACzE,MAAM,aAAa,GAAS,OAAe,CAAC,MAAM,CAAA;QAClD,IAAI,aAAa,IAAI,OAAO,aAAa,CAAC,eAAe,KAAK,UAAU,EAAE,CAAC;YACzE,aAAa,CAAC,eAAe,CAAC,OAAO,CAAC,CAAA;QACxC,CAAC;QAED,+EAA+E;QAC/E,8DAA8D;QAC9D,mEAAmE;QACnE,qEAAqE;QACrE,sEAAsE;QACtE,MAAM,YAAY,GAAS,OAAe,CAAC,WAAW,EAAE,QAAQ,CAAA;QAChE,IAAI,YAAY,EAAE,MAAM,IAAI,OAAO,YAAY,CAAC,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YAC7E,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAA;QAC1C,CAAC;QAED,CAAC;QAAC,OAAe,CAAC,OAAO,EAAE,EAAE,CAAA;QAE7B,kFAAkF;QAClF,0DAA0D;QAC1D,MAAM,cAAc,GAAI,IAAI,CAAC,OAAiB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC,CAAA;QAChF,IAAI,CAAC,gBAAgB,CAAC,CAAC,GAAG,cAAc,EAAE,MAAM,CAAC,CAAC,CAEjD;QAAC,IAAY,CAAC,OAAO,EAAE,CAAC,mBAAmB,EAAE;YAC5C,IAAI,EAAE,mBAAmB;YACzB,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;SAC5D,CAAC,CAAA;IACJ,CAAC;IAED;;;OAGG;IACH,iBAAiB,CAAC,OAAkB,EAAE,MAAc;QAClD,MAAM,KAAK,GAAS,OAAe,CAAC,KAAK,IAAI,EAAE,CAAA;QAC/C,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;YACxB,MAAM,EAAE,KAAK,EAAE,MAAM;YACrB,WAAW,EAAE,UAAU,EAAE,OAAO;YAChC,iBAAiB;YACjB,QAAQ,EAAG,cAAc;YACzB,IAAI,EAAO,sEAAsE;YACjF,OAAO;SACR,CAAC,CAAA;QACF,MAAM,MAAM,GAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAA;QAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACrC,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,SAAQ;YAChC,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;QAC1B,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;;;OAIG;IACH,qBAAqB,CAAC,MAAc;QAClC,OAAO,IAAI,CAAC,yBAAyB,CAAC,MAAM,CAAC,CAAA;IAC/C,CAAC;IAED;;;;;;;;;;;OAWG;IACH,WAAW,CAAC,MAAc;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAA;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAA,CAAG,uEAAuE;QAC/G,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;YACtB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAK,oCAAoC;YAChE,KAAK,EAAE,MAAM,CAAgB,+CAA+C;SAC7E,CAAA;IACH,CAAC;IAED;;;;;;OAMG;IACH,YAAY,CAAC,OAAwB,EAAE,GAAY,EAAE,KAAc;QACjE,MAAM,MAAM,GAAG,OAAO,OAAO,KAAK,QAAQ;YACxC,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC,CAAA;QAChD,OAAO,IAAI,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACrC,CAAC;IAED;;;;;;;;;OASG;IACH,YAAY,CAAC,MAAc;QACzB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACtB,MAAM,EAAE,GAAQ,IAAI,CAAC,KAAK,CAAA;QAC1B,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,UAAU,GAAG,EAAE,EAAE,MAAM,IAAI,GAAG,CAAA;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAA;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC,CAAA;QAC3B,2DAA2D;QAC3D,wEAAwE;QACxE,8DAA8D;QAC9D,0DAA0D;QAC1D,oBAAoB;QACpB,OAAO;YACL,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,MAAM,GAAG,QAAQ,GAAG,QAAQ,GAAG,CAAC;YACrD,CAAC,EAAE,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,UAAU,GAAG,CAAC;SACnC,CAAA;IACH,CAAC;IAED;;;OAGG;IACH,WAAW,CAAC,MAAc,EAAE,MAAc;QACxC,MAAM,CAAC,GAAI,IAAY,CAAC,OAAO,CAAA;QAC/B,IAAI,OAAO,CAAC,KAAK,UAAU;YAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;QAChE,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAA;IACjC,CAAC;IAED,kEAAkE;IAC1D,mBAAmB,GAAgC,IAAI,GAAG,EAAE,CAAA;IAEpE;;;;;;;OAOG;IACK,yBAAyB,CAAC,MAAc;QAC9C,MAAM,EAAE,GAAS,IAAY,CAAC,WAAW,CAAA;QACzC,IAAI,CAAC,EAAE,EAAE,QAAQ;YAAE,OAAO,SAAS,CAAA;QAEnC,IAAI,GAAG,GAAG,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;QAC9C,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,GAAG,GAAG,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAA;YAC1B,GAAG,CAAC,IAAI,GAAG,oBAAoB,MAAM,EAAE,CAAA;YACvC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;YACpB,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;QAC3C,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI;YAAE,OAAO,SAAS,CAAA;QAE3B,MAAM,EAAE,GAAQ,IAAI,CAAC,KAAK,CAAA;QAC1B,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,SAAS,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI,CAAA;QACnC,MAAM,UAAU,GAAG,EAAE,EAAE,MAAM,IAAI,GAAG,CAAA;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC,CAAA;QACvD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,eAAe,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAC,CAAA;QAClF,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;QACvC,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAA;QACjC,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;QACtC,MAAM,MAAM,GAAG,WAAW,GAAG,GAAG,CAAA,CAAI,mDAAmD;QACvF,MAAM,QAAQ,GAAG,UAAU,CAAA;QAE3B,4EAA4E;QAC5E,sEAAsE;QACtE,6EAA6E;QAC7E,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;QAC7D,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,MAAM,GAAG,CAAC,CAAA;QAC3D,MAAM,CAAC,GAAG,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,UAAU,GAAG,CAAC,CAAA;QAC9D,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;QACzB,GAAG,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAA;QAC3B,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,4EAA4E;IAE5E;;;;OAIG;IACH,MAAM,CAAC,GAA6B;QAClC,MAAM,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAA;QAC7C,MAAM,GAAG,GAAI,IAAI,CAAC,KAAK,CAAC,GAAc,IAAI,CAAC,CAAA;QAC3C,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,GAAG,CAAA;QACjD,MAAM,MAAM,GAAI,IAAI,CAAC,KAAK,CAAC,MAAiB,IAAI,GAAG,CAAA;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QACtE,MAAM,IAAI,GAAI,IAAI,CAAC,KAAK,CAAC,SAAoB,IAAI,SAAS,CAAA;QAC1D,MAAM,MAAM,GAAI,IAAI,CAAC,KAAK,CAAC,WAAsB,IAAI,MAAM,CAAA;QAC3D,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,SAAoB,IAAI,CAAC,CAAA;QAEvD,aAAa;QACb,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,SAAS,GAAG,IAAI,CAAA;QACpB,GAAG,CAAC,WAAW,GAAG,GAAG,CAAA;QACrB,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QACtC,GAAG,CAAC,OAAO,EAAE,CAAA;QAEb,oCAAoC;QACpC,GAAG,CAAC,WAAW,GAAG,MAAM,CAAA;QACxB,GAAG,CAAC,SAAS,GAAG,SAAS,CAAA;QACzB,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QACxC,GAAG,CAAC,SAAS,EAAE,CAAA;QACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAA;YACnC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;YAClB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,CAAA;QAC7B,CAAC;QACD,GAAG,CAAC,MAAM,EAAE,CAAA;IACd,CAAC;IAED,IAAI,SAAS;QACX,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,sEAAsE;IAEtE,YAAY;QACV,CAAC;QAAC,IAAI,CAAC,WAAmB,EAAE,gBAAgB,EAAE,EAAE,CAAA;IAClD,CAAC;IAED,iFAAiF;IAEjF,2EAA2E;IAC3E,EAAE;IACF,sDAAsD;IACtD,sCAAsC;IACtC,wDAAwD;IACxD,EAAE;IACF,kBAAkB;IAClB,yEAAyE;IACzE,EAAE;IACF,MAAM;IACN,8FAA8F;IAC9F,wEAAwE;IACxE,kGAAkG;IAClG,mDAAmD;IAEnD;;;;OAIG;IACH,IAAI,QAAQ;QACV,OAAO;YACL,QAAQ,EAAE;gBACR,QAAQ,EAAE;oBACR,KAAK,EAAE,IAAI,CAAC,YAAY;iBACzB;aACF;SACF,CAAA;IACH,CAAC;IAEO,YAAY,GAAG,CAAC,UAAsB,EAAE,EAAE;QAChD,0DAA0D;QAC1D,IAAI,CAAE,IAAY,CAAC,GAAG,EAAE,UAAU;YAAE,OAAM;QAE1C,MAAM,EAAE,GAAS,IAAY,CAAC,WAAW,CAAA;QACzC,IAAI,CAAC,EAAE,EAAE,QAAQ;YAAE,OAAM;QAEzB,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,CAAA;QAC5C,IAAI,CAAC,GAAG;YAAE,OAAM;QAEhB,MAAM,SAAS,GAAoC,EAAE,CAAC,SAAS,CAAA;QAC/D,IAAI,MAA0B,CAAA;QAC9B,IAAI,MAAW,CAAA;QACf,IAAI,OAAO,GAAG,KAAK,CAAA;QACnB,IAAI,UAA8B,CAAA;QAElC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,wDAAwD;YACxD,MAAM,OAAO,GAAuB,SAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAA;YACxE,MAAM,GAAG,OAAO,EAAE,CAAC,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAA;YACxC,MAAM,GAAG,MAAM,EAAE,MAAM,CAAA;YACvB,OAAO,GAAG,IAAI,CAAA;YACd,UAAU,GAAG,GAAG,CAAC,UAAU,CAAA;QAC7B,CAAC;aAAM,CAAC;YACN,4DAA4D;YAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;YACjD,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC;gBAAE,OAAM;YACnD,MAAM,GAAG,GAAG,CAAA;YACZ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAA8B,CAAA;YACtD,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9E,CAAC;QAED,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,CAAA;QAC5E,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC,CAAA;QAExC,yEAAyE;QACzE,IAAI,MAAM;YAAE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IAC7D,CAAC,CAAA;IAED,yEAAyE;IAEzE;;;;;;;;;;;OAWG;IACK,eAAe,CAAC,UAAsB;QAC5C,MAAM,EAAE,GAAS,IAAY,CAAC,WAAW,CAAA;QACzC,IAAI,CAAC,EAAE,EAAE,QAAQ;YAAE,OAAO,SAAS,CAAA;QAEnC,MAAM,EAAE,GAAQ,EAAE,CAAC,cAAc,CAAA;QACjC,IAAI,CAAC,EAAE;YAAE,OAAO,SAAS,CAAA;QAEzB,MAAM,GAAG,GAAQ,EAAE,CAAC,gBAAgB,IAAI,EAAE,CAAC,WAAW,CAAA;QACtD,IAAI,UAA4C,CAAA;QAChD,IAAI,GAAG,EAAE,mBAAmB,EAAE,CAAC;YAC7B,UAAU,GAAG,GAAG,CAAC,mBAAmB,EAAsC,CAAA;QAC5E,CAAC;QAED,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,MAAM,KAAK,GAAG,EAAE,CAAC,OAAkC,CAAA;YACnD,MAAM,QAAQ,GAAG,EAAE,CAAC,UAA6C,CAAA;YACjE,MAAM,MAAM,GACT,EAAE,CAAC,cAA2C;gBAC9C,GAAG,EAAE,YAAyC;gBAC9C,GAAG,EAAE,MAAmC,CAAA;YAC3C,MAAM,MAAM,GAAG,QAAQ,EAAE,UAAU,CAAA;YACnC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM;gBAAE,OAAO,SAAS,CAAA;YAClD,MAAM,IAAI,GAAG,MAAM,CAAC,qBAAqB,EAAE,CAAA;YAC3C,IAAI,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAA;YAC3D,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,OAAO,CAC3B,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EACvD,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CACzD,CAAA;YACD,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,SAAS,EAAE,CAAA;YACvC,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;YACpC,UAAU,GAAG,SAAS,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAA;QAC/D,CAAC;QAED,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QAE5D,+EAA+E;QAC/E,sEAAsE;QACtE,0BAA0B;QAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;QAC7B,IAAI,GAAG,GAA0B,OAAO,CAAC,MAAM,CAAA;QAC/C,OAAO,GAAG,EAAE,CAAC;YACX,IAAI,GAAG,CAAC,QAAQ,EAAE,OAAO,KAAK,EAAE;gBAAE,OAAO,OAAO,CAAA;YAChD,GAAG,GAAG,GAAG,CAAC,MAAM,CAAA;QAClB,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IAED;;;;;;;;OAQG;IACK,qBAAqB,CAAC,UAAyB;QACrD,MAAM,EAAE,GAAS,IAAY,CAAC,WAAW,CAAA;QACzC,IAAI,CAAC,EAAE,EAAE,QAAQ;YAAE,OAAO,IAAI,CAAA;QAE9B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAClD,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,CAAA;QACvE,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,CAAA;QAExB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,MAAiB,IAAI,CAAC,CAAC,CAAC,CAAA;QAC1E,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,IAAI,CAAA;QAClD,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,IAAI,CAAA;QAClD,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,eAA0B,IAAI,CAAC,CAAA;QAC7D,MAAM,SAAS,GAAG,KAAK,GAAG,SAAS,CAAA;QAEnC,MAAM,QAAQ,GAAG,KAAK,GAAG,IAAI,CAAA;QAC7B,MAAM,WAAW,GAAG,SAAS,GAAG,MAAM,CAAA;QAEtC,iFAAiF;QACjF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAA;QAC3D,MAAM,WAAW,GAAG,KAAK,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,SAAS,CAAA;QACnD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,GAAG,WAAW,CAAC,CAAA;QACtD,MAAM,MAAM,GAAG,CAAC,CAAA,CAAG,wBAAwB;QAE3C,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,IAAI,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,IAAI,MAAM,EAAE,CAAC;YACvE,OAAO,qBAAqB,MAAM,WAAW,QAAQ,GAAG,CAAA;QAC1D,CAAC;QACD,OAAO,GAAG,MAAM,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAA;IAC1C,CAAC;IAED;;;;;;;;;;;;;OAaG;IACH,yBAAyB,CACvB,MAAc,EACd,QAA8C;QAE9C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAC/B,MAAM,CAAC,GAAQ,IAAI,CAAC,KAAK,CAAA;QACzB,MAAM,IAAI,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,CAAA;QACzB,MAAM,GAAG,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAA;QACvB,MAAM,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,CAAA;QAE3B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,+BAA+B;YAC/B,OAAO,EAAE,CAAC,EAAE,IAAI,GAAG,KAAK,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,GAAG,EAAE,CAAA;QACvE,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QAE7D,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAA;QAEjD,kEAAkE;QAClE,+DAA+D;QAC/D,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,GAAG,GAAG,CAAA;QAEtC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,EAAE,CAAA;IAC7C,CAAC;IAED,4EAA4E;IAE5E,eAAe;QACb,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;;AAz1BkB,IAAI;IADxB,cAAc,CAAC,cAAc,CAAC;GACV,IAAI,CA01BxB;eA11BoB,IAAI","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport { Component, ComponentNature, ContainerAbstract, Holdable, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport * as THREE from 'three'\nimport {\n CellContainer,\n CellMap,\n CarrierHolder,\n Placeable,\n RecordStorage,\n SlotTarget,\n componentBoundingBox,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype,\n type SlotRecord,\n type SlottedHolder\n} from '@operato/scene-base'\n\nimport { StorageRack3D } from './storage-rack-3d.js'\nimport { rackAcceptsMoverTool } from './rack-capability.js'\n\n/** Rack 컴포넌트 state */\nexport interface StorageRackState extends State {\n // ── 토폴로지 ──\n bays?: number\n levels?: number\n\n /**\n * Level 1 (첫 shelf) 의 *시작 높이* (mm, rack 의 3D Y 축, 바닥부터). 미명시 0\n * (바닥 = 첫 shelf). 양수 시 그만큼 위로 올라가 stocker port / conveyor 같은\n * 컴포넌트가 들어갈 *빈 공간* 확보. Frame uprights 는 바닥 ~ 천장 그대로.\n */\n shelfBaseHeight?: number\n\n /**\n * 적재 시각화 데이터. 배열의 각 record 는 최소 `cellId` 필드가 필요. cellMap 에\n * 존재하는 cellId 만 InstancedMesh 의 instance 로 렌더링됨 (한 박스 = 한 cell).\n * Plan A: 이 record 들이 *\"매트릭스 안\"* 의 carrier — obtainCarrier 가 materialize\n * 시 record 빠짐, receiveAt 시 record push. pickAndPlace 와 양방향 atomic sync.\n */\n data?: Array<{ cellId: string; [key: string]: any }>\n\n /**\n * RackCell 컴포넌트의 eager 생성 여부.\n * - `undefined` (default): state.data 있으면 false (batched, 메모리 절약),\n * 없으면 true (legacy non-batched, RackCell-based Mover 호환).\n * - `true`: 명시적 eager — 모든 cell 을 RackCell 로 생성.\n * - `false`: 명시적 skip — Plan A 의 slot API 만 사용 (obtainCarrier / slotTargetAt).\n */\n eagerCells?: boolean\n\n /**\n * Legend 컴포넌트의 id. legend 의 `state.status = {field, ranges:[{value|min,max, color}], defaultColor}`\n * 를 사용해 각 record 의 `field` 값을 색상으로 매핑. 미명시 시 scene-wide auto-discovery\n * (type='legend' 인 첫 번째 컴포넌트).\n */\n legendTarget?: string\n\n /**\n * Cell 클릭 시 invoke 할 things-scene `Popup` 컴포넌트의 id. Popup 컴포넌트는 scene\n * 어딘가에 일반 컴포넌트로 배치되어 있고, 그 자체의 state (board / modal / closable /\n * draggable / tether / billboard 등) 가 popup 동작을 정의. rack 은 *anchor 만 동적으로*\n * override 해 호출 — 클릭된 cell 위에 popup 이 뜸.\n *\n * 미명시 시 popup 비활성 (rack-cell-click 이벤트는 여전히 발사 — 외부 consumer 가\n * 직접 처리 가능).\n */\n popupRef?: string\n\n /** 가로 frame (beam) 만 숨김 — uprights 는 유지. */\n hideHorizontalFrame?: boolean\n\n // ── 디버그 ──\n debugCells?: boolean\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'number',\n label: 'levels',\n name: 'levels',\n placeholder: '# of vertical levels (default 4)'\n },\n {\n type: 'number',\n label: 'bays',\n name: 'bays',\n placeholder: '# of horizontal bays (default 5)'\n },\n {\n type: 'number',\n label: 'shelf-base-height',\n name: 'shelfBaseHeight',\n placeholder: 'mm — level 1 시작 높이 (바닥부터). stocker port / conveyor 공간.'\n },\n {\n type: 'id-input',\n label: 'legend-target',\n name: 'legendTarget',\n property: { component: 'legend' },\n placeholder: '미명시 시 scene 의 legend 자동 발견'\n },\n {\n type: 'id-input',\n label: 'popup-ref',\n name: 'popupRef',\n property: { component: 'popup' },\n placeholder: 'click 시 invoke 할 Popup 컴포넌트 id (anchor 는 클릭된 cell 로 override)'\n },\n {\n type: 'checkbox',\n label: 'hide-horizontal-frame',\n name: 'hideHorizontalFrame'\n }\n ],\n help: 'scene/component/rack'\n}\n\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Rack lives only in the 3D scene graph.\n//\n// Mixin chain: CellContainer → CarrierHolder → Placeable → ContainerAbstract\n// CellContainer: cell topology (cellMap, cell(), findAvailableCell(), occupiedCellIds())\n// CarrierHolder: 3D attach-point protocol (attachPointFor, containable gates)\n// Placeable: floor-archetype positioning\n// ContainerAbstract: child component management\n\n// Transient carrier refid generator — load 시 root._addTraverse 가 자식 부터 처리\n// 하면서 cell.model.refid 가 비어있으면 root.getNewRefid() = 1,2,3... 작은 값 부여\n// → *부모 Rack + 모델 안 다른 컴포넌트* refid 와 충돌 (\"Refid Index replaced\" 경고).\n// transient materialize 시 *큰 시작값 + monotonic counter* 로 자체 부여 → 충돌 0.\n// hierarchy override / state.data 만 저장 → 모델 파일엔 refid 안 새겨짐.\nlet _carrierRefidCounter = 200_000_000\nfunction _nextCarrierRefid(): number {\n return _carrierRefidCounter++\n}\n/**\n * Rack — a multi-level storage shelf system. A *Storage* whose role is to hold\n * carriers in a (bay × level) grid of cells.\n *\n * `levels` × `bays` cells form a vertical grid. Each cell holds one logistics\n * package (Pallet / Box / Parcel). A picker (Crane / Forklift / robot arm)\n * accesses individual cells via the Plan A slot API — the picker interacts\n * with `SlotTarget` (no explicit cell-component required).\n *\n * **Plan A**: carriers are direct children of the rack, addressed by\n * `state.cellId`. Stock visualization uses InstancedMesh (batched). Slot\n * lookup / pick / place via `obtainCarrier` / `receiveAt` / `slotTargetAt`.\n *\n * **Placement**: `floor` archetype, full ceiling depth by default.\n *\n * **Mobility**: this Rack is stationary. A `MobileRack = Mover(Rack)` mixin\n * extension can be added later for AGV-mounted or cart-mounted variants —\n * the cell topology and pickable contract stay the same.\n */\n@sceneComponent('storage-rack')\nexport default class Rack\n extends RecordStorage<{ cellId: string; [key: string]: any }>()(\n CellContainer(Holdable(CarrierHolder(Placeable(ContainerAbstract))))\n )\n implements SlottedHolder\n{\n declare state: StorageRackState\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (h: Heights) => h.ceiling - h.floor\n\n // ── RecordStorage mixin hook overrides ────────────────────────────────\n // record.cellId 가 slotId (mixin default 의 r.id 가 아닌 r.cellId).\n _recordToSlotId(record: { cellId: string }): string {\n return record.cellId ?? ''\n }\n // 3D rebuild 가 _realObject.rebuildStockMesh (mixin default 와 동일이지만 명시).\n _rebuildVisual(): void {\n ;(this._realObject as any)?.rebuildStockMesh?.()\n }\n\n // Phase Auto-Nav (AN-PR-2) — Obstacle 자격.\n get isObstacle(): boolean {\n return (this.state as any)?.isObstacle !== false\n }\n obstacleBoundingBox(): { left: number; top: number; width: number; height: number; y?: number; zHeight?: number } | null {\n // scene-base 의 componentBoundingBox 위임 — rotation 적용된 AABB.\n return componentBoundingBox(this)\n }\n\n /**\n * 이 rack 에 *_놓으려는 mover_* 의 능력을 수용하는가. canAccept(carrier) 는 carrier\n * 타입만 보지만, 이건 *_적재 mover 의 물리 능력_* 을 본다.\n *\n * rack 선반 적재는 *_높이 도달_* mover (crane / stacker / forklift) 의 몫이다.\n * 평탄 데크 차량(agv-deck)은 바닥 운반 전용 — 선반에 직접 못 올린다. 따라서\n * agv-deck 류는 거부 → transfer planner 가 자동으로 in-port 경유(환승)를 택한다.\n *\n * 거부 목록은 state.blockedTools 로 override (default ['agv-deck']). 향후 선반\n * 높이(level) vs mover liftHeight 비교로 정교화 가능.\n */\n canAcceptFromMover(mover: any): boolean {\n const toolType = mover?.toolType ?? mover?.state?.toolType\n const blocked = (this.state as any)?.blockedTools ?? ['agv-deck']\n return rackAcceptsMoverTool(toolType, blocked)\n }\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /**\n * Runtime — bays / levels 변경 시 anchor 캐시 무효화. cell 위치가 바뀌므로 다음\n * `_ensureSlotAttachObject3d` 호출이 새 좌표로 갱신.\n */\n onchange(after: Record<string, unknown>, _before: Record<string, unknown>): void {\n super.onchange?.(after, _before)\n if (\n 'bays' in after ||\n 'levels' in after ||\n 'shelfBaseHeight' in after ||\n 'width' in after ||\n 'height' in after ||\n 'depth' in after\n ) {\n this._attachAnchorBySlot.clear()\n }\n if ('hideHorizontalFrame' in after) {\n ;(this._realObject as any)?.applyFrameVisibility?.()\n }\n }\n\n // ── CellContainer ─────────────────────────────────────────────────────────\n\n /**\n * Derive the cell topology from the rack's current dimensions and bay/level\n * counts. The CellMap is rebuilt fresh each time (state changes trigger\n * re-reads via things-scene's invalidation pipeline).\n *\n * Coordinate convention (matches things-scene 3D):\n * X = bay axis (left → right)\n * Y = level axis (floor → ceiling, the rack's `depth` state property)\n * Z = row axis (front → back, the rack's `height` state property)\n */\n get cellMap(): CellMap {\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const levels = Math.max(1, Math.floor((this.state.levels as number) || 4))\n const width = (this.state.width as number) || 1000\n const rackDepth = (this.state.depth as number) || 3000 // Y: floor→ceiling\n const rackHeight = (this.state.height as number) || 600 // Z: front→back\n const shelfBase = Math.max(0, Math.min(\n (this.state.shelfBaseHeight as number) || 0,\n rackDepth * 0.9 // clamp ≤ 90% — 최소 shelf zone\n ))\n const shelfZone = rackDepth - shelfBase // 실제 shelf 가 차지하는 Y 영역\n\n return CellMap.grid({\n bays,\n rows: 1,\n levels,\n bayWidth: width / bays,\n rowDepth: rackHeight,\n levelHeight: shelfZone / levels,\n origin: { x: 0, y: shelfBase, z: 0 } // 첫 cell 의 Y = shelfBase\n })\n }\n\n // ── Container gates ───────────────────────────────────────────────────────\n\n /**\n * Allow:\n * - Carriable components (pallets, boxes, parcels) — direct children, operation archetype.\n *\n * Block:\n * - Everything else (sensors, labels, etc. can be siblings of the rack, not children).\n */\n containable(component: Component): boolean {\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this)\n }\n\n // ── CarrierHolder — attach frame for direct carrier children ─────────────\n\n /**\n * Attach frame for direct-child carriers — Plan A 의 모든 carrier 가 rack 의\n * 직접 자식이므로 매번 호출됨. carrier 의 state.cellId 에 해당하는 *cell-local\n * anchor object3d* 를 반환 → carrier 의 object3d 가 자동으로 셀 위치에 정렬됨.\n */\n attachPointFor(carrier: Component): AttachFrame | null {\n // Plan A: rack 의 직접 자식 carrier 는 *state.cellId* 로 슬롯 위치를 표시 (매트릭스\n // 내 주소). attachPointFor 는 그 cellId 의 *셀-로컬 anchor object3d* 를 반환 →\n // carrier 의 object3d 가 자동으로 셀 위치에 정렬됨.\n //\n // localPosition: {0,0,0} 명시 — Carriable.applyHolderAttachPoint 가 Three.js\n // attach() 후 *world pose 보존* 만 하고 local 을 reset 하지 않는 결함 우회.\n // 명시 시 (Carriable + CarrierHolder.reparent 모두) 그대로 anchor origin 에 snap.\n const cellId = (carrier as any)?.state?.cellId as string | undefined\n if (cellId) {\n const obj = this._ensureSlotAttachObject3d(cellId)\n if (obj) return { attach: obj, localPosition: { x: 0, y: 0, z: 0 } }\n }\n // Fallback — cellId 없는 (legacy) 호출 시 rack root.\n const root = this._realObject?.object3d\n if (!root) return null\n return { attach: root, localPosition: { x: 0, y: 0, z: 0 } }\n }\n\n // ── Plan A — Slot API (LoopSorter-style; \"rack 안 = 데이터, 밖 = 컴포넌트\") ───\n //\n // Conceptual model:\n // - rack 안의 carrier 는 *state.data 의 한 record* (데이터)\n // - rack 밖의 carrier 는 *Component* (실재)\n // - 경계 통과 시 transient materialize / atomic absorb\n //\n // 불변식: 동일 cellId 가 state.data 의 record 와 rack-child carrier 양쪽에 동시\n // 존재하지 않음. obtainCarrier 와 receiveAt 가 atomic 하게 전환.\n //\n // 호출 흐름:\n // - Pick: const c = rack.obtainCarrier('A-0-0') → c 는 rack child, record 빠짐\n // await crane.pick(c) → c.parent = crane (rack child 에서도 빠짐)\n // - Place: await crane.place(c, destRack.slotTargetAt('B-0-0'))\n // SlotTarget.receive → destRack.receiveAt → c dispose + record push\n\n // `records` getter — RecordStorage mixin 제공.\n\n /**\n * 1-based (bay, row, level) → 0-based cellId 문자열.\n *\n * rack.slotIdOf(1, 1, 6) → '0-0-5'\n * rack.slotIdOf(3, 1, 4) → '2-0-3'\n */\n slotIdOf(bay: number, row: number = 1, level: number = 1): string {\n return `${bay - 1}-${row - 1}-${level - 1}`\n }\n\n /**\n * 모든 slot id 의 목록 (Plan A 의 *cell* = slot 통일). bays × rows × levels 전 조합.\n * storage-rack 의 rows 는 항상 1 (단일 row) 이므로 실제론 bays × levels.\n *\n * SlottedHolder.slotIds — capability 기반 enumeration entry point.\n */\n slotIds(): ReadonlyArray<string> {\n const bays = Math.max(1, Math.floor((this.state as any)?.bays ?? 5))\n const levels = Math.max(1, Math.floor((this.state as any)?.levels ?? 4))\n const ids: string[] = []\n for (let bay = 1; bay <= bays; bay++) {\n for (let level = 1; level <= levels; level++) {\n ids.push(this.slotIdOf(bay, 1, level))\n }\n }\n return ids\n }\n\n /**\n * 점유된 slot 의 id 목록 — state.data record + *carrier* children 둘 다.\n * RackCell (시각 proxy) 같은 *carrier 아닌 자식* 은 제외 (isCarriable 검사).\n *\n * @param filter predicate — 통과하는 slotId 만. sweep 중 즉시 reject.\n */\n occupiedSlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n const set = new Set<string>()\n for (const r of this.records) {\n const cid = r?.cellId\n if (typeof cid === 'string' && (!filter || filter(cid))) set.add(cid)\n }\n for (const c of (this as any).components ?? []) {\n if (!(c as any)?.isCarriable) continue\n const cid = (c as any)?.state?.cellId\n if (typeof cid === 'string' && (!filter || filter(cid))) set.add(cid)\n }\n return Array.from(set)\n }\n\n /** 비어있는 slot 의 id 목록 — slotIds() - occupiedSlotIds(). filter 도 동일. */\n emptySlotIds(filter?: (slotId: string) => boolean): ReadonlyArray<string> {\n const occ = new Set(this.occupiedSlotIds())\n const result: string[] = []\n for (const id of this.slotIds()) {\n if (occ.has(id)) continue\n if (filter && !filter(id)) continue\n result.push(id)\n }\n return result\n }\n\n /**\n * slot 의 *world position* — anchor object3d *생성 없이* 직접 계산. crane 의\n * reach 검사 등 *match 전 단계* 에서 *anchor 생성 0* 으로 사용.\n */\n slotWorldPosition(cellId: string): { x: number; y: number; z: number } | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return undefined\n\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackDepth = rs?.depth || 3000\n const rackHeight = rs?.height || 600\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, rackDepth * 0.9))\n const shelfZone = rackDepth - shelfBase\n const bayWidth = rackWidth / bays\n const levelHeight = shelfZone / levels\n const stockD = levelHeight * 0.7\n const rowDepth = rackHeight\n\n const x = cell.localPosition.x + bayWidth / 2 - rackWidth / 2\n const y = cell.localPosition.y - rackDepth / 2 + stockD / 2\n const z = cell.localPosition.z + rowDepth / 2 - rackHeight / 2\n\n const v = new THREE.Vector3(x, y, z)\n ro.object3d.localToWorld(v)\n return { x: v.x, y: v.y, z: v.z }\n }\n\n /** cellId 에 carrier 가 있는가 — child carrier 또는 state.data record 어느 쪽이든. */\n hasCarrierAt(cellId: string): boolean {\n if (this._carrierChildAt(cellId)) return true\n return this.records.some((r: any) => r.cellId === cellId)\n }\n\n /** cellId 매칭되는 rack 의 직접 자식 carrier (operation archetype). */\n private _carrierChildAt(cellId: string): Component | undefined {\n const children = (this.components as Component[] | undefined) ?? []\n return children.find(c => {\n const placement = (c.constructor as any).placement\n return placement === 'operation' && (c.state as any)?.cellId === cellId\n })\n }\n\n /**\n * carrier 를 obtain — 이미 child 면 그대로, 아니면 state.data record 로 transient\n * materialize 후 rack 의 직접 자식으로 add 하고 state.data 에서 그 record 제거.\n * record 도 child 도 없으면 null.\n *\n * Signature overloads:\n * obtainCarrier('0-0-5') — string cellId 직접\n * obtainCarrier(1, 1, 6) — 1-based (bay, row, level)\n * obtainCarrier(1) ≡ obtainCarrier(1,1,1)\n */\n obtainCarrier(idOrBay: string | number, row?: number, level?: number): Component | null {\n const cellId = typeof idOrBay === 'string'\n ? idOrBay\n : this.slotIdOf(idOrBay, row ?? 1, level ?? 1)\n const existing = this._carrierChildAt(cellId)\n if (existing) return existing\n\n const records = this.records as Array<any>\n const idx = records.findIndex(r => r?.cellId === cellId)\n if (idx === -1) return null\n const record = records[idx]\n\n const carrierType = (record.type as string) || 'parcel'\n const CarrierClass = (Component as any).register(carrierType) as\n | (new (...args: any[]) => Component) | undefined\n if (!CarrierClass) {\n console.warn(`[storage-rack] obtainCarrier(\"${cellId}\"): carrier type \"${carrierType}\" 미등록`)\n return null\n }\n\n // 크기 기본값 — rack 기하에서 derive (record 가 명시 안 한 경우)\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackDepth = rs?.depth || 3000\n const rackHeight = rs?.height || 600\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, rackDepth * 0.9))\n const shelfZone = rackDepth - shelfBase\n const bayWidth = rackWidth / bays\n const levelHeight = shelfZone / levels\n\n // record 에서 id / refid / transform 류는 *제외* — id 가 들어가면 scene 안 기존\n // component 와 충돌해 parent 가 잘못 잡힘 (model-layer 의 원본을 재사용 등).\n const { id: _id, refid: _refid, transform: _tf, ...recordCopy } = record as any\n const carrierW = record.width ?? bayWidth * 0.85\n const carrierH = record.height ?? rackHeight * 0.85\n // cell 의 *rack-inner 좌표* (= carrier 의 parent=rack 의 inner 좌표계 의 점).\n // carrier.center = carrier.state.left + carrierW/2 가 *rack-inner 좌표 의 cell center*\n // 이어야 Crane.moveTo (target.center → target.toScene) 가 정확한 layer 좌표로 변환.\n // 이전엔 left=0, top=0 → center=(carrierW/2, carrierH/2) = bay 0 의 좌상단 근처 → fork 어긋남.\n const cellInfo = this.cellMap?.findById(cellId)\n const bayIdx = (cellInfo?.bay ?? 1) - 1\n const cellCenterInnerX = bayIdx * bayWidth + bayWidth / 2\n const cellCenterInnerY = rackHeight / 2\n const carrierState: any = {\n ...recordCopy,\n type: carrierType,\n cellId, // 슬롯 주소\n refid: _nextCarrierRefid(), // refid 충돌 회피\n width: carrierW,\n height: carrierH,\n depth: record.depth ?? levelHeight * 0.7,\n left: cellCenterInnerX - carrierW / 2,\n top: cellCenterInnerY - carrierH / 2\n }\n\n const carrier = new CarrierClass(carrierState, (this as any)._app)\n // *silent: true* — Plan A 의 transient materialize 는 사용자가 직접 컴포넌트\n // 만든 게 아니라 *내부적으로 잠시 빌리는 것*. 새 컴포넌트 추가 → root.onadded\n // → refreshMappings (1s debounce) → 모든 컴포넌트 매핑 재실행 의 cascade 차단.\n // (silent 모드: _silentAdd 플래그 set → refreshMappings skip)\n ;(this as any).addHolding(carrier) // transient carrier → _holdings (§1.2)\n\n // 3D 강제 빌드 + attach (pipeline tick 없이도 즉시 표시 — Mover 가 곧 pick).\n void (carrier as any).realObject\n ;(carrier as any).applyHolderAttachPoint?.()\n\n // record 제거 — atomic: child 추가 직후. 동일 cellId 의 *모든* record 정리.\n // *silent* 갱신 — mapping cascade (onchangeData → executeMappings → script fire)\n // 회피. external (WMS push) 호출은 setState 거치므로 그쪽 mapping 은 정상 발사.\n this._setDataSilently(records.filter(r => r?.cellId !== cellId))\n\n return carrier\n }\n\n // _setDataSilently — RecordStorage mixin 제공 (_rebuildVisual hook 통해\n // rebuildStockMesh 호출). 동등 동작 + cachedState invalidate.\n\n /**\n * cell 이 carrier 를 받을 수 있는가.\n *\n * 규칙:\n * - state.data 에 record 가 있으면 점유 → false\n * - carrier-child 가 있고 *그 child 가 들여오려는 carrier 자기 자신이 아니면* → false\n * - 들여오려는 carrier 가 *바로 그 cell 의 child 자기 자신* 이면 → true (idempotent —\n * obtain('A') 직후 receive('A', sameCarrier) 가 *자기 자리 복귀* 로 동작)\n */\n canReceiveAt(cellId: string, carrier?: Component): boolean {\n const records = this.records as Array<any>\n if (records.some(r => r?.cellId === cellId)) return false\n const existingChild = this._carrierChildAt(cellId)\n if (existingChild && existingChild !== carrier) return false\n return true\n }\n\n /**\n * Carrier 가 rack 의 slot 으로 들어옴 — \"매트릭스 진입\": 즉시 dispose + state.data 에\n * record 로 환원. 결과: InstancedMesh 가 다시 그 자리에 instance 표시, rack 의 자식\n * 컴포넌트 트리는 깨끗.\n */\n async receiveAt(cellId: string, carrier: Component, _options?: any): Promise<void> {\n // R18 guard — disposed carrier 의 재처리 차단.\n if ((carrier as any)?._disposed) {\n throw new Error(\n `Rack.receiveAt(\"${cellId}\"): carrier is already disposed. ` +\n 'After a successful pickAndPlace the carrier becomes a state.data record — ' +\n 'use rack.obtainCarrier(cellId) to get a fresh transient carrier instead.'\n )\n }\n if (!this.canReceiveAt(cellId, carrier)) {\n ;(this as any).trigger?.('transfer-rejected', {\n type: 'transfer-rejected',\n component: carrier, container: this, reason: 'slot-occupied', cellId\n })\n return\n }\n\n const record = this.recordFromCarrier(carrier, cellId)\n\n // Carrier 의 parent 에서 떼고 dispose. parent 는 보통 mover (crane) 이거나 rack 자신.\n const carrierParent: any = (carrier as any).parent\n if (carrierParent && typeof carrierParent.removeComponent === 'function') {\n carrierParent.removeComponent(carrier)\n }\n\n // 명시적 Three.js detach — RealObject.dispose() 의 clear() 는 *object3d 의 children*\n // 만 정리하고 *object3d 자체* 는 scene graph 의 parent 에서 *떼지 않음*. 결과:\n // crane fork 또는 slot anchor 에 attach 됐던 object3d 가 빈 상태로 남아 ghost.\n // dispose 호출 *전* 에 명시적으로 parent.remove. (geometry/material dispose 는\n // RealObject.dispose() 의 clear() 에 위임 — 공유 material 정책 framework 책임.)\n const carrierObj3d: any = (carrier as any)._realObject?.object3d\n if (carrierObj3d?.parent && typeof carrierObj3d.parent.remove === 'function') {\n carrierObj3d.parent.remove(carrierObj3d)\n }\n\n ;(carrier as any).dispose?.()\n\n // state.data 에 push — *silent* 갱신 (mapping cascade 회피, 위 _setDataSilently 주석 참조).\n // 중복 방어: 동일 cellId 의 기존 record 가 있으면 제거 후 새 record 단일 추가.\n const currentRecords = (this.records as any[]).filter(r => r?.cellId !== cellId)\n this._setDataSilently([...currentRecords, record])\n\n ;(this as any).trigger?.('transfer-received', {\n type: 'transfer-received',\n component: carrier, container: this, slotId: cellId, record\n })\n }\n\n /**\n * Carrier 의 state 를 state.data record 로 추출. application 이 carrier subclass 별\n * 추가 필드 인코딩 원하면 override. transform/position 관련은 record 와 무관해 skip.\n */\n recordFromCarrier(carrier: Component, cellId: string): { cellId: string; [key: string]: any } {\n const state: any = (carrier as any).state ?? {}\n const SKIP_KEYS = new Set([\n 'left', 'top', 'zPos',\n 'transform', 'rotation', 'scale',\n '_transferSlotId',\n 'cellId', // 새로 override\n 'id', // 다음 materialize 시 충돌 방지 (id 는 component-instance 의 것, record 의 것 아님)\n 'refid'\n ])\n const record: any = { cellId, type: state.type }\n for (const key of Object.keys(state)) {\n if (SKIP_KEYS.has(key)) continue\n record[key] = state[key]\n }\n return record\n }\n\n /**\n * SlottedHolder 컨트랙 — slot 의 attach object3d 반환. SlotTarget 이 자기\n * `_realObject.object3d` proxy 로 사용하고, Carriable.applyHolderAttachPoint 도\n * 이걸 attach frame 으로 사용 (transit 중 carrier 가 slot 위치에 정렬).\n */\n getSlotAttachObject3d(cellId: string): THREE.Object3D | undefined {\n return this._ensureSlotAttachObject3d(cellId)\n }\n\n /**\n * SlottedHolder 컨트랙 — slot 의 *expected carrier* 의 3D 크기 (slot 자체의 기하 크기가\n * 아님). Crane 의 `resolveCarrierBottomY = centerY - depth/2` 에서 *carrier 가 놓일 때\n * 예상되는 carrier depth* 를 써야 fork 가 *carrier 바닥 = shelf* 에 정확히 진입.\n *\n * 즉:\n * depth = stockD (= levelHeight * 0.7) — *carrier 의 vertical extent*. 전체 셀 높이\n * (levelHeight) 가 아닌 *실제 stock 박스 깊이*. anchor 가 stock 시각 중심 (\n * shelf + stockD/2) 에 위치하므로 depth = stockD 여야 bottom 계산이 shelf.\n * width = bayWidth — 그대로\n * height = rowDepth — 그대로 (2D 의 Z 축 폭)\n */\n getSlotSize(cellId: string): { width: number; height: number; depth: number } | undefined {\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return undefined\n const stockD = cell.size.height * 0.7 // matches _ensureSlotAttachObject3d + storage-rack-3d.rebuildStockMesh\n return {\n width: cell.size.width,\n height: cell.size.depth, // 2D height = Z extent (front-back)\n depth: stockD // 3D depth = carrier Y extent (NOT full level)\n }\n }\n\n /**\n * SlottedHolder 컨트랙 — cellId 에 대한 SlotTarget. Mover.pickAndPlace 의 dest 로 넘김.\n *\n * Signature overloads:\n * slotTargetAt('0-0-5') — string cellId 직접\n * slotTargetAt(1, 1, 6) — 1-based (bay, row, level)\n */\n slotTargetAt(idOrBay: string | number, row?: number, level?: number): SlotTarget {\n const cellId = typeof idOrBay === 'string'\n ? idOrBay\n : this.slotIdOf(idOrBay, row ?? 1, level ?? 1)\n return new SlotTarget(this, cellId)\n }\n\n /**\n * SlotTarget 의 2D center 위임 — Mover.moveTo 의 2D path 계산에 사용.\n *\n * 반환값은 *rack 자체의 local frame* (rack 의 left/top 미포함) — 즉 cell 의 위치를\n * rack 의 *내부 좌표계로* 표현. SlotTarget.toScene 이 rack.toScene 을 위임해 *rack 의\n * rotation / 부모 chain 변환 포함* 한 절대 좌표로 변환.\n *\n * 이전 결함: rack.left/top 을 포함해 model-layer 프레임 좌표 반환 + toScene 미구현 →\n * rack 이 rotated 또는 nested 일 때 X 가 어긋났음.\n */\n cellCenter2D(cellId: string): { x: number; y: number } | null {\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return null\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackHeight = rs?.height || 100\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const bayWidth = rackWidth / bays\n const bayIdx = cell.bay - 1\n // things-scene 컨벤션: 컴포넌트의 `center` 는 *parent 좌표계 의 center*\n // (= bounds.left + width/2). 즉 *layer 좌표* — rack 의 left/top 포함, *rack 의\n // rotation 미적용*. toScene 가 rotation 처리. parcel.center 등 모든 실제\n // 컴포넌트가 이 컨벤션이므로 SlotTarget.center 도 동일해야 *pick 과 place 의\n // 좌표 변환 체인 일관성* 유지.\n return {\n x: (rs?.left ?? 0) + bayIdx * bayWidth + bayWidth / 2,\n y: (rs?.top ?? 0) + rackHeight / 2\n }\n }\n\n /**\n * SlotTarget 의 toScene 위임 — *rack-local* 좌표를 *scene-absolute* 로 변환.\n * rack.toScene 이 rack 의 rotation / translation / parent chain 모두 처리.\n */\n cellToScene(localX: number, localY: number): { x: number; y: number } {\n const f = (this as any).toScene\n if (typeof f === 'function') return f.call(this, localX, localY)\n return { x: localX, y: localY }\n }\n\n /** cellId 별 attach anchor object3d cache (rack.object3d 의 자식). */\n private _attachAnchorBySlot: Map<string, THREE.Object3D> = new Map()\n\n /**\n * cellId 위치에 lightweight anchor object3d 를 *singleton 으로* 보장 + 갱신.\n * 이 anchor 가:\n * - Carriable.applyHolderAttachPoint 가 attach 하는 frame\n * - SlotTarget._realObject.object3d 의 proxy\n * - 두 용도가 *같은 object3d* 를 공유해 carrier 가 transient 동안 SlotTarget 의\n * pose 와 정확히 동기화.\n */\n private _ensureSlotAttachObject3d(cellId: string): THREE.Object3D | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n\n let obj = this._attachAnchorBySlot.get(cellId)\n if (!obj) {\n obj = new THREE.Object3D()\n obj.name = `rack-slot-anchor:${cellId}`\n ro.object3d.add(obj)\n this._attachAnchorBySlot.set(cellId, obj)\n }\n\n const cell = this.cellMap?.findById(cellId)\n if (!cell) return undefined\n\n const rs: any = this.state\n const rackWidth = rs?.width || 1000\n const rackDepth = rs?.depth || 3000\n const rackHeight = rs?.height || 600\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const shelfBase = Math.max(0, Math.min(rs?.shelfBaseHeight || 0, rackDepth * 0.9))\n const shelfZone = rackDepth - shelfBase\n const bayWidth = rackWidth / bays\n const levelHeight = shelfZone / levels\n const stockD = levelHeight * 0.7 // ← storage-rack-3d.rebuildStockMesh 의 stockD 와 동일\n const rowDepth = rackHeight\n\n // Anchor Y = *stock 시각 중심* (shelf + stockD/2). InstancedMesh 의 stock 박스 중심과\n // 일치 → carrier (depth = stockD) 가 attach 시 정확히 stock 위치에 올라 앉음. Crane\n // 의 resolveCarrierBottomY = centerY - depth/2 = shelf 라 fork 가 정확히 shelf 진입.\n const x = cell.localPosition.x + bayWidth / 2 - rackWidth / 2\n const y = cell.localPosition.y - rackDepth / 2 + stockD / 2\n const z = cell.localPosition.z + rowDepth / 2 - rackHeight / 2\n obj.position.set(x, y, z)\n obj.updateMatrixWorld(true)\n return obj\n }\n\n // ── 2D rendering ─────────────────────────────────────────────────────────\n\n /**\n * 2D — top-down rectangle showing the rack footprint with bay subdivisions.\n * 편집/배치 가 가능하도록 *명시 fill + stroke* — pipeline 분기 무관하게 항상\n * 보임. fill 은 반투명 (carrier / cell 위 overlay).\n */\n render(ctx: CanvasRenderingContext2D) {\n const left = (this.state.left as number) ?? 0\n const top = (this.state.top as number) ?? 0\n const width = (this.state.width as number) ?? 400\n const height = (this.state.height as number) ?? 100\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const fill = (this.state.fillStyle as string) || '#a0a0a8'\n const stroke = (this.state.strokeStyle as string) || '#555'\n const lineWidth = (this.state.lineWidth as number) || 1\n\n // Fill (반투명)\n ctx.save()\n ctx.fillStyle = fill\n ctx.globalAlpha = 0.2\n ctx.fillRect(left, top, width, height)\n ctx.restore()\n\n // Stroke — outer + bay subdivisions\n ctx.strokeStyle = stroke\n ctx.lineWidth = lineWidth\n ctx.strokeRect(left, top, width, height)\n ctx.beginPath()\n for (let i = 1; i < bays; i++) {\n const x = left + (width * i) / bays\n ctx.moveTo(x, top)\n ctx.lineTo(x, top + height)\n }\n ctx.stroke()\n }\n\n get fillStyle() {\n return '#a0a0a8'\n }\n\n // ── Data binding — state.data 변경 시 InstancedMesh 재구성 ───────────────\n\n onchangeData(): void {\n ;(this._realObject as any)?.rebuildStockMesh?.()\n }\n\n // legendTarget / _onLegendChanged / resolveLegendColor — RecordStorage mixin 제공.\n\n // ── Click event — rack-cell-click 발사 ────────────────────────────────────\n //\n // 사용자가 *어떤 셀*을 클릭하든 (stock 가시화된 셀이든, 빈 셀이든) rack 이 다음\n // payload 로 `rack-cell-click` 을 emit:\n // { cellId, record?, hitPoint, instanceId?, isStock }\n //\n // 외부 consumer 등록:\n // rack.on('rack-cell-click', ({ cellId, record, isStock }) => { ... })\n //\n // 분기:\n // - InstancedMesh (stock) hit → cellId/record 는 records[instanceId] 에서 직접 추출, isStock=true\n // - 그 외 rack mesh (shelf/frame) hit → hit.point 를 rack-local 좌표로 변환 후\n // (bay, level) 역산, record 는 state.data 검색, isStock=false\n // edit mode 클릭은 framework 의 선택 로직 우선이라 emit 하지 않음.\n\n /**\n * things-scene EventManager3D 가 raycast → object3d.userData.context.component 의\n * `trigger(\"click\", mouseEvent)` 을 호출 → eventMap 으로 receive.\n * `(self).(self).click` 으로 등록해 *우리 rack 의 어떤 mesh 든 클릭됐을 때* 발사.\n */\n get eventMap() {\n return {\n '(self)': {\n '(self)': {\n click: this._onRackClick\n }\n }\n }\n }\n\n private _onRackClick = (mouseEvent: MouseEvent) => {\n // view mode 에서만 동작 (modeling 중 클릭은 framework 의 선택 로직 우선).\n if (!(this as any).app?.isViewMode) return\n\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return\n\n const hit = this._raycastRackHit(mouseEvent)\n if (!hit) return\n\n const stockMesh: THREE.InstancedMesh | undefined = ro.stockMesh\n let cellId: string | undefined\n let record: any\n let isStock = false\n let instanceId: number | undefined\n\n if (hit.object === stockMesh) {\n // (A) Stock instance 직접 hit — records 에서 정확한 record 추출.\n const records: any[] | undefined = (stockMesh as any).userData?._records\n record = records?.[hit.instanceId ?? -1]\n cellId = record?.cellId\n isStock = true\n instanceId = hit.instanceId\n } else {\n // (B) 빈 cell / shelf / frame hit — world point → cellId 역산.\n const cid = this._cellIdFromWorldPoint(hit.point)\n if (!cid || cid.startsWith('out-of-bounds')) return\n cellId = cid\n const data = this.state.data as Array<any> | undefined\n record = Array.isArray(data) ? data.find(r => r?.cellId === cid) : undefined\n }\n\n const payload = { cellId, record, hitPoint: hit.point, instanceId, isStock }\n this.trigger('rack-cell-click', payload)\n\n // Popup 호출 — 일반 mechanism (Popup 컴포넌트) 활용, anchor 만 클릭된 cell 로 override.\n if (cellId) this._invokePopup(cellId, record ?? { cellId })\n }\n\n // _invokePopup — RecordStorage mixin 제공 (cellId=slotId, record=payload).\n\n /**\n * 클릭 시 framework 의 mouse NDC (이미 InteractionManager 가 set 한 상태) 를 재사용해\n * raycast → *우리 rack* 의 어떤 mesh 가 closest hit 인지 반환. 다른 object 가 더 가까우면\n * undefined (다른 rack 또는 무관 mesh 의 hit).\n *\n * 접근 경로:\n * 1. ThreeCapability — ModelLayer 는 `_threeCapability`, ThreeContainer 는 `_capability`.\n * capability 의 `getObjectsByRaycast()` 가 *동일한* mouse NDC 로 framework 가 click\n * 처리 직전에 쓴 그 raycaster 를 재사용 (가장 정확).\n * 2. capability 가 없는 컨테이너 — public scene3d / renderer3d / camera + mouseEvent\n * 좌표로 자체 ndc 변환 후 fresh raycaster.\n */\n private _raycastRackHit(mouseEvent: MouseEvent): THREE.Intersection | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n\n const tc: any = ro.threeContainer\n if (!tc) return undefined\n\n const cap: any = tc._threeCapability ?? tc._capability\n let intersects: THREE.Intersection[] | undefined\n if (cap?.getObjectsByRaycast) {\n intersects = cap.getObjectsByRaycast() as THREE.Intersection[] | undefined\n }\n\n if (!intersects || intersects.length === 0) {\n const scene = tc.scene3d as THREE.Scene | undefined\n const renderer = tc.renderer3d as THREE.WebGLRenderer | undefined\n const camera =\n (tc.activeCamera3d as THREE.Camera | undefined) ??\n (cap?.activeCamera as THREE.Camera | undefined) ??\n (cap?.camera as THREE.Camera | undefined)\n const canvas = renderer?.domElement\n if (!scene || !canvas || !camera) return undefined\n const rect = canvas.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return undefined\n const ndc = new THREE.Vector2(\n ((mouseEvent.clientX - rect.left) / rect.width) * 2 - 1,\n -((mouseEvent.clientY - rect.top) / rect.height) * 2 + 1\n )\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(ndc, camera)\n intersects = raycaster.intersectObjects(scene.children, true)\n }\n\n if (!intersects || intersects.length === 0) return undefined\n\n // Three.js intersectObjects 는 distance 오름차순 정렬. 첫 hit 이 *우리 rack* 의 descendant\n // 인지 확인 (userData.context walk-up 으로). 다른 object 가 더 가까우면 (다른 rack 또는\n // 무관 mesh 가 사이에 있음) — 무시.\n const closest = intersects[0]\n let obj: THREE.Object3D | null = closest.object\n while (obj) {\n if (obj.userData?.context === ro) return closest\n obj = obj.parent\n }\n return undefined\n }\n\n /**\n * world point → cellId 역산.\n *\n * 1. rack 의 `matrixWorld.invert()` 로 world → rack-local 변환 (rack 의 회전·이동\n * 반영)\n * 2. rack-local point 의 `(x, y)` 를 (bay, level) 격자에 매핑\n *\n * 범위 밖이면 `\"out-of-bounds(...)\"` 문자열 반환 (caller 가 무시).\n */\n private _cellIdFromWorldPoint(worldPoint: THREE.Vector3): string | null {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return null\n\n const local = new THREE.Vector3().copy(worldPoint)\n const mInv = new THREE.Matrix4().copy(ro.object3d.matrixWorld).invert()\n local.applyMatrix4(mInv)\n\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const levels = Math.max(1, Math.floor((this.state.levels as number) || 4))\n const width = (this.state.width as number) || 1000\n const depth = (this.state.depth as number) || 3000\n const shelfBase = (this.state.shelfBaseHeight as number) || 0\n const shelfZone = depth - shelfBase\n\n const bayWidth = width / bays\n const levelHeight = shelfZone / levels\n\n // rack 의 3D origin = rack center. X: [-width/2,+width/2], Y: [-depth/2,+depth/2]\n const bayIdx = Math.floor((local.x + width / 2) / bayWidth)\n const yFromBottom = local.y + depth / 2 - shelfBase\n const levelIdx = Math.floor(yFromBottom / levelHeight)\n const rowIdx = 0 // storage-rack 은 rows=1\n\n if (bayIdx < 0 || bayIdx >= bays || levelIdx < 0 || levelIdx >= levels) {\n return `out-of-bounds(bay=${bayIdx}, level=${levelIdx})`\n }\n return `${bayIdx}-${rowIdx}-${levelIdx}`\n }\n\n /**\n * Cell-precise approach point — mover 가 *_cell 정면 외부 stand-off_* 까지만.\n *\n * cellId format: `${bay - 1}-${row - 1}-${level - 1}` (0-based).\n *\n * **사용자 의도**: rack 은 *_전면_* 만 포크질 가능. front face = state.top 쪽\n * (작은 z, 3D 의 -Z forward). back face 사용 금지 — forklift 가 rack 후면에\n * 정차하는 동작은 잘못. navigation 의 obstacle avoidance 가 rack 우회 path 계산.\n *\n * forkLen — fork blade tip 부터 mover center 까지 거리. mover 가 그 거리만큼\n * cell face 앞에서 정차 → 정확히 fork blade 가 cell face 정렬.\n *\n * (rotation 지원 V11 — 현재 axis-aligned rack 만, facing default = top.)\n */\n slotApproachWorldPosition(\n slotId: string,\n _fromPos?: { x: number; y: number; z: number }\n ): { x: number; y: number; z: number } {\n const parts = slotId.split('-')\n const s: any = this.state\n const left = s?.left ?? 0\n const top = s?.top ?? 0\n const width = s?.width ?? 0\n\n if (parts.length !== 3) {\n // fallback — front face center\n return { x: left + width / 2, y: 0, z: top - (s.depth ?? 100) * 0.5 }\n }\n const col = Number(parts[0])\n const bays = Math.max(1, Math.floor((s.bays as number) ?? 5))\n\n const cellX = left + (col + 0.5) * (width / bays)\n\n // fork 진입 거리 — rack.depth 의 절반 (mover 정차 점이 fork blade 가 cell 정면에\n // 정렬되는 거리). _fromPos 무시 — *_항상 front face_* (사용자 의도: 전면만 포크질).\n const forkLen = (s.depth ?? 100) * 0.5\n\n return { x: cellX, y: 0, z: top - forkLen }\n }\n\n // ── 3D ───────────────────────────────────────────────────────────────────\n\n buildRealObject(): RealObject | undefined {\n return new StorageRack3D(this)\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@operato/scene-storage",
|
|
3
3
|
"description": "Storage-domain components for things-scene (smart factory / logistics) — pallet, box, parcel; AS/RS and shelves planned.",
|
|
4
4
|
"author": "heartyoh",
|
|
5
|
-
"version": "10.0.0-beta.
|
|
5
|
+
"version": "10.0.0-beta.59",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
28
|
"@hatiolab/things-scene": "^10.0.0-beta.1",
|
|
29
|
-
"@operato/scene-base": "^10.0.0-beta.
|
|
29
|
+
"@operato/scene-base": "^10.0.0-beta.59",
|
|
30
30
|
"three": "^0.183.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"typescript": "^5.0.4"
|
|
46
46
|
},
|
|
47
47
|
"prettier": "@hatiolab/prettier-config",
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "887bb859f44b7137cc82f1d8587a1b94bfb901b8"
|
|
49
49
|
}
|
package/src/crane.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
|
-
import { Component, ComponentNature, ContainerAbstract, ContainerCapacity, RealObject, Transfer, getWorldPose, sceneComponent } from '@hatiolab/things-scene'
|
|
4
|
+
import { Component, ComponentNature, ContainerAbstract, ContainerCapacity, Holdable, RealObject, Transfer, getWorldPose, sceneComponent } from '@hatiolab/things-scene'
|
|
5
5
|
import type { SlotDef, State, Material3D, Transferable } from '@hatiolab/things-scene'
|
|
6
6
|
import {
|
|
7
7
|
CarrierHolder,
|
|
@@ -264,7 +264,7 @@ const NATURE: ComponentNature = {
|
|
|
264
264
|
* engage + reparent. During transit the carrier IS a child of the crane.
|
|
265
265
|
*/
|
|
266
266
|
@sceneComponent('crane')
|
|
267
|
-
export default class Crane extends Mover(CarrierHolder(ContainerCapacity(Legendable(Placeable(ContainerAbstract))))) {
|
|
267
|
+
export default class Crane extends Mover(CarrierHolder(ContainerCapacity(Holdable(Legendable(Placeable(ContainerAbstract)))))) {
|
|
268
268
|
declare state: CraneState
|
|
269
269
|
declare _realObject?: Crane3D
|
|
270
270
|
|
|
@@ -484,7 +484,8 @@ export default class Crane extends Mover(CarrierHolder(ContainerCapacity(Legenda
|
|
|
484
484
|
if (targetBottomWorldY !== null) {
|
|
485
485
|
// Phase Z PR-4: 임의 slot 의 carrier 검사 (multi-fork 대비). 단일 'forks'
|
|
486
486
|
// 가정 제거 — c._transferSlotId 가 set 됐으면 어떤 slot 이든 holding.
|
|
487
|
-
|
|
487
|
+
// Holdable 자손이면 _holdings, 아니면 _components.
|
|
488
|
+
const isHoldingCarrier = (((this as any)._holdings ?? (this as any).components) as any[] | undefined)?.some?.(
|
|
488
489
|
(c: any) => c?._transferSlotId != null
|
|
489
490
|
) ?? false
|
|
490
491
|
const liftH = numOr((this.state as any).forkLift, 30)
|
|
@@ -590,10 +591,15 @@ export default class Crane extends Mover(CarrierHolder(ContainerCapacity(Legenda
|
|
|
590
591
|
|
|
591
592
|
if (kind === 'pick') {
|
|
592
593
|
this.setState({ status: 'loading' as CraneStatus })
|
|
594
|
+
// 1. fork extend — cell 위 carrier 위치로 fork 진입.
|
|
593
595
|
await this._tween({ forkExtension: extTarget }, D_EXT)
|
|
594
596
|
|
|
595
|
-
//
|
|
596
|
-
//
|
|
597
|
+
// 2. fork lift — carrier 떠올림. 이 시점에 carrier 가 *_물리적으로 fork 위에
|
|
598
|
+
// 얹힘_* — handover 의 자연 타이밍.
|
|
599
|
+
await this._tween({ forkLiftRT: liftH }, D_LIFT)
|
|
600
|
+
|
|
601
|
+
// 3. Mid-engage reparent — carrier 가 fork 위로 *즉시 snap* (animated:false).
|
|
602
|
+
// Transfer 객체 통과 → monitor panel 추적. lift 직후 = 떠올린 시점.
|
|
597
603
|
const source = (target as any).parent
|
|
598
604
|
if (source) {
|
|
599
605
|
try {
|
|
@@ -608,7 +614,7 @@ export default class Crane extends Mover(CarrierHolder(ContainerCapacity(Legenda
|
|
|
608
614
|
}
|
|
609
615
|
}
|
|
610
616
|
|
|
611
|
-
|
|
617
|
+
// 4. fork retract — carrier 위에 얹힌 채로 빠짐.
|
|
612
618
|
await this._tween({ forkExtension: 0 }, D_EXT)
|
|
613
619
|
} else {
|
|
614
620
|
this.setState({ status: 'unloading' as CraneStatus })
|
|
@@ -621,7 +627,8 @@ export default class Crane extends Mover(CarrierHolder(ContainerCapacity(Legenda
|
|
|
621
627
|
|
|
622
628
|
// 3. dispatch — carrier world 위치 = cell 내 attach 위치, jump 없음. Transfer 추적.
|
|
623
629
|
// Phase Z PR-4: 임의 slot 의 carrier 검사 (multi-fork 대비).
|
|
624
|
-
|
|
630
|
+
// Holdable 자손이면 _holdings, 아니면 _components.
|
|
631
|
+
const comps = ((this as any)._holdings ?? (this as any).components) as any[] | undefined
|
|
625
632
|
const carrier = comps?.find?.((c: any) => c?._transferSlotId != null)
|
|
626
633
|
?? comps?.[0]
|
|
627
634
|
if (carrier) {
|
package/src/rack-grid.ts
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* - 자식 StorageRack 내부에서는 `0-0-${shelf-1}` (자체 cellId 형식). RackGrid 가 변환.
|
|
31
31
|
*/
|
|
32
32
|
import {
|
|
33
|
-
ApplicationContext, Component, ComponentNature, ContainerAbstract, Control, Layout,
|
|
33
|
+
ApplicationContext, Component, ComponentNature, ContainerAbstract, Control, Holdable, Layout,
|
|
34
34
|
Model, POINT, Properties, RealObject, sceneComponent
|
|
35
35
|
} from '@hatiolab/things-scene'
|
|
36
36
|
import type { State } from '@hatiolab/things-scene'
|
|
@@ -270,7 +270,7 @@ export interface RackGridState extends State {
|
|
|
270
270
|
@sceneComponent('rack-grid')
|
|
271
271
|
export default class RackGrid
|
|
272
272
|
extends RecordStorage<{ cellId: string; [key: string]: any }>()(
|
|
273
|
-
CarrierHolder(Placeable(ContainerAbstract))
|
|
273
|
+
Holdable(CarrierHolder(Placeable(ContainerAbstract)))
|
|
274
274
|
)
|
|
275
275
|
implements SlottedHolder
|
|
276
276
|
{
|
|
@@ -1273,7 +1273,7 @@ export default class RackGrid
|
|
|
1273
1273
|
|
|
1274
1274
|
const carrier = new CarrierClass(carrierState, (this as any)._app)
|
|
1275
1275
|
// silent: true — Plan A transient materialize 는 내부 use, mapping cascade 차단.
|
|
1276
|
-
;(this as any).
|
|
1276
|
+
;(this as any).addHolding(carrier) // transient carrier → _holdings (§1.2)
|
|
1277
1277
|
|
|
1278
1278
|
// 3D 강제 빌드 + holder attach + manual placement/anchor.
|
|
1279
1279
|
void (carrier as any).realObject
|
package/src/spot.ts
CHANGED
|
@@ -73,6 +73,8 @@ export default class Spot extends SingleSlotHolder()(
|
|
|
73
73
|
CarrierHolder(Placeable(ContainerAbstract))
|
|
74
74
|
) {
|
|
75
75
|
// SingleSlotHolder hook override — Spot 의 slot id 'pad'.
|
|
76
|
+
// (hasCarrierAt / obtainCarrier / receiveAt 는 mixin default 의 _holdings
|
|
77
|
+
// 기반 구현 사용 — Spot 측 override 불필요, 2026-06-16 mixin 표준화.)
|
|
76
78
|
_singleSlotId() { return SPOT_SLOT_ID }
|
|
77
79
|
declare state: SpotState
|
|
78
80
|
declare _realObject?: Spot3D
|
package/src/stockpile-grid.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import * as THREE from 'three'
|
|
20
|
-
import { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
20
|
+
import { Component, ComponentNature, ContainerAbstract, Holdable, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
21
21
|
import type { State, Material3D } from '@hatiolab/things-scene'
|
|
22
22
|
import {
|
|
23
23
|
CarrierHolder,
|
|
@@ -99,7 +99,7 @@ const NATURE: ComponentNature = {
|
|
|
99
99
|
|
|
100
100
|
@sceneComponent('stockpile-grid')
|
|
101
101
|
export default class StockpileGrid extends RecordStorage<StockpileGridCell>()(
|
|
102
|
-
CarrierHolder(Placeable(ContainerAbstract))
|
|
102
|
+
Holdable(CarrierHolder(Placeable(ContainerAbstract)))
|
|
103
103
|
) implements SlottedHolder {
|
|
104
104
|
declare state: StockpileGridState
|
|
105
105
|
declare _realObject?: StockpileGrid3D
|
|
@@ -285,7 +285,7 @@ export default class StockpileGrid extends RecordStorage<StockpileGridCell>()(
|
|
|
285
285
|
}
|
|
286
286
|
|
|
287
287
|
const carrier = new CarrierClass(carrierState, (this as any)._app)
|
|
288
|
-
;(this as any).
|
|
288
|
+
;(this as any).addHolding(carrier) // transient carrier → _holdings (§1.2)
|
|
289
289
|
void (carrier as any).realObject
|
|
290
290
|
;(carrier as any).applyHolderAttachPoint?.()
|
|
291
291
|
return carrier
|
package/src/stockpile.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import * as THREE from 'three'
|
|
17
|
-
import { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
17
|
+
import { Component, ComponentNature, ContainerAbstract, Holdable, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
18
18
|
import type { State, Material3D } from '@hatiolab/things-scene'
|
|
19
19
|
import {
|
|
20
20
|
CarrierHolder,
|
|
@@ -69,6 +69,12 @@ export interface StockpileState extends State {
|
|
|
69
69
|
*/
|
|
70
70
|
destination?: string
|
|
71
71
|
|
|
72
|
+
/**
|
|
73
|
+
* 라우팅 가중치 (Phase B1). 같은 destination 의 N sink 분산 시 weight 정책 사용.
|
|
74
|
+
* 미설정 = 1. weight ≤ 0 invalid (validator warning).
|
|
75
|
+
*/
|
|
76
|
+
weight?: number
|
|
77
|
+
|
|
72
78
|
/** click 시 invoke 할 Popup 컴포넌트 id (StorageRack / RackGrid 와 동일 패턴). */
|
|
73
79
|
popupRef?: string
|
|
74
80
|
|
|
@@ -102,6 +108,7 @@ const NATURE: ComponentNature = {
|
|
|
102
108
|
{ type: 'select', label: 'pick-policy', name: 'pickPolicy',
|
|
103
109
|
property: { options: ['lifo', 'fifo'] } },
|
|
104
110
|
{ type: 'string', label: 'destination', name: 'destination' },
|
|
111
|
+
{ type: 'number', label: 'weight', name: 'weight', placeholder: '같은 destination N sink 분산 가중치 (기본 1)' },
|
|
105
112
|
{ type: 'id-input', label: 'popup-ref', name: 'popupRef',
|
|
106
113
|
property: { component: 'popup' } },
|
|
107
114
|
{ type: 'id-input', label: 'legend-target', name: 'legendTarget',
|
|
@@ -113,7 +120,7 @@ const NATURE: ComponentNature = {
|
|
|
113
120
|
|
|
114
121
|
@sceneComponent('stockpile')
|
|
115
122
|
export default class Stockpile extends RecordStorage<StockpileRecord>()(
|
|
116
|
-
CarrierHolder(Placeable(ContainerAbstract))
|
|
123
|
+
Holdable(CarrierHolder(Placeable(ContainerAbstract)))
|
|
117
124
|
) implements SlottedHolder {
|
|
118
125
|
declare state: StockpileState
|
|
119
126
|
declare _realObject?: Stockpile3D
|
|
@@ -130,6 +137,16 @@ export default class Stockpile extends RecordStorage<StockpileRecord>()(
|
|
|
130
137
|
return (this.state.destination as string | undefined) ?? (this.state.id as string)
|
|
131
138
|
}
|
|
132
139
|
|
|
140
|
+
/**
|
|
141
|
+
* RoutingTarget.routingWeight — state.weight 명시 시만 숫자 반환. 미명시는 undefined →
|
|
142
|
+
* caller 가 *_inDegree fallback (경로 갯수)_* 으로 자연 capacity 측정. default 1 반환은
|
|
143
|
+
* "명시됨" 으로 오인되어 inDegree 무시 — 가중치 결함의 원인 (2026-06-17 라이브 진단).
|
|
144
|
+
*/
|
|
145
|
+
routingWeight(): number | undefined {
|
|
146
|
+
const w = this.state.weight
|
|
147
|
+
return typeof w === 'number' && Number.isFinite(w) ? w : undefined
|
|
148
|
+
}
|
|
149
|
+
|
|
133
150
|
// ── 그래프 참여 ─────────────────────────────────────────────────────────────
|
|
134
151
|
// StockPile 은 *방향 없는 받는 footprint*. 별도 면 anchor 를 publish 하지 않는다 —
|
|
135
152
|
// 어느 면으로 받는지는 의미 없고, 슈트/컨베이어의 *출구 anchor 가 자기 footprint 에
|
|
@@ -229,8 +246,11 @@ export default class Stockpile extends RecordStorage<StockpileRecord>()(
|
|
|
229
246
|
}
|
|
230
247
|
|
|
231
248
|
const carrier = new CarrierClass(carrierState, (this as any)._app)
|
|
232
|
-
//
|
|
233
|
-
|
|
249
|
+
// transient carrier → _holdings (모델링 자식 `_components` 아님). Mover.pick
|
|
250
|
+
// 이 reparent 호출 시 ContainerAbstract.addComponent 가 oldContainer._holdings
|
|
251
|
+
// 도 자동 정리 (stale 방지, §1.2 직교). board JSON 직렬화 / Inspector 표시
|
|
252
|
+
// 자동 차단 — Spot 시범 패턴 (2026-06-16).
|
|
253
|
+
;(this as any).addHolding(carrier)
|
|
234
254
|
void (carrier as any).realObject
|
|
235
255
|
;(carrier as any).applyHolderAttachPoint?.()
|
|
236
256
|
return carrier
|
package/src/storage-rack.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
3
|
*/
|
|
4
|
-
import { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
4
|
+
import { Component, ComponentNature, ContainerAbstract, Holdable, RealObject, sceneComponent } from '@hatiolab/things-scene'
|
|
5
5
|
import type { State, Material3D } from '@hatiolab/things-scene'
|
|
6
6
|
import * as THREE from 'three'
|
|
7
7
|
import {
|
|
@@ -168,7 +168,7 @@ function _nextCarrierRefid(): number {
|
|
|
168
168
|
@sceneComponent('storage-rack')
|
|
169
169
|
export default class Rack
|
|
170
170
|
extends RecordStorage<{ cellId: string; [key: string]: any }>()(
|
|
171
|
-
CellContainer(CarrierHolder(Placeable(ContainerAbstract)))
|
|
171
|
+
CellContainer(Holdable(CarrierHolder(Placeable(ContainerAbstract))))
|
|
172
172
|
)
|
|
173
173
|
implements SlottedHolder
|
|
174
174
|
{
|
|
@@ -516,7 +516,7 @@ export default class Rack
|
|
|
516
516
|
// 만든 게 아니라 *내부적으로 잠시 빌리는 것*. 새 컴포넌트 추가 → root.onadded
|
|
517
517
|
// → refreshMappings (1s debounce) → 모든 컴포넌트 매핑 재실행 의 cascade 차단.
|
|
518
518
|
// (silent 모드: _silentAdd 플래그 set → refreshMappings skip)
|
|
519
|
-
;(this as any).
|
|
519
|
+
;(this as any).addHolding(carrier) // transient carrier → _holdings (§1.2)
|
|
520
520
|
|
|
521
521
|
// 3D 강제 빌드 + attach (pipeline tick 없이도 즉시 표시 — Mover 가 곧 pick).
|
|
522
522
|
void (carrier as any).realObject
|