{"version":3,"file":"task-runner.mjs","sources":["../../src/task-runner.ts"],"sourcesContent":["import type { ScreenshotItem } from '@/screenshot-item';\nimport { setTimingFieldOnce } from '@/task-timing';\nimport {\n  ExecutionDump,\n  type ExecutionRecorderItem,\n  type ExecutionTask,\n  type ExecutionTaskActionApply,\n  type ExecutionTaskApply,\n  type ExecutionTaskPlanningLocateOutput,\n  type ExecutionTaskProgressOptions,\n  type ExecutionTaskReturn,\n  type ExecutorContext,\n  type PlanningActionParamError,\n  type UIContext,\n} from '@/types';\nimport {\n  type SerializedError,\n  serializeError,\n  truncateSerializedErrorString,\n} from '@midscene/shared/agent-tools/error-formatter';\nimport { getDebug } from '@midscene/shared/logger';\nimport { assert, uuid } from '@midscene/shared/utils';\n\nconst debug = getDebug('task-runner');\nconst UI_CONTEXT_CACHE_TTL_MS = 300;\n\n/**\n * A native, per-task lifecycle notification. The runner is the single source\n * of truth for when a task actually transitions, so it reports each transition\n * exactly once with the task that changed. Consumers no longer have to re-scan\n * the task list and diff it against remembered keys to reconstruct this stream.\n */\nexport type TaskRunnerEventKind =\n  | 'append'\n  | 'start'\n  | 'finish'\n  | 'error'\n  | 'cancel';\n\nexport interface TaskRunnerEvent {\n  kind: TaskRunnerEventKind;\n  task: ExecutionTask;\n  runner: TaskRunner;\n}\n\nexport interface SerializedErrorTask {\n  taskId: string;\n  type: ExecutionTask['type'];\n  subType?: string;\n  status: ExecutionTask['status'];\n  thought?: string;\n  errorMessage?: string;\n}\n\nexport interface SerializedTaskExecutionError extends SerializedError {\n  code: 'TASK_EXECUTION_FAILED';\n  cause: SerializedError;\n  task?: SerializedErrorTask;\n}\n\nfunction serializeErrorTask(\n  task: ExecutionTask | null,\n): SerializedErrorTask | undefined {\n  if (!task) {\n    return undefined;\n  }\n\n  return {\n    taskId: truncateSerializedErrorString(task.taskId),\n    type: task.type,\n    ...(task.subType === undefined\n      ? {}\n      : { subType: truncateSerializedErrorString(task.subType) }),\n    status: task.status,\n    ...(task.thought === undefined\n      ? {}\n      : { thought: truncateSerializedErrorString(task.thought) }),\n    ...(task.errorMessage === undefined\n      ? {}\n      : {\n          errorMessage: truncateSerializedErrorString(task.errorMessage),\n        }),\n  };\n}\n\nexport type TaskRunnerEventListener = (\n  event: TaskRunnerEvent,\n) => Promise<void> | void;\n\n/** Minimal prompt-image shape retained as report asset metadata. */\nexport interface ExecutionReferenceImage {\n  readonly url: string;\n}\n\ntype TaskRunnerInitOptions = ExecutionTaskProgressOptions & {\n  tasks?: ExecutionTaskApply[];\n  referenceImages?: readonly ExecutionReferenceImage[];\n  /**\n   * Coarse \"the execution snapshot changed\" signal. Fires on any state change\n   * (append, status flips, completion) with the whole runner, so consumers can\n   * re-dump/re-render the current snapshot. Deliberately batch-granular, unlike\n   * the per-task {@link onTaskEvent} stream.\n   */\n  onSnapshotChange?: (\n    runner: TaskRunner,\n    error?: TaskExecutionError,\n  ) => Promise<void> | void;\n  onTaskEvent?: TaskRunnerEventListener;\n};\n\ntype TaskRunnerOperationOptions = {\n  allowWhenError?: boolean;\n};\n\nexport class TaskRunner {\n  readonly id: string;\n  name: string;\n\n  tasks: ExecutionTask[];\n\n  // status of runner\n  status: 'init' | 'pending' | 'running' | 'completed' | 'error';\n\n  onTaskStart?: ExecutionTaskProgressOptions['onTaskStart'];\n\n  private readonly uiContextBuilder: () => Promise<UIContext>;\n\n  private readonly onSnapshotChange?:\n    | ((runner: TaskRunner, error?: TaskExecutionError) => Promise<void> | void)\n    | undefined;\n\n  private readonly onTaskEvent?: TaskRunnerEventListener | undefined;\n\n  private readonly executionLogTime: number;\n\n  private readonly referenceImageUrls = new Set<string>();\n\n  constructor(\n    name: string,\n    uiContextBuilder: () => Promise<UIContext>,\n    options?: TaskRunnerInitOptions,\n  ) {\n    this.id = uuid();\n    this.status =\n      options?.tasks && options.tasks.length > 0 ? 'pending' : 'init';\n    this.name = name;\n    this.tasks = (options?.tasks || []).map((item) =>\n      this.markTaskAsPending(item),\n    );\n    this.onTaskStart = options?.onTaskStart;\n    this.uiContextBuilder = uiContextBuilder;\n    this.onSnapshotChange = options?.onSnapshotChange;\n    this.onTaskEvent = options?.onTaskEvent;\n    this.executionLogTime = Date.now();\n    for (const image of options?.referenceImages ?? []) {\n      this.referenceImageUrls.add(image.url);\n    }\n  }\n\n  private async emitSnapshotChange(error?: TaskExecutionError): Promise<void> {\n    if (!this.onSnapshotChange) {\n      return;\n    }\n    await this.onSnapshotChange(this, error);\n  }\n\n  private async emitTaskEvent(\n    kind: TaskRunnerEventKind,\n    task: ExecutionTask,\n  ): Promise<void> {\n    if (!this.onTaskEvent) {\n      return;\n    }\n    try {\n      await this.onTaskEvent({ kind, task, runner: this });\n    } catch (error) {\n      console.error('Error in onTaskEvent listener', error);\n    }\n  }\n\n  private lastUiContext?: {\n    context: UIContext;\n    capturedAt: number;\n  };\n\n  private async getUiContext(options?: { forceRefresh?: boolean }): Promise<\n    UIContext | undefined\n  > {\n    const now = Date.now();\n    const shouldReuse =\n      !options?.forceRefresh &&\n      this.lastUiContext &&\n      now - this.lastUiContext.capturedAt <= UI_CONTEXT_CACHE_TTL_MS;\n\n    if (shouldReuse && this.lastUiContext?.context) {\n      debug(\n        `reuse cached uiContext captured ${now - this.lastUiContext.capturedAt}ms ago`,\n      );\n      return this.lastUiContext?.context;\n    }\n\n    try {\n      const uiContext = await this.uiContextBuilder();\n      if (uiContext) {\n        this.lastUiContext = {\n          context: uiContext,\n          capturedAt: Date.now(),\n        };\n      } else {\n        this.lastUiContext = undefined;\n      }\n      return uiContext;\n    } catch (error) {\n      this.lastUiContext = undefined;\n      throw error;\n    }\n  }\n\n  private async captureScreenshot(): Promise<ScreenshotItem | undefined> {\n    try {\n      const uiContext = await this.getUiContext({ forceRefresh: true });\n      return uiContext?.screenshot;\n    } catch (error) {\n      console.error('error while capturing screenshot', error);\n    }\n    return undefined;\n  }\n\n  private attachRecorderItem(\n    task: ExecutionTask,\n    screenshot: ScreenshotItem | undefined,\n    phase: 'after-calling',\n  ): void {\n    if (!phase || !screenshot) {\n      return;\n    }\n\n    const recorderItem: ExecutionRecorderItem = {\n      type: 'screenshot',\n      ts: Date.now(),\n      screenshot,\n      timing: phase,\n    };\n\n    if (!task.recorder) {\n      task.recorder = [recorderItem];\n      return;\n    }\n    task.recorder.push(recorderItem);\n  }\n\n  private markTaskAsPending(task: ExecutionTaskApply): ExecutionTask {\n    return {\n      taskId: uuid(),\n      status: 'pending',\n      ...task,\n    };\n  }\n\n  private normalizeStatusFromError(\n    options?: TaskRunnerOperationOptions,\n    errorMessage?: string,\n  ): void {\n    if (this.status !== 'error') {\n      return;\n    }\n    assert(\n      options?.allowWhenError,\n      errorMessage ||\n        `task runner is in error state, cannot proceed\\nerror=${this.latestErrorTask()?.errorMessage}\\n${this.latestErrorTask()?.errorStack}`,\n    );\n    // reset runner state so new tasks can run\n    this.status = this.tasks.length > 0 ? 'pending' : 'init';\n  }\n\n  async append(\n    task: ExecutionTaskApply[] | ExecutionTaskApply,\n    options?: TaskRunnerOperationOptions,\n  ): Promise<void> {\n    this.normalizeStatusFromError(\n      options,\n      `task runner is in error state, cannot append task\\nerror=${this.latestErrorTask()?.errorMessage}\\n${this.latestErrorTask()?.errorStack}`,\n    );\n    const appended: ExecutionTask[] = [];\n    if (Array.isArray(task)) {\n      appended.push(...task.map((item) => this.markTaskAsPending(item)));\n    } else {\n      appended.push(this.markTaskAsPending(task));\n    }\n    this.tasks.push(...appended);\n    if (this.status !== 'running') {\n      this.status = 'pending';\n    }\n    await this.emitSnapshotChange();\n    for (const appendedTask of appended) {\n      await this.emitTaskEvent('append', appendedTask);\n    }\n  }\n\n  async appendAndFlush(\n    task: ExecutionTaskApply[] | ExecutionTaskApply,\n    options?: TaskRunnerOperationOptions,\n  ): Promise<{ output: any; thought?: string } | undefined> {\n    await this.append(task, options);\n    return this.flush(options);\n  }\n\n  async flush(\n    options?: TaskRunnerOperationOptions,\n  ): Promise<{ output: any; thought?: string } | undefined> {\n    if (this.status === 'init' && this.tasks.length > 0) {\n      console.warn(\n        'illegal state for task runner, status is init but tasks are not empty',\n      );\n    }\n\n    this.normalizeStatusFromError(options, 'task runner is in error state');\n    assert(this.status !== 'running', 'task runner is already running');\n    assert(this.status !== 'completed', 'task runner is already completed');\n\n    const nextPendingIndex = this.tasks.findIndex(\n      (task) => task.status === 'pending',\n    );\n    if (nextPendingIndex < 0) {\n      // all tasks are completed\n      return;\n    }\n\n    this.status = 'running';\n    await this.emitSnapshotChange();\n    let taskIndex = nextPendingIndex;\n    let successfullyCompleted = true;\n\n    let previousFindOutput: ExecutionTaskPlanningLocateOutput | undefined;\n\n    while (taskIndex < this.tasks.length) {\n      const task = this.tasks[taskIndex];\n      assert(\n        task.status === 'pending',\n        `task status should be pending, but got: ${task.status}`,\n      );\n      task.timing = {\n        start: Date.now(),\n      };\n      try {\n        task.status = 'running';\n        await this.emitSnapshotChange();\n        await this.emitTaskEvent('start', task);\n        try {\n          if (this.onTaskStart) {\n            await this.onTaskStart(task);\n          }\n        } catch (e) {\n          console.error('error in onTaskStart', e);\n        }\n        assert(\n          ['Insight', 'Action Space', 'Planning'].indexOf(task.type) >= 0,\n          `unsupported task type: ${task.type}`,\n        );\n\n        const { executor } = task;\n        assert(executor, `executor is required for task type: ${task.type}`);\n\n        let returnValue;\n        // For Insight tasks (Query/Assert/WaitFor), always get fresh context\n        // to ensure we have the latest UI state after any preceding actions\n        const forceRefresh = task.type === 'Insight';\n        setTimingFieldOnce(task.timing, 'getUiContextStart');\n        const uiContext = await this.getUiContext({ forceRefresh });\n        setTimingFieldOnce(task.timing, 'getUiContextEnd');\n\n        task.uiContext = uiContext;\n        const executorContext: ExecutorContext = {\n          task,\n          element: previousFindOutput?.element,\n          uiContext,\n        };\n\n        if (task.type === 'Insight') {\n          assert(\n            task.subType === 'Query' ||\n              task.subType === 'Assert' ||\n              task.subType === 'WaitFor' ||\n              task.subType === 'Boolean' ||\n              task.subType === 'Number' ||\n              task.subType === 'String',\n            `unsupported service subType: ${task.subType}`,\n          );\n          returnValue = await task.executor(executorContext);\n        } else if (task.type === 'Planning') {\n          returnValue = await task.executor(executorContext);\n          if (task.subType === 'Locate') {\n            previousFindOutput = (\n              returnValue as ExecutionTaskReturn<ExecutionTaskPlanningLocateOutput>\n            )?.output;\n          }\n        } else if (task.type === 'Action Space') {\n          try {\n            returnValue = await task.executor(executorContext);\n          } finally {\n            // The short TTL still lets planning and the action itself share one\n            // context. Once an action settles, time alone can no longer prove\n            // that the cached context represents the current UI.\n            this.lastUiContext = undefined;\n          }\n        } else {\n          console.warn(\n            `unsupported task type: ${task.type}, will try to execute it directly`,\n          );\n          returnValue = await task.executor(executorContext);\n        }\n\n        const isLastTask = taskIndex === this.tasks.length - 1;\n\n        if (isLastTask) {\n          setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotStart');\n          const screenshot = await this.captureScreenshot();\n          this.attachRecorderItem(task, screenshot, 'after-calling');\n          setTimingFieldOnce(task.timing, 'captureAfterCallingSnapshotEnd');\n        }\n\n        Object.assign(task, returnValue);\n        task.status = 'finished';\n        task.timing.end = Date.now();\n        task.timing.cost = task.timing.end - task.timing.start;\n        await this.emitSnapshotChange();\n        await this.emitTaskEvent('finish', task);\n        taskIndex++;\n      } catch (error) {\n        successfullyCompleted = false;\n        const serializedError = serializeError(error);\n        task.error = serializedError;\n        task.errorMessage = serializedError.message;\n        task.errorStack = serializedError.stack;\n\n        task.status = 'failed';\n        task.timing.end = Date.now();\n        task.timing.cost = task.timing.end - task.timing.start;\n        await this.emitSnapshotChange();\n        await this.emitTaskEvent('error', task);\n        break;\n      }\n    }\n\n    // set all remaining tasks as cancelled\n    const cancelledTasks: ExecutionTask[] = [];\n    for (let i = taskIndex + 1; i < this.tasks.length; i++) {\n      this.tasks[i].status = 'cancelled';\n      cancelledTasks.push(this.tasks[i]);\n    }\n    if (cancelledTasks.length > 0) {\n      await this.emitSnapshotChange();\n      for (const cancelledTask of cancelledTasks) {\n        await this.emitTaskEvent('cancel', cancelledTask);\n      }\n    }\n\n    let finalizeError: TaskExecutionError | undefined;\n    if (!successfullyCompleted) {\n      this.status = 'error';\n      const errorTask = this.latestErrorTask();\n      const error = errorTask?.error ?? {\n        name: 'Error',\n        message: 'Task execution failed',\n      };\n      finalizeError = new TaskExecutionError(\n        error,\n        serializeErrorTask(errorTask),\n      );\n      await this.emitSnapshotChange(finalizeError);\n    } else {\n      this.status = 'completed';\n      await this.emitSnapshotChange();\n    }\n\n    if (finalizeError) {\n      throw finalizeError;\n    }\n\n    if (this.tasks.length) {\n      // return the last output\n      const outputIndex = Math.min(taskIndex, this.tasks.length - 1);\n      const { thought, output } = this.tasks[outputIndex];\n      return {\n        thought,\n        output,\n      };\n    }\n  }\n\n  isInErrorState(): boolean {\n    return this.status === 'error';\n  }\n\n  latestErrorTask(): ExecutionTask | null {\n    if (this.status !== 'error') {\n      return null;\n    }\n    // Find the LAST failed task (not the first one)\n    // This is important when using allowWhenError to continue after errors\n    for (let i = this.tasks.length - 1; i >= 0; i--) {\n      if (this.tasks[i].status === 'failed') {\n        return this.tasks[i];\n      }\n    }\n    return null;\n  }\n\n  dump(): ExecutionDump {\n    return new ExecutionDump(\n      {\n        id: this.id,\n        logTime: this.executionLogTime,\n        name: this.name,\n        tasks: this.tasks,\n      },\n      { referenceImageUrls: [...this.referenceImageUrls] },\n    );\n  }\n\n  async appendErrorPlan(errorMsg: string): Promise<{\n    output: undefined;\n    runner: TaskRunner;\n  }> {\n    const errorTask: ExecutionTaskActionApply<PlanningActionParamError> = {\n      type: 'Action Space',\n      subType: 'Error',\n      param: {\n        thought: errorMsg,\n      },\n      thought: errorMsg,\n      executor: async () => {\n        throw new Error(errorMsg || 'error without thought');\n      },\n    };\n    await this.appendAndFlush(errorTask);\n\n    return {\n      output: undefined,\n      runner: this,\n    };\n  }\n}\n\nexport class TaskExecutionError extends Error {\n  readonly code = 'TASK_EXECUTION_FAILED' as const;\n\n  override readonly cause: SerializedError;\n\n  readonly task?: SerializedErrorTask;\n\n  constructor(error: SerializedError, task?: SerializedErrorTask) {\n    super(error.message, { cause: error });\n    this.name = 'TaskExecutionError';\n    this.cause = error;\n    this.task = task;\n    if (this.stack) {\n      this.stack = truncateSerializedErrorString(this.stack);\n    }\n  }\n\n  /**\n   * Return the same bounded fields already stored on the live error. The\n   * wrapper stack identifies where TaskExecutionError was created; cause.stack\n   * preserves the executor's original stack.\n   */\n  toJSON(): SerializedTaskExecutionError {\n    return {\n      name: this.name,\n      code: this.code,\n      message: this.message,\n      ...(this.stack === undefined ? {} : { stack: this.stack }),\n      cause: this.cause,\n      ...(this.task === undefined ? {} : { task: this.task }),\n    };\n  }\n}\n"],"names":["debug","getDebug","UI_CONTEXT_CACHE_TTL_MS","serializeErrorTask","task","truncateSerializedErrorString","undefined","TaskRunner","error","kind","console","options","now","Date","shouldReuse","uiContext","screenshot","phase","recorderItem","uuid","errorMessage","assert","appended","Array","item","appendedTask","nextPendingIndex","taskIndex","successfullyCompleted","previousFindOutput","e","executor","returnValue","forceRefresh","setTimingFieldOnce","executorContext","isLastTask","Object","serializedError","serializeError","cancelledTasks","i","cancelledTask","finalizeError","errorTask","TaskExecutionError","outputIndex","Math","thought","output","ExecutionDump","errorMsg","Error","name","uiContextBuilder","Set","image"],"mappings":";;;;;;;;;;;;;;;AAuBA,MAAMA,QAAQC,SAAS;AACvB,MAAMC,0BAA0B;AAoChC,SAASC,mBACPC,IAA0B;IAE1B,IAAI,CAACA,MACH;IAGF,OAAO;QACL,QAAQC,8BAA8BD,KAAK,MAAM;QACjD,MAAMA,KAAK,IAAI;QACf,GAAIA,AAAiBE,WAAjBF,KAAK,OAAO,GACZ,CAAC,IACD;YAAE,SAASC,8BAA8BD,KAAK,OAAO;QAAE,CAAC;QAC5D,QAAQA,KAAK,MAAM;QACnB,GAAIA,AAAiBE,WAAjBF,KAAK,OAAO,GACZ,CAAC,IACD;YAAE,SAASC,8BAA8BD,KAAK,OAAO;QAAE,CAAC;QAC5D,GAAIA,AAAsBE,WAAtBF,KAAK,YAAY,GACjB,CAAC,IACD;YACE,cAAcC,8BAA8BD,KAAK,YAAY;QAC/D,CAAC;IACP;AACF;AA+BO,MAAMG;IA6CX,MAAc,mBAAmBC,KAA0B,EAAiB;QAC1E,IAAI,CAAC,IAAI,CAAC,gBAAgB,EACxB;QAEF,MAAM,IAAI,CAAC,gBAAgB,CAAC,IAAI,EAAEA;IACpC;IAEA,MAAc,cACZC,IAAyB,EACzBL,IAAmB,EACJ;QACf,IAAI,CAAC,IAAI,CAAC,WAAW,EACnB;QAEF,IAAI;YACF,MAAM,IAAI,CAAC,WAAW,CAAC;gBAAEK;gBAAML;gBAAM,QAAQ,IAAI;YAAC;QACpD,EAAE,OAAOI,OAAO;YACdE,QAAQ,KAAK,CAAC,iCAAiCF;QACjD;IACF;IAOA,MAAc,aAAaG,OAAoC,EAE7D;QACA,MAAMC,MAAMC,KAAK,GAAG;QACpB,MAAMC,cACJ,CAACH,SAAS,gBACV,IAAI,CAAC,aAAa,IAClBC,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,IAAIV;QAEzC,IAAIY,eAAe,IAAI,CAAC,aAAa,EAAE,SAAS;YAC9Cd,MACE,CAAC,gCAAgC,EAAEY,MAAM,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,MAAM,CAAC;YAEhF,OAAO,IAAI,CAAC,aAAa,EAAE;QAC7B;QAEA,IAAI;YACF,MAAMG,YAAY,MAAM,IAAI,CAAC,gBAAgB;YAC7C,IAAIA,WACF,IAAI,CAAC,aAAa,GAAG;gBACnB,SAASA;gBACT,YAAYF,KAAK,GAAG;YACtB;iBAEA,IAAI,CAAC,aAAa,GAAGP;YAEvB,OAAOS;QACT,EAAE,OAAOP,OAAO;YACd,IAAI,CAAC,aAAa,GAAGF;YACrB,MAAME;QACR;IACF;IAEA,MAAc,oBAAyD;QACrE,IAAI;YACF,MAAMO,YAAY,MAAM,IAAI,CAAC,YAAY,CAAC;gBAAE,cAAc;YAAK;YAC/D,OAAOA,WAAW;QACpB,EAAE,OAAOP,OAAO;YACdE,QAAQ,KAAK,CAAC,oCAAoCF;QACpD;IAEF;IAEQ,mBACNJ,IAAmB,EACnBY,UAAsC,EACtCC,KAAsB,EAChB;QACN,IAAI,CAACA,SAAS,CAACD,YACb;QAGF,MAAME,eAAsC;YAC1C,MAAM;YACN,IAAIL,KAAK,GAAG;YACZG;YACA,QAAQC;QACV;QAEA,IAAI,CAACb,KAAK,QAAQ,EAAE;YAClBA,KAAK,QAAQ,GAAG;gBAACc;aAAa;YAC9B;QACF;QACAd,KAAK,QAAQ,CAAC,IAAI,CAACc;IACrB;IAEQ,kBAAkBd,IAAwB,EAAiB;QACjE,OAAO;YACL,QAAQe;YACR,QAAQ;YACR,GAAGf,IAAI;QACT;IACF;IAEQ,yBACNO,OAAoC,EACpCS,YAAqB,EACf;QACN,IAAI,AAAgB,YAAhB,IAAI,CAAC,MAAM,EACb;QAEFC,OACEV,SAAS,gBACTS,gBACE,CAAC,qDAAqD,EAAE,IAAI,CAAC,eAAe,IAAI,aAAa,EAAE,EAAE,IAAI,CAAC,eAAe,IAAI,YAAY;QAGzI,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,YAAY;IACpD;IAEA,MAAM,OACJhB,IAA+C,EAC/CO,OAAoC,EACrB;QACf,IAAI,CAAC,wBAAwB,CAC3BA,SACA,CAAC,yDAAyD,EAAE,IAAI,CAAC,eAAe,IAAI,aAAa,EAAE,EAAE,IAAI,CAAC,eAAe,IAAI,YAAY;QAE3I,MAAMW,WAA4B,EAAE;QACpC,IAAIC,MAAM,OAAO,CAACnB,OAChBkB,SAAS,IAAI,IAAIlB,KAAK,GAAG,CAAC,CAACoB,OAAS,IAAI,CAAC,iBAAiB,CAACA;aAE3DF,SAAS,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAClB;QAEvC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAIkB;QACnB,IAAI,AAAgB,cAAhB,IAAI,CAAC,MAAM,EACb,IAAI,CAAC,MAAM,GAAG;QAEhB,MAAM,IAAI,CAAC,kBAAkB;QAC7B,KAAK,MAAMG,gBAAgBH,SACzB,MAAM,IAAI,CAAC,aAAa,CAAC,UAAUG;IAEvC;IAEA,MAAM,eACJrB,IAA+C,EAC/CO,OAAoC,EACoB;QACxD,MAAM,IAAI,CAAC,MAAM,CAACP,MAAMO;QACxB,OAAO,IAAI,CAAC,KAAK,CAACA;IACpB;IAEA,MAAM,MACJA,OAAoC,EACoB;QACxD,IAAI,AAAgB,WAAhB,IAAI,CAAC,MAAM,IAAe,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAChDD,QAAQ,IAAI,CACV;QAIJ,IAAI,CAAC,wBAAwB,CAACC,SAAS;QACvCU,OAAO,AAAgB,cAAhB,IAAI,CAAC,MAAM,EAAgB;QAClCA,OAAO,AAAgB,gBAAhB,IAAI,CAAC,MAAM,EAAkB;QAEpC,MAAMK,mBAAmB,IAAI,CAAC,KAAK,CAAC,SAAS,CAC3C,CAACtB,OAASA,AAAgB,cAAhBA,KAAK,MAAM;QAEvB,IAAIsB,mBAAmB,GAErB;QAGF,IAAI,CAAC,MAAM,GAAG;QACd,MAAM,IAAI,CAAC,kBAAkB;QAC7B,IAAIC,YAAYD;QAChB,IAAIE,wBAAwB;QAE5B,IAAIC;QAEJ,MAAOF,YAAY,IAAI,CAAC,KAAK,CAAC,MAAM,CAAE;YACpC,MAAMvB,OAAO,IAAI,CAAC,KAAK,CAACuB,UAAU;YAClCN,OACEjB,AAAgB,cAAhBA,KAAK,MAAM,EACX,CAAC,wCAAwC,EAAEA,KAAK,MAAM,EAAE;YAE1DA,KAAK,MAAM,GAAG;gBACZ,OAAOS,KAAK,GAAG;YACjB;YACA,IAAI;gBACFT,KAAK,MAAM,GAAG;gBACd,MAAM,IAAI,CAAC,kBAAkB;gBAC7B,MAAM,IAAI,CAAC,aAAa,CAAC,SAASA;gBAClC,IAAI;oBACF,IAAI,IAAI,CAAC,WAAW,EAClB,MAAM,IAAI,CAAC,WAAW,CAACA;gBAE3B,EAAE,OAAO0B,GAAG;oBACVpB,QAAQ,KAAK,CAAC,wBAAwBoB;gBACxC;gBACAT,OACE;oBAAC;oBAAW;oBAAgB;iBAAW,CAAC,OAAO,CAACjB,KAAK,IAAI,KAAK,GAC9D,CAAC,uBAAuB,EAAEA,KAAK,IAAI,EAAE;gBAGvC,MAAM,EAAE2B,QAAQ,EAAE,GAAG3B;gBACrBiB,OAAOU,UAAU,CAAC,oCAAoC,EAAE3B,KAAK,IAAI,EAAE;gBAEnE,IAAI4B;gBAGJ,MAAMC,eAAe7B,AAAc,cAAdA,KAAK,IAAI;gBAC9B8B,mBAAmB9B,KAAK,MAAM,EAAE;gBAChC,MAAMW,YAAY,MAAM,IAAI,CAAC,YAAY,CAAC;oBAAEkB;gBAAa;gBACzDC,mBAAmB9B,KAAK,MAAM,EAAE;gBAEhCA,KAAK,SAAS,GAAGW;gBACjB,MAAMoB,kBAAmC;oBACvC/B;oBACA,SAASyB,oBAAoB;oBAC7Bd;gBACF;gBAEA,IAAIX,AAAc,cAAdA,KAAK,IAAI,EAAgB;oBAC3BiB,OACEjB,AAAiB,YAAjBA,KAAK,OAAO,IACVA,AAAiB,aAAjBA,KAAK,OAAO,IACZA,AAAiB,cAAjBA,KAAK,OAAO,IACZA,AAAiB,cAAjBA,KAAK,OAAO,IACZA,AAAiB,aAAjBA,KAAK,OAAO,IACZA,AAAiB,aAAjBA,KAAK,OAAO,EACd,CAAC,6BAA6B,EAAEA,KAAK,OAAO,EAAE;oBAEhD4B,cAAc,MAAM5B,KAAK,QAAQ,CAAC+B;gBACpC,OAAO,IAAI/B,AAAc,eAAdA,KAAK,IAAI,EAAiB;oBACnC4B,cAAc,MAAM5B,KAAK,QAAQ,CAAC+B;oBAClC,IAAI/B,AAAiB,aAAjBA,KAAK,OAAO,EACdyB,qBACEG,aACC;gBAEP,OAAO,IAAI5B,AAAc,mBAAdA,KAAK,IAAI,EAClB,IAAI;oBACF4B,cAAc,MAAM5B,KAAK,QAAQ,CAAC+B;gBACpC,SAAU;oBAIR,IAAI,CAAC,aAAa,GAAG7B;gBACvB;qBACK;oBACLI,QAAQ,IAAI,CACV,CAAC,uBAAuB,EAAEN,KAAK,IAAI,CAAC,iCAAiC,CAAC;oBAExE4B,cAAc,MAAM5B,KAAK,QAAQ,CAAC+B;gBACpC;gBAEA,MAAMC,aAAaT,cAAc,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG;gBAErD,IAAIS,YAAY;oBACdF,mBAAmB9B,KAAK,MAAM,EAAE;oBAChC,MAAMY,aAAa,MAAM,IAAI,CAAC,iBAAiB;oBAC/C,IAAI,CAAC,kBAAkB,CAACZ,MAAMY,YAAY;oBAC1CkB,mBAAmB9B,KAAK,MAAM,EAAE;gBAClC;gBAEAiC,OAAO,MAAM,CAACjC,MAAM4B;gBACpB5B,KAAK,MAAM,GAAG;gBACdA,KAAK,MAAM,CAAC,GAAG,GAAGS,KAAK,GAAG;gBAC1BT,KAAK,MAAM,CAAC,IAAI,GAAGA,KAAK,MAAM,CAAC,GAAG,GAAGA,KAAK,MAAM,CAAC,KAAK;gBACtD,MAAM,IAAI,CAAC,kBAAkB;gBAC7B,MAAM,IAAI,CAAC,aAAa,CAAC,UAAUA;gBACnCuB;YACF,EAAE,OAAOnB,OAAO;gBACdoB,wBAAwB;gBACxB,MAAMU,kBAAkBC,eAAe/B;gBACvCJ,KAAK,KAAK,GAAGkC;gBACblC,KAAK,YAAY,GAAGkC,gBAAgB,OAAO;gBAC3ClC,KAAK,UAAU,GAAGkC,gBAAgB,KAAK;gBAEvClC,KAAK,MAAM,GAAG;gBACdA,KAAK,MAAM,CAAC,GAAG,GAAGS,KAAK,GAAG;gBAC1BT,KAAK,MAAM,CAAC,IAAI,GAAGA,KAAK,MAAM,CAAC,GAAG,GAAGA,KAAK,MAAM,CAAC,KAAK;gBACtD,MAAM,IAAI,CAAC,kBAAkB;gBAC7B,MAAM,IAAI,CAAC,aAAa,CAAC,SAASA;gBAClC;YACF;QACF;QAGA,MAAMoC,iBAAkC,EAAE;QAC1C,IAAK,IAAIC,IAAId,YAAY,GAAGc,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAEA,IAAK;YACtD,IAAI,CAAC,KAAK,CAACA,EAAE,CAAC,MAAM,GAAG;YACvBD,eAAe,IAAI,CAAC,IAAI,CAAC,KAAK,CAACC,EAAE;QACnC;QACA,IAAID,eAAe,MAAM,GAAG,GAAG;YAC7B,MAAM,IAAI,CAAC,kBAAkB;YAC7B,KAAK,MAAME,iBAAiBF,eAC1B,MAAM,IAAI,CAAC,aAAa,CAAC,UAAUE;QAEvC;QAEA,IAAIC;QACJ,IAAKf,uBAYE;YACL,IAAI,CAAC,MAAM,GAAG;YACd,MAAM,IAAI,CAAC,kBAAkB;QAC/B,OAf4B;YAC1B,IAAI,CAAC,MAAM,GAAG;YACd,MAAMgB,YAAY,IAAI,CAAC,eAAe;YACtC,MAAMpC,QAAQoC,WAAW,SAAS;gBAChC,MAAM;gBACN,SAAS;YACX;YACAD,gBAAgB,IAAIE,mBAClBrC,OACAL,mBAAmByC;YAErB,MAAM,IAAI,CAAC,kBAAkB,CAACD;QAChC;QAKA,IAAIA,eACF,MAAMA;QAGR,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAErB,MAAMG,cAAcC,KAAK,GAAG,CAACpB,WAAW,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG;YAC5D,MAAM,EAAEqB,OAAO,EAAEC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAACH,YAAY;YACnD,OAAO;gBACLE;gBACAC;YACF;QACF;IACF;IAEA,iBAA0B;QACxB,OAAO,AAAgB,YAAhB,IAAI,CAAC,MAAM;IACpB;IAEA,kBAAwC;QACtC,IAAI,AAAgB,YAAhB,IAAI,CAAC,MAAM,EACb,OAAO;QAIT,IAAK,IAAIR,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,GAAGA,KAAK,GAAGA,IAC1C,IAAI,AAAyB,aAAzB,IAAI,CAAC,KAAK,CAACA,EAAE,CAAC,MAAM,EACtB,OAAO,IAAI,CAAC,KAAK,CAACA,EAAE;QAGxB,OAAO;IACT;IAEA,OAAsB;QACpB,OAAO,IAAIS,cACT;YACE,IAAI,IAAI,CAAC,EAAE;YACX,SAAS,IAAI,CAAC,gBAAgB;YAC9B,MAAM,IAAI,CAAC,IAAI;YACf,OAAO,IAAI,CAAC,KAAK;QACnB,GACA;YAAE,oBAAoB;mBAAI,IAAI,CAAC,kBAAkB;aAAC;QAAC;IAEvD;IAEA,MAAM,gBAAgBC,QAAgB,EAGnC;QACD,MAAMP,YAAgE;YACpE,MAAM;YACN,SAAS;YACT,OAAO;gBACL,SAASO;YACX;YACA,SAASA;YACT,UAAU;gBACR,MAAM,IAAIC,MAAMD,YAAY;YAC9B;QACF;QACA,MAAM,IAAI,CAAC,cAAc,CAACP;QAE1B,OAAO;YACL,QAAQtC;YACR,QAAQ,IAAI;QACd;IACF;IApZA,YACE+C,IAAY,EACZC,gBAA0C,EAC1C3C,OAA+B,CAC/B;QA1BF,uBAAS,MAAT;QACA;QAEA;QAGA;QAEA;QAEA,uBAAiB,oBAAjB;QAEA,uBAAiB,oBAAjB;QAIA,uBAAiB,eAAjB;QAEA,uBAAiB,oBAAjB;QAEA,uBAAiB,sBAAqB,IAAI4C;QA6C1C,uBAAQ,iBAAR;QAtCE,IAAI,CAAC,EAAE,GAAGpC;QACV,IAAI,CAAC,MAAM,GACTR,SAAS,SAASA,QAAQ,KAAK,CAAC,MAAM,GAAG,IAAI,YAAY;QAC3D,IAAI,CAAC,IAAI,GAAG0C;QACZ,IAAI,CAAC,KAAK,GAAI1C,AAAAA,CAAAA,SAAS,SAAS,EAAC,EAAG,GAAG,CAAC,CAACa,OACvC,IAAI,CAAC,iBAAiB,CAACA;QAEzB,IAAI,CAAC,WAAW,GAAGb,SAAS;QAC5B,IAAI,CAAC,gBAAgB,GAAG2C;QACxB,IAAI,CAAC,gBAAgB,GAAG3C,SAAS;QACjC,IAAI,CAAC,WAAW,GAAGA,SAAS;QAC5B,IAAI,CAAC,gBAAgB,GAAGE,KAAK,GAAG;QAChC,KAAK,MAAM2C,SAAS7C,SAAS,mBAAmB,EAAE,CAChD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC6C,MAAM,GAAG;IAEzC;AAiYF;AAEO,MAAMX,2BAA2BO;IAsBtC,SAAuC;QACrC,OAAO;YACL,MAAM,IAAI,CAAC,IAAI;YACf,MAAM,IAAI,CAAC,IAAI;YACf,SAAS,IAAI,CAAC,OAAO;YACrB,GAAI,AAAe9C,WAAf,IAAI,CAAC,KAAK,GAAiB,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAC,KAAK;YAAC,CAAC;YACzD,OAAO,IAAI,CAAC,KAAK;YACjB,GAAI,AAAcA,WAAd,IAAI,CAAC,IAAI,GAAiB,CAAC,IAAI;gBAAE,MAAM,IAAI,CAAC,IAAI;YAAC,CAAC;QACxD;IACF;IAxBA,YAAYE,KAAsB,EAAEJ,IAA0B,CAAE;QAC9D,KAAK,CAACI,MAAM,OAAO,EAAE;YAAE,OAAOA;QAAM,IAPtC,uBAAS,QAAO,0BAEhB,uBAAkB,SAAlB,SAEA,uBAAS,QAAT;QAIE,IAAI,CAAC,IAAI,GAAG;QACZ,IAAI,CAAC,KAAK,GAAGA;QACb,IAAI,CAAC,IAAI,GAAGJ;QACZ,IAAI,IAAI,CAAC,KAAK,EACZ,IAAI,CAAC,KAAK,GAAGC,8BAA8B,IAAI,CAAC,KAAK;IAEzD;AAiBF"}