{"version":3,"file":"protocol.cjs","names":["Type","Errors","Check"],"sources":["../../src/schemas/protocol.ts"],"sourcesContent":["import { type Static, type TSchema, Type } from 'typebox';\nimport { Check, Errors } from 'typebox/value';\n\nexport const DOOM_PROTOCOL_ERROR_CODE = {\n  aborted: 'ABORTED',\n  invalidMessage: 'INVALID_MESSAGE',\n  providerError: 'PROVIDER_ERROR',\n  timeout: 'TIMEOUT',\n} as const;\n\nconst DEFAULT_PROTOCOL_TIMEOUT_MS = 5_000;\nconst DEFAULT_DUPLICATE_WINDOW = 256;\n\nexport interface EventBusLike {\n  emit(event: string, data: unknown): void;\n  on(event: string, handler: (data: unknown) => void): () => void;\n}\n\nexport const ProtocolErrorSchema = Type.Object(\n  {\n    code: Type.String({ minLength: 1 }),\n    message: Type.String({ minLength: 1 }),\n    retryable: Type.Optional(Type.Boolean()),\n  },\n  { additionalProperties: false },\n);\n\nexport type ProtocolErrorPayload = Static<typeof ProtocolErrorSchema>;\n\nexport class DoomProtocolError extends Error {\n  readonly code: string;\n  readonly retryable: boolean;\n\n  constructor(payload: ProtocolErrorPayload) {\n    super(payload.message);\n    this.name = 'DoomProtocolError';\n    this.code = payload.code;\n    this.retryable = payload.retryable ?? false;\n  }\n}\n\nexport class DoomProtocolValidationError extends DoomProtocolError {\n  constructor(channel: string, details: string) {\n    super({ code: DOOM_PROTOCOL_ERROR_CODE.invalidMessage, message: `Invalid message on ${channel}: ${details}` });\n    this.name = 'DoomProtocolValidationError';\n  }\n}\n\nexport interface ProtocolIdentity {\n  source: string;\n  sessionId: string;\n}\n\ninterface ProtocolEnvelope<TPayload> extends ProtocolIdentity {\n  protocol: string;\n  version: 1;\n  kind: string;\n  messageId: string;\n  correlationId?: string;\n  payload: TPayload;\n}\n\nexport interface NotificationDefinition<TPayload extends TSchema> {\n  channel: string;\n  kind: string;\n  payload: TPayload;\n}\n\nexport interface RequestReplyDefinition<TRequest extends TSchema, TResponse extends TSchema> {\n  requestChannel: string;\n  responseChannel: string;\n  errorChannel: string;\n  requestKind: string;\n  responseKind: string;\n  request: TRequest;\n  response: TResponse;\n}\n\nexport interface RequestOptions {\n  signal?: AbortSignal;\n  timeoutMs?: number;\n  /** Ignore correlated replies from any source except this exact provider. */\n  expectedSource?: string;\n}\n\nexport interface ProtocolRuntimeOptions extends ProtocolIdentity {\n  bus: EventBusLike;\n  defaultTimeoutMs?: number;\n  createMessageId?: () => string;\n  duplicateWindow?: number;\n}\n\nexport interface ProtocolRuntime {\n  notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>): void;\n  onNotification<TPayload extends TSchema>(\n    definition: NotificationDefinition<TPayload>,\n    handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>,\n  ): () => void;\n  request<TRequest extends TSchema, TResponse extends TSchema>(\n    definition: RequestReplyDefinition<TRequest, TResponse>,\n    payload: Static<TRequest>,\n    options?: RequestOptions,\n  ): Promise<Static<TResponse>>;\n  provide<TRequest extends TSchema, TResponse extends TSchema>(\n    definition: RequestReplyDefinition<TRequest, TResponse>,\n    handler: (payload: Static<TRequest>, identity: ProtocolIdentity) => Static<TResponse> | Promise<Static<TResponse>>,\n  ): () => void;\n}\n\nconst EnvelopeBaseSchema = Type.Object(\n  {\n    protocol: Type.String({ minLength: 1 }),\n    version: Type.Literal(1),\n    kind: Type.String({ minLength: 1 }),\n    messageId: Type.String({ minLength: 1 }),\n    correlationId: Type.Optional(Type.String({ minLength: 1 })),\n    source: Type.String({ minLength: 1 }),\n    sessionId: Type.String({ minLength: 1 }),\n  },\n  { additionalProperties: false },\n);\n\nfunction envelopeSchema<TPayload extends TSchema>(payload: TPayload) {\n  return Type.Object({ ...EnvelopeBaseSchema.properties, payload }, { additionalProperties: false });\n}\n\nfunction protocolName(channel: string): string {\n  const match = /^(doom:[^:]+(?::[^:]+)*):v\\d+:/.exec(channel);\n  if (!match) throw new Error(`Invalid Doom protocol channel: ${channel}`);\n  return match[1];\n}\n\nfunction validationDetails(schema: TSchema, value: unknown): string {\n  return Errors(schema, value)\n    .slice(0, 3)\n    .map((error) => `${error.instancePath || '/'} ${error.message}`)\n    .join('; ');\n}\n\nfunction assertValid<TSchemaValue extends TSchema>(\n  channel: string,\n  schema: TSchemaValue,\n  value: unknown,\n): asserts value is Static<TSchemaValue> {\n  if (!Check(schema, value)) throw new DoomProtocolValidationError(channel, validationDetails(schema, value));\n}\n\nfunction asProtocolError(error: unknown): ProtocolErrorPayload {\n  if (error instanceof DoomProtocolError) {\n    return { code: error.code, message: error.message, retryable: error.retryable };\n  }\n  return {\n    code: DOOM_PROTOCOL_ERROR_CODE.providerError,\n    message: error instanceof Error ? error.message : String(error),\n  };\n}\n\nexport function defineNotification<TPayload extends TSchema>(definition: {\n  channel: `doom:${string}:${string}:v1:${string}`;\n  kind: string;\n  payload: TPayload;\n}): NotificationDefinition<TPayload> {\n  protocolName(definition.channel);\n  return definition;\n}\n\nexport function defineRequestReply<TRequest extends TSchema, TResponse extends TSchema>(definition: {\n  channels: {\n    request: `doom:${string}:${string}:v1:${string}`;\n    response: `doom:${string}:${string}:v1:${string}`;\n    error: `doom:${string}:${string}:v1:${string}`;\n  };\n  kinds: { request: string; response: string };\n  request: TRequest;\n  response: TResponse;\n}): RequestReplyDefinition<TRequest, TResponse> {\n  const protocol = protocolName(definition.channels.request);\n  for (const channel of [definition.channels.response, definition.channels.error]) {\n    if (protocolName(channel) !== protocol) throw new Error('Request/reply channels must share one protocol');\n  }\n  return {\n    requestChannel: definition.channels.request,\n    responseChannel: definition.channels.response,\n    errorChannel: definition.channels.error,\n    requestKind: definition.kinds.request,\n    responseKind: definition.kinds.response,\n    request: definition.request,\n    response: definition.response,\n  };\n}\n\nexport const defineJob = defineRequestReply;\n\nexport function createProtocolRuntime(options: ProtocolRuntimeOptions): ProtocolRuntime {\n  const timeoutDefault = options.defaultTimeoutMs ?? DEFAULT_PROTOCOL_TIMEOUT_MS;\n  const duplicateWindow = options.duplicateWindow ?? DEFAULT_DUPLICATE_WINDOW;\n  const createMessageId = options.createMessageId ?? (() => `${options.source}:${crypto.randomUUID()}`);\n\n  const rethrowAsync = (error: unknown): void => {\n    queueMicrotask(() => {\n      throw error instanceof Error ? error : new Error(String(error));\n    });\n  };\n\n  function duplicateGuard(): (messageId: string) => boolean {\n    const handled = new Set<string>();\n    return (messageId) => {\n      if (handled.has(messageId)) return false;\n      handled.add(messageId);\n      if (handled.size > duplicateWindow) handled.delete(handled.values().next().value as string);\n      return true;\n    };\n  }\n\n  function base(channel: string, kind: string, messageId = createMessageId(), correlationId?: string) {\n    return {\n      protocol: protocolName(channel),\n      version: 1 as const,\n      kind,\n      messageId,\n      ...(correlationId ? { correlationId } : {}),\n      source: options.source,\n      sessionId: options.sessionId,\n    };\n  }\n\n  return {\n    notify<TPayload extends TSchema>(definition: NotificationDefinition<TPayload>, payload: Static<TPayload>) {\n      assertValid(definition.channel, definition.payload, payload);\n      options.bus.emit(definition.channel, { ...base(definition.channel, definition.kind), payload });\n    },\n\n    onNotification<TPayload extends TSchema>(\n      definition: NotificationDefinition<TPayload>,\n      handler: (payload: Static<TPayload>, identity: ProtocolIdentity) => void | Promise<void>,\n    ) {\n      const schema = envelopeSchema(definition.payload);\n      const remember = duplicateGuard();\n      return options.bus.on(definition.channel, (message) => {\n        assertValid(definition.channel, schema, message);\n        const envelope = message as unknown as ProtocolEnvelope<Static<TPayload>>;\n        if (envelope.sessionId !== options.sessionId) return;\n        if (!remember(envelope.messageId)) return;\n        void Promise.resolve(handler(envelope.payload, envelope)).catch(rethrowAsync);\n      });\n    },\n\n    request<TRequest extends TSchema, TResponse extends TSchema>(\n      definition: RequestReplyDefinition<TRequest, TResponse>,\n      payload: Static<TRequest>,\n      requestOptions: RequestOptions = {},\n    ) {\n      assertValid(definition.requestChannel, definition.request, payload);\n      const messageId = createMessageId();\n      const responseSchema = envelopeSchema(definition.response);\n      const errorSchema = envelopeSchema(ProtocolErrorSchema);\n      return new Promise<Static<typeof definition.response>>((resolve, reject) => {\n        let settled = false;\n        const cleanups: Array<() => void> = [];\n        const finish = (action: () => void) => {\n          if (settled) return;\n          settled = true;\n          for (const cleanup of cleanups.splice(0)) cleanup();\n          action();\n        };\n        cleanups.push(\n          options.bus.on(definition.responseChannel, (message) => {\n            assertValid(definition.responseChannel, responseSchema, message);\n            const envelope = message as unknown as ProtocolEnvelope<Static<TResponse>>;\n            if (envelope.sessionId !== options.sessionId) return;\n            if (envelope.correlationId !== messageId) return;\n            if (requestOptions.expectedSource && envelope.source !== requestOptions.expectedSource) return;\n            finish(() => resolve(envelope.payload));\n          }),\n          options.bus.on(definition.errorChannel, (message) => {\n            assertValid(definition.errorChannel, errorSchema, message);\n            const envelope = message as unknown as ProtocolEnvelope<ProtocolErrorPayload>;\n            if (envelope.sessionId !== options.sessionId) return;\n            if (envelope.correlationId !== messageId) return;\n            if (requestOptions.expectedSource && envelope.source !== requestOptions.expectedSource) return;\n            finish(() => reject(new DoomProtocolError(envelope.payload)));\n          }),\n        );\n        const timer = setTimeout(\n          () =>\n            finish(() =>\n              reject(\n                new DoomProtocolError({\n                  code: DOOM_PROTOCOL_ERROR_CODE.timeout,\n                  message: `Timed out waiting for ${definition.responseKind}`,\n                }),\n              ),\n            ),\n          requestOptions.timeoutMs ?? timeoutDefault,\n        );\n        cleanups.push(() => clearTimeout(timer));\n        if (requestOptions.signal) {\n          const abort = () =>\n            finish(() =>\n              reject(new DoomProtocolError({ code: DOOM_PROTOCOL_ERROR_CODE.aborted, message: 'Request aborted' })),\n            );\n          requestOptions.signal.addEventListener('abort', abort, { once: true });\n          cleanups.push(() => requestOptions.signal?.removeEventListener('abort', abort));\n          if (requestOptions.signal.aborted) return abort();\n        }\n        options.bus.emit(definition.requestChannel, {\n          ...base(definition.requestChannel, definition.requestKind, messageId),\n          payload,\n        });\n      });\n    },\n\n    provide<TRequest extends TSchema, TResponse extends TSchema>(\n      definition: RequestReplyDefinition<TRequest, TResponse>,\n      handler: (\n        payload: Static<TRequest>,\n        identity: ProtocolIdentity,\n      ) => Static<TResponse> | Promise<Static<TResponse>>,\n    ) {\n      const requestSchema = envelopeSchema(definition.request);\n      const remember = duplicateGuard();\n      return options.bus.on(definition.requestChannel, (message) => {\n        assertValid(definition.requestChannel, requestSchema, message);\n        const envelope = message as unknown as ProtocolEnvelope<Static<TRequest>>;\n        if (envelope.sessionId !== options.sessionId) return;\n        if (!remember(envelope.messageId)) return;\n        void Promise.resolve()\n          .then(() => handler(envelope.payload, envelope))\n          .then(\n            (payload) => {\n              assertValid(definition.responseChannel, definition.response, payload);\n              options.bus.emit(definition.responseChannel, {\n                ...base(definition.responseChannel, definition.responseKind, createMessageId(), envelope.messageId),\n                payload,\n              });\n            },\n            (error) => {\n              options.bus.emit(definition.errorChannel, {\n                ...base(definition.errorChannel, 'error', createMessageId(), envelope.messageId),\n                payload: asProtocolError(error),\n              });\n            },\n          );\n      });\n    },\n  };\n}\n"],"mappings":"oDAGA,MAAa,EAA2B,CACtC,QAAS,UACT,eAAgB,kBAChB,cAAe,iBACf,QAAS,SACX,EAUa,EAAsBA,EAAAA,KAAK,OACtC,CACE,KAAMA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EAClC,QAASA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACrC,UAAWA,EAAAA,KAAK,SAASA,EAAAA,KAAK,QAAQ,CAAC,CACzC,EACA,CAAE,qBAAsB,EAAM,CAChC,EAIA,IAAa,EAAb,cAAuC,KAAM,CAC3C,KACA,UAEA,YAAY,EAA+B,CACzC,MAAM,EAAQ,OAAO,EACrB,KAAK,KAAO,oBACZ,KAAK,KAAO,EAAQ,KACpB,KAAK,UAAY,EAAQ,WAAa,EACxC,CACF,EAEa,EAAb,cAAiD,CAAkB,CACjE,YAAY,EAAiB,EAAiB,CAC5C,MAAM,CAAE,KAAM,EAAyB,eAAgB,QAAS,sBAAsB,EAAQ,IAAI,GAAU,CAAC,EAC7G,KAAK,KAAO,6BACd,CACF,EA+DA,MAAM,EAAqBA,EAAAA,KAAK,OAC9B,CACE,SAAUA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACtC,QAASA,EAAAA,KAAK,QAAQ,CAAC,EACvB,KAAMA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EAClC,UAAWA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACvC,cAAeA,EAAAA,KAAK,SAASA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,CAAC,EAC1D,OAAQA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,EACpC,UAAWA,EAAAA,KAAK,OAAO,CAAE,UAAW,CAAE,CAAC,CACzC,EACA,CAAE,qBAAsB,EAAM,CAChC,EAEA,SAAS,EAAyC,EAAmB,CACnE,OAAOA,EAAAA,KAAK,OAAO,CAAE,GAAG,EAAmB,WAAY,SAAQ,EAAG,CAAE,qBAAsB,EAAM,CAAC,CACnG,CAEA,SAAS,EAAa,EAAyB,CAC7C,IAAM,EAAQ,iCAAiC,KAAK,CAAO,EAC3D,GAAI,CAAC,EAAO,MAAU,MAAM,kCAAkC,GAAS,EACvE,OAAO,EAAM,EACf,CAEA,SAAS,EAAkB,EAAiB,EAAwB,CAClE,OAAA,EAAOC,EAAAA,OAAAA,CAAO,EAAQ,CAAK,CAAC,CACzB,MAAM,EAAG,CAAC,CAAC,CACX,IAAK,GAAU,GAAG,EAAM,cAAgB,IAAI,GAAG,EAAM,SAAS,CAAC,CAC/D,KAAK,IAAI,CACd,CAEA,SAAS,EACP,EACA,EACA,EACuC,CACvC,GAAI,EAAA,EAACC,EAAAA,MAAAA,CAAM,EAAQ,CAAK,EAAG,MAAM,IAAI,EAA4B,EAAS,EAAkB,EAAQ,CAAK,CAAC,CAC5G,CAEA,SAAS,EAAgB,EAAsC,CAI7D,OAHI,aAAiB,EACZ,CAAE,KAAM,EAAM,KAAM,QAAS,EAAM,QAAS,UAAW,EAAM,SAAU,EAEzE,CACL,KAAM,EAAyB,cAC/B,QAAS,aAAiB,MAAQ,EAAM,QAAU,OAAO,CAAK,CAChE,CACF,CAEA,SAAgB,EAA6C,EAIxB,CAEnC,OADA,EAAa,EAAW,OAAO,EACxB,CACT,CAEA,SAAgB,EAAwE,EASxC,CAC9C,IAAM,EAAW,EAAa,EAAW,SAAS,OAAO,EACzD,IAAK,IAAM,IAAW,CAAC,EAAW,SAAS,SAAU,EAAW,SAAS,KAAK,EAC5E,GAAI,EAAa,CAAO,IAAM,EAAU,MAAU,MAAM,gDAAgD,EAE1G,MAAO,CACL,eAAgB,EAAW,SAAS,QACpC,gBAAiB,EAAW,SAAS,SACrC,aAAc,EAAW,SAAS,MAClC,YAAa,EAAW,MAAM,QAC9B,aAAc,EAAW,MAAM,SAC/B,QAAS,EAAW,QACpB,SAAU,EAAW,QACvB,CACF,CAEA,MAAa,EAAY,EAEzB,SAAgB,EAAsB,EAAkD,CACtF,IAAM,EAAiB,EAAQ,kBAAoB,IAC7C,EAAkB,EAAQ,iBAAmB,IAC7C,EAAkB,EAAQ,sBAA0B,GAAG,EAAQ,OAAO,GAAG,OAAO,WAAW,KAE3F,EAAgB,GAAyB,CAC7C,mBAAqB,CACnB,MAAM,aAAiB,MAAQ,EAAY,MAAM,OAAO,CAAK,CAAC,CAChE,CAAC,CACH,EAEA,SAAS,GAAiD,CACxD,IAAM,EAAU,IAAI,IACpB,MAAQ,IACN,CAAI,EAAQ,IAAI,CAAS,IACzB,EAAQ,IAAI,CAAS,EACjB,EAAQ,KAAO,GAAiB,EAAQ,OAAO,EAAQ,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,KAAe,EACnF,GAEX,CAEA,SAAS,EAAK,EAAiB,EAAc,EAAY,EAAgB,EAAG,EAAwB,CAClG,MAAO,CACL,SAAU,EAAa,CAAO,EAC9B,QAAS,EACT,OACA,YACA,GAAI,EAAgB,CAAE,eAAc,EAAI,CAAC,EACzC,OAAQ,EAAQ,OAChB,UAAW,EAAQ,SACrB,CACF,CAEA,MAAO,CACL,OAAiC,EAA8C,EAA2B,CACxG,EAAY,EAAW,QAAS,EAAW,QAAS,CAAO,EAC3D,EAAQ,IAAI,KAAK,EAAW,QAAS,CAAE,GAAG,EAAK,EAAW,QAAS,EAAW,IAAI,EAAG,SAAQ,CAAC,CAChG,EAEA,eACE,EACA,EACA,CACA,IAAM,EAAS,EAAe,EAAW,OAAO,EAC1C,EAAW,EAAe,EAChC,OAAO,EAAQ,IAAI,GAAG,EAAW,QAAU,GAAY,CACrD,EAAY,EAAW,QAAS,EAAQ,CAAO,EAC/C,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC9B,EAAS,EAAS,SAAS,GAChC,QAAa,QAAQ,EAAQ,EAAS,QAAS,CAAQ,CAAC,CAAC,CAAC,MAAM,CAAY,CAC9E,CAAC,CACH,EAEA,QACE,EACA,EACA,EAAiC,CAAC,EAClC,CACA,EAAY,EAAW,eAAgB,EAAW,QAAS,CAAO,EAClE,IAAM,EAAY,EAAgB,EAC5B,EAAiB,EAAe,EAAW,QAAQ,EACnD,EAAc,EAAe,CAAmB,EACtD,OAAO,IAAI,SAA6C,EAAS,IAAW,CAC1E,IAAI,EAAU,GACR,EAA8B,CAAC,EAC/B,EAAU,GAAuB,CACjC,MACJ,GAAU,GACV,IAAK,IAAM,KAAW,EAAS,OAAO,CAAC,EAAG,EAAQ,EAClD,EAAO,CAFG,CAGZ,EACA,EAAS,KACP,EAAQ,IAAI,GAAG,EAAW,gBAAkB,GAAY,CACtD,EAAY,EAAW,gBAAiB,EAAgB,CAAO,EAC/D,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC/B,EAAS,gBAAkB,IAC3B,EAAe,gBAAkB,EAAS,SAAW,EAAe,gBACxE,MAAa,EAAQ,EAAS,OAAO,CAAC,EACxC,CAAC,EACD,EAAQ,IAAI,GAAG,EAAW,aAAe,GAAY,CACnD,EAAY,EAAW,aAAc,EAAa,CAAO,EACzD,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC/B,EAAS,gBAAkB,IAC3B,EAAe,gBAAkB,EAAS,SAAW,EAAe,gBACxE,MAAa,EAAO,IAAI,EAAkB,EAAS,OAAO,CAAC,CAAC,EAC9D,CAAC,CACH,EACA,IAAM,EAAQ,eAEV,MACE,EACE,IAAI,EAAkB,CACpB,KAAM,EAAyB,QAC/B,QAAS,yBAAyB,EAAW,cAC/C,CAAC,CACH,CACF,EACF,EAAe,WAAa,CAC9B,EAEA,GADA,EAAS,SAAW,aAAa,CAAK,CAAC,EACnC,EAAe,OAAQ,CACzB,IAAM,MACJ,MACE,EAAO,IAAI,EAAkB,CAAE,KAAM,EAAyB,QAAS,QAAS,iBAAkB,CAAC,CAAC,CACtG,EAGF,GAFA,EAAe,OAAO,iBAAiB,QAAS,EAAO,CAAE,KAAM,EAAK,CAAC,EACrE,EAAS,SAAW,EAAe,QAAQ,oBAAoB,QAAS,CAAK,CAAC,EAC1E,EAAe,OAAO,QAAS,OAAO,EAAM,CAClD,CACA,EAAQ,IAAI,KAAK,EAAW,eAAgB,CAC1C,GAAG,EAAK,EAAW,eAAgB,EAAW,YAAa,CAAS,EACpE,SACF,CAAC,CACH,CAAC,CACH,EAEA,QACE,EACA,EAIA,CACA,IAAM,EAAgB,EAAe,EAAW,OAAO,EACjD,EAAW,EAAe,EAChC,OAAO,EAAQ,IAAI,GAAG,EAAW,eAAiB,GAAY,CAC5D,EAAY,EAAW,eAAgB,EAAe,CAAO,EAC7D,IAAM,EAAW,EACb,EAAS,YAAc,EAAQ,WAC9B,EAAS,EAAS,SAAS,GAChC,QAAa,QAAQ,CAAC,CACnB,SAAW,EAAQ,EAAS,QAAS,CAAQ,CAAC,CAAC,CAC/C,KACE,GAAY,CACX,EAAY,EAAW,gBAAiB,EAAW,SAAU,CAAO,EACpE,EAAQ,IAAI,KAAK,EAAW,gBAAiB,CAC3C,GAAG,EAAK,EAAW,gBAAiB,EAAW,aAAc,EAAgB,EAAG,EAAS,SAAS,EAClG,SACF,CAAC,CACH,EACC,GAAU,CACT,EAAQ,IAAI,KAAK,EAAW,aAAc,CACxC,GAAG,EAAK,EAAW,aAAc,QAAS,EAAgB,EAAG,EAAS,SAAS,EAC/E,QAAS,EAAgB,CAAK,CAChC,CAAC,CACH,CACF,CACJ,CAAC,CACH,CACF,CACF"}