{"version":3,"file":"ai-model/prompt/markdown-generator.mjs","sources":["../../../../src/ai-model/prompt/markdown-generator.ts"],"sourcesContent":["import type { IModelConfig } from '@midscene/shared/env';\nimport {\n  imageInfoOfBase64,\n  parseBase64,\n  resizeImgBase64,\n} from '@midscene/shared/img';\nimport { getDebug } from '@midscene/shared/logger';\nimport {\n  type MidsceneRecorderMarkdownScreenshotAsset,\n  getMidsceneRecorderEventDescription,\n  stringifyMidsceneRecorderTargetBlock,\n} from '@midscene/shared/recorder';\nimport type { ChatCompletionMessageParam } from 'openai/resources/index';\nimport { callAIWithStringResponse } from '../index';\nimport { type ModelRuntime, getModelRuntime } from '../models';\nimport {\n  type RecorderGenerationInput,\n  prepareRecorderGenerationContext,\n  validateEvents,\n} from './recorder-generation-common';\n\nexport type RecorderMarkdownGenerationInput = RecorderGenerationInput;\n\nconst MARKDOWN_REPLAY_SCREENSHOT_PAYLOAD_BUDGET = 600_000;\nconst MARKDOWN_REPLAY_SCREENSHOT_MAX_EDGE = 768;\nconst debugMarkdownReplay = getDebug('ai:recorder-markdown', {\n  console: true,\n});\n\nfunction limitScreenshotAssetsForMarkdownReplay(\n  screenshotAssets: MidsceneRecorderMarkdownScreenshotAsset[],\n) {\n  let usedPayload = 0;\n  return screenshotAssets.filter((asset) => {\n    const payloadSize = asset.dataUrl.length;\n    if (\n      payloadSize > MARKDOWN_REPLAY_SCREENSHOT_PAYLOAD_BUDGET ||\n      usedPayload + payloadSize > MARKDOWN_REPLAY_SCREENSHOT_PAYLOAD_BUDGET\n    ) {\n      return false;\n    }\n    usedPayload += payloadSize;\n    return true;\n  });\n}\n\nasync function compressScreenshotAssetForMarkdownReplay(\n  asset: MidsceneRecorderMarkdownScreenshotAsset,\n): Promise<MidsceneRecorderMarkdownScreenshotAsset> {\n  const { width, height } = await imageInfoOfBase64(asset.dataUrl);\n  const longestEdge = Math.max(width, height);\n  if (longestEdge <= MARKDOWN_REPLAY_SCREENSHOT_MAX_EDGE) {\n    return asset;\n  }\n\n  const scale = MARKDOWN_REPLAY_SCREENSHOT_MAX_EDGE / longestEdge;\n  const dataUrl = await resizeImgBase64(asset.dataUrl, {\n    width: Math.max(1, Math.round(width * scale)),\n    height: Math.max(1, Math.round(height * scale)),\n  });\n  const { body, mimeType } = parseBase64(dataUrl);\n  return {\n    ...asset,\n    dataUrl,\n    base64Data: body,\n    mimeType,\n  };\n}\n\nasync function prepareScreenshotAssetsForMarkdownReplay(\n  screenshotAssets: MidsceneRecorderMarkdownScreenshotAsset[],\n) {\n  const compressedAssets: MidsceneRecorderMarkdownScreenshotAsset[] = [];\n  for (const asset of screenshotAssets) {\n    try {\n      compressedAssets.push(\n        await compressScreenshotAssetForMarkdownReplay(asset),\n      );\n    } catch {\n      compressedAssets.push(asset);\n    }\n  }\n  return limitScreenshotAssetsForMarkdownReplay(compressedAssets);\n}\n\nfunction summarizeScreenshotAssets(\n  screenshotAssets: MidsceneRecorderMarkdownScreenshotAsset[],\n) {\n  const payloadSizes = screenshotAssets.map((asset) => asset.dataUrl.length);\n  return {\n    count: screenshotAssets.length,\n    totalPayloadChars: payloadSizes.reduce((sum, size) => sum + size, 0),\n    maxPayloadChars: payloadSizes.length ? Math.max(...payloadSizes) : 0,\n  };\n}\n\nfunction getPromptShape(prompt: ChatCompletionMessageParam[]) {\n  let textChars = 0;\n  let imageCount = 0;\n  for (const message of prompt) {\n    const content = message.content;\n    if (typeof content === 'string') {\n      textChars += content.length;\n      continue;\n    }\n    if (!Array.isArray(content)) {\n      continue;\n    }\n    for (const part of content) {\n      if (typeof part === 'object' && part && 'type' in part) {\n        if (part.type === 'text' && 'text' in part) {\n          textChars += String(part.text).length;\n        }\n        if (part.type === 'image_url') {\n          imageCount += 1;\n        }\n      }\n    }\n  }\n  return { textChars, imageCount };\n}\n\nfunction removeOmittedScreenshotPaths(\n  summary: ReturnType<typeof prepareRecorderGenerationContext>['summary'],\n  screenshotAssets: MidsceneRecorderMarkdownScreenshotAsset[],\n) {\n  const includedScreenshotPaths = new Set(\n    screenshotAssets.map((asset) => asset.relativePath),\n  );\n  return {\n    ...summary,\n    events: summary.events.map((event) =>\n      event.screenshotPath && !includedScreenshotPaths.has(event.screenshotPath)\n        ? { ...event, screenshotPath: undefined }\n        : event,\n    ),\n  };\n}\n\nfunction getMarkdownLanguageInstruction(language?: string) {\n  const normalizedLanguage = language?.trim();\n  if (!normalizedLanguage) {\n    return '';\n  }\n\n  return `\nLanguage requirement:\n- Write all human-readable Markdown instructions in ${normalizedLanguage}.\n- Keep file paths, URLs, platform ids, API names, and quoted UI text unchanged.`;\n}\n\nfunction normalizeGeneratedMarkdown(content: string) {\n  const trimmed = content.trim();\n  const fencedMatch = trimmed.match(\n    /^```(?:md|markdown)?\\s*([\\s\\S]*?)\\s*```$/i,\n  );\n  return `${(fencedMatch?.[1] ?? trimmed).trim()}\\n`;\n}\n\nfunction resolveModelRuntime(model: IModelConfig | ModelRuntime): ModelRuntime {\n  if ('config' in model && 'adapter' in model) {\n    return model;\n  }\n  return getModelRuntime(model);\n}\n\nexport function createRecorderMarkdownReplayPrompt(\n  input: RecorderMarkdownGenerationInput,\n): ChatCompletionMessageParam[] {\n  validateEvents(input.events);\n\n  const { summary: rawSummary, screenshotAssets: rawScreenshotAssets } =\n    prepareRecorderGenerationContext(input);\n  const screenshotAssets =\n    limitScreenshotAssetsForMarkdownReplay(rawScreenshotAssets);\n  const summary = removeOmittedScreenshotPaths(rawSummary, screenshotAssets);\n  return createRecorderMarkdownReplayPromptFromContext(\n    input,\n    summary,\n    screenshotAssets,\n  );\n}\n\nasync function createRecorderMarkdownReplayPromptForGeneration(\n  input: RecorderMarkdownGenerationInput,\n): Promise<ChatCompletionMessageParam[]> {\n  validateEvents(input.events);\n\n  const { summary: rawSummary, screenshotAssets: rawScreenshotAssets } =\n    prepareRecorderGenerationContext(input);\n  const screenshotAssets =\n    await prepareScreenshotAssetsForMarkdownReplay(rawScreenshotAssets);\n  const summary = removeOmittedScreenshotPaths(rawSummary, screenshotAssets);\n  const prompt = createRecorderMarkdownReplayPromptFromContext(\n    input,\n    summary,\n    screenshotAssets,\n  );\n  debugMarkdownReplay('markdown replay prompt shape %o', {\n    eventCount: input.events.length,\n    maxScreenshots: input.maxScreenshots,\n    rawScreenshots: summarizeScreenshotAssets(rawScreenshotAssets),\n    includedScreenshots: summarizeScreenshotAssets(screenshotAssets),\n    prompt: getPromptShape(prompt),\n  });\n  return prompt;\n}\n\nfunction createRecorderMarkdownReplayPromptFromContext(\n  input: RecorderMarkdownGenerationInput,\n  summary: ReturnType<typeof prepareRecorderGenerationContext>['summary'],\n  screenshotAssets: MidsceneRecorderMarkdownScreenshotAsset[],\n): ChatCompletionMessageParam[] {\n  const screenshotIndexByEventHash = new Map(\n    screenshotAssets.map((asset, index) => [\n      asset.eventHashId,\n      `screenshot-${index + 1}`,\n    ]),\n  );\n  const events = summary.events.map((event) => {\n    const screenshotRef = screenshotIndexByEventHash.get(event.hashId);\n    const { screenshotPath, ...eventWithoutScreenshotPath } = event;\n    return screenshotRef\n      ? { ...eventWithoutScreenshotPath, screenshotRef }\n      : eventWithoutScreenshotPath;\n  });\n  const promptPayload = {\n    testName: input.testName || summary.testName,\n    target: {\n      platformId: input.target.platformId,\n      label: input.target.label,\n      values: input.target.values,\n    },\n    startUrl: summary.startUrl,\n    events,\n    screenshots: screenshotAssets.map((asset, index) => ({\n      screenshotRef: `screenshot-${index + 1}`,\n      eventIndex: asset.eventIndex,\n      eventHashId: asset.eventHashId,\n      eventType: asset.eventType,\n      description: getMidsceneRecorderEventDescription(\n        input.events[asset.eventIndex],\n      ),\n    })),\n  };\n  const promptText = `Generate a Markdown replay script for Midscene Agent. It will be executed with:\nawait agent.aiAct(markdownReplayPrompt)\n\nUse only the recorder data and screenshots below.\n\nTarget block:\n${stringifyMidsceneRecorderTargetBlock(input.target)}\n\nReplay goal:\n- Reproduce the recorded user workflow exactly.\n- Preserve event order.\n- Preserve the user's original intent.\n- Do not invent alternative navigation paths.\n- Do not skip, merge, reorder, or add extra user actions.\n- Prefer recorded UI text, element descriptions, URLs, input values, and scroll direction.\n- For input events, enter event.typedText/event.value exactly; do not infer or correct the text from screenshots.\n- Prefer event.semantic.replayInstruction and event.semantic.elementDescription when event.semantic.source is \"aiDescribe\" or \"recorderAI\" and event.semantic.status is \"ready\".\n- For scroll events, preserve the recorded scroll region from event.semantic.elementDescription/replayInstruction. If the scroll happened in a specific panel, list, table, dialog body, menu, navigation area, or content pane, keep that region in the Markdown step instead of generalizing it to the whole page.\n- If event.semantic.source is \"heuristic\" or event.semantic.status is \"pending\"/\"failed\", use the screenshot/context to write the best visual instruction.\n- Coordinates are only fallback hints. Do not make coordinates the primary instruction when text or screenshots are available.\n- For a click/tap that only focuses a field before an input event, describe the target as the field/control itself. Do not target a placeholder character, typed character, caret, or inner text fragment inside the field.\n- If a target cannot be found, stop and report the missing step. Do not click similar-looking elements.\n- Screenshots are only generation-time visual evidence for you. The generated Markdown will be passed directly to agent.aiAct(markdownReplayPrompt), which accepts text only and cannot receive attached images.\n- Convert any useful screenshot evidence into textual replay instructions. Do not include screenshots, image syntax, image paths, or reference-image names in the generated Markdown.\n- Never write Markdown image syntax such as ![step context](...), reference-style images, HTML <img> tags, ./screenshots/... paths, or screenshot-* names in the output.\n\nRequired structure:\n# ${input.testName || summary.testName}\n\n## Goal\nReproduce the recorded user workflow exactly.\n\n## Target\n- Platform: ${input.target.platformId}\n- Start target: ${summary.startUrl || input.target.label || input.target.deviceId || 'Recorded target'}\n\n## Steps\n1. ...\n\nRecorder data:\n${JSON.stringify(promptPayload, null, 2)}${getMarkdownLanguageInstruction(input.language)}\n\nImportant: Return ONLY raw Markdown. Do NOT wrap the response in markdown code blocks.`;\n\n  const content: any[] = [\n    {\n      type: 'text',\n      text: promptText,\n    },\n  ];\n\n  for (const asset of screenshotAssets) {\n    const screenshotRef = screenshotIndexByEventHash.get(asset.eventHashId);\n    content.push({\n      type: 'text',\n      text: `${screenshotRef} for event #${asset.eventIndex + 1}`,\n    });\n    content.push({\n      type: 'image_url',\n      image_url: {\n        url: asset.dataUrl,\n      },\n    });\n  }\n\n  return [\n    {\n      role: 'system',\n      content:\n        'You generate precise Markdown replay scripts for Midscene agent.aiAct. The final output is plain text that will be passed directly to agent.aiAct, so it must be deterministic, ordered, safe for AI execution, and must not contain image references, screenshot paths, or screenshot labels.',\n    },\n    {\n      role: 'user',\n      content,\n    },\n  ];\n}\n\nexport async function generateRecorderMarkdownReplay(\n  input: RecorderMarkdownGenerationInput,\n  model: IModelConfig | ModelRuntime,\n): Promise<string> {\n  try {\n    const prompt = await createRecorderMarkdownReplayPromptForGeneration(input);\n    const response = await callAIWithStringResponse(\n      prompt,\n      resolveModelRuntime(model),\n    );\n\n    if (response?.content && typeof response.content === 'string') {\n      return normalizeGeneratedMarkdown(response.content);\n    }\n\n    throw new Error('Failed to generate recorder Markdown replay');\n  } catch (error) {\n    throw new Error(`Failed to generate recorder Markdown replay: ${error}`);\n  }\n}\n\nexport async function convertRecordLogIntoMarkdown(\n  log: RecorderMarkdownGenerationInput,\n  modelConfig: IModelConfig,\n): Promise<string> {\n  return generateRecorderMarkdownReplay(log, modelConfig);\n}\n"],"names":["MARKDOWN_REPLAY_SCREENSHOT_PAYLOAD_BUDGET","MARKDOWN_REPLAY_SCREENSHOT_MAX_EDGE","debugMarkdownReplay","getDebug","limitScreenshotAssetsForMarkdownReplay","screenshotAssets","usedPayload","asset","payloadSize","compressScreenshotAssetForMarkdownReplay","width","height","imageInfoOfBase64","longestEdge","Math","scale","dataUrl","resizeImgBase64","body","mimeType","parseBase64","prepareScreenshotAssetsForMarkdownReplay","compressedAssets","summarizeScreenshotAssets","payloadSizes","sum","size","getPromptShape","prompt","textChars","imageCount","message","content","Array","part","String","removeOmittedScreenshotPaths","summary","includedScreenshotPaths","Set","event","undefined","getMarkdownLanguageInstruction","language","normalizedLanguage","normalizeGeneratedMarkdown","trimmed","fencedMatch","resolveModelRuntime","model","getModelRuntime","createRecorderMarkdownReplayPrompt","input","validateEvents","rawSummary","rawScreenshotAssets","prepareRecorderGenerationContext","createRecorderMarkdownReplayPromptFromContext","createRecorderMarkdownReplayPromptForGeneration","screenshotIndexByEventHash","Map","index","events","screenshotRef","screenshotPath","eventWithoutScreenshotPath","promptPayload","getMidsceneRecorderEventDescription","promptText","stringifyMidsceneRecorderTargetBlock","JSON","generateRecorderMarkdownReplay","response","callAIWithStringResponse","Error","error","convertRecordLogIntoMarkdown","log","modelConfig"],"mappings":";;;;;;AAuBA,MAAMA,4CAA4C;AAClD,MAAMC,sCAAsC;AAC5C,MAAMC,sBAAsBC,SAAS,wBAAwB;IAC3D,SAAS;AACX;AAEA,SAASC,uCACPC,gBAA2D;IAE3D,IAAIC,cAAc;IAClB,OAAOD,iBAAiB,MAAM,CAAC,CAACE;QAC9B,MAAMC,cAAcD,MAAM,OAAO,CAAC,MAAM;QACxC,IACEC,cAAcR,6CACdM,cAAcE,cAAcR,2CAE5B,OAAO;QAETM,eAAeE;QACf,OAAO;IACT;AACF;AAEA,eAAeC,yCACbF,KAA8C;IAE9C,MAAM,EAAEG,KAAK,EAAEC,MAAM,EAAE,GAAG,MAAMC,kBAAkBL,MAAM,OAAO;IAC/D,MAAMM,cAAcC,KAAK,GAAG,CAACJ,OAAOC;IACpC,IAAIE,eAAeZ,qCACjB,OAAOM;IAGT,MAAMQ,QAAQd,sCAAsCY;IACpD,MAAMG,UAAU,MAAMC,gBAAgBV,MAAM,OAAO,EAAE;QACnD,OAAOO,KAAK,GAAG,CAAC,GAAGA,KAAK,KAAK,CAACJ,QAAQK;QACtC,QAAQD,KAAK,GAAG,CAAC,GAAGA,KAAK,KAAK,CAACH,SAASI;IAC1C;IACA,MAAM,EAAEG,IAAI,EAAEC,QAAQ,EAAE,GAAGC,YAAYJ;IACvC,OAAO;QACL,GAAGT,KAAK;QACRS;QACA,YAAYE;QACZC;IACF;AACF;AAEA,eAAeE,yCACbhB,gBAA2D;IAE3D,MAAMiB,mBAA8D,EAAE;IACtE,KAAK,MAAMf,SAASF,iBAClB,IAAI;QACFiB,iBAAiB,IAAI,CACnB,MAAMb,yCAAyCF;IAEnD,EAAE,OAAM;QACNe,iBAAiB,IAAI,CAACf;IACxB;IAEF,OAAOH,uCAAuCkB;AAChD;AAEA,SAASC,0BACPlB,gBAA2D;IAE3D,MAAMmB,eAAenB,iBAAiB,GAAG,CAAC,CAACE,QAAUA,MAAM,OAAO,CAAC,MAAM;IACzE,OAAO;QACL,OAAOF,iBAAiB,MAAM;QAC9B,mBAAmBmB,aAAa,MAAM,CAAC,CAACC,KAAKC,OAASD,MAAMC,MAAM;QAClE,iBAAiBF,aAAa,MAAM,GAAGV,KAAK,GAAG,IAAIU,gBAAgB;IACrE;AACF;AAEA,SAASG,eAAeC,MAAoC;IAC1D,IAAIC,YAAY;IAChB,IAAIC,aAAa;IACjB,KAAK,MAAMC,WAAWH,OAAQ;QAC5B,MAAMI,UAAUD,QAAQ,OAAO;QAC/B,IAAI,AAAmB,YAAnB,OAAOC,SAAsB;YAC/BH,aAAaG,QAAQ,MAAM;YAC3B;QACF;QACA,IAAKC,MAAM,OAAO,CAACD,UAGnB;YAAA,KAAK,MAAME,QAAQF,QACjB,IAAI,AAAgB,YAAhB,OAAOE,QAAqBA,QAAQ,UAAUA,MAAM;gBACtD,IAAIA,AAAc,WAAdA,KAAK,IAAI,IAAe,UAAUA,MACpCL,aAAaM,OAAOD,KAAK,IAAI,EAAE,MAAM;gBAEvC,IAAIA,AAAc,gBAAdA,KAAK,IAAI,EACXJ,cAAc;YAElB;QACF;IACF;IACA,OAAO;QAAED;QAAWC;IAAW;AACjC;AAEA,SAASM,6BACPC,OAAuE,EACvEhC,gBAA2D;IAE3D,MAAMiC,0BAA0B,IAAIC,IAClClC,iBAAiB,GAAG,CAAC,CAACE,QAAUA,MAAM,YAAY;IAEpD,OAAO;QACL,GAAG8B,OAAO;QACV,QAAQA,QAAQ,MAAM,CAAC,GAAG,CAAC,CAACG,QAC1BA,MAAM,cAAc,IAAI,CAACF,wBAAwB,GAAG,CAACE,MAAM,cAAc,IACrE;gBAAE,GAAGA,KAAK;gBAAE,gBAAgBC;YAAU,IACtCD;IAER;AACF;AAEA,SAASE,+BAA+BC,QAAiB;IACvD,MAAMC,qBAAqBD,UAAU;IACrC,IAAI,CAACC,oBACH,OAAO;IAGT,OAAO,CAAC;;oDAE0C,EAAEA,mBAAmB;+EACM,CAAC;AAChF;AAEA,SAASC,2BAA2Bb,OAAe;IACjD,MAAMc,UAAUd,QAAQ,IAAI;IAC5B,MAAMe,cAAcD,QAAQ,KAAK,CAC/B;IAEF,OAAO,GAAIC,AAAAA,CAAAA,aAAa,CAAC,EAAE,IAAID,OAAM,EAAG,IAAI,GAAG,EAAE,CAAC;AACpD;AAEA,SAASE,oBAAoBC,KAAkC;IAC7D,IAAI,YAAYA,SAAS,aAAaA,OACpC,OAAOA;IAET,OAAOC,gBAAgBD;AACzB;AAEO,SAASE,mCACdC,KAAsC;IAEtCC,eAAeD,MAAM,MAAM;IAE3B,MAAM,EAAE,SAASE,UAAU,EAAE,kBAAkBC,mBAAmB,EAAE,GAClEC,iCAAiCJ;IACnC,MAAM/C,mBACJD,uCAAuCmD;IACzC,MAAMlB,UAAUD,6BAA6BkB,YAAYjD;IACzD,OAAOoD,8CACLL,OACAf,SACAhC;AAEJ;AAEA,eAAeqD,gDACbN,KAAsC;IAEtCC,eAAeD,MAAM,MAAM;IAE3B,MAAM,EAAE,SAASE,UAAU,EAAE,kBAAkBC,mBAAmB,EAAE,GAClEC,iCAAiCJ;IACnC,MAAM/C,mBACJ,MAAMgB,yCAAyCkC;IACjD,MAAMlB,UAAUD,6BAA6BkB,YAAYjD;IACzD,MAAMuB,SAAS6B,8CACbL,OACAf,SACAhC;IAEFH,oBAAoB,mCAAmC;QACrD,YAAYkD,MAAM,MAAM,CAAC,MAAM;QAC/B,gBAAgBA,MAAM,cAAc;QACpC,gBAAgB7B,0BAA0BgC;QAC1C,qBAAqBhC,0BAA0BlB;QAC/C,QAAQsB,eAAeC;IACzB;IACA,OAAOA;AACT;AAEA,SAAS6B,8CACPL,KAAsC,EACtCf,OAAuE,EACvEhC,gBAA2D;IAE3D,MAAMsD,6BAA6B,IAAIC,IACrCvD,iBAAiB,GAAG,CAAC,CAACE,OAAOsD,QAAU;YACrCtD,MAAM,WAAW;YACjB,CAAC,WAAW,EAAEsD,QAAQ,GAAG;SAC1B;IAEH,MAAMC,SAASzB,QAAQ,MAAM,CAAC,GAAG,CAAC,CAACG;QACjC,MAAMuB,gBAAgBJ,2BAA2B,GAAG,CAACnB,MAAM,MAAM;QACjE,MAAM,EAAEwB,cAAc,EAAE,GAAGC,4BAA4B,GAAGzB;QAC1D,OAAOuB,gBACH;YAAE,GAAGE,0BAA0B;YAAEF;QAAc,IAC/CE;IACN;IACA,MAAMC,gBAAgB;QACpB,UAAUd,MAAM,QAAQ,IAAIf,QAAQ,QAAQ;QAC5C,QAAQ;YACN,YAAYe,MAAM,MAAM,CAAC,UAAU;YACnC,OAAOA,MAAM,MAAM,CAAC,KAAK;YACzB,QAAQA,MAAM,MAAM,CAAC,MAAM;QAC7B;QACA,UAAUf,QAAQ,QAAQ;QAC1ByB;QACA,aAAazD,iBAAiB,GAAG,CAAC,CAACE,OAAOsD,QAAW;gBACnD,eAAe,CAAC,WAAW,EAAEA,QAAQ,GAAG;gBACxC,YAAYtD,MAAM,UAAU;gBAC5B,aAAaA,MAAM,WAAW;gBAC9B,WAAWA,MAAM,SAAS;gBAC1B,aAAa4D,oCACXf,MAAM,MAAM,CAAC7C,MAAM,UAAU,CAAC;YAElC;IACF;IACA,MAAM6D,aAAa,CAAC;;;;;;AAMtB,EAAEC,qCAAqCjB,MAAM,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;EAqBnD,EAAEA,MAAM,QAAQ,IAAIf,QAAQ,QAAQ,CAAC;;;;;;YAM3B,EAAEe,MAAM,MAAM,CAAC,UAAU,CAAC;gBACtB,EAAEf,QAAQ,QAAQ,IAAIe,MAAM,MAAM,CAAC,KAAK,IAAIA,MAAM,MAAM,CAAC,QAAQ,IAAI,kBAAkB;;;;;;AAMvG,EAAEkB,KAAK,SAAS,CAACJ,eAAe,MAAM,KAAKxB,+BAA+BU,MAAM,QAAQ,EAAE;;sFAEJ,CAAC;IAErF,MAAMpB,UAAiB;QACrB;YACE,MAAM;YACN,MAAMoC;QACR;KACD;IAED,KAAK,MAAM7D,SAASF,iBAAkB;QACpC,MAAM0D,gBAAgBJ,2BAA2B,GAAG,CAACpD,MAAM,WAAW;QACtEyB,QAAQ,IAAI,CAAC;YACX,MAAM;YACN,MAAM,GAAG+B,cAAc,YAAY,EAAExD,MAAM,UAAU,GAAG,GAAG;QAC7D;QACAyB,QAAQ,IAAI,CAAC;YACX,MAAM;YACN,WAAW;gBACT,KAAKzB,MAAM,OAAO;YACpB;QACF;IACF;IAEA,OAAO;QACL;YACE,MAAM;YACN,SACE;QACJ;QACA;YACE,MAAM;YACNyB;QACF;KACD;AACH;AAEO,eAAeuC,+BACpBnB,KAAsC,EACtCH,KAAkC;IAElC,IAAI;QACF,MAAMrB,SAAS,MAAM8B,gDAAgDN;QACrE,MAAMoB,WAAW,MAAMC,yBACrB7C,QACAoB,oBAAoBC;QAGtB,IAAIuB,UAAU,WAAW,AAA4B,YAA5B,OAAOA,SAAS,OAAO,EAC9C,OAAO3B,2BAA2B2B,SAAS,OAAO;QAGpD,MAAM,IAAIE,MAAM;IAClB,EAAE,OAAOC,OAAO;QACd,MAAM,IAAID,MAAM,CAAC,6CAA6C,EAAEC,OAAO;IACzE;AACF;AAEO,eAAeC,6BACpBC,GAAoC,EACpCC,WAAyB;IAEzB,OAAOP,+BAA+BM,KAAKC;AAC7C"}