{"version":3,"file":"index.mjs","names":[],"sources":["../../src/atoms.ts","../../src/path-resolution.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Atom } from '@effect-atom/atom';\n\nimport { type MulticastObservable } from '@dxos/async';\n\nconst observableFamily = Atom.family((observable: MulticastObservable<any>) => {\n  return Atom.make((get) => {\n    const subscription = observable.subscribe((value) => get.setSelf(value));\n\n    get.addFinalizer(() => subscription.unsubscribe());\n\n    return observable.get();\n  });\n});\n\n/**\n * Creates an Atom.Atom<T> from a MulticastObservable<T>\n * Will return the same atom instance for the same observable.\n */\nexport const fromObservable = <T>(observable: MulticastObservable<T>): Atom.Atom<T> => {\n  return observableFamily(observable) as Atom.Atom<T>;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Array from 'effect/Array';\nimport * as Effect from 'effect/Effect';\nimport * as Function from 'effect/Function';\nimport * as Option from 'effect/Option';\nimport * as Record from 'effect/Record';\n\nimport { EffectEx } from '@dxos/effect';\nimport { EntityId, SpaceId } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { Position } from '@dxos/util';\n\nimport * as Graph from './graph';\nimport * as GraphBuilder from './graph-builder';\nimport * as Node from './node';\n\n/**\n * A single `(prefix, id?)` pair as parsed by `@dxos/app-toolkit`'s `UrlPath.parse`. Kept as a\n * plain structural type here (rather than importing `UrlPath.Pair`) because app-graph must not\n * depend on app-toolkit.\n */\nexport type UrlPair = {\n  key: string;\n  id?: string;\n  workspace: string;\n};\n\n/**\n * A resolved pair: the index it occupied in the parsed chain, and the qualified graph node id it\n * resolved to. `null` in the caller's result array means the pair didn't resolve (unknown key or\n * no matching node); how an unresolved pair is surfaced is the caller's concern.\n */\nexport type ResolvedPair = {\n  pairIndex: number;\n  nodeId: string;\n};\n\n/** The graph-path representation of a node, the reverse of a `UrlPair` (`id` is absent for singleton keys). */\nexport type RepresentedNode = {\n  key: string;\n  id?: string;\n  workspace: string;\n};\n\n/** Reserved words that can never be registered as a `urlKey`, duplicated from `UrlPath.isReservedKey`\n * (rather than imported) to keep app-graph free of an app-toolkit dependency. A key declared by a\n * binding — including the `anchor` and `linked` tiers — is never reserved. */\nconst RESERVED_URL_KEYS = new Set(['reset', 'redirect', 'not-found']);\n\nconst isReservedUrlKey = (key: string): boolean =>\n  RESERVED_URL_KEYS.has(key) || SpaceId.isValid(key) || EntityId.isValid(key);\n\n/**\n * Ordered `urlKey`-declaring extensions: sorted by Position then insertion order (matching\n * connector-ordering semantics elsewhere in this package), with reserved-word keys dropped (each with\n * a `log.warn`). A single key may legitimately be shared by more than one extension (e.g. plugin-space\n * declares `collection` on both the root-collection children connector and the nested-collection\n * children connector, which together address any object reachable through a space's collection tree),\n * so keys are NOT deduped here — {@link buildKeyTable} groups the sharers under one key and forward\n * resolution matches a node produced by any of them. Shared with {@link buildUrlKeyTable} so the\n * reservation rule is expressed exactly once.\n */\ntype UrlKeyedExtension = GraphBuilder.BuilderExtension & { url: GraphBuilder.UrlBinding };\n\n/** Narrows to an extension that declared a URL binding, so callers need no non-null assertion. */\nconst isUrlKeyed = (extension: GraphBuilder.BuilderExtension): extension is UrlKeyedExtension => !!extension.url?.key;\n\nconst getKeyedExtensions = (builder: GraphBuilder.GraphBuilder): UrlKeyedExtension[] => {\n  const extensions = Function.pipe(Record.values(builder.getExtensions()), Array.sortBy(Position.compare));\n\n  const keyed: UrlKeyedExtension[] = [];\n  for (const extension of extensions) {\n    if (!isUrlKeyed(extension)) {\n      continue;\n    }\n    if (isReservedUrlKey(extension.url.key)) {\n      log.warn('reserved URL prefix key', { key: extension.url.key, extension: extension.id });\n      continue;\n    }\n    keyed.push(extension);\n  }\n  return keyed;\n};\n\n/**\n * Build the global `urlKey -> extensionIds` table from the builder's current extensions. Recomputed\n * on every call — cheap (a synchronous scan of already-registered extensions) and always current, so\n * activating/deactivating plugins can never leave a stale table around. A key maps to the ordered list\n * of every extension that declared it (usually one); forward resolution treats a node produced by any\n * of them as a match for the key.\n */\nconst buildKeyTable = (builder: GraphBuilder.GraphBuilder): Map<string, string[]> => {\n  const table = new Map<string, string[]>();\n  for (const extension of getKeyedExtensions(builder)) {\n    const key = extension.url.key;\n    const existing = table.get(key);\n    if (existing) {\n      existing.push(extension.id);\n    } else {\n      table.set(key, [extension.id]);\n    }\n  }\n  return table;\n};\n\n/**\n * A single registered URL prefix key, in the shape `UrlPath.parse` expects. Kept as a plain\n * structural type here (rather than importing `UrlPath.KeyTableEntry`) because app-graph must not\n * depend on app-toolkit.\n */\nexport type UrlKeyTableEntry = { key: string; hasId: boolean; anchor: boolean };\n\n/**\n * Build the `urlKey -> { key, hasId }` table consumed by `UrlPath.parse`, straight from the\n * builder's current `urlKey`/`urlKeyHasId` declarations — the \"registration, not parser\" property\n * the URL grammar requires. Callers (the layout url-handler) pass this to `UrlPath.parse`\n * to tokenize a pathname into a pair chain.\n */\nexport const buildUrlKeyTable = (builder: GraphBuilder.GraphBuilder): Map<string, UrlKeyTableEntry> => {\n  const table = new Map<string, UrlKeyTableEntry>();\n  // The grammar's fixed tiers are configured on the builder, not declared by any extension: the anchor\n  // rebases the chain, and the linked key addresses a `~<variant>` child of the preceding item.\n  const { anchorKey, linkedKey } = builder.urlGrammar;\n  if (anchorKey) {\n    table.set(anchorKey, { key: anchorKey, hasId: true, anchor: true });\n  }\n  if (linkedKey) {\n    table.set(linkedKey, { key: linkedKey, hasId: true, anchor: false });\n  }\n  for (const extension of getKeyedExtensions(builder)) {\n    const key = extension.url.key;\n    // The tokenizer's flat lookup is derived from `kind`: a singleton has no id.\n    const hasId = extension.url.kind !== 'singleton';\n    const anchor = false;\n    const existing = table.get(key);\n    if (existing && existing.hasId !== hasId) {\n      // Extensions that share a key must agree on their kind — the parse table has one entry per key.\n      // A mismatch is a declaration bug; keep the first and warn.\n      log.warn('conflicting kind for shared URL prefix key', { key, extension: extension.id });\n      continue;\n    }\n    table.set(key, { key, hasId, anchor });\n  }\n  return table;\n};\n\n/**\n * Expand every ancestor prefix of a qualified node id (including the id itself), then flush once.\n * Mirrors `@dxos/app-toolkit`'s `NotFound.expandPath` technique, reimplemented locally so app-graph\n * doesn't depend on app-toolkit.\n */\nconst expandAncestors = async (builder: GraphBuilder.GraphBuilder, qualifiedId: string): Promise<void> => {\n  const segments = qualifiedId.split('/');\n  for (let index = 1; index <= segments.length; index++) {\n    Graph.expand(builder.graph, segments.slice(0, index).join('/'), 'child');\n  }\n  await GraphBuilder.flush(builder);\n};\n\n/** An extension registered for a URL key: its path (static segments or a dynamic resolver). */\ntype KeyedExtension = { id: string; path: string[] | GraphBuilder.PathResolver };\n\n/**\n * Materialize a candidate qualified node id and confirm it exists: expand its ancestors, then check\n * the node is known. Returns the id on success, `null` otherwise.\n */\nconst materializeCandidate = async (\n  builder: GraphBuilder.GraphBuilder,\n  candidateId: string,\n): Promise<string | null> => {\n  await expandAncestors(builder, candidateId);\n  return Option.isSome(Graph.getNode(builder.graph, candidateId)) ? candidateId : null;\n};\n\n/**\n * Resolve a single `(key, id)` pair to a qualified node id, anchored at the workspace base. Resolution\n * is fully explicit — no search. Each keyed extension's `path` is one of:\n *   1. Static segments (`string[]`, the preferred deterministic case): the id is the `+`-joined node\n *      segments *after* the path, so a fixed-depth nested shape (e.g. `db/<slug>+<id>`) resolves with\n *      no resolver — split the id back into segments and expand the exact path.\n *   2. A dynamic {@link GraphBuilder.PathResolver} (recursive/mutable shapes, i.e. nested collections),\n *      whose candidate is materialized and verified the same way.\n * Static paths are tried before resolvers; an unmatched pair yields `null`.\n */\nconst resolveKeyId = async (\n  builder: GraphBuilder.GraphBuilder,\n  workspaceBaseId: string,\n  workspace: string,\n  extensions: ReadonlyArray<KeyedExtension>,\n  id: string,\n): Promise<string | null> => {\n  // 1. Static segments: an exact candidate, no search (type sections, database/inbox objects, etc.).\n  const idSegments = id.split(builder.urlGrammar.tailSeparator);\n  for (const extension of extensions) {\n    if (Array.isArray(extension.path)) {\n      const resolved = await materializeCandidate(\n        builder,\n        [workspaceBaseId, ...extension.path, ...idSegments].join('/'),\n      );\n      if (resolved) {\n        return resolved;\n      }\n    }\n  }\n\n  // 2. Dynamic resolver: the extension computes the candidate id from runtime data (self-contained\n  // Effect; a defect degrades to no candidate rather than crashing resolution).\n  for (const extension of extensions) {\n    if (typeof extension.path === 'function') {\n      const candidateId = await EffectEx.runPromise(\n        extension.path({ id, workspace, workspaceBaseId }).pipe(Effect.catchAllDefect(() => Effect.succeed(null))),\n      );\n      if (candidateId) {\n        const resolved = await materializeCandidate(builder, candidateId);\n        if (resolved) {\n          return resolved;\n        }\n      }\n    }\n  }\n\n  return null;\n};\n\n/**\n * Resolve a linked pair (`<key>/<variant>`) against the item it attaches to: the linked-segment child\n * (`<precedingNodeId>/~<variant>`) of `precedingNodeId`. A single expand, no BFS — a linked node is\n * always a direct child of the item it attaches to. Matched by the variant (the `~`-stripped last\n * segment), so it works regardless of which extension produced the node.\n */\nconst resolveLinked = async (\n  builder: GraphBuilder.GraphBuilder,\n  precedingNodeId: string,\n  variant: string,\n): Promise<string | null> => {\n  Graph.expand(builder.graph, precedingNodeId, 'child');\n  await GraphBuilder.flush(builder);\n\n  const linkedSegment = `${builder.urlGrammar.linkedPrefix}${variant}`;\n  const match = Graph.getConnections(builder.graph, precedingNodeId, 'child').find(\n    (child) => child.id.slice(child.id.lastIndexOf('/') + 1) === linkedSegment,\n  );\n  return match?.id ?? null;\n};\n\nconst resolveUrlAsync = async (\n  builder: GraphBuilder.GraphBuilder,\n  parsed: { workspace: string; pairs: ReadonlyArray<UrlPair> },\n): Promise<Array<ResolvedPair | null>> => {\n  const keyTable = buildKeyTable(builder);\n  const allExtensions = builder.getExtensions();\n  const results: Array<ResolvedPair | null> = [];\n  // Tracks the most recently resolved *item* node, the base for `linked` pairs — a linked pair\n  // always attaches to the preceding item, never to another linked pair.\n  let lastItemNodeId: string | undefined;\n\n  for (let pairIndex = 0; pairIndex < parsed.pairs.length; pairIndex++) {\n    const pair = parsed.pairs[pairIndex];\n\n    // Linked pair: resolves against the preceding item by variant, not the workspace base — the linked\n    // resolution tier. Produced by no extension (it is a grammar key), so it is matched before the key\n    // table, and it is not itself an item, so it does not become the base for a following linked pair.\n    if (pair.key === builder.urlGrammar.linkedKey) {\n      const nodeId = lastItemNodeId && pair.id ? await resolveLinked(builder, lastItemNodeId, pair.id) : null;\n      results.push(nodeId ? { pairIndex, nodeId } : null);\n      continue;\n    }\n\n    const extensionIdList = keyTable.get(pair.key);\n    if (!extensionIdList || extensionIdList.length === 0) {\n      log.warn('unknown URL prefix key', { key: pair.key });\n      results.push(null);\n      if (pair.id !== undefined) {\n        lastItemNodeId = undefined;\n      }\n      continue;\n    }\n\n    const workspaceBaseId = `${Node.RootId}/${pair.workspace}`;\n    const extensions: KeyedExtension[] = [];\n    for (const extensionId of extensionIdList) {\n      const url = allExtensions[extensionId]?.url;\n      if (url) {\n        extensions.push({ id: extensionId, path: url.path });\n      }\n    }\n    // A normal key addresses a node by id; an id-less singleton key (e.g. `home`) addresses a fixed node\n    // whose terminal segment IS the key — resolve it the same way with the key standing in for the id\n    // (`root/<ws>/<...path>/<key>`).\n    const nodeId = await resolveKeyId(builder, workspaceBaseId, pair.workspace, extensions, pair.id ?? pair.key);\n    results.push(nodeId ? { pairIndex, nodeId } : null);\n    lastItemNodeId = nodeId ?? undefined;\n  }\n\n  return results;\n};\n\n/**\n * Resolve a parsed URL's pair chain to graph node ids, walking left to right. Resolution is fully\n * explicit — each keyed extension declares either a static `urlPath` template (preferred) or a dynamic\n * `resolve` Effect (data-dependent shapes); there is no generic search. Reverse mapping still uses the\n * provenance the builder tracks (see `GraphBuilder.getNodeExtensionId`).\n *\n * An unknown key, or a key whose extension produces no matching node, yields `null` at that index;\n * how a `null` is surfaced is the caller's concern. A linked pair resolves against the *preceding\n * item's* node, not the raw preceding pair.\n */\nexport const resolveUrl = (\n  builder: GraphBuilder.GraphBuilder,\n  parsed: { workspace: string; pairs: ReadonlyArray<UrlPair> },\n): Effect.Effect<Array<ResolvedPair | null>> => Effect.promise(() => resolveUrlAsync(builder, parsed));\n\n/**\n * Reverse-map a graph node id back to its `(key, id?, workspace)` representation, the inverse of\n * `resolveUrl`. A linked node (a `~<variant>` segment) maps to the declared `linked` key\n * with the variant as its id — independent of the producing extension, so every linked node is\n * addressable. Any other node maps via its producing extension's `urlKey` (`getNodeExtensionId`);\n * a node with no key-declaring producer returns `Option.none()` (unmapped — serialization skips it\n * with a dev-time warning one layer up, per the design's \"unmapped nodes\" rule).\n */\nexport const representNode = (builder: GraphBuilder.GraphBuilder, nodeId: string): Option.Option<RepresentedNode> => {\n  const segments = nodeId.split('/');\n  // Canonical node ids are `root/<workspace>/...`; the workspace is always the second segment.\n  const workspace = segments[1];\n  if (!workspace) {\n    return Option.none();\n  }\n\n  const lastSegment = segments[segments.length - 1];\n  if (lastSegment.startsWith(builder.urlGrammar.linkedPrefix)) {\n    // Linked node: keyed by the grammar's `linked` key, with the variant (the `~`-stripped segment) as\n    // its id — matched by the convention, independent of the producing extension.\n    const linkedKey = builder.urlGrammar.linkedKey;\n    if (linkedKey) {\n      return Option.some({ key: linkedKey, id: lastSegment.slice(builder.urlGrammar.linkedPrefix.length), workspace });\n    }\n  }\n\n  const extensionId = builder.getNodeExtensionId(nodeId);\n  if (!extensionId) {\n    return Option.none();\n  }\n  const url = builder.getExtensions()[extensionId]?.url;\n  if (!url) {\n    return Option.none();\n  }\n\n  // The (key, id?) representation is derived from the node id + binding (a singleton has no id; a\n  // resolver-backed key keeps just the object id; a static path `+`-joins the segments after the path) —\n  // the same derivation the builder uses to stamp `urlSegment`.\n  return Option.some({ ...GraphBuilder.urlRepresentation(nodeId, url, builder.urlGrammar.tailSeparator), workspace });\n};\n"],"mappings":";;;;;;;;;;;;;AAQA,IAAM,mBAAmB,KAAK,QAAQ,eAAyC;CAC7E,OAAO,KAAK,MAAM,QAAQ;EACxB,MAAM,eAAe,WAAW,WAAW,UAAU,IAAI,QAAQ,KAAK,CAAC;EAEvE,IAAI,mBAAmB,aAAa,YAAY,CAAC;EAEjD,OAAO,WAAW,IAAI;CACxB,CAAC;AACH,CAAC;;;;;AAMD,IAAa,kBAAqB,eAAqD;CACrF,OAAO,iBAAiB,UAAU;AACpC;;;;;;;;;;;;AC0BA,IAAM,oCAAoB,IAAI,IAAI;CAAC;CAAS;CAAY;AAAW,CAAC;AAEpE,IAAM,oBAAoB,QACxB,kBAAkB,IAAI,GAAG,KAAK,QAAQ,QAAQ,GAAG,KAAK,SAAS,QAAQ,GAAG;;AAe5E,IAAM,cAAc,cAA6E,CAAC,CAAC,UAAU,KAAK;AAElH,IAAM,sBAAsB,YAA4D;CACtF,MAAM,aAAa,SAAS,KAAK,OAAO,OAAO,QAAQ,cAAc,CAAC,GAAG,MAAM,OAAO,SAAS,OAAO,CAAC;CAEvG,MAAM,QAA6B,CAAC;CACpC,KAAK,MAAM,aAAa,YAAY;EAClC,IAAI,CAAC,WAAW,SAAS,GACvB;EAEF,IAAI,iBAAiB,UAAU,IAAI,GAAG,GAAG;GACvC,IAAI,KAAK,2BAA2B;IAAE,KAAK,UAAU,IAAI;IAAK,WAAW,UAAU;GAAG,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACvF;EACF;EACA,MAAM,KAAK,SAAS;CACtB;CACA,OAAO;AACT;;;;;;;;AASA,IAAM,iBAAiB,YAA8D;CACnF,MAAM,wBAAQ,IAAI,IAAsB;CACxC,KAAK,MAAM,aAAa,mBAAmB,OAAO,GAAG;EACnD,MAAM,MAAM,UAAU,IAAI;EAC1B,MAAM,WAAW,MAAM,IAAI,GAAG;EAC9B,IAAI,UACF,SAAS,KAAK,UAAU,EAAE;OAE1B,MAAM,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;CAEjC;CACA,OAAO;AACT;;;;;;;AAeA,IAAa,oBAAoB,YAAsE;CACrG,MAAM,wBAAQ,IAAI,IAA8B;CAGhD,MAAM,EAAE,WAAW,cAAc,QAAQ;CACzC,IAAI,WACF,MAAM,IAAI,WAAW;EAAE,KAAK;EAAW,OAAO;EAAM,QAAQ;CAAK,CAAC;CAEpE,IAAI,WACF,MAAM,IAAI,WAAW;EAAE,KAAK;EAAW,OAAO;EAAM,QAAQ;CAAM,CAAC;CAErE,KAAK,MAAM,aAAa,mBAAmB,OAAO,GAAG;EACnD,MAAM,MAAM,UAAU,IAAI;EAE1B,MAAM,QAAQ,UAAU,IAAI,SAAS;EACrC,MAAM,SAAS;EACf,MAAM,WAAW,MAAM,IAAI,GAAG;EAC9B,IAAI,YAAY,SAAS,UAAU,OAAO;GAGxC,IAAI,KAAK,8CAA8C;IAAE;IAAK,WAAW,UAAU;GAAG,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACvF;EACF;EACA,MAAM,IAAI,KAAK;GAAE;GAAK;GAAO;EAAO,CAAC;CACvC;CACA,OAAO;AACT;;;;;;AAOA,IAAM,kBAAkB,OAAO,SAAoC,gBAAuC;CACxG,MAAM,WAAW,YAAY,MAAM,GAAG;CACtC,KAAK,IAAI,QAAQ,GAAG,SAAS,SAAS,QAAQ,SAC5C,OAAa,QAAQ,OAAO,SAAS,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,GAAG,GAAG,OAAO;CAEzE,MAAM,MAAmB,OAAO;AAClC;;;;;AASA,IAAM,uBAAuB,OAC3B,SACA,gBAC2B;CAC3B,MAAM,gBAAgB,SAAS,WAAW;CAC1C,OAAO,OAAO,OAAO,QAAc,QAAQ,OAAO,WAAW,CAAC,IAAI,cAAc;AAClF;;;;;;;;;;;AAYA,IAAM,eAAe,OACnB,SACA,iBACA,WACA,YACA,OAC2B;CAE3B,MAAM,aAAa,GAAG,MAAM,QAAQ,WAAW,aAAa;CAC5D,KAAK,MAAM,aAAa,YACtB,IAAI,MAAM,QAAQ,UAAU,IAAI,GAAG;EACjC,MAAM,WAAW,MAAM,qBACrB,SACA;GAAC;GAAiB,GAAG,UAAU;GAAM,GAAG;EAAU,CAAC,CAAC,KAAK,GAAG,CAC9D;EACA,IAAI,UACF,OAAO;CAEX;CAKF,KAAK,MAAM,aAAa,YACtB,IAAI,OAAO,UAAU,SAAS,YAAY;EACxC,MAAM,cAAc,MAAM,SAAS,WACjC,UAAU,KAAK;GAAE;GAAI;GAAW;EAAgB,CAAC,CAAC,CAAC,KAAK,OAAO,qBAAqB,OAAO,QAAQ,IAAI,CAAC,CAAC,CAC3G;EACA,IAAI,aAAa;GACf,MAAM,WAAW,MAAM,qBAAqB,SAAS,WAAW;GAChE,IAAI,UACF,OAAO;EAEX;CACF;CAGF,OAAO;AACT;;;;;;;AAQA,IAAM,gBAAgB,OACpB,SACA,iBACA,YAC2B;CAC3B,OAAa,QAAQ,OAAO,iBAAiB,OAAO;CACpD,MAAM,MAAmB,OAAO;CAEhC,MAAM,gBAAgB,GAAG,QAAQ,WAAW,eAAe;CAI3D,OAHc,eAAqB,QAAQ,OAAO,iBAAiB,OAAO,CAAC,CAAC,MACzE,UAAU,MAAM,GAAG,MAAM,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC,MAAM,aAExD,CAAA,EAAO,MAAM;AACtB;AAEA,IAAM,kBAAkB,OACtB,SACA,WACwC;CACxC,MAAM,WAAW,cAAc,OAAO;CACtC,MAAM,gBAAgB,QAAQ,cAAc;CAC5C,MAAM,UAAsC,CAAC;CAG7C,IAAI;CAEJ,KAAK,IAAI,YAAY,GAAG,YAAY,OAAO,MAAM,QAAQ,aAAa;EACpE,MAAM,OAAO,OAAO,MAAM;EAK1B,IAAI,KAAK,QAAQ,QAAQ,WAAW,WAAW;GAC7C,MAAM,SAAS,kBAAkB,KAAK,KAAK,MAAM,cAAc,SAAS,gBAAgB,KAAK,EAAE,IAAI;GACnG,QAAQ,KAAK,SAAS;IAAE;IAAW;GAAO,IAAI,IAAI;GAClD;EACF;EAEA,MAAM,kBAAkB,SAAS,IAAI,KAAK,GAAG;EAC7C,IAAI,CAAC,mBAAmB,gBAAgB,WAAW,GAAG;GACpD,IAAI,KAAK,0BAA0B,EAAE,KAAK,KAAK,IAAI,GAAA;IAAA,YAAA;IAAA,GAAA;IAAA,GAAA;IAAA,GAAA,KAAA;GAAA,CAAC;GACpD,QAAQ,KAAK,IAAI;GACjB,IAAI,KAAK,OAAO,KAAA,GACd,iBAAiB,KAAA;GAEnB;EACF;EAEA,MAAM,kBAAkB,GAAG,OAAY,GAAG,KAAK;EAC/C,MAAM,aAA+B,CAAC;EACtC,KAAK,MAAM,eAAe,iBAAiB;GACzC,MAAM,MAAM,cAAc,YAAY,EAAE;GACxC,IAAI,KACF,WAAW,KAAK;IAAE,IAAI;IAAa,MAAM,IAAI;GAAK,CAAC;EAEvD;EAIA,MAAM,SAAS,MAAM,aAAa,SAAS,iBAAiB,KAAK,WAAW,YAAY,KAAK,MAAM,KAAK,GAAG;EAC3G,QAAQ,KAAK,SAAS;GAAE;GAAW;EAAO,IAAI,IAAI;EAClD,iBAAiB,UAAU,KAAA;CAC7B;CAEA,OAAO;AACT;;;;;;;;;;;AAYA,IAAa,cACX,SACA,WAC8C,OAAO,cAAc,gBAAgB,SAAS,MAAM,CAAC;;;;;;;;;AAUrG,IAAa,iBAAiB,SAAoC,WAAmD;CACnH,MAAM,WAAW,OAAO,MAAM,GAAG;CAEjC,MAAM,YAAY,SAAS;CAC3B,IAAI,CAAC,WACH,OAAO,OAAO,KAAK;CAGrB,MAAM,cAAc,SAAS,SAAS,SAAS;CAC/C,IAAI,YAAY,WAAW,QAAQ,WAAW,YAAY,GAAG;EAG3D,MAAM,YAAY,QAAQ,WAAW;EACrC,IAAI,WACF,OAAO,OAAO,KAAK;GAAE,KAAK;GAAW,IAAI,YAAY,MAAM,QAAQ,WAAW,aAAa,MAAM;GAAG;EAAU,CAAC;CAEnH;CAEA,MAAM,cAAc,QAAQ,mBAAmB,MAAM;CACrD,IAAI,CAAC,aACH,OAAO,OAAO,KAAK;CAErB,MAAM,MAAM,QAAQ,cAAc,CAAC,CAAC,YAAY,EAAE;CAClD,IAAI,CAAC,KACH,OAAO,OAAO,KAAK;CAMrB,OAAO,OAAO,KAAK;EAAE,GAAG,kBAA+B,QAAQ,KAAK,QAAQ,WAAW,aAAa;EAAG;CAAU,CAAC;AACpH"}