{"version":3,"file":"index.umd.cjs","sources":["../src/constants.ts","../src/errors.ts","../src/emitter.ts","../src/sdk.ts","../src/utils.ts","../src/HikPlayer.ts"],"sourcesContent":["/**\n * 与 SDK 一一对应的常量集合。所有常量均使用 `as const` 以派生字面量联合类型。\n * 取值来源：`WebSDK3.4_无插件开发包编程指南`。\n */\n\n// ─────────────────────────── 协议与端口 ───────────────────────────\n\n/** SDK 内部协议数值；与字符串形态的互转见 `toProtocolValue`。 */\nexport const PROTOCOL = {\n  HTTP: 1,\n  HTTPS: 2,\n} as const\n\nexport const DEFAULT_PORT = {\n  HTTP: 80,\n  HTTPS: 443,\n  RTSP: 554,\n} as const\n\n// ─────────────────────────── 码流与窗口 ───────────────────────────\n\n/** 码流类型，传给 `I_StartRealPlay` / `I_StartPlayback` / `I_RecordSearch`。 */\nexport const STREAM_TYPE = {\n  Main: 1,\n  Sub: 2,\n  Third: 3,\n} as const\n\n/**\n * 分屏布局，传给 `I_InitPlugin.iWndowType` 与 `I_ChangeWndNum`。\n *\n * 取值非平方关系：`1/2/3/4` 直接对应 `1x1 / 2x2 / 3x3 / 4x4`，超过 4 按 4x4 处理。\n */\nexport const LAYOUT = {\n  Single: 1,\n  Quad: 2,\n  Nine: 3,\n  Sixteen: 4,\n} as const\n\n/** `I_GetWindowStatus().iPlayStatus` / `I_GetWndSet()` 元素的播放状态。 */\nexport const PLAY_STATUS = {\n  Idle: 0,\n  Preview: 1,\n  Playback: 2,\n  Paused: 3,\n  SingleFrame: 4,\n  Reverse: 5,\n  ReversePaused: 6,\n} as const\n\n// ─────────────────────────── PTZ ───────────────────────────\n\n/**\n * PTZ 控制类型，对应 `I_PTZControl` 的 `iPTZIndex`。\n *\n * 海康文档原文：`5-左上，6-左下，7-右上，8-右下`，注意命名顺序与直觉相反。\n */\nexport const PTZ_COMMAND = {\n  Up: 1,\n  Down: 2,\n  Left: 3,\n  Right: 4,\n  UpLeft: 5,\n  DownLeft: 6,\n  UpRight: 7,\n  DownRight: 8,\n  /** 自动巡航开关 */\n  AutoPan: 9,\n  ZoomIn: 10,\n  ZoomOut: 11,\n  FocusFar: 12,\n  FocusNear: 13,\n  IrisOpen: 14,\n  IrisClose: 15,\n} as const\n\n/** PTZ 速度合法区间，超出抛出 `INVALID_ARGUMENT`。 */\nexport const PTZ_SPEED_RANGE = { min: 1, max: 7, default: 4 } as const\n\n// ─────────────────────────── 录像 / 抓拍 ───────────────────────────\n\n/** `I_RecordSearch` 单次返回上限；分页按此步长递增 `iSearchPos`。 */\nexport const RECORD_SEARCH_PAGE_SIZE = 40\n\n/** `I2_OpenFileDlg` 对话框类型（`0` 文件夹，`1` 文件）。 */\nexport const FILE_DIALOG = {\n  Directory: 0,\n  File: 1,\n} as const\n\n/**\n * `I_RestoreDefault` 的 `szMode` 取值。\n * - `basic`：保留用户与网络等基础配置\n * - `full`：完全恢复，包括所有用户信息\n */\nexport const RESTORE_MODE = {\n  Basic: 'basic',\n  Full: 'full',\n} as const\n\n// ─────────────────────────── 转码回放 ───────────────────────────\n\n/** 转码回放 `TransFrameRate` 档位。 */\nexport const TRANSCODE_FRAME_RATE = {\n  All: '0',\n  Fps1: '5',\n  Fps2: '6',\n  Fps4: '7',\n  Fps6: '8',\n  Fps8: '9',\n  Fps10: '10',\n  Fps12: '11',\n  Fps16: '12',\n  Fps20: '13',\n  Fps15: '14',\n  Fps18: '15',\n  Fps22: '16',\n  Auto: '255',\n} as const\n\n/** 转码回放 `TransResolution` 档位。 */\nexport const TRANSCODE_RESOLUTION = {\n  CIF: '1',\n  QCIF: '2',\n  /** 4CIF / D1 */\n  D1: '3',\n  Auto: '255',\n} as const\n\n/** 转码回放 `TransBitrate` 档位。 */\nexport const TRANSCODE_BITRATE = {\n  K32: '2',\n  K48: '3',\n  K64: '4',\n  K80: '5',\n  K96: '6',\n  K128: '7',\n  K160: '8',\n  K192: '9',\n  K224: '10',\n  K256: '11',\n  K320: '12',\n  K384: '13',\n  K448: '14',\n  K512: '15',\n  K640: '16',\n  K768: '17',\n  K896: '18',\n  K1024: '19',\n  K1280: '20',\n  K1536: '21',\n  K1792: '22',\n  K2048: '23',\n  K3072: '24',\n  K4096: '25',\n  K8192: '26',\n  Auto: '255',\n} as const\n\n// ─────────────────────────── 事件 / 错误码 ───────────────────────────\n\n/** 插件 `cbEvent` 的事件类型（第一个参数）。 */\nexport const PLUGIN_EVENT = {\n  /** 回放异常 / 取流被动断开 */\n  PlayAbnormal: 0,\n  /** 回放正常结束 */\n  PlaybackEnd: 2,\n  /** 对讲失败 */\n  AudioTalkFail: 3,\n  /** 硬盘空间不足 */\n  NoFreeSpace: 21,\n} as const\n\n/** 设备/插件运行时错误码与中文描述（来源：`cbPluginErrorHandler` 与流回调 `iErrorCode`）。 */\nexport const SDK_RUNTIME_ERROR = Object.freeze({\n  1001: '码流传输过程异常',\n  1002: '回放结束',\n  1003: '取流失败，连接被动断开',\n  1004: '对讲连接被动断开',\n  1005: '广播连接被动断开',\n  1006: '视频编码格式不支持，目前只支持 H.264 / H.265',\n  1007: '网络异常导致 WebSocket 断开',\n  1008: '首帧回调超时',\n  1009: '对讲码流传输过程异常',\n  1010: '广播码流传输过程异常',\n  1011: '数据接收异常，请检查是否修改了视频格式',\n  1012: '播放资源不足',\n  1013: '当前环境不支持该鱼眼展开模式',\n  1014: '外部强制关闭',\n  1015: '获取播放 URL 失败',\n  1016: '文件下载完成',\n  1017: '密码错误',\n  1018: '链接到萤石平台失败',\n  1019: '未找到录像片段',\n  1020: '水印模式等场景，当前通道需要重新播放',\n  1021: '缓存溢出',\n  1022: '采集音频失败：非 https/localhost 域名或未插耳机等',\n})\n\n// ─────────────────────────── 字面量类型 ───────────────────────────\n\n/** 面向用户的协议字符串形态。 */\nexport type ProtocolScheme = 'http' | 'https'\n\nexport type Protocol = typeof PROTOCOL[keyof typeof PROTOCOL]\nexport type StreamType = typeof STREAM_TYPE[keyof typeof STREAM_TYPE]\nexport type Layout = typeof LAYOUT[keyof typeof LAYOUT]\nexport type PlayStatus = typeof PLAY_STATUS[keyof typeof PLAY_STATUS]\nexport type PtzCommand = typeof PTZ_COMMAND[keyof typeof PTZ_COMMAND]\nexport type FileDialogType = typeof FILE_DIALOG[keyof typeof FILE_DIALOG]\nexport type RestoreMode = typeof RESTORE_MODE[keyof typeof RESTORE_MODE]\nexport type PluginEventCode = typeof PLUGIN_EVENT[keyof typeof PLUGIN_EVENT]\nexport type TranscodeFrameRate = typeof TRANSCODE_FRAME_RATE[keyof typeof TRANSCODE_FRAME_RATE]\nexport type TranscodeResolution = typeof TRANSCODE_RESOLUTION[keyof typeof TRANSCODE_RESOLUTION]\nexport type TranscodeBitrate = typeof TRANSCODE_BITRATE[keyof typeof TRANSCODE_BITRATE]\nexport type SdkRuntimeError = keyof typeof SDK_RUNTIME_ERROR\n","/**\n * 错误码枚举，用于 `switch` 分支判断与日志聚合。\n *\n * - `SDK_NOT_FOUND`         未检测到 `window.WebVideoCtrl`（多半 `webVideoCtrl.js` 未加载）\n * - `SDK_METHOD_MISSING`    SDK 目标方法不存在（常见于版本不匹配）\n * - `SDK_CALL_FAILED`       SDK 回调 `error` 或抛异常；详情见 `details.status / responseXml`\n * - `NOT_INITIALIZED`       未调用 `init()` 就操作播放器\n * - `ALREADY_INITIALIZED`   已初始化的播放器被重复初始化\n * - `INITIALIZATION_TIMEOUT` 底层播放组件未在指定时间内完成初始化\n * - `INVALID_ARGUMENT`      参数校验失败（如端口越界、时间区间反转）\n * - `DEVICE_NOT_FOUND`      未登录或已登出的设备被引用\n * - `WINDOW_NOT_PLAYING`    对未播放窗口执行 `stop / pause`\n * - `SCRIPT_LOAD_FAILED`    `loadWebVideoCtrl()` 加载脚本失败或超时\n */\nexport type HikErrorCode\n  = | 'SDK_NOT_FOUND'\n    | 'SDK_METHOD_MISSING'\n    | 'SDK_CALL_FAILED'\n    | 'NOT_INITIALIZED'\n    | 'ALREADY_INITIALIZED'\n    | 'INITIALIZATION_TIMEOUT'\n    | 'INVALID_ARGUMENT'\n    | 'DEVICE_NOT_FOUND'\n    | 'WINDOW_NOT_PLAYING'\n    | 'SCRIPT_LOAD_FAILED'\n\n/** 错误附带的调试信息，所有字段均可选。 */\nexport interface HikErrorDetails {\n  /** 触发错误的 SDK 方法名 */\n  method?: string\n  /** HTTP 状态码（来自 SDK `error(status, xmlDoc)` 回调） */\n  status?: number\n  /** 设备返回的 XML 文本（已序列化） */\n  responseXml?: string\n  /** SDK 同步返回值（如 `I_Logout` 返回 -1） */\n  returnValue?: unknown\n  [key: string]: unknown\n}\n\n/**\n * 海康封装库统一错误类型。\n *\n * 优先用 `code` 做分支判断，避免依赖 `message` 文案；原始错误经由 `cause` 透传（ES2022）。\n */\nexport class HikError extends Error {\n  override readonly name = 'HikError'\n  readonly code: HikErrorCode\n  readonly details?: HikErrorDetails\n\n  constructor(\n    code: HikErrorCode,\n    message: string,\n    details?: HikErrorDetails,\n    cause?: unknown,\n  ) {\n    super(message, cause === undefined ? undefined : { cause })\n    this.code = code\n    this.details = details\n    // 修复跨编译目标的原型链，保证 `instanceof HikError` 始终成立\n    Object.setPrototypeOf(this, new.target.prototype)\n  }\n}\n\n/** 将任意值收敛为 `HikError`，便于在 `catch` 中统一重抛。 */\nexport function toHikError(\n  error: unknown,\n  fallbackCode: HikErrorCode = 'SDK_CALL_FAILED',\n  fallbackMessage: string = '调用 SDK 失败',\n): HikError {\n  if (error instanceof HikError)\n    return error\n  const message = error instanceof Error ? error.message : fallbackMessage\n  return new HikError(fallbackCode, message, undefined, error)\n}\n","/**\n * 极简类型化事件总线，仅支持\"具名事件 → 单一负载\"语义。\n * 监听器异常仅记录到 console，不阻塞其它监听器。\n */\n\nexport type EventHandler<P> = (payload: P) => void\n\nexport class TypedEmitter<EventMap extends Record<string, any>> {\n  private readonly listeners = new Map<keyof EventMap, Set<EventHandler<unknown>>>()\n\n  /** 订阅事件，返回取消订阅函数。 */\n  on<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): () => void {\n    const bag = this.listeners.get(event) ?? new Set<EventHandler<unknown>>()\n    bag.add(handler as EventHandler<unknown>)\n    this.listeners.set(event, bag)\n    return () => this.off(event, handler)\n  }\n\n  /** 仅触发一次，触发后自动解除订阅。 */\n  once<K extends keyof EventMap>(event: K, handler: EventHandler<EventMap[K]>): () => void {\n    const wrapper: EventHandler<EventMap[K]> = (payload) => {\n      this.off(event, wrapper)\n      handler(payload)\n    }\n    return this.on(event, wrapper)\n  }\n\n  /** 取消订阅；不传 handler 则清空该事件全部监听。 */\n  off<K extends keyof EventMap>(event: K, handler?: EventHandler<EventMap[K]>): void {\n    const bag = this.listeners.get(event)\n    if (!bag)\n      return\n    if (!handler) {\n      this.listeners.delete(event)\n      return\n    }\n    bag.delete(handler as EventHandler<unknown>)\n    if (bag.size === 0)\n      this.listeners.delete(event)\n  }\n\n  /** 派发事件到所有监听器。 */\n  emit<K extends keyof EventMap>(event: K, payload: EventMap[K]): void {\n    const bag = this.listeners.get(event)\n    if (!bag?.size)\n      return\n    // 拷贝迭代，允许监听器在回调中安全地 off 自己或新增订阅\n    for (const handler of [...bag]) {\n      try {\n        handler(payload)\n      }\n      catch (err) {\n        console.error(`[hikvideoctrl] 事件 ${String(event)} 监听器抛出异常`, err)\n      }\n    }\n  }\n\n  /** 清空全部监听器。 */\n  clear(): void {\n    this.listeners.clear()\n  }\n}\n","import { HikError } from './errors'\n\n/**\n * 海康 `window.WebVideoCtrl` 的最小可用类型。\n *\n * 仅声明本封装实际调用的方法；其余接口仍可通过索引签名访问。\n * 命名沿用 SDK 原始 `I_*` / `I2_*` 风格以对照官方文档。\n */\nexport interface WebVideoCtrlSDK {\n  /** 浏览器是否支持无插件模式（Chromium 内核 ≥ 91）。 */\n  I_SupportNoPlugin: () => boolean\n\n  /** 初始化插件；无插件模式下 `bNoPlugin / bWndFull / iPlayMode` 由封装层固化。 */\n  I_InitPlugin: (\n    width: number | string,\n    height: number | string,\n    options: SdkInitOptions,\n  ) => void\n\n  /** 将插件挂载到指定 DOM 容器；`0` 成功，`-1` 失败。 */\n  I_InsertOBJECTPlugin: (containerId: string) => number\n\n  /** 释放底层 Worker / WebSocket 资源。 */\n  I_DestroyWorker?: () => void\n\n  /** 调整插件渲染尺寸（像素）。 */\n  I_Resize?: (width: number, height: number) => void\n\n  /** 切换分屏布局。 */\n  I_ChangeWndNum: (layout: number) => Promise<void>\n\n  /** 查询窗口状态；未播放或越界返回 null。 */\n  I_GetWindowStatus: {\n    (): SdkWindowInfo[]\n    (windowIndex: number): SdkWindowInfo | null\n  }\n\n  /** 获取全部窗口集合。 */\n  I_GetWndSet: () => SdkWindowInfo[]\n\n  // ─── 设备 ───\n  I_Login: (\n    host: string,\n    protocol: 1 | 2,\n    port: number,\n    username: string,\n    password: string,\n    options: SdkAjaxOptions,\n  ) => number | void\n  I_Logout: (deviceIdentify: string) => number\n  I_GetDeviceInfo: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_GetDevicePort: (deviceIdentify: string) => SdkDevicePort | null\n  I_GetAnalogChannelInfo: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_GetDigitalChannelInfo: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_GetZeroChannelInfo: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_GetAudioInfo: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_GetSecurityVersion: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_RecordSearch: (\n    deviceIdentify: string,\n    channelId: number,\n    startTime: string,\n    endTime: string,\n    options: SdkAjaxOptions & { iStreamType?: number, iSearchPos?: number },\n  ) => void\n\n  // ─── 播放 / 控制 ───\n  I_StartRealPlay: (deviceIdentify: string, options: SdkAjaxOptions & Record<string, unknown>) => void\n  I_StartPlayback: (deviceIdentify: string, options: SdkAjaxOptions & Record<string, unknown>) => void\n  I_Stop: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_StopAll: () => Promise<void>\n  I_Pause: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_Resume: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_PlayFast: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_PlaySlow: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_GetOSDTime: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_OpenSound: (windowIndex?: number) => Promise<void>\n  I_CloseSound: (windowIndex?: number) => Promise<void>\n  I_SetVolume: (volume: number, windowIndex?: number) => Promise<void>\n  I_SetSecretKey: (secretKey: string, windowIndex?: number) => Promise<void> | number\n  I_FullScreen: (enable: boolean) => Promise<void>\n  I_EnableEZoom: (windowIndex?: number) => Promise<unknown>\n  I_DisableEZoom: (windowIndex?: number) => Promise<unknown>\n  I_Enable3DZoom: (windowIndex?: number, callback?: (info: unknown) => void) => Promise<unknown>\n  I_Disable3DZoom: (windowIndex?: number) => number\n\n  // ─── 抓拍 / 录像 ───\n  I2_CapturePic: (\n    fileName: string,\n    options: { iWndIndex?: number, cbCallback?: (data: Uint8Array) => void },\n  ) => PromiseLike<unknown> | number\n  I_DeviceCapturePic: (\n    deviceIdentify: string,\n    channelId: number,\n    fileName: string,\n    options: {\n      bDateDir?: boolean\n      iResolutionWidth?: number\n      iResolutionHeight?: number\n    },\n  ) => number\n  I_StartRecord: (\n    fileName: string,\n    options: SdkAjaxOptions & { iWndIndex?: number, bDateDir?: boolean },\n  ) => void\n  I_StopRecord: (options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_StartDownloadRecord: (\n    deviceIdentify: string,\n    playbackUri: string,\n    fileName: string,\n    options: { bDateDir?: boolean },\n  ) => Promise<unknown>\n  I_StartDownloadRecordByTime: (\n    deviceIdentify: string,\n    playbackUri: string,\n    fileName: string,\n    startTime: string,\n    endTime: string,\n    options: { bDateDir?: boolean },\n  ) => Promise<unknown>\n\n  // ─── PTZ ───\n  I_PTZControl: (\n    action: number,\n    stop: boolean,\n    options: SdkAjaxOptions & { iWndIndex?: number, iPTZSpeed?: number },\n  ) => void\n  I_SetPreset: (presetId: number, options: SdkAjaxOptions & { iWndIndex?: number }) => void\n  I_GoPreset: (presetId: number, options: SdkAjaxOptions & { iWndIndex?: number }) => void\n\n  // ─── 维护 ───\n  I_ExportDeviceConfig: (deviceIdentify: string, password: string) => Promise<unknown>\n  I_ImportDeviceConfig: (\n    deviceIdentify: string,\n    fileName: string,\n    password?: string,\n    file?: File,\n  ) => Promise<unknown>\n  I_RestoreDefault: (\n    deviceIdentify: string,\n    mode: 'basic' | 'full',\n    options: SdkAjaxOptions,\n  ) => void\n  I_Restart: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I_Reconnect: (deviceIdentify: string, options: SdkAjaxOptions) => void\n  I2_StartUpgrade: (deviceIdentify: string, fileName: string, file?: File) => Promise<unknown>\n  I_UpgradeProgress: (deviceIdentify: string) => Promise<{ percent: number, upgrading: boolean }>\n\n  /** 无插件模式固定返回 `0`；保留用于与官方 SDK 完整对照。 */\n  I_CheckPluginVersion: () => number\n\n  // ─── 透传 ───\n  I_SendHTTPRequest: (\n    deviceIdentify: string,\n    uri: string,\n    options: SdkAjaxOptions & SdkHttpOptions,\n  ) => void\n  I_GetTextOverlay: (\n    uri: string,\n    deviceIdentify: string,\n    options: SdkAjaxOptions,\n  ) => void\n  I2_OpenFileDlg: (type: 0 | 1) => Promise<{ szFileName: string | -1, file: File | null }>\n\n  /** 未列出的 `I_*` 方法仍可通过索引签名调用。 */\n  [method: string]: unknown\n}\n\n/** `I_InitPlugin` 透传参数。 */\nexport interface SdkInitOptions {\n  iWndowType?: number\n  bWndFull?: boolean\n  bNoPlugin?: boolean\n  iPlayMode?: number\n  szColorProperty?: string\n  bDebugMode?: boolean\n  cbSelWnd?: (xmlDoc: Document) => void\n  cbDoubleClickWnd?: (windowIndex: number, fullScreen: boolean) => void\n  cbEvent?: (eventType: number, windowIndex: number, param2: number) => void\n  cbInitPluginComplete?: () => void\n  cbPluginErrorHandler?: (windowIndex: number, errorCode: number, error: unknown) => void\n  cbPerformanceLack?: () => void\n  cbSecretKeyError?: (windowIndex: number) => void\n  [key: string]: unknown\n}\n\n/** SDK 风格的 success / error 回调容器，所有 options 形式的 API 共享此形态。 */\nexport interface SdkAjaxOptions {\n  async?: boolean\n  /** data 可能是 Document、string、jqXHR-like 或 SDK 自定义对象。 */\n  success?: (data: unknown) => void\n  /** 首个参数为 HTTP 状态码，第二个为设备 XML（若可获取）。 */\n  error?: (status?: number, xmlDoc?: Document | null, nativeError?: unknown) => void\n  [key: string]: unknown\n}\n\n/** `I_SendHTTPRequest` 扩展字段。 */\nexport interface SdkHttpOptions {\n  type?: 'GET' | 'POST' | 'PUT' | 'DELETE'\n  data?: string\n  /** `true` 携带已登录设备认证；字符串则直接透传。 */\n  auth?: boolean | string\n}\n\n/** `I_GetWindowStatus` / `I_GetWndSet` 返回的窗口信息。 */\nexport interface SdkWindowInfo {\n  iIndex: number\n  szIP: string\n  szDeviceIdentify?: string\n  iChannelID: number\n  iPlayStatus: number\n  [key: string]: unknown\n}\n\n/** `I_GetDevicePort` 返回的端口信息。 */\nexport interface SdkDevicePort {\n  iDevicePort: number\n  iRtspPort: number\n  iHttpPort?: number\n  iWebSocketPort?: number\n  iWebSocketsPort?: number\n  [key: string]: unknown\n}\n\n// ─────────────────────────── 调用桥接 ───────────────────────────\n\n/** 同步调用：直接转发 SDK 方法返回值（用于 `I_GetWindowStatus` 等立即返回的 API）。 */\nexport function callSync<T>(sdk: WebVideoCtrlSDK, method: string, ...args: unknown[]): T {\n  const fn = resolveMethod(sdk, method)\n  try {\n    return fn.apply(sdk, args) as T\n  }\n  catch (error) {\n    throw new HikError('SDK_CALL_FAILED', `调用 ${method} 失败`, { method }, error)\n  }\n}\n\n/**\n * Promise 风格调用：SDK 方法本身返回 Promise / thenable。\n * 同步异常、Promise reject 与同步返回 `-1` 均收敛为 `HikError`；其它非 thenable 直接 resolve。\n */\nexport function callPromise<T>(sdk: WebVideoCtrlSDK, method: string, ...args: unknown[]): Promise<T> {\n  const fn = resolveMethod(sdk, method)\n  let raw: unknown\n  try {\n    raw = fn.apply(sdk, args)\n  }\n  catch (error) {\n    return Promise.reject(new HikError('SDK_CALL_FAILED', `调用 ${method} 失败`, { method }, error))\n  }\n  if (raw === -1) {\n    return Promise.reject(new HikError('SDK_CALL_FAILED', `${method} 同步返回 -1`, {\n      method,\n      returnValue: raw,\n    }))\n  }\n  if (!isThenable(raw))\n    return Promise.resolve(raw as T)\n  return Promise.resolve(raw).then(\n    value => value as T,\n    (cause) => {\n      throw new HikError('SDK_CALL_FAILED', `调用 ${method} 失败`, { method }, cause)\n    },\n  )\n}\n\n/**\n * 回调式调用：SDK 方法通过 `options.success / options.error` 通知结果。\n *\n * - callback 挂载到 `args` 中最后一个 plain object 上，缺失时自动追加。\n * - 用户预先填的 `success / error` 仍会被调用，但其异常不会污染 Promise 状态。\n * - SDK 同步返回 `-1` 视为立即失败，避免 Promise 永久 pending。\n */\nexport function callWithCallback<T>(\n  sdk: WebVideoCtrlSDK,\n  method: string,\n  ...args: unknown[]\n): Promise<T> {\n  const fn = resolveMethod(sdk, method)\n\n  return new Promise<T>((resolve, reject) => {\n    let settled = false\n    const finishOk = (data: T) => {\n      if (settled)\n        return\n      settled = true\n      resolve(data)\n    }\n    const finishErr = (err: HikError) => {\n      if (settled)\n        return\n      settled = true\n      reject(err)\n    }\n\n    let bag: Record<string, unknown> | null = null\n    for (let i = args.length - 1; i >= 0; i -= 1) {\n      if (isPlainObject(args[i])) {\n        bag = args[i] as Record<string, unknown>\n        break\n      }\n    }\n    if (!bag) {\n      bag = {}\n      args.push(bag)\n    }\n\n    const userSuccess = bag.success as ((data: unknown) => void) | undefined\n    const userError = bag.error as\n      | ((status?: number, xml?: Document | null, native?: unknown) => void)\n      | undefined\n\n    bag.success = (data: unknown) => {\n      try {\n        userSuccess?.(data)\n      }\n      catch (err) {\n        console.error(`[hikvideoctrl] ${method} success 用户回调异常`, err)\n      }\n      finishOk(data as T)\n    }\n\n    bag.error = (status?: number, xmlDoc?: Document | null, native?: unknown) => {\n      try {\n        userError?.(status, xmlDoc, native)\n      }\n      catch (err) {\n        console.error(`[hikvideoctrl] ${method} error 用户回调异常`, err)\n      }\n      finishErr(buildCallbackError(method, status, xmlDoc, native))\n    }\n\n    try {\n      const ret = fn.apply(sdk, args)\n      if (!settled && typeof ret === 'number' && ret === -1) {\n        finishErr(new HikError('SDK_CALL_FAILED', `${method} 同步返回 -1`, {\n          method,\n          returnValue: ret,\n        }))\n      }\n    }\n    catch (error) {\n      finishErr(new HikError('SDK_CALL_FAILED', `调用 ${method} 失败`, { method }, error))\n    }\n  })\n}\n\n// ─────────────────────────── 加载器 ───────────────────────────\n\nexport interface LoadWebVideoCtrlOptions {\n  /** 等待 `window.WebVideoCtrl` 出现的超时时间（毫秒），默认 15000。 */\n  timeout?: number\n  /**\n   * 同源脚本处理策略。\n   * - `'reuse'`（默认）：相同 src 已加载则等待其完成\n   * - `'fresh'`：每次插入新 script 节点\n   */\n  strategy?: 'reuse' | 'fresh'\n}\n\n/**\n * 异步加载 `webVideoCtrl.js`，返回 SDK 实例。\n *\n * 已存在 `window.WebVideoCtrl` 时直接复用；否则注入 `<script>` 并等待就绪。\n *\n * 注：SDK 依赖同目录下的 `jsPlugin/`、`encryption/` 等子资源（相对路径请求），\n * 调用者需保证 `scriptUrl` 同级可访问。\n */\nexport function loadWebVideoCtrl(\n  scriptUrl: string,\n  options: LoadWebVideoCtrlOptions = {},\n): Promise<WebVideoCtrlSDK> {\n  if (typeof window === 'undefined') {\n    return Promise.reject(\n      new HikError('SCRIPT_LOAD_FAILED', 'loadWebVideoCtrl 仅可在浏览器环境中调用'),\n    )\n  }\n\n  const existing = (window as { WebVideoCtrl?: WebVideoCtrlSDK }).WebVideoCtrl\n  if (existing)\n    return Promise.resolve(existing)\n\n  const timeout = options.timeout ?? 15_000\n  const strategy = options.strategy ?? 'reuse'\n  if (!Number.isFinite(timeout) || timeout <= 0) {\n    return Promise.reject(\n      new HikError('INVALID_ARGUMENT', '脚本加载超时时间必须为正数', { timeout }),\n    )\n  }\n\n  return new Promise<WebVideoCtrlSDK>((resolve, reject) => {\n    const cleanupTimer = window.setTimeout(() => {\n      reject(new HikError('SCRIPT_LOAD_FAILED', `加载 ${scriptUrl} 超时（${timeout}ms）`))\n    }, timeout)\n\n    const onReady = () => {\n      window.clearTimeout(cleanupTimer)\n      const sdk = (window as { WebVideoCtrl?: WebVideoCtrlSDK }).WebVideoCtrl\n      if (sdk)\n        resolve(sdk)\n      else\n        reject(new HikError('SCRIPT_LOAD_FAILED', `${scriptUrl} 已加载，但未检测到 window.WebVideoCtrl`))\n    }\n\n    const onFail = (cause: unknown) => {\n      window.clearTimeout(cleanupTimer)\n      reject(new HikError('SCRIPT_LOAD_FAILED', `加载 ${scriptUrl} 失败`, { url: scriptUrl }, cause))\n    }\n\n    if (strategy === 'reuse') {\n      const absoluteUrl = new URL(scriptUrl, document.baseURI).href\n      const reused = Array.from(document.scripts).find(script => script.src === absoluteUrl)\n      if (reused) {\n        reused.addEventListener('load', onReady, { once: true })\n        reused.addEventListener('error', onFail, { once: true })\n        return\n      }\n    }\n\n    const script = document.createElement('script')\n    script.src = scriptUrl\n    script.async = true\n    script.addEventListener('load', onReady, { once: true })\n    script.addEventListener('error', onFail, { once: true })\n    document.head.appendChild(script)\n  })\n}\n\n// ─────────────────────────── 私有工具 ───────────────────────────\n\nfunction resolveMethod(sdk: WebVideoCtrlSDK, method: string): (...args: unknown[]) => unknown {\n  const fn = (sdk as Record<string, unknown>)[method]\n  if (typeof fn !== 'function') {\n    throw new HikError('SDK_METHOD_MISSING', `WebVideoCtrl.${method} 不存在或不是函数`, {\n      method,\n    })\n  }\n  return fn as (...args: unknown[]) => unknown\n}\n\nfunction isThenable(value: unknown): value is PromiseLike<unknown> {\n  return (\n    typeof value === 'object'\n    && value !== null\n    && typeof (value as { then?: unknown }).then === 'function'\n  )\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n  if (typeof value !== 'object' || value === null || Array.isArray(value))\n    return false\n  const proto = Object.getPrototypeOf(value)\n  return proto === Object.prototype || proto === null\n}\n\nfunction buildCallbackError(\n  method: string,\n  status?: number,\n  xmlDoc?: Document | null,\n  native?: unknown,\n): HikError {\n  const message\n    = typeof status === 'number'\n      ? `${method} 调用失败（HTTP ${status}）`\n      : `${method} 调用失败`\n  return new HikError(\n    'SDK_CALL_FAILED',\n    message,\n    {\n      method,\n      status,\n      ...(xmlDoc ? { responseXml: serializeXml(xmlDoc) } : null),\n    },\n    native,\n  )\n}\n\nfunction serializeXml(doc: Document): string {\n  if (typeof XMLSerializer === 'undefined')\n    return ''\n  try {\n    return new XMLSerializer().serializeToString(doc)\n  }\n  catch {\n    return ''\n  }\n}\n","import { HikError } from './errors'\n\n// ─────────────────────────── 时间 ───────────────────────────\n\n/**\n * 按 `yyyy-MM-dd HH:mm:ss[.SSS]` 格式化日期。\n *\n * 支持的 token：`yyyy / MM / dd / HH / mm / ss / SSS`。\n */\nexport function formatDate(date: Date, pattern: string = 'yyyy-MM-dd HH:mm:ss'): string {\n  const dict: Record<string, string> = {\n    yyyy: String(date.getFullYear()),\n    MM: pad2(date.getMonth() + 1),\n    dd: pad2(date.getDate()),\n    HH: pad2(date.getHours()),\n    mm: pad2(date.getMinutes()),\n    ss: pad2(date.getSeconds()),\n    SSS: String(date.getMilliseconds()).padStart(3, '0'),\n  }\n  return pattern.replace(/yyyy|SSS|MM|dd|HH|mm|ss/g, t => dict[t] ?? t)\n}\n\n/** 当前时间字符串，等价于 `formatDate(new Date(), pattern)`。 */\nexport function currentTimestamp(pattern: string = 'yyyy-MM-dd HH:mm:ss'): string {\n  return formatDate(new Date(), pattern)\n}\n\n/** 当天 `00:00:00` ~ `23:59:59`，便于直接传入回放/搜索接口。 */\nexport function todayTimeRange(): { start: string, end: string } {\n  const base = formatDate(new Date(), 'yyyy-MM-dd')\n  return { start: `${base} 00:00:00`, end: `${base} 23:59:59` }\n}\n\n/** 校验 `[start, end]` 区间合法。 */\nexport function isValidTimeRange(start: string, end: string): boolean {\n  const s = parseSdkTime(start)\n  const e = parseSdkTime(end)\n  return s !== null && e !== null && e >= s\n}\n\n// ─────────────────────────── 地址校验 ───────────────────────────\n\n/** 严格匹配点分十进制 IPv4。 */\nexport function isIPv4(value: string): boolean {\n  return /^(?:(?:25[0-5]|2[0-4]\\d|[01]?\\d{1,2})\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d{1,2})$/.test(value)\n}\n\n/** 校验标准 IPv6（接受带方括号和 IPv4 映射地址）。 */\nexport function isIPv6(value: string): boolean {\n  const host = value.startsWith('[') && value.endsWith(']') ? value.slice(1, -1) : value\n  if (!host.includes(':'))\n    return false\n  try {\n    const parsed = new URL(`http://[${host}]/`).hostname\n    return parsed.startsWith('[') && parsed.endsWith(']')\n  }\n  catch {\n    return false\n  }\n}\n\n/** 标准 DNS 主机名；兼容局域网单标签名称与 punycode 域名。 */\nexport function isHostname(value: string): boolean {\n  if (!value || value.length > 253 || value.endsWith('.'))\n    return false\n  if (/^[\\d.]+$/.test(value))\n    return false\n  return value.split('.').every(label => (\n    label.length >= 1\n    && label.length <= 63\n    && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label)\n  ))\n}\n\n/** 主机地址综合校验（IPv4 / IPv6 / 域名 / `localhost`）。 */\nexport function isValidHost(host: string): boolean {\n  if (!host)\n    return false\n  if (host === 'localhost')\n    return true\n  return isIPv4(host) || isIPv6(host) || isHostname(host)\n}\n\n/** 端口号是否合法（1-65535 的整数）。 */\nexport function isValidPort(port: number): boolean {\n  return Number.isInteger(port) && port >= 1 && port <= 65535\n}\n\n/** 校验并返回端口，非法时抛 `INVALID_ARGUMENT`。 */\nexport function normalizePort(port: number): number {\n  if (!isValidPort(port))\n    throw new HikError('INVALID_ARGUMENT', '端口号应在 1 - 65535 之间', { received: port })\n  return port\n}\n\n// ─────────────────────────── 设备标识 ───────────────────────────\n\n/** 生成 SDK 内部设备标识 `<host>_<port>`。 */\nexport function makeDeviceIdentify(host: string, port: number): string {\n  return `${host}_${port}`\n}\n\n/** 反解 `<host>_<port>`；缺省端口返回 80。 */\nexport function parseDeviceIdentify(identify: string): { host: string, port: number } {\n  const idx = identify.lastIndexOf('_')\n  if (idx < 0)\n    return { host: identify, port: 80 }\n  return {\n    host: identify.slice(0, idx),\n    port: Number.parseInt(identify.slice(idx + 1), 10) || 80,\n  }\n}\n\n/** 协议名 → SDK 数值；`'https'` → 2，其它 → 1。 */\nexport function toProtocolValue(protocol: 'http' | 'https'): 1 | 2 {\n  return protocol === 'https' ? 2 : 1\n}\n\n// ─────────────────────────── 容器解析 ───────────────────────────\n\n/**\n * 解析插件容器参数，接受 `'#id'`、`'id'` 或 DOM 元素。\n * 元素无 id 时会自动注入临时 id。\n */\nexport function resolveContainer(input: string | HTMLElement): {\n  id: string\n  element: HTMLElement | null\n} {\n  if (typeof input === 'string') {\n    const id = input.startsWith('#') ? input.slice(1) : input\n    if (!id.trim())\n      throw new HikError('INVALID_ARGUMENT', '插件容器 ID 不能为空')\n    const element = typeof document === 'undefined' ? null : document.getElementById(id)\n    return { id, element }\n  }\n\n  if (typeof HTMLElement === 'undefined' || !(input instanceof HTMLElement))\n    throw new HikError('INVALID_ARGUMENT', '插件容器必须是 DOM 元素或元素 ID')\n\n  if (!input.id)\n    input.id = `hik-player-${randomId()}`\n  return { id: input.id, element: input }\n}\n\n/**\n * 将尺寸归一化为像素整数。\n *\n * 数字截断为整数；`\"240px\"` 剥离单位；百分比基于容器实际尺寸换算；\n * 其它字符串尝试 `parseFloat`，失败则回退到容器尺寸或 `fallback`。\n */\nexport function normalizeSize(\n  value: string | number | undefined,\n  element: HTMLElement | null,\n  axis: 'width' | 'height',\n  fallback: number,\n): number {\n  if (typeof value === 'number' && Number.isFinite(value))\n    return Math.max(0, Math.trunc(value))\n\n  if (typeof value === 'string') {\n    const trimmed = value.trim()\n    if (/^\\d+(?:\\.\\d+)?px$/i.test(trimmed))\n      return Math.trunc(Number.parseFloat(trimmed))\n    if (/^\\d+(?:\\.\\d+)?%$/.test(trimmed) && element) {\n      const measured = measure(element, axis)\n      if (measured > 0)\n        return Math.trunc((measured * Number.parseFloat(trimmed)) / 100)\n    }\n    const num = Number.parseFloat(trimmed)\n    if (Number.isFinite(num) && num > 0)\n      return Math.trunc(num)\n  }\n\n  if (element) {\n    const measured = measure(element, axis)\n    if (measured > 0)\n      return Math.trunc(measured)\n  }\n\n  return fallback\n}\n\nfunction measure(element: HTMLElement, axis: 'width' | 'height'): number {\n  const rect = element.getBoundingClientRect()\n  return axis === 'width' ? rect.width : rect.height\n}\n\n// ─────────────────────────── XML ───────────────────────────\n\n/** 解析 XML 字符串为 `Document`，失败返回 `null`。 */\nexport function parseXml(xml: string | null | undefined): Document | null {\n  if (!xml)\n    return null\n  if (typeof DOMParser === 'undefined')\n    return null\n  try {\n    const doc = new DOMParser().parseFromString(xml, 'text/xml')\n    return doc.querySelector('parsererror') ? null : doc\n  }\n  catch {\n    return null\n  }\n}\n\n/**\n * 将 SDK 回调入参统一为 `Document`。\n *\n * `success(data)` 入参可能形态：\n * - `Document`：现代 SDK 主路径\n * - `string`：早期版本透传 responseText\n * - jQuery `jqXHR`：旧 demo 兼容路径，含 `responseXML` 或 `responseText`\n */\nexport function ensureXmlDocument(input: unknown): Document | null {\n  if (!input)\n    return null\n  if (isDocument(input))\n    return input as Document\n  if (typeof input === 'string')\n    return parseXml(input)\n  const responseXML = (input as { responseXML?: unknown }).responseXML\n  if (isDocument(responseXML))\n    return responseXML as Document\n  const responseText = (input as { responseText?: unknown }).responseText\n  if (typeof responseText === 'string')\n    return parseXml(responseText)\n  return null\n}\n\n/** XML 文档序列化为字符串；缺失声明时补齐 utf-8。 */\nexport function stringifyXml(doc: Document | null | undefined): string {\n  if (!doc || typeof XMLSerializer === 'undefined')\n    return ''\n  try {\n    const xml = new XMLSerializer().serializeToString(doc)\n    return xml.includes('<?xml') ? xml : `<?xml version=\"1.0\" encoding=\"utf-8\"?>${xml}`\n  }\n  catch {\n    return ''\n  }\n}\n\n/** 读取 XML 节点内容；缺失返回 `fallback`。 */\nexport function xmlText(doc: Document | Element | null | undefined, selector: string, fallback: string = ''): string {\n  return doc?.querySelector(selector)?.textContent?.trim() ?? fallback\n}\n\n// ─────────────────────────── 其它 ───────────────────────────\n\n/** Promise 化的延时。 */\nexport function delay(ms: number): Promise<void> {\n  return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/** 生成 `<prefix>_<timestamp>_<random>.<ext>` 形式的唯一文件名。 */\nexport function uniqueFileName(prefix: string, extension: string): string {\n  return `${prefix}_${Date.now()}_${randomId()}.${extension.replace(/^\\./, '')}`\n}\n\n/** 短随机串，用于 dom id 或文件名后缀。 */\nexport function randomId(): string {\n  if (globalThis.crypto?.randomUUID)\n    return globalThis.crypto.randomUUID().replace(/-/g, '').slice(0, 8)\n  return Math.random().toString(36).slice(2, 10)\n}\n\nfunction pad2(value: number): string {\n  return String(value).padStart(2, '0')\n}\n\nfunction parseSdkTime(value: string): number | null {\n  const match = /^(\\d{4})-(\\d{2})-(\\d{2}) (\\d{2}):(\\d{2}):(\\d{2})$/.exec(value)\n  if (!match)\n    return null\n  const [, yearText, monthText, dayText, hourText, minuteText, secondText] = match\n  const year = Number(yearText)\n  const month = Number(monthText)\n  const day = Number(dayText)\n  const hour = Number(hourText)\n  const minute = Number(minuteText)\n  const second = Number(secondText)\n  const date = new Date(year, month - 1, day, hour, minute, second, 0)\n  if (\n    date.getFullYear() !== year\n    || date.getMonth() !== month - 1\n    || date.getDate() !== day\n    || date.getHours() !== hour\n    || date.getMinutes() !== minute\n    || date.getSeconds() !== second\n  ) {\n    return null\n  }\n  return date.getTime()\n}\n\nfunction isDocument(value: unknown): value is Document {\n  return Boolean(\n    value\n    && typeof value === 'object'\n    && (value as { nodeType?: unknown }).nodeType === 9\n    && typeof (value as { querySelector?: unknown }).querySelector === 'function',\n  )\n}\n","import type { RestoreMode } from './constants'\nimport type {\n  SdkAjaxOptions,\n  SdkDevicePort,\n  SdkInitOptions,\n  SdkWindowInfo,\n  WebVideoCtrlSDK,\n} from './sdk'\nimport type {\n  CaptureOptions,\n  ChannelInfo,\n  DeviceCaptureOptions,\n  DeviceCredentials,\n  DeviceInfo,\n  DevicePort,\n  DeviceSession,\n  DownloadByTimeOptions,\n  DownloadOptions,\n  HikPlayerEventMap,\n  HikPlayerOptions,\n  HttpRequestOptions,\n  ImportDeviceConfigOptions,\n  OpenFileDialogResult,\n  PlaybackOptions,\n  PluginInitOptions,\n  PreviewOptions,\n  PtzControlOptions,\n  WindowStatus as PublicWindowStatus,\n  RecordingOptions,\n  RecordMatch,\n  RecordSearchOptions,\n  RecordSearchResult,\n  StartUpgradeOptions,\n} from './types'\nimport { PTZ_SPEED_RANGE, RECORD_SEARCH_PAGE_SIZE } from './constants'\nimport { TypedEmitter } from './emitter'\nimport { HikError } from './errors'\nimport { callPromise, callSync, callWithCallback } from './sdk'\nimport {\n  ensureXmlDocument,\n  formatDate,\n  isValidHost,\n  isValidTimeRange,\n  makeDeviceIdentify,\n  normalizePort,\n  normalizeSize,\n  resolveContainer,\n  toProtocolValue,\n  uniqueFileName,\n  xmlText,\n} from './utils'\n\n/**\n * 海康无插件 WebVideoCtrl 的现代化 TypeScript 客户端。\n *\n * 一个实例对应\"一个插件 + 一组登录设备 + 一组播放窗口\"。\n * SDK 的同步 / Promise / 回调三种调用形态统一抽象为 `async/await`。\n * 通过 `on/off/once` 订阅强类型事件（同步派发）。\n *\n * 推荐使用 {@link createHikPlayer} 创建实例，便于注入测试 SDK 替身。\n */\nexport class HikPlayer {\n  readonly #sdk: WebVideoCtrlSDK\n  readonly #emitter = new TypedEmitter<HikPlayerEventMap>()\n  readonly #devices = new Map<string, DeviceSession>()\n  #initialized = false\n  #initializing = false\n  #containerId: string | null = null\n  #containerElement: HTMLElement | null = null\n  #activeWindow = 0\n\n  constructor(options: HikPlayerOptions = {}) {\n    const sdk = options.sdk ?? (globalThis as { window?: { WebVideoCtrl?: WebVideoCtrlSDK } }).window?.WebVideoCtrl\n    if (!sdk) {\n      throw new HikError(\n        'SDK_NOT_FOUND',\n        '未检测到 window.WebVideoCtrl。请先加载 webVideoCtrl.js，或通过 options.sdk 注入。',\n      )\n    }\n    this.#sdk = sdk\n  }\n\n  // ─────────────────────────── 元信息 ───────────────────────────\n\n  /** 是否已完成初始化。 */\n  get isInitialized(): boolean {\n    return this.#initialized\n  }\n\n  /** 当前选中窗口索引；未初始化时为 0。 */\n  get activeWindowIndex(): number {\n    return this.#activeWindow\n  }\n\n  /** 已挂载的容器 id；未初始化时为 null。 */\n  get containerId(): string | null {\n    return this.#containerId\n  }\n\n  /** 底层 SDK 实例，供高级扩展使用。 */\n  get sdk(): WebVideoCtrlSDK {\n    return this.#sdk\n  }\n\n  /** 浏览器是否支持无插件模式（Chromium 内核 ≥ 91）。 */\n  supportsNoPlugin(): boolean {\n    return Boolean(this.#sdk.I_SupportNoPlugin?.())\n  }\n\n  /** 检查官方播放组件版本；无插件模式固定返回 `0`。 */\n  checkPluginVersion(): number {\n    return callSync<number>(this.#sdk, 'I_CheckPluginVersion')\n  }\n\n  // ─────────────────────────── 生命周期 ───────────────────────────\n\n  /**\n   * 初始化播放器。\n   *\n   * 流程：环境校验 → `I_InitPlugin` → `cbInitPluginComplete` 内调用\n   * `I_InsertOBJECTPlugin` 挂载到容器。\n   */\n  async init(options: PluginInitOptions): Promise<void> {\n    if (this.#initialized || this.#initializing)\n      throw new HikError('ALREADY_INITIALIZED', '播放器已初始化，请勿重复调用 init()')\n    if (!this.supportsNoPlugin())\n      throw new HikError('SDK_NOT_FOUND', '当前浏览器不支持 WebVideoCtrl 无插件模式（需 Chromium ≥ 91）')\n\n    const { id: containerId, element } = resolveContainer(options.container)\n    const width = normalizeSize(options.width, element, 'width', 800)\n    const height = normalizeSize(options.height, element, 'height', 600)\n    const layout = options.layout ?? 1\n    ensureLayout(layout)\n    const timeout = options.timeout ?? 15_000\n    if (!Number.isFinite(timeout) || timeout <= 0)\n      throw new HikError('INVALID_ARGUMENT', '初始化超时时间必须为正数', { timeout })\n\n    this.#initializing = true\n\n    await new Promise<void>((resolve, reject) => {\n      const settle = { done: false }\n      let timer: ReturnType<typeof setTimeout> | undefined\n      const fail = (err: HikError) => {\n        if (settle.done)\n          return\n        settle.done = true\n        if (timer !== undefined)\n          clearTimeout(timer)\n        this.#initializing = false\n        reject(err)\n      }\n      timer = setTimeout(() => {\n        fail(new HikError(\n          'INITIALIZATION_TIMEOUT',\n          `底层播放组件初始化超时（${timeout}ms）`,\n          { method: 'I_InitPlugin', timeout },\n        ))\n      }, timeout)\n\n      const initOptions: SdkInitOptions = {\n        iWndowType: layout,\n        // 无插件模式：bNoPlugin 必须 true，bWndFull / iPlayMode 文档明示不可改\n        bNoPlugin: true,\n        bWndFull: true,\n        iPlayMode: 2,\n        bDebugMode: options.debugMode ?? false,\n        szColorProperty: options.colorProperty,\n        cbSelWnd: (xmlDoc: Document) => {\n          const index = Number.parseInt(xmlText(xmlDoc, 'SelectWnd', '0'), 10) || 0\n          this.#activeWindow = index\n          this.#emitter.emit('window:selected', { windowIndex: index })\n          options.onWindowSelect?.(index)\n        },\n        cbDoubleClickWnd: (index, fullScreen) => {\n          this.#emitter.emit('window:dblclick', { windowIndex: index, fullScreen })\n          options.onWindowDoubleClick?.(index, fullScreen)\n        },\n        cbEvent: (eventType, windowIndex, param2) => {\n          this.#emitter.emit('plugin:event', { eventType, windowIndex, param2 })\n          options.onEvent?.(eventType, windowIndex, param2)\n        },\n        cbPluginErrorHandler: (windowIndex, errorCode, error) => {\n          this.#emitter.emit('plugin:error', { windowIndex, errorCode, error })\n          options.onError?.(windowIndex, errorCode, error)\n        },\n        cbPerformanceLack: () => {\n          this.#emitter.emit('plugin:performance-lack', undefined)\n          options.onPerformanceLack?.()\n        },\n        cbSecretKeyError: (windowIndex) => {\n          this.#emitter.emit('plugin:secret-key-error', { windowIndex })\n          options.onSecretKeyError?.(windowIndex)\n        },\n        cbInitPluginComplete: () => {\n          if (settle.done)\n            return\n          try {\n            const result = this.#sdk.I_InsertOBJECTPlugin(containerId)\n            if (result !== 0) {\n              fail(new HikError('SDK_CALL_FAILED', `I_InsertOBJECTPlugin 返回 ${result}`, {\n                method: 'I_InsertOBJECTPlugin',\n                returnValue: result,\n              }))\n              return\n            }\n            this.#initialized = true\n            this.#initializing = false\n            this.#containerId = containerId\n            this.#containerElement = element\n            this.#emitter.emit('plugin:initialized', undefined)\n            settle.done = true\n            if (timer !== undefined)\n              clearTimeout(timer)\n            resolve()\n          }\n          catch (err) {\n            fail(new HikError('SDK_CALL_FAILED', '插入插件 DOM 失败', { method: 'I_InsertOBJECTPlugin' }, err))\n          }\n        },\n      }\n\n      try {\n        this.#sdk.I_InitPlugin(width, height, initOptions)\n      }\n      catch (err) {\n        fail(new HikError('SDK_CALL_FAILED', '插件初始化失败', { method: 'I_InitPlugin' }, err))\n      }\n    })\n  }\n\n  /**\n   * 停止全部播放、释放 Worker、清空事件订阅。\n   * 重复调用安全；销毁后实例不再可用。适合 SPA 路由切换 / 组件卸载时调用。\n   */\n  async destroy(): Promise<void> {\n    if (!this.#initialized)\n      return\n    // 未播放任何窗口时 I_StopAll 可能 reject，吞掉以保证销毁流程不中断\n    try {\n      await callPromise<void>(this.#sdk, 'I_StopAll')\n    }\n    catch (err) {\n      console.warn('[hikvideoctrl] destroy 期间 I_StopAll 失败，已忽略', err)\n    }\n    try {\n      this.#sdk.I_DestroyWorker?.()\n    }\n    catch (err) {\n      console.warn('[hikvideoctrl] I_DestroyWorker 失败，已忽略', err)\n    }\n    this.#initialized = false\n    this.#containerId = null\n    this.#containerElement = null\n    this.#activeWindow = 0\n    this.#devices.clear()\n    this.#emitter.emit('plugin:destroyed', undefined)\n    this.#emitter.clear()\n  }\n\n  /** 调整插件渲染尺寸；不传按容器实际尺寸自适应。 */\n  resize(width?: number | string, height?: number | string): void {\n    this.#ensureInitialized()\n    const w = normalizeSize(width, this.#containerElement, 'width', 0)\n    const h = normalizeSize(height, this.#containerElement, 'height', 0)\n    this.#sdk.I_Resize?.(w, h)\n  }\n\n  // ─────────────────────────── 事件 ───────────────────────────\n\n  /** 订阅事件，返回取消订阅函数。 */\n  on<K extends keyof HikPlayerEventMap>(\n    event: K,\n    handler: (payload: HikPlayerEventMap[K]) => void,\n  ): () => void {\n    return this.#emitter.on(event, handler)\n  }\n\n  /** 仅触发一次，触发后自动解除订阅。 */\n  once<K extends keyof HikPlayerEventMap>(\n    event: K,\n    handler: (payload: HikPlayerEventMap[K]) => void,\n  ): () => void {\n    return this.#emitter.once(event, handler)\n  }\n\n  /** 取消订阅；不传 handler 则清空该事件全部监听。 */\n  off<K extends keyof HikPlayerEventMap>(\n    event: K,\n    handler?: (payload: HikPlayerEventMap[K]) => void,\n  ): void {\n    this.#emitter.off(event, handler)\n  }\n\n  // ─────────────────────────── 窗口 ───────────────────────────\n\n  /** 切换分屏布局（1=1x1 / 2=2x2 / 3=3x3 / 4=4x4）。 */\n  async changeLayout(layout: number): Promise<void> {\n    this.#ensureInitialized()\n    ensureLayout(layout)\n    await callPromise<void>(this.#sdk, 'I_ChangeWndNum', layout)\n  }\n\n  /**\n   * 进入全屏播放。\n   * 官方无插件接口只能进入全屏；传 `false` 时由封装层调用浏览器 Fullscreen API 退出。\n   */\n  async fullScreen(enable: boolean = true): Promise<void> {\n    this.#ensureInitialized()\n    if (!enable) {\n      if (typeof document !== 'undefined' && document.fullscreenElement)\n        await document.exitFullscreen()\n      return\n    }\n    await callPromise<void>(this.#sdk, 'I_FullScreen', enable)\n  }\n\n  /** 获取窗口状态；未播放或越界返回 null。 */\n  getWindowStatus(windowIndex: number = this.#activeWindow): PublicWindowStatus | null {\n    this.#ensureInitialized()\n    const raw = callSync<SdkWindowInfo | null>(this.#sdk, 'I_GetWindowStatus', this.#windowIndex(windowIndex))\n    return raw ? toPublicWindow(raw) : null\n  }\n\n  /** 全部正在播放的窗口。 */\n  getAllWindows(): PublicWindowStatus[] {\n    this.#ensureInitialized()\n    const list = callSync<SdkWindowInfo[]>(this.#sdk, 'I_GetWndSet') ?? []\n    return list.filter(Boolean).map(toPublicWindow)\n  }\n\n  // ─────────────────────────── 设备登录 ───────────────────────────\n\n  /**\n   * 登录设备。\n   *\n   * 返回的 `DeviceSession.id` 即 SDK 内部的 `<host>_<port>` 标识，\n   * 后续接口的 `deviceId` 参数均应使用此值。\n   */\n  async login(credentials: DeviceCredentials): Promise<DeviceSession> {\n    this.#ensureInitialized()\n\n    const host = credentials.host?.trim() ?? ''\n    if (!host)\n      throw new HikError('INVALID_ARGUMENT', '设备地址不能为空')\n    if (!isValidHost(host))\n      throw new HikError('INVALID_ARGUMENT', `无效的设备地址：${host}`)\n    if (!credentials.username)\n      throw new HikError('INVALID_ARGUMENT', '用户名不能为空')\n    if (credentials.password === undefined || credentials.password === null)\n      throw new HikError('INVALID_ARGUMENT', '密码不能为空')\n\n    const protocol = credentials.protocol ?? 'http'\n    if (protocol !== 'http' && protocol !== 'https')\n      throw new HikError('INVALID_ARGUMENT', `不支持的设备协议：${String(protocol)}`)\n    const port = normalizePort(credentials.port ?? (protocol === 'https' ? 443 : 80))\n\n    const ajax: SdkAjaxOptions = {}\n    if (credentials.login?.async !== undefined)\n      ajax.async = credentials.login.async\n    if (credentials.login?.cgi !== undefined)\n      (ajax as Record<string, unknown>).cgi = credentials.login.cgi\n\n    await callWithCallback<unknown>(\n      this.#sdk,\n      'I_Login',\n      host,\n      toProtocolValue(protocol),\n      port,\n      credentials.username,\n      credentials.password,\n      ajax,\n    )\n\n    const session: DeviceSession = {\n      id: makeDeviceIdentify(host, port),\n      host,\n      port,\n      protocol,\n      username: credentials.username,\n    }\n    this.#devices.set(session.id, session)\n    this.#emitter.emit('device:connected', session)\n    return session\n  }\n\n  /** 登出设备，自动停止相关播放窗口并清空 SecretKey。 */\n  async logout(deviceId: string): Promise<void> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    await this.#stopDeviceStreams(deviceId)\n\n    const result = callSync<number>(this.#sdk, 'I_Logout', deviceId)\n    if (result !== 0) {\n      throw new HikError('SDK_CALL_FAILED', `登出 ${deviceId} 失败`, {\n        method: 'I_Logout',\n        returnValue: result,\n      })\n    }\n    this.#devices.delete(deviceId)\n    this.#emitter.emit('device:disconnected', { deviceId })\n  }\n\n  /** 已登录设备列表。 */\n  listDevices(): DeviceSession[] {\n    return [...this.#devices.values()]\n  }\n\n  /** 查询设备会话；未登录时返回 undefined。 */\n  getDevice(deviceId: string): DeviceSession | undefined {\n    return this.#devices.get(deviceId)\n  }\n\n  // ─────────────────────────── 设备信息 / 通道 ───────────────────────────\n\n  /** 设备基本信息（型号、序列号、版本等）。 */\n  async getDeviceInfo(deviceId: string): Promise<DeviceInfo | null> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    const raw = await callWithCallback<unknown>(this.#sdk, 'I_GetDeviceInfo', deviceId, {})\n    const doc = ensureXmlDocument(raw)\n    if (!doc)\n      return null\n    return {\n      deviceName: xmlText(doc, 'deviceName'),\n      deviceId: xmlText(doc, 'deviceID'),\n      deviceType: xmlText(doc, 'deviceType'),\n      model: xmlText(doc, 'model'),\n      serialNumber: xmlText(doc, 'serialNumber'),\n      macAddress: xmlText(doc, 'macAddress'),\n      firmwareVersion: xmlText(doc, 'firmwareVersion'),\n      firmwareReleasedDate: xmlText(doc, 'firmwareReleasedDate'),\n      encoderVersion: xmlText(doc, 'encoderVersion'),\n      encoderReleasedDate: xmlText(doc, 'encoderReleasedDate'),\n      raw: doc,\n    }\n  }\n\n  /** 获取设备安全能力版本 XML。 */\n  async getSecurityVersion(deviceId: string): Promise<Document | null> {\n    return this.#fetchXml('I_GetSecurityVersion', deviceId)\n  }\n\n  /** 同步读取设备 HTTP / RTSP 端口。 */\n  getDevicePort(deviceId: string): DevicePort {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    const raw = callSync<SdkDevicePort | null>(this.#sdk, 'I_GetDevicePort', deviceId)\n    if (!raw) {\n      throw new HikError('SDK_CALL_FAILED', `获取 ${deviceId} 端口失败`, {\n        method: 'I_GetDevicePort',\n      })\n    }\n    return {\n      iDevicePort: raw.iDevicePort,\n      iRtspPort: raw.iRtspPort,\n      iHttpPort: raw.iHttpPort,\n      iWebSocketPort: raw.iWebSocketPort,\n      iWebSocketsPort: raw.iWebSocketsPort,\n    }\n  }\n\n  /** 模拟通道（DVR 同轴摄像头）。 */\n  async getAnalogChannels(deviceId: string): Promise<ChannelInfo[]> {\n    const doc = await this.#fetchXml('I_GetAnalogChannelInfo', deviceId)\n    if (!doc)\n      return []\n    return Array.from(doc.querySelectorAll('VideoInputChannel')).map((node, idx) => ({\n      id: xmlText(node, 'id', String(idx + 1)),\n      name: xmlText(node, 'name', `Camera ${String(idx + 1).padStart(2, '0')}`),\n      kind: 'analog',\n      online: true,\n      enabled: xmlText(node, 'videoInputEnabled', 'true') !== 'false',\n      videoFormat: xmlText(node, 'videoFormat') || undefined,\n    }))\n  }\n\n  /** 数字通道（NVR 接入的网络摄像头）。 */\n  async getDigitalChannels(deviceId: string): Promise<ChannelInfo[]> {\n    const doc = await this.#fetchXml('I_GetDigitalChannelInfo', deviceId)\n    if (!doc)\n      return []\n    return Array.from(doc.querySelectorAll('InputProxyChannelStatus')).map((node, idx) => {\n      const online = xmlText(node, 'online', 'false') === 'true'\n      return {\n        id: xmlText(node, 'id', String(idx + 1)),\n        name: xmlText(node, 'name', `IPCamera ${String(idx + 1).padStart(2, '0')}`),\n        kind: 'digital' as const,\n        online,\n        enabled: true,\n      }\n    })\n  }\n\n  /** 零通道（整机预览，NVR/混合 DVR 特有）。 */\n  async getZeroChannels(deviceId: string): Promise<ChannelInfo[]> {\n    const doc = await this.#fetchXml('I_GetZeroChannelInfo', deviceId)\n    if (!doc)\n      return []\n    return Array.from(doc.querySelectorAll('ZeroVideoChannel'))\n      .filter(node => xmlText(node, 'enabled', 'false') === 'true')\n      .map((node, idx) => ({\n        id: xmlText(node, 'id', String(idx + 1)),\n        name: xmlText(node, 'name', `Zero Channel ${String(idx + 1).padStart(2, '0')}`),\n        kind: 'zero' as const,\n        online: true,\n        enabled: true,\n      }))\n  }\n\n  /**\n   * 一次性获取设备的全部通道（合并模拟 / 数字 / 零）。\n   * 任一接口失败仅丢弃该类通道，便于在能力不全的设备上降级。\n   */\n  async getChannels(deviceId: string): Promise<ChannelInfo[]> {\n    const [analog, digital, zero] = await Promise.all([\n      this.getAnalogChannels(deviceId).catch(() => [] as ChannelInfo[]),\n      this.getDigitalChannels(deviceId).catch(() => [] as ChannelInfo[]),\n      this.getZeroChannels(deviceId).catch(() => [] as ChannelInfo[]),\n    ])\n    return [...analog, ...digital, ...zero]\n  }\n\n  /** 语音对讲通道列表（保留原始 XML，业务层按需解析）。 */\n  async getAudioChannels(deviceId: string): Promise<Document | null> {\n    return this.#fetchXml('I_GetAudioInfo', deviceId)\n  }\n\n  // ─────────────────────────── 实时预览 ───────────────────────────\n\n  /** 开始实时预览。 */\n  async startPreview(deviceId: string, options: PreviewOptions): Promise<void> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n\n    const channel = ensurePositiveInteger(options.channel, '通道号')\n    const streamType = ensureIntegerInRange(options.streamType ?? 1, 1, 3, '码流类型')\n    const windowIndex = this.#windowIndex(options.windowIndex)\n    await this.#stopWindowIfPlaying(windowIndex)\n    const sdkOptions: Record<string, unknown> = {\n      iWndIndex: windowIndex,\n      iChannelID: channel,\n      iStreamType: streamType,\n      bZeroChannel: options.zeroChannel ?? false,\n    }\n    if (options.rtspPort !== undefined) {\n      const rtspPort = normalizePort(options.rtspPort)\n      sdkOptions.iRtspPort = rtspPort\n    }\n    if (options.webSocketPort !== undefined)\n      sdkOptions.iWSPort = normalizePort(options.webSocketPort)\n    if (options.useProxy !== undefined)\n      sdkOptions.bProxy = options.useProxy\n\n    await callWithCallback<unknown>(this.#sdk, 'I_StartRealPlay', deviceId, sdkOptions)\n    this.#emitter.emit('preview:started', {\n      deviceId,\n      channel,\n      windowIndex,\n      zeroChannel: options.zeroChannel ?? false,\n    })\n  }\n\n  /** 停止指定窗口的预览 / 回放，缺省为当前选中窗口。 */\n  async stop(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const target = this.#windowIndex(windowIndex)\n    const status = this.getWindowStatus(target)\n    if (!status)\n      throw new HikError('WINDOW_NOT_PLAYING', `窗口 ${target} 未在播放`)\n    await callWithCallback<unknown>(this.#sdk, 'I_Stop', { iWndIndex: target })\n\n    const event = status.playStatus === 2 ? 'playback:stopped' : 'preview:stopped'\n    this.#emitter.emit(event, { deviceId: status.deviceId, windowIndex: target })\n  }\n\n  /** 停止全部窗口（含预览与回放）。 */\n  async stopAll(): Promise<void> {\n    this.#ensureInitialized()\n    await callPromise<void>(this.#sdk, 'I_StopAll')\n    this.#emitter.emit('preview:stopped-all', undefined)\n  }\n\n  // ─────────────────────────── 录像回放 ───────────────────────────\n\n  /** 按时间段开始回放；时间格式必须为 `yyyy-MM-dd HH:mm:ss`。 */\n  async startPlayback(deviceId: string, options: PlaybackOptions): Promise<void> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    if (!isValidTimeRange(options.startTime, options.endTime))\n      throw new HikError('INVALID_ARGUMENT', `回放时间区间无效：${options.startTime} ~ ${options.endTime}`)\n\n    const channel = ensurePositiveInteger(options.channel, '通道号')\n    const streamType = ensureIntegerInRange(options.streamType ?? 1, 1, 2, '回放码流类型')\n    const windowIndex = this.#windowIndex(options.windowIndex)\n    await this.#stopWindowIfPlaying(windowIndex)\n    const sdkOptions: Record<string, unknown> = {\n      iWndIndex: windowIndex,\n      iChannelID: channel,\n      iStreamType: streamType,\n      szStartTime: options.startTime,\n      szEndTime: options.endTime,\n    }\n    if (options.rtspPort !== undefined) {\n      const rtspPort = normalizePort(options.rtspPort)\n      sdkOptions.iRtspPort = rtspPort\n    }\n    if (options.webSocketPort !== undefined)\n      sdkOptions.iWSPort = normalizePort(options.webSocketPort)\n    if (options.useProxy !== undefined)\n      sdkOptions.bProxy = options.useProxy\n    await callWithCallback<unknown>(this.#sdk, 'I_StartPlayback', deviceId, sdkOptions)\n    this.#emitter.emit('playback:started', {\n      deviceId,\n      channel,\n      windowIndex,\n      startTime: options.startTime,\n      endTime: options.endTime,\n    })\n  }\n\n  /** 暂停回放。 */\n  async pause(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_Pause', {\n      iWndIndex: target,\n    })\n  }\n\n  /** 从暂停 / 单帧恢复正常回放。 */\n  async resume(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_Resume', {\n      iWndIndex: target,\n    })\n  }\n\n  /** 加速回放（每次提升一档）。 */\n  async playFast(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_PlayFast', {\n      iWndIndex: target,\n    })\n  }\n\n  /** 减速回放（每次降低一档）。 */\n  async playSlow(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_PlaySlow', {\n      iWndIndex: target,\n    })\n  }\n\n  /** 当前窗口的 OSD 时间，格式 `yyyy-MM-dd HH:mm:ss`。 */\n  async getOsdTime(windowIndex?: number): Promise<string> {\n    this.#ensureInitialized()\n    const target = this.#playingWindowIndex(windowIndex)\n    const raw = await callWithCallback<unknown>(this.#sdk, 'I_GetOSDTime', {\n      iWndIndex: target,\n    })\n    if (typeof raw === 'string')\n      return raw\n    if (raw instanceof Date)\n      return formatDate(raw)\n    return String(raw ?? '')\n  }\n\n  // ─────────────────────────── 音频 / 缩放 / 加密 ───────────────────────────\n\n  /** 打开声音。 */\n  async openSound(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    await callPromise<void>(this.#sdk, 'I_OpenSound', this.#playingWindowIndex(windowIndex))\n  }\n\n  /** 关闭声音。 */\n  async closeSound(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    await callPromise<void>(this.#sdk, 'I_CloseSound', this.#playingWindowIndex(windowIndex))\n  }\n\n  /** 设置音量（0-100）。 */\n  async setVolume(volume: number, windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    if (!Number.isInteger(volume) || volume < 0 || volume > 100)\n      throw new HikError('INVALID_ARGUMENT', '音量必须是 0 - 100 的整数', { volume })\n    await callPromise<void>(this.#sdk, 'I_SetVolume', volume, this.#playingWindowIndex(windowIndex))\n  }\n\n  /** 启用电子放大。 */\n  async enableEZoom(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    await callPromise<unknown>(this.#sdk, 'I_EnableEZoom', this.#playingWindowIndex(windowIndex))\n  }\n\n  /** 禁用电子放大。 */\n  async disableEZoom(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    await callPromise<unknown>(this.#sdk, 'I_DisableEZoom', this.#playingWindowIndex(windowIndex))\n  }\n\n  /**\n   * 启用 3D 放大。\n   * 启用后按住左键从左上拖到右下放大，反之缩小。\n   */\n  async enable3DZoom(windowIndex?: number, onZoomInfo?: (info: unknown) => void): Promise<void> {\n    this.#ensureInitialized()\n    await callPromise<unknown>(\n      this.#sdk,\n      'I_Enable3DZoom',\n      this.#playingWindowIndex(windowIndex),\n      onZoomInfo,\n    )\n  }\n\n  /** 禁用 3D 放大。 */\n  async disable3DZoom(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const result = await callPromise<unknown>(this.#sdk, 'I_Disable3DZoom', this.#playingWindowIndex(windowIndex))\n    if (result === -1) {\n      throw new HikError('SDK_CALL_FAILED', '关闭 3D 放大失败', {\n        method: 'I_Disable3DZoom',\n        returnValue: result,\n      })\n    }\n  }\n\n  /** 设置该窗口的码流加密密钥。 */\n  async setSecretKey(secretKey: string, windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    // V3.4 返回 Promise，旧版本可能返回 number；callPromise 对非 thenable 直接 resolve\n    await callPromise<unknown>(\n      this.#sdk,\n      'I_SetSecretKey',\n      secretKey,\n      this.#windowIndex(windowIndex),\n    )\n  }\n\n  // ─────────────────────────── 抓拍 / 本地录像 ───────────────────────────\n\n  /**\n   * 抓拍当前画面。\n   *\n   * - 不传 `onData`：保存到浏览器下载文件夹（`.bmp` 抓 BMP，否则 JPEG）。\n   * - 传 `onData`：仅回调原始 Uint8Array，不下载文件。\n   *\n   * @returns SDK 实际使用的文件名\n   */\n  async capture(options: CaptureOptions = {}): Promise<string> {\n    this.#ensureInitialized()\n    const windowIndex = this.#playingWindowIndex(options.windowIndex)\n    const fileName = options.fileName ?? uniqueFileName('capture', 'jpg')\n    ensureNonEmpty(fileName, '抓拍文件名')\n    const onData = options.onData\n    let onDataTask: Promise<void> | undefined\n\n    const result = await callPromise<unknown>(this.#sdk, 'I2_CapturePic', fileName, {\n      iWndIndex: windowIndex,\n      cbCallback: onData\n        ? (data: Uint8Array) => {\n            try {\n              onDataTask = Promise.resolve(onData(data)).then(() => undefined)\n            }\n            catch (err) {\n              onDataTask = Promise.reject(err)\n            }\n          }\n        : undefined,\n    })\n    if (result === -1) {\n      throw new HikError('SDK_CALL_FAILED', '抓拍失败', {\n        method: 'I2_CapturePic',\n        returnValue: result,\n      })\n    }\n    await onDataTask\n    this.#emitter.emit('capture:completed', {\n      fileName,\n      windowIndex,\n      asFile: !options.onData,\n    })\n    return fileName\n  }\n\n  /** 直接从设备通道抓取 JPEG，无需先在播放窗口中预览。 */\n  async captureDevice(deviceId: string, options: DeviceCaptureOptions): Promise<string> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    const channel = ensurePositiveInteger(options.channel, '通道号')\n    const requestedFileName = options.fileName ?? uniqueFileName('device-capture', 'jpg')\n    ensureNonEmpty(requestedFileName, '抓拍文件名')\n    const baseFileName = requestedFileName.replace(/\\.jpe?g$/i, '')\n    ensureNonEmpty(baseFileName, '抓拍文件名')\n    const fileName = `${baseFileName}.jpg`\n\n    const hasWidth = options.width !== undefined\n    const hasHeight = options.height !== undefined\n    if (hasWidth !== hasHeight)\n      throw new HikError('INVALID_ARGUMENT', '设备抓图宽度和高度必须同时传入')\n\n    const sdkOptions: Record<string, unknown> = {\n      bDateDir: options.byDateDirectory ?? true,\n    }\n    if (hasWidth && hasHeight) {\n      sdkOptions.iResolutionWidth = ensurePositiveInteger(options.width, '图片宽度')\n      sdkOptions.iResolutionHeight = ensurePositiveInteger(options.height, '图片高度')\n    }\n\n    const result = callSync<number>(\n      this.#sdk,\n      'I_DeviceCapturePic',\n      deviceId,\n      channel,\n      baseFileName,\n      sdkOptions,\n    )\n    if (result !== 0) {\n      throw new HikError('SDK_CALL_FAILED', '设备抓图失败', {\n        method: 'I_DeviceCapturePic',\n        returnValue: result,\n      })\n    }\n    this.#emitter.emit('device-capture:completed', { deviceId, channel, fileName })\n    return fileName\n  }\n\n  /** 开始本地录像，保存到浏览器下载文件夹。 */\n  async startRecording(options: RecordingOptions = {}): Promise<string> {\n    this.#ensureInitialized()\n    const windowIndex = this.#playingWindowIndex(options.windowIndex)\n    const fileName = options.fileName ?? uniqueFileName('record', 'mp4')\n    ensureNonEmpty(fileName, '录像文件名')\n    await callWithCallback<unknown>(this.#sdk, 'I_StartRecord', fileName, {\n      iWndIndex: windowIndex,\n      bDateDir: options.byDateDirectory ?? true,\n    })\n    this.#emitter.emit('recording:started', { fileName, windowIndex })\n    return fileName\n  }\n\n  /** 停止本地录像。 */\n  async stopRecording(windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_StopRecord', { iWndIndex: target })\n    this.#emitter.emit('recording:stopped', { windowIndex: target })\n  }\n\n  // ─────────────────────────── 录像搜索 / 下载 ───────────────────────────\n\n  /**\n   * 搜索指定通道、时间段内的录像。\n   * SDK 单次最多返回 40 条，`searchPos` 或 `page` 控制翻页；`status` 为 `MORE` 表示仍有后续数据。\n   */\n  async searchRecords(deviceId: string, options: RecordSearchOptions): Promise<RecordSearchResult> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    if (!isValidTimeRange(options.startTime, options.endTime))\n      throw new HikError('INVALID_ARGUMENT', `搜索时间区间无效：${options.startTime} ~ ${options.endTime}`)\n\n    const channel = ensurePositiveInteger(options.channel, '通道号')\n    const streamType = ensureIntegerInRange(options.streamType ?? 1, 1, 2, '录像码流类型')\n    if (options.page !== undefined && (!Number.isInteger(options.page) || options.page < 1))\n      throw new HikError('INVALID_ARGUMENT', '页码必须是大于等于 1 的整数', { page: options.page })\n    if (\n      options.searchPos !== undefined\n      && (!Number.isInteger(options.searchPos)\n        || options.searchPos < 0\n        || options.searchPos % RECORD_SEARCH_PAGE_SIZE !== 0)\n    ) {\n      throw new HikError(\n        'INVALID_ARGUMENT',\n        `搜索起点必须是大于等于 0 且为 ${RECORD_SEARCH_PAGE_SIZE} 的倍数`,\n        { searchPos: options.searchPos },\n      )\n    }\n\n    const searchPos\n      = options.searchPos !== undefined\n        ? options.searchPos\n        : Math.max(0, (options.page ?? 1) - 1) * RECORD_SEARCH_PAGE_SIZE\n\n    const raw = await callWithCallback<unknown>(\n      this.#sdk,\n      'I_RecordSearch',\n      deviceId,\n      channel,\n      options.startTime,\n      options.endTime,\n      {\n        iStreamType: streamType,\n        iSearchPos: searchPos,\n      },\n    )\n    const doc = ensureXmlDocument(raw)\n    if (!doc) {\n      return {\n        matches: [],\n        status: 'NO MATCHES',\n        count: 0,\n        raw: new DOMParser().parseFromString('<CMSearchResult/>', 'text/xml'),\n      }\n    }\n    const status = xmlText(doc, 'responseStatusStrg', 'NO MATCHES') as RecordSearchResult['status']\n    const matches: RecordMatch[] = Array.from(doc.querySelectorAll('searchMatchItem'))\n      .map((node): RecordMatch | null => {\n        const playbackUri = xmlText(node, 'playbackURI')\n        if (!playbackUri || !playbackUri.includes('name='))\n          return null\n        return {\n          trackId: xmlText(node, 'trackID'),\n          startTime: normalizeIsoLikeTime(xmlText(node, 'startTime')),\n          endTime: normalizeIsoLikeTime(xmlText(node, 'endTime')),\n          fileName: extractFileNameFromUri(playbackUri),\n          playbackUri,\n          kind: (xmlText(node, 'metadataDescriptor') || 'timing') as RecordMatch['kind'],\n        }\n      })\n      .filter((item): item is RecordMatch => item !== null)\n    const count = Number.parseInt(xmlText(doc, 'numOfMatches', String(matches.length)), 10)\n    return { matches, status, count: Number.isFinite(count) ? count : matches.length, raw: doc }\n  }\n\n  /**\n   * 按 `playbackURI` 下载录像。\n   * V3.4.0 无插件模式通常直接触发浏览器下载并 resolve `undefined`。\n   */\n  async downloadRecord(\n    deviceId: string,\n    playbackUri: string,\n    fileName: string,\n    options: DownloadOptions = {},\n  ): Promise<unknown> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(playbackUri, '录像地址')\n    ensureNonEmpty(fileName, '下载文件名')\n    return callPromise<unknown>(\n      this.#sdk,\n      'I_StartDownloadRecord',\n      deviceId,\n      playbackUri,\n      fileName,\n      { bDateDir: options.byDateDirectory ?? true },\n    )\n  }\n\n  /** 按时间段下载录像（需设备支持）。 */\n  async downloadRecordByTime(\n    deviceId: string,\n    playbackUri: string,\n    options: DownloadByTimeOptions,\n  ): Promise<unknown> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(playbackUri, '录像地址')\n    ensureNonEmpty(options.fileName, '下载文件名')\n    if (!isValidTimeRange(options.startTime, options.endTime))\n      throw new HikError('INVALID_ARGUMENT', `下载时间区间无效：${options.startTime} ~ ${options.endTime}`)\n    return callPromise<unknown>(\n      this.#sdk,\n      'I_StartDownloadRecordByTime',\n      deviceId,\n      playbackUri,\n      options.fileName,\n      options.startTime,\n      options.endTime,\n      { bDateDir: options.byDateDirectory ?? true },\n    )\n  }\n\n  // ─────────────────────────── PTZ ───────────────────────────\n\n  /** 开始 PTZ 动作；松开按键时务必调用 `ptzStop()`，否则球机持续运动。 */\n  async ptzStart(options: PtzControlOptions): Promise<void> {\n    this.#ensureInitialized()\n    ensureIntegerInRange(options.action, 1, 15, 'PTZ 操作类型')\n    await this.#ptzCommand(options, false)\n  }\n\n  /** 停止 PTZ 动作。 */\n  async ptzStop(action: PtzControlOptions['action'], windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    ensureIntegerInRange(action, 1, 15, 'PTZ 操作类型')\n    await this.#ptzCommand({ action, windowIndex }, true)\n  }\n\n  /** 保存预置位（先用 PTZ 调整画面，再调用此方法绑定到 ID）。 */\n  async setPreset(presetId: number, windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    ensurePositiveInteger(presetId, '预置点 ID')\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_SetPreset', presetId, {\n      iWndIndex: target,\n    })\n  }\n\n  /** 调用预置位。 */\n  async goPreset(presetId: number, windowIndex?: number): Promise<void> {\n    this.#ensureInitialized()\n    ensurePositiveInteger(presetId, '预置点 ID')\n    const target = this.#playingWindowIndex(windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_GoPreset', presetId, {\n      iWndIndex: target,\n    })\n  }\n\n  // ─────────────────────────── 设备维护 ───────────────────────────\n\n  /** 导出设备配置文件（SDK 弹出系统保存框）。 */\n  async exportDeviceConfig(deviceId: string, password: string): Promise<unknown> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(password, '导出密码')\n    return callPromise<unknown>(this.#sdk, 'I_ExportDeviceConfig', deviceId, password)\n  }\n\n  /**\n   * 导入设备配置文件。\n   *\n   * `fileName` 与 `file` 通常来自 `openFileDialog(FILE_DIALOG.File)`。\n   * V3.4.0 实际上传浏览器 File 句柄，仅传文件名通常无法完成导入。\n   */\n  async importDeviceConfig(\n    deviceId: string,\n    fileName: string,\n    options: ImportDeviceConfigOptions,\n  ): Promise<unknown> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(fileName, '配置文件名')\n    if (!options?.file)\n      throw new HikError('INVALID_ARGUMENT', '无插件模式导入配置必须提供 File 句柄')\n    return callPromise<unknown>(\n      this.#sdk,\n      'I_ImportDeviceConfig',\n      deviceId,\n      fileName,\n      options.password,\n      options.file,\n    )\n  }\n\n  /** 恢复出厂参数（`basic` 保留网络与用户，`full` 全量重置）。 */\n  async restoreDefault(deviceId: string, mode: RestoreMode): Promise<void> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    await callWithCallback<unknown>(this.#sdk, 'I_RestoreDefault', deviceId, mode, {})\n  }\n\n  /** 重启设备；成功仅表示设备已收到指令。 */\n  async restart(deviceId: string): Promise<void> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    await callWithCallback<unknown>(this.#sdk, 'I_Restart', deviceId, {})\n  }\n\n  /** 断线重连（不会重新登录）。 */\n  async reconnect(deviceId: string): Promise<void> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    await callWithCallback<unknown>(this.#sdk, 'I_Reconnect', deviceId, {})\n  }\n\n  /** 开始固件异步升级；升级完成后设备需要重启。`file` 通常来自 `openFileDialog(FILE_DIALOG.File)`。 */\n  async startUpgrade(\n    deviceId: string,\n    fileName: string,\n    options: StartUpgradeOptions,\n  ): Promise<unknown> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(fileName, '升级文件名')\n    if (!options?.file)\n      throw new HikError('INVALID_ARGUMENT', '无插件模式升级必须提供 File 句柄')\n    return callPromise<unknown>(this.#sdk, 'I2_StartUpgrade', deviceId, fileName, options.file)\n  }\n\n  /** 查询升级进度；不传 `deviceId` 时仅在单设备场景自动推断。 */\n  async getUpgradeProgress(deviceId?: string): Promise<{ percent: number, upgrading: boolean }> {\n    this.#ensureInitialized()\n    const targetDeviceId = this.#resolveDeviceId(deviceId)\n    return callPromise<{ percent: number, upgrading: boolean }>(this.#sdk, 'I_UpgradeProgress', targetDeviceId)\n  }\n\n  // ─────────────────────────── 透传 HTTP / 杂项 ───────────────────────────\n\n  /** 透传 ISAPI 请求到设备；登录后已持有认证信息，`auth` 通常无需显式传入。 */\n  async sendHttpRequest(\n    deviceId: string,\n    uri: string,\n    options: HttpRequestOptions = {},\n  ): Promise<Document | null> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(uri, '请求 URI')\n    const sdkOptions: SdkAjaxOptions & Record<string, unknown> = {\n      type: options.method,\n      data: options.body,\n      async: options.async,\n    }\n    if (options.auth !== true && options.auth !== undefined)\n      sdkOptions.auth = options.auth\n    const raw = await callWithCallback<unknown>(this.#sdk, 'I_SendHTTPRequest', deviceId, uri, sdkOptions)\n    return ensureXmlDocument(raw)\n  }\n\n  /** 通道字符叠加配置（OSD 文字）。 */\n  async getTextOverlay(deviceId: string, uri: string): Promise<Document | null> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    ensureNonEmpty(uri, '叠加信息 URI')\n    const raw = await callWithCallback<unknown>(this.#sdk, 'I_GetTextOverlay', uri, deviceId, {})\n    return ensureXmlDocument(raw)\n  }\n\n  /** 打开系统文件 / 文件夹对话框；`szFileName === '-1'` 表示用户取消。 */\n  async openFileDialog(type: 0 | 1): Promise<OpenFileDialogResult> {\n    this.#ensureInitialized()\n    ensureIntegerInRange(type, 0, 1, '文件对话框类型')\n    return callPromise<OpenFileDialogResult>(this.#sdk, 'I2_OpenFileDlg', type)\n  }\n\n  // ─────────────────────────── 内部辅助 ───────────────────────────\n\n  #ensureInitialized(): void {\n    if (!this.#initialized)\n      throw new HikError('NOT_INITIALIZED', '请先调用 init() 完成插件初始化')\n  }\n\n  #ensureDevice(deviceId: string): void {\n    if (!this.#devices.has(deviceId))\n      throw new HikError('DEVICE_NOT_FOUND', `设备未登录或已登出：${deviceId}`)\n  }\n\n  #windowIndex(windowIndex: number | undefined): number {\n    const target = windowIndex ?? this.#activeWindow\n    if (!Number.isInteger(target) || target < 0 || target > 15) {\n      throw new HikError('INVALID_ARGUMENT', '窗口索引必须是 0 - 15 的整数', {\n        windowIndex: target,\n      })\n    }\n    return target\n  }\n\n  #playingWindowIndex(windowIndex: number | undefined): number {\n    const target = this.#windowIndex(windowIndex)\n    if (!this.getWindowStatus(target))\n      throw new HikError('WINDOW_NOT_PLAYING', `窗口 ${target} 未在播放`)\n    return target\n  }\n\n  async #stopWindowIfPlaying(windowIndex: number): Promise<void> {\n    if (this.getWindowStatus(windowIndex))\n      await this.stop(windowIndex)\n  }\n\n  #resolveDeviceId(deviceId: string | undefined): string {\n    if (deviceId) {\n      this.#ensureDevice(deviceId)\n      return deviceId\n    }\n    if (this.#devices.size === 1)\n      return this.#devices.keys().next().value as string\n    throw new HikError('INVALID_ARGUMENT', '请指定 deviceId')\n  }\n\n  /** 获取并解析 SDK XML 响应。 */\n  async #fetchXml(method: string, deviceId: string): Promise<Document | null> {\n    this.#ensureInitialized()\n    this.#ensureDevice(deviceId)\n    const raw = await callWithCallback<unknown>(this.#sdk, method, deviceId, {})\n    return ensureXmlDocument(raw)\n  }\n\n  async #ptzCommand(options: PtzControlOptions, stop: boolean): Promise<void> {\n    const speed = clampPtzSpeed(options.speed)\n    const windowIndex = this.#playingWindowIndex(options.windowIndex)\n    await callWithCallback<unknown>(this.#sdk, 'I_PTZControl', options.action, stop, {\n      iWndIndex: windowIndex,\n      iPTZSpeed: speed,\n    })\n  }\n\n  /** 登出前关闭设备相关的全部窗口流，并清空 SecretKey。 */\n  async #stopDeviceStreams(deviceId: string): Promise<void> {\n    const windows = (callSync<SdkWindowInfo[]>(this.#sdk, 'I_GetWndSet') ?? []).filter((wnd): wnd is SdkWindowInfo => {\n      if (!wnd)\n        return false\n      if (wnd.szDeviceIdentify === deviceId)\n        return true\n      // 兼容老版本 SDK：szDeviceIdentify 缺失时按 IP 前缀匹配\n      return Boolean(wnd.szIP && deviceId.startsWith(`${wnd.szIP}_`))\n    })\n\n    await Promise.all(windows.map(async (wnd) => {\n      try {\n        await callWithCallback<unknown>(this.#sdk, 'I_Stop', { iWndIndex: wnd.iIndex })\n      }\n      catch (err) {\n        console.warn(`[hikvideoctrl] 停止窗口 ${wnd.iIndex} 失败`, err)\n      }\n      try {\n        await callPromise<unknown>(this.#sdk, 'I_SetSecretKey', '', wnd.iIndex)\n      }\n      catch {\n        // 未启用加密的设备调用清除会返回失败，忽略\n      }\n    }))\n  }\n}\n\n// ─────────────────────────── 工厂 / 工具 ───────────────────────────\n\n/** 创建 `HikPlayer` 实例的工厂函数，便于注入 SDK 替身。 */\nexport function createHikPlayer(options: HikPlayerOptions = {}): HikPlayer {\n  return new HikPlayer(options)\n}\n\n/** 不创建实例的情况下检测浏览器是否支持无插件模式。 */\nexport function isNoPluginSupported(): boolean {\n  if (typeof window === 'undefined')\n    return false\n  return Boolean(window.WebVideoCtrl?.I_SupportNoPlugin?.())\n}\n\n// ─────────────────────────── 私有工具 ───────────────────────────\n\nfunction clampPtzSpeed(speed: number | undefined): number {\n  if (speed === undefined || !Number.isFinite(speed))\n    return PTZ_SPEED_RANGE.default\n  const value = Math.trunc(speed)\n  if (value < PTZ_SPEED_RANGE.min || value > PTZ_SPEED_RANGE.max) {\n    throw new HikError(\n      'INVALID_ARGUMENT',\n      `PTZ 速度取值范围应在 ${PTZ_SPEED_RANGE.min} - ${PTZ_SPEED_RANGE.max} 之间`,\n      { speed },\n    )\n  }\n  return value\n}\n\nfunction ensureLayout(layout: number): void {\n  ensureIntegerInRange(layout, 1, 4, '分屏布局')\n}\n\nfunction ensureIntegerInRange(\n  value: unknown,\n  min: number,\n  max: number,\n  label: string,\n): number {\n  if (!Number.isInteger(value) || (value as number) < min || (value as number) > max) {\n    throw new HikError('INVALID_ARGUMENT', `${label}必须是 ${min} - ${max} 的整数`, {\n      received: value,\n    })\n  }\n  return value as number\n}\n\nfunction ensurePositiveInteger(value: unknown, label: string): number {\n  if (!Number.isInteger(value) || (value as number) < 1) {\n    throw new HikError('INVALID_ARGUMENT', `${label}必须是正整数`, { received: value })\n  }\n  return value as number\n}\n\nfunction ensureNonEmpty(value: string, label: string): void {\n  if (!value.trim())\n    throw new HikError('INVALID_ARGUMENT', `${label}不能为空`)\n}\n\nfunction toPublicWindow(raw: SdkWindowInfo): PublicWindowStatus {\n  return {\n    index: raw.iIndex,\n    deviceId: typeof raw.szDeviceIdentify === 'string' ? raw.szDeviceIdentify : (raw.szIP ?? ''),\n    channelId: raw.iChannelID,\n    playStatus: raw.iPlayStatus,\n    raw,\n  }\n}\n\n/** `2013-12-23T03:06:58Z` → `2013-12-23 03:06:58`。 */\nfunction normalizeIsoLikeTime(value: string): string {\n  return value.replace('T', ' ').replace('Z', '')\n}\n\n/** 抽取 `playbackURI` 中 `name=` 与 `&size=` 之间的录像文件名。 */\nfunction extractFileNameFromUri(uri: string): string {\n  const nameIdx = uri.indexOf('name=')\n  if (nameIdx < 0)\n    return ''\n  const sizeIdx = uri.indexOf('&size=', nameIdx)\n  return sizeIdx > 0 ? uri.slice(nameIdx + 5, sizeIdx) : uri.slice(nameIdx + 5)\n}\n"],"names":["PROTOCOL","DEFAULT_PORT","STREAM_TYPE","LAYOUT","PLAY_STATUS","PTZ_COMMAND","PTZ_SPEED_RANGE","RECORD_SEARCH_PAGE_SIZE","FILE_DIALOG","RESTORE_MODE","TRANSCODE_FRAME_RATE","TRANSCODE_RESOLUTION","TRANSCODE_BITRATE","PLUGIN_EVENT","SDK_RUNTIME_ERROR","HikError","code","message","details","cause","toHikError","error","fallbackCode","fallbackMessage","TypedEmitter","event","handler","bag","wrapper","payload","err","callSync","sdk","method","args","fn","resolveMethod","callPromise","raw","isThenable","value","callWithCallback","resolve","reject","settled","finishOk","data","finishErr","i","isPlainObject","userSuccess","userError","status","xmlDoc","native","buildCallbackError","ret","loadWebVideoCtrl","scriptUrl","options","existing","timeout","strategy","cleanupTimer","onReady","onFail","absoluteUrl","reused","script","proto","serializeXml","doc","formatDate","date","pattern","dict","pad2","t","currentTimestamp","todayTimeRange","base","isValidTimeRange","start","end","s","parseSdkTime","e","isIPv4","isIPv6","host","parsed","isHostname","label","isValidHost","isValidPort","port","normalizePort","makeDeviceIdentify","parseDeviceIdentify","identify","idx","toProtocolValue","protocol","resolveContainer","input","id","element","randomId","normalizeSize","axis","fallback","trimmed","measured","measure","num","rect","parseXml","xml","ensureXmlDocument","isDocument","responseXML","responseText","stringifyXml","xmlText","selector","uniqueFileName","prefix","extension","match","yearText","monthText","dayText","hourText","minuteText","secondText","year","month","day","hour","minute","second","HikPlayer","#sdk","#emitter","#devices","#initialized","#initializing","#containerId","#containerElement","#activeWindow","containerId","width","height","layout","ensureLayout","settle","timer","fail","initOptions","index","fullScreen","eventType","windowIndex","param2","errorCode","result","#ensureInitialized","w","h","enable","#windowIndex","toPublicWindow","credentials","ajax","session","deviceId","#ensureDevice","#stopDeviceStreams","#fetchXml","node","online","analog","digital","zero","channel","ensurePositiveInteger","streamType","ensureIntegerInRange","#stopWindowIfPlaying","sdkOptions","rtspPort","target","#playingWindowIndex","volume","onZoomInfo","secretKey","fileName","ensureNonEmpty","onData","onDataTask","requestedFileName","baseFileName","hasWidth","hasHeight","searchPos","matches","playbackUri","normalizeIsoLikeTime","extractFileNameFromUri","item","count","#ptzCommand","action","presetId","password","mode","targetDeviceId","#resolveDeviceId","uri","type","stop","speed","clampPtzSpeed","windows","wnd","createHikPlayer","isNoPluginSupported","min","max","nameIdx","sizeIdx"],"mappings":"qOAQO,MAAMA,EAAW,CACtB,KAAM,EACN,MAAO,CACT,EAEaC,EAAe,CAC1B,KAAM,GACN,MAAO,IACP,KAAM,GACR,EAKaC,GAAc,CACzB,KAAM,EACN,IAAK,EACL,MAAO,CACT,EAOaC,GAAS,CACpB,OAAQ,EACR,KAAM,EACN,KAAM,EACN,QAAS,CACX,EAGaC,GAAc,CACzB,KAAM,EACN,QAAS,EACT,SAAU,EACV,OAAQ,EACR,YAAa,EACb,QAAS,EACT,cAAe,CACjB,EASaC,GAAc,CACzB,GAAI,EACJ,KAAM,EACN,KAAM,EACN,MAAO,EACP,OAAQ,EACR,SAAU,EACV,QAAS,EACT,UAAW,EAEX,QAAS,EACT,OAAQ,GACR,QAAS,GACT,SAAU,GACV,UAAW,GACX,SAAU,GACV,UAAW,EACb,EAGaC,EAAkB,CAAE,IAAK,EAAG,IAAK,EAAG,QAAS,CAAA,EAK7CC,EAA0B,GAG1BC,GAAc,CACzB,UAAW,EACX,KAAM,CACR,EAOaC,GAAe,CAC1B,MAAO,QACP,KAAM,MACR,EAKaC,GAAuB,CAClC,IAAK,IACL,KAAM,IACN,KAAM,IACN,KAAM,IACN,KAAM,IACN,KAAM,IACN,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,KAAM,KACR,EAGaC,GAAuB,CAClC,IAAK,IACL,KAAM,IAEN,GAAI,IACJ,KAAM,KACR,EAGaC,GAAoB,CAC/B,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,IAAK,IACL,KAAM,IACN,KAAM,IACN,KAAM,IACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,KAAM,KACN,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,MAAO,KACP,KAAM,KACR,EAKaC,GAAe,CAE1B,aAAc,EAEd,YAAa,EAEb,cAAe,EAEf,YAAa,EACf,EAGaC,GAAoB,OAAO,OAAO,CAC7C,KAAM,WACN,KAAM,OACN,KAAM,cACN,KAAM,WACN,KAAM,WACN,KAAM,gCACN,KAAM,sBACN,KAAM,SACN,KAAM,aACN,KAAM,aACN,KAAM,sBACN,KAAM,SACN,KAAM,iBACN,KAAM,SACN,KAAM,cACN,KAAM,SACN,KAAM,OACN,KAAM,YACN,KAAM,UACN,KAAM,qBACN,KAAM,OACN,KAAM,mCACR,CAAC,EC1JM,MAAMC,UAAiB,KAAM,CAChB,KAAO,WAChB,KACA,QAET,YACEC,EACAC,EACAC,EACAC,EACA,CACA,MAAMF,EAASE,IAAU,OAAY,OAAY,CAAE,MAAAA,EAAO,EAC1D,KAAK,KAAOH,EACZ,KAAK,QAAUE,EAEf,OAAO,eAAe,KAAM,WAAW,SAAS,CAClD,CACF,CAGO,SAASE,GACdC,EACAC,EAA6B,kBAC7BC,EAA0B,YAChB,CACV,GAAIF,aAAiBN,EACnB,OAAOM,EACT,MAAMJ,EAAUI,aAAiB,MAAQA,EAAM,QAAUE,EACzD,OAAO,IAAIR,EAASO,EAAcL,EAAS,OAAWI,CAAK,CAC7D,CClEO,MAAMG,EAAmD,CAC7C,cAAgB,IAGjC,GAA6BC,EAAUC,EAAgD,CACrF,MAAMC,EAAM,KAAK,UAAU,IAAIF,CAAK,OAAS,IAC7C,OAAAE,EAAI,IAAID,CAAgC,EACxC,KAAK,UAAU,IAAID,EAAOE,CAAG,EACtB,IAAM,KAAK,IAAIF,EAAOC,CAAO,CACtC,CAGA,KAA+BD,EAAUC,EAAgD,CACvF,MAAME,EAAsCC,GAAY,CACtD,KAAK,IAAIJ,EAAOG,CAAO,EACvBF,EAAQG,CAAO,CACjB,EACA,OAAO,KAAK,GAAGJ,EAAOG,CAAO,CAC/B,CAGA,IAA8BH,EAAUC,EAA2C,CACjF,MAAMC,EAAM,KAAK,UAAU,IAAIF,CAAK,EACpC,GAAKE,EAEL,IAAI,CAACD,EAAS,CACZ,KAAK,UAAU,OAAOD,CAAK,EAC3B,MACF,CACAE,EAAI,OAAOD,CAAgC,EACvCC,EAAI,OAAS,GACf,KAAK,UAAU,OAAOF,CAAK,EAC/B,CAGA,KAA+BA,EAAUI,EAA4B,CACnE,MAAMF,EAAM,KAAK,UAAU,IAAIF,CAAK,EACpC,GAAKE,GAAK,KAGV,UAAWD,IAAW,CAAC,GAAGC,CAAG,EAC3B,GAAI,CACFD,EAAQG,CAAO,CACjB,OACOC,EAAK,CACV,QAAQ,MAAM,qBAAqB,OAAOL,CAAK,CAAC,WAAYK,CAAG,CACjE,CAEJ,CAGA,OAAc,CACZ,KAAK,UAAU,MAAA,CACjB,CACF,CCqKO,SAASC,EAAYC,EAAsBC,KAAmBC,EAAoB,CACvF,MAAMC,EAAKC,EAAcJ,EAAKC,CAAM,EACpC,GAAI,CACF,OAAOE,EAAG,MAAMH,EAAKE,CAAI,CAC3B,OACOb,EAAO,CACZ,MAAM,IAAIN,EAAS,kBAAmB,MAAMkB,CAAM,MAAO,CAAE,OAAAA,CAAA,EAAUZ,CAAK,CAC5E,CACF,CAMO,SAASgB,EAAeL,EAAsBC,KAAmBC,EAA6B,CACnG,MAAMC,EAAKC,EAAcJ,EAAKC,CAAM,EACpC,IAAIK,EACJ,GAAI,CACFA,EAAMH,EAAG,MAAMH,EAAKE,CAAI,CAC1B,OACOb,EAAO,CACZ,OAAO,QAAQ,OAAO,IAAIN,EAAS,kBAAmB,MAAMkB,CAAM,MAAO,CAAE,OAAAA,CAAA,EAAUZ,CAAK,CAAC,CAC7F,CACA,OAAIiB,IAAQ,GACH,QAAQ,OAAO,IAAIvB,EAAS,kBAAmB,GAAGkB,CAAM,WAAY,CACzE,OAAAA,EACA,YAAaK,CAAA,CACd,CAAC,EAECC,GAAWD,CAAG,EAEZ,QAAQ,QAAQA,CAAG,EAAE,KAC1BE,GAASA,EACRrB,GAAU,CACT,MAAM,IAAIJ,EAAS,kBAAmB,MAAMkB,CAAM,MAAO,CAAE,OAAAA,CAAA,EAAUd,CAAK,CAC5E,CAAA,EALO,QAAQ,QAAQmB,CAAQ,CAOnC,CASO,SAASG,EACdT,EACAC,KACGC,EACS,CACZ,MAAMC,EAAKC,EAAcJ,EAAKC,CAAM,EAEpC,OAAO,IAAI,QAAW,CAACS,EAASC,IAAW,CACzC,IAAIC,EAAU,GACd,MAAMC,EAAYC,GAAY,CACxBF,IAEJA,EAAU,GACVF,EAAQI,CAAI,EACd,EACMC,EAAajB,GAAkB,CAC/Bc,IAEJA,EAAU,GACVD,EAAOb,CAAG,EACZ,EAEA,IAAIH,EAAsC,KAC1C,QAASqB,EAAId,EAAK,OAAS,EAAGc,GAAK,EAAGA,GAAK,EACzC,GAAIC,GAAcf,EAAKc,CAAC,CAAC,EAAG,CAC1BrB,EAAMO,EAAKc,CAAC,EACZ,KACF,CAEGrB,IACHA,EAAM,CAAA,EACNO,EAAK,KAAKP,CAAG,GAGf,MAAMuB,EAAcvB,EAAI,QAClBwB,EAAYxB,EAAI,MAItBA,EAAI,QAAWmB,GAAkB,CAC/B,GAAI,CACFI,IAAcJ,CAAI,CACpB,OACOhB,EAAK,CACV,QAAQ,MAAM,kBAAkBG,CAAM,kBAAmBH,CAAG,CAC9D,CACAe,EAASC,CAAS,CACpB,EAEAnB,EAAI,MAAQ,CAACyB,EAAiBC,EAA0BC,IAAqB,CAC3E,GAAI,CACFH,IAAYC,EAAQC,EAAQC,CAAM,CACpC,OACOxB,EAAK,CACV,QAAQ,MAAM,kBAAkBG,CAAM,gBAAiBH,CAAG,CAC5D,CACAiB,EAAUQ,GAAmBtB,EAAQmB,EAAQC,EAAQC,CAAM,CAAC,CAC9D,EAEA,GAAI,CACF,MAAME,EAAMrB,EAAG,MAAMH,EAAKE,CAAI,EAC1B,CAACU,GAAW,OAAOY,GAAQ,UAAYA,IAAQ,IACjDT,EAAU,IAAIhC,EAAS,kBAAmB,GAAGkB,CAAM,WAAY,CAC7D,OAAAA,EACA,YAAauB,CAAA,CACd,CAAC,CAEN,OACOnC,EAAO,CACZ0B,EAAU,IAAIhC,EAAS,kBAAmB,MAAMkB,CAAM,MAAO,CAAE,OAAAA,CAAA,EAAUZ,CAAK,CAAC,CACjF,CACF,CAAC,CACH,CAuBO,SAASoC,GACdC,EACAC,EAAmC,GACT,CAC1B,GAAI,OAAO,OAAW,IACpB,OAAO,QAAQ,OACb,IAAI5C,EAAS,qBAAsB,8BAA8B,CAAA,EAIrE,MAAM6C,EAAY,OAA8C,aAChE,GAAIA,EACF,OAAO,QAAQ,QAAQA,CAAQ,EAEjC,MAAMC,EAAUF,EAAQ,SAAW,KAC7BG,EAAWH,EAAQ,UAAY,QACrC,MAAI,CAAC,OAAO,SAASE,CAAO,GAAKA,GAAW,EACnC,QAAQ,OACb,IAAI9C,EAAS,mBAAoB,gBAAiB,CAAE,QAAA8C,EAAS,CAAA,EAI1D,IAAI,QAAyB,CAACnB,EAASC,IAAW,CACvD,MAAMoB,EAAe,OAAO,WAAW,IAAM,CAC3CpB,EAAO,IAAI5B,EAAS,qBAAsB,MAAM2C,CAAS,OAAOG,CAAO,KAAK,CAAC,CAC/E,EAAGA,CAAO,EAEJG,EAAU,IAAM,CACpB,OAAO,aAAaD,CAAY,EAChC,MAAM/B,EAAO,OAA8C,aACvDA,EACFU,EAAQV,CAAG,EAEXW,EAAO,IAAI5B,EAAS,qBAAsB,GAAG2C,CAAS,gCAAgC,CAAC,CAC3F,EAEMO,EAAU9C,GAAmB,CACjC,OAAO,aAAa4C,CAAY,EAChCpB,EAAO,IAAI5B,EAAS,qBAAsB,MAAM2C,CAAS,MAAO,CAAE,IAAKA,CAAA,EAAavC,CAAK,CAAC,CAC5F,EAEA,GAAI2C,IAAa,QAAS,CACxB,MAAMI,EAAc,IAAI,IAAIR,EAAW,SAAS,OAAO,EAAE,KACnDS,EAAS,MAAM,KAAK,SAAS,OAAO,EAAE,KAAKC,GAAUA,EAAO,MAAQF,CAAW,EACrF,GAAIC,EAAQ,CACVA,EAAO,iBAAiB,OAAQH,EAAS,CAAE,KAAM,GAAM,EACvDG,EAAO,iBAAiB,QAASF,EAAQ,CAAE,KAAM,GAAM,EACvD,MACF,CACF,CAEA,MAAMG,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,IAAMV,EACbU,EAAO,MAAQ,GACfA,EAAO,iBAAiB,OAAQJ,EAAS,CAAE,KAAM,GAAM,EACvDI,EAAO,iBAAiB,QAASH,EAAQ,CAAE,KAAM,GAAM,EACvD,SAAS,KAAK,YAAYG,CAAM,CAClC,CAAC,CACH,CAIA,SAAShC,EAAcJ,EAAsBC,EAAiD,CAC5F,MAAME,EAAMH,EAAgCC,CAAM,EAClD,GAAI,OAAOE,GAAO,WAChB,MAAM,IAAIpB,EAAS,qBAAsB,gBAAgBkB,CAAM,YAAa,CAC1E,OAAAA,CAAA,CACD,EAEH,OAAOE,CACT,CAEA,SAASI,GAAWC,EAA+C,CACjE,OACE,OAAOA,GAAU,UACdA,IAAU,MACV,OAAQA,EAA6B,MAAS,UAErD,CAEA,SAASS,GAAcT,EAAkD,CACvE,GAAI,OAAOA,GAAU,UAAYA,IAAU,MAAQ,MAAM,QAAQA,CAAK,EACpE,MAAO,GACT,MAAM6B,EAAQ,OAAO,eAAe7B,CAAK,EACzC,OAAO6B,IAAU,OAAO,WAAaA,IAAU,IACjD,CAEA,SAASd,GACPtB,EACAmB,EACAC,EACAC,EACU,CACV,MAAMrC,EACF,OAAOmC,GAAW,SAChB,GAAGnB,CAAM,cAAcmB,CAAM,IAC7B,GAAGnB,CAAM,QACf,OAAO,IAAIlB,EACT,kBACAE,EACA,CACE,OAAAgB,EACA,OAAAmB,EACA,GAAIC,EAAS,CAAE,YAAaiB,GAAajB,CAAM,GAAM,IAAA,EAEvDC,CAAA,CAEJ,CAEA,SAASgB,GAAaC,EAAuB,CAC3C,GAAI,OAAO,cAAkB,IAC3B,MAAO,GACT,GAAI,CACF,OAAO,IAAI,cAAA,EAAgB,kBAAkBA,CAAG,CAClD,MACM,CACJ,MAAO,EACT,CACF,CC5dO,SAASC,EAAWC,EAAYC,EAAkB,sBAA+B,CACtF,MAAMC,EAA+B,CACnC,KAAM,OAAOF,EAAK,aAAa,EAC/B,GAAIG,EAAKH,EAAK,SAAA,EAAa,CAAC,EAC5B,GAAIG,EAAKH,EAAK,SAAS,EACvB,GAAIG,EAAKH,EAAK,UAAU,EACxB,GAAIG,EAAKH,EAAK,YAAY,EAC1B,GAAIG,EAAKH,EAAK,YAAY,EAC1B,IAAK,OAAOA,EAAK,gBAAA,CAAiB,EAAE,SAAS,EAAG,GAAG,CAAA,EAErD,OAAOC,EAAQ,QAAQ,8BAAiCC,EAAKE,CAAC,GAAKA,CAAC,CACtE,CAGO,SAASC,GAAiBJ,EAAkB,sBAA+B,CAChF,OAAOF,EAAW,IAAI,KAAQE,CAAO,CACvC,CAGO,SAASK,IAAiD,CAC/D,MAAMC,EAAOR,EAAW,IAAI,KAAQ,YAAY,EAChD,MAAO,CAAE,MAAO,GAAGQ,CAAI,YAAa,IAAK,GAAGA,CAAI,WAAA,CAClD,CAGO,SAASC,EAAiBC,EAAeC,EAAsB,CACpE,MAAMC,EAAIC,EAAaH,CAAK,EACtBI,EAAID,EAAaF,CAAG,EAC1B,OAAOC,IAAM,MAAQE,IAAM,MAAQA,GAAKF,CAC1C,CAKO,SAASG,EAAO/C,EAAwB,CAC7C,MAAO,gFAAgF,KAAKA,CAAK,CACnG,CAGO,SAASgD,EAAOhD,EAAwB,CAC7C,MAAMiD,EAAOjD,EAAM,WAAW,GAAG,GAAKA,EAAM,SAAS,GAAG,EAAIA,EAAM,MAAM,EAAG,EAAE,EAAIA,EACjF,GAAI,CAACiD,EAAK,SAAS,GAAG,EACpB,MAAO,GACT,GAAI,CACF,MAAMC,EAAS,IAAI,IAAI,WAAWD,CAAI,IAAI,EAAE,SAC5C,OAAOC,EAAO,WAAW,GAAG,GAAKA,EAAO,SAAS,GAAG,CACtD,MACM,CACJ,MAAO,EACT,CACF,CAGO,SAASC,EAAWnD,EAAwB,CAGjD,MAFI,CAACA,GAASA,EAAM,OAAS,KAAOA,EAAM,SAAS,GAAG,GAElD,WAAW,KAAKA,CAAK,EAChB,GACFA,EAAM,MAAM,GAAG,EAAE,MAAMoD,GAC5BA,EAAM,QAAU,GACbA,EAAM,QAAU,IAChB,qCAAqC,KAAKA,CAAK,CACnD,CACH,CAGO,SAASC,EAAYJ,EAAuB,CACjD,OAAKA,EAEDA,IAAS,YACJ,GACFF,EAAOE,CAAI,GAAKD,EAAOC,CAAI,GAAKE,EAAWF,CAAI,EAH7C,EAIX,CAGO,SAASK,EAAYC,EAAuB,CACjD,OAAO,OAAO,UAAUA,CAAI,GAAKA,GAAQ,GAAKA,GAAQ,KACxD,CAGO,SAASC,EAAcD,EAAsB,CAClD,GAAI,CAACD,EAAYC,CAAI,EACnB,MAAM,IAAIhF,EAAS,mBAAoB,qBAAsB,CAAE,SAAUgF,EAAM,EACjF,OAAOA,CACT,CAKO,SAASE,EAAmBR,EAAcM,EAAsB,CACrE,MAAO,GAAGN,CAAI,IAAIM,CAAI,EACxB,CAGO,SAASG,GAAoBC,EAAkD,CACpF,MAAMC,EAAMD,EAAS,YAAY,GAAG,EACpC,OAAIC,EAAM,EACD,CAAE,KAAMD,EAAU,KAAM,EAAA,EAC1B,CACL,KAAMA,EAAS,MAAM,EAAGC,CAAG,EAC3B,KAAM,OAAO,SAASD,EAAS,MAAMC,EAAM,CAAC,EAAG,EAAE,GAAK,EAAA,CAE1D,CAGO,SAASC,EAAgBC,EAAmC,CACjE,OAAOA,IAAa,QAAU,EAAI,CACpC,CAQO,SAASC,GAAiBC,EAG/B,CACA,GAAI,OAAOA,GAAU,SAAU,CAC7B,MAAMC,EAAKD,EAAM,WAAW,GAAG,EAAIA,EAAM,MAAM,CAAC,EAAIA,EACpD,GAAI,CAACC,EAAG,KAAA,EACN,MAAM,IAAI1F,EAAS,mBAAoB,cAAc,EACvD,MAAM2F,EAAU,OAAO,SAAa,IAAc,KAAO,SAAS,eAAeD,CAAE,EACnF,MAAO,CAAE,GAAAA,EAAI,QAAAC,CAAA,CACf,CAEA,GAAI,OAAO,YAAgB,KAAe,EAAEF,aAAiB,aAC3D,MAAM,IAAIzF,EAAS,mBAAoB,sBAAsB,EAE/D,OAAKyF,EAAM,KACTA,EAAM,GAAK,cAAcG,EAAA,CAAU,IAC9B,CAAE,GAAIH,EAAM,GAAI,QAASA,CAAA,CAClC,CAQO,SAASI,EACdpE,EACAkE,EACAG,EACAC,EACQ,CACR,GAAI,OAAOtE,GAAU,UAAY,OAAO,SAASA,CAAK,EACpD,OAAO,KAAK,IAAI,EAAG,KAAK,MAAMA,CAAK,CAAC,EAEtC,GAAI,OAAOA,GAAU,SAAU,CAC7B,MAAMuE,EAAUvE,EAAM,KAAA,EACtB,GAAI,qBAAqB,KAAKuE,CAAO,EACnC,OAAO,KAAK,MAAM,OAAO,WAAWA,CAAO,CAAC,EAC9C,GAAI,mBAAmB,KAAKA,CAAO,GAAKL,EAAS,CAC/C,MAAMM,EAAWC,EAAQP,EAASG,CAAI,EACtC,GAAIG,EAAW,EACb,OAAO,KAAK,MAAOA,EAAW,OAAO,WAAWD,CAAO,EAAK,GAAG,CACnE,CACA,MAAMG,EAAM,OAAO,WAAWH,CAAO,EACrC,GAAI,OAAO,SAASG,CAAG,GAAKA,EAAM,EAChC,OAAO,KAAK,MAAMA,CAAG,CACzB,CAEA,GAAIR,EAAS,CACX,MAAMM,EAAWC,EAAQP,EAASG,CAAI,EACtC,GAAIG,EAAW,EACb,OAAO,KAAK,MAAMA,CAAQ,CAC9B,CAEA,OAAOF,CACT,CAEA,SAASG,EAAQP,EAAsBG,EAAkC,CACvE,MAAMM,EAAOT,EAAQ,sBAAA,EACrB,OAAOG,IAAS,QAAUM,EAAK,MAAQA,EAAK,MAC9C,CAKO,SAASC,EAASC,EAAiD,CAGxE,GAFI,CAACA,GAED,OAAO,UAAc,IACvB,OAAO,KACT,GAAI,CACF,MAAM9C,EAAM,IAAI,UAAA,EAAY,gBAAgB8C,EAAK,UAAU,EAC3D,OAAO9C,EAAI,cAAc,aAAa,EAAI,KAAOA,CACnD,MACM,CACJ,OAAO,IACT,CACF,CAUO,SAAS+C,EAAkBd,EAAiC,CACjE,GAAI,CAACA,EACH,OAAO,KACT,GAAIe,EAAWf,CAAK,EAClB,OAAOA,EACT,GAAI,OAAOA,GAAU,SACnB,OAAOY,EAASZ,CAAK,EACvB,MAAMgB,EAAehB,EAAoC,YACzD,GAAIe,EAAWC,CAAW,EACxB,OAAOA,EACT,MAAMC,EAAgBjB,EAAqC,aAC3D,OAAI,OAAOiB,GAAiB,SACnBL,EAASK,CAAY,EACvB,IACT,CAGO,SAASC,GAAanD,EAA0C,CACrE,GAAI,CAACA,GAAO,OAAO,cAAkB,IACnC,MAAO,GACT,GAAI,CACF,MAAM8C,EAAM,IAAI,gBAAgB,kBAAkB9C,CAAG,EACrD,OAAO8C,EAAI,SAAS,OAAO,EAAIA,EAAM,yCAAyCA,CAAG,EACnF,MACM,CACJ,MAAO,EACT,CACF,CAGO,SAASM,EAAQpD,EAA4CqD,EAAkBd,EAAmB,GAAY,CACnH,OAAOvC,GAAK,cAAcqD,CAAQ,GAAG,aAAa,QAAUd,CAC9D,CAUO,SAASe,EAAeC,EAAgBC,EAA2B,CACxE,MAAO,GAAGD,CAAM,IAAI,KAAK,KAAK,IAAInB,EAAA,CAAU,IAAIoB,EAAU,QAAQ,MAAO,EAAE,CAAC,EAC9E,CAGO,SAASpB,GAAmB,CACjC,OAAI,WAAW,QAAQ,WACd,WAAW,OAAO,WAAA,EAAa,QAAQ,KAAM,EAAE,EAAE,MAAM,EAAG,CAAC,EAC7D,KAAK,SAAS,SAAS,EAAE,EAAE,MAAM,EAAG,EAAE,CAC/C,CAEA,SAAS/B,EAAKpC,EAAuB,CACnC,OAAO,OAAOA,CAAK,EAAE,SAAS,EAAG,GAAG,CACtC,CAEA,SAAS6C,EAAa7C,EAA8B,CAClD,MAAMwF,EAAQ,oDAAoD,KAAKxF,CAAK,EAC5E,GAAI,CAACwF,EACH,OAAO,KACT,KAAM,CAAA,CAAGC,EAAUC,EAAWC,EAASC,EAAUC,EAAYC,CAAU,EAAIN,EACrEO,EAAO,OAAON,CAAQ,EACtBO,EAAQ,OAAON,CAAS,EACxBO,EAAM,OAAON,CAAO,EACpBO,EAAO,OAAON,CAAQ,EACtBO,EAAS,OAAON,CAAU,EAC1BO,EAAS,OAAON,CAAU,EAC1B7D,EAAO,IAAI,KAAK8D,EAAMC,EAAQ,EAAGC,EAAKC,EAAMC,EAAQC,EAAQ,CAAC,EACnE,OACEnE,EAAK,gBAAkB8D,GACpB9D,EAAK,aAAe+D,EAAQ,GAC5B/D,EAAK,QAAA,IAAcgE,GACnBhE,EAAK,SAAA,IAAeiE,GACpBjE,EAAK,eAAiBkE,GACtBlE,EAAK,WAAA,IAAiBmE,EAElB,KAEFnE,EAAK,QAAA,CACd,CAEA,SAAS8C,EAAW/E,EAAmC,CACrD,MAAO,GACLA,GACG,OAAOA,GAAU,UAChBA,EAAiC,WAAa,GAC/C,OAAQA,EAAsC,eAAkB,WAEvE,CChPO,MAAMqG,CAAU,CACZC,GACAC,GAAW,IAAIvH,GACfwH,OAAe,IACxBC,GAAe,GACfC,GAAgB,GAChBC,GAA8B,KAC9BC,GAAwC,KACxCC,GAAgB,EAEhB,YAAY1F,EAA4B,GAAI,CAC1C,MAAM3B,EAAM2B,EAAQ,KAAQ,WAA+D,QAAQ,aACnG,GAAI,CAAC3B,EACH,MAAM,IAAIjB,EACR,gBACA,mEAAA,EAGJ,KAAK+H,GAAO9G,CACd,CAKA,IAAI,eAAyB,CAC3B,OAAO,KAAKiH,EACd,CAGA,IAAI,mBAA4B,CAC9B,OAAO,KAAKI,EACd,CAGA,IAAI,aAA6B,CAC/B,OAAO,KAAKF,EACd,CAGA,IAAI,KAAuB,CACzB,OAAO,KAAKL,EACd,CAGA,kBAA4B,CAC1B,MAAO,EAAQ,KAAKA,GAAK,oBAAA,CAC3B,CAGA,oBAA6B,CAC3B,OAAO/G,EAAiB,KAAK+G,GAAM,sBAAsB,CAC3D,CAUA,MAAM,KAAKnF,EAA2C,CACpD,GAAI,KAAKsF,IAAgB,KAAKC,GAC5B,MAAM,IAAInI,EAAS,sBAAuB,uBAAuB,EACnE,GAAI,CAAC,KAAK,iBAAA,EACR,MAAM,IAAIA,EAAS,gBAAiB,8CAA8C,EAEpF,KAAM,CAAE,GAAIuI,EAAa,QAAA5C,GAAYH,GAAiB5C,EAAQ,SAAS,EACjE4F,EAAQ3C,EAAcjD,EAAQ,MAAO+C,EAAS,QAAS,GAAG,EAC1D8C,EAAS5C,EAAcjD,EAAQ,OAAQ+C,EAAS,SAAU,GAAG,EAC7D+C,EAAS9F,EAAQ,QAAU,EACjC+F,EAAaD,CAAM,EACnB,MAAM5F,EAAUF,EAAQ,SAAW,KACnC,GAAI,CAAC,OAAO,SAASE,CAAO,GAAKA,GAAW,EAC1C,MAAM,IAAI9C,EAAS,mBAAoB,eAAgB,CAAE,QAAA8C,EAAS,EAEpE,KAAKqF,GAAgB,GAErB,MAAM,IAAI,QAAc,CAACxG,EAASC,IAAW,CAC3C,MAAMgH,EAAS,CAAE,KAAM,EAAA,EACvB,IAAIC,EACJ,MAAMC,EAAQ/H,GAAkB,CAC1B6H,EAAO,OAEXA,EAAO,KAAO,GACVC,IAAU,QACZ,aAAaA,CAAK,EACpB,KAAKV,GAAgB,GACrBvG,EAAOb,CAAG,EACZ,EACA8H,EAAQ,WAAW,IAAM,CACvBC,EAAK,IAAI9I,EACP,yBACA,eAAe8C,CAAO,MACtB,CAAE,OAAQ,eAAgB,QAAAA,CAAA,CAAQ,CACnC,CACH,EAAGA,CAAO,EAEV,MAAMiG,EAA8B,CAClC,WAAYL,EAEZ,UAAW,GACX,SAAU,GACV,UAAW,EACX,WAAY9F,EAAQ,WAAa,GACjC,gBAAiBA,EAAQ,cACzB,SAAWN,GAAqB,CAC9B,MAAM0G,EAAQ,OAAO,SAASpC,EAAQtE,EAAQ,YAAa,GAAG,EAAG,EAAE,GAAK,EACxE,KAAKgG,GAAgBU,EACrB,KAAKhB,GAAS,KAAK,kBAAmB,CAAE,YAAagB,EAAO,EAC5DpG,EAAQ,iBAAiBoG,CAAK,CAChC,EACA,iBAAkB,CAACA,EAAOC,IAAe,CACvC,KAAKjB,GAAS,KAAK,kBAAmB,CAAE,YAAagB,EAAO,WAAAC,EAAY,EACxErG,EAAQ,sBAAsBoG,EAAOC,CAAU,CACjD,EACA,QAAS,CAACC,EAAWC,EAAaC,IAAW,CAC3C,KAAKpB,GAAS,KAAK,eAAgB,CAAE,UAAAkB,EAAW,YAAAC,EAAa,OAAAC,EAAQ,EACrExG,EAAQ,UAAUsG,EAAWC,EAAaC,CAAM,CAClD,EACA,qBAAsB,CAACD,EAAaE,EAAW/I,IAAU,CACvD,KAAK0H,GAAS,KAAK,eAAgB,CAAE,YAAAmB,EAAa,UAAAE,EAAW,MAAA/I,EAAO,EACpEsC,EAAQ,UAAUuG,EAAaE,EAAW/I,CAAK,CACjD,EACA,kBAAmB,IAAM,CACvB,KAAK0H,GAAS,KAAK,0BAA2B,MAAS,EACvDpF,EAAQ,oBAAA,CACV,EACA,iBAAmBuG,GAAgB,CACjC,KAAKnB,GAAS,KAAK,0BAA2B,CAAE,YAAAmB,EAAa,EAC7DvG,EAAQ,mBAAmBuG,CAAW,CACxC,EACA,qBAAsB,IAAM,CAC1B,GAAI,CAAAP,EAAO,KAEX,GAAI,CACF,MAAMU,EAAS,KAAKvB,GAAK,qBAAqBQ,CAAW,EACzD,GAAIe,IAAW,EAAG,CAChBR,EAAK,IAAI9I,EAAS,kBAAmB,2BAA2BsJ,CAAM,GAAI,CACxE,OAAQ,uBACR,YAAaA,CAAA,CACd,CAAC,EACF,MACF,CACA,KAAKpB,GAAe,GACpB,KAAKC,GAAgB,GACrB,KAAKC,GAAeG,EACpB,KAAKF,GAAoB1C,EACzB,KAAKqC,GAAS,KAAK,qBAAsB,MAAS,EAClDY,EAAO,KAAO,GACVC,IAAU,QACZ,aAAaA,CAAK,EACpBlH,EAAA,CACF,OACOZ,EAAK,CACV+H,EAAK,IAAI9I,EAAS,kBAAmB,cAAe,CAAE,OAAQ,wBAA0Be,CAAG,CAAC,CAC9F,CACF,CAAA,EAGF,GAAI,CACF,KAAKgH,GAAK,aAAaS,EAAOC,EAAQM,CAAW,CACnD,OACOhI,EAAK,CACV+H,EAAK,IAAI9I,EAAS,kBAAmB,UAAW,CAAE,OAAQ,gBAAkBe,CAAG,CAAC,CAClF,CACF,CAAC,CACH,CAMA,MAAM,SAAyB,CAC7B,GAAK,KAAKmH,GAGV,IAAI,CACF,MAAM5G,EAAkB,KAAKyG,GAAM,WAAW,CAChD,OACOhH,EAAK,CACV,QAAQ,KAAK,6CAA8CA,CAAG,CAChE,CACA,GAAI,CACF,KAAKgH,GAAK,kBAAA,CACZ,OACOhH,EAAK,CACV,QAAQ,KAAK,wCAAyCA,CAAG,CAC3D,CACA,KAAKmH,GAAe,GACpB,KAAKE,GAAe,KACpB,KAAKC,GAAoB,KACzB,KAAKC,GAAgB,EACrB,KAAKL,GAAS,MAAA,EACd,KAAKD,GAAS,KAAK,mBAAoB,MAAS,EAChD,KAAKA,GAAS,MAAA,EAChB,CAGA,OAAOQ,EAAyBC,EAAgC,CAC9D,KAAKc,GAAA,EACL,MAAMC,EAAI3D,EAAc2C,EAAO,KAAKH,GAAmB,QAAS,CAAC,EAC3DoB,EAAI5D,EAAc4C,EAAQ,KAAKJ,GAAmB,SAAU,CAAC,EACnE,KAAKN,GAAK,WAAWyB,EAAGC,CAAC,CAC3B,CAKA,GACE/I,EACAC,EACY,CACZ,OAAO,KAAKqH,GAAS,GAAGtH,EAAOC,CAAO,CACxC,CAGA,KACED,EACAC,EACY,CACZ,OAAO,KAAKqH,GAAS,KAAKtH,EAAOC,CAAO,CAC1C,CAGA,IACED,EACAC,EACM,CACN,KAAKqH,GAAS,IAAItH,EAAOC,CAAO,CAClC,CAKA,MAAM,aAAa+H,EAA+B,CAChD,KAAKa,GAAA,EACLZ,EAAaD,CAAM,EACnB,MAAMpH,EAAkB,KAAKyG,GAAM,iBAAkBW,CAAM,CAC7D,CAMA,MAAM,WAAWgB,EAAkB,GAAqB,CAEtD,GADA,KAAKH,GAAA,EACD,CAACG,EAAQ,CACP,OAAO,SAAa,KAAe,SAAS,mBAC9C,MAAM,SAAS,eAAA,EACjB,MACF,CACA,MAAMpI,EAAkB,KAAKyG,GAAM,eAAgB2B,CAAM,CAC3D,CAGA,gBAAgBP,EAAsB,KAAKb,GAA0C,CACnF,KAAKiB,GAAA,EACL,MAAMhI,EAAMP,EAA+B,KAAK+G,GAAM,oBAAqB,KAAK4B,GAAaR,CAAW,CAAC,EACzG,OAAO5H,EAAMqI,EAAerI,CAAG,EAAI,IACrC,CAGA,eAAsC,CACpC,YAAKgI,GAAA,GACQvI,EAA0B,KAAK+G,GAAM,aAAa,GAAK,CAAA,GACxD,OAAO,OAAO,EAAE,IAAI6B,CAAc,CAChD,CAUA,MAAM,MAAMC,EAAwD,CAClE,KAAKN,GAAA,EAEL,MAAM7E,EAAOmF,EAAY,MAAM,KAAA,GAAU,GACzC,GAAI,CAACnF,EACH,MAAM,IAAI1E,EAAS,mBAAoB,UAAU,EACnD,GAAI,CAAC8E,EAAYJ,CAAI,EACnB,MAAM,IAAI1E,EAAS,mBAAoB,WAAW0E,CAAI,EAAE,EAC1D,GAAI,CAACmF,EAAY,SACf,MAAM,IAAI7J,EAAS,mBAAoB,SAAS,EAClD,GAAI6J,EAAY,WAAa,QAAaA,EAAY,WAAa,KACjE,MAAM,IAAI7J,EAAS,mBAAoB,QAAQ,EAEjD,MAAMuF,EAAWsE,EAAY,UAAY,OACzC,GAAItE,IAAa,QAAUA,IAAa,QACtC,MAAM,IAAIvF,EAAS,mBAAoB,YAAY,OAAOuF,CAAQ,CAAC,EAAE,EACvE,MAAMP,EAAOC,EAAc4E,EAAY,OAAStE,IAAa,QAAU,IAAM,GAAG,EAE1EuE,EAAuB,CAAA,EACzBD,EAAY,OAAO,QAAU,SAC/BC,EAAK,MAAQD,EAAY,MAAM,OAC7BA,EAAY,OAAO,MAAQ,SAC5BC,EAAiC,IAAMD,EAAY,MAAM,KAE5D,MAAMnI,EACJ,KAAKqG,GACL,UACArD,EACAY,EAAgBC,CAAQ,EACxBP,EACA6E,EAAY,SACZA,EAAY,SACZC,CAAA,EAGF,MAAMC,EAAyB,CAC7B,GAAI7E,EAAmBR,EAAMM,CAAI,EACjC,KAAAN,EACA,KAAAM,EACA,SAAAO,EACA,SAAUsE,EAAY,QAAA,EAExB,YAAK5B,GAAS,IAAI8B,EAAQ,GAAIA,CAAO,EACrC,KAAK/B,GAAS,KAAK,mBAAoB+B,CAAO,EACvCA,CACT,CAGA,MAAM,OAAOC,EAAiC,CAC5C,KAAKT,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAM,KAAKE,GAAmBF,CAAQ,EAEtC,MAAMV,EAAStI,EAAiB,KAAK+G,GAAM,WAAYiC,CAAQ,EAC/D,GAAIV,IAAW,EACb,MAAM,IAAItJ,EAAS,kBAAmB,MAAMgK,CAAQ,MAAO,CACzD,OAAQ,WACR,YAAaV,CAAA,CACd,EAEH,KAAKrB,GAAS,OAAO+B,CAAQ,EAC7B,KAAKhC,GAAS,KAAK,sBAAuB,CAAE,SAAAgC,EAAU,CACxD,CAGA,aAA+B,CAC7B,MAAO,CAAC,GAAG,KAAK/B,GAAS,QAAQ,CACnC,CAGA,UAAU+B,EAA6C,CACrD,OAAO,KAAK/B,GAAS,IAAI+B,CAAQ,CACnC,CAKA,MAAM,cAAcA,EAA8C,CAChE,KAAKT,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMzI,EAAM,MAAMG,EAA0B,KAAKqG,GAAM,kBAAmBiC,EAAU,EAAE,EAChFxG,EAAM+C,EAAkBhF,CAAG,EACjC,OAAKiC,EAEE,CACL,WAAYoD,EAAQpD,EAAK,YAAY,EACrC,SAAUoD,EAAQpD,EAAK,UAAU,EACjC,WAAYoD,EAAQpD,EAAK,YAAY,EACrC,MAAOoD,EAAQpD,EAAK,OAAO,EAC3B,aAAcoD,EAAQpD,EAAK,cAAc,EACzC,WAAYoD,EAAQpD,EAAK,YAAY,EACrC,gBAAiBoD,EAAQpD,EAAK,iBAAiB,EAC/C,qBAAsBoD,EAAQpD,EAAK,sBAAsB,EACzD,eAAgBoD,EAAQpD,EAAK,gBAAgB,EAC7C,oBAAqBoD,EAAQpD,EAAK,qBAAqB,EACvD,IAAKA,CAAA,EAZE,IAcX,CAGA,MAAM,mBAAmBwG,EAA4C,CACnE,OAAO,KAAKG,GAAU,uBAAwBH,CAAQ,CACxD,CAGA,cAAcA,EAA8B,CAC1C,KAAKT,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMzI,EAAMP,EAA+B,KAAK+G,GAAM,kBAAmBiC,CAAQ,EACjF,GAAI,CAACzI,EACH,MAAM,IAAIvB,EAAS,kBAAmB,MAAMgK,CAAQ,QAAS,CAC3D,OAAQ,iBAAA,CACT,EAEH,MAAO,CACL,YAAazI,EAAI,YACjB,UAAWA,EAAI,UACf,UAAWA,EAAI,UACf,eAAgBA,EAAI,eACpB,gBAAiBA,EAAI,eAAA,CAEzB,CAGA,MAAM,kBAAkByI,EAA0C,CAChE,MAAMxG,EAAM,MAAM,KAAK2G,GAAU,yBAA0BH,CAAQ,EACnE,OAAKxG,EAEE,MAAM,KAAKA,EAAI,iBAAiB,mBAAmB,CAAC,EAAE,IAAI,CAAC4G,EAAM/E,KAAS,CAC/E,GAAIuB,EAAQwD,EAAM,KAAM,OAAO/E,EAAM,CAAC,CAAC,EACvC,KAAMuB,EAAQwD,EAAM,OAAQ,UAAU,OAAO/E,EAAM,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,EACxE,KAAM,SACN,OAAQ,GACR,QAASuB,EAAQwD,EAAM,oBAAqB,MAAM,IAAM,QACxD,YAAaxD,EAAQwD,EAAM,aAAa,GAAK,MAAA,EAC7C,EARO,CAAA,CASX,CAGA,MAAM,mBAAmBJ,EAA0C,CACjE,MAAMxG,EAAM,MAAM,KAAK2G,GAAU,0BAA2BH,CAAQ,EACpE,OAAKxG,EAEE,MAAM,KAAKA,EAAI,iBAAiB,yBAAyB,CAAC,EAAE,IAAI,CAAC4G,EAAM/E,IAAQ,CACpF,MAAMgF,EAASzD,EAAQwD,EAAM,SAAU,OAAO,IAAM,OACpD,MAAO,CACL,GAAIxD,EAAQwD,EAAM,KAAM,OAAO/E,EAAM,CAAC,CAAC,EACvC,KAAMuB,EAAQwD,EAAM,OAAQ,YAAY,OAAO/E,EAAM,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,EAC1E,KAAM,UACN,OAAAgF,EACA,QAAS,EAAA,CAEb,CAAC,EAVQ,CAAA,CAWX,CAGA,MAAM,gBAAgBL,EAA0C,CAC9D,MAAMxG,EAAM,MAAM,KAAK2G,GAAU,uBAAwBH,CAAQ,EACjE,OAAKxG,EAEE,MAAM,KAAKA,EAAI,iBAAiB,kBAAkB,CAAC,EACvD,OAAO4G,GAAQxD,EAAQwD,EAAM,UAAW,OAAO,IAAM,MAAM,EAC3D,IAAI,CAACA,EAAM/E,KAAS,CACnB,GAAIuB,EAAQwD,EAAM,KAAM,OAAO/E,EAAM,CAAC,CAAC,EACvC,KAAMuB,EAAQwD,EAAM,OAAQ,gBAAgB,OAAO/E,EAAM,CAAC,EAAE,SAAS,EAAG,GAAG,CAAC,EAAE,EAC9E,KAAM,OACN,OAAQ,GACR,QAAS,EAAA,EACT,EATK,CAAA,CAUX,CAMA,MAAM,YAAY2E,EAA0C,CAC1D,KAAM,CAACM,EAAQC,EAASC,CAAI,EAAI,MAAM,QAAQ,IAAI,CAChD,KAAK,kBAAkBR,CAAQ,EAAE,MAAM,IAAM,CAAA,CAAmB,EAChE,KAAK,mBAAmBA,CAAQ,EAAE,MAAM,IAAM,CAAA,CAAmB,EACjE,KAAK,gBAAgBA,CAAQ,EAAE,MAAM,IAAM,CAAA,CAAmB,CAAA,CAC/D,EACD,MAAO,CAAC,GAAGM,EAAQ,GAAGC,EAAS,GAAGC,CAAI,CACxC,CAGA,MAAM,iBAAiBR,EAA4C,CACjE,OAAO,KAAKG,GAAU,iBAAkBH,CAAQ,CAClD,CAKA,MAAM,aAAaA,EAAkBpH,EAAwC,CAC3E,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAE3B,MAAMS,EAAUC,EAAsB9H,EAAQ,QAAS,KAAK,EACtD+H,EAAaC,EAAqBhI,EAAQ,YAAc,EAAG,EAAG,EAAG,MAAM,EACvEuG,EAAc,KAAKQ,GAAa/G,EAAQ,WAAW,EACzD,MAAM,KAAKiI,GAAqB1B,CAAW,EAC3C,MAAM2B,EAAsC,CAC1C,UAAW3B,EACX,WAAYsB,EACZ,YAAaE,EACb,aAAc/H,EAAQ,aAAe,EAAA,EAEvC,GAAIA,EAAQ,WAAa,OAAW,CAClC,MAAMmI,EAAW9F,EAAcrC,EAAQ,QAAQ,EAC/CkI,EAAW,UAAYC,CACzB,CACInI,EAAQ,gBAAkB,SAC5BkI,EAAW,QAAU7F,EAAcrC,EAAQ,aAAa,GACtDA,EAAQ,WAAa,SACvBkI,EAAW,OAASlI,EAAQ,UAE9B,MAAMlB,EAA0B,KAAKqG,GAAM,kBAAmBiC,EAAUc,CAAU,EAClF,KAAK9C,GAAS,KAAK,kBAAmB,CACpC,SAAAgC,EACA,QAAAS,EACA,YAAAtB,EACA,YAAavG,EAAQ,aAAe,EAAA,CACrC,CACH,CAGA,MAAM,KAAKuG,EAAqC,CAC9C,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKrB,GAAaR,CAAW,EACtC9G,EAAS,KAAK,gBAAgB2I,CAAM,EAC1C,GAAI,CAAC3I,EACH,MAAM,IAAIrC,EAAS,qBAAsB,MAAMgL,CAAM,OAAO,EAC9D,MAAMtJ,EAA0B,KAAKqG,GAAM,SAAU,CAAE,UAAWiD,EAAQ,EAE1E,MAAMtK,EAAQ2B,EAAO,aAAe,EAAI,mBAAqB,kBAC7D,KAAK2F,GAAS,KAAKtH,EAAO,CAAE,SAAU2B,EAAO,SAAU,YAAa2I,EAAQ,CAC9E,CAGA,MAAM,SAAyB,CAC7B,KAAKzB,GAAA,EACL,MAAMjI,EAAkB,KAAKyG,GAAM,WAAW,EAC9C,KAAKC,GAAS,KAAK,sBAAuB,MAAS,CACrD,CAKA,MAAM,cAAcgC,EAAkBpH,EAAyC,CAG7E,GAFA,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EACvB,CAAC9F,EAAiBtB,EAAQ,UAAWA,EAAQ,OAAO,EACtD,MAAM,IAAI5C,EAAS,mBAAoB,YAAY4C,EAAQ,SAAS,MAAMA,EAAQ,OAAO,EAAE,EAE7F,MAAM6H,EAAUC,EAAsB9H,EAAQ,QAAS,KAAK,EACtD+H,EAAaC,EAAqBhI,EAAQ,YAAc,EAAG,EAAG,EAAG,QAAQ,EACzEuG,EAAc,KAAKQ,GAAa/G,EAAQ,WAAW,EACzD,MAAM,KAAKiI,GAAqB1B,CAAW,EAC3C,MAAM2B,EAAsC,CAC1C,UAAW3B,EACX,WAAYsB,EACZ,YAAaE,EACb,YAAa/H,EAAQ,UACrB,UAAWA,EAAQ,OAAA,EAErB,GAAIA,EAAQ,WAAa,OAAW,CAClC,MAAMmI,EAAW9F,EAAcrC,EAAQ,QAAQ,EAC/CkI,EAAW,UAAYC,CACzB,CACInI,EAAQ,gBAAkB,SAC5BkI,EAAW,QAAU7F,EAAcrC,EAAQ,aAAa,GACtDA,EAAQ,WAAa,SACvBkI,EAAW,OAASlI,EAAQ,UAC9B,MAAMlB,EAA0B,KAAKqG,GAAM,kBAAmBiC,EAAUc,CAAU,EAClF,KAAK9C,GAAS,KAAK,mBAAoB,CACrC,SAAAgC,EACA,QAAAS,EACA,YAAAtB,EACA,UAAWvG,EAAQ,UACnB,QAASA,EAAQ,OAAA,CAClB,CACH,CAGA,MAAM,MAAMuG,EAAqC,CAC/C,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,UAAW,CACpD,UAAWiD,CAAA,CACZ,CACH,CAGA,MAAM,OAAO7B,EAAqC,CAChD,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,WAAY,CACrD,UAAWiD,CAAA,CACZ,CACH,CAGA,MAAM,SAAS7B,EAAqC,CAClD,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,aAAc,CACvD,UAAWiD,CAAA,CACZ,CACH,CAGA,MAAM,SAAS7B,EAAqC,CAClD,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,aAAc,CACvD,UAAWiD,CAAA,CACZ,CACH,CAGA,MAAM,WAAW7B,EAAuC,CACtD,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKC,GAAoB9B,CAAW,EAC7C5H,EAAM,MAAMG,EAA0B,KAAKqG,GAAM,eAAgB,CACrE,UAAWiD,CAAA,CACZ,EACD,OAAI,OAAOzJ,GAAQ,SACVA,EACLA,aAAe,KACVkC,EAAWlC,CAAG,EAChB,OAAOA,GAAO,EAAE,CACzB,CAKA,MAAM,UAAU4H,EAAqC,CACnD,KAAKI,GAAA,EACL,MAAMjI,EAAkB,KAAKyG,GAAM,cAAe,KAAKkD,GAAoB9B,CAAW,CAAC,CACzF,CAGA,MAAM,WAAWA,EAAqC,CACpD,KAAKI,GAAA,EACL,MAAMjI,EAAkB,KAAKyG,GAAM,eAAgB,KAAKkD,GAAoB9B,CAAW,CAAC,CAC1F,CAGA,MAAM,UAAU+B,EAAgB/B,EAAqC,CAEnE,GADA,KAAKI,GAAA,EACD,CAAC,OAAO,UAAU2B,CAAM,GAAKA,EAAS,GAAKA,EAAS,IACtD,MAAM,IAAIlL,EAAS,mBAAoB,oBAAqB,CAAE,OAAAkL,EAAQ,EACxE,MAAM5J,EAAkB,KAAKyG,GAAM,cAAemD,EAAQ,KAAKD,GAAoB9B,CAAW,CAAC,CACjG,CAGA,MAAM,YAAYA,EAAqC,CACrD,KAAKI,GAAA,EACL,MAAMjI,EAAqB,KAAKyG,GAAM,gBAAiB,KAAKkD,GAAoB9B,CAAW,CAAC,CAC9F,CAGA,MAAM,aAAaA,EAAqC,CACtD,KAAKI,GAAA,EACL,MAAMjI,EAAqB,KAAKyG,GAAM,iBAAkB,KAAKkD,GAAoB9B,CAAW,CAAC,CAC/F,CAMA,MAAM,aAAaA,EAAsBgC,EAAqD,CAC5F,KAAK5B,GAAA,EACL,MAAMjI,EACJ,KAAKyG,GACL,iBACA,KAAKkD,GAAoB9B,CAAW,EACpCgC,CAAA,CAEJ,CAGA,MAAM,cAAchC,EAAqC,CACvD,KAAKI,GAAA,EACL,MAAMD,EAAS,MAAMhI,EAAqB,KAAKyG,GAAM,kBAAmB,KAAKkD,GAAoB9B,CAAW,CAAC,EAC7G,GAAIG,IAAW,GACb,MAAM,IAAItJ,EAAS,kBAAmB,aAAc,CAClD,OAAQ,kBACR,YAAasJ,CAAA,CACd,CAEL,CAGA,MAAM,aAAa8B,EAAmBjC,EAAqC,CACzE,KAAKI,GAAA,EAEL,MAAMjI,EACJ,KAAKyG,GACL,iBACAqD,EACA,KAAKzB,GAAaR,CAAW,CAAA,CAEjC,CAYA,MAAM,QAAQvG,EAA0B,GAAqB,CAC3D,KAAK2G,GAAA,EACL,MAAMJ,EAAc,KAAK8B,GAAoBrI,EAAQ,WAAW,EAC1DyI,EAAWzI,EAAQ,UAAYkE,EAAe,UAAW,KAAK,EACpEwE,EAAeD,EAAU,OAAO,EAChC,MAAME,EAAS3I,EAAQ,OACvB,IAAI4I,EAEJ,MAAMlC,EAAS,MAAMhI,EAAqB,KAAKyG,GAAM,gBAAiBsD,EAAU,CAC9E,UAAWlC,EACX,WAAYoC,EACPxJ,GAAqB,CACpB,GAAI,CACFyJ,EAAa,QAAQ,QAAQD,EAAOxJ,CAAI,CAAC,EAAE,KAAK,IAAA,EAAe,CACjE,OACOhB,EAAK,CACVyK,EAAa,QAAQ,OAAOzK,CAAG,CACjC,CACF,EACA,MAAA,CACL,EACD,GAAIuI,IAAW,GACb,MAAM,IAAItJ,EAAS,kBAAmB,OAAQ,CAC5C,OAAQ,gBACR,YAAasJ,CAAA,CACd,EAEH,aAAMkC,EACN,KAAKxD,GAAS,KAAK,oBAAqB,CACtC,SAAAqD,EACA,YAAAlC,EACA,OAAQ,CAACvG,EAAQ,MAAA,CAClB,EACMyI,CACT,CAGA,MAAM,cAAcrB,EAAkBpH,EAAgD,CACpF,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMS,EAAUC,EAAsB9H,EAAQ,QAAS,KAAK,EACtD6I,EAAoB7I,EAAQ,UAAYkE,EAAe,iBAAkB,KAAK,EACpFwE,EAAeG,EAAmB,OAAO,EACzC,MAAMC,EAAeD,EAAkB,QAAQ,YAAa,EAAE,EAC9DH,EAAeI,EAAc,OAAO,EACpC,MAAML,EAAW,GAAGK,CAAY,OAE1BC,EAAW/I,EAAQ,QAAU,OAC7BgJ,EAAYhJ,EAAQ,SAAW,OACrC,GAAI+I,IAAaC,EACf,MAAM,IAAI5L,EAAS,mBAAoB,iBAAiB,EAE1D,MAAM8K,EAAsC,CAC1C,SAAUlI,EAAQ,iBAAmB,EAAA,EAEnC+I,GAAYC,IACdd,EAAW,iBAAmBJ,EAAsB9H,EAAQ,MAAO,MAAM,EACzEkI,EAAW,kBAAoBJ,EAAsB9H,EAAQ,OAAQ,MAAM,GAG7E,MAAM0G,EAAStI,EACb,KAAK+G,GACL,qBACAiC,EACAS,EACAiB,EACAZ,CAAA,EAEF,GAAIxB,IAAW,EACb,MAAM,IAAItJ,EAAS,kBAAmB,SAAU,CAC9C,OAAQ,qBACR,YAAasJ,CAAA,CACd,EAEH,YAAKtB,GAAS,KAAK,2BAA4B,CAAE,SAAAgC,EAAU,QAAAS,EAAS,SAAAY,EAAU,EACvEA,CACT,CAGA,MAAM,eAAezI,EAA4B,GAAqB,CACpE,KAAK2G,GAAA,EACL,MAAMJ,EAAc,KAAK8B,GAAoBrI,EAAQ,WAAW,EAC1DyI,EAAWzI,EAAQ,UAAYkE,EAAe,SAAU,KAAK,EACnE,OAAAwE,EAAeD,EAAU,OAAO,EAChC,MAAM3J,EAA0B,KAAKqG,GAAM,gBAAiBsD,EAAU,CACpE,UAAWlC,EACX,SAAUvG,EAAQ,iBAAmB,EAAA,CACtC,EACD,KAAKoF,GAAS,KAAK,oBAAqB,CAAE,SAAAqD,EAAU,YAAAlC,EAAa,EAC1DkC,CACT,CAGA,MAAM,cAAclC,EAAqC,CACvD,KAAKI,GAAA,EACL,MAAMyB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,eAAgB,CAAE,UAAWiD,EAAQ,EAChF,KAAKhD,GAAS,KAAK,oBAAqB,CAAE,YAAagD,EAAQ,CACjE,CAQA,MAAM,cAAchB,EAAkBpH,EAA2D,CAG/F,GAFA,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EACvB,CAAC9F,EAAiBtB,EAAQ,UAAWA,EAAQ,OAAO,EACtD,MAAM,IAAI5C,EAAS,mBAAoB,YAAY4C,EAAQ,SAAS,MAAMA,EAAQ,OAAO,EAAE,EAE7F,MAAM6H,EAAUC,EAAsB9H,EAAQ,QAAS,KAAK,EACtD+H,EAAaC,EAAqBhI,EAAQ,YAAc,EAAG,EAAG,EAAG,QAAQ,EAC/E,GAAIA,EAAQ,OAAS,SAAc,CAAC,OAAO,UAAUA,EAAQ,IAAI,GAAKA,EAAQ,KAAO,GACnF,MAAM,IAAI5C,EAAS,mBAAoB,kBAAmB,CAAE,KAAM4C,EAAQ,KAAM,EAClF,GACEA,EAAQ,YAAc,SAClB,CAAC,OAAO,UAAUA,EAAQ,SAAS,GAClCA,EAAQ,UAAY,GACpBA,EAAQ,UAAYpD,IAA4B,GAErD,MAAM,IAAIQ,EACR,mBACA,oBAAoBR,CAAuB,OAC3C,CAAE,UAAWoD,EAAQ,SAAA,CAAU,EAInC,MAAMiJ,EACFjJ,EAAQ,YAAc,OACpBA,EAAQ,UACR,KAAK,IAAI,GAAIA,EAAQ,MAAQ,GAAK,CAAC,EAAIpD,EAEvC+B,EAAM,MAAMG,EAChB,KAAKqG,GACL,iBACAiC,EACAS,EACA7H,EAAQ,UACRA,EAAQ,QACR,CACE,YAAa+H,EACb,WAAYkB,CAAA,CACd,EAEIrI,EAAM+C,EAAkBhF,CAAG,EACjC,GAAI,CAACiC,EACH,MAAO,CACL,QAAS,CAAA,EACT,OAAQ,aACR,MAAO,EACP,IAAK,IAAI,UAAA,EAAY,gBAAgB,oBAAqB,UAAU,CAAA,EAGxE,MAAMnB,EAASuE,EAAQpD,EAAK,qBAAsB,YAAY,EACxDsI,EAAyB,MAAM,KAAKtI,EAAI,iBAAiB,iBAAiB,CAAC,EAC9E,IAAK4G,GAA6B,CACjC,MAAM2B,EAAcnF,EAAQwD,EAAM,aAAa,EAC/C,MAAI,CAAC2B,GAAe,CAACA,EAAY,SAAS,OAAO,EACxC,KACF,CACL,QAASnF,EAAQwD,EAAM,SAAS,EAChC,UAAW4B,EAAqBpF,EAAQwD,EAAM,WAAW,CAAC,EAC1D,QAAS4B,EAAqBpF,EAAQwD,EAAM,SAAS,CAAC,EACtD,SAAU6B,GAAuBF,CAAW,EAC5C,YAAAA,EACA,KAAOnF,EAAQwD,EAAM,oBAAoB,GAAK,QAAA,CAElD,CAAC,EACA,OAAQ8B,GAA8BA,IAAS,IAAI,EAChDC,EAAQ,OAAO,SAASvF,EAAQpD,EAAK,eAAgB,OAAOsI,EAAQ,MAAM,CAAC,EAAG,EAAE,EACtF,MAAO,CAAE,QAAAA,EAAS,OAAAzJ,EAAQ,MAAO,OAAO,SAAS8J,CAAK,EAAIA,EAAQL,EAAQ,OAAQ,IAAKtI,CAAA,CACzF,CAMA,MAAM,eACJwG,EACA+B,EACAV,EACAzI,EAA2B,CAAA,EACT,CAClB,YAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeS,EAAa,MAAM,EAClCT,EAAeD,EAAU,OAAO,EACzB/J,EACL,KAAKyG,GACL,wBACAiC,EACA+B,EACAV,EACA,CAAE,SAAUzI,EAAQ,iBAAmB,EAAA,CAAK,CAEhD,CAGA,MAAM,qBACJoH,EACA+B,EACAnJ,EACkB,CAKlB,GAJA,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeS,EAAa,MAAM,EAClCT,EAAe1I,EAAQ,SAAU,OAAO,EACpC,CAACsB,EAAiBtB,EAAQ,UAAWA,EAAQ,OAAO,EACtD,MAAM,IAAI5C,EAAS,mBAAoB,YAAY4C,EAAQ,SAAS,MAAMA,EAAQ,OAAO,EAAE,EAC7F,OAAOtB,EACL,KAAKyG,GACL,8BACAiC,EACA+B,EACAnJ,EAAQ,SACRA,EAAQ,UACRA,EAAQ,QACR,CAAE,SAAUA,EAAQ,iBAAmB,EAAA,CAAK,CAEhD,CAKA,MAAM,SAASA,EAA2C,CACxD,KAAK2G,GAAA,EACLqB,EAAqBhI,EAAQ,OAAQ,EAAG,GAAI,UAAU,EACtD,MAAM,KAAKwJ,GAAYxJ,EAAS,EAAK,CACvC,CAGA,MAAM,QAAQyJ,EAAqClD,EAAqC,CACtF,KAAKI,GAAA,EACLqB,EAAqByB,EAAQ,EAAG,GAAI,UAAU,EAC9C,MAAM,KAAKD,GAAY,CAAE,OAAAC,EAAQ,YAAAlD,CAAA,EAAe,EAAI,CACtD,CAGA,MAAM,UAAUmD,EAAkBnD,EAAqC,CACrE,KAAKI,GAAA,EACLmB,EAAsB4B,EAAU,QAAQ,EACxC,MAAMtB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,cAAeuE,EAAU,CAClE,UAAWtB,CAAA,CACZ,CACH,CAGA,MAAM,SAASsB,EAAkBnD,EAAqC,CACpE,KAAKI,GAAA,EACLmB,EAAsB4B,EAAU,QAAQ,EACxC,MAAMtB,EAAS,KAAKC,GAAoB9B,CAAW,EACnD,MAAMzH,EAA0B,KAAKqG,GAAM,aAAcuE,EAAU,CACjE,UAAWtB,CAAA,CACZ,CACH,CAKA,MAAM,mBAAmBhB,EAAkBuC,EAAoC,CAC7E,YAAKhD,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeiB,EAAU,MAAM,EACxBjL,EAAqB,KAAKyG,GAAM,uBAAwBiC,EAAUuC,CAAQ,CACnF,CAQA,MAAM,mBACJvC,EACAqB,EACAzI,EACkB,CAIlB,GAHA,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeD,EAAU,OAAO,EAC5B,CAACzI,GAAS,KACZ,MAAM,IAAI5C,EAAS,mBAAoB,uBAAuB,EAChE,OAAOsB,EACL,KAAKyG,GACL,uBACAiC,EACAqB,EACAzI,EAAQ,SACRA,EAAQ,IAAA,CAEZ,CAGA,MAAM,eAAeoH,EAAkBwC,EAAkC,CACvE,KAAKjD,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMtI,EAA0B,KAAKqG,GAAM,mBAAoBiC,EAAUwC,EAAM,EAAE,CACnF,CAGA,MAAM,QAAQxC,EAAiC,CAC7C,KAAKT,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMtI,EAA0B,KAAKqG,GAAM,YAAaiC,EAAU,CAAA,CAAE,CACtE,CAGA,MAAM,UAAUA,EAAiC,CAC/C,KAAKT,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMtI,EAA0B,KAAKqG,GAAM,cAAeiC,EAAU,CAAA,CAAE,CACxE,CAGA,MAAM,aACJA,EACAqB,EACAzI,EACkB,CAIlB,GAHA,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeD,EAAU,OAAO,EAC5B,CAACzI,GAAS,KACZ,MAAM,IAAI5C,EAAS,mBAAoB,qBAAqB,EAC9D,OAAOsB,EAAqB,KAAKyG,GAAM,kBAAmBiC,EAAUqB,EAAUzI,EAAQ,IAAI,CAC5F,CAGA,MAAM,mBAAmBoH,EAAqE,CAC5F,KAAKT,GAAA,EACL,MAAMkD,EAAiB,KAAKC,GAAiB1C,CAAQ,EACrD,OAAO1I,EAAqD,KAAKyG,GAAM,oBAAqB0E,CAAc,CAC5G,CAKA,MAAM,gBACJzC,EACA2C,EACA/J,EAA8B,CAAA,EACJ,CAC1B,KAAK2G,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeqB,EAAK,QAAQ,EAC5B,MAAM7B,EAAuD,CAC3D,KAAMlI,EAAQ,OACd,KAAMA,EAAQ,KACd,MAAOA,EAAQ,KAAA,EAEbA,EAAQ,OAAS,IAAQA,EAAQ,OAAS,SAC5CkI,EAAW,KAAOlI,EAAQ,MAC5B,MAAMrB,EAAM,MAAMG,EAA0B,KAAKqG,GAAM,oBAAqBiC,EAAU2C,EAAK7B,CAAU,EACrG,OAAOvE,EAAkBhF,CAAG,CAC9B,CAGA,MAAM,eAAeyI,EAAkB2C,EAAuC,CAC5E,KAAKpD,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3BsB,EAAeqB,EAAK,UAAU,EAC9B,MAAMpL,EAAM,MAAMG,EAA0B,KAAKqG,GAAM,mBAAoB4E,EAAK3C,EAAU,EAAE,EAC5F,OAAOzD,EAAkBhF,CAAG,CAC9B,CAGA,MAAM,eAAeqL,EAA4C,CAC/D,YAAKrD,GAAA,EACLqB,EAAqBgC,EAAM,EAAG,EAAG,SAAS,EACnCtL,EAAkC,KAAKyG,GAAM,iBAAkB6E,CAAI,CAC5E,CAIArD,IAA2B,CACzB,GAAI,CAAC,KAAKrB,GACR,MAAM,IAAIlI,EAAS,kBAAmB,qBAAqB,CAC/D,CAEAiK,GAAcD,EAAwB,CACpC,GAAI,CAAC,KAAK/B,GAAS,IAAI+B,CAAQ,EAC7B,MAAM,IAAIhK,EAAS,mBAAoB,aAAagK,CAAQ,EAAE,CAClE,CAEAL,GAAaR,EAAyC,CACpD,MAAM6B,EAAS7B,GAAe,KAAKb,GACnC,GAAI,CAAC,OAAO,UAAU0C,CAAM,GAAKA,EAAS,GAAKA,EAAS,GACtD,MAAM,IAAIhL,EAAS,mBAAoB,qBAAsB,CAC3D,YAAagL,CAAA,CACd,EAEH,OAAOA,CACT,CAEAC,GAAoB9B,EAAyC,CAC3D,MAAM6B,EAAS,KAAKrB,GAAaR,CAAW,EAC5C,GAAI,CAAC,KAAK,gBAAgB6B,CAAM,EAC9B,MAAM,IAAIhL,EAAS,qBAAsB,MAAMgL,CAAM,OAAO,EAC9D,OAAOA,CACT,CAEA,KAAMH,GAAqB1B,EAAoC,CACzD,KAAK,gBAAgBA,CAAW,GAClC,MAAM,KAAK,KAAKA,CAAW,CAC/B,CAEAuD,GAAiB1C,EAAsC,CACrD,GAAIA,EACF,YAAKC,GAAcD,CAAQ,EACpBA,EAET,GAAI,KAAK/B,GAAS,OAAS,EACzB,OAAO,KAAKA,GAAS,KAAA,EAAO,OAAO,MACrC,MAAM,IAAIjI,EAAS,mBAAoB,cAAc,CACvD,CAGA,KAAMmK,GAAUjJ,EAAgB8I,EAA4C,CAC1E,KAAKT,GAAA,EACL,KAAKU,GAAcD,CAAQ,EAC3B,MAAMzI,EAAM,MAAMG,EAA0B,KAAKqG,GAAM7G,EAAQ8I,EAAU,EAAE,EAC3E,OAAOzD,EAAkBhF,CAAG,CAC9B,CAEA,KAAM6K,GAAYxJ,EAA4BiK,EAA8B,CAC1E,MAAMC,EAAQC,GAAcnK,EAAQ,KAAK,EACnCuG,EAAc,KAAK8B,GAAoBrI,EAAQ,WAAW,EAChE,MAAMlB,EAA0B,KAAKqG,GAAM,eAAgBnF,EAAQ,OAAQiK,EAAM,CAC/E,UAAW1D,EACX,UAAW2D,CAAA,CACZ,CACH,CAGA,KAAM5C,GAAmBF,EAAiC,CACxD,MAAMgD,GAAWhM,EAA0B,KAAK+G,GAAM,aAAa,GAAK,CAAA,GAAI,OAAQkF,GAC7EA,EAEDA,EAAI,mBAAqBjD,EACpB,GAEF,GAAQiD,EAAI,MAAQjD,EAAS,WAAW,GAAGiD,EAAI,IAAI,GAAG,GAJpD,EAKV,EAED,MAAM,QAAQ,IAAID,EAAQ,IAAI,MAAOC,GAAQ,CAC3C,GAAI,CACF,MAAMvL,EAA0B,KAAKqG,GAAM,SAAU,CAAE,UAAWkF,EAAI,OAAQ,CAChF,OACOlM,EAAK,CACV,QAAQ,KAAK,uBAAuBkM,EAAI,MAAM,MAAOlM,CAAG,CAC1D,CACA,GAAI,CACF,MAAMO,EAAqB,KAAKyG,GAAM,iBAAkB,GAAIkF,EAAI,MAAM,CACxE,MACM,CAEN,CACF,CAAC,CAAC,CACJ,CACF,CAKO,SAASC,GAAgBtK,EAA4B,GAAe,CACzE,OAAO,IAAIkF,EAAUlF,CAAO,CAC9B,CAGO,SAASuK,IAA+B,CAC7C,OAAI,OAAO,OAAW,IACb,GACF,EAAQ,OAAO,cAAc,oBAAA,CACtC,CAIA,SAASJ,GAAcD,EAAmC,CACxD,GAAIA,IAAU,QAAa,CAAC,OAAO,SAASA,CAAK,EAC/C,OAAOvN,EAAgB,QACzB,MAAMkC,EAAQ,KAAK,MAAMqL,CAAK,EAC9B,GAAIrL,EAAQlC,EAAgB,KAAOkC,EAAQlC,EAAgB,IACzD,MAAM,IAAIS,EACR,mBACA,gBAAgBT,EAAgB,GAAG,MAAMA,EAAgB,GAAG,MAC5D,CAAE,MAAAuN,CAAA,CAAM,EAGZ,OAAOrL,CACT,CAEA,SAASkH,EAAaD,EAAsB,CAC1CkC,EAAqBlC,EAAQ,EAAG,EAAG,MAAM,CAC3C,CAEA,SAASkC,EACPnJ,EACA2L,EACAC,EACAxI,EACQ,CACR,GAAI,CAAC,OAAO,UAAUpD,CAAK,GAAMA,EAAmB2L,GAAQ3L,EAAmB4L,EAC7E,MAAM,IAAIrN,EAAS,mBAAoB,GAAG6E,CAAK,OAAOuI,CAAG,MAAMC,CAAG,OAAQ,CACxE,SAAU5L,CAAA,CACX,EAEH,OAAOA,CACT,CAEA,SAASiJ,EAAsBjJ,EAAgBoD,EAAuB,CACpE,GAAI,CAAC,OAAO,UAAUpD,CAAK,GAAMA,EAAmB,EAClD,MAAM,IAAIzB,EAAS,mBAAoB,GAAG6E,CAAK,SAAU,CAAE,SAAUpD,EAAO,EAE9E,OAAOA,CACT,CAEA,SAAS6J,EAAe7J,EAAeoD,EAAqB,CAC1D,GAAI,CAACpD,EAAM,KAAA,EACT,MAAM,IAAIzB,EAAS,mBAAoB,GAAG6E,CAAK,MAAM,CACzD,CAEA,SAAS+E,EAAerI,EAAwC,CAC9D,MAAO,CACL,MAAOA,EAAI,OACX,SAAU,OAAOA,EAAI,kBAAqB,SAAWA,EAAI,iBAAoBA,EAAI,MAAQ,GACzF,UAAWA,EAAI,WACf,WAAYA,EAAI,YAChB,IAAAA,CAAA,CAEJ,CAGA,SAASyK,EAAqBvK,EAAuB,CACnD,OAAOA,EAAM,QAAQ,IAAK,GAAG,EAAE,QAAQ,IAAK,EAAE,CAChD,CAGA,SAASwK,GAAuBU,EAAqB,CACnD,MAAMW,EAAUX,EAAI,QAAQ,OAAO,EACnC,GAAIW,EAAU,EACZ,MAAO,GACT,MAAMC,EAAUZ,EAAI,QAAQ,SAAUW,CAAO,EAC7C,OAAOC,EAAU,EAAIZ,EAAI,MAAMW,EAAU,EAAGC,CAAO,EAAIZ,EAAI,MAAMW,EAAU,CAAC,CAC9E"}