graphwise 1.0.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -0
- package/dist/expansion/base.d.ts +12 -0
- package/dist/expansion/base.d.ts.map +1 -0
- package/dist/expansion/base.unit.test.d.ts +2 -0
- package/dist/expansion/base.unit.test.d.ts.map +1 -0
- package/dist/expansion/dome.d.ts +16 -0
- package/dist/expansion/dome.d.ts.map +1 -0
- package/dist/expansion/dome.unit.test.d.ts +2 -0
- package/dist/expansion/dome.unit.test.d.ts.map +1 -0
- package/dist/expansion/edge.d.ts +15 -0
- package/dist/expansion/edge.d.ts.map +1 -0
- package/dist/expansion/edge.unit.test.d.ts +2 -0
- package/dist/expansion/edge.unit.test.d.ts.map +1 -0
- package/dist/expansion/hae.d.ts +22 -0
- package/dist/expansion/hae.d.ts.map +1 -0
- package/dist/expansion/hae.unit.test.d.ts +2 -0
- package/dist/expansion/hae.unit.test.d.ts.map +1 -0
- package/dist/expansion/index.d.ts +22 -0
- package/dist/expansion/index.d.ts.map +1 -0
- package/dist/expansion/maze.d.ts +25 -0
- package/dist/expansion/maze.d.ts.map +1 -0
- package/dist/expansion/maze.unit.test.d.ts +2 -0
- package/dist/expansion/maze.unit.test.d.ts.map +1 -0
- package/dist/expansion/pipe.d.ts +15 -0
- package/dist/expansion/pipe.d.ts.map +1 -0
- package/dist/expansion/pipe.unit.test.d.ts +2 -0
- package/dist/expansion/pipe.unit.test.d.ts.map +1 -0
- package/dist/expansion/reach.d.ts +26 -0
- package/dist/expansion/reach.d.ts.map +1 -0
- package/dist/expansion/reach.unit.test.d.ts +2 -0
- package/dist/expansion/reach.unit.test.d.ts.map +1 -0
- package/dist/expansion/sage.d.ts +24 -0
- package/dist/expansion/sage.d.ts.map +1 -0
- package/dist/expansion/sage.unit.test.d.ts +2 -0
- package/dist/expansion/sage.unit.test.d.ts.map +1 -0
- package/dist/expansion/types.d.ts +105 -0
- package/dist/expansion/types.d.ts.map +1 -0
- package/dist/extraction/ego-network.d.ts +32 -0
- package/dist/extraction/ego-network.d.ts.map +1 -0
- package/dist/extraction/ego-network.unit.test.d.ts +5 -0
- package/dist/extraction/ego-network.unit.test.d.ts.map +1 -0
- package/dist/extraction/index.d.ts +20 -0
- package/dist/extraction/index.d.ts.map +1 -0
- package/dist/extraction/induced-subgraph.d.ts +19 -0
- package/dist/extraction/induced-subgraph.d.ts.map +1 -0
- package/dist/extraction/induced-subgraph.unit.test.d.ts +5 -0
- package/dist/extraction/induced-subgraph.unit.test.d.ts.map +1 -0
- package/dist/extraction/k-core.d.ts +24 -0
- package/dist/extraction/k-core.d.ts.map +1 -0
- package/dist/extraction/k-core.unit.test.d.ts +5 -0
- package/dist/extraction/k-core.unit.test.d.ts.map +1 -0
- package/dist/extraction/motif.d.ts +50 -0
- package/dist/extraction/motif.d.ts.map +1 -0
- package/dist/extraction/motif.unit.test.d.ts +5 -0
- package/dist/extraction/motif.unit.test.d.ts.map +1 -0
- package/dist/extraction/node-filter.d.ts +35 -0
- package/dist/extraction/node-filter.d.ts.map +1 -0
- package/dist/extraction/node-filter.unit.test.d.ts +5 -0
- package/dist/extraction/node-filter.unit.test.d.ts.map +1 -0
- package/dist/extraction/truss.d.ts +41 -0
- package/dist/extraction/truss.d.ts.map +1 -0
- package/dist/extraction/truss.unit.test.d.ts +5 -0
- package/dist/extraction/truss.unit.test.d.ts.map +1 -0
- package/dist/gpu/context.d.ts +118 -0
- package/dist/gpu/context.d.ts.map +1 -0
- package/dist/gpu/context.unit.test.d.ts +2 -0
- package/dist/gpu/context.unit.test.d.ts.map +1 -0
- package/dist/gpu/csr.d.ts +97 -0
- package/dist/gpu/csr.d.ts.map +1 -0
- package/dist/gpu/csr.unit.test.d.ts +2 -0
- package/dist/gpu/csr.unit.test.d.ts.map +1 -0
- package/dist/gpu/detect.d.ts +25 -0
- package/dist/gpu/detect.d.ts.map +1 -0
- package/dist/gpu/detect.unit.test.d.ts +2 -0
- package/dist/gpu/detect.unit.test.d.ts.map +1 -0
- package/dist/gpu/index.cjs +6 -0
- package/dist/gpu/index.d.ts +11 -0
- package/dist/gpu/index.d.ts.map +1 -0
- package/dist/gpu/index.js +2 -0
- package/dist/gpu/types.d.ts +50 -0
- package/dist/gpu/types.d.ts.map +1 -0
- package/dist/gpu-BJRVYBjx.cjs +338 -0
- package/dist/gpu-BJRVYBjx.cjs.map +1 -0
- package/dist/gpu-BveuXugy.js +315 -0
- package/dist/gpu-BveuXugy.js.map +1 -0
- package/dist/graph/adjacency-map.d.ts +95 -0
- package/dist/graph/adjacency-map.d.ts.map +1 -0
- package/dist/graph/adjacency-map.unit.test.d.ts +2 -0
- package/dist/graph/adjacency-map.unit.test.d.ts.map +1 -0
- package/dist/graph/index.cjs +3 -0
- package/dist/graph/index.d.ts +9 -0
- package/dist/graph/index.d.ts.map +1 -0
- package/dist/graph/index.js +2 -0
- package/dist/graph/interfaces.d.ts +125 -0
- package/dist/graph/interfaces.d.ts.map +1 -0
- package/dist/graph/types.d.ts +72 -0
- package/dist/graph/types.d.ts.map +1 -0
- package/dist/graph-DLWiziLB.js +222 -0
- package/dist/graph-DLWiziLB.js.map +1 -0
- package/dist/graph-az06J1YV.cjs +227 -0
- package/dist/graph-az06J1YV.cjs.map +1 -0
- package/dist/index/index.cjs +1404 -0
- package/dist/index/index.cjs.map +1 -0
- package/dist/index/index.js +1356 -0
- package/dist/index/index.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/kmeans-B0HEOU6k.cjs +234 -0
- package/dist/kmeans-B0HEOU6k.cjs.map +1 -0
- package/dist/kmeans-DgbsOznU.js +223 -0
- package/dist/kmeans-DgbsOznU.js.map +1 -0
- package/dist/ranking/baselines/shortest.d.ts +15 -0
- package/dist/ranking/baselines/shortest.d.ts.map +1 -0
- package/dist/ranking/baselines/shortest.unit.test.d.ts +2 -0
- package/dist/ranking/baselines/shortest.unit.test.d.ts.map +1 -0
- package/dist/ranking/baselines/types.d.ts +30 -0
- package/dist/ranking/baselines/types.d.ts.map +1 -0
- package/dist/ranking/index.d.ts +15 -0
- package/dist/ranking/index.d.ts.map +1 -0
- package/dist/ranking/mi/adamic-adar.d.ts +13 -0
- package/dist/ranking/mi/adamic-adar.d.ts.map +1 -0
- package/dist/ranking/mi/adaptive.d.ts +16 -0
- package/dist/ranking/mi/adaptive.d.ts.map +1 -0
- package/dist/ranking/mi/etch.d.ts +7 -0
- package/dist/ranking/mi/etch.d.ts.map +1 -0
- package/dist/ranking/mi/index.d.ts +18 -0
- package/dist/ranking/mi/index.d.ts.map +1 -0
- package/dist/ranking/mi/jaccard.d.ts +13 -0
- package/dist/ranking/mi/jaccard.d.ts.map +1 -0
- package/dist/ranking/mi/mi-variants.unit.test.d.ts +2 -0
- package/dist/ranking/mi/mi-variants.unit.test.d.ts.map +1 -0
- package/dist/ranking/mi/notch.d.ts +7 -0
- package/dist/ranking/mi/notch.d.ts.map +1 -0
- package/dist/ranking/mi/scale.d.ts +7 -0
- package/dist/ranking/mi/scale.d.ts.map +1 -0
- package/dist/ranking/mi/skew.d.ts +7 -0
- package/dist/ranking/mi/skew.d.ts.map +1 -0
- package/dist/ranking/mi/span.d.ts +7 -0
- package/dist/ranking/mi/span.d.ts.map +1 -0
- package/dist/ranking/mi/types.d.ts +35 -0
- package/dist/ranking/mi/types.d.ts.map +1 -0
- package/dist/ranking/parse.d.ts +56 -0
- package/dist/ranking/parse.d.ts.map +1 -0
- package/dist/ranking/parse.unit.test.d.ts +2 -0
- package/dist/ranking/parse.unit.test.d.ts.map +1 -0
- package/dist/schemas/define.d.ts +18 -0
- package/dist/schemas/define.d.ts.map +1 -0
- package/dist/schemas/define.unit.test.d.ts +2 -0
- package/dist/schemas/define.unit.test.d.ts.map +1 -0
- package/dist/schemas/graph.d.ts +85 -0
- package/dist/schemas/graph.d.ts.map +1 -0
- package/dist/schemas/graph.unit.test.d.ts +2 -0
- package/dist/schemas/graph.unit.test.d.ts.map +1 -0
- package/dist/schemas/index.cjs +3791 -0
- package/dist/schemas/index.cjs.map +1 -0
- package/dist/schemas/index.d.ts +3 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +3782 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/seeds/grasp.d.ts +79 -0
- package/dist/seeds/grasp.d.ts.map +1 -0
- package/dist/seeds/grasp.unit.test.d.ts +2 -0
- package/dist/seeds/grasp.unit.test.d.ts.map +1 -0
- package/dist/seeds/index.cjs +4 -0
- package/dist/seeds/index.d.ts +10 -0
- package/dist/seeds/index.d.ts.map +1 -0
- package/dist/seeds/index.js +2 -0
- package/dist/seeds/stratified.d.ts +85 -0
- package/dist/seeds/stratified.d.ts.map +1 -0
- package/dist/seeds/stratified.unit.test.d.ts +2 -0
- package/dist/seeds/stratified.unit.test.d.ts.map +1 -0
- package/dist/seeds-B6J9oJfU.cjs +404 -0
- package/dist/seeds-B6J9oJfU.cjs.map +1 -0
- package/dist/seeds-UNZxqm_U.js +393 -0
- package/dist/seeds-UNZxqm_U.js.map +1 -0
- package/dist/structures/index.cjs +3 -0
- package/dist/structures/index.d.ts +3 -0
- package/dist/structures/index.d.ts.map +1 -0
- package/dist/structures/index.js +2 -0
- package/dist/structures/priority-queue.d.ts +59 -0
- package/dist/structures/priority-queue.d.ts.map +1 -0
- package/dist/structures/priority-queue.unit.test.d.ts +2 -0
- package/dist/structures/priority-queue.unit.test.d.ts.map +1 -0
- package/dist/structures-BPfhfqNP.js +133 -0
- package/dist/structures-BPfhfqNP.js.map +1 -0
- package/dist/structures-CJ_S_7fs.cjs +138 -0
- package/dist/structures-CJ_S_7fs.cjs.map +1 -0
- package/dist/traversal/bfs.d.ts +50 -0
- package/dist/traversal/bfs.d.ts.map +1 -0
- package/dist/traversal/bfs.unit.test.d.ts +2 -0
- package/dist/traversal/bfs.unit.test.d.ts.map +1 -0
- package/dist/traversal/dfs.d.ts +50 -0
- package/dist/traversal/dfs.d.ts.map +1 -0
- package/dist/traversal/dfs.unit.test.d.ts +2 -0
- package/dist/traversal/dfs.unit.test.d.ts.map +1 -0
- package/dist/traversal/index.cjs +6 -0
- package/dist/traversal/index.d.ts +11 -0
- package/dist/traversal/index.d.ts.map +1 -0
- package/dist/traversal/index.js +2 -0
- package/dist/traversal-CQCjUwUJ.js +149 -0
- package/dist/traversal-CQCjUwUJ.js.map +1 -0
- package/dist/traversal-QeHaNUWn.cjs +172 -0
- package/dist/traversal-QeHaNUWn.cjs.map +1 -0
- package/dist/utils/clustering-coefficient.d.ts +38 -0
- package/dist/utils/clustering-coefficient.d.ts.map +1 -0
- package/dist/utils/clustering-coefficient.unit.test.d.ts +2 -0
- package/dist/utils/clustering-coefficient.unit.test.d.ts.map +1 -0
- package/dist/utils/entropy.d.ts +58 -0
- package/dist/utils/entropy.d.ts.map +1 -0
- package/dist/utils/entropy.unit.test.d.ts +2 -0
- package/dist/utils/entropy.unit.test.d.ts.map +1 -0
- package/dist/utils/index.cjs +13 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/kmeans.d.ts +73 -0
- package/dist/utils/kmeans.d.ts.map +1 -0
- package/dist/utils/kmeans.unit.test.d.ts +2 -0
- package/dist/utils/kmeans.unit.test.d.ts.map +1 -0
- package/dist/utils-Q_akvlMn.js +164 -0
- package/dist/utils-Q_akvlMn.js.map +1 -0
- package/dist/utils-spZa1ZvS.cjs +205 -0
- package/dist/utils-spZa1ZvS.cjs.map +1 -0
- package/package.json +136 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/expansion/base.ts","../../src/expansion/dome.ts","../../src/expansion/edge.ts","../../src/ranking/mi/jaccard.ts","../../src/expansion/hae.ts","../../src/expansion/pipe.ts","../../src/expansion/sage.ts","../../src/expansion/reach.ts","../../src/expansion/maze.ts","../../src/ranking/parse.ts","../../src/ranking/mi/adamic-adar.ts","../../src/ranking/mi/scale.ts","../../src/ranking/mi/skew.ts","../../src/ranking/mi/span.ts","../../src/ranking/mi/etch.ts","../../src/ranking/mi/notch.ts","../../src/ranking/mi/adaptive.ts","../../src/ranking/baselines/shortest.ts","../../src/extraction/ego-network.ts","../../src/extraction/k-core.ts","../../src/extraction/truss.ts","../../src/extraction/motif.ts","../../src/extraction/induced-subgraph.ts","../../src/extraction/node-filter.ts"],"sourcesContent":["/**\n * BASE (Bidirectional Adaptive Seed Expansion) engine.\n *\n * Core algorithm implementing priority-ordered bidirectional expansion\n * with frontier collision detection for path discovery.\n *\n * Key properties:\n * 1. Priority-ordered exploration - global min-priority across all frontiers\n * 2. Frontier collision detection - path recorded when frontiers meet\n * 3. Implicit termination - halts when all queues empty\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport { PriorityQueue } from \"../structures/priority-queue\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionPath,\n\tExpansionStats,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\n\n/**\n * Internal queue entry for frontier expansion.\n */\ninterface QueueEntry {\n\tnodeId: NodeId;\n\tfrontierIndex: number;\n\tpredecessor: NodeId | null;\n}\n\n/**\n * Default priority function - degree-ordered (DOME).\n */\nfunction degreePriority<N extends NodeData, E extends EdgeData>(\n\t_nodeId: NodeId,\n\tcontext: PriorityContext<N, E>,\n): number {\n\treturn context.degree;\n}\n\n/**\n * Run BASE expansion algorithm.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration\n * @returns Expansion result with discovered paths\n */\nexport function base<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: ExpansionConfig<N, E>,\n): ExpansionResult {\n\tconst startTime = performance.now();\n\n\tconst {\n\t\tmaxNodes = 0,\n\t\tmaxIterations = 0,\n\t\tmaxPaths = 0,\n\t\tpriority = degreePriority,\n\t\tdebug = false,\n\t} = config ?? {};\n\n\tif (seeds.length === 0) {\n\t\treturn emptyResult(\"base\", startTime);\n\t}\n\n\t// Initialise frontiers - one per seed\n\tconst numFrontiers = seeds.length;\n\tconst visitedByFrontier: Map<NodeId, number>[] = [];\n\tconst predecessors: Map<NodeId, NodeId | null>[] = [];\n\tconst queues: PriorityQueue<QueueEntry>[] = [];\n\n\tfor (let i = 0; i < numFrontiers; i++) {\n\t\tvisitedByFrontier.push(new Map());\n\t\tpredecessors.push(new Map());\n\t\tqueues.push(new PriorityQueue<QueueEntry>());\n\n\t\tconst seed = seeds[i];\n\t\tif (seed === undefined) continue;\n\n\t\tconst seedNode = seed.id;\n\t\t// Note: seed is NOT marked as visited here - it will be marked when processed\n\t\t// like any other node. This allows the seed to be properly expanded.\n\t\tpredecessors[i]?.set(seedNode, null);\n\n\t\tconst context = createPriorityContext(\n\t\t\tgraph,\n\t\t\tseedNode,\n\t\t\ti,\n\t\t\tvisitedByFrontier,\n\t\t\t[],\n\t\t\t0,\n\t\t);\n\n\t\tconst seedPriority = priority(seedNode, context);\n\t\tqueues[i]?.push(\n\t\t\t{\n\t\t\t\tnodeId: seedNode,\n\t\t\t\tfrontierIndex: i,\n\t\t\t\tpredecessor: null,\n\t\t\t},\n\t\t\tseedPriority,\n\t\t);\n\t}\n\n\tconst allVisited = new Set<NodeId>();\n\tconst sampledEdges = new Set<string>();\n\tconst discoveredPaths: ExpansionPath[] = [];\n\tlet iterations = 0;\n\tlet edgesTraversed = 0;\n\tlet termination: ExpansionStats[\"termination\"] = \"exhausted\";\n\n\t// Main expansion loop\n\tconst continueExpansion = (): boolean => {\n\t\tif (maxIterations > 0 && iterations >= maxIterations) {\n\t\t\ttermination = \"limit\";\n\t\t\treturn false;\n\t\t}\n\t\tif (maxNodes > 0 && allVisited.size >= maxNodes) {\n\t\t\ttermination = \"limit\";\n\t\t\treturn false;\n\t\t}\n\t\tif (maxPaths > 0 && discoveredPaths.length >= maxPaths) {\n\t\t\ttermination = \"limit\";\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t};\n\n\twhile (continueExpansion()) {\n\t\t// Find frontier with lowest priority entry\n\t\tlet lowestPriority = Number.POSITIVE_INFINITY;\n\t\tlet activeFrontier = -1;\n\n\t\tfor (let i = 0; i < numFrontiers; i++) {\n\t\t\tconst queue = queues[i];\n\t\t\tif (queue !== undefined && !queue.isEmpty()) {\n\t\t\t\tconst peek = queue.peek();\n\t\t\t\tif (peek !== undefined && peek.priority < lowestPriority) {\n\t\t\t\t\tlowestPriority = peek.priority;\n\t\t\t\t\tactiveFrontier = i;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// All queues empty - exhausted\n\t\tif (activeFrontier < 0) {\n\t\t\ttermination = \"exhausted\";\n\t\t\tbreak;\n\t\t}\n\n\t\tconst queue = queues[activeFrontier];\n\t\tif (queue === undefined) break;\n\n\t\tconst entry = queue.pop();\n\t\tif (entry === undefined) break;\n\n\t\tconst { nodeId, predecessor } = entry.item;\n\n\t\t// Skip if already visited by this frontier\n\t\tconst frontierVisited = visitedByFrontier[activeFrontier];\n\t\tif (frontierVisited === undefined || frontierVisited.has(nodeId)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Mark visited\n\t\tfrontierVisited.set(nodeId, activeFrontier);\n\t\tif (predecessor !== null) {\n\t\t\tconst predMap = predecessors[activeFrontier];\n\t\t\tif (predMap !== undefined) {\n\t\t\t\tpredMap.set(nodeId, predecessor);\n\t\t\t}\n\t\t}\n\t\tallVisited.add(nodeId);\n\n\t\tif (debug) {\n\t\t\tconsole.log(\n\t\t\t\t`[BASE] Iteration ${String(iterations)}: Frontier ${String(activeFrontier)} visiting ${nodeId}`,\n\t\t\t);\n\t\t}\n\n\t\t// Check for collision with other frontiers\n\t\tfor (let otherFrontier = 0; otherFrontier < numFrontiers; otherFrontier++) {\n\t\t\tif (otherFrontier === activeFrontier) continue;\n\n\t\t\tconst otherVisited = visitedByFrontier[otherFrontier];\n\t\t\tif (otherVisited === undefined) continue;\n\n\t\t\tif (otherVisited.has(nodeId)) {\n\t\t\t\t// Collision! Reconstruct path\n\t\t\t\tconst path = reconstructPath(\n\t\t\t\t\tnodeId,\n\t\t\t\t\tactiveFrontier,\n\t\t\t\t\totherFrontier,\n\t\t\t\t\tpredecessors,\n\t\t\t\t\tseeds,\n\t\t\t\t);\n\t\t\t\tif (path !== null) {\n\t\t\t\t\tdiscoveredPaths.push(path);\n\t\t\t\t\tif (debug) {\n\t\t\t\t\t\tconsole.log(`[BASE] Path found: ${path.nodes.join(\" -> \")}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Expand neighbours\n\t\tconst neighbours = graph.neighbours(nodeId);\n\t\tfor (const neighbour of neighbours) {\n\t\t\tedgesTraversed++;\n\n\t\t\t// Track sampled edge\n\t\t\tconst edgeKey =\n\t\t\t\tnodeId < neighbour\n\t\t\t\t\t? `${nodeId}::${neighbour}`\n\t\t\t\t\t: `${neighbour}::${nodeId}`;\n\t\t\tsampledEdges.add(edgeKey);\n\n\t\t\t// Skip if already visited by this frontier\n\t\t\tconst frontierVisited = visitedByFrontier[activeFrontier];\n\t\t\tif (frontierVisited === undefined || frontierVisited.has(neighbour)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst context = createPriorityContext(\n\t\t\t\tgraph,\n\t\t\t\tneighbour,\n\t\t\t\tactiveFrontier,\n\t\t\t\tvisitedByFrontier,\n\t\t\t\tdiscoveredPaths,\n\t\t\t\titerations + 1,\n\t\t\t);\n\n\t\t\tconst neighbourPriority = priority(neighbour, context);\n\n\t\t\tqueue.push(\n\t\t\t\t{\n\t\t\t\t\tnodeId: neighbour,\n\t\t\t\t\tfrontierIndex: activeFrontier,\n\t\t\t\t\tpredecessor: nodeId,\n\t\t\t\t},\n\t\t\t\tneighbourPriority,\n\t\t\t);\n\t\t}\n\n\t\titerations++;\n\t}\n\n\tconst endTime = performance.now();\n\tconst visitedPerFrontier = visitedByFrontier.map((m) => new Set(m.keys()));\n\n\t// Convert sampled edges to tuples\n\tconst edgeTuples = new Set<readonly [NodeId, NodeId]>();\n\tfor (const edgeKey of sampledEdges) {\n\t\tconst parts = edgeKey.split(\"::\");\n\t\tif (parts.length === 2) {\n\t\t\tconst source = parts[0];\n\t\t\tconst target = parts[1];\n\t\t\tif (source !== undefined && target !== undefined) {\n\t\t\t\tedgeTuples.add([source, target] as const);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\tpaths: discoveredPaths,\n\t\tsampledNodes: allVisited,\n\t\tsampledEdges: edgeTuples,\n\t\tvisitedPerFrontier,\n\t\tstats: {\n\t\t\titerations,\n\t\t\tnodesVisited: allVisited.size,\n\t\t\tedgesTraversed,\n\t\t\tpathsFound: discoveredPaths.length,\n\t\t\tdurationMs: endTime - startTime,\n\t\t\talgorithm: \"base\",\n\t\t\ttermination,\n\t\t},\n\t};\n}\n\n/**\n * Create priority context for a node.\n */\nfunction createPriorityContext<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tnodeId: NodeId,\n\tfrontierIndex: number,\n\tvisitedByFrontier: readonly Map<NodeId, number>[],\n\tdiscoveredPaths: readonly ExpansionPath[],\n\titeration: number,\n): PriorityContext<N, E> {\n\tconst combinedVisited = new Map<NodeId, number>();\n\tfor (const frontierMap of visitedByFrontier) {\n\t\tfor (const [id, idx] of frontierMap) {\n\t\t\tcombinedVisited.set(id, idx);\n\t\t}\n\t}\n\n\tconst allVisited = new Set<NodeId>(combinedVisited.keys());\n\n\treturn {\n\t\tgraph,\n\t\tdegree: graph.degree(nodeId),\n\t\tfrontierIndex,\n\t\tvisitedByFrontier: combinedVisited,\n\t\tallVisited,\n\t\tdiscoveredPaths,\n\t\titeration,\n\t};\n}\n\n/**\n * Reconstruct path from collision point.\n */\nfunction reconstructPath(\n\tcollisionNode: NodeId,\n\tfrontierA: number,\n\tfrontierB: number,\n\tpredecessors: readonly Map<NodeId, NodeId | null>[],\n\tseeds: readonly Seed[],\n): ExpansionPath | null {\n\tconst pathA: NodeId[] = [collisionNode];\n\tconst predA = predecessors[frontierA];\n\tif (predA !== undefined) {\n\t\tlet node: NodeId | null | undefined = collisionNode;\n\t\tlet next: NodeId | null | undefined = predA.get(node);\n\t\twhile (next !== null && next !== undefined) {\n\t\t\tnode = next;\n\t\t\tpathA.unshift(node);\n\t\t\tnext = predA.get(node);\n\t\t}\n\t}\n\n\tconst pathB: NodeId[] = [];\n\tconst predB = predecessors[frontierB];\n\tif (predB !== undefined) {\n\t\tlet node: NodeId | null | undefined = collisionNode;\n\t\tlet next: NodeId | null | undefined = predB.get(node);\n\t\twhile (next !== null && next !== undefined) {\n\t\t\tnode = next;\n\t\t\tpathB.push(node);\n\t\t\tnext = predB.get(node);\n\t\t}\n\t}\n\n\tconst fullPath = [...pathA, ...pathB];\n\n\tconst seedA = seeds[frontierA];\n\tconst seedB = seeds[frontierB];\n\n\tif (seedA === undefined || seedB === undefined) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tfromSeed: seedA,\n\t\ttoSeed: seedB,\n\t\tnodes: fullPath,\n\t};\n}\n\n/**\n * Create an empty result for early termination.\n */\nfunction emptyResult(algorithm: string, startTime: number): ExpansionResult {\n\treturn {\n\t\tpaths: [],\n\t\tsampledNodes: new Set(),\n\t\tsampledEdges: new Set(),\n\t\tvisitedPerFrontier: [],\n\t\tstats: {\n\t\t\titerations: 0,\n\t\t\tnodesVisited: 0,\n\t\t\tedgesTraversed: 0,\n\t\t\tpathsFound: 0,\n\t\t\tdurationMs: performance.now() - startTime,\n\t\t\talgorithm,\n\t\t\ttermination: \"exhausted\",\n\t\t},\n\t};\n}\n","/**\n * DOME (Degree-Ordered Multi-Expansion) algorithm.\n *\n * Simplest BASE variant: priority = node degree.\n * Lower degree nodes are expanded first (can be reversed via config).\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\n\n/**\n * Run DOME expansion (degree-ordered).\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration\n * @returns Expansion result with discovered paths\n */\nexport function dome<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: ExpansionConfig<N, E>,\n): ExpansionResult {\n\t// DOME uses degree as priority (lower degree = higher priority)\n\tconst domePriority = (\n\t\tnodeId: string,\n\t\tcontext: PriorityContext<N, E>,\n\t): number => {\n\t\t// Use context to satisfy strict unused variable checks\n\t\tvoid context;\n\t\treturn graph.degree(nodeId);\n\t};\n\n\treturn base(graph, seeds, {\n\t\t...config,\n\t\tpriority: domePriority,\n\t});\n}\n\n/**\n * DOME with reverse priority (high degree first).\n */\nexport function domeHighDegree<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: ExpansionConfig<N, E>,\n): ExpansionResult {\n\t// Negate degree to prioritise high-degree nodes\n\tconst domePriority = (\n\t\tnodeId: string,\n\t\tcontext: PriorityContext<N, E>,\n\t): number => {\n\t\t// Use context to satisfy strict unused variable checks\n\t\tvoid context;\n\t\treturn -graph.degree(nodeId);\n\t};\n\n\treturn base(graph, seeds, {\n\t\t...config,\n\t\tpriority: domePriority,\n\t});\n}\n","/**\n * EDGE (Edge-Degree Guided Expansion) algorithm.\n *\n * Prioritises exploration by edge degree rather than node degree.\n * Expands edges with lower combined endpoint degrees first.\n *\n * Useful for finding paths through sparse regions of the graph,\n * avoiding dense clusters.\n *\n * @module expansion/edge\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\n\n/**\n * EDGE priority function.\n *\n * Priority = degree(source) + degree(target)\n * Lower values = higher priority (explored first)\n */\nfunction edgePriority<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n): number {\n\t// Sum of source degree and neighbour degrees\n\tconst graph = context.graph;\n\tlet totalDegree = context.degree;\n\n\tfor (const neighbour of graph.neighbours(nodeId)) {\n\t\ttotalDegree += graph.degree(neighbour);\n\t}\n\n\treturn totalDegree;\n}\n\n/**\n * Run EDGE expansion algorithm.\n *\n * Expands from seeds prioritising low-degree edges first.\n * Useful for avoiding hubs and exploring sparse regions.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration\n * @returns Expansion result with discovered paths\n */\nexport function edge<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: ExpansionConfig<N, E>,\n): ExpansionResult {\n\treturn base(graph, seeds, {\n\t\t...config,\n\t\tpriority: edgePriority,\n\t});\n}\n","/**\n * Jaccard similarity coefficient for edge salience.\n *\n * Measures overlap between neighbourhoods of connected nodes:\n * MI(u,v) = |N(u) ∩ N(v)| / |N(u) ∪ N(v)|\n *\n * Range: [0, 1]\n * - 0: No shared neighbours (low salience)\n * - 1: Identical neighbourhoods (high salience)\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute Jaccard similarity between neighbourhoods of two nodes.\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @param config - Optional configuration\n * @returns Jaccard coefficient in [0, 1]\n */\nexport function jaccard<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10 } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\t// Compute intersection size\n\tlet intersectionSize = 0;\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tintersectionSize++;\n\t\t}\n\t}\n\n\t// Compute union size\n\tconst unionSize =\n\t\tsourceNeighbours.size + targetNeighbours.size - intersectionSize;\n\n\t// Avoid division by zero\n\tif (unionSize === 0) {\n\t\treturn 0;\n\t}\n\n\tconst score = intersectionSize / unionSize;\n\n\t// Apply epsilon floor for numerical stability\n\treturn Math.max(epsilon, score);\n}\n","/**\n * HAE (High-Association Expansion) algorithm.\n *\n * Prioritises exploration by mutual information scores.\n * Expands high-MI edges first, favouring paths with strong associations.\n *\n * Requires MI function configuration.\n *\n * @module expansion/hae\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\nimport { jaccard } from \"../ranking/mi/jaccard\";\n\n/**\n * Configuration for HAE expansion.\n */\nexport interface HAEConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> extends ExpansionConfig<N, E> {\n\t/** MI function for computing edge priorities (default: jaccard) */\n\treadonly mi?: (\n\t\tgraph: ReadableGraph<N, E>,\n\t\tsource: string,\n\t\ttarget: string,\n\t) => number;\n}\n\n/**\n * HAE priority function.\n *\n * Priority = 1 - MI(source, neighbour)\n * Higher MI = lower priority value = explored first\n */\nfunction haePriority<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n\tmi: (graph: ReadableGraph<N, E>, source: string, target: string) => number,\n): number {\n\tconst graph = context.graph;\n\tconst frontierIndex = context.frontierIndex;\n\n\t// Get the seed node for this frontier\n\t// We need to find the predecessor to compute MI\n\tlet maxMi = 0;\n\n\t// Compute average MI to all visited nodes in this frontier\n\tlet totalMi = 0;\n\tlet count = 0;\n\n\tfor (const [visitedId, idx] of context.visitedByFrontier) {\n\t\tif (idx === frontierIndex && visitedId !== nodeId) {\n\t\t\tconst edgeMi = mi(graph, visitedId, nodeId);\n\t\t\ttotalMi += edgeMi;\n\t\t\tcount++;\n\t\t\tif (edgeMi > maxMi) {\n\t\t\t\tmaxMi = edgeMi;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Use average MI (higher = more important = lower priority value)\n\tconst avgMi = count > 0 ? totalMi / count : 0;\n\n\t// Invert so higher MI = lower priority value = expanded first\n\treturn 1 - avgMi;\n}\n\n/**\n * Run HAE expansion algorithm.\n *\n * Expands from seeds prioritising high-MI edges.\n * Useful for finding paths with strong semantic associations.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration with MI function\n * @returns Expansion result with discovered paths\n */\nexport function hae<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: HAEConfig<N, E>,\n): ExpansionResult {\n\tconst { mi = jaccard, ...restConfig } = config ?? {};\n\n\tconst priority = (nodeId: string, context: PriorityContext<N, E>): number =>\n\t\thaePriority(nodeId, context, mi);\n\n\treturn base(graph, seeds, {\n\t\t...restConfig,\n\t\tpriority,\n\t});\n}\n","/**\n * PIPE (Path Importance Priority Expansion) algorithm.\n *\n * Prioritises nodes that are more likely to be on important paths.\n * Uses betweenness-like estimation based on neighbourhood overlap.\n *\n * Useful for finding paths through \"bridge\" nodes.\n *\n * @module expansion/pipe\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\n\n/**\n * PIPE priority function.\n *\n * Priority = 1 / (1 + bridge_score)\n * Bridge score = neighbourhood overlap with other frontiers\n * Higher bridge score = more likely to be on paths = explored first\n */\nfunction pipePriority<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n): number {\n\tconst graph = context.graph;\n\tconst currentFrontier = context.frontierIndex;\n\tconst nodeNeighbours = new Set(graph.neighbours(nodeId));\n\n\t// Count how many neighbours are visited by other frontiers\n\tlet bridgeScore = 0;\n\n\tfor (const [visitedId, frontierIdx] of context.visitedByFrontier) {\n\t\tif (frontierIdx !== currentFrontier && nodeNeighbours.has(visitedId)) {\n\t\t\tbridgeScore++;\n\t\t}\n\t}\n\n\t// Also consider discovered paths - nodes on existing paths are valuable\n\tfor (const path of context.discoveredPaths) {\n\t\tif (path.nodes.includes(nodeId)) {\n\t\t\tbridgeScore += 2; // Bonus for being on discovered paths\n\t\t}\n\t}\n\n\t// Invert: higher bridge score = lower priority value = expanded first\n\treturn 1 / (1 + bridgeScore);\n}\n\n/**\n * Run PIPE expansion algorithm.\n *\n * Expands from seeds prioritising bridge nodes.\n * Useful for finding paths through structurally important nodes.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration\n * @returns Expansion result with discovered paths\n */\nexport function pipe<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: ExpansionConfig<N, E>,\n): ExpansionResult {\n\treturn base(graph, seeds, {\n\t\t...config,\n\t\tpriority: pipePriority,\n\t});\n}\n","/**\n * SAGE (Salience-Aware Graph Expansion) algorithm.\n *\n * Two-phase expansion:\n * 1. Initial DOME-style expansion to discover candidate paths\n * 2. Re-prioritise based on path salience scores\n *\n * Combines structural exploration with semantic ranking.\n *\n * @module expansion/sage\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\nimport { jaccard } from \"../ranking/mi/jaccard\";\n\n/**\n * Configuration for SAGE expansion.\n */\nexport interface SAGEConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> extends ExpansionConfig<N, E> {\n\t/** MI function for salience computation (default: jaccard) */\n\treadonly mi?: (\n\t\tgraph: ReadableGraph<N, E>,\n\t\tsource: string,\n\t\ttarget: string,\n\t) => number;\n\t/** Weight for salience component (0-1, default: 0.5) */\n\treadonly salienceWeight?: number;\n}\n\n/**\n * SAGE priority function.\n *\n * Combines degree with salience:\n * Priority = (1 - w) * degree + w * (1 - avg_salience)\n * Lower values = higher priority\n */\nfunction sagePriority<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n\tmi: (graph: ReadableGraph<N, E>, source: string, target: string) => number,\n\tsalienceWeight: number,\n): number {\n\tconst graph = context.graph;\n\tconst degree = context.degree;\n\tconst frontierIndex = context.frontierIndex;\n\n\t// Compute average salience to visited nodes in this frontier\n\tlet totalSalience = 0;\n\tlet count = 0;\n\n\tfor (const [visitedId, idx] of context.visitedByFrontier) {\n\t\tif (idx === frontierIndex && visitedId !== nodeId) {\n\t\t\ttotalSalience += mi(graph, visitedId, nodeId);\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tconst avgSalience = count > 0 ? totalSalience / count : 0;\n\n\t// Combine degree with salience\n\t// Lower priority value = expanded first\n\t// High salience should lower priority value\n\tconst degreeComponent = (1 - salienceWeight) * degree;\n\tconst salienceComponent = salienceWeight * (1 - avgSalience);\n\n\treturn degreeComponent + salienceComponent;\n}\n\n/**\n * Run SAGE expansion algorithm.\n *\n * Combines structural exploration with semantic salience.\n * Useful for finding paths that are both short and semantically meaningful.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration with MI function\n * @returns Expansion result with discovered paths\n */\nexport function sage<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: SAGEConfig<N, E>,\n): ExpansionResult {\n\tconst { mi = jaccard, salienceWeight = 0.5, ...restConfig } = config ?? {};\n\n\tconst priority = (nodeId: string, context: PriorityContext<N, E>): number =>\n\t\tsagePriority(nodeId, context, mi, salienceWeight);\n\n\treturn base(graph, seeds, {\n\t\t...restConfig,\n\t\tpriority,\n\t});\n}\n","/**\n * REACH (Rank-Enhanced Adaptive Collision Hash) algorithm.\n *\n * Two-phase expansion:\n * 1. Phase 1: Degree-ordered expansion to collect MI statistics\n * 2. Phase 2: MI-guided expansion using learned thresholds\n *\n * Adapts to graph structure by learning optimal MI thresholds.\n *\n * @module expansion/reach\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\nimport { jaccard } from \"../ranking/mi/jaccard\";\n\n/**\n * Configuration for REACH expansion.\n */\nexport interface REACHConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> extends ExpansionConfig<N, E> {\n\t/** MI function for salience computation (default: jaccard) */\n\treadonly mi?: (\n\t\tgraph: ReadableGraph<N, E>,\n\t\tsource: string,\n\t\ttarget: string,\n\t) => number;\n\t/** MI percentile threshold for phase 2 (default: 0.25) */\n\treadonly miThreshold?: number;\n\t/** Maximum nodes for phase 1 sampling (default: 1000) */\n\treadonly phase1MaxNodes?: number;\n}\n\n/**\n * REACH priority function (phase 2).\n *\n * Uses learned MI threshold to prioritise high-MI edges.\n */\nfunction reachPriority<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n\tmi: (graph: ReadableGraph<N, E>, source: string, target: string) => number,\n\tmiThreshold: number,\n): number {\n\tconst graph = context.graph;\n\tconst frontierIndex = context.frontierIndex;\n\n\t// Compute average MI to visited nodes\n\tlet totalMi = 0;\n\tlet count = 0;\n\n\tfor (const [visitedId, idx] of context.visitedByFrontier) {\n\t\tif (idx === frontierIndex && visitedId !== nodeId) {\n\t\t\ttotalMi += mi(graph, visitedId, nodeId);\n\t\t\tcount++;\n\t\t}\n\t}\n\n\tconst avgMi = count > 0 ? totalMi / count : 0;\n\n\t// If MI is above threshold, give high priority (low value)\n\t// Otherwise, fall back to degree\n\tif (avgMi >= miThreshold) {\n\t\treturn 1 - avgMi; // High MI = low priority value\n\t} else {\n\t\treturn context.degree + 100; // Low MI = delayed expansion\n\t}\n}\n\n/**\n * Run REACH expansion algorithm.\n *\n * Two-phase adaptive expansion that learns MI thresholds\n * from initial sampling, then uses them for guided expansion.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration\n * @returns Expansion result with discovered paths\n */\nexport function reach<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: REACHConfig<N, E>,\n): ExpansionResult {\n\tconst { mi = jaccard, miThreshold = 0.25, ...restConfig } = config ?? {};\n\n\t// Run guided expansion with MI threshold\n\tconst priority = (nodeId: string, context: PriorityContext<N, E>): number =>\n\t\treachPriority(nodeId, context, mi, miThreshold);\n\n\treturn base(graph, seeds, {\n\t\t...restConfig,\n\t\tpriority,\n\t});\n}\n","/**\n * MAZE (Multi-Algorithm Zone Exploration) algorithm.\n *\n * Switches between different expansion strategies based on\n * local graph density and progress.\n *\n * Strategies:\n * - Sparse regions: DOME (expand hubs)\n * - Dense regions: EDGE (expand through low-degree edges)\n * - Bridge nodes: PIPE (expand bridges)\n *\n * @module expansion/maze\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type {\n\tSeed,\n\tExpansionResult,\n\tExpansionConfig,\n\tPriorityContext,\n} from \"./types\";\nimport { base } from \"./base\";\n\n/**\n * Configuration for MAZE expansion.\n */\nexport interface MAZEConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> extends ExpansionConfig<N, E> {\n\t/** Density threshold for switching to EDGE mode (default: 0.5) */\n\treadonly densityThreshold?: number;\n\t/** Bridge threshold for switching to PIPE mode (default: 0.3) */\n\treadonly bridgeThreshold?: number;\n}\n\n/**\n * Compute local density around a node.\n */\nfunction localDensity<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tnodeId: string,\n): number {\n\tconst neighbours = Array.from(graph.neighbours(nodeId));\n\tconst degree = neighbours.length;\n\n\tif (degree < 2) {\n\t\treturn 0;\n\t}\n\n\t// Count edges among neighbours\n\tlet edges = 0;\n\tfor (let i = 0; i < neighbours.length; i++) {\n\t\tfor (let j = i + 1; j < neighbours.length; j++) {\n\t\t\tconst ni = neighbours[i];\n\t\t\tconst nj = neighbours[j];\n\t\t\tif (\n\t\t\t\tni !== undefined &&\n\t\t\t\tnj !== undefined &&\n\t\t\t\tgraph.getEdge(ni, nj) !== undefined\n\t\t\t) {\n\t\t\t\tedges++;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst maxEdges = (degree * (degree - 1)) / 2;\n\treturn edges / maxEdges;\n}\n\n/**\n * Compute bridge score (how many other frontiers visit neighbours).\n */\nfunction bridgeScore<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n): number {\n\tconst currentFrontier = context.frontierIndex;\n\tconst nodeNeighbours = new Set(context.graph.neighbours(nodeId));\n\n\tlet score = 0;\n\tfor (const [visitedId, idx] of context.visitedByFrontier) {\n\t\tif (idx !== currentFrontier && nodeNeighbours.has(visitedId)) {\n\t\t\tscore++;\n\t\t}\n\t}\n\n\treturn score;\n}\n\n/**\n * MAZE adaptive priority function.\n *\n * Switches strategies based on local conditions:\n * - High density + low bridge: EDGE mode\n * - Low density + low bridge: DOME mode\n * - High bridge score: PIPE mode\n */\nfunction mazePriority<N extends NodeData, E extends EdgeData>(\n\tnodeId: string,\n\tcontext: PriorityContext<N, E>,\n\tdensityThreshold: number,\n\tbridgeThreshold: number,\n): number {\n\tconst graph = context.graph;\n\tconst degree = context.degree;\n\n\t// Compute local metrics\n\tconst density = localDensity(graph, nodeId);\n\tconst bridge = bridgeScore(nodeId, context);\n\n\t// Normalise bridge score by number of frontiers\n\tconst numFrontiers = new Set(context.visitedByFrontier.values()).size;\n\tconst normalisedBridge = numFrontiers > 0 ? bridge / numFrontiers : 0;\n\n\t// Select strategy\n\tif (normalisedBridge >= bridgeThreshold) {\n\t\t// PIPE mode: prioritise bridges\n\t\treturn 1 / (1 + bridge);\n\t} else if (density >= densityThreshold) {\n\t\t// EDGE mode: avoid dense regions, expand through sparse edges\n\t\treturn -degree; // Negative to prioritise low degree\n\t} else {\n\t\t// DOME mode: expand hubs first\n\t\treturn degree;\n\t}\n}\n\n/**\n * Run MAZE expansion algorithm.\n *\n * Adaptively switches between expansion strategies based on\n * local graph structure. Useful for heterogeneous graphs\n * with varying density.\n *\n * @param graph - Source graph\n * @param seeds - Seed nodes for expansion\n * @param config - Expansion configuration\n * @returns Expansion result with discovered paths\n */\nexport function maze<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tseeds: readonly Seed[],\n\tconfig?: MAZEConfig<N, E>,\n): ExpansionResult {\n\tconst {\n\t\tdensityThreshold = 0.5,\n\t\tbridgeThreshold = 0.3,\n\t\t...restConfig\n\t} = config ?? {};\n\n\tconst priority = (nodeId: string, context: PriorityContext<N, E>): number =>\n\t\tmazePriority(nodeId, context, densityThreshold, bridgeThreshold);\n\n\treturn base(graph, seeds, {\n\t\t...restConfig,\n\t\tpriority,\n\t});\n}\n","/**\n * PARSE (Path-Aware Ranking via Salience Estimation).\n *\n * Ranks discovered paths by computing geometric mean of edge MI scores.\n * Path salience = (∏ MI(uᵢ, uᵢ₊₁))^(1/|path|)\n *\n * This ranking is length-unbiased: shorter paths with strong edges\n * can outrank longer paths with weak edges.\n *\n * @module ranking/parse\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport type { ExpansionPath } from \"../expansion/types\";\nimport type { MIFunction } from \"./mi/types\";\nimport { jaccard } from \"./mi/jaccard\";\n\n/**\n * Configuration for PARSE ranking.\n */\nexport interface PARSEConfig<\n\tN extends NodeData = NodeData,\n\tE extends EdgeData = EdgeData,\n> {\n\t/** MI function to use (default: jaccard) */\n\treadonly mi?: MIFunction<N, E>;\n\t/** Minimum epsilon for MI (default: 1e-10) */\n\treadonly epsilon?: number;\n\t/** Whether to include salience scores in result (default: true) */\n\treadonly includeSalience?: boolean;\n}\n\n/**\n * A ranked path with salience score.\n */\nexport interface RankedPath extends ExpansionPath {\n\t/** Salience score (geometric mean of edge MI) */\n\treadonly salience: number;\n}\n\n/**\n * Result of PARSE ranking.\n */\nexport interface PARSEResult {\n\t/** Paths ranked by salience (highest first) */\n\treadonly paths: readonly RankedPath[];\n\t/** Ranking statistics */\n\treadonly stats: {\n\t\t/** Total paths ranked */\n\t\treadonly pathsRanked: number;\n\t\t/** Mean salience */\n\t\treadonly meanSalience: number;\n\t\t/** Median salience */\n\t\treadonly medianSalience: number;\n\t\t/** Maximum salience */\n\t\treadonly maxSalience: number;\n\t\t/** Minimum salience */\n\t\treadonly minSalience: number;\n\t\t/** Ranking duration in milliseconds */\n\t\treadonly durationMs: number;\n\t};\n}\n\n/**\n * Rank paths using PARSE (Path-Aware Ranking via Salience Estimation).\n *\n * Computes geometric mean of edge MI scores for each path,\n * then sorts by salience (highest first).\n *\n * @param graph - Source graph\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths with statistics\n */\nexport function parse<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: PARSEConfig<N, E>,\n): PARSEResult {\n\tconst startTime = performance.now();\n\n\tconst { mi = jaccard, epsilon = 1e-10 } = config ?? {};\n\n\tconst rankedPaths: RankedPath[] = [];\n\n\tfor (const path of paths) {\n\t\tconst salience = computePathSalience(graph, path, mi, epsilon);\n\t\trankedPaths.push({\n\t\t\t...path,\n\t\t\tsalience,\n\t\t});\n\t}\n\n\t// Sort by salience descending\n\trankedPaths.sort((a, b) => b.salience - a.salience);\n\n\tconst endTime = performance.now();\n\n\t// Compute statistics\n\tconst saliences = rankedPaths.map((p) => p.salience);\n\tconst meanSalience =\n\t\tsaliences.length > 0\n\t\t\t? saliences.reduce((a, b) => a + b, 0) / saliences.length\n\t\t\t: 0;\n\tconst sortedSaliences = [...saliences].sort((a, b) => a - b);\n\tconst mid = Math.floor(sortedSaliences.length / 2);\n\tconst medianSalience =\n\t\tsortedSaliences.length > 0\n\t\t\t? sortedSaliences.length % 2 !== 0\n\t\t\t\t? (sortedSaliences[mid] ?? 0)\n\t\t\t\t: ((sortedSaliences[mid - 1] ?? 0) + (sortedSaliences[mid] ?? 0)) / 2\n\t\t\t: 0;\n\tconst maxSalience =\n\t\tsortedSaliences.length > 0\n\t\t\t? (sortedSaliences[sortedSaliences.length - 1] ?? 0)\n\t\t\t: 0;\n\tconst minSalience =\n\t\tsortedSaliences.length > 0 ? (sortedSaliences[0] ?? 0) : 0;\n\n\treturn {\n\t\tpaths: rankedPaths,\n\t\tstats: {\n\t\t\tpathsRanked: rankedPaths.length,\n\t\t\tmeanSalience,\n\t\t\tmedianSalience,\n\t\t\tmaxSalience,\n\t\t\tminSalience,\n\t\t\tdurationMs: endTime - startTime,\n\t\t},\n\t};\n}\n\n/**\n * Compute salience for a single path.\n *\n * Uses geometric mean of edge MI scores for length-unbiased ranking.\n */\nfunction computePathSalience<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tpath: ExpansionPath,\n\tmi: MIFunction<N, E>,\n\tepsilon: number,\n): number {\n\tconst nodes = path.nodes;\n\n\tif (nodes.length < 2) {\n\t\treturn epsilon;\n\t}\n\n\t// Compute MI for each edge\n\tlet productMi = 1;\n\tlet edgeCount = 0;\n\n\tfor (let i = 0; i < nodes.length - 1; i++) {\n\t\tconst source = nodes[i];\n\t\tconst target = nodes[i + 1];\n\n\t\tif (source !== undefined && target !== undefined) {\n\t\t\tconst edgeMi = mi(graph, source, target);\n\t\t\tproductMi *= Math.max(epsilon, edgeMi);\n\t\t\tedgeCount++;\n\t\t}\n\t}\n\n\tif (edgeCount === 0) {\n\t\treturn epsilon;\n\t}\n\n\t// Geometric mean\n\tconst salience = Math.pow(productMi, 1 / edgeCount);\n\treturn Math.max(epsilon, Math.min(1, salience));\n}\n","/**\n * Adamic-Adar index for edge salience.\n *\n * Sum of inverse log degrees of common neighbours:\n * MI(u,v) = Σ_{z ∈ N(u) ∩ N(v)} 1 / log(deg(z))\n *\n * Range: [0, ∞) - higher values indicate stronger association\n * Normalised to [0, 1] by dividing by max possible value.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute Adamic-Adar index between neighbourhoods of two nodes.\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @param config - Optional configuration\n * @returns Adamic-Adar index (normalised to [0, 1] if configured)\n */\nexport function adamicAdar<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10, normalise = true } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\t// Compute common neighbours and sum inverse log degrees\n\tlet score = 0;\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tconst degree = graph.degree(neighbour);\n\t\t\tif (degree > 1) {\n\t\t\t\tscore += 1 / Math.log(degree);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalise to [0, 1] if requested\n\tif (normalise) {\n\t\t// Max possible is when all common neighbours have degree 2 (minimum for log)\n\t\t// This is a heuristic normalisation\n\t\tconst commonCount =\n\t\t\tsourceNeighbours.size < targetNeighbours.size\n\t\t\t\t? sourceNeighbours.size\n\t\t\t\t: targetNeighbours.size;\n\t\tif (commonCount === 0) {\n\t\t\treturn 0;\n\t\t}\n\t\tconst maxScore = commonCount / Math.log(2);\n\t\tscore = score / maxScore;\n\t}\n\n\t// Apply epsilon floor for numerical stability\n\treturn Math.max(epsilon, score);\n}\n","/**\n * SCALE (Structural Coherence via Adjacency Lattice Entropy) MI variant.\n *\n * Combines Jaccard similarity with degree ratio to capture both\n * neighbourhood overlap and degree balance.\n *\n * SCALE(u,v) = 2 * Jaccard(u,v) * deg_ratio / (Jaccard(u,v) + deg_ratio)\n * where deg_ratio = min(deg(u), deg(v)) / max(deg(u), deg(v))\n *\n * Range: [0, 1]\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute SCALE MI between two nodes.\n */\nexport function scale<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10 } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\tconst sourceDegree = sourceNeighbours.size;\n\tconst targetDegree = targetNeighbours.size;\n\n\t// Compute Jaccard\n\tlet intersectionSize = 0;\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tintersectionSize++;\n\t\t}\n\t}\n\n\tconst unionSize = sourceDegree + targetDegree - intersectionSize;\n\tconst jaccard = unionSize > 0 ? intersectionSize / unionSize : 0;\n\n\t// Compute degree ratio\n\tconst minDegree = Math.min(sourceDegree, targetDegree);\n\tconst maxDegree = Math.max(sourceDegree, targetDegree);\n\tconst degreeRatio = maxDegree > 0 ? minDegree / maxDegree : 0;\n\n\t// Harmonic mean combination\n\tif (jaccard + degreeRatio === 0) {\n\t\treturn epsilon;\n\t}\n\n\tconst score = (2 * jaccard * degreeRatio) / (jaccard + degreeRatio);\n\n\treturn Math.max(epsilon, Math.min(1, score));\n}\n","/**\n * SKEW (Structural Kernel Entropy Weighting) MI variant.\n *\n * Weights neighbours by inverse degree (like Adamic-Adar) but\n * also considers the skew of the degree distribution.\n *\n * SKEW(u,v) = sum_{w in N(u) ∩ N(v)} 1 / log(deg(w) + 1)\n * / max weighted intersection possible\n *\n * Range: [0, 1]\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute SKEW MI between two nodes.\n */\nexport function skew<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10 } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\t// Compute weighted intersection (Adamic-Adar style)\n\tlet weightedIntersection = 0;\n\tlet commonCount = 0;\n\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tcommonCount++;\n\t\t\tconst degree = graph.degree(neighbour);\n\t\t\tif (degree > 1) {\n\t\t\t\tweightedIntersection += 1 / Math.log(degree);\n\t\t\t}\n\t\t}\n\t}\n\n\tif (commonCount === 0) {\n\t\treturn epsilon;\n\t}\n\n\t// Normalise by theoretical maximum\n\tconst sourceDegree = sourceNeighbours.size;\n\tconst targetDegree = targetNeighbours.size;\n\tconst minDegree = Math.min(sourceDegree, targetDegree);\n\n\t// Approximate max score\n\tconst maxScore = minDegree / Math.log(2);\n\tconst score = weightedIntersection / maxScore;\n\n\treturn Math.max(epsilon, Math.min(1, score));\n}\n","/**\n * SPAN (Structural Pattern ANalysis) MI variant.\n *\n * Combines Jaccard with degree similarity to capture both\n * neighbourhood overlap and structural equivalence.\n *\n * SPAN(u,v) = sqrt(Jaccard(u,v) * deg_similarity)\n * where deg_similarity = 1 - |deg(u) - deg(v)| / max(deg(u), deg(v))\n *\n * Range: [0, 1]\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute SPAN MI between two nodes.\n */\nexport function span<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10 } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\tconst sourceDegree = sourceNeighbours.size;\n\tconst targetDegree = targetNeighbours.size;\n\n\t// Compute Jaccard\n\tlet intersectionSize = 0;\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tintersectionSize++;\n\t\t}\n\t}\n\n\tconst unionSize = sourceDegree + targetDegree - intersectionSize;\n\tconst jaccard = unionSize > 0 ? intersectionSize / unionSize : 0;\n\n\t// Compute degree similarity\n\tconst maxDegree = Math.max(sourceDegree, targetDegree);\n\tconst degreeDiff = Math.abs(sourceDegree - targetDegree);\n\tconst degreeSimilarity = maxDegree > 0 ? 1 - degreeDiff / maxDegree : 1;\n\n\t// Geometric mean combination\n\tconst score = Math.sqrt(jaccard * degreeSimilarity);\n\n\treturn Math.max(epsilon, Math.min(1, score));\n}\n","/**\n * ETCH (Edge Topology Coherence via Homophily) MI variant.\n *\n * Measures the density of connections among common neighbours,\n * capturing structural cohesion around the edge.\n *\n * ETCH(u,v) = weighted combination of:\n * - Joint density: edges among N(u) ∩ N(v)\n * - Common density: edges from (u,v) to common neighbours\n *\n * Range: [0, 1]\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute ETCH MI between two nodes.\n */\nexport function etch<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10 } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\t// Find common neighbours\n\tconst commonNeighbours: NodeId[] = [];\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tcommonNeighbours.push(neighbour);\n\t\t}\n\t}\n\n\tif (commonNeighbours.length < 2) {\n\t\treturn epsilon;\n\t}\n\n\t// Component 1: Joint density (edges among common neighbours)\n\tlet jointEdges = 0;\n\tfor (let i = 0; i < commonNeighbours.length; i++) {\n\t\tfor (let j = i + 1; j < commonNeighbours.length; j++) {\n\t\t\tconst ni = commonNeighbours[i];\n\t\t\tconst nj = commonNeighbours[j];\n\t\t\tif (\n\t\t\t\tni !== undefined &&\n\t\t\t\tnj !== undefined &&\n\t\t\t\tgraph.getEdge(ni, nj) !== undefined\n\t\t\t) {\n\t\t\t\tjointEdges++;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst maxJointEdges =\n\t\t(commonNeighbours.length * (commonNeighbours.length - 1)) / 2;\n\tconst jointDensity = maxJointEdges > 0 ? jointEdges / maxJointEdges : 0;\n\n\t// Component 2: Common density (edges from endpoints to common neighbours)\n\tlet commonEdges = 0;\n\tfor (const cn of commonNeighbours) {\n\t\tif (graph.getEdge(source, cn) !== undefined) {\n\t\t\tcommonEdges++;\n\t\t}\n\t\tif (graph.getEdge(target, cn) !== undefined) {\n\t\t\tcommonEdges++;\n\t\t}\n\t}\n\n\tconst maxCommonEdges = commonNeighbours.length * 2;\n\tconst commonDensity = maxCommonEdges > 0 ? commonEdges / maxCommonEdges : 0;\n\n\t// Weighted combination\n\tconst score = jointDensity * 0.7 + commonDensity * 0.3;\n\n\treturn Math.max(epsilon, Math.min(1, score));\n}\n","/**\n * NOTCH (Neighbourhood Overlap Topology Coherence via Homophily) MI variant.\n *\n * Combines neighbourhood overlap with degree correlation to capture\n * both local structure and global position similarity.\n *\n * NOTCH(u,v) = overlap * 0.6 + degree_correlation * 0.4\n *\n * Range: [0, 1]\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { MIConfig } from \"./types\";\n\n/**\n * Compute NOTCH MI between two nodes.\n */\nexport function notch<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: MIConfig,\n): number {\n\tconst { epsilon = 1e-10 } = config ?? {};\n\n\t// Get neighbourhoods\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\n\t// Remove self-references\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\tconst sourceDegree = sourceNeighbours.size;\n\tconst targetDegree = targetNeighbours.size;\n\n\t// Component 1: Overlap coefficient\n\tlet intersectionSize = 0;\n\tfor (const neighbour of sourceNeighbours) {\n\t\tif (targetNeighbours.has(neighbour)) {\n\t\t\tintersectionSize++;\n\t\t}\n\t}\n\n\tconst minDegree = Math.min(sourceDegree, targetDegree);\n\tconst overlap = minDegree > 0 ? intersectionSize / minDegree : 0;\n\n\t// Component 2: Degree correlation (similarity to ideal degree match)\n\tconst maxDegree = Math.max(sourceDegree, targetDegree);\n\tconst correlation =\n\t\tmaxDegree > 0 ? 1 - Math.abs(sourceDegree - targetDegree) / maxDegree : 1;\n\n\t// Weighted combination\n\tconst score = overlap * 0.6 + correlation * 0.4;\n\n\treturn Math.max(epsilon, Math.min(1, score));\n}\n","/**\n * Unified Adaptive MI - combines multiple MI signals dynamically.\n *\n * Adapts to graph structure by weighting different MI components\n * based on local graph properties.\n *\n * Range: [0, 1] - higher values indicate stronger association\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { AdaptiveMIConfig } from \"./types\";\nimport { jaccard } from \"./jaccard\";\nimport { adamicAdar } from \"./adamic-adar\";\n\n/**\n * Compute unified adaptive MI between two connected nodes.\n *\n * Combines structural, degree, and overlap signals with\n * adaptive weighting based on graph density.\n *\n * @param graph - Source graph\n * @param source - Source node ID\n * @param target - Target node ID\n * @param config - Optional configuration with component weights\n * @returns Adaptive MI score in [0, 1]\n */\nexport function adaptive<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsource: NodeId,\n\ttarget: NodeId,\n\tconfig?: AdaptiveMIConfig,\n): number {\n\tconst {\n\t\tepsilon = 1e-10,\n\t\tstructuralWeight = 0.4,\n\t\tdegreeWeight = 0.3,\n\t\toverlapWeight = 0.3,\n\t} = config ?? {};\n\n\t// Component 1: Structural similarity (Jaccard)\n\tconst structural = jaccard(graph, source, target, { epsilon });\n\n\t// Component 2: Degree-weighted association (Adamic-Adar, normalised)\n\tconst degreeComponent = adamicAdar(graph, source, target, {\n\t\tepsilon,\n\t\tnormalise: true,\n\t});\n\n\t// Component 3: Overlap coefficient\n\tconst sourceNeighbours = new Set(graph.neighbours(source));\n\tconst targetNeighbours = new Set(graph.neighbours(target));\n\tsourceNeighbours.delete(target);\n\ttargetNeighbours.delete(source);\n\n\tconst sourceDegree = sourceNeighbours.size;\n\tconst targetDegree = targetNeighbours.size;\n\n\tlet overlap: number;\n\tif (sourceDegree > 0 && targetDegree > 0) {\n\t\tlet commonCount = 0;\n\t\tfor (const n of sourceNeighbours) {\n\t\t\tif (targetNeighbours.has(n)) {\n\t\t\t\tcommonCount++;\n\t\t\t}\n\t\t}\n\t\tconst minDegree = Math.min(sourceDegree, targetDegree);\n\t\toverlap = commonCount / minDegree;\n\t} else {\n\t\toverlap = epsilon;\n\t}\n\n\t// Normalise weights\n\tconst totalWeight = structuralWeight + degreeWeight + overlapWeight;\n\n\t// Weighted combination\n\tconst score =\n\t\t(structuralWeight * structural +\n\t\t\tdegreeWeight * degreeComponent +\n\t\t\toverlapWeight * overlap) /\n\t\ttotalWeight;\n\n\treturn Math.max(epsilon, Math.min(1, score));\n}\n","/**\n * Shortest path baseline ranking.\n *\n * Ranks paths by length (shorter = higher score).\n * Score = 1 / length (normalised).\n */\n\nimport type { NodeData, EdgeData, ReadableGraph } from \"../../graph\";\nimport type { ExpansionPath } from \"../../expansion/types\";\nimport type { BaselineConfig, BaselineResult, ScoredPath } from \"./types\";\n\n/**\n * Rank paths by length (shortest first).\n *\n * Score = 1 / path_length, normalised to [0, 1].\n *\n * @param _graph - Source graph (unused for length ranking)\n * @param paths - Paths to rank\n * @param config - Configuration options\n * @returns Ranked paths (shortest first)\n */\nexport function shortest<N extends NodeData, E extends EdgeData>(\n\t_graph: ReadableGraph<N, E>,\n\tpaths: readonly ExpansionPath[],\n\tconfig?: BaselineConfig,\n): BaselineResult {\n\tconst { includeScores = true } = config ?? {};\n\n\tif (paths.length === 0) {\n\t\treturn {\n\t\t\tpaths: [],\n\t\t\tmethod: \"shortest\",\n\t\t};\n\t}\n\n\t// Compute raw scores (1 / length)\n\tconst scored: { path: ExpansionPath; score: number }[] = paths.map(\n\t\t(path) => ({\n\t\t\tpath,\n\t\t\tscore: 1 / path.nodes.length,\n\t\t}),\n\t);\n\n\t// Find max for normalisation\n\tconst maxScore = Math.max(...scored.map((s) => s.score));\n\n\t// Normalise and sort\n\tconst ranked: ScoredPath[] = scored\n\t\t.map(({ path, score }) => ({\n\t\t\t...path,\n\t\t\tscore: includeScores ? score / maxScore : score / maxScore,\n\t\t}))\n\t\t.sort((a, b) => b.score - a.score);\n\n\treturn {\n\t\tpaths: ranked,\n\t\tmethod: \"shortest\",\n\t};\n}\n","/**\n * Ego-network (k-hop neighbourhood) extraction.\n *\n * Extracts the induced subgraph of all nodes within k hops of a centre node.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport { AdjacencyMapGraph } from \"../graph/adjacency-map\";\n\n/**\n * Options for ego-network extraction.\n */\nexport interface EgoNetworkOptions {\n\t/** Number of hops from the centre node. Default: 1. */\n\treadonly hops?: number;\n}\n\n/**\n * Extract the ego-network (k-hop neighbourhood) of a centre node.\n *\n * The ego-network includes all nodes reachable within k hops from the\n * centre node, plus all edges between those nodes (induced subgraph).\n *\n * For directed graphs, the search follows outgoing edges by default.\n * To include incoming edges, use direction 'both' in the underlying traversal.\n *\n * @param graph - The source graph\n * @param centre - The centre node ID\n * @param options - Extraction options\n * @returns An induced subgraph of the k-hop neighbourhood\n * @throws Error if the centre node does not exist in the graph\n *\n * @example\n * ```typescript\n * // 2-hop neighbourhood\n * const ego = extractEgoNetwork(graph, 'A', { hops: 2 });\n * ```\n */\nexport function extractEgoNetwork<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tcentre: NodeId,\n\toptions?: EgoNetworkOptions,\n): AdjacencyMapGraph<N, E> {\n\tconst hops = options?.hops ?? 1;\n\n\tif (!graph.hasNode(centre)) {\n\t\tthrow new Error(`Centre node '${centre}' does not exist in the graph`);\n\t}\n\n\tif (hops < 0) {\n\t\tthrow new Error(`Hops must be non-negative, got ${String(hops)}`);\n\t}\n\n\t// Find all nodes within k hops using BFS\n\tconst nodesInEgoNetwork = new Set<NodeId>([centre]);\n\n\tif (hops > 0) {\n\t\tconst visited = new Set<NodeId>([centre]);\n\t\t// Queue entries: [nodeId, distance from centre]\n\t\tconst queue: [NodeId, number][] = [[centre, 0]];\n\n\t\twhile (queue.length > 0) {\n\t\t\tconst entry = queue.shift();\n\t\t\tif (entry === undefined) break;\n\t\t\tconst [current, distance] = entry;\n\n\t\t\tif (distance < hops) {\n\t\t\t\tfor (const neighbour of graph.neighbours(current)) {\n\t\t\t\t\tif (!visited.has(neighbour)) {\n\t\t\t\t\t\tvisited.add(neighbour);\n\t\t\t\t\t\tnodesInEgoNetwork.add(neighbour);\n\t\t\t\t\t\tqueue.push([neighbour, distance + 1]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Build induced subgraph\n\tconst result = graph.directed\n\t\t? AdjacencyMapGraph.directed<N, E>()\n\t\t: AdjacencyMapGraph.undirected<N, E>();\n\n\t// Add nodes\n\tfor (const nodeId of nodesInEgoNetwork) {\n\t\tconst nodeData = graph.getNode(nodeId);\n\t\tif (nodeData !== undefined) {\n\t\t\tresult.addNode(nodeData);\n\t\t}\n\t}\n\n\t// Add edges between nodes in the ego network\n\tfor (const edge of graph.edges()) {\n\t\tif (\n\t\t\tnodesInEgoNetwork.has(edge.source) &&\n\t\t\tnodesInEgoNetwork.has(edge.target)\n\t\t) {\n\t\t\tresult.addEdge(edge);\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * K-core decomposition algorithm.\n *\n * A k-core is the maximal subgraph where every node has degree at least k.\n * The decomposition is computed by iteratively removing nodes with degree < k.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport { AdjacencyMapGraph } from \"../graph/adjacency-map\";\n\n/**\n * Extract the k-core of a graph.\n *\n * The k-core is the maximal connected subgraph where every node has\n * degree at least k. This is computed using a peeling algorithm that\n * iteratively removes nodes with degree less than k.\n *\n * For undirected graphs, degree counts all adjacent nodes.\n * For directed graphs, degree counts both in- and out-neighbours.\n *\n * @param graph - The source graph\n * @param k - The minimum degree threshold\n * @returns A new graph containing the k-core (may be empty)\n *\n * @example\n * ```typescript\n * // Extract the 3-core (nodes with at least 3 neighbours)\n * const core3 = extractKCore(graph, 3);\n * ```\n */\nexport function extractKCore<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tk: number,\n): AdjacencyMapGraph<N, E> {\n\tif (k < 0) {\n\t\tthrow new Error(`k must be non-negative, got ${String(k)}`);\n\t}\n\n\t// Track remaining nodes and their degrees\n\tconst remaining = new Set<NodeId>();\n\tconst degrees = new Map<NodeId, number>();\n\n\tfor (const nodeId of graph.nodeIds()) {\n\t\tremaining.add(nodeId);\n\t\t// For directed graphs, use total degree (both directions)\n\t\tconst deg = graph.directed\n\t\t\t? graph.degree(nodeId, \"both\")\n\t\t\t: graph.degree(nodeId);\n\t\tdegrees.set(nodeId, deg);\n\t}\n\n\t// Use a queue for nodes to remove (degree < k)\n\tconst toRemove: NodeId[] = [];\n\n\tfor (const [nodeId, deg] of degrees) {\n\t\tif (deg < k) {\n\t\t\ttoRemove.push(nodeId);\n\t\t}\n\t}\n\n\t// Iteratively remove nodes with degree < k\n\twhile (toRemove.length > 0) {\n\t\tconst nodeId = toRemove.shift();\n\t\tif (nodeId === undefined) break;\n\n\t\tif (!remaining.has(nodeId)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tremaining.delete(nodeId);\n\n\t\t// Update degrees of neighbours\n\t\tconst neighbours = graph.directed\n\t\t\t? graph.neighbours(nodeId, \"both\")\n\t\t\t: graph.neighbours(nodeId);\n\n\t\tfor (const neighbour of neighbours) {\n\t\t\tif (remaining.has(neighbour)) {\n\t\t\t\tconst currentDeg = degrees.get(neighbour) ?? 0;\n\t\t\t\tconst newDeg = currentDeg - 1;\n\t\t\t\tdegrees.set(neighbour, newDeg);\n\n\t\t\t\tif (newDeg < k && newDeg === k - 1) {\n\t\t\t\t\t// Only add to queue if crossing below k threshold\n\t\t\t\t\ttoRemove.push(neighbour);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Build the result as an induced subgraph\n\tconst result = graph.directed\n\t\t? AdjacencyMapGraph.directed<N, E>()\n\t\t: AdjacencyMapGraph.undirected<N, E>();\n\n\t// Add remaining nodes\n\tfor (const nodeId of remaining) {\n\t\tconst nodeData = graph.getNode(nodeId);\n\t\tif (nodeData !== undefined) {\n\t\t\tresult.addNode(nodeData);\n\t\t}\n\t}\n\n\t// Add edges between remaining nodes\n\tfor (const edge of graph.edges()) {\n\t\tif (remaining.has(edge.source) && remaining.has(edge.target)) {\n\t\t\tresult.addEdge(edge);\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * K-truss decomposition algorithm.\n *\n * A k-truss is the maximal subgraph where every edge participates in at\n * least k-2 triangles. The 2-truss is the entire graph, the 3-truss\n * requires each edge to be in at least one triangle, etc.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport { AdjacencyMapGraph } from \"../graph/adjacency-map\";\n\n/**\n * Count triangles involving a given edge.\n *\n * For an edge (u, v), count common neighbours of u and v.\n * Each common neighbour w forms a triangle u-v-w.\n *\n * @param graph - The graph\n * @param u - First endpoint\n * @param v - Second endpoint\n * @returns Number of triangles containing the edge (u, v)\n */\nfunction countEdgeTriangles(\n\tgraph: ReadableGraph,\n\tu: NodeId,\n\tv: NodeId,\n): number {\n\tconst uNeighbours = new Set(graph.neighbours(u));\n\tlet count = 0;\n\n\tfor (const w of graph.neighbours(v)) {\n\t\tif (w !== u && uNeighbours.has(w)) {\n\t\t\tcount++;\n\t\t}\n\t}\n\n\treturn count;\n}\n\n/**\n * Extract the k-truss of a graph.\n *\n * The k-truss is the maximal subgraph where every edge participates in\n * at least k-2 triangles. This is computed by iteratively removing edges\n * with fewer than k-2 triangles, then removing isolated nodes.\n *\n * Note: K-truss is typically defined for undirected graphs. For directed\n * graphs, this treats the graph as undirected for triangle counting.\n *\n * @param graph - The source graph\n * @param k - The minimum triangle count threshold (edge must be in >= k-2 triangles)\n * @returns A new graph containing the k-truss (may be empty)\n *\n * @example\n * ```typescript\n * // Extract the 3-truss (edges in at least 1 triangle)\n * const truss3 = extractKTruss(graph, 3);\n * ```\n */\nexport function extractKTruss<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tk: number,\n): AdjacencyMapGraph<N, E> {\n\tif (k < 2) {\n\t\tthrow new Error(`k must be at least 2, got ${String(k)}`);\n\t}\n\n\tconst minTriangles = k - 2;\n\n\t// Build undirected adjacency for triangle counting\n\t// Store as Map<NodeId, Set<NodeId>> for efficient lookup\n\tconst adjacency = new Map<NodeId, Set<NodeId>>();\n\tconst edgeData = new Map<string, E>();\n\tconst remainingEdges = new Set<string>();\n\n\tfor (const nodeId of graph.nodeIds()) {\n\t\tadjacency.set(nodeId, new Set());\n\t}\n\n\t// Build adjacency (treating as undirected)\n\tfor (const edge of graph.edges()) {\n\t\tconst { source, target } = edge;\n\n\t\t// Add to adjacency (both directions)\n\t\tadjacency.get(source)?.add(target);\n\t\tadjacency.get(target)?.add(source);\n\n\t\t// Store edge data with canonical key\n\t\tconst key =\n\t\t\tsource < target ? `${source}::${target}` : `${target}::${source}`;\n\t\tedgeData.set(key, edge);\n\t\tremainingEdges.add(key);\n\t}\n\n\t// Compute initial triangle counts for each edge\n\tconst triangleCounts = new Map<string, number>();\n\tconst edgesToRemove: string[] = [];\n\n\tfor (const key of remainingEdges) {\n\t\tconst edge = edgeData.get(key);\n\t\tif (edge !== undefined) {\n\t\t\tconst count = countEdgeTriangles(graph, edge.source, edge.target);\n\t\t\ttriangleCounts.set(key, count);\n\t\t\tif (count < minTriangles) {\n\t\t\t\tedgesToRemove.push(key);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Iteratively remove edges with insufficient triangles\n\twhile (edgesToRemove.length > 0) {\n\t\tconst edgeKey = edgesToRemove.shift();\n\t\tif (edgeKey === undefined) break;\n\n\t\tif (!remainingEdges.has(edgeKey)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tremainingEdges.delete(edgeKey);\n\t\tconst edge = edgeData.get(edgeKey);\n\n\t\tif (edge === undefined) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst { source, target } = edge;\n\n\t\t// Remove from adjacency\n\t\tadjacency.get(source)?.delete(target);\n\t\tadjacency.get(target)?.delete(source);\n\n\t\t// Find triangles that were broken and update counts\n\t\t// Common neighbours form triangles (source, target, neighbour)\n\t\tconst sourceNeighbours = adjacency.get(source);\n\t\tif (sourceNeighbours !== undefined) {\n\t\t\tfor (const w of adjacency.get(target) ?? []) {\n\t\t\t\tif (sourceNeighbours.has(w)) {\n\t\t\t\t\t// Triangle (source, target, w) is broken\n\t\t\t\t\t// Update triangle counts for edges (source, w) and (target, w)\n\t\t\t\t\tconst keySw = source < w ? `${source}::${w}` : `${w}::${source}`;\n\t\t\t\t\tconst keyTw = target < w ? `${target}::${w}` : `${w}::${target}`;\n\n\t\t\t\t\tfor (const keyToUpdate of [keySw, keyTw]) {\n\t\t\t\t\t\tif (remainingEdges.has(keyToUpdate)) {\n\t\t\t\t\t\t\tconst currentCount = triangleCounts.get(keyToUpdate) ?? 0;\n\t\t\t\t\t\t\tconst newCount = currentCount - 1;\n\t\t\t\t\t\t\ttriangleCounts.set(keyToUpdate, newCount);\n\n\t\t\t\t\t\t\tif (newCount < minTriangles && newCount === minTriangles - 1) {\n\t\t\t\t\t\t\t\tedgesToRemove.push(keyToUpdate);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// Determine which nodes are still connected by remaining edges\n\tconst nodesWithEdges = new Set<NodeId>();\n\tfor (const key of remainingEdges) {\n\t\tconst edge = edgeData.get(key);\n\t\tif (edge !== undefined) {\n\t\t\tnodesWithEdges.add(edge.source);\n\t\t\tnodesWithEdges.add(edge.target);\n\t\t}\n\t}\n\n\t// Build the result\n\tconst result = graph.directed\n\t\t? AdjacencyMapGraph.directed<N, E>()\n\t\t: AdjacencyMapGraph.undirected<N, E>();\n\n\t// Add nodes that have at least one remaining edge\n\tfor (const nodeId of nodesWithEdges) {\n\t\tconst nodeData = graph.getNode(nodeId);\n\t\tif (nodeData !== undefined) {\n\t\t\tresult.addNode(nodeData);\n\t\t}\n\t}\n\n\t// Add remaining edges\n\tfor (const key of remainingEdges) {\n\t\tconst edge = edgeData.get(key);\n\t\tif (\n\t\t\tedge !== undefined &&\n\t\t\tresult.hasNode(edge.source) &&\n\t\t\tresult.hasNode(edge.target)\n\t\t) {\n\t\t\tresult.addEdge(edge);\n\t\t}\n\t}\n\n\treturn result;\n}\n\n/**\n * Compute the truss number for each edge.\n *\n * The truss number of an edge is the largest k such that the edge\n * belongs to the k-truss.\n *\n * @param graph - The source graph\n * @returns Map from edge key (canonical \"u::v\") to truss number\n *\n * @example\n * ```typescript\n * const trussNumbers = computeTrussNumbers(graph);\n * const edgeKey = 'A::B'; // where A < B lexicographically\n * console.log(`Edge A-B is in the ${trussNumbers.get(edgeKey)}-truss`);\n * ```\n */\nexport function computeTrussNumbers<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n): Map<string, number> {\n\t// Build adjacency and edge tracking\n\tconst adjacency = new Map<NodeId, Set<NodeId>>();\n\tconst edgeData = new Map<string, E>();\n\tconst remainingEdges = new Set<string>();\n\n\tfor (const nodeId of graph.nodeIds()) {\n\t\tadjacency.set(nodeId, new Set());\n\t}\n\n\tfor (const edge of graph.edges()) {\n\t\tconst { source, target } = edge;\n\t\tadjacency.get(source)?.add(target);\n\t\tadjacency.get(target)?.add(source);\n\n\t\tconst key =\n\t\t\tsource < target ? `${source}::${target}` : `${target}::${source}`;\n\t\tedgeData.set(key, edge);\n\t\tremainingEdges.add(key);\n\t}\n\n\t// Compute initial triangle counts\n\tconst triangleCounts = new Map<string, number>();\n\tfor (const key of remainingEdges) {\n\t\tconst edge = edgeData.get(key);\n\t\tif (edge !== undefined) {\n\t\t\ttriangleCounts.set(\n\t\t\t\tkey,\n\t\t\t\tcountEdgeTriangles(graph, edge.source, edge.target),\n\t\t\t);\n\t\t}\n\t}\n\n\t// Result map\n\tconst trussNumbers = new Map<string, number>();\n\n\t// Process edges in order of triangle count\n\tconst edgesByTriangleCount = new Map<number, Set<string>>();\n\n\tfor (const [key, count] of triangleCounts) {\n\t\tif (!edgesByTriangleCount.has(count)) {\n\t\t\tedgesByTriangleCount.set(count, new Set());\n\t\t}\n\t\tedgesByTriangleCount.get(count)?.add(key);\n\t}\n\n\t// Process from lowest triangle count upwards\n\tconst sortedCounts = [...edgesByTriangleCount.keys()].sort((a, b) => a - b);\n\n\tfor (const currentCount of sortedCounts) {\n\t\tconst bucket = edgesByTriangleCount.get(currentCount);\n\t\tif (bucket === undefined) continue;\n\n\t\twhile (bucket.size > 0) {\n\t\t\tconst edgeKey = bucket.values().next().value;\n\t\t\tif (edgeKey === undefined) break;\n\t\t\tbucket.delete(edgeKey);\n\n\t\t\tif (!remainingEdges.has(edgeKey)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// Truss number is triangle count + 2\n\t\t\tconst trussNumber = currentCount + 2;\n\t\t\ttrussNumbers.set(edgeKey, trussNumber);\n\t\t\tremainingEdges.delete(edgeKey);\n\n\t\t\tconst edge = edgeData.get(edgeKey);\n\t\t\tif (edge === undefined) continue;\n\n\t\t\tconst { source, target } = edge;\n\n\t\t\t// Remove from adjacency\n\t\t\tadjacency.get(source)?.delete(target);\n\t\t\tadjacency.get(target)?.delete(source);\n\n\t\t\t// Update triangle counts for affected edges\n\t\t\tconst sourceNeighbours = adjacency.get(source);\n\t\t\tif (sourceNeighbours !== undefined) {\n\t\t\t\tfor (const w of adjacency.get(target) ?? []) {\n\t\t\t\t\tif (sourceNeighbours.has(w)) {\n\t\t\t\t\t\tconst keySw = source < w ? `${source}::${w}` : `${w}::${source}`;\n\t\t\t\t\t\tconst keyTw = target < w ? `${target}::${w}` : `${w}::${target}`;\n\n\t\t\t\t\t\tfor (const keyToUpdate of [keySw, keyTw]) {\n\t\t\t\t\t\t\tif (remainingEdges.has(keyToUpdate)) {\n\t\t\t\t\t\t\t\tconst oldCount = triangleCounts.get(keyToUpdate) ?? 0;\n\t\t\t\t\t\t\t\tconst newCount = oldCount - 1;\n\t\t\t\t\t\t\t\ttriangleCounts.set(keyToUpdate, newCount);\n\n\t\t\t\t\t\t\t\t// Move to new bucket\n\t\t\t\t\t\t\t\tedgesByTriangleCount.get(oldCount)?.delete(keyToUpdate);\n\t\t\t\t\t\t\t\tif (!edgesByTriangleCount.has(newCount)) {\n\t\t\t\t\t\t\t\t\tedgesByTriangleCount.set(newCount, new Set());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tedgesByTriangleCount.get(newCount)?.add(keyToUpdate);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn trussNumbers;\n}\n","/**\n * Motif enumeration algorithms.\n *\n * Motifs are small recurring subgraph patterns. This module provides\n * enumeration and counting of motifs of size 3 and 4.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\n\n/**\n * Result of a motif census operation.\n */\nexport interface MotifCensus {\n\t/** Map from motif type identifier to count */\n\treadonly counts: ReadonlyMap<string, number>;\n\t/** Optional map from motif type to node instances */\n\treadonly instances?: ReadonlyMap<string, readonly NodeId[][]>;\n}\n\n/**\n * Canonicalise an edge pattern for hashing.\n *\n * Returns a canonical string representation of a small graph pattern.\n */\nfunction canonicalisePattern(\n\tnodeCount: number,\n\tedges: readonly (readonly [number, number])[],\n): string {\n\t// For small graphs (3-4 nodes), we enumerate all permutations\n\t// and return the lexicographically smallest edge list\n\n\tconst permutations = getPermutations(nodeCount);\n\tlet minPattern: string | null = null;\n\n\tfor (const perm of permutations) {\n\t\t// Transform edges according to permutation\n\t\tconst transformedEdges = edges\n\t\t\t.map(([u, v]) => {\n\t\t\t\tconst pu = perm[u] ?? -1;\n\t\t\t\tconst pv = perm[v] ?? -1;\n\t\t\t\tif (pu < 0 || pv < 0) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\treturn pu < pv\n\t\t\t\t\t? `${String(pu)}-${String(pv)}`\n\t\t\t\t\t: `${String(pv)}-${String(pu)}`;\n\t\t\t})\n\t\t\t.filter((edge): edge is string => edge !== undefined)\n\t\t\t.sort()\n\t\t\t.join(\",\");\n\n\t\tif (minPattern === null || transformedEdges < minPattern) {\n\t\t\tminPattern = transformedEdges;\n\t\t}\n\t}\n\n\treturn minPattern ?? \"\";\n}\n\n/**\n * Generate all permutations of [0, n-1].\n */\nfunction getPermutations(n: number): number[][] {\n\tif (n === 0) return [[]];\n\tif (n === 1) return [[0]];\n\n\tconst result: number[][] = [];\n\tconst arr = Array.from({ length: n }, (_, i) => i);\n\n\tfunction permute(start: number): void {\n\t\tif (start === n - 1) {\n\t\t\tresult.push([...arr]);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (let i = start; i < n; i++) {\n\t\t\tconst startVal = arr[start];\n\t\t\tconst iVal = arr[i];\n\t\t\tif (startVal === undefined || iVal === undefined) continue;\n\t\t\tarr[start] = iVal;\n\t\t\tarr[i] = startVal;\n\t\t\tpermute(start + 1);\n\t\t\tarr[start] = startVal;\n\t\t\tarr[i] = iVal;\n\t\t}\n\t}\n\n\tpermute(0);\n\treturn result;\n}\n\n/**\n * Enumerate all 3-node motifs in the graph.\n *\n * A 3-node motif (triad) can be one of 4 isomorphism classes for undirected graphs:\n * - Empty: no edges\n * - 1-edge: single edge\n * - 2-star: two edges sharing a node (path of length 2)\n * - Triangle: three edges (complete graph K3)\n *\n * For directed graphs, there are 16 isomorphism classes.\n *\n * @param graph - The source graph\n * @param includeInstances - Whether to include node instances in the result\n * @returns Motif census with counts and optionally instances\n */\nfunction enumerate3NodeMotifs<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tincludeInstances: boolean,\n): MotifCensus {\n\tconst counts = new Map<string, number>();\n\tconst instances = includeInstances\n\t\t? new Map<string, NodeId[][]>()\n\t\t: undefined;\n\n\tconst nodeList = [...graph.nodeIds()];\n\tconst n = nodeList.length;\n\n\t// Iterate over all triples of nodes\n\tfor (let i = 0; i < n; i++) {\n\t\tconst ni = nodeList[i];\n\t\tif (ni === undefined) continue;\n\t\tfor (let j = i + 1; j < n; j++) {\n\t\t\tconst nj = nodeList[j];\n\t\t\tif (nj === undefined) continue;\n\t\t\tfor (let k = j + 1; k < n; k++) {\n\t\t\t\tconst nk = nodeList[k];\n\t\t\t\tif (nk === undefined) continue;\n\n\t\t\t\tconst nodes: [NodeId, NodeId, NodeId] = [ni, nj, nk];\n\t\t\t\tconst edges: [number, number][] = [];\n\n\t\t\t\t// Check all 3 possible edges\n\t\t\t\tconst edgeChecks: [number, number][] = [\n\t\t\t\t\t[0, 1],\n\t\t\t\t\t[0, 2],\n\t\t\t\t\t[1, 2],\n\t\t\t\t];\n\n\t\t\t\tfor (const [u, v] of edgeChecks) {\n\t\t\t\t\tconst nu = nodes[u];\n\t\t\t\t\tconst nv = nodes[v];\n\t\t\t\t\tif (nu === undefined || nv === undefined) continue;\n\n\t\t\t\t\tif (graph.getEdge(nu, nv) !== undefined) {\n\t\t\t\t\t\tedges.push([u, v]);\n\t\t\t\t\t} else if (!graph.directed && graph.getEdge(nv, nu) !== undefined) {\n\t\t\t\t\t\tedges.push([u, v]);\n\t\t\t\t\t} else if (graph.directed && graph.getEdge(nv, nu) !== undefined) {\n\t\t\t\t\t\t// For directed graphs, store directed edge\n\t\t\t\t\t\tedges.push([v, u]);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst pattern = canonicalisePattern(3, edges);\n\t\t\t\tconst count = counts.get(pattern) ?? 0;\n\t\t\t\tcounts.set(pattern, count + 1);\n\n\t\t\t\tif (includeInstances && instances !== undefined) {\n\t\t\t\t\tif (!instances.has(pattern)) {\n\t\t\t\t\t\tinstances.set(pattern, []);\n\t\t\t\t\t}\n\t\t\t\t\tconst patternInstances = instances.get(pattern);\n\t\t\t\t\tif (patternInstances !== undefined) {\n\t\t\t\t\t\tpatternInstances.push([ni, nj, nk]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { counts, instances };\n}\n\n/**\n * Enumerate all 4-node motifs in the graph.\n *\n * A 4-node motif can be one of 11 isomorphism classes for undirected graphs\n * (ranging from empty to complete K4), or many more for directed graphs.\n *\n * @param graph - The source graph\n * @param includeInstances - Whether to include node instances in the result\n * @returns Motif census with counts and optionally instances\n */\nfunction enumerate4NodeMotifs<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tincludeInstances: boolean,\n): MotifCensus {\n\tconst counts = new Map<string, number>();\n\tconst instances = includeInstances\n\t\t? new Map<string, NodeId[][]>()\n\t\t: undefined;\n\n\tconst nodeList = [...graph.nodeIds()];\n\tconst n = nodeList.length;\n\n\t// Iterate over all quadruples of nodes\n\tfor (let i = 0; i < n; i++) {\n\t\tconst ni = nodeList[i];\n\t\tif (ni === undefined) continue;\n\t\tfor (let j = i + 1; j < n; j++) {\n\t\t\tconst nj = nodeList[j];\n\t\t\tif (nj === undefined) continue;\n\t\t\tfor (let k = j + 1; k < n; k++) {\n\t\t\t\tconst nk = nodeList[k];\n\t\t\t\tif (nk === undefined) continue;\n\t\t\t\tfor (let l = k + 1; l < n; l++) {\n\t\t\t\t\tconst nl = nodeList[l];\n\t\t\t\t\tif (nl === undefined) continue;\n\n\t\t\t\t\tconst nodes: [NodeId, NodeId, NodeId, NodeId] = [ni, nj, nk, nl];\n\t\t\t\t\tconst edges: [number, number][] = [];\n\n\t\t\t\t\t// Check all 6 possible edges\n\t\t\t\t\tconst edgeChecks: [number, number][] = [\n\t\t\t\t\t\t[0, 1],\n\t\t\t\t\t\t[0, 2],\n\t\t\t\t\t\t[0, 3],\n\t\t\t\t\t\t[1, 2],\n\t\t\t\t\t\t[1, 3],\n\t\t\t\t\t\t[2, 3],\n\t\t\t\t\t];\n\n\t\t\t\t\tfor (const [u, v] of edgeChecks) {\n\t\t\t\t\t\tconst nu = nodes[u];\n\t\t\t\t\t\tconst nv = nodes[v];\n\t\t\t\t\t\tif (nu === undefined || nv === undefined) continue;\n\n\t\t\t\t\t\tif (graph.getEdge(nu, nv) !== undefined) {\n\t\t\t\t\t\t\tedges.push([u, v]);\n\t\t\t\t\t\t} else if (!graph.directed && graph.getEdge(nv, nu) !== undefined) {\n\t\t\t\t\t\t\tedges.push([u, v]);\n\t\t\t\t\t\t} else if (graph.directed && graph.getEdge(nv, nu) !== undefined) {\n\t\t\t\t\t\t\t// For directed graphs, store directed edge\n\t\t\t\t\t\t\tedges.push([v, u]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tconst pattern = canonicalisePattern(4, edges);\n\t\t\t\t\tconst count = counts.get(pattern) ?? 0;\n\t\t\t\t\tcounts.set(pattern, count + 1);\n\n\t\t\t\t\tif (includeInstances && instances !== undefined) {\n\t\t\t\t\t\tif (!instances.has(pattern)) {\n\t\t\t\t\t\t\tinstances.set(pattern, []);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tconst patternInstances = instances.get(pattern);\n\t\t\t\t\t\tif (patternInstances !== undefined) {\n\t\t\t\t\t\t\tpatternInstances.push([ni, nj, nk, nl]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { counts, instances };\n}\n\n/**\n * Human-readable names for common 3-node motifs.\n */\nconst MOTIF_3_NAMES: ReadonlyMap<string, string> = new Map([\n\t[\"\", \"empty\"], // No edges\n\t[\"0-1\", \"1-edge\"], // Single edge\n\t[\"0-1,0-2\", \"2-star\"], // Path of length 2 (V-shape)\n\t[\"0-1,1-2\", \"path-3\"], // Path of length 2 (alternative)\n\t[\"0-1,0-2,1-2\", \"triangle\"], // Complete K3\n]);\n\n/**\n * Human-readable names for common 4-node motifs.\n */\nconst MOTIF_4_NAMES: ReadonlyMap<string, string> = new Map([\n\t[\"\", \"empty\"],\n\t[\"0-1\", \"1-edge\"],\n\t[\"0-1,0-2\", \"2-star\"],\n\t[\"0-1,0-2,0-3\", \"3-star\"],\n\t[\"0-1,0-2,1-2\", \"triangle\"], // K3 + isolated\n\t[\"0-1,0-2,1-2,2-3\", \"paw\"], // Triangle with tail\n\t[\"0-1,0-2,2-3\", \"path-4\"], // Path of length 3\n\t[\"0-1,0-2,1-3,2-3\", \"4-cycle\"], // Cycle C4\n\t[\"0-1,0-2,1-2,0-3,1-3\", \"diamond\"], // K4 minus one edge\n\t[\"0-1,0-2,0-3,1-2,1-3,2-3\", \"K4\"], // Complete graph\n]);\n\n/**\n * Enumerate motifs of a given size in the graph.\n *\n * This function counts all occurrences of each distinct motif type\n * (isomorphism class) in the graph. For graphs with many nodes,\n * 4-motif enumeration can be expensive (O(n^4) worst case).\n *\n * @param graph - The source graph\n * @param size - Motif size (3 or 4 nodes)\n * @returns Motif census with counts per motif type\n *\n * @example\n * ```typescript\n * // Count all triangles and other 3-node patterns\n * const census3 = enumerateMotifs(graph, 3);\n * console.log(`Triangles: ${census3.counts.get('0-1,0-2,1-2')}`);\n *\n * // Count 4-node patterns\n * const census4 = enumerateMotifs(graph, 4);\n * ```\n */\nexport function enumerateMotifs<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tsize: 3 | 4,\n): MotifCensus {\n\t// Don't include instances by default for efficiency\n\treturn size === 3\n\t\t? enumerate3NodeMotifs(graph, false)\n\t\t: enumerate4NodeMotifs(graph, false);\n}\n\n/**\n * Enumerate motifs with optional instance tracking.\n *\n * @param graph - The source graph\n * @param size - Motif size (3 or 4 nodes)\n * @param includeInstances - Whether to include node instances\n * @returns Motif census with counts and optionally instances\n */\nexport function enumerateMotifsWithInstances<\n\tN extends NodeData,\n\tE extends EdgeData,\n>(\n\tgraph: ReadableGraph<N, E>,\n\tsize: 3 | 4,\n\tincludeInstances: boolean,\n): MotifCensus {\n\treturn size === 3\n\t\t? enumerate3NodeMotifs(graph, includeInstances)\n\t\t: enumerate4NodeMotifs(graph, includeInstances);\n}\n\n/**\n * Get a human-readable name for a motif pattern.\n *\n * @param pattern - The canonical pattern string\n * @param size - Motif size (3 or 4 nodes)\n * @returns A human-readable name, or the pattern itself if unknown\n */\nexport function getMotifName(pattern: string, size: 3 | 4): string {\n\tconst names = size === 3 ? MOTIF_3_NAMES : MOTIF_4_NAMES;\n\treturn names.get(pattern) ?? pattern;\n}\n","/**\n * Induced subgraph extraction.\n *\n * Extracts a subgraph containing exactly the specified nodes and all\n * edges between them from the original graph.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport { AdjacencyMapGraph } from \"../graph/adjacency-map\";\n\n/**\n * Extract the induced subgraph containing exactly the specified nodes.\n *\n * The induced subgraph includes all nodes from the input set that exist\n * in the original graph, plus all edges where both endpoints are in the set.\n *\n * @param graph - The source graph\n * @param nodes - Set of node IDs to include in the subgraph\n * @returns A new graph containing the induced subgraph\n *\n * @example\n * ```typescript\n * const subgraph = extractInducedSubgraph(graph, new Set(['A', 'B', 'C']));\n * ```\n */\nexport function extractInducedSubgraph<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\tnodes: ReadonlySet<NodeId>,\n): AdjacencyMapGraph<N, E> {\n\tconst result = graph.directed\n\t\t? AdjacencyMapGraph.directed<N, E>()\n\t\t: AdjacencyMapGraph.undirected<N, E>();\n\n\t// Add nodes that exist in both the set and the graph\n\tfor (const nodeId of nodes) {\n\t\tconst nodeData = graph.getNode(nodeId);\n\t\tif (nodeData !== undefined) {\n\t\t\tresult.addNode(nodeData);\n\t\t}\n\t}\n\n\t// Add edges where both endpoints exist in the result\n\tfor (const edge of graph.edges()) {\n\t\tif (result.hasNode(edge.source) && result.hasNode(edge.target)) {\n\t\t\tresult.addEdge(edge);\n\t\t}\n\t}\n\n\treturn result;\n}\n","/**\n * Filtered subgraph extraction.\n *\n * Extracts a subgraph based on predicate functions for nodes and edges.\n */\n\nimport type { NodeId, NodeData, EdgeData, ReadableGraph } from \"../graph\";\nimport { AdjacencyMapGraph } from \"../graph/adjacency-map\";\n\n/**\n * Options for filtering a subgraph.\n */\nexport interface FilterOptions<N extends NodeData, E extends EdgeData> {\n\t/** Predicate to filter nodes. Return true to include the node. */\n\treadonly nodePredicate?: (node: N) => boolean;\n\t/** Predicate to filter edges. Return true to include the edge. */\n\treadonly edgePredicate?: (edge: E) => boolean;\n\t/** Whether to remove nodes that become isolated after edge filtering. Default: false. */\n\treadonly removeIsolated?: boolean;\n}\n\n/**\n * Extract a filtered subgraph based on node and edge predicates.\n *\n * Nodes are first filtered by the node predicate (if provided).\n * Edges are then filtered by the edge predicate (if provided), and only\n * retained if both endpoints pass the node predicate.\n *\n * @param graph - The source graph\n * @param options - Filter options specifying node/edge predicates\n * @returns A new graph containing only nodes and edges that pass the predicates\n *\n * @example\n * ```typescript\n * // Extract subgraph of high-weight nodes\n * const filtered = filterSubgraph(graph, {\n * nodePredicate: (node) => (node.weight ?? 0) > 0.5,\n * removeIsolated: true\n * });\n * ```\n */\nexport function filterSubgraph<N extends NodeData, E extends EdgeData>(\n\tgraph: ReadableGraph<N, E>,\n\toptions?: FilterOptions<N, E>,\n): AdjacencyMapGraph<N, E> {\n\tconst {\n\t\tnodePredicate,\n\t\tedgePredicate,\n\t\tremoveIsolated = false,\n\t} = options ?? {};\n\n\tconst result = graph.directed\n\t\t? AdjacencyMapGraph.directed<N, E>()\n\t\t: AdjacencyMapGraph.undirected<N, E>();\n\n\t// Track which nodes were added\n\tconst includedNodes = new Set<NodeId>();\n\n\t// Add nodes that pass the predicate\n\tfor (const nodeId of graph.nodeIds()) {\n\t\tconst nodeData = graph.getNode(nodeId);\n\t\tif (nodeData !== undefined) {\n\t\t\tif (nodePredicate === undefined || nodePredicate(nodeData)) {\n\t\t\t\tresult.addNode(nodeData);\n\t\t\t\tincludedNodes.add(nodeId);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Add edges that pass both endpoint and edge predicates\n\tfor (const edge of graph.edges()) {\n\t\tif (!includedNodes.has(edge.source) || !includedNodes.has(edge.target)) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (edgePredicate === undefined || edgePredicate(edge)) {\n\t\t\tresult.addEdge(edge);\n\t\t}\n\t}\n\n\t// Remove isolated nodes if requested\n\tif (removeIsolated) {\n\t\tconst isolatedNodes: NodeId[] = [];\n\t\tfor (const nodeId of result.nodeIds()) {\n\t\t\tif (result.degree(nodeId) === 0) {\n\t\t\t\tisolatedNodes.push(nodeId);\n\t\t\t}\n\t\t}\n\t\tfor (const nodeId of isolatedNodes) {\n\t\t\tresult.removeNode(nodeId);\n\t\t}\n\t}\n\n\treturn result;\n}\n"],"mappings":";;;;;;;;;;;;AAmCA,SAAS,eACR,SACA,SACS;AACT,QAAO,QAAQ;;;;;;;;;;AAWhB,SAAgB,KACf,OACA,OACA,QACkB;CAClB,MAAM,YAAY,YAAY,KAAK;CAEnC,MAAM,EACL,WAAW,GACX,gBAAgB,GAChB,WAAW,GACX,WAAW,gBACX,QAAQ,UACL,UAAU,EAAE;AAEhB,KAAI,MAAM,WAAW,EACpB,QAAO,YAAY,QAAQ,UAAU;CAItC,MAAM,eAAe,MAAM;CAC3B,MAAM,oBAA2C,EAAE;CACnD,MAAM,eAA6C,EAAE;CACrD,MAAM,SAAsC,EAAE;AAE9C,MAAK,IAAI,IAAI,GAAG,IAAI,cAAc,KAAK;AACtC,oBAAkB,qBAAK,IAAI,KAAK,CAAC;AACjC,eAAa,qBAAK,IAAI,KAAK,CAAC;AAC5B,SAAO,KAAK,IAAI,mBAAA,eAA2B,CAAC;EAE5C,MAAM,OAAO,MAAM;AACnB,MAAI,SAAS,KAAA,EAAW;EAExB,MAAM,WAAW,KAAK;AAGtB,eAAa,IAAI,IAAI,UAAU,KAAK;EAWpC,MAAM,eAAe,SAAS,UATd,sBACf,OACA,UACA,GACA,mBACA,EAAE,EACF,EACA,CAE+C;AAChD,SAAO,IAAI,KACV;GACC,QAAQ;GACR,eAAe;GACf,aAAa;GACb,EACD,aACA;;CAGF,MAAM,6BAAa,IAAI,KAAa;CACpC,MAAM,+BAAe,IAAI,KAAa;CACtC,MAAM,kBAAmC,EAAE;CAC3C,IAAI,aAAa;CACjB,IAAI,iBAAiB;CACrB,IAAI,cAA6C;CAGjD,MAAM,0BAAmC;AACxC,MAAI,gBAAgB,KAAK,cAAc,eAAe;AACrD,iBAAc;AACd,UAAO;;AAER,MAAI,WAAW,KAAK,WAAW,QAAQ,UAAU;AAChD,iBAAc;AACd,UAAO;;AAER,MAAI,WAAW,KAAK,gBAAgB,UAAU,UAAU;AACvD,iBAAc;AACd,UAAO;;AAER,SAAO;;AAGR,QAAO,mBAAmB,EAAE;EAE3B,IAAI,iBAAiB,OAAO;EAC5B,IAAI,iBAAiB;AAErB,OAAK,IAAI,IAAI,GAAG,IAAI,cAAc,KAAK;GACtC,MAAM,QAAQ,OAAO;AACrB,OAAI,UAAU,KAAA,KAAa,CAAC,MAAM,SAAS,EAAE;IAC5C,MAAM,OAAO,MAAM,MAAM;AACzB,QAAI,SAAS,KAAA,KAAa,KAAK,WAAW,gBAAgB;AACzD,sBAAiB,KAAK;AACtB,sBAAiB;;;;AAMpB,MAAI,iBAAiB,GAAG;AACvB,iBAAc;AACd;;EAGD,MAAM,QAAQ,OAAO;AACrB,MAAI,UAAU,KAAA,EAAW;EAEzB,MAAM,QAAQ,MAAM,KAAK;AACzB,MAAI,UAAU,KAAA,EAAW;EAEzB,MAAM,EAAE,QAAQ,gBAAgB,MAAM;EAGtC,MAAM,kBAAkB,kBAAkB;AAC1C,MAAI,oBAAoB,KAAA,KAAa,gBAAgB,IAAI,OAAO,CAC/D;AAID,kBAAgB,IAAI,QAAQ,eAAe;AAC3C,MAAI,gBAAgB,MAAM;GACzB,MAAM,UAAU,aAAa;AAC7B,OAAI,YAAY,KAAA,EACf,SAAQ,IAAI,QAAQ,YAAY;;AAGlC,aAAW,IAAI,OAAO;AAEtB,MAAI,MACH,SAAQ,IACP,oBAAoB,OAAO,WAAW,CAAC,aAAa,OAAO,eAAe,CAAC,YAAY,SACvF;AAIF,OAAK,IAAI,gBAAgB,GAAG,gBAAgB,cAAc,iBAAiB;AAC1E,OAAI,kBAAkB,eAAgB;GAEtC,MAAM,eAAe,kBAAkB;AACvC,OAAI,iBAAiB,KAAA,EAAW;AAEhC,OAAI,aAAa,IAAI,OAAO,EAAE;IAE7B,MAAM,OAAO,gBACZ,QACA,gBACA,eACA,cACA,MACA;AACD,QAAI,SAAS,MAAM;AAClB,qBAAgB,KAAK,KAAK;AAC1B,SAAI,MACH,SAAQ,IAAI,sBAAsB,KAAK,MAAM,KAAK,OAAO,GAAG;;;;EAOhE,MAAM,aAAa,MAAM,WAAW,OAAO;AAC3C,OAAK,MAAM,aAAa,YAAY;AACnC;GAGA,MAAM,UACL,SAAS,YACN,GAAG,OAAO,IAAI,cACd,GAAG,UAAU,IAAI;AACrB,gBAAa,IAAI,QAAQ;GAGzB,MAAM,kBAAkB,kBAAkB;AAC1C,OAAI,oBAAoB,KAAA,KAAa,gBAAgB,IAAI,UAAU,CAClE;GAYD,MAAM,oBAAoB,SAAS,WATnB,sBACf,OACA,WACA,gBACA,mBACA,iBACA,aAAa,EACb,CAEqD;AAEtD,SAAM,KACL;IACC,QAAQ;IACR,eAAe;IACf,aAAa;IACb,EACD,kBACA;;AAGF;;CAGD,MAAM,UAAU,YAAY,KAAK;CACjC,MAAM,qBAAqB,kBAAkB,KAAK,MAAM,IAAI,IAAI,EAAE,MAAM,CAAC,CAAC;CAG1E,MAAM,6BAAa,IAAI,KAAgC;AACvD,MAAK,MAAM,WAAW,cAAc;EACnC,MAAM,QAAQ,QAAQ,MAAM,KAAK;AACjC,MAAI,MAAM,WAAW,GAAG;GACvB,MAAM,SAAS,MAAM;GACrB,MAAM,SAAS,MAAM;AACrB,OAAI,WAAW,KAAA,KAAa,WAAW,KAAA,EACtC,YAAW,IAAI,CAAC,QAAQ,OAAO,CAAU;;;AAK5C,QAAO;EACN,OAAO;EACP,cAAc;EACd,cAAc;EACd;EACA,OAAO;GACN;GACA,cAAc,WAAW;GACzB;GACA,YAAY,gBAAgB;GAC5B,YAAY,UAAU;GACtB,WAAW;GACX;GACA;EACD;;;;;AAMF,SAAS,sBACR,OACA,QACA,eACA,mBACA,iBACA,WACwB;CACxB,MAAM,kCAAkB,IAAI,KAAqB;AACjD,MAAK,MAAM,eAAe,kBACzB,MAAK,MAAM,CAAC,IAAI,QAAQ,YACvB,iBAAgB,IAAI,IAAI,IAAI;CAI9B,MAAM,aAAa,IAAI,IAAY,gBAAgB,MAAM,CAAC;AAE1D,QAAO;EACN;EACA,QAAQ,MAAM,OAAO,OAAO;EAC5B;EACA,mBAAmB;EACnB;EACA;EACA;EACA;;;;;AAMF,SAAS,gBACR,eACA,WACA,WACA,cACA,OACuB;CACvB,MAAM,QAAkB,CAAC,cAAc;CACvC,MAAM,QAAQ,aAAa;AAC3B,KAAI,UAAU,KAAA,GAAW;EACxB,IAAI,OAAkC;EACtC,IAAI,OAAkC,MAAM,IAAI,KAAK;AACrD,SAAO,SAAS,QAAQ,SAAS,KAAA,GAAW;AAC3C,UAAO;AACP,SAAM,QAAQ,KAAK;AACnB,UAAO,MAAM,IAAI,KAAK;;;CAIxB,MAAM,QAAkB,EAAE;CAC1B,MAAM,QAAQ,aAAa;AAC3B,KAAI,UAAU,KAAA,GAAW;EACxB,IAAI,OAAkC;EACtC,IAAI,OAAkC,MAAM,IAAI,KAAK;AACrD,SAAO,SAAS,QAAQ,SAAS,KAAA,GAAW;AAC3C,UAAO;AACP,SAAM,KAAK,KAAK;AAChB,UAAO,MAAM,IAAI,KAAK;;;CAIxB,MAAM,WAAW,CAAC,GAAG,OAAO,GAAG,MAAM;CAErC,MAAM,QAAQ,MAAM;CACpB,MAAM,QAAQ,MAAM;AAEpB,KAAI,UAAU,KAAA,KAAa,UAAU,KAAA,EACpC,QAAO;AAGR,QAAO;EACN,UAAU;EACV,QAAQ;EACR,OAAO;EACP;;;;;AAMF,SAAS,YAAY,WAAmB,WAAoC;AAC3E,QAAO;EACN,OAAO,EAAE;EACT,8BAAc,IAAI,KAAK;EACvB,8BAAc,IAAI,KAAK;EACvB,oBAAoB,EAAE;EACtB,OAAO;GACN,YAAY;GACZ,cAAc;GACd,gBAAgB;GAChB,YAAY;GACZ,YAAY,YAAY,KAAK,GAAG;GAChC;GACA,aAAa;GACb;EACD;;;;;;;;;;;;ACvWF,SAAgB,KACf,OACA,OACA,QACkB;CAElB,MAAM,gBACL,QACA,YACY;AAGZ,SAAO,MAAM,OAAO,OAAO;;AAG5B,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH,UAAU;EACV,CAAC;;;;;;;;;;ACfH,SAAS,aACR,QACA,SACS;CAET,MAAM,QAAQ,QAAQ;CACtB,IAAI,cAAc,QAAQ;AAE1B,MAAK,MAAM,aAAa,MAAM,WAAW,OAAO,CAC/C,gBAAe,MAAM,OAAO,UAAU;AAGvC,QAAO;;;;;;;;;;;;;AAcR,SAAgB,KACf,OACA,OACA,QACkB;AAClB,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH,UAAU;EACV,CAAC;;;;;;;;;;;;;ACtCH,SAAgB,QACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE;CAGxC,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAG/B,IAAI,mBAAmB;AACvB,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,CAClC;CAKF,MAAM,YACL,iBAAiB,OAAO,iBAAiB,OAAO;AAGjD,KAAI,cAAc,EACjB,QAAO;CAGR,MAAM,QAAQ,mBAAmB;AAGjC,QAAO,KAAK,IAAI,SAAS,MAAM;;;;;;;;;;ACjBhC,SAAS,YACR,QACA,SACA,IACS;CACT,MAAM,QAAQ,QAAQ;CACtB,MAAM,gBAAgB,QAAQ;CAI9B,IAAI,QAAQ;CAGZ,IAAI,UAAU;CACd,IAAI,QAAQ;AAEZ,MAAK,MAAM,CAAC,WAAW,QAAQ,QAAQ,kBACtC,KAAI,QAAQ,iBAAiB,cAAc,QAAQ;EAClD,MAAM,SAAS,GAAG,OAAO,WAAW,OAAO;AAC3C,aAAW;AACX;AACA,MAAI,SAAS,MACZ,SAAQ;;AASX,QAAO,KAHO,QAAQ,IAAI,UAAU,QAAQ;;;;;;;;;;;;;AAiB7C,SAAgB,IACf,OACA,OACA,QACkB;CAClB,MAAM,EAAE,KAAK,SAAS,GAAG,eAAe,UAAU,EAAE;CAEpD,MAAM,YAAY,QAAgB,YACjC,YAAY,QAAQ,SAAS,GAAG;AAEjC,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH;EACA,CAAC;;;;;;;;;;;ACzEH,SAAS,aACR,QACA,SACS;CACT,MAAM,QAAQ,QAAQ;CACtB,MAAM,kBAAkB,QAAQ;CAChC,MAAM,iBAAiB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAGxD,IAAI,cAAc;AAElB,MAAK,MAAM,CAAC,WAAW,gBAAgB,QAAQ,kBAC9C,KAAI,gBAAgB,mBAAmB,eAAe,IAAI,UAAU,CACnE;AAKF,MAAK,MAAM,QAAQ,QAAQ,gBAC1B,KAAI,KAAK,MAAM,SAAS,OAAO,CAC9B,gBAAe;AAKjB,QAAO,KAAK,IAAI;;;;;;;;;;;;;AAcjB,SAAgB,KACf,OACA,OACA,QACkB;AAClB,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH,UAAU;EACV,CAAC;;;;;;;;;;;AC5BH,SAAS,aACR,QACA,SACA,IACA,gBACS;CACT,MAAM,QAAQ,QAAQ;CACtB,MAAM,SAAS,QAAQ;CACvB,MAAM,gBAAgB,QAAQ;CAG9B,IAAI,gBAAgB;CACpB,IAAI,QAAQ;AAEZ,MAAK,MAAM,CAAC,WAAW,QAAQ,QAAQ,kBACtC,KAAI,QAAQ,iBAAiB,cAAc,QAAQ;AAClD,mBAAiB,GAAG,OAAO,WAAW,OAAO;AAC7C;;CAIF,MAAM,cAAc,QAAQ,IAAI,gBAAgB,QAAQ;AAQxD,SAHyB,IAAI,kBAAkB,SACrB,kBAAkB,IAAI;;;;;;;;;;;;;AAgBjD,SAAgB,KACf,OACA,OACA,QACkB;CAClB,MAAM,EAAE,KAAK,SAAS,iBAAiB,IAAK,GAAG,eAAe,UAAU,EAAE;CAE1E,MAAM,YAAY,QAAgB,YACjC,aAAa,QAAQ,SAAS,IAAI,eAAe;AAElD,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH;EACA,CAAC;;;;;;;;;ACxDH,SAAS,cACR,QACA,SACA,IACA,aACS;CACT,MAAM,QAAQ,QAAQ;CACtB,MAAM,gBAAgB,QAAQ;CAG9B,IAAI,UAAU;CACd,IAAI,QAAQ;AAEZ,MAAK,MAAM,CAAC,WAAW,QAAQ,QAAQ,kBACtC,KAAI,QAAQ,iBAAiB,cAAc,QAAQ;AAClD,aAAW,GAAG,OAAO,WAAW,OAAO;AACvC;;CAIF,MAAM,QAAQ,QAAQ,IAAI,UAAU,QAAQ;AAI5C,KAAI,SAAS,YACZ,QAAO,IAAI;KAEX,QAAO,QAAQ,SAAS;;;;;;;;;;;;;AAe1B,SAAgB,MACf,OACA,OACA,QACkB;CAClB,MAAM,EAAE,KAAK,SAAS,cAAc,KAAM,GAAG,eAAe,UAAU,EAAE;CAGxE,MAAM,YAAY,QAAgB,YACjC,cAAc,QAAQ,SAAS,IAAI,YAAY;AAEhD,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH;EACA,CAAC;;;;;;;AC/DH,SAAS,aACR,OACA,QACS;CACT,MAAM,aAAa,MAAM,KAAK,MAAM,WAAW,OAAO,CAAC;CACvD,MAAM,SAAS,WAAW;AAE1B,KAAI,SAAS,EACZ,QAAO;CAIR,IAAI,QAAQ;AACZ,MAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,IACtC,MAAK,IAAI,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;EAC/C,MAAM,KAAK,WAAW;EACtB,MAAM,KAAK,WAAW;AACtB,MACC,OAAO,KAAA,KACP,OAAO,KAAA,KACP,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EAE1B;;CAKH,MAAM,WAAY,UAAU,SAAS,KAAM;AAC3C,QAAO,QAAQ;;;;;AAMhB,SAAS,YACR,QACA,SACS;CACT,MAAM,kBAAkB,QAAQ;CAChC,MAAM,iBAAiB,IAAI,IAAI,QAAQ,MAAM,WAAW,OAAO,CAAC;CAEhE,IAAI,QAAQ;AACZ,MAAK,MAAM,CAAC,WAAW,QAAQ,QAAQ,kBACtC,KAAI,QAAQ,mBAAmB,eAAe,IAAI,UAAU,CAC3D;AAIF,QAAO;;;;;;;;;;AAWR,SAAS,aACR,QACA,SACA,kBACA,iBACS;CACT,MAAM,QAAQ,QAAQ;CACtB,MAAM,SAAS,QAAQ;CAGvB,MAAM,UAAU,aAAa,OAAO,OAAO;CAC3C,MAAM,SAAS,YAAY,QAAQ,QAAQ;CAG3C,MAAM,eAAe,IAAI,IAAI,QAAQ,kBAAkB,QAAQ,CAAC,CAAC;AAIjE,MAHyB,eAAe,IAAI,SAAS,eAAe,MAG5C,gBAEvB,QAAO,KAAK,IAAI;UACN,WAAW,iBAErB,QAAO,CAAC;KAGR,QAAO;;;;;;;;;;;;;;AAgBT,SAAgB,KACf,OACA,OACA,QACkB;CAClB,MAAM,EACL,mBAAmB,IACnB,kBAAkB,IAClB,GAAG,eACA,UAAU,EAAE;CAEhB,MAAM,YAAY,QAAgB,YACjC,aAAa,QAAQ,SAAS,kBAAkB,gBAAgB;AAEjE,QAAO,KAAK,OAAO,OAAO;EACzB,GAAG;EACH;EACA,CAAC;;;;;;;;;;;;;;;ACnFH,SAAgB,MACf,OACA,OACA,QACc;CACd,MAAM,YAAY,YAAY,KAAK;CAEnC,MAAM,EAAE,KAAK,SAAS,UAAU,UAAU,UAAU,EAAE;CAEtD,MAAM,cAA4B,EAAE;AAEpC,MAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,WAAW,oBAAoB,OAAO,MAAM,IAAI,QAAQ;AAC9D,cAAY,KAAK;GAChB,GAAG;GACH;GACA,CAAC;;AAIH,aAAY,MAAM,GAAG,MAAM,EAAE,WAAW,EAAE,SAAS;CAEnD,MAAM,UAAU,YAAY,KAAK;CAGjC,MAAM,YAAY,YAAY,KAAK,MAAM,EAAE,SAAS;CACpD,MAAM,eACL,UAAU,SAAS,IAChB,UAAU,QAAQ,GAAG,MAAM,IAAI,GAAG,EAAE,GAAG,UAAU,SACjD;CACJ,MAAM,kBAAkB,CAAC,GAAG,UAAU,CAAC,MAAM,GAAG,MAAM,IAAI,EAAE;CAC5D,MAAM,MAAM,KAAK,MAAM,gBAAgB,SAAS,EAAE;CAClD,MAAM,iBACL,gBAAgB,SAAS,IACtB,gBAAgB,SAAS,MAAM,IAC7B,gBAAgB,QAAQ,MACvB,gBAAgB,MAAM,MAAM,MAAM,gBAAgB,QAAQ,MAAM,IACnE;CACJ,MAAM,cACL,gBAAgB,SAAS,IACrB,gBAAgB,gBAAgB,SAAS,MAAM,IAChD;CACJ,MAAM,cACL,gBAAgB,SAAS,IAAK,gBAAgB,MAAM,IAAK;AAE1D,QAAO;EACN,OAAO;EACP,OAAO;GACN,aAAa,YAAY;GACzB;GACA;GACA;GACA;GACA,YAAY,UAAU;GACtB;EACD;;;;;;;AAQF,SAAS,oBACR,OACA,MACA,IACA,SACS;CACT,MAAM,QAAQ,KAAK;AAEnB,KAAI,MAAM,SAAS,EAClB,QAAO;CAIR,IAAI,YAAY;CAChB,IAAI,YAAY;AAEhB,MAAK,IAAI,IAAI,GAAG,IAAI,MAAM,SAAS,GAAG,KAAK;EAC1C,MAAM,SAAS,MAAM;EACrB,MAAM,SAAS,MAAM,IAAI;AAEzB,MAAI,WAAW,KAAA,KAAa,WAAW,KAAA,GAAW;GACjD,MAAM,SAAS,GAAG,OAAO,QAAQ,OAAO;AACxC,gBAAa,KAAK,IAAI,SAAS,OAAO;AACtC;;;AAIF,KAAI,cAAc,EACjB,QAAO;CAIR,MAAM,WAAW,KAAK,IAAI,WAAW,IAAI,UAAU;AACnD,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,SAAS,CAAC;;;;;;;;;;;;;ACpJhD,SAAgB,WACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,OAAO,YAAY,SAAS,UAAU,EAAE;CAG1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAG/B,IAAI,QAAQ;AACZ,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,EAAE;EACpC,MAAM,SAAS,MAAM,OAAO,UAAU;AACtC,MAAI,SAAS,EACZ,UAAS,IAAI,KAAK,IAAI,OAAO;;AAMhC,KAAI,WAAW;EAGd,MAAM,cACL,iBAAiB,OAAO,iBAAiB,OACtC,iBAAiB,OACjB,iBAAiB;AACrB,MAAI,gBAAgB,EACnB,QAAO;EAER,MAAM,WAAW,cAAc,KAAK,IAAI,EAAE;AAC1C,UAAQ,QAAQ;;AAIjB,QAAO,KAAK,IAAI,SAAS,MAAM;;;;;;;AC/ChC,SAAgB,MACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE;CAGxC,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAE/B,MAAM,eAAe,iBAAiB;CACtC,MAAM,eAAe,iBAAiB;CAGtC,IAAI,mBAAmB;AACvB,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,CAClC;CAIF,MAAM,YAAY,eAAe,eAAe;CAChD,MAAM,UAAU,YAAY,IAAI,mBAAmB,YAAY;CAG/D,MAAM,YAAY,KAAK,IAAI,cAAc,aAAa;CACtD,MAAM,YAAY,KAAK,IAAI,cAAc,aAAa;CACtD,MAAM,cAAc,YAAY,IAAI,YAAY,YAAY;AAG5D,KAAI,UAAU,gBAAgB,EAC7B,QAAO;CAGR,MAAM,QAAS,IAAI,UAAU,eAAgB,UAAU;AAEvD,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;;;;;;;AC1C7C,SAAgB,KACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE;CAGxC,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAG/B,IAAI,uBAAuB;CAC3B,IAAI,cAAc;AAElB,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,EAAE;AACpC;EACA,MAAM,SAAS,MAAM,OAAO,UAAU;AACtC,MAAI,SAAS,EACZ,yBAAwB,IAAI,KAAK,IAAI,OAAO;;AAK/C,KAAI,gBAAgB,EACnB,QAAO;CAIR,MAAM,eAAe,iBAAiB;CACtC,MAAM,eAAe,iBAAiB;CAItC,MAAM,WAHY,KAAK,IAAI,cAAc,aAAa,GAGzB,KAAK,IAAI,EAAE;CACxC,MAAM,QAAQ,uBAAuB;AAErC,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;;;;;;;AC3C7C,SAAgB,KACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE;CAGxC,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAE/B,MAAM,eAAe,iBAAiB;CACtC,MAAM,eAAe,iBAAiB;CAGtC,IAAI,mBAAmB;AACvB,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,CAClC;CAIF,MAAM,YAAY,eAAe,eAAe;CAChD,MAAM,UAAU,YAAY,IAAI,mBAAmB,YAAY;CAG/D,MAAM,YAAY,KAAK,IAAI,cAAc,aAAa;CACtD,MAAM,aAAa,KAAK,IAAI,eAAe,aAAa;CACxD,MAAM,mBAAmB,YAAY,IAAI,IAAI,aAAa,YAAY;CAGtE,MAAM,QAAQ,KAAK,KAAK,UAAU,iBAAiB;AAEnD,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;;;;;;;ACrC7C,SAAgB,KACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE;CAGxC,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAG/B,MAAM,mBAA6B,EAAE;AACrC,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,CAClC,kBAAiB,KAAK,UAAU;AAIlC,KAAI,iBAAiB,SAAS,EAC7B,QAAO;CAIR,IAAI,aAAa;AACjB,MAAK,IAAI,IAAI,GAAG,IAAI,iBAAiB,QAAQ,IAC5C,MAAK,IAAI,IAAI,IAAI,GAAG,IAAI,iBAAiB,QAAQ,KAAK;EACrD,MAAM,KAAK,iBAAiB;EAC5B,MAAM,KAAK,iBAAiB;AAC5B,MACC,OAAO,KAAA,KACP,OAAO,KAAA,KACP,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EAE1B;;CAKH,MAAM,gBACJ,iBAAiB,UAAU,iBAAiB,SAAS,KAAM;CAC7D,MAAM,eAAe,gBAAgB,IAAI,aAAa,gBAAgB;CAGtE,IAAI,cAAc;AAClB,MAAK,MAAM,MAAM,kBAAkB;AAClC,MAAI,MAAM,QAAQ,QAAQ,GAAG,KAAK,KAAA,EACjC;AAED,MAAI,MAAM,QAAQ,QAAQ,GAAG,KAAK,KAAA,EACjC;;CAIF,MAAM,iBAAiB,iBAAiB,SAAS;CACjD,MAAM,gBAAgB,iBAAiB,IAAI,cAAc,iBAAiB;CAG1E,MAAM,QAAQ,eAAe,KAAM,gBAAgB;AAEnD,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;;;;;;;ACnE7C,SAAgB,MACf,OACA,QACA,QACA,QACS;CACT,MAAM,EAAE,UAAU,UAAU,UAAU,EAAE;CAGxC,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAG1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAE/B,MAAM,eAAe,iBAAiB;CACtC,MAAM,eAAe,iBAAiB;CAGtC,IAAI,mBAAmB;AACvB,MAAK,MAAM,aAAa,iBACvB,KAAI,iBAAiB,IAAI,UAAU,CAClC;CAIF,MAAM,YAAY,KAAK,IAAI,cAAc,aAAa;CACtD,MAAM,UAAU,YAAY,IAAI,mBAAmB,YAAY;CAG/D,MAAM,YAAY,KAAK,IAAI,cAAc,aAAa;CACtD,MAAM,cACL,YAAY,IAAI,IAAI,KAAK,IAAI,eAAe,aAAa,GAAG,YAAY;CAGzE,MAAM,QAAQ,UAAU,KAAM,cAAc;AAE5C,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;;;;;;;;;;;;;;;;AC7B7C,SAAgB,SACf,OACA,QACA,QACA,QACS;CACT,MAAM,EACL,UAAU,OACV,mBAAmB,IACnB,eAAe,IACf,gBAAgB,OACb,UAAU,EAAE;CAGhB,MAAM,aAAa,QAAQ,OAAO,QAAQ,QAAQ,EAAE,SAAS,CAAC;CAG9D,MAAM,kBAAkB,WAAW,OAAO,QAAQ,QAAQ;EACzD;EACA,WAAW;EACX,CAAC;CAGF,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;CAC1D,MAAM,mBAAmB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC;AAC1D,kBAAiB,OAAO,OAAO;AAC/B,kBAAiB,OAAO,OAAO;CAE/B,MAAM,eAAe,iBAAiB;CACtC,MAAM,eAAe,iBAAiB;CAEtC,IAAI;AACJ,KAAI,eAAe,KAAK,eAAe,GAAG;EACzC,IAAI,cAAc;AAClB,OAAK,MAAM,KAAK,iBACf,KAAI,iBAAiB,IAAI,EAAE,CAC1B;AAIF,YAAU,cADQ,KAAK,IAAI,cAAc,aAAa;OAGtD,WAAU;CAIX,MAAM,cAAc,mBAAmB,eAAe;CAGtD,MAAM,SACJ,mBAAmB,aACnB,eAAe,kBACf,gBAAgB,WACjB;AAED,QAAO,KAAK,IAAI,SAAS,KAAK,IAAI,GAAG,MAAM,CAAC;;;;;;;;;;;;;;AC5D7C,SAAgB,SACf,QACA,OACA,QACiB;CACjB,MAAM,EAAE,gBAAgB,SAAS,UAAU,EAAE;AAE7C,KAAI,MAAM,WAAW,EACpB,QAAO;EACN,OAAO,EAAE;EACT,QAAQ;EACR;CAIF,MAAM,SAAmD,MAAM,KAC7D,UAAU;EACV;EACA,OAAO,IAAI,KAAK,MAAM;EACtB,EACD;CAGD,MAAM,WAAW,KAAK,IAAI,GAAG,OAAO,KAAK,MAAM,EAAE,MAAM,CAAC;AAUxD,QAAO;EACN,OAR4B,OAC3B,KAAK,EAAE,MAAM,aAAa;GAC1B,GAAG;GACH,OAAO,gBAAgB,QAAQ,WAAW,QAAQ;GAClD,EAAE,CACF,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,MAAM;EAIlC,QAAQ;EACR;;;;;;;;;;;;;;;;;;;;;;;;;ACnBF,SAAgB,kBACf,OACA,QACA,SAC0B;CAC1B,MAAM,OAAO,SAAS,QAAQ;AAE9B,KAAI,CAAC,MAAM,QAAQ,OAAO,CACzB,OAAM,IAAI,MAAM,gBAAgB,OAAO,+BAA+B;AAGvE,KAAI,OAAO,EACV,OAAM,IAAI,MAAM,kCAAkC,OAAO,KAAK,GAAG;CAIlE,MAAM,oBAAoB,IAAI,IAAY,CAAC,OAAO,CAAC;AAEnD,KAAI,OAAO,GAAG;EACb,MAAM,UAAU,IAAI,IAAY,CAAC,OAAO,CAAC;EAEzC,MAAM,QAA4B,CAAC,CAAC,QAAQ,EAAE,CAAC;AAE/C,SAAO,MAAM,SAAS,GAAG;GACxB,MAAM,QAAQ,MAAM,OAAO;AAC3B,OAAI,UAAU,KAAA,EAAW;GACzB,MAAM,CAAC,SAAS,YAAY;AAE5B,OAAI,WAAW;SACT,MAAM,aAAa,MAAM,WAAW,QAAQ,CAChD,KAAI,CAAC,QAAQ,IAAI,UAAU,EAAE;AAC5B,aAAQ,IAAI,UAAU;AACtB,uBAAkB,IAAI,UAAU;AAChC,WAAM,KAAK,CAAC,WAAW,WAAW,EAAE,CAAC;;;;;CAQ1C,MAAM,SAAS,MAAM,WAClB,cAAA,kBAAkB,UAAgB,GAClC,cAAA,kBAAkB,YAAkB;AAGvC,MAAK,MAAM,UAAU,mBAAmB;EACvC,MAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,MAAI,aAAa,KAAA,EAChB,QAAO,QAAQ,SAAS;;AAK1B,MAAK,MAAM,QAAQ,MAAM,OAAO,CAC/B,KACC,kBAAkB,IAAI,KAAK,OAAO,IAClC,kBAAkB,IAAI,KAAK,OAAO,CAElC,QAAO,QAAQ,KAAK;AAItB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;ACvER,SAAgB,aACf,OACA,GAC0B;AAC1B,KAAI,IAAI,EACP,OAAM,IAAI,MAAM,+BAA+B,OAAO,EAAE,GAAG;CAI5D,MAAM,4BAAY,IAAI,KAAa;CACnC,MAAM,0BAAU,IAAI,KAAqB;AAEzC,MAAK,MAAM,UAAU,MAAM,SAAS,EAAE;AACrC,YAAU,IAAI,OAAO;EAErB,MAAM,MAAM,MAAM,WACf,MAAM,OAAO,QAAQ,OAAO,GAC5B,MAAM,OAAO,OAAO;AACvB,UAAQ,IAAI,QAAQ,IAAI;;CAIzB,MAAM,WAAqB,EAAE;AAE7B,MAAK,MAAM,CAAC,QAAQ,QAAQ,QAC3B,KAAI,MAAM,EACT,UAAS,KAAK,OAAO;AAKvB,QAAO,SAAS,SAAS,GAAG;EAC3B,MAAM,SAAS,SAAS,OAAO;AAC/B,MAAI,WAAW,KAAA,EAAW;AAE1B,MAAI,CAAC,UAAU,IAAI,OAAO,CACzB;AAGD,YAAU,OAAO,OAAO;EAGxB,MAAM,aAAa,MAAM,WACtB,MAAM,WAAW,QAAQ,OAAO,GAChC,MAAM,WAAW,OAAO;AAE3B,OAAK,MAAM,aAAa,WACvB,KAAI,UAAU,IAAI,UAAU,EAAE;GAE7B,MAAM,UADa,QAAQ,IAAI,UAAU,IAAI,KACjB;AAC5B,WAAQ,IAAI,WAAW,OAAO;AAE9B,OAAI,SAAS,KAAK,WAAW,IAAI,EAEhC,UAAS,KAAK,UAAU;;;CAO5B,MAAM,SAAS,MAAM,WAClB,cAAA,kBAAkB,UAAgB,GAClC,cAAA,kBAAkB,YAAkB;AAGvC,MAAK,MAAM,UAAU,WAAW;EAC/B,MAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,MAAI,aAAa,KAAA,EAChB,QAAO,QAAQ,SAAS;;AAK1B,MAAK,MAAM,QAAQ,MAAM,OAAO,CAC/B,KAAI,UAAU,IAAI,KAAK,OAAO,IAAI,UAAU,IAAI,KAAK,OAAO,CAC3D,QAAO,QAAQ,KAAK;AAItB,QAAO;;;;;;;;;;;;;;;ACxFR,SAAS,mBACR,OACA,GACA,GACS;CACT,MAAM,cAAc,IAAI,IAAI,MAAM,WAAW,EAAE,CAAC;CAChD,IAAI,QAAQ;AAEZ,MAAK,MAAM,KAAK,MAAM,WAAW,EAAE,CAClC,KAAI,MAAM,KAAK,YAAY,IAAI,EAAE,CAChC;AAIF,QAAO;;;;;;;;;;;;;;;;;;;;;;AAuBR,SAAgB,cACf,OACA,GAC0B;AAC1B,KAAI,IAAI,EACP,OAAM,IAAI,MAAM,6BAA6B,OAAO,EAAE,GAAG;CAG1D,MAAM,eAAe,IAAI;CAIzB,MAAM,4BAAY,IAAI,KAA0B;CAChD,MAAM,2BAAW,IAAI,KAAgB;CACrC,MAAM,iCAAiB,IAAI,KAAa;AAExC,MAAK,MAAM,UAAU,MAAM,SAAS,CACnC,WAAU,IAAI,wBAAQ,IAAI,KAAK,CAAC;AAIjC,MAAK,MAAM,QAAQ,MAAM,OAAO,EAAE;EACjC,MAAM,EAAE,QAAQ,WAAW;AAG3B,YAAU,IAAI,OAAO,EAAE,IAAI,OAAO;AAClC,YAAU,IAAI,OAAO,EAAE,IAAI,OAAO;EAGlC,MAAM,MACL,SAAS,SAAS,GAAG,OAAO,IAAI,WAAW,GAAG,OAAO,IAAI;AAC1D,WAAS,IAAI,KAAK,KAAK;AACvB,iBAAe,IAAI,IAAI;;CAIxB,MAAM,iCAAiB,IAAI,KAAqB;CAChD,MAAM,gBAA0B,EAAE;AAElC,MAAK,MAAM,OAAO,gBAAgB;EACjC,MAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,MAAI,SAAS,KAAA,GAAW;GACvB,MAAM,QAAQ,mBAAmB,OAAO,KAAK,QAAQ,KAAK,OAAO;AACjE,kBAAe,IAAI,KAAK,MAAM;AAC9B,OAAI,QAAQ,aACX,eAAc,KAAK,IAAI;;;AAM1B,QAAO,cAAc,SAAS,GAAG;EAChC,MAAM,UAAU,cAAc,OAAO;AACrC,MAAI,YAAY,KAAA,EAAW;AAE3B,MAAI,CAAC,eAAe,IAAI,QAAQ,CAC/B;AAGD,iBAAe,OAAO,QAAQ;EAC9B,MAAM,OAAO,SAAS,IAAI,QAAQ;AAElC,MAAI,SAAS,KAAA,EACZ;EAGD,MAAM,EAAE,QAAQ,WAAW;AAG3B,YAAU,IAAI,OAAO,EAAE,OAAO,OAAO;AACrC,YAAU,IAAI,OAAO,EAAE,OAAO,OAAO;EAIrC,MAAM,mBAAmB,UAAU,IAAI,OAAO;AAC9C,MAAI,qBAAqB,KAAA;QACnB,MAAM,KAAK,UAAU,IAAI,OAAO,IAAI,EAAE,CAC1C,KAAI,iBAAiB,IAAI,EAAE,EAAE;IAG5B,MAAM,QAAQ,SAAS,IAAI,GAAG,OAAO,IAAI,MAAM,GAAG,EAAE,IAAI;IACxD,MAAM,QAAQ,SAAS,IAAI,GAAG,OAAO,IAAI,MAAM,GAAG,EAAE,IAAI;AAExD,SAAK,MAAM,eAAe,CAAC,OAAO,MAAM,CACvC,KAAI,eAAe,IAAI,YAAY,EAAE;KAEpC,MAAM,YADe,eAAe,IAAI,YAAY,IAAI,KACxB;AAChC,oBAAe,IAAI,aAAa,SAAS;AAEzC,SAAI,WAAW,gBAAgB,aAAa,eAAe,EAC1D,eAAc,KAAK,YAAY;;;;;CAUtC,MAAM,iCAAiB,IAAI,KAAa;AACxC,MAAK,MAAM,OAAO,gBAAgB;EACjC,MAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,MAAI,SAAS,KAAA,GAAW;AACvB,kBAAe,IAAI,KAAK,OAAO;AAC/B,kBAAe,IAAI,KAAK,OAAO;;;CAKjC,MAAM,SAAS,MAAM,WAClB,cAAA,kBAAkB,UAAgB,GAClC,cAAA,kBAAkB,YAAkB;AAGvC,MAAK,MAAM,UAAU,gBAAgB;EACpC,MAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,MAAI,aAAa,KAAA,EAChB,QAAO,QAAQ,SAAS;;AAK1B,MAAK,MAAM,OAAO,gBAAgB;EACjC,MAAM,OAAO,SAAS,IAAI,IAAI;AAC9B,MACC,SAAS,KAAA,KACT,OAAO,QAAQ,KAAK,OAAO,IAC3B,OAAO,QAAQ,KAAK,OAAO,CAE3B,QAAO,QAAQ,KAAK;;AAItB,QAAO;;;;;;;;;ACzKR,SAAS,oBACR,WACA,OACS;CAIT,MAAM,eAAe,gBAAgB,UAAU;CAC/C,IAAI,aAA4B;AAEhC,MAAK,MAAM,QAAQ,cAAc;EAEhC,MAAM,mBAAmB,MACvB,KAAK,CAAC,GAAG,OAAO;GAChB,MAAM,KAAK,KAAK,MAAM;GACtB,MAAM,KAAK,KAAK,MAAM;AACtB,OAAI,KAAK,KAAK,KAAK,EAClB;AAED,UAAO,KAAK,KACT,GAAG,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG,KAC3B,GAAG,OAAO,GAAG,CAAC,GAAG,OAAO,GAAG;IAC7B,CACD,QAAQ,SAAyB,SAAS,KAAA,EAAU,CACpD,MAAM,CACN,KAAK,IAAI;AAEX,MAAI,eAAe,QAAQ,mBAAmB,WAC7C,cAAa;;AAIf,QAAO,cAAc;;;;;AAMtB,SAAS,gBAAgB,GAAuB;AAC/C,KAAI,MAAM,EAAG,QAAO,CAAC,EAAE,CAAC;AACxB,KAAI,MAAM,EAAG,QAAO,CAAC,CAAC,EAAE,CAAC;CAEzB,MAAM,SAAqB,EAAE;CAC7B,MAAM,MAAM,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,GAAG,MAAM,EAAE;CAElD,SAAS,QAAQ,OAAqB;AACrC,MAAI,UAAU,IAAI,GAAG;AACpB,UAAO,KAAK,CAAC,GAAG,IAAI,CAAC;AACrB;;AAGD,OAAK,IAAI,IAAI,OAAO,IAAI,GAAG,KAAK;GAC/B,MAAM,WAAW,IAAI;GACrB,MAAM,OAAO,IAAI;AACjB,OAAI,aAAa,KAAA,KAAa,SAAS,KAAA,EAAW;AAClD,OAAI,SAAS;AACb,OAAI,KAAK;AACT,WAAQ,QAAQ,EAAE;AAClB,OAAI,SAAS;AACb,OAAI,KAAK;;;AAIX,SAAQ,EAAE;AACV,QAAO;;;;;;;;;;;;;;;;;AAkBR,SAAS,qBACR,OACA,kBACc;CACd,MAAM,yBAAS,IAAI,KAAqB;CACxC,MAAM,YAAY,mCACf,IAAI,KAAyB,GAC7B,KAAA;CAEH,MAAM,WAAW,CAAC,GAAG,MAAM,SAAS,CAAC;CACrC,MAAM,IAAI,SAAS;AAGnB,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC3B,MAAM,KAAK,SAAS;AACpB,MAAI,OAAO,KAAA,EAAW;AACtB,OAAK,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC/B,MAAM,KAAK,SAAS;AACpB,OAAI,OAAO,KAAA,EAAW;AACtB,QAAK,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;IAC/B,MAAM,KAAK,SAAS;AACpB,QAAI,OAAO,KAAA,EAAW;IAEtB,MAAM,QAAkC;KAAC;KAAI;KAAI;KAAG;IACpD,MAAM,QAA4B,EAAE;AASpC,SAAK,MAAM,CAAC,GAAG,MANwB;KACtC,CAAC,GAAG,EAAE;KACN,CAAC,GAAG,EAAE;KACN,CAAC,GAAG,EAAE;KACN,EAEgC;KAChC,MAAM,KAAK,MAAM;KACjB,MAAM,KAAK,MAAM;AACjB,SAAI,OAAO,KAAA,KAAa,OAAO,KAAA,EAAW;AAE1C,SAAI,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EAC7B,OAAM,KAAK,CAAC,GAAG,EAAE,CAAC;cACR,CAAC,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EACvD,OAAM,KAAK,CAAC,GAAG,EAAE,CAAC;cACR,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EAEtD,OAAM,KAAK,CAAC,GAAG,EAAE,CAAC;;IAIpB,MAAM,UAAU,oBAAoB,GAAG,MAAM;IAC7C,MAAM,QAAQ,OAAO,IAAI,QAAQ,IAAI;AACrC,WAAO,IAAI,SAAS,QAAQ,EAAE;AAE9B,QAAI,oBAAoB,cAAc,KAAA,GAAW;AAChD,SAAI,CAAC,UAAU,IAAI,QAAQ,CAC1B,WAAU,IAAI,SAAS,EAAE,CAAC;KAE3B,MAAM,mBAAmB,UAAU,IAAI,QAAQ;AAC/C,SAAI,qBAAqB,KAAA,EACxB,kBAAiB,KAAK;MAAC;MAAI;MAAI;MAAG,CAAC;;;;;AAOxC,QAAO;EAAE;EAAQ;EAAW;;;;;;;;;;;;AAa7B,SAAS,qBACR,OACA,kBACc;CACd,MAAM,yBAAS,IAAI,KAAqB;CACxC,MAAM,YAAY,mCACf,IAAI,KAAyB,GAC7B,KAAA;CAEH,MAAM,WAAW,CAAC,GAAG,MAAM,SAAS,CAAC;CACrC,MAAM,IAAI,SAAS;AAGnB,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;EAC3B,MAAM,KAAK,SAAS;AACpB,MAAI,OAAO,KAAA,EAAW;AACtB,OAAK,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;GAC/B,MAAM,KAAK,SAAS;AACpB,OAAI,OAAO,KAAA,EAAW;AACtB,QAAK,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;IAC/B,MAAM,KAAK,SAAS;AACpB,QAAI,OAAO,KAAA,EAAW;AACtB,SAAK,IAAI,IAAI,IAAI,GAAG,IAAI,GAAG,KAAK;KAC/B,MAAM,KAAK,SAAS;AACpB,SAAI,OAAO,KAAA,EAAW;KAEtB,MAAM,QAA0C;MAAC;MAAI;MAAI;MAAI;MAAG;KAChE,MAAM,QAA4B,EAAE;AAYpC,UAAK,MAAM,CAAC,GAAG,MATwB;MACtC,CAAC,GAAG,EAAE;MACN,CAAC,GAAG,EAAE;MACN,CAAC,GAAG,EAAE;MACN,CAAC,GAAG,EAAE;MACN,CAAC,GAAG,EAAE;MACN,CAAC,GAAG,EAAE;MACN,EAEgC;MAChC,MAAM,KAAK,MAAM;MACjB,MAAM,KAAK,MAAM;AACjB,UAAI,OAAO,KAAA,KAAa,OAAO,KAAA,EAAW;AAE1C,UAAI,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EAC7B,OAAM,KAAK,CAAC,GAAG,EAAE,CAAC;eACR,CAAC,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EACvD,OAAM,KAAK,CAAC,GAAG,EAAE,CAAC;eACR,MAAM,YAAY,MAAM,QAAQ,IAAI,GAAG,KAAK,KAAA,EAEtD,OAAM,KAAK,CAAC,GAAG,EAAE,CAAC;;KAIpB,MAAM,UAAU,oBAAoB,GAAG,MAAM;KAC7C,MAAM,QAAQ,OAAO,IAAI,QAAQ,IAAI;AACrC,YAAO,IAAI,SAAS,QAAQ,EAAE;AAE9B,SAAI,oBAAoB,cAAc,KAAA,GAAW;AAChD,UAAI,CAAC,UAAU,IAAI,QAAQ,CAC1B,WAAU,IAAI,SAAS,EAAE,CAAC;MAE3B,MAAM,mBAAmB,UAAU,IAAI,QAAQ;AAC/C,UAAI,qBAAqB,KAAA,EACxB,kBAAiB,KAAK;OAAC;OAAI;OAAI;OAAI;OAAG,CAAC;;;;;;AAQ7C,QAAO;EAAE;EAAQ;EAAW;;;;;AAM7B,IAAM,gBAA6C,IAAI,IAAI;CAC1D,CAAC,IAAI,QAAQ;CACb,CAAC,OAAO,SAAS;CACjB,CAAC,WAAW,SAAS;CACrB,CAAC,WAAW,SAAS;CACrB,CAAC,eAAe,WAAW;CAC3B,CAAC;;;;AAKF,IAAM,gBAA6C,IAAI,IAAI;CAC1D,CAAC,IAAI,QAAQ;CACb,CAAC,OAAO,SAAS;CACjB,CAAC,WAAW,SAAS;CACrB,CAAC,eAAe,SAAS;CACzB,CAAC,eAAe,WAAW;CAC3B,CAAC,mBAAmB,MAAM;CAC1B,CAAC,eAAe,SAAS;CACzB,CAAC,mBAAmB,UAAU;CAC9B,CAAC,uBAAuB,UAAU;CAClC,CAAC,2BAA2B,KAAK;CACjC,CAAC;;;;;;;;;;;;;;;;;;;;;;AAuBF,SAAgB,gBACf,OACA,MACc;AAEd,QAAO,SAAS,IACb,qBAAqB,OAAO,MAAM,GAClC,qBAAqB,OAAO,MAAM;;;;;;;;;;AAWtC,SAAgB,6BAIf,OACA,MACA,kBACc;AACd,QAAO,SAAS,IACb,qBAAqB,OAAO,iBAAiB,GAC7C,qBAAqB,OAAO,iBAAiB;;;;;;;;;AAUjD,SAAgB,aAAa,SAAiB,MAAqB;AAElE,SADc,SAAS,IAAI,gBAAgB,eAC9B,IAAI,QAAQ,IAAI;;;;;;;;;;;;;;;;;;;AClU9B,SAAgB,uBACf,OACA,OAC0B;CAC1B,MAAM,SAAS,MAAM,WAClB,cAAA,kBAAkB,UAAgB,GAClC,cAAA,kBAAkB,YAAkB;AAGvC,MAAK,MAAM,UAAU,OAAO;EAC3B,MAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,MAAI,aAAa,KAAA,EAChB,QAAO,QAAQ,SAAS;;AAK1B,MAAK,MAAM,QAAQ,MAAM,OAAO,CAC/B,KAAI,OAAO,QAAQ,KAAK,OAAO,IAAI,OAAO,QAAQ,KAAK,OAAO,CAC7D,QAAO,QAAQ,KAAK;AAItB,QAAO;;;;;;;;;;;;;;;;;;;;;;;;ACPR,SAAgB,eACf,OACA,SAC0B;CAC1B,MAAM,EACL,eACA,eACA,iBAAiB,UACd,WAAW,EAAE;CAEjB,MAAM,SAAS,MAAM,WAClB,cAAA,kBAAkB,UAAgB,GAClC,cAAA,kBAAkB,YAAkB;CAGvC,MAAM,gCAAgB,IAAI,KAAa;AAGvC,MAAK,MAAM,UAAU,MAAM,SAAS,EAAE;EACrC,MAAM,WAAW,MAAM,QAAQ,OAAO;AACtC,MAAI,aAAa,KAAA;OACZ,kBAAkB,KAAA,KAAa,cAAc,SAAS,EAAE;AAC3D,WAAO,QAAQ,SAAS;AACxB,kBAAc,IAAI,OAAO;;;;AAM5B,MAAK,MAAM,QAAQ,MAAM,OAAO,EAAE;AACjC,MAAI,CAAC,cAAc,IAAI,KAAK,OAAO,IAAI,CAAC,cAAc,IAAI,KAAK,OAAO,CACrE;AAED,MAAI,kBAAkB,KAAA,KAAa,cAAc,KAAK,CACrD,QAAO,QAAQ,KAAK;;AAKtB,KAAI,gBAAgB;EACnB,MAAM,gBAA0B,EAAE;AAClC,OAAK,MAAM,UAAU,OAAO,SAAS,CACpC,KAAI,OAAO,OAAO,OAAO,KAAK,EAC7B,eAAc,KAAK,OAAO;AAG5B,OAAK,MAAM,UAAU,cACpB,QAAO,WAAW,OAAO;;AAI3B,QAAO"}
|