{"version":3,"file":"message-reconciliation.cjs","names":[],"sources":["../../src/stream/message-reconciliation.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\n\nexport interface ReconcileMessagesFromValuesOptions {\n  /**\n   * Messages from the authoritative `values.messages` snapshot.\n   */\n  readonly valueMessages: readonly BaseMessage[];\n  /**\n   * Current message projection, including stream-assembled in-flight messages.\n   */\n  readonly currentMessages: readonly BaseMessage[];\n  /**\n   * Index from message id to current message position.\n   */\n  readonly currentIndexById: ReadonlyMap<string, number>;\n  /**\n   * Ids observed in the most recent previous `values.messages` snapshot.\n   * If one of these ids is missing from the next snapshot, it is treated as\n   * an explicit server-side removal.\n   */\n  readonly previousValueMessageIds: ReadonlySet<string>;\n  /**\n   * Optional stream-id filter. When supplied, only these current ids are\n   * eligible to override the values snapshot. When omitted, any id present in\n   * `currentIndexById` is eligible, preserving the root controller's historic\n   * behavior.\n   */\n  readonly streamedMessageIds?: ReadonlySet<string>;\n  /**\n   * Allows callers to keep a values message even when a streamed message with\n   * the same id exists. Used by the root controller when the values message\n   * carries data the current copy lacks (finalized tool calls, or\n   * same-content metadata such as committed `additional_kwargs`).\n   */\n  readonly preferValuesMessage?: (\n    valuesMessage: BaseMessage,\n    streamedMessage: BaseMessage\n  ) => boolean;\n  /**\n   * When true, treat the snapshot as a non-authoritative (older / replayed)\n   * view: never drop a current message just because it is absent from this\n   * snapshot. Used on reconnect, where the content pump replays older\n   * checkpoints after the authoritative `getState()` seed — an older\n   * snapshot legitimately lacks later messages and must not remove them.\n   */\n  readonly addOnly?: boolean;\n}\n\nexport interface ReconciledMessages {\n  readonly messages: readonly BaseMessage[];\n  readonly valueMessageIds: Set<string>;\n}\n\n/**\n * Merge an authoritative `values.messages` snapshot with the current streamed\n * message projection.\n *\n * Values remain authoritative for ordering and removals. Streamed messages\n * remain authoritative for in-flight content that has moved past this\n * snapshot. When the server echoes a same-id message with equal content\n * plus enrichment (tool calls, `additional_kwargs`, …), values win.\n * Stream-only messages are preserved until they either appear in values\n * or are known to have been removed.\n */\nexport function reconcileMessagesFromValues({\n  valueMessages,\n  currentMessages,\n  currentIndexById,\n  previousValueMessageIds,\n  streamedMessageIds,\n  preferValuesMessage,\n  addOnly,\n}: ReconcileMessagesFromValuesOptions): ReconciledMessages {\n  const valueMessageIds = new Set<string>();\n  const merged: BaseMessage[] = [];\n\n  for (const valuesMessage of valueMessages) {\n    const id = normalizedMessageId(valuesMessage);\n    if (id == null) {\n      merged.push(valuesMessage);\n      continue;\n    }\n\n    valueMessageIds.add(id);\n    const streamIdx = currentIndexById.get(id);\n    const canUseStreamed =\n      streamIdx != null &&\n      (streamedMessageIds == null || streamedMessageIds.has(id));\n    const streamedMessage = canUseStreamed\n      ? currentMessages[streamIdx]\n      : undefined;\n\n    if (\n      streamedMessage != null &&\n      preferValuesMessage?.(valuesMessage, streamedMessage) !== true\n    ) {\n      merged.push(streamedMessage);\n    } else {\n      merged.push(valuesMessage);\n    }\n  }\n\n  for (const existing of currentMessages) {\n    const id = normalizedMessageId(existing);\n    if (id == null) continue;\n    if (valueMessageIds.has(id)) continue;\n    // A previously-seen id missing from this snapshot is a server-side\n    // removal — UNLESS this is an older/replayed snapshot (`addOnly`),\n    // where the absence only means \"this earlier checkpoint predates the\n    // message\", not \"the message was removed\".\n    if (!addOnly && previousValueMessageIds.has(id)) continue;\n    if (streamedMessageIds != null && !streamedMessageIds.has(id)) continue;\n    merged.push(existing);\n  }\n\n  return {\n    messages: messagesEqualList(currentMessages, merged)\n      ? currentMessages\n      : merged,\n    valueMessageIds,\n  };\n}\n\n/**\n * Build a position index for keyed messages.\n */\nexport function buildMessageIndex(\n  messages: readonly BaseMessage[]\n): Map<string, number> {\n  const index = new Map<string, number>();\n  messages.forEach((message, idx) => {\n    const id = normalizedMessageId(message);\n    if (id != null) index.set(id, idx);\n  });\n  return index;\n}\n\n/**\n * Decide whether a values message should replace a same-id streamed or\n * optimistic message.\n *\n * Values win when they carry data the current copy lacks:\n *   - finalized tool-call args (see\n *     {@link shouldPreferValuesMessageForToolCalls})\n *   - metadata enrichment or in-place nested metadata mutations with\n *     unchanged content (e.g. server-committed `additional_kwargs`, or\n *     `response_metadata.card.status` updating from `accepted` → `done`)\n *\n * Preferring is asymmetric: a lagging/poorer values snapshot must not\n * replace a richer current copy (seeded `getState()` metadata, messages-\n * channel `usage_metadata`, etc.) merely because the two messages differ.\n * Values that would drop nested metadata keys keep the current copy.\n *\n * In-place leaf mutations are only applied when\n * {@link ShouldPreferValuesMessageOptions.allowInPlaceMutations} is true\n * (the default). Callers pass `false` for stale/`addOnly` reconnect\n * snapshots so an older `accepted` card cannot overwrite a newer `done`.\n *\n * Streamed content still wins when it has moved past this snapshot, so\n * in-flight token streaming is not overwritten by a lagging values event.\n */\nexport interface ShouldPreferValuesMessageOptions {\n  /**\n   * When false, only prefer values for key-adding enrichment (or filling\n   * empty metadata), not for same-key nested leaf mutations. Used for\n   * lagging reconnect/`addOnly` snapshots.\n   *\n   * @default true\n   */\n  readonly allowInPlaceMutations?: boolean;\n}\n\nexport function shouldPreferValuesMessage(\n  valuesMessage: BaseMessage,\n  streamedMessage: BaseMessage,\n  options?: ShouldPreferValuesMessageOptions\n): boolean {\n  if (shouldPreferValuesMessageForToolCalls(valuesMessage, streamedMessage)) {\n    return true;\n  }\n  if (!jsonishEqual(valuesMessage.content, streamedMessage.content)) {\n    return false;\n  }\n  return valuesAddsMetadataEnrichment(valuesMessage, streamedMessage, options);\n}\n\n/** Metadata fields that a values echo may enrich on a same-id message. */\nconst METADATA_ENRICHMENT_KEYS = [\n  \"additional_kwargs\",\n  \"response_metadata\",\n  \"usage_metadata\",\n] as const;\n\n/**\n * True when values adds or mutates metadata without stripping richer\n * fields already present on the current copy.\n *\n * Covers both key additions (optimistic human gaining\n * `additional_kwargs.attachments`) and — when\n * `allowInPlaceMutations` is true — in-place nested mutations of\n * existing keys (HITL card `status: accepted → done`) as long as every\n * nested key on the current field is retained.\n */\nfunction valuesAddsMetadataEnrichment(\n  valuesMessage: BaseMessage,\n  streamedMessage: BaseMessage,\n  options?: ShouldPreferValuesMessageOptions\n): boolean {\n  const allowInPlaceMutations = options?.allowInPlaceMutations !== false;\n  const valuesRecord = valuesMessage as unknown as Record<string, unknown>;\n  const streamedRecord = streamedMessage as unknown as Record<string, unknown>;\n\n  let enriches = false;\n  for (const key of METADATA_ENRICHMENT_KEYS) {\n    const valuesField = valuesRecord[key];\n    const streamedField = streamedRecord[key];\n    if (jsonishEqual(valuesField, streamedField)) continue;\n\n    const valuesEmpty = isEmptyMeta(valuesField);\n    const streamedEmpty = isEmptyMeta(streamedField);\n\n    if (valuesEmpty && !streamedEmpty) {\n      // Preferring values would erase richer current metadata.\n      return false;\n    }\n    if (!valuesEmpty && streamedEmpty) {\n      enriches = true;\n      continue;\n    }\n    // Both non-empty and differ.\n    if (allowInPlaceMutations) {\n      // Prefer values when it retains every nested key (leaf mutations\n      // and added keys allowed). Dropping keys would erase richer\n      // current metadata — keep the current copy.\n      if (retainsAllNestedKeys(valuesField, streamedField)) {\n        enriches = true;\n        continue;\n      }\n      return false;\n    }\n    // Stale/addOnly snapshots: only treat as enrichment when values is\n    // a shallow key-superset with equal existing values. Same-key leaf\n    // mutations must not roll current metadata backward.\n    if (isObjectShallowSuperset(valuesField, streamedField)) {\n      enriches = true;\n      continue;\n    }\n    return false;\n  }\n  return enriches;\n}\n\nfunction isEmptyMeta(value: unknown): boolean {\n  if (value == null) return true;\n  if (typeof value === \"string\") return value.length === 0;\n  if (Array.isArray(value)) return value.length === 0;\n  if (typeof value === \"object\") {\n    return Object.keys(value as Record<string, unknown>).length === 0;\n  }\n  return false;\n}\n\n/**\n * True when `candidate` is a shallow object superset of `baseline`:\n * every baseline key is present with an equal value, and candidate has\n * at least one extra key.\n */\nfunction isObjectShallowSuperset(\n  candidate: unknown,\n  baseline: unknown\n): boolean {\n  if (\n    candidate == null ||\n    baseline == null ||\n    typeof candidate !== \"object\" ||\n    typeof baseline !== \"object\" ||\n    Array.isArray(candidate) ||\n    Array.isArray(baseline)\n  ) {\n    return false;\n  }\n  const candidateRecord = candidate as Record<string, unknown>;\n  const baselineRecord = baseline as Record<string, unknown>;\n  const baselineKeys = Object.keys(baselineRecord);\n  const candidateKeys = Object.keys(candidateRecord);\n  if (candidateKeys.length <= baselineKeys.length) return false;\n  for (const key of baselineKeys) {\n    if (!Object.prototype.hasOwnProperty.call(candidateRecord, key)) {\n      return false;\n    }\n    if (!jsonishEqual(candidateRecord[key], baselineRecord[key])) {\n      return false;\n    }\n  }\n  return true;\n}\n\n/**\n * True when `candidate` retains every nested key present on `baseline`.\n * Nested leaf values may differ (in-place mutations); missing keys mean\n * preferring candidate would erase richer current metadata.\n */\nfunction retainsAllNestedKeys(candidate: unknown, baseline: unknown): boolean {\n  if (baseline == null || typeof baseline !== \"object\") {\n    // Leaf baseline — candidate may replace the value in place.\n    return true;\n  }\n  if (\n    candidate == null ||\n    typeof candidate !== \"object\" ||\n    Array.isArray(baseline) !== Array.isArray(candidate)\n  ) {\n    return false;\n  }\n\n  if (Array.isArray(baseline)) {\n    const candidateArr = candidate as unknown[];\n    const baselineArr = baseline as unknown[];\n    if (candidateArr.length < baselineArr.length) return false;\n    for (let i = 0; i < baselineArr.length; i += 1) {\n      if (!retainsAllNestedKeys(candidateArr[i], baselineArr[i])) {\n        return false;\n      }\n    }\n    return true;\n  }\n\n  const candidateRecord = candidate as Record<string, unknown>;\n  const baselineRecord = baseline as Record<string, unknown>;\n  for (const key of Object.keys(baselineRecord)) {\n    if (!Object.prototype.hasOwnProperty.call(candidateRecord, key)) {\n      return false;\n    }\n    if (!retainsAllNestedKeys(candidateRecord[key], baselineRecord[key])) {\n      return false;\n    }\n  }\n  return true;\n}\n\n/**\n * Decide whether a values message carries tool-call data missing from the\n * streamed message.\n */\nexport function shouldPreferValuesMessageForToolCalls(\n  valuesMessage: BaseMessage,\n  streamedMessage: BaseMessage\n): boolean {\n  const valuesToolCalls = getMessageToolCalls(valuesMessage);\n  if (valuesToolCalls.length === 0) return false;\n\n  const streamedToolCalls = getMessageToolCalls(streamedMessage);\n  if (streamedToolCalls.length < valuesToolCalls.length) return true;\n\n  const streamedIds = new Set(\n    streamedToolCalls\n      .map((toolCall) => toolCall.id)\n      .filter((id): id is string => typeof id === \"string\" && id.length > 0)\n  );\n  if (\n    valuesToolCalls.some((toolCall) => {\n      return typeof toolCall.id === \"string\" && !streamedIds.has(toolCall.id);\n    })\n  ) {\n    return true;\n  }\n\n  // Values snapshots carry the finalized tool-call args. Prefer them only when\n  // they add meaningful data, so empty placeholder args do not replace an\n  // otherwise useful streamed message.\n  return valuesToolCalls.some((valuesToolCall) => {\n    const streamedToolCall = streamedToolCalls.find(\n      (candidate) =>\n        typeof valuesToolCall.id === \"string\" &&\n        candidate.id === valuesToolCall.id\n    );\n    return (\n      streamedToolCall != null &&\n      hasMeaningfulArgs(valuesToolCall.args) &&\n      !jsonishEqual(valuesToolCall.args, streamedToolCall.args)\n    );\n  });\n}\n\nfunction hasMeaningfulArgs(args: unknown): boolean {\n  if (args == null) return false;\n  if (typeof args === \"string\") return args.length > 0;\n  if (typeof args === \"object\") return Object.keys(args).length > 0;\n  return true;\n}\n\nexport function messagesEqualList(\n  previous: readonly BaseMessage[],\n  next: readonly BaseMessage[]\n): boolean {\n  if (previous === next) return true;\n  if (previous.length !== next.length) return false;\n  for (let i = 0; i < previous.length; i += 1) {\n    if (!messagesEqual(previous[i], next[i])) return false;\n  }\n  return true;\n}\n\nexport function messagesEqual(\n  previous: BaseMessage | undefined,\n  next: BaseMessage | undefined\n): boolean {\n  if (previous === next) return true;\n  if (previous == null || next == null) return false;\n  const previousRecord = previous as unknown as Record<string, unknown>;\n  const nextRecord = next as unknown as Record<string, unknown>;\n  const previousType =\n    typeof previous.getType === \"function\"\n      ? previous.getType()\n      : previousRecord.type;\n  const nextType =\n    typeof next.getType === \"function\" ? next.getType() : nextRecord.type;\n\n  return (\n    previous.id === next.id &&\n    previousType === nextType &&\n    jsonishEqual(previous.content, next.content) &&\n    previousRecord.tool_call_id === nextRecord.tool_call_id &&\n    previousRecord.status === nextRecord.status &&\n    jsonishEqual(\n      previousRecord.additional_kwargs,\n      nextRecord.additional_kwargs\n    ) &&\n    jsonishEqual(\n      previousRecord.response_metadata,\n      nextRecord.response_metadata\n    ) &&\n    jsonishEqual(previousRecord.tool_calls, nextRecord.tool_calls) &&\n    jsonishEqual(\n      previousRecord.tool_call_chunks,\n      nextRecord.tool_call_chunks\n    ) &&\n    jsonishEqual(previousRecord.usage_metadata, nextRecord.usage_metadata)\n  );\n}\n\nfunction normalizedMessageId(message: BaseMessage): string | undefined {\n  return typeof message.id === \"string\" && message.id.length > 0\n    ? message.id\n    : undefined;\n}\n\nfunction getMessageToolCalls(\n  message: BaseMessage\n): Array<{ id?: string; name?: string; args?: unknown }> {\n  const raw = (message as unknown as { tool_calls?: unknown }).tool_calls;\n  if (!Array.isArray(raw)) return [];\n  return raw.filter(\n    (toolCall): toolCall is { id?: string; name?: string; args?: unknown } =>\n      toolCall != null && typeof toolCall === \"object\"\n  );\n}\n\nfunction jsonishEqual(previous: unknown, next: unknown): boolean {\n  return jsonishEqualAtDepth(previous, next, 0);\n}\n\nfunction jsonishEqualAtDepth(\n  previous: unknown,\n  next: unknown,\n  depth: number\n): boolean {\n  if (Object.is(previous, next)) return true;\n  if (previous == null || next == null) return false;\n  if (typeof previous !== \"object\" || typeof next !== \"object\") return false;\n  if (depth >= 4) return false;\n\n  if (Array.isArray(previous) || Array.isArray(next)) {\n    if (!Array.isArray(previous) || !Array.isArray(next)) return false;\n    if (previous.length !== next.length) return false;\n    for (let i = 0; i < previous.length; i += 1) {\n      if (!jsonishEqualAtDepth(previous[i], next[i], depth + 1)) return false;\n    }\n    return true;\n  }\n\n  const previousRecord = previous as Record<string, unknown>;\n  const nextRecord = next as Record<string, unknown>;\n  const previousKeys = Object.keys(previousRecord).filter(\n    (key) => typeof previousRecord[key] !== \"function\"\n  );\n  const nextKeys = Object.keys(nextRecord).filter(\n    (key) => typeof nextRecord[key] !== \"function\"\n  );\n  if (previousKeys.length !== nextKeys.length) return false;\n\n  for (const key of previousKeys) {\n    if (!Object.prototype.hasOwnProperty.call(nextRecord, key)) return false;\n    if (!jsonishEqualAtDepth(previousRecord[key], nextRecord[key], depth + 1)) {\n      return false;\n    }\n  }\n  return true;\n}\n"],"mappings":";;;;;;;;;;;;AAgEA,SAAgB,4BAA4B,EAC1C,eACA,iBACA,kBACA,yBACA,oBACA,qBACA,WACyD;CACzD,MAAM,kCAAkB,IAAI,KAAa;CACzC,MAAM,SAAwB,EAAE;AAEhC,MAAK,MAAM,iBAAiB,eAAe;EACzC,MAAM,KAAK,oBAAoB,cAAc;AAC7C,MAAI,MAAM,MAAM;AACd,UAAO,KAAK,cAAc;AAC1B;;AAGF,kBAAgB,IAAI,GAAG;EACvB,MAAM,YAAY,iBAAiB,IAAI,GAAG;EAI1C,MAAM,kBAFJ,aAAa,SACZ,sBAAsB,QAAQ,mBAAmB,IAAI,GAAG,IAEvD,gBAAgB,aAChB,KAAA;AAEJ,MACE,mBAAmB,QACnB,sBAAsB,eAAe,gBAAgB,KAAK,KAE1D,QAAO,KAAK,gBAAgB;MAE5B,QAAO,KAAK,cAAc;;AAI9B,MAAK,MAAM,YAAY,iBAAiB;EACtC,MAAM,KAAK,oBAAoB,SAAS;AACxC,MAAI,MAAM,KAAM;AAChB,MAAI,gBAAgB,IAAI,GAAG,CAAE;AAK7B,MAAI,CAAC,WAAW,wBAAwB,IAAI,GAAG,CAAE;AACjD,MAAI,sBAAsB,QAAQ,CAAC,mBAAmB,IAAI,GAAG,CAAE;AAC/D,SAAO,KAAK,SAAS;;AAGvB,QAAO;EACL,UAAU,kBAAkB,iBAAiB,OAAO,GAChD,kBACA;EACJ;EACD;;;;;AAMH,SAAgB,kBACd,UACqB;CACrB,MAAM,wBAAQ,IAAI,KAAqB;AACvC,UAAS,SAAS,SAAS,QAAQ;EACjC,MAAM,KAAK,oBAAoB,QAAQ;AACvC,MAAI,MAAM,KAAM,OAAM,IAAI,IAAI,IAAI;GAClC;AACF,QAAO;;AAsCT,SAAgB,0BACd,eACA,iBACA,SACS;AACT,KAAI,sCAAsC,eAAe,gBAAgB,CACvE,QAAO;AAET,KAAI,CAAC,aAAa,cAAc,SAAS,gBAAgB,QAAQ,CAC/D,QAAO;AAET,QAAO,6BAA6B,eAAe,iBAAiB,QAAQ;;;AAI9E,MAAM,2BAA2B;CAC/B;CACA;CACA;CACD;;;;;;;;;;;AAYD,SAAS,6BACP,eACA,iBACA,SACS;CACT,MAAM,wBAAwB,SAAS,0BAA0B;CACjE,MAAM,eAAe;CACrB,MAAM,iBAAiB;CAEvB,IAAI,WAAW;AACf,MAAK,MAAM,OAAO,0BAA0B;EAC1C,MAAM,cAAc,aAAa;EACjC,MAAM,gBAAgB,eAAe;AACrC,MAAI,aAAa,aAAa,cAAc,CAAE;EAE9C,MAAM,cAAc,YAAY,YAAY;EAC5C,MAAM,gBAAgB,YAAY,cAAc;AAEhD,MAAI,eAAe,CAAC,cAElB,QAAO;AAET,MAAI,CAAC,eAAe,eAAe;AACjC,cAAW;AACX;;AAGF,MAAI,uBAAuB;AAIzB,OAAI,qBAAqB,aAAa,cAAc,EAAE;AACpD,eAAW;AACX;;AAEF,UAAO;;AAKT,MAAI,wBAAwB,aAAa,cAAc,EAAE;AACvD,cAAW;AACX;;AAEF,SAAO;;AAET,QAAO;;AAGT,SAAS,YAAY,OAAyB;AAC5C,KAAI,SAAS,KAAM,QAAO;AAC1B,KAAI,OAAO,UAAU,SAAU,QAAO,MAAM,WAAW;AACvD,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,WAAW;AAClD,KAAI,OAAO,UAAU,SACnB,QAAO,OAAO,KAAK,MAAiC,CAAC,WAAW;AAElE,QAAO;;;;;;;AAQT,SAAS,wBACP,WACA,UACS;AACT,KACE,aAAa,QACb,YAAY,QACZ,OAAO,cAAc,YACrB,OAAO,aAAa,YACpB,MAAM,QAAQ,UAAU,IACxB,MAAM,QAAQ,SAAS,CAEvB,QAAO;CAET,MAAM,kBAAkB;CACxB,MAAM,iBAAiB;CACvB,MAAM,eAAe,OAAO,KAAK,eAAe;AAEhD,KADsB,OAAO,KAAK,gBAAgB,CAChC,UAAU,aAAa,OAAQ,QAAO;AACxD,MAAK,MAAM,OAAO,cAAc;AAC9B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,iBAAiB,IAAI,CAC7D,QAAO;AAET,MAAI,CAAC,aAAa,gBAAgB,MAAM,eAAe,KAAK,CAC1D,QAAO;;AAGX,QAAO;;;;;;;AAQT,SAAS,qBAAqB,WAAoB,UAA4B;AAC5E,KAAI,YAAY,QAAQ,OAAO,aAAa,SAE1C,QAAO;AAET,KACE,aAAa,QACb,OAAO,cAAc,YACrB,MAAM,QAAQ,SAAS,KAAK,MAAM,QAAQ,UAAU,CAEpD,QAAO;AAGT,KAAI,MAAM,QAAQ,SAAS,EAAE;EAC3B,MAAM,eAAe;EACrB,MAAM,cAAc;AACpB,MAAI,aAAa,SAAS,YAAY,OAAQ,QAAO;AACrD,OAAK,IAAI,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK,EAC3C,KAAI,CAAC,qBAAqB,aAAa,IAAI,YAAY,GAAG,CACxD,QAAO;AAGX,SAAO;;CAGT,MAAM,kBAAkB;CACxB,MAAM,iBAAiB;AACvB,MAAK,MAAM,OAAO,OAAO,KAAK,eAAe,EAAE;AAC7C,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,iBAAiB,IAAI,CAC7D,QAAO;AAET,MAAI,CAAC,qBAAqB,gBAAgB,MAAM,eAAe,KAAK,CAClE,QAAO;;AAGX,QAAO;;;;;;AAOT,SAAgB,sCACd,eACA,iBACS;CACT,MAAM,kBAAkB,oBAAoB,cAAc;AAC1D,KAAI,gBAAgB,WAAW,EAAG,QAAO;CAEzC,MAAM,oBAAoB,oBAAoB,gBAAgB;AAC9D,KAAI,kBAAkB,SAAS,gBAAgB,OAAQ,QAAO;CAE9D,MAAM,cAAc,IAAI,IACtB,kBACG,KAAK,aAAa,SAAS,GAAG,CAC9B,QAAQ,OAAqB,OAAO,OAAO,YAAY,GAAG,SAAS,EAAE,CACzE;AACD,KACE,gBAAgB,MAAM,aAAa;AACjC,SAAO,OAAO,SAAS,OAAO,YAAY,CAAC,YAAY,IAAI,SAAS,GAAG;GACvE,CAEF,QAAO;AAMT,QAAO,gBAAgB,MAAM,mBAAmB;EAC9C,MAAM,mBAAmB,kBAAkB,MACxC,cACC,OAAO,eAAe,OAAO,YAC7B,UAAU,OAAO,eAAe,GACnC;AACD,SACE,oBAAoB,QACpB,kBAAkB,eAAe,KAAK,IACtC,CAAC,aAAa,eAAe,MAAM,iBAAiB,KAAK;GAE3D;;AAGJ,SAAS,kBAAkB,MAAwB;AACjD,KAAI,QAAQ,KAAM,QAAO;AACzB,KAAI,OAAO,SAAS,SAAU,QAAO,KAAK,SAAS;AACnD,KAAI,OAAO,SAAS,SAAU,QAAO,OAAO,KAAK,KAAK,CAAC,SAAS;AAChE,QAAO;;AAGT,SAAgB,kBACd,UACA,MACS;AACT,KAAI,aAAa,KAAM,QAAO;AAC9B,KAAI,SAAS,WAAW,KAAK,OAAQ,QAAO;AAC5C,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,EACxC,KAAI,CAAC,cAAc,SAAS,IAAI,KAAK,GAAG,CAAE,QAAO;AAEnD,QAAO;;AAGT,SAAgB,cACd,UACA,MACS;AACT,KAAI,aAAa,KAAM,QAAO;AAC9B,KAAI,YAAY,QAAQ,QAAQ,KAAM,QAAO;CAC7C,MAAM,iBAAiB;CACvB,MAAM,aAAa;CACnB,MAAM,eACJ,OAAO,SAAS,YAAY,aACxB,SAAS,SAAS,GAClB,eAAe;CACrB,MAAM,WACJ,OAAO,KAAK,YAAY,aAAa,KAAK,SAAS,GAAG,WAAW;AAEnE,QACE,SAAS,OAAO,KAAK,MACrB,iBAAiB,YACjB,aAAa,SAAS,SAAS,KAAK,QAAQ,IAC5C,eAAe,iBAAiB,WAAW,gBAC3C,eAAe,WAAW,WAAW,UACrC,aACE,eAAe,mBACf,WAAW,kBACZ,IACD,aACE,eAAe,mBACf,WAAW,kBACZ,IACD,aAAa,eAAe,YAAY,WAAW,WAAW,IAC9D,aACE,eAAe,kBACf,WAAW,iBACZ,IACD,aAAa,eAAe,gBAAgB,WAAW,eAAe;;AAI1E,SAAS,oBAAoB,SAA0C;AACrE,QAAO,OAAO,QAAQ,OAAO,YAAY,QAAQ,GAAG,SAAS,IACzD,QAAQ,KACR,KAAA;;AAGN,SAAS,oBACP,SACuD;CACvD,MAAM,MAAO,QAAgD;AAC7D,KAAI,CAAC,MAAM,QAAQ,IAAI,CAAE,QAAO,EAAE;AAClC,QAAO,IAAI,QACR,aACC,YAAY,QAAQ,OAAO,aAAa,SAC3C;;AAGH,SAAS,aAAa,UAAmB,MAAwB;AAC/D,QAAO,oBAAoB,UAAU,MAAM,EAAE;;AAG/C,SAAS,oBACP,UACA,MACA,OACS;AACT,KAAI,OAAO,GAAG,UAAU,KAAK,CAAE,QAAO;AACtC,KAAI,YAAY,QAAQ,QAAQ,KAAM,QAAO;AAC7C,KAAI,OAAO,aAAa,YAAY,OAAO,SAAS,SAAU,QAAO;AACrE,KAAI,SAAS,EAAG,QAAO;AAEvB,KAAI,MAAM,QAAQ,SAAS,IAAI,MAAM,QAAQ,KAAK,EAAE;AAClD,MAAI,CAAC,MAAM,QAAQ,SAAS,IAAI,CAAC,MAAM,QAAQ,KAAK,CAAE,QAAO;AAC7D,MAAI,SAAS,WAAW,KAAK,OAAQ,QAAO;AAC5C,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,EACxC,KAAI,CAAC,oBAAoB,SAAS,IAAI,KAAK,IAAI,QAAQ,EAAE,CAAE,QAAO;AAEpE,SAAO;;CAGT,MAAM,iBAAiB;CACvB,MAAM,aAAa;CACnB,MAAM,eAAe,OAAO,KAAK,eAAe,CAAC,QAC9C,QAAQ,OAAO,eAAe,SAAS,WACzC;CACD,MAAM,WAAW,OAAO,KAAK,WAAW,CAAC,QACtC,QAAQ,OAAO,WAAW,SAAS,WACrC;AACD,KAAI,aAAa,WAAW,SAAS,OAAQ,QAAO;AAEpD,MAAK,MAAM,OAAO,cAAc;AAC9B,MAAI,CAAC,OAAO,UAAU,eAAe,KAAK,YAAY,IAAI,CAAE,QAAO;AACnE,MAAI,CAAC,oBAAoB,eAAe,MAAM,WAAW,MAAM,QAAQ,EAAE,CACvE,QAAO;;AAGX,QAAO"}