UNPKG

@copilotkit/a2ui-renderer

Version:

A2UI Renderer for CopilotKit - render A2UI surfaces in React applications

1 lines 18.5 kB
{"version":3,"file":"surface.cjs","names":["LitElement","basicCatalog","MessageProcessor","nothing"],"sources":["../../src/web-components/surface.ts"],"sourcesContent":["import { html, LitElement, nothing } from \"lit\";\nimport { MessageProcessor } from \"@a2ui/web_core/v0_9\";\nimport type { A2uiMessage, Catalog } from \"@a2ui/web_core/v0_9\";\nimport { basicCatalog } from \"./catalog/basic\";\nimport type { LitComponentImplementation, LitRenderable } from \"./types\";\n\nconst DEFAULT_SURFACE_ID = \"default\";\nconst BASIC_CATALOG_ID =\n \"https://a2ui.org/specification/v0_9/basic_catalog.json\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value && typeof value === \"object\" && !Array.isArray(value));\n}\n\nfunction getRecordProperty(\n record: Record<string, unknown>,\n key: string,\n): Record<string, unknown> | undefined {\n const value = record[key];\n return isRecord(value) ? value : undefined;\n}\n\nfunction getStringProperty(\n record: Record<string, unknown>,\n key: string,\n): string | undefined {\n const value = record[key];\n return typeof value === \"string\" && value.length > 0 ? value : undefined;\n}\n\nfunction getBooleanProperty(\n record: Record<string, unknown>,\n key: string,\n): boolean | undefined {\n const value = record[key];\n return typeof value === \"boolean\" ? value : undefined;\n}\n\nfunction getSurfaceId(payload: Record<string, unknown> | undefined): string {\n return payload\n ? (getStringProperty(payload, \"surfaceId\") ?? DEFAULT_SURFACE_ID)\n : DEFAULT_SURFACE_ID;\n}\n\nfunction getOperationSurfaceId(operation: A2uiMessage): string {\n if (\"createSurface\" in operation) return operation.createSurface.surfaceId;\n if (\"updateComponents\" in operation)\n return operation.updateComponents.surfaceId;\n if (\"updateDataModel\" in operation)\n return operation.updateDataModel.surfaceId;\n if (\"deleteSurface\" in operation) return operation.deleteSurface.surfaceId;\n return DEFAULT_SURFACE_ID;\n}\n\nfunction normalizeOperations(\n operations: unknown[],\n catalogId: string,\n): A2uiMessage[] {\n return operations.flatMap((operation): A2uiMessage[] => {\n if (!isRecord(operation)) return [];\n\n const createSurface = getRecordProperty(operation, \"createSurface\");\n if (createSurface) {\n const message = {\n version: \"v0.9\",\n createSurface: {\n surfaceId: getSurfaceId(createSurface),\n catalogId: getStringProperty(createSurface, \"catalogId\") ?? catalogId,\n theme: createSurface.theme ?? {},\n sendDataModel: getBooleanProperty(createSurface, \"sendDataModel\"),\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n const updateComponents = getRecordProperty(operation, \"updateComponents\");\n if (updateComponents) {\n const components = updateComponents.components;\n const message = {\n version: \"v0.9\",\n updateComponents: {\n surfaceId: getSurfaceId(updateComponents),\n components: Array.isArray(components)\n ? components.map(normalizeComponent)\n : [],\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n const updateDataModel = getRecordProperty(operation, \"updateDataModel\");\n if (updateDataModel) {\n const message = {\n version: \"v0.9\",\n updateDataModel: {\n surfaceId: getSurfaceId(updateDataModel),\n path: getStringProperty(updateDataModel, \"path\") ?? \"/\",\n value: updateDataModel.value,\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n const deleteSurface = getRecordProperty(operation, \"deleteSurface\");\n if (deleteSurface) {\n const message = {\n version: \"v0.9\",\n deleteSurface: {\n surfaceId: getSurfaceId(deleteSurface),\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n const beginRendering = getRecordProperty(operation, \"beginRendering\");\n if (beginRendering) {\n const message = {\n version: \"v0.9\",\n createSurface: {\n surfaceId: getSurfaceId(beginRendering),\n catalogId,\n theme: beginRendering.styles ?? {},\n sendDataModel: getBooleanProperty(beginRendering, \"sendDataModel\"),\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n const surfaceUpdate = getRecordProperty(operation, \"surfaceUpdate\");\n if (surfaceUpdate) {\n const components = surfaceUpdate.components;\n const message = {\n version: \"v0.9\",\n updateComponents: {\n surfaceId: getSurfaceId(surfaceUpdate),\n components: Array.isArray(components)\n ? components.map(normalizeComponent)\n : [],\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n const dataModelUpdate = getRecordProperty(operation, \"dataModelUpdate\");\n if (dataModelUpdate) {\n const message = {\n version: \"v0.9\",\n updateDataModel: {\n surfaceId: getSurfaceId(dataModelUpdate),\n path: getStringProperty(dataModelUpdate, \"path\") ?? \"/\",\n value: dataModelUpdate.value ?? dataModelUpdate.contents,\n },\n } satisfies A2uiMessage;\n return [message];\n }\n\n return [];\n });\n}\n\nfunction normalizeComponent(component: unknown): unknown {\n if (!component || typeof component !== \"object\") return component;\n const record = component as {\n id?: string;\n component?: string | Record<string, unknown>;\n [key: string]: unknown;\n };\n if (!record.component || typeof record.component === \"string\") return record;\n\n const entries = Object.entries(record.component);\n if (entries.length !== 1) return record;\n const [componentName, props] = entries[0]!;\n return {\n id: record.id,\n component: componentName,\n ...(props && typeof props === \"object\" ? props : {}),\n };\n}\n\nfunction toClientEventMessage(action: unknown): Record<string, unknown> {\n const record = isRecord(action) ? action : {};\n return {\n userAction: {\n name: getStringProperty(record, \"name\") ?? \"unknown\",\n surfaceId: getStringProperty(record, \"surfaceId\") ?? DEFAULT_SURFACE_ID,\n sourceComponentId: getStringProperty(record, \"sourceComponentId\"),\n context: isRecord(record.context) ? record.context : {},\n timestamp:\n getStringProperty(record, \"timestamp\") ?? new Date().toISOString(),\n dataContextPath: getStringProperty(record, \"dataContextPath\"),\n },\n };\n}\n\nfunction defaultLoading() {\n return html`\n <div\n class=\"cpk:flex cpk:flex-col cpk:gap-3 cpk:rounded-xl cpk:border cpk:border-gray-100 cpk:bg-gray-50/50 cpk:p-5\"\n style=\"min-height: 120px;\"\n data-testid=\"a2ui-loading\"\n >\n <div class=\"cpk:flex cpk:items-center cpk:gap-2\">\n <div\n class=\"cpk:h-3 cpk:w-3 cpk:rounded-full cpk:bg-gray-200\"\n style=\"animation: cpk-a2ui-pulse 1.5s ease-in-out infinite;\"\n data-testid=\"a2ui-loading-dot\"\n ></div>\n <span class=\"cpk:text-xs cpk:font-medium cpk:text-gray-400\">\n Generating UI...\n </span>\n </div>\n <div class=\"cpk:flex cpk:flex-col cpk:gap-2\">\n ${[0.8, 0.6, 0.4].map(\n (width, i) => html`\n <div\n class=\"cpk:h-3 cpk:rounded cpk:bg-gray-200/70\"\n style=${`width: ${width * 100}%; animation: cpk-a2ui-pulse 1.5s ease-in-out ${i * 0.15}s infinite;`}\n data-testid=\"a2ui-loading-bar\"\n ></div>\n `,\n )}\n </div>\n <style>\n @keyframes cpk-a2ui-pulse {\n 0%,\n 100% {\n opacity: 0.4;\n }\n 50% {\n opacity: 1;\n }\n }\n </style>\n </div>\n `;\n}\n\nexport class CpkA2uiSurface extends LitElement {\n static properties = {\n operations: { attribute: false },\n catalog: { attribute: false },\n theme: { attribute: false },\n surfaceId: { attribute: false },\n loadingComponent: { attribute: false },\n };\n\n operations: unknown[] = [];\n catalog?: Catalog<LitComponentImplementation>;\n theme?: Record<string, unknown>;\n surfaceId?: string;\n loadingComponent?: () => LitRenderable;\n\n private processor: MessageProcessor<LitComponentImplementation> | null = null;\n private processorCatalog?: Catalog<LitComponentImplementation>;\n private lastOpsHash = \"\";\n private renderedSurfaceIds: string[] = [];\n private error: string | null = null;\n\n protected createRenderRoot() {\n return this;\n }\n\n protected willUpdate(changed: Map<string, unknown>) {\n if (changed.has(\"catalog\")) {\n this.processor = null;\n this.processorCatalog = undefined;\n this.lastOpsHash = \"\";\n this.renderedSurfaceIds = [];\n }\n\n if (\n changed.has(\"operations\") ||\n changed.has(\"catalog\") ||\n changed.has(\"theme\") ||\n changed.has(\"surfaceId\")\n ) {\n this.processOperations();\n }\n }\n\n private getCatalog(): Catalog<LitComponentImplementation> {\n return this.catalog ?? basicCatalog;\n }\n\n private getProcessor(): MessageProcessor<LitComponentImplementation> {\n const catalog = this.getCatalog();\n if (!this.processor || this.processorCatalog !== catalog) {\n this.processorCatalog = catalog;\n this.processor = new MessageProcessor([catalog], (action) => {\n const message = toClientEventMessage(action);\n this.dispatchEvent(\n new CustomEvent(\"a2ui-action\", {\n detail: message,\n bubbles: true,\n composed: true,\n }),\n );\n });\n }\n return this.processor;\n }\n\n private processOperations(): void {\n if (!Array.isArray(this.operations) || this.operations.length === 0) {\n this.renderedSurfaceIds = [];\n this.error = null;\n return;\n }\n\n const catalogId = this.getCatalog().id || BASIC_CATALOG_ID;\n const normalized = normalizeOperations(this.operations, catalogId);\n const hash = JSON.stringify({\n operations: normalized,\n surfaceId: this.surfaceId,\n theme: this.theme,\n });\n if (hash === this.lastOpsHash) return;\n this.lastOpsHash = hash;\n\n const grouped = new Map<string, A2uiMessage[]>();\n for (const operation of normalized) {\n const surfaceId = this.surfaceId ?? getOperationSurfaceId(operation);\n if (!grouped.has(surfaceId)) grouped.set(surfaceId, []);\n grouped.get(surfaceId)!.push(operation);\n }\n\n const processor = this.getProcessor();\n try {\n for (const [surfaceId, ops] of grouped) {\n const existing = processor.model.getSurface(surfaceId);\n let filtered = existing\n ? ops.filter((op) => !(\"createSurface\" in op))\n : ops;\n\n if (!existing && !filtered.some((op) => \"createSurface\" in op)) {\n filtered = [\n {\n version: \"v0.9\",\n createSurface: {\n surfaceId,\n catalogId,\n theme: this.theme ?? {},\n },\n },\n ...filtered,\n ];\n }\n processor.processMessages(filtered);\n }\n this.renderedSurfaceIds = [...grouped.keys()];\n this.error = null;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n this.error = message;\n this.dispatchEvent(\n new CustomEvent(\"a2ui-error\", {\n detail: { error: err, message },\n bubbles: true,\n composed: true,\n }),\n );\n }\n }\n\n render() {\n if (this.error) {\n return html`\n <div\n class=\"cpk:rounded-lg cpk:border cpk:border-red-200 cpk:bg-red-50 cpk:p-3 cpk:text-sm cpk:text-red-700\"\n >\n A2UI render error: ${this.error}\n </div>\n `;\n }\n\n if (!this.renderedSurfaceIds.length) {\n return this.loadingComponent ? this.loadingComponent() : defaultLoading();\n }\n\n const processor = this.getProcessor();\n return html`\n <div\n class=\"cpk:flex cpk:min-h-0 cpk:flex-1 cpk:flex-col cpk:gap-6 cpk:overflow-auto cpk:py-6\"\n data-testid=\"a2ui-activity-renderer\"\n >\n ${this.renderedSurfaceIds.map((surfaceId) => {\n const surface = processor.model.getSurface(surfaceId);\n if (!surface) return nothing;\n return html`\n <div\n class=\"cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4\"\n data-surface-id=${surfaceId}\n >\n <div\n class=\"a2ui-surface cpk:flex cpk:flex-1\"\n data-surface-id=${surfaceId}\n >\n <cpk-a2ui-node\n .surface=${surface}\n .componentId=${\"root\"}\n .basePath=${\"/\"}\n ></cpk-a2ui-node>\n </div>\n </div>\n `;\n })}\n </div>\n `;\n }\n}\n"],"mappings":";;;;;AAMA,MAAM,qBAAqB;AAC3B,MAAM,mBACJ;AAEF,SAAS,SAAS,OAAkD;AAClE,QAAO,QAAQ,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,CAAC;;AAG7E,SAAS,kBACP,QACA,KACqC;CACrC,MAAM,QAAQ,OAAO;AACrB,QAAO,SAAS,MAAM,GAAG,QAAQ;;AAGnC,SAAS,kBACP,QACA,KACoB;CACpB,MAAM,QAAQ,OAAO;AACrB,QAAO,OAAO,UAAU,YAAY,MAAM,SAAS,IAAI,QAAQ;;AAGjE,SAAS,mBACP,QACA,KACqB;CACrB,MAAM,QAAQ,OAAO;AACrB,QAAO,OAAO,UAAU,YAAY,QAAQ;;AAG9C,SAAS,aAAa,SAAsD;AAC1E,QAAO,UACF,kBAAkB,SAAS,YAAY,IAAI,qBAC5C;;AAGN,SAAS,sBAAsB,WAAgC;AAC7D,KAAI,mBAAmB,UAAW,QAAO,UAAU,cAAc;AACjE,KAAI,sBAAsB,UACxB,QAAO,UAAU,iBAAiB;AACpC,KAAI,qBAAqB,UACvB,QAAO,UAAU,gBAAgB;AACnC,KAAI,mBAAmB,UAAW,QAAO,UAAU,cAAc;AACjE,QAAO;;AAGT,SAAS,oBACP,YACA,WACe;AACf,QAAO,WAAW,SAAS,cAA6B;AACtD,MAAI,CAAC,SAAS,UAAU,CAAE,QAAO,EAAE;EAEnC,MAAM,gBAAgB,kBAAkB,WAAW,gBAAgB;AACnE,MAAI,cAUF,QAAO,CATS;GACd,SAAS;GACT,eAAe;IACb,WAAW,aAAa,cAAc;IACtC,WAAW,kBAAkB,eAAe,YAAY,IAAI;IAC5D,OAAO,cAAc,SAAS,EAAE;IAChC,eAAe,mBAAmB,eAAe,gBAAgB;IAClE;GACF,CACe;EAGlB,MAAM,mBAAmB,kBAAkB,WAAW,mBAAmB;AACzE,MAAI,kBAAkB;GACpB,MAAM,aAAa,iBAAiB;AAUpC,UAAO,CATS;IACd,SAAS;IACT,kBAAkB;KAChB,WAAW,aAAa,iBAAiB;KACzC,YAAY,MAAM,QAAQ,WAAW,GACjC,WAAW,IAAI,mBAAmB,GAClC,EAAE;KACP;IACF,CACe;;EAGlB,MAAM,kBAAkB,kBAAkB,WAAW,kBAAkB;AACvE,MAAI,gBASF,QAAO,CARS;GACd,SAAS;GACT,iBAAiB;IACf,WAAW,aAAa,gBAAgB;IACxC,MAAM,kBAAkB,iBAAiB,OAAO,IAAI;IACpD,OAAO,gBAAgB;IACxB;GACF,CACe;EAGlB,MAAM,gBAAgB,kBAAkB,WAAW,gBAAgB;AACnE,MAAI,cAOF,QAAO,CANS;GACd,SAAS;GACT,eAAe,EACb,WAAW,aAAa,cAAc,EACvC;GACF,CACe;EAGlB,MAAM,iBAAiB,kBAAkB,WAAW,iBAAiB;AACrE,MAAI,eAUF,QAAO,CATS;GACd,SAAS;GACT,eAAe;IACb,WAAW,aAAa,eAAe;IACvC;IACA,OAAO,eAAe,UAAU,EAAE;IAClC,eAAe,mBAAmB,gBAAgB,gBAAgB;IACnE;GACF,CACe;EAGlB,MAAM,gBAAgB,kBAAkB,WAAW,gBAAgB;AACnE,MAAI,eAAe;GACjB,MAAM,aAAa,cAAc;AAUjC,UAAO,CATS;IACd,SAAS;IACT,kBAAkB;KAChB,WAAW,aAAa,cAAc;KACtC,YAAY,MAAM,QAAQ,WAAW,GACjC,WAAW,IAAI,mBAAmB,GAClC,EAAE;KACP;IACF,CACe;;EAGlB,MAAM,kBAAkB,kBAAkB,WAAW,kBAAkB;AACvE,MAAI,gBASF,QAAO,CARS;GACd,SAAS;GACT,iBAAiB;IACf,WAAW,aAAa,gBAAgB;IACxC,MAAM,kBAAkB,iBAAiB,OAAO,IAAI;IACpD,OAAO,gBAAgB,SAAS,gBAAgB;IACjD;GACF,CACe;AAGlB,SAAO,EAAE;GACT;;AAGJ,SAAS,mBAAmB,WAA6B;AACvD,KAAI,CAAC,aAAa,OAAO,cAAc,SAAU,QAAO;CACxD,MAAM,SAAS;AAKf,KAAI,CAAC,OAAO,aAAa,OAAO,OAAO,cAAc,SAAU,QAAO;CAEtE,MAAM,UAAU,OAAO,QAAQ,OAAO,UAAU;AAChD,KAAI,QAAQ,WAAW,EAAG,QAAO;CACjC,MAAM,CAAC,eAAe,SAAS,QAAQ;AACvC,QAAO;EACL,IAAI,OAAO;EACX,WAAW;EACX,GAAI,SAAS,OAAO,UAAU,WAAW,QAAQ,EAAE;EACpD;;AAGH,SAAS,qBAAqB,QAA0C;CACtE,MAAM,SAAS,SAAS,OAAO,GAAG,SAAS,EAAE;AAC7C,QAAO,EACL,YAAY;EACV,MAAM,kBAAkB,QAAQ,OAAO,IAAI;EAC3C,WAAW,kBAAkB,QAAQ,YAAY,IAAI;EACrD,mBAAmB,kBAAkB,QAAQ,oBAAoB;EACjE,SAAS,SAAS,OAAO,QAAQ,GAAG,OAAO,UAAU,EAAE;EACvD,WACE,kBAAkB,QAAQ,YAAY,qBAAI,IAAI,MAAM,EAAC,aAAa;EACpE,iBAAiB,kBAAkB,QAAQ,kBAAkB;EAC9D,EACF;;AAGH,SAAS,iBAAiB;AACxB,QAAO,QAAI;;;;;;;;;;;;;;;;;UAiBH;EAAC;EAAK;EAAK;EAAI,CAAC,KACf,OAAO,MAAM,QAAI;;;sBAGN,UAAU,QAAQ,IAAI,gDAAgD,IAAI,IAAK,aAAa;;;YAIzG,CAAC;;;;;;;;;;;;;;;;AAiBV,IAAa,iBAAb,cAAoCA,eAAW;;;oBASrB,EAAE;mBAM+C;qBAEnD;4BACiB,EAAE;eACV;;;oBAlBX;GAClB,YAAY,EAAE,WAAW,OAAO;GAChC,SAAS,EAAE,WAAW,OAAO;GAC7B,OAAO,EAAE,WAAW,OAAO;GAC3B,WAAW,EAAE,WAAW,OAAO;GAC/B,kBAAkB,EAAE,WAAW,OAAO;GACvC;;CAcD,AAAU,mBAAmB;AAC3B,SAAO;;CAGT,AAAU,WAAW,SAA+B;AAClD,MAAI,QAAQ,IAAI,UAAU,EAAE;AAC1B,QAAK,YAAY;AACjB,QAAK,mBAAmB;AACxB,QAAK,cAAc;AACnB,QAAK,qBAAqB,EAAE;;AAG9B,MACE,QAAQ,IAAI,aAAa,IACzB,QAAQ,IAAI,UAAU,IACtB,QAAQ,IAAI,QAAQ,IACpB,QAAQ,IAAI,YAAY,CAExB,MAAK,mBAAmB;;CAI5B,AAAQ,aAAkD;AACxD,SAAO,KAAK,WAAWC;;CAGzB,AAAQ,eAA6D;EACnE,MAAM,UAAU,KAAK,YAAY;AACjC,MAAI,CAAC,KAAK,aAAa,KAAK,qBAAqB,SAAS;AACxD,QAAK,mBAAmB;AACxB,QAAK,YAAY,IAAIC,qCAAiB,CAAC,QAAQ,GAAG,WAAW;IAC3D,MAAM,UAAU,qBAAqB,OAAO;AAC5C,SAAK,cACH,IAAI,YAAY,eAAe;KAC7B,QAAQ;KACR,SAAS;KACT,UAAU;KACX,CAAC,CACH;KACD;;AAEJ,SAAO,KAAK;;CAGd,AAAQ,oBAA0B;AAChC,MAAI,CAAC,MAAM,QAAQ,KAAK,WAAW,IAAI,KAAK,WAAW,WAAW,GAAG;AACnE,QAAK,qBAAqB,EAAE;AAC5B,QAAK,QAAQ;AACb;;EAGF,MAAM,YAAY,KAAK,YAAY,CAAC,MAAM;EAC1C,MAAM,aAAa,oBAAoB,KAAK,YAAY,UAAU;EAClE,MAAM,OAAO,KAAK,UAAU;GAC1B,YAAY;GACZ,WAAW,KAAK;GAChB,OAAO,KAAK;GACb,CAAC;AACF,MAAI,SAAS,KAAK,YAAa;AAC/B,OAAK,cAAc;EAEnB,MAAM,0BAAU,IAAI,KAA4B;AAChD,OAAK,MAAM,aAAa,YAAY;GAClC,MAAM,YAAY,KAAK,aAAa,sBAAsB,UAAU;AACpE,OAAI,CAAC,QAAQ,IAAI,UAAU,CAAE,SAAQ,IAAI,WAAW,EAAE,CAAC;AACvD,WAAQ,IAAI,UAAU,CAAE,KAAK,UAAU;;EAGzC,MAAM,YAAY,KAAK,cAAc;AACrC,MAAI;AACF,QAAK,MAAM,CAAC,WAAW,QAAQ,SAAS;IACtC,MAAM,WAAW,UAAU,MAAM,WAAW,UAAU;IACtD,IAAI,WAAW,WACX,IAAI,QAAQ,OAAO,EAAE,mBAAmB,IAAI,GAC5C;AAEJ,QAAI,CAAC,YAAY,CAAC,SAAS,MAAM,OAAO,mBAAmB,GAAG,CAC5D,YAAW,CACT;KACE,SAAS;KACT,eAAe;MACb;MACA;MACA,OAAO,KAAK,SAAS,EAAE;MACxB;KACF,EACD,GAAG,SACJ;AAEH,cAAU,gBAAgB,SAAS;;AAErC,QAAK,qBAAqB,CAAC,GAAG,QAAQ,MAAM,CAAC;AAC7C,QAAK,QAAQ;WACN,KAAK;GACZ,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAChE,QAAK,QAAQ;AACb,QAAK,cACH,IAAI,YAAY,cAAc;IAC5B,QAAQ;KAAE,OAAO;KAAK;KAAS;IAC/B,SAAS;IACT,UAAU;IACX,CAAC,CACH;;;CAIL,SAAS;AACP,MAAI,KAAK,MACP,QAAO,QAAI;;;;+BAIc,KAAK,MAAM;;;AAKtC,MAAI,CAAC,KAAK,mBAAmB,OAC3B,QAAO,KAAK,mBAAmB,KAAK,kBAAkB,GAAG,gBAAgB;EAG3E,MAAM,YAAY,KAAK,cAAc;AACrC,SAAO,QAAI;;;;;UAKL,KAAK,mBAAmB,KAAK,cAAc;GAC3C,MAAM,UAAU,UAAU,MAAM,WAAW,UAAU;AACrD,OAAI,CAAC,QAAS,QAAOC;AACrB,UAAO,QAAI;;;gCAGW,UAAU;;;;kCAIR,UAAU;;;6BAGf,QAAQ;iCACJ,OAAO;8BACV,IAAI;;;;;IAKxB,CAAC"}