{"version":3,"file":"api-client.mjs","sources":["../../../src/lib/api/api-client.ts"],"sourcesContent":["/**\n * @file API Client Factory\n * @description Enterprise-grade API client with typed request generation, automatic retry\n * with exponential backoff, request/response interceptors, request deduplication,\n * and automatic token refresh capabilities.\n *\n * This module provides the core HTTP client infrastructure with:\n * - Full TypeScript support with generics\n * - Configurable retry strategies with exponential backoff and jitter\n * - Request/response/error interceptor chains\n * - Automatic request deduplication for concurrent identical requests\n * - Token refresh with request queuing\n * - Request prioritization and cancellation\n * - Comprehensive error normalization\n * - Configurable token provider for custom authentication storage\n *\n * @example Basic Usage\n * ```typescript\n * import { createApiClient, ApiClient } from '@/lib/api';\n *\n * // Create a typed client\n * const client = createApiClient({\n *   baseUrl: 'https://api.example.com',\n *   timeout: 30000,\n *   autoRefreshToken: true,\n * });\n *\n * // Make typed requests\n * const user = await client.get<User>('/users/123');\n * const created = await client.post<User>('/users', { name: 'John' });\n * ```\n *\n * @example Custom Token Provider\n * ```typescript\n * import { createApiClient, TokenProvider } from '@/lib/api';\n *\n * // Use custom token storage (e.g., secure storage, cookies, etc.)\n * const client = createApiClient({\n *   baseUrl: 'https://api.example.com',\n *   tokenProvider: {\n *     getAccessToken: () => authService.getToken(),\n *     getRefreshToken: () => authService.getRefreshToken(),\n *     setAccessToken: (token) => authService.setToken(token),\n *     setRefreshToken: (token) => authService.setRefreshToken(token),\n *     clearTokens: () => authService.logout(),\n *   },\n * });\n * ```\n */\n\nimport type {\n  ApiClientConfig,\n  ApiError,\n  ApiResponse,\n  ErrorCategory,\n  ErrorInterceptor,\n  ErrorSeverity,\n  QueryParams,\n  RequestConfig,\n  RequestInterceptor,\n  RequestMeta,\n  ResponseInterceptor,\n  ResponseTiming,\n  RetryConfig,\n  ServerErrorResponse,\n  TokenProvider,\n} from './types';\nimport { API_CONFIG, calculateBackoffWithJitter, TIMING } from '@/config';\nimport { createSecureLocalStorage, isSecureStorageAvailable, type SecureStorage, } from '@/lib/security/secure-storage';\nimport { RATE_LIMIT_PRESETS, type RateLimitConfig, RateLimiter, RateLimitError, } from './advanced/rate-limiter';\n\n// =============================================================================\n// DEFAULT CONFIGURATION\n// =============================================================================\n\n/**\n * Default retry configuration\n */\nconst DEFAULT_RETRY_CONFIG: RetryConfig = {\n  maxAttempts: TIMING.RETRY.API_ATTEMPTS,\n  baseDelay: TIMING.API.RETRY_BASE_DELAY,\n  maxDelay: TIMING.API.RETRY_MAX_DELAY,\n  backoffFactor: 2,\n  retryableStatusCodes: [408, 429, 500, 502, 503, 504],\n  retryOnNetworkError: true,\n};\n\n/**\n * Default client configuration\n */\nconst DEFAULT_CLIENT_CONFIG: Partial<ApiClientConfig> = {\n  timeout: API_CONFIG.TIMEOUT.DEFAULT,\n  headers: {\n    'Content-Type': 'application/json',\n    'Accept': 'application/json',\n  },\n  deduplicate: true,\n  autoRefreshToken: true,\n  tokenRefreshThreshold: TIMING.AUTH.TOKEN_EXPIRY_BUFFER,\n  credentials: 'include',\n};\n\n// =============================================================================\n// REQUEST DEDUPLICATION\n// =============================================================================\n\n/**\n * In-flight request cache for deduplication\n */\nconst inflightRequests = new Map<string, Promise<ApiResponse>>();\n\n/**\n * Generate a cache key for request deduplication\n */\nfunction generateRequestKey(config: RequestConfig): string {\n  const { method, url, params, body } = config;\n  const paramsStr = params != null ? JSON.stringify(sortObject(params)) : '';\n  const bodyStr = body != null ? JSON.stringify(body) : '';\n  return `${method}:${url}:${paramsStr}:${bodyStr}`;\n}\n\n/**\n * Sort object keys for consistent cache key generation\n */\nfunction sortObject<T extends Record<string, unknown>>(obj: T): T {\n  const sorted = {} as T;\n  const keys = Object.keys(obj).sort() as Array<keyof T>;\n  for (const key of keys) {\n    sorted[key] = obj[key];\n  }\n  return sorted;\n}\n\n// =============================================================================\n// TOKEN REFRESH HANDLING\n// =============================================================================\n\n/**\n * Token refresh state management\n */\ninterface TokenRefreshState {\n  isRefreshing: boolean;\n  refreshPromise: Promise<string> | null;\n  pendingRequests: Array<{\n    resolve: (token: string) => void;\n    reject: (error: Error) => void;\n  }>;\n}\n\nconst tokenRefreshState: TokenRefreshState = {\n  isRefreshing: false,\n  refreshPromise: null,\n  pendingRequests: [],\n};\n\n/**\n * Secure token storage keys used by the default provider.\n *\n * SECURITY: These keys are used with SecureStorage for encrypted token persistence.\n */\nconst SECURE_API_TOKEN_KEYS = {\n  ACCESS_TOKEN: 'api_access_token',\n  REFRESH_TOKEN: 'api_refresh_token',\n} as const;\n\n/**\n * Session encryption key for API token storage.\n *\n * SECURITY: The encryption key is generated using cryptographically secure\n * random bytes via the Web Crypto API. This key is:\n * - Generated fresh per session\n * - Stored only in memory (never persisted)\n * - Used for encrypting tokens at rest in localStorage\n */\nlet apiSessionEncryptionKey: string | null = null;\n\n/**\n * Generates a cryptographically secure encryption key for API token storage.\n *\n * SECURITY: Uses crypto.getRandomValues() for true cryptographic randomness.\n *\n * @returns A base64-encoded 256-bit random key\n */\nfunction generateApiSessionKey(): string {\n  const keyBytes = new Uint8Array(32);\n  crypto.getRandomValues(keyBytes);\n  return btoa(String.fromCharCode(...keyBytes));\n}\n\n/**\n * Gets or creates the API session encryption key.\n */\nfunction getApiSessionEncryptionKey(): string {\n  apiSessionEncryptionKey ??= generateApiSessionKey();\n  return apiSessionEncryptionKey;\n}\n\n/**\n * Lazily initialized secure storage for API tokens.\n */\nlet secureApiTokenStorage: SecureStorage | null = null;\n\n/**\n * Gets the secure storage instance for API tokens.\n *\n * SECURITY: Uses session-generated encryption key for AES-GCM encryption.\n */\nfunction getSecureApiStorage(): SecureStorage | null {\n  if (!isSecureStorageAvailable()) {\n    return null;\n  }\n  secureApiTokenStorage ??= createSecureLocalStorage(getApiSessionEncryptionKey());\n  return secureApiTokenStorage;\n}\n\n/**\n * In-memory token cache for the default provider.\n *\n * SECURITY: This cache enables synchronous access while maintaining\n * encrypted persistence. Cache is cleared on page reload.\n */\nconst tokenCache: {\n  accessToken: string | null;\n  refreshToken: string | null;\n} = {\n  accessToken: null,\n  refreshToken: null,\n};\n\n/**\n * Default secure token provider using encrypted localStorage.\n *\n * SECURITY: This provider uses SecureStorage for encrypted token persistence:\n * - Tokens are encrypted using AES-GCM before storage\n * - Session key is cryptographically random (32 bytes)\n * - Key derivation uses PBKDF2 with high iteration count\n * - Each encryption uses a unique IV\n *\n * Methods return Promises to support async encryption operations.\n * The API client handles Promise.resolve() wrapping for compatibility.\n *\n * For maximum security, applications should use the authService which\n * provides additional features like rate limiting and session management.\n */\nconst defaultTokenProvider: TokenProvider = {\n  getAccessToken: async (): Promise<string | null> => {\n    // Return cached value for sync-compatible fast path\n    if (tokenCache.accessToken != null && tokenCache.accessToken !== '') {\n      return tokenCache.accessToken;\n    }\n\n    const storage = getSecureApiStorage();\n    if (storage == null) {\n      // Fallback: no secure storage available (SSR or unsupported browser)\n      return null;\n    }\n\n    try {\n      const result = await storage.getItem<string>(SECURE_API_TOKEN_KEYS.ACCESS_TOKEN);\n      if (result.success && result.data != null && result.data !== '') {\n        tokenCache.accessToken = result.data;\n        return result.data;\n      }\n    } catch {\n      // Decryption failed - token may be corrupted or key changed\n      console.warn('[API Client] Failed to decrypt access token from secure storage');\n    }\n    return null;\n  },\n\n  getRefreshToken: async (): Promise<string | null> => {\n    // Return cached value for sync-compatible fast path\n    if (tokenCache.refreshToken != null && tokenCache.refreshToken !== '') {\n      return tokenCache.refreshToken;\n    }\n\n    const storage = getSecureApiStorage();\n    if (storage == null) {\n      return null;\n    }\n\n    try {\n      const result = await storage.getItem<string>(SECURE_API_TOKEN_KEYS.REFRESH_TOKEN);\n      if (result.success && result.data != null && result.data !== '') {\n        tokenCache.refreshToken = result.data;\n        return result.data;\n      }\n    } catch {\n      console.warn('[API Client] Failed to decrypt refresh token from secure storage');\n    }\n    return null;\n  },\n\n  setAccessToken: async (token: string): Promise<void> => {\n    // Update cache immediately for sync access\n    tokenCache.accessToken = token;\n\n    const storage = getSecureApiStorage();\n    if (!storage) {\n      return;\n    }\n\n    try {\n      const result = await storage.setItem(SECURE_API_TOKEN_KEYS.ACCESS_TOKEN, token);\n      if (!result.success) {\n        console.error('[API Client] Failed to store access token:', result.error);\n      }\n    } catch (error) {\n      console.error('[API Client] Error encrypting access token:', error);\n    }\n  },\n\n  setRefreshToken: async (token: string): Promise<void> => {\n    // Update cache immediately for sync access\n    tokenCache.refreshToken = token;\n\n    const storage = getSecureApiStorage();\n    if (!storage) {\n      return;\n    }\n\n    try {\n      const result = await storage.setItem(SECURE_API_TOKEN_KEYS.REFRESH_TOKEN, token);\n      if (!result.success) {\n        console.error('[API Client] Failed to store refresh token:', result.error);\n      }\n    } catch (error) {\n      console.error('[API Client] Error encrypting refresh token:', error);\n    }\n  },\n\n  clearTokens: async (): Promise<void> => {\n    // Clear cache immediately\n    tokenCache.accessToken = null;\n    tokenCache.refreshToken = null;\n\n    const storage = getSecureApiStorage();\n    if (!storage) {\n      return;\n    }\n\n    try {\n      await Promise.all([\n        Promise.resolve(storage.removeItem(SECURE_API_TOKEN_KEYS.ACCESS_TOKEN)),\n        Promise.resolve(storage.removeItem(SECURE_API_TOKEN_KEYS.REFRESH_TOKEN)),\n      ]);\n    } catch (error) {\n      console.error('[API Client] Error clearing tokens from secure storage:', error);\n    }\n  },\n};\n\n/**\n * Create token refresh function using the provided token provider\n */\nfunction createTokenRefreshFn(tokenProvider: TokenProvider): () => Promise<string> {\n  return async function tokenRefresh(): Promise<string> {\n    const refreshToken = await tokenProvider.getRefreshToken();\n    if (refreshToken == null || refreshToken === '') {\n      throw new Error('No refresh token available');\n    }\n\n    const response = await fetch(`${API_CONFIG.BASE_URL}${API_CONFIG.ENDPOINTS.AUTH.REFRESH}`, {\n      method: 'POST',\n      headers: { 'Content-Type': 'application/json' },\n      body: JSON.stringify({ refreshToken }),\n    });\n\n    if (!response.ok) {\n      throw new Error('Token refresh failed');\n    }\n\n    const data = await response.json() as { accessToken: string; refreshToken?: string };\n    await tokenProvider.setAccessToken(data.accessToken);\n    if (data.refreshToken != null && data.refreshToken !== '') {\n      await tokenProvider.setRefreshToken(data.refreshToken);\n    }\n\n    return data.accessToken;\n  };\n}\n\n// =============================================================================\n// ERROR HANDLING\n// =============================================================================\n\n/**\n * Map HTTP status codes to error categories\n */\nfunction getErrorCategory(status: number): ErrorCategory {\n  if (status === 401) return 'authentication';\n  if (status === 403) return 'authorization';\n  if (status === 404) return 'not_found';\n  if (status === 409) return 'conflict';\n  if (status === 422 || status === 400) return 'validation';\n  if (status === 429) return 'rate_limit';\n  if (status === 408) return 'timeout';\n  if (status >= 500) return 'server';\n  return 'unknown';\n}\n\n/**\n * Map error categories to severity levels\n */\nfunction getErrorSeverity(category: ErrorCategory): ErrorSeverity {\n  switch (category) {\n    case 'authentication':\n    case 'authorization':\n    case 'server':\n      return 'error';\n    case 'validation':\n    case 'conflict':\n    case 'not_found':\n      return 'warning';\n    case 'rate_limit':\n    case 'timeout':\n      return 'info';\n    default:\n      return 'error';\n  }\n}\n\n/**\n * Check if an error is retryable\n */\nfunction isRetryable(status: number, retryConfig: RetryConfig): boolean {\n  return retryConfig.retryableStatusCodes.includes(status);\n}\n\n/**\n * Create a normalized API error from various error sources\n */\nfunction createApiError(\n  status: number,\n  message: string,\n  options: {\n    code?: string;\n    response?: unknown;\n    request?: RequestConfig;\n    requestId?: string;\n    correlationId?: string;\n    cause?: Error;\n    fieldErrors?: Array<{ field: string; message: string }>;\n  } = {}\n): ApiError {\n  const category = getErrorCategory(status);\n  const severity = getErrorSeverity(category);\n  const retryConfig = DEFAULT_RETRY_CONFIG;\n\n  const error = new Error(message) as ApiError;\n  error.name = 'ApiError';\n  error.status = status;\n  error.code = options.code ?? `HTTP_${status}`;\n  error.message = message;\n  error.category = category;\n  error.severity = severity;\n  error.fieldErrors = options.fieldErrors;\n  error.request = options.request;\n  error.response = options.response;\n  error.requestId = options.requestId;\n  error.correlationId = options.correlationId;\n  error.timestamp = Date.now();\n  error.cause = options.cause;\n  error.retryable = isRetryable(status, retryConfig);\n\n  return error;\n}\n\n/**\n * Parse server error response into normalized format\n */\nfunction parseServerError(response: ServerErrorResponse, _status: number): Partial<ApiError> {\n  let message = 'An unexpected error occurred';\n  let code: string | undefined;\n  const fieldErrors: Array<{ field: string; message: string }> = [];\n\n  if (typeof response.message === 'string') {\n    ({ message } = response);\n  } else if (typeof response.error === 'string') {\n    message = response.error;\n  } else if (response.error != null) {\n    const { message: errorMessage, code: errorCode } = response.error;\n    message = errorMessage;\n    code = errorCode;\n  }\n\n  if (response.code != null && response.code !== '') {\n    const { code: responseCode } = response;\n    code = responseCode;\n  }\n\n  if (Array.isArray(response.errors)) {\n    for (const err of response.errors) {\n      fieldErrors.push({ field: err.field, message: err.message });\n    }\n  }\n\n  return { message, code, fieldErrors: fieldErrors.length > 0 ? fieldErrors : undefined };\n}\n\n// =============================================================================\n// API CLIENT CLASS\n// =============================================================================\n\n/**\n * Enterprise API Client with comprehensive features\n */\nexport class ApiClient {\n  private config: Required<ApiClientConfig>;\n  private readonly requestInterceptors: RequestInterceptor[] = [];\n  private readonly responseInterceptors: ResponseInterceptor[] = [];\n  private readonly errorInterceptors: ErrorInterceptor[] = [];\n  private tokenRefreshFn: () => Promise<string>;\n  private tokenProvider: TokenProvider;\n  private abortControllers = new Map<string, AbortController>();\n\n  /**\n   * Rate limiter instance for client-side rate limiting.\n   * Null if rate limiting is disabled.\n   */\n  private rateLimiter: RateLimiter | null = null;\n\n  constructor(config: ApiClientConfig) {\n    // Store token provider (use default if not provided)\n    this.tokenProvider = config.tokenProvider ?? defaultTokenProvider;\n\n    this.config = {\n      ...DEFAULT_CLIENT_CONFIG,\n      ...config,\n      retry: { ...DEFAULT_RETRY_CONFIG, ...config.retry },\n      headers: { ...DEFAULT_CLIENT_CONFIG.headers, ...config.headers },\n      requestInterceptors: config.requestInterceptors ?? [],\n      responseInterceptors: config.responseInterceptors ?? [],\n      errorInterceptors: config.errorInterceptors ?? [],\n      onError: config.onError ?? (() => {}),\n      onRequestStart: config.onRequestStart ?? (() => {}),\n      onRequestEnd: config.onRequestEnd ?? (() => {}),\n      fetch: config.fetch ?? fetch.bind(globalThis),\n      tokenProvider: this.tokenProvider,\n    } as Required<ApiClientConfig>;\n\n    // Initialize interceptors\n    this.requestInterceptors = [...this.config.requestInterceptors];\n    this.responseInterceptors = [...this.config.responseInterceptors];\n    this.errorInterceptors = [...this.config.errorInterceptors];\n\n    // Create token refresh function using the token provider\n    this.tokenRefreshFn = createTokenRefreshFn(this.tokenProvider);\n\n    // Initialize rate limiter if configured\n    if (config.rateLimit != null) {\n      const rateLimitConfig: RateLimitConfig =\n        typeof config.rateLimit === 'string'\n          ? RATE_LIMIT_PRESETS[config.rateLimit as keyof typeof RATE_LIMIT_PRESETS]\n          : config.rateLimit;\n      this.rateLimiter = new RateLimiter(rateLimitConfig);\n    }\n  }\n\n  // ===========================================================================\n  // PUBLIC API METHODS\n  // ===========================================================================\n\n  /**\n   * Perform a GET request\n   */\n  async get<TResponse>(\n    url: string,\n    options: Omit<RequestConfig, 'method' | 'url' | 'body'> = {}\n  ): Promise<ApiResponse<TResponse>> {\n    return this.request<TResponse>({ ...options, method: 'GET', url });\n  }\n\n  /**\n   * Perform a POST request\n   */\n  async post<TResponse, TBody = unknown>(\n    url: string,\n    body?: TBody,\n    options: Omit<RequestConfig, 'method' | 'url' | 'body'> = {}\n  ): Promise<ApiResponse<TResponse>> {\n    return this.request<TResponse>({ ...options, method: 'POST', url, body });\n  }\n\n  /**\n   * Perform a PUT request\n   */\n  async put<TResponse, TBody = unknown>(\n    url: string,\n    body?: TBody,\n    options: Omit<RequestConfig, 'method' | 'url' | 'body'> = {}\n  ): Promise<ApiResponse<TResponse>> {\n    return this.request<TResponse>({ ...options, method: 'PUT', url, body });\n  }\n\n  /**\n   * Perform a PATCH request\n   */\n  async patch<TResponse, TBody = unknown>(\n    url: string,\n    body?: TBody,\n    options: Omit<RequestConfig, 'method' | 'url' | 'body'> = {}\n  ): Promise<ApiResponse<TResponse>> {\n    return this.request<TResponse>({ ...options, method: 'PATCH', url, body });\n  }\n\n  /**\n   * Perform a DELETE request\n   */\n  async delete<TResponse>(\n    url: string,\n    options: Omit<RequestConfig, 'method' | 'url'> = {}\n  ): Promise<ApiResponse<TResponse>> {\n    return this.request<TResponse>({ ...options, method: 'DELETE', url });\n  }\n\n  /**\n   * Perform a HEAD request\n   */\n  async head(\n    url: string,\n    options: Omit<RequestConfig, 'method' | 'url' | 'body'> = {}\n  ): Promise<ApiResponse<void>> {\n    return this.request<void>({ ...options, method: 'HEAD', url });\n  }\n\n  /**\n   * Generic request method\n   */\n  async request<TResponse>(config: RequestConfig): Promise<ApiResponse<TResponse>> {\n    const requestId = this.generateRequestId();\n    const meta: RequestMeta = {\n      ...config.meta,\n      requestId,\n      startTime: Date.now(),\n    };\n\n    let processedConfig: RequestConfig & { meta: RequestMeta } = { ...config, meta };\n\n    // Run request interceptors\n    processedConfig = (await this.runRequestInterceptors(\n      processedConfig\n    )) as typeof processedConfig;\n\n    // Build URL for rate limiting key\n    const url = this.buildUrl(processedConfig);\n\n    // Apply rate limiting if enabled\n    if (this.rateLimiter != null && !(config.meta?.skipRateLimit === true)) {\n      try {\n        return await this.rateLimiter.execute(url, async () => {\n          return this.executeRequestWithDedup<TResponse>(processedConfig, requestId);\n        });\n      } catch (error) {\n        if (error instanceof RateLimitError) {\n          // Convert RateLimitError to ApiError\n          const apiError = createApiError(429, error.message, {\n            code: 'RATE_LIMITED',\n            request: processedConfig,\n            requestId,\n          });\n          apiError.retryable = true;\n          throw apiError;\n        }\n        throw error;\n      }\n    }\n\n    return this.executeRequestWithDedup<TResponse>(processedConfig, requestId);\n  }\n\n  /**\n   * Add a request interceptor\n   */\n  addRequestInterceptor(interceptor: RequestInterceptor): () => void {\n    this.requestInterceptors.push(interceptor);\n    return () => {\n      const index = this.requestInterceptors.indexOf(interceptor);\n      if (index !== -1) {\n        this.requestInterceptors.splice(index, 1);\n      }\n    };\n  }\n\n  // ===========================================================================\n  // INTERCEPTOR MANAGEMENT\n  // ===========================================================================\n\n  /**\n   * Add a response interceptor\n   */\n  addResponseInterceptor(interceptor: ResponseInterceptor): () => void {\n    this.responseInterceptors.push(interceptor);\n    return () => {\n      const index = this.responseInterceptors.indexOf(interceptor);\n      if (index !== -1) {\n        this.responseInterceptors.splice(index, 1);\n      }\n    };\n  }\n\n  /**\n   * Add an error interceptor\n   */\n  addErrorInterceptor(interceptor: ErrorInterceptor): () => void {\n    this.errorInterceptors.push(interceptor);\n    return () => {\n      const index = this.errorInterceptors.indexOf(interceptor);\n      if (index !== -1) {\n        this.errorInterceptors.splice(index, 1);\n      }\n    };\n  }\n\n  /**\n   * Set custom token refresh function\n   */\n  setTokenRefresh(fn: () => Promise<string>): void {\n    this.tokenRefreshFn = fn;\n  }\n\n  // ===========================================================================\n  // TOKEN REFRESH\n  // ===========================================================================\n\n  /**\n   * Get the current token provider\n   */\n  getTokenProvider(): TokenProvider {\n    return this.tokenProvider;\n  }\n\n  /**\n   * Set a new token provider\n   *\n   * This also updates the token refresh function to use the new provider.\n   */\n  setTokenProvider(provider: TokenProvider): void {\n    this.tokenProvider = provider;\n    this.tokenRefreshFn = createTokenRefreshFn(provider);\n  }\n\n  /**\n   * Get the rate limiter instance.\n   * Returns null if rate limiting is not enabled.\n   */\n  getRateLimiter(): RateLimiter | null {\n    return this.rateLimiter;\n  }\n\n  /**\n   * Enable or update rate limiting.\n   *\n   * @param config - Rate limit configuration or preset name\n   *\n   * @example\n   * ```typescript\n   * // Use a preset\n   * client.setRateLimit('standard');\n   *\n   * // Use custom config\n   * client.setRateLimit({\n   *   maxRequests: 100,\n   *   windowMs: 60000,\n   *   strategy: 'queue',\n   * });\n   * ```\n   */\n  setRateLimit(config: RateLimitConfig | keyof typeof RATE_LIMIT_PRESETS): void {\n    const rateLimitConfig: RateLimitConfig =\n      typeof config === 'string' ? RATE_LIMIT_PRESETS[config] : config;\n    this.rateLimiter = new RateLimiter(rateLimitConfig);\n  }\n\n  // ===========================================================================\n  // RATE LIMITING\n  // ===========================================================================\n\n  /**\n   * Disable rate limiting.\n   */\n  disableRateLimit(): void {\n    this.rateLimiter = null;\n  }\n\n  /**\n   * Check if a request would be rate limited.\n   *\n   * @param endpoint - Endpoint URL to check\n   * @returns Whether the request would be limited\n   */\n  wouldBeRateLimited(endpoint: string): boolean {\n    return this.rateLimiter?.wouldBeLimited(endpoint) ?? false;\n  }\n\n  /**\n   * Cancel a specific request by ID\n   */\n  cancelRequest(requestId: string): void {\n    const controller = this.abortControllers.get(requestId);\n    if (controller) {\n      controller.abort();\n      this.abortControllers.delete(requestId);\n    }\n  }\n\n  /**\n   * Cancel all pending requests\n   */\n  cancelAllRequests(): void {\n    for (const controller of this.abortControllers.values()) {\n      controller.abort();\n    }\n    this.abortControllers.clear();\n  }\n\n  // ===========================================================================\n  // REQUEST CANCELLATION\n  // ===========================================================================\n\n  /**\n   * Execute request with deduplication logic\n   */\n  private async executeRequestWithDedup<TResponse>(\n    config: RequestConfig,\n    requestId: string\n  ): Promise<ApiResponse<TResponse>> {\n    // Check for deduplication\n    if (this.config.deduplicate && config.method === 'GET' && !(config.meta?.skipAuth === true)) {\n      const cacheKey = generateRequestKey(config);\n      const inflight = inflightRequests.get(cacheKey);\n      if (inflight) {\n        return inflight as Promise<ApiResponse<TResponse>>;\n      }\n\n      const promise = this.executeRequest<TResponse>(config, requestId);\n      inflightRequests.set(cacheKey, promise as Promise<ApiResponse>);\n\n      try {\n        return await promise;\n      } finally {\n        inflightRequests.delete(cacheKey);\n      }\n    }\n\n    return this.executeRequest<TResponse>(config, requestId);\n  }\n\n  /**\n   * Perform token refresh with request queuing\n   */\n  private async refreshToken(): Promise<string> {\n    if (tokenRefreshState.isRefreshing && tokenRefreshState.refreshPromise) {\n      return tokenRefreshState.refreshPromise;\n    }\n\n    tokenRefreshState.isRefreshing = true;\n    tokenRefreshState.refreshPromise = this.tokenRefreshFn();\n\n    try {\n      const token = await tokenRefreshState.refreshPromise;\n\n      // Resolve all pending requests\n      for (const { resolve } of tokenRefreshState.pendingRequests) {\n        resolve(token);\n      }\n      tokenRefreshState.pendingRequests = [];\n\n      return token;\n    } catch (error) {\n      // Reject all pending requests\n      for (const { reject } of tokenRefreshState.pendingRequests) {\n        reject(error instanceof Error ? error : new Error(String(error)));\n      }\n      tokenRefreshState.pendingRequests = [];\n\n      throw error;\n    } finally {\n      tokenRefreshState.isRefreshing = false;\n      tokenRefreshState.refreshPromise = null;\n    }\n  }\n\n  // ===========================================================================\n  // PRIVATE METHODS\n  // ===========================================================================\n\n  /**\n   * Execute the actual HTTP request with retry logic\n   */\n  private async executeRequest<TResponse>(\n    config: RequestConfig,\n    requestId: string,\n    attempt = 0\n  ): Promise<ApiResponse<TResponse>> {\n    const retryConfig = { ...DEFAULT_RETRY_CONFIG, ...this.config.retry, ...config.retry };\n    const abortController = new AbortController();\n    this.abortControllers.set(requestId, abortController);\n\n    // Merge signals if one was provided\n    if (config.signal) {\n      config.signal.addEventListener('abort', () => abortController.abort());\n    }\n\n    const startTime = Date.now();\n    this.config.onRequestStart(config);\n\n    try {\n      // Build the full URL\n      const url = this.buildUrl(config);\n\n      // Build headers\n      const headers = await this.buildHeaders(config);\n\n      // Build request options\n      const requestInit: RequestInit = {\n        method: config.method,\n        headers,\n        signal: abortController.signal,\n        credentials: config.credentials ?? this.config.credentials,\n        cache: config.cache,\n      };\n\n      // Add body for methods that support it\n      if (config.body !== undefined && ['POST', 'PUT', 'PATCH'].includes(config.method)) {\n        requestInit.body = this.serializeBody(config);\n      }\n\n      // Set up timeout\n      const timeout =\n        config.timeout != null && config.timeout !== 0 ? config.timeout : this.config.timeout;\n      const timeoutId = setTimeout(() => abortController.abort(), timeout);\n\n      try {\n        const response = await this.config.fetch(url, requestInit);\n        clearTimeout(timeoutId);\n\n        const endTime = Date.now();\n        const timing: ResponseTiming = {\n          startTime,\n          endTime,\n          duration: endTime - startTime,\n        };\n\n        // Update rate limiter from response headers\n        if (this.rateLimiter != null) {\n          const rateLimitHeaders = {\n            'x-ratelimit-remaining': response.headers.get('x-ratelimit-remaining') ?? undefined,\n            'x-ratelimit-limit': response.headers.get('x-ratelimit-limit') ?? undefined,\n            'x-ratelimit-reset': response.headers.get('x-ratelimit-reset') ?? undefined,\n            'retry-after': response.headers.get('retry-after') ?? undefined,\n          };\n          this.rateLimiter.updateFromHeaders(url, rateLimitHeaders);\n        }\n\n        // Handle non-OK responses\n        if (!response.ok) {\n          const errorResponse = await this.parseErrorResponse(response);\n          const apiError = createApiError(\n            response.status,\n            errorResponse.message ?? `HTTP ${response.status}`,\n            {\n              code: errorResponse.code,\n              response: errorResponse,\n              request: config,\n              requestId,\n              fieldErrors: errorResponse.fieldErrors,\n            }\n          );\n\n          // Handle 429 rate limit response\n          if (response.status === 429 && this.rateLimiter != null) {\n            const retryAfter = response.headers.get('retry-after') ?? undefined;\n            this.rateLimiter.handle429(url, retryAfter);\n          }\n\n          // Handle 401 with token refresh\n          if (\n            response.status === 401 &&\n            this.config.autoRefreshToken &&\n            config.meta?.skipAuth !== true\n          ) {\n            try {\n              await this.refreshToken();\n              // Retry the request with new token\n              return this.executeRequest<TResponse>(config, requestId, attempt);\n            } catch {\n              // Token refresh failed, propagate original error\n            }\n          }\n\n          // Check if we should retry\n          if (\n            apiError.retryable &&\n            attempt < retryConfig.maxAttempts - 1 &&\n            config.meta?.skipRetry !== true\n          ) {\n            const shouldRetry =\n              retryConfig.shouldRetry != null ? retryConfig.shouldRetry(apiError, attempt) : true;\n\n            if (shouldRetry === true) {\n              retryConfig.onRetry?.(apiError, attempt);\n              const delay = calculateBackoffWithJitter(\n                attempt,\n                retryConfig.baseDelay,\n                retryConfig.maxDelay\n              );\n              await this.delay(delay);\n              return this.executeRequest<TResponse>(config, requestId, attempt + 1);\n            }\n          }\n\n          throw apiError;\n        }\n\n        // Parse successful response\n        const data = await this.parseResponse<TResponse>(response, config);\n\n        // Build response object\n        let apiResponse: ApiResponse<TResponse> = {\n          data,\n          status: response.status,\n          statusText: response.statusText,\n          headers: this.parseHeaders(response.headers),\n          request: config,\n          timing,\n        };\n\n        // Run response interceptors\n        apiResponse = await this.runResponseInterceptors(apiResponse);\n\n        this.config.onRequestEnd(apiResponse);\n\n        return apiResponse;\n      } finally {\n        clearTimeout(timeoutId);\n        this.abortControllers.delete(requestId);\n      }\n    } catch (error) {\n      this.abortControllers.delete(requestId);\n\n      // Handle abort errors\n      if (error instanceof DOMException && error.name === 'AbortError') {\n        const apiError = createApiError(0, 'Request was cancelled', {\n          code: 'REQUEST_CANCELLED',\n          request: config,\n          requestId,\n        });\n        apiError.category = 'cancelled';\n        apiError.retryable = false;\n        throw apiError;\n      }\n\n      // Handle network errors\n      if (error instanceof TypeError && error.message.includes('fetch')) {\n        const apiError = createApiError(0, 'Network error occurred', {\n          code: 'NETWORK_ERROR',\n          request: config,\n          requestId,\n          cause: error,\n        });\n        apiError.category = 'network';\n\n        // Retry network errors\n        if (\n          retryConfig.retryOnNetworkError === true &&\n          attempt < retryConfig.maxAttempts - 1 &&\n          config.meta?.skipRetry !== true\n        ) {\n          retryConfig.onRetry?.(apiError, attempt);\n          const delay = calculateBackoffWithJitter(\n            attempt,\n            retryConfig.baseDelay,\n            retryConfig.maxDelay\n          );\n          await this.delay(delay);\n          return this.executeRequest<TResponse>(config, requestId, attempt + 1);\n        }\n\n        throw apiError;\n      }\n\n      // Re-throw API errors\n      if (this.isApiError(error)) {\n        // Run error interceptors\n        const processedError = await this.runErrorInterceptors(error);\n        this.config.onError(processedError);\n        this.config.onRequestEnd(processedError);\n        throw processedError;\n      }\n\n      // Wrap unknown errors\n      const apiError = createApiError(0, 'An unexpected error occurred', {\n        code: 'UNKNOWN_ERROR',\n        request: config,\n        requestId,\n        cause: error instanceof Error ? error : new Error(String(error)),\n      });\n\n      const processedError = await this.runErrorInterceptors(apiError);\n      this.config.onError(processedError);\n      this.config.onRequestEnd(processedError);\n      throw processedError;\n    }\n  }\n\n  /**\n   * Build the full URL with path params and query string\n   */\n  private buildUrl(config: RequestConfig): string {\n    let { url } = config;\n\n    // Substitute path parameters\n    if (config.pathParams) {\n      for (const [key, value] of Object.entries(config.pathParams)) {\n        url = url.replace(`:${key}`, encodeURIComponent(String(value)));\n      }\n    }\n\n    // Build full URL\n    const baseUrl = this.config.baseUrl.replace(/\\/$/, '');\n    const path = url.startsWith('/') ? url : `/${url}`;\n    let fullUrl = `${baseUrl}${path}`;\n\n    // Add query parameters\n    if (config.params && Object.keys(config.params).length > 0) {\n      const searchParams = this.buildQueryString(config.params);\n      fullUrl = `${fullUrl}?${searchParams}`;\n    }\n\n    return fullUrl;\n  }\n\n  /**\n   * Build query string from params object\n   */\n  private buildQueryString(params: QueryParams): string {\n    const searchParams = new URLSearchParams();\n\n    for (const [key, value] of Object.entries(params)) {\n      if (value === undefined || value === null) {\n        continue;\n      }\n\n      if (Array.isArray(value)) {\n        for (const item of value) {\n          searchParams.append(key, String(item));\n        }\n      } else {\n        searchParams.set(key, String(value));\n      }\n    }\n\n    return searchParams.toString();\n  }\n\n  /**\n   * Build request headers\n   */\n  private async buildHeaders(config: RequestConfig): Promise<Headers> {\n    const headers = new Headers();\n\n    // Add default headers\n    for (const [key, value] of Object.entries(this.config.headers)) {\n      if (value != null && value !== '') {\n        headers.set(key, value);\n      }\n    }\n\n    // Add config-specific headers\n    if (config.headers != null) {\n      for (const [key, value] of Object.entries(config.headers)) {\n        if (value != null && value !== '') {\n          headers.set(key, value);\n        }\n      }\n    }\n\n    // Add content type if body exists\n    if (config.body !== undefined && config.contentType != null) {\n      headers.set('Content-Type', config.contentType);\n    }\n\n    // Add authorization header using token provider\n    if (config.meta?.skipAuth !== true) {\n      const token = await this.tokenProvider.getAccessToken();\n      if (token != null && token !== '') {\n        headers.set('Authorization', `Bearer ${token}`);\n      }\n    }\n\n    // Add request ID\n    if (config.meta?.requestId != null && config.meta.requestId !== '') {\n      headers.set('X-Request-ID', config.meta.requestId);\n    }\n\n    // Add correlation ID\n    if (config.meta?.correlationId != null && config.meta.correlationId !== '') {\n      headers.set('X-Correlation-ID', config.meta.correlationId);\n    }\n\n    // Add idempotency key\n    if (config.meta?.idempotencyKey != null && config.meta.idempotencyKey !== '') {\n      headers.set('X-Idempotency-Key', config.meta.idempotencyKey);\n    }\n\n    return headers;\n  }\n\n  /**\n   * Serialize request body based on content type\n   */\n  private serializeBody(config: RequestConfig): BodyInit | undefined {\n    const { body, contentType } = config;\n\n    if (body === undefined) {\n      return undefined;\n    }\n\n    // Handle FormData directly\n    if (body instanceof FormData) {\n      return body;\n    }\n\n    // Handle Blob directly\n    if (body instanceof Blob) {\n      return body;\n    }\n\n    // Handle ArrayBuffer directly\n    if (body instanceof ArrayBuffer) {\n      return body;\n    }\n\n    // Handle streams\n    if (body instanceof ReadableStream) {\n      return body;\n    }\n\n    // Handle based on content type\n    switch (contentType) {\n      case 'application/x-www-form-urlencoded':\n        return new URLSearchParams(body as Record<string, string>).toString();\n\n      case 'multipart/form-data': {\n        const formData = new FormData();\n        for (const [key, value] of Object.entries(body as Record<string, unknown>)) {\n          if (value instanceof Blob) {\n            formData.append(key, value);\n          } else {\n            formData.append(key, String(value));\n          }\n        }\n        return formData;\n      }\n\n      case 'text/plain':\n        return typeof body === 'string' ? body : JSON.stringify(body);\n\n      case 'application/json':\n      default:\n        return JSON.stringify(body);\n    }\n  }\n\n  /**\n   * Parse response based on content type and config\n   */\n  private async parseResponse<T>(response: Response, config: RequestConfig): Promise<T> {\n    const responseType = config.responseType ?? 'json';\n\n    switch (responseType) {\n      case 'json': {\n        const text = await response.text();\n        if (!text) {\n          return undefined as T;\n        }\n        try {\n          return JSON.parse(text) as T;\n        } catch {\n          return text as T;\n        }\n      }\n\n      case 'text':\n        return (await response.text()) as T;\n\n      case 'blob':\n        return (await response.blob()) as T;\n\n      case 'arraybuffer':\n        return (await response.arrayBuffer()) as T;\n\n      case 'stream':\n        return response.body as T;\n\n      default:\n        return (await response.json()) as T;\n    }\n  }\n\n  /**\n   * Parse error response body\n   */\n  private async parseErrorResponse(response: Response): Promise<Partial<ApiError>> {\n    try {\n      const text = await response.text();\n      if (!text) {\n        return { message: `HTTP ${response.status}` };\n      }\n\n      try {\n        const json = JSON.parse(text) as ServerErrorResponse;\n        return parseServerError(json, response.status);\n      } catch {\n        return { message: text };\n      }\n    } catch {\n      return { message: `HTTP ${response.status}` };\n    }\n  }\n\n  /**\n   * Parse response headers into a plain object\n   */\n  private parseHeaders(headers: Headers): Record<string, string> {\n    const result: Record<string, string> = {};\n    headers.forEach((value, key) => {\n      result[key.toLowerCase()] = value;\n    });\n    return result;\n  }\n\n  /**\n   * Run request interceptors in sequence\n   */\n  private async runRequestInterceptors(config: RequestConfig): Promise<RequestConfig> {\n    let result = config;\n    for (const interceptor of this.requestInterceptors) {\n      result = await interceptor(result);\n    }\n    return result;\n  }\n\n  /**\n   * Run response interceptors in sequence\n   */\n  private async runResponseInterceptors<T>(response: ApiResponse<T>): Promise<ApiResponse<T>> {\n    let result = response;\n    for (const interceptor of this.responseInterceptors) {\n      result = await interceptor(result);\n    }\n    return result;\n  }\n\n  /**\n   * Run error interceptors in sequence\n   */\n  private async runErrorInterceptors(error: ApiError): Promise<ApiError> {\n    let result = error;\n    for (const interceptor of this.errorInterceptors) {\n      result = await interceptor(result);\n    }\n    return result;\n  }\n\n  /**\n   * Generate a unique request ID\n   */\n  private generateRequestId(): string {\n    return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n  }\n\n  /**\n   * Type guard for API errors\n   */\n  private isApiError(error: unknown): error is ApiError {\n    return (\n      error !== null &&\n      typeof error === 'object' &&\n      'name' in error &&\n      (error as ApiError).name === 'ApiError'\n    );\n  }\n\n  /**\n   * Promise-based delay utility\n   */\n  private async delay(ms: number): Promise<void> {\n    return new Promise((resolve) => setTimeout(resolve, ms));\n  }\n}\n\n// =============================================================================\n// FACTORY FUNCTION\n// =============================================================================\n\n/**\n * Create a new API client instance\n *\n * @param config - Client configuration\n * @returns Configured ApiClient instance\n *\n * @example\n * ```typescript\n * const client = createApiClient({\n *   baseUrl: 'https://api.example.com',\n *   timeout: 30000,\n *   autoRefreshToken: true,\n * });\n *\n * // Add global request logging\n * client.addRequestInterceptor((config) => {\n *   console.log(`[API] ${config.method} ${config.url}`);\n *   return config;\n * });\n *\n * // Make requests\n * const users = await client.get<User[]>('/users');\n * ```\n */\nexport function createApiClient(config: ApiClientConfig): ApiClient {\n  return new ApiClient(config);\n}\n\n// =============================================================================\n// SINGLETON INSTANCE\n// =============================================================================\n\n/**\n * Default API client instance configured with application defaults\n */\nexport const apiClient = createApiClient({\n  baseUrl: API_CONFIG.BASE_URL,\n  timeout: API_CONFIG.TIMEOUT.DEFAULT,\n  headers: API_CONFIG.HEADERS,\n  retry: {\n    maxAttempts: API_CONFIG.RETRY.ATTEMPTS,\n    baseDelay: API_CONFIG.RETRY.BASE_DELAY,\n    maxDelay: API_CONFIG.RETRY.MAX_DELAY,\n  },\n});\n\n// =============================================================================\n// UTILITY EXPORTS\n// =============================================================================\n\nexport { createApiError, isRetryable, getErrorCategory, getErrorSeverity };\n\n// Re-export rate limiter for convenience\nexport { RateLimiter, RateLimitError, RATE_LIMIT_PRESETS, type RateLimitConfig };\n"],"names":["DEFAULT_RETRY_CONFIG","TIMING","DEFAULT_CLIENT_CONFIG","API_CONFIG","inflightRequests","generateRequestKey","config","method","url","params","body","paramsStr","sortObject","bodyStr","obj","sorted","keys","key","tokenRefreshState","SECURE_API_TOKEN_KEYS","apiSessionEncryptionKey","generateApiSessionKey","keyBytes","getApiSessionEncryptionKey","secureApiTokenStorage","getSecureApiStorage","isSecureStorageAvailable","createSecureLocalStorage","tokenCache","defaultTokenProvider","storage","result","token","error","createTokenRefreshFn","tokenProvider","refreshToken","response","data","getErrorCategory","status","getErrorSeverity","category","isRetryable","retryConfig","createApiError","message","options","severity","parseServerError","_status","code","fieldErrors","errorMessage","errorCode","responseCode","err","ApiClient","rateLimitConfig","RATE_LIMIT_PRESETS","RateLimiter","requestId","meta","processedConfig","RateLimitError","apiError","interceptor","index","fn","provider","endpoint","controller","cacheKey","inflight","promise","resolve","reject","attempt","abortController","startTime","headers","requestInit","timeout","timeoutId","endTime","timing","rateLimitHeaders","errorResponse","retryAfter","delay","calculateBackoffWithJitter","apiResponse","processedError","value","baseUrl","path","fullUrl","searchParams","item","contentType","formData","text","json","ms","createApiClient","apiClient"],"mappings":";;;;;AA8EA,MAAMA,IAAoC;AAAA,EACxC,aAAaC,EAAO,MAAM;AAAA,EAC1B,WAAWA,EAAO,IAAI;AAAA,EACtB,UAAUA,EAAO,IAAI;AAAA,EACrB,eAAe;AAAA,EACf,sBAAsB,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAAA,EACnD,qBAAqB;AACvB,GAKMC,IAAkD;AAAA,EACtD,SAASC,EAAW,QAAQ;AAAA,EAC5B,SAAS;AAAA,IACP,gBAAgB;AAAA,IAChB,QAAU;AAAA,EAAA;AAAA,EAEZ,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,uBAAuBF,EAAO,KAAK;AAAA,EACnC,aAAa;AACf,GASMG,wBAAuB,IAAA;AAK7B,SAASC,EAAmBC,GAA+B;AACzD,QAAM,EAAE,QAAAC,GAAQ,KAAAC,GAAK,QAAAC,GAAQ,MAAAC,MAASJ,GAChCK,IAAYF,KAAU,OAAO,KAAK,UAAUG,EAAWH,CAAM,CAAC,IAAI,IAClEI,IAAUH,KAAQ,OAAO,KAAK,UAAUA,CAAI,IAAI;AACtD,SAAO,GAAGH,CAAM,IAAIC,CAAG,IAAIG,CAAS,IAAIE,CAAO;AACjD;AAKA,SAASD,EAA8CE,GAAW;AAChE,QAAMC,IAAS,CAAA,GACTC,IAAO,OAAO,KAAKF,CAAG,EAAE,KAAA;AAC9B,aAAWG,KAAOD;AAChB,IAAAD,EAAOE,CAAG,IAAIH,EAAIG,CAAG;AAEvB,SAAOF;AACT;AAkBA,MAAMG,IAAuC;AAAA,EAC3C,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,iBAAiB,CAAA;AACnB,GAOMC,IAAwB;AAAA,EAC5B,cAAc;AAAA,EACd,eAAe;AACjB;AAWA,IAAIC,IAAyC;AAS7C,SAASC,IAAgC;AACvC,QAAMC,IAAW,IAAI,WAAW,EAAE;AAClC,gBAAO,gBAAgBA,CAAQ,GACxB,KAAK,OAAO,aAAa,GAAGA,CAAQ,CAAC;AAC9C;AAKA,SAASC,IAAqC;AAC5C,SAAAH,MAA4BC,EAAA,GACrBD;AACT;AAKA,IAAII,IAA8C;AAOlD,SAASC,IAA4C;AACnD,SAAKC,OAGLF,MAA0BG,EAAyBJ,GAA4B,GACxEC,KAHE;AAIX;AAQA,MAAMI,IAGF;AAAA,EACF,aAAa;AAAA,EACb,cAAc;AAChB,GAiBMC,IAAsC;AAAA,EAC1C,gBAAgB,YAAoC;AAElD,QAAID,EAAW,eAAe,QAAQA,EAAW,gBAAgB;AAC/D,aAAOA,EAAW;AAGpB,UAAME,IAAUL,EAAA;AAChB,QAAIK,KAAW;AAEb,aAAO;AAGT,QAAI;AACF,YAAMC,IAAS,MAAMD,EAAQ,QAAgBX,EAAsB,YAAY;AAC/E,UAAIY,EAAO,WAAWA,EAAO,QAAQ,QAAQA,EAAO,SAAS;AAC3D,eAAAH,EAAW,cAAcG,EAAO,MACzBA,EAAO;AAAA,IAElB,QAAQ;AAEN,cAAQ,KAAK,iEAAiE;AAAA,IAChF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,iBAAiB,YAAoC;AAEnD,QAAIH,EAAW,gBAAgB,QAAQA,EAAW,iBAAiB;AACjE,aAAOA,EAAW;AAGpB,UAAME,IAAUL,EAAA;AAChB,QAAIK,KAAW;AACb,aAAO;AAGT,QAAI;AACF,YAAMC,IAAS,MAAMD,EAAQ,QAAgBX,EAAsB,aAAa;AAChF,UAAIY,EAAO,WAAWA,EAAO,QAAQ,QAAQA,EAAO,SAAS;AAC3D,eAAAH,EAAW,eAAeG,EAAO,MAC1BA,EAAO;AAAA,IAElB,QAAQ;AACN,cAAQ,KAAK,kEAAkE;AAAA,IACjF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,gBAAgB,OAAOC,MAAiC;AAEtD,IAAAJ,EAAW,cAAcI;AAEzB,UAAMF,IAAUL,EAAA;AAChB,QAAKK;AAIL,UAAI;AACF,cAAMC,IAAS,MAAMD,EAAQ,QAAQX,EAAsB,cAAca,CAAK;AAC9E,QAAKD,EAAO,WACV,QAAQ,MAAM,8CAA8CA,EAAO,KAAK;AAAA,MAE5E,SAASE,GAAO;AACd,gBAAQ,MAAM,+CAA+CA,CAAK;AAAA,MACpE;AAAA,EACF;AAAA,EAEA,iBAAiB,OAAOD,MAAiC;AAEvD,IAAAJ,EAAW,eAAeI;AAE1B,UAAMF,IAAUL,EAAA;AAChB,QAAKK;AAIL,UAAI;AACF,cAAMC,IAAS,MAAMD,EAAQ,QAAQX,EAAsB,eAAea,CAAK;AAC/E,QAAKD,EAAO,WACV,QAAQ,MAAM,+CAA+CA,EAAO,KAAK;AAAA,MAE7E,SAASE,GAAO;AACd,gBAAQ,MAAM,gDAAgDA,CAAK;AAAA,MACrE;AAAA,EACF;AAAA,EAEA,aAAa,YAA2B;AAEtC,IAAAL,EAAW,cAAc,MACzBA,EAAW,eAAe;AAE1B,UAAME,IAAUL,EAAA;AAChB,QAAKK;AAIL,UAAI;AACF,cAAM,QAAQ,IAAI;AAAA,UAChB,QAAQ,QAAQA,EAAQ,WAAWX,EAAsB,YAAY,CAAC;AAAA,UACtE,QAAQ,QAAQW,EAAQ,WAAWX,EAAsB,aAAa,CAAC;AAAA,QAAA,CACxE;AAAA,MACH,SAASc,GAAO;AACd,gBAAQ,MAAM,2DAA2DA,CAAK;AAAA,MAChF;AAAA,EACF;AACF;AAKA,SAASC,EAAqBC,GAAqD;AACjF,SAAO,iBAA+C;AACpD,UAAMC,IAAe,MAAMD,EAAc,gBAAA;AACzC,QAAIC,KAAgB,QAAQA,MAAiB;AAC3C,YAAM,IAAI,MAAM,4BAA4B;AAG9C,UAAMC,IAAW,MAAM,MAAM,GAAGlC,EAAW,QAAQ,GAAGA,EAAW,UAAU,KAAK,OAAO,IAAI;AAAA,MACzF,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAA;AAAA,MAC3B,MAAM,KAAK,UAAU,EAAE,cAAAiC,GAAc;AAAA,IAAA,CACtC;AAED,QAAI,CAACC,EAAS;AACZ,YAAM,IAAI,MAAM,sBAAsB;AAGxC,UAAMC,IAAO,MAAMD,EAAS,KAAA;AAC5B,iBAAMF,EAAc,eAAeG,EAAK,WAAW,GAC/CA,EAAK,gBAAgB,QAAQA,EAAK,iBAAiB,MACrD,MAAMH,EAAc,gBAAgBG,EAAK,YAAY,GAGhDA,EAAK;AAAA,EACd;AACF;AASA,SAASC,EAAiBC,GAA+B;AACvD,SAAIA,MAAW,MAAY,mBACvBA,MAAW,MAAY,kBACvBA,MAAW,MAAY,cACvBA,MAAW,MAAY,aACvBA,MAAW,OAAOA,MAAW,MAAY,eACzCA,MAAW,MAAY,eACvBA,MAAW,MAAY,YACvBA,KAAU,MAAY,WACnB;AACT;AAKA,SAASC,EAAiBC,GAAwC;AAChE,UAAQA,GAAA;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EAAA;AAEb;AAKA,SAASC,EAAYH,GAAgBI,GAAmC;AACtE,SAAOA,EAAY,qBAAqB,SAASJ,CAAM;AACzD;AAKA,SAASK,EACPL,GACAM,GACAC,IAQI,CAAA,GACM;AACV,QAAML,IAAWH,EAAiBC,CAAM,GAClCQ,IAAWP,EAAiBC,CAAQ,GACpCE,IAAc5C,GAEdiC,IAAQ,IAAI,MAAMa,CAAO;AAC/B,SAAAb,EAAM,OAAO,YACbA,EAAM,SAASO,GACfP,EAAM,OAAOc,EAAQ,QAAQ,QAAQP,CAAM,IAC3CP,EAAM,UAAUa,GAChBb,EAAM,WAAWS,GACjBT,EAAM,WAAWe,GACjBf,EAAM,cAAcc,EAAQ,aAC5Bd,EAAM,UAAUc,EAAQ,SACxBd,EAAM,WAAWc,EAAQ,UACzBd,EAAM,YAAYc,EAAQ,WAC1Bd,EAAM,gBAAgBc,EAAQ,eAC9Bd,EAAM,YAAY,KAAK,IAAA,GACvBA,EAAM,QAAQc,EAAQ,OACtBd,EAAM,YAAYU,EAAYH,GAAQI,CAAW,GAE1CX;AACT;AAKA,SAASgB,EAAiBZ,GAA+Ba,GAAoC;AAC3F,MAAIJ,IAAU,gCACVK;AACJ,QAAMC,IAAyD,CAAA;AAE/D,MAAI,OAAOf,EAAS,WAAY;AAC9B,KAAC,EAAE,SAAAS,MAAYT;AAAA,WACN,OAAOA,EAAS,SAAU;AACnC,IAAAS,IAAUT,EAAS;AAAA,WACVA,EAAS,SAAS,MAAM;AACjC,UAAM,EAAE,SAASgB,GAAc,MAAMC,EAAA,IAAcjB,EAAS;AAC5D,IAAAS,IAAUO,GACVF,IAAOG;AAAA,EACT;AAEA,MAAIjB,EAAS,QAAQ,QAAQA,EAAS,SAAS,IAAI;AACjD,UAAM,EAAE,MAAMkB,EAAA,IAAiBlB;AAC/B,IAAAc,IAAOI;AAAA,EACT;AAEA,MAAI,MAAM,QAAQlB,EAAS,MAAM;AAC/B,eAAWmB,KAAOnB,EAAS;AACzB,MAAAe,EAAY,KAAK,EAAE,OAAOI,EAAI,OAAO,SAASA,EAAI,SAAS;AAI/D,SAAO,EAAE,SAAAV,GAAS,MAAAK,GAAM,aAAaC,EAAY,SAAS,IAAIA,IAAc,OAAA;AAC9E;AASO,MAAMK,EAAU;AAAA,EACb;AAAA,EACS,sBAA4C,CAAA;AAAA,EAC5C,uBAA8C,CAAA;AAAA,EAC9C,oBAAwC,CAAA;AAAA,EACjD;AAAA,EACA;AAAA,EACA,uCAAuB,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvB,cAAkC;AAAA,EAE1C,YAAYnD,GAAyB;AA4BnC,QA1BA,KAAK,gBAAgBA,EAAO,iBAAiBuB,GAE7C,KAAK,SAAS;AAAA,MACZ,GAAG3B;AAAA,MACH,GAAGI;AAAA,MACH,OAAO,EAAE,GAAGN,GAAsB,GAAGM,EAAO,MAAA;AAAA,MAC5C,SAAS,EAAE,GAAGJ,EAAsB,SAAS,GAAGI,EAAO,QAAA;AAAA,MACvD,qBAAqBA,EAAO,uBAAuB,CAAA;AAAA,MACnD,sBAAsBA,EAAO,wBAAwB,CAAA;AAAA,MACrD,mBAAmBA,EAAO,qBAAqB,CAAA;AAAA,MAC/C,SAASA,EAAO,YAAY,MAAM;AAAA,MAAC;AAAA,MACnC,gBAAgBA,EAAO,mBAAmB,MAAM;AAAA,MAAC;AAAA,MACjD,cAAcA,EAAO,iBAAiB,MAAM;AAAA,MAAC;AAAA,MAC7C,OAAOA,EAAO,SAAS,MAAM,KAAK,UAAU;AAAA,MAC5C,eAAe,KAAK;AAAA,IAAA,GAItB,KAAK,sBAAsB,CAAC,GAAG,KAAK,OAAO,mBAAmB,GAC9D,KAAK,uBAAuB,CAAC,GAAG,KAAK,OAAO,oBAAoB,GAChE,KAAK,oBAAoB,CAAC,GAAG,KAAK,OAAO,iBAAiB,GAG1D,KAAK,iBAAiB4B,EAAqB,KAAK,aAAa,GAGzD5B,EAAO,aAAa,MAAM;AAC5B,YAAMoD,IACJ,OAAOpD,EAAO,aAAc,WACxBqD,EAAmBrD,EAAO,SAA4C,IACtEA,EAAO;AACb,WAAK,cAAc,IAAIsD,EAAYF,CAAe;AAAA,IACpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,IACJlD,GACAuC,IAA0D,IACzB;AACjC,WAAO,KAAK,QAAmB,EAAE,GAAGA,GAAS,QAAQ,OAAO,KAAAvC,GAAK;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJA,GACAE,GACAqC,IAA0D,CAAA,GACzB;AACjC,WAAO,KAAK,QAAmB,EAAE,GAAGA,GAAS,QAAQ,QAAQ,KAAAvC,GAAK,MAAAE,GAAM;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,IACJF,GACAE,GACAqC,IAA0D,CAAA,GACzB;AACjC,WAAO,KAAK,QAAmB,EAAE,GAAGA,GAAS,QAAQ,OAAO,KAAAvC,GAAK,MAAAE,GAAM;AAAA,EACzE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MACJF,GACAE,GACAqC,IAA0D,CAAA,GACzB;AACjC,WAAO,KAAK,QAAmB,EAAE,GAAGA,GAAS,QAAQ,SAAS,KAAAvC,GAAK,MAAAE,GAAM;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OACJF,GACAuC,IAAiD,IAChB;AACjC,WAAO,KAAK,QAAmB,EAAE,GAAGA,GAAS,QAAQ,UAAU,KAAAvC,GAAK;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KACJA,GACAuC,IAA0D,IAC9B;AAC5B,WAAO,KAAK,QAAc,EAAE,GAAGA,GAAS,QAAQ,QAAQ,KAAAvC,GAAK;AAAA,EAC/D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAmBF,GAAwD;AAC/E,UAAMuD,IAAY,KAAK,kBAAA,GACjBC,IAAoB;AAAA,MACxB,GAAGxD,EAAO;AAAA,MACV,WAAAuD;AAAA,MACA,WAAW,KAAK,IAAA;AAAA,IAAI;AAGtB,QAAIE,IAAyD,EAAE,GAAGzD,GAAQ,MAAAwD,EAAA;AAG1E,IAAAC,IAAmB,MAAM,KAAK;AAAA,MAC5BA;AAAA,IAAA;AAIF,UAAMvD,IAAM,KAAK,SAASuD,CAAe;AAGzC,QAAI,KAAK,eAAe,QAAUzD,EAAO,MAAM,kBAAkB;AAC/D,UAAI;AACF,eAAO,MAAM,KAAK,YAAY,QAAQE,GAAK,YAClC,KAAK,wBAAmCuD,GAAiBF,CAAS,CAC1E;AAAA,MACH,SAAS5B,GAAO;AACd,YAAIA,aAAiB+B,GAAgB;AAEnC,gBAAMC,IAAWpB,EAAe,KAAKZ,EAAM,SAAS;AAAA,YAClD,MAAM;AAAA,YACN,SAAS8B;AAAA,YACT,WAAAF;AAAA,UAAA,CACD;AACD,gBAAAI,EAAS,YAAY,IACfA;AAAA,QACR;AACA,cAAMhC;AAAA,MACR;AAGF,WAAO,KAAK,wBAAmC8B,GAAiBF,CAAS;AAAA,EAC3E;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsBK,GAA6C;AACjE,gBAAK,oBAAoB,KAAKA,CAAW,GAClC,MAAM;AACX,YAAMC,IAAQ,KAAK,oBAAoB,QAAQD,CAAW;AAC1D,MAAIC,MAAU,MACZ,KAAK,oBAAoB,OAAOA,GAAO,CAAC;AAAA,IAE5C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,uBAAuBD,GAA8C;AACnE,gBAAK,qBAAqB,KAAKA,CAAW,GACnC,MAAM;AACX,YAAMC,IAAQ,KAAK,qBAAqB,QAAQD,CAAW;AAC3D,MAAIC,MAAU,MACZ,KAAK,qBAAqB,OAAOA,GAAO,CAAC;AAAA,IAE7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoBD,GAA2C;AAC7D,gBAAK,kBAAkB,KAAKA,CAAW,GAChC,MAAM;AACX,YAAMC,IAAQ,KAAK,kBAAkB,QAAQD,CAAW;AACxD,MAAIC,MAAU,MACZ,KAAK,kBAAkB,OAAOA,GAAO,CAAC;AAAA,IAE1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgBC,GAAiC;AAC/C,SAAK,iBAAiBA;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,mBAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,iBAAiBC,GAA+B;AAC9C,SAAK,gBAAgBA,GACrB,KAAK,iBAAiBnC,EAAqBmC,CAAQ;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAqC;AACnC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoBA,aAAa/D,GAAiE;AAC5E,UAAMoD,IACJ,OAAOpD,KAAW,WAAWqD,EAAmBrD,CAAM,IAAIA;AAC5D,SAAK,cAAc,IAAIsD,EAAYF,CAAe;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,mBAAyB;AACvB,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,mBAAmBY,GAA2B;AAC5C,WAAO,KAAK,aAAa,eAAeA,CAAQ,KAAK;AAAA,EACvD;AAAA;AAAA;AAAA;AAAA,EAKA,cAAcT,GAAyB;AACrC,UAAMU,IAAa,KAAK,iBAAiB,IAAIV,CAAS;AACtD,IAAIU,MACFA,EAAW,MAAA,GACX,KAAK,iBAAiB,OAAOV,CAAS;AAAA,EAE1C;AAAA;AAAA;AAAA;AAAA,EAKA,oBAA0B;AACxB,eAAWU,KAAc,KAAK,iBAAiB,OAAA;AAC7C,MAAAA,EAAW,MAAA;AAEb,SAAK,iBAAiB,MAAA;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,wBACZjE,GACAuD,GACiC;AAEjC,QAAI,KAAK,OAAO,eAAevD,EAAO,WAAW,SAAWA,EAAO,MAAM,aAAa,IAAO;AAC3F,YAAMkE,IAAWnE,EAAmBC,CAAM,GACpCmE,IAAWrE,EAAiB,IAAIoE,CAAQ;AAC9C,UAAIC;AACF,eAAOA;AAGT,YAAMC,IAAU,KAAK,eAA0BpE,GAAQuD,CAAS;AAChE,MAAAzD,EAAiB,IAAIoE,GAAUE,CAA+B;AAE9D,UAAI;AACF,eAAO,MAAMA;AAAA,MACf,UAAA;AACE,QAAAtE,EAAiB,OAAOoE,CAAQ;AAAA,MAClC;AAAA,IACF;AAEA,WAAO,KAAK,eAA0BlE,GAAQuD,CAAS;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,eAAgC;AAC5C,QAAI3C,EAAkB,gBAAgBA,EAAkB;AACtD,aAAOA,EAAkB;AAG3B,IAAAA,EAAkB,eAAe,IACjCA,EAAkB,iBAAiB,KAAK,eAAA;AAExC,QAAI;AACF,YAAMc,IAAQ,MAAMd,EAAkB;AAGtC,iBAAW,EAAE,SAAAyD,OAAazD,EAAkB;AAC1C,QAAAyD,EAAQ3C,CAAK;AAEf,aAAAd,EAAkB,kBAAkB,CAAA,GAE7Bc;AAAA,IACT,SAASC,GAAO;AAEd,iBAAW,EAAE,QAAA2C,OAAY1D,EAAkB;AACzC,QAAA0D,EAAO3C,aAAiB,QAAQA,IAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,CAAC;AAElE,YAAAf,EAAkB,kBAAkB,CAAA,GAE9Be;AAAA,IACR,UAAA;AACE,MAAAf,EAAkB,eAAe,IACjCA,EAAkB,iBAAiB;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAc,eACZZ,GACAuD,GACAgB,IAAU,GACuB;AACjC,UAAMjC,IAAc,EAAE,GAAG5C,GAAsB,GAAG,KAAK,OAAO,OAAO,GAAGM,EAAO,MAAA,GACzEwE,IAAkB,IAAI,gBAAA;AAC5B,SAAK,iBAAiB,IAAIjB,GAAWiB,CAAe,GAGhDxE,EAAO,UACTA,EAAO,OAAO,iBAAiB,SAAS,MAAMwE,EAAgB,OAAO;AAGvE,UAAMC,IAAY,KAAK,IAAA;AACvB,SAAK,OAAO,eAAezE,CAAM;AAEjC,QAAI;AAEF,YAAME,IAAM,KAAK,SAASF,CAAM,GAG1B0E,IAAU,MAAM,KAAK,aAAa1E,CAAM,GAGxC2E,IAA2B;AAAA,QAC/B,QAAQ3E,EAAO;AAAA,QACf,SAAA0E;AAAA,QACA,QAAQF,EAAgB;AAAA,QACxB,aAAaxE,EAAO,eAAe,KAAK,OAAO;AAAA,QAC/C,OAAOA,EAAO;AAAA,MAAA;AAIhB,MAAIA,EAAO,SAAS,UAAa,CAAC,QAAQ,OAAO,OAAO,EAAE,SAASA,EAAO,MAAM,MAC9E2E,EAAY,OAAO,KAAK,cAAc3E,CAAM;AAI9C,YAAM4E,IACJ5E,EAAO,WAAW,QAAQA,EAAO,YAAY,IAAIA,EAAO,UAAU,KAAK,OAAO,SAC1E6E,IAAY,WAAW,MAAML,EAAgB,MAAA,GAASI,CAAO;AAEnE,UAAI;AACF,cAAM7C,IAAW,MAAM,KAAK,OAAO,MAAM7B,GAAKyE,CAAW;AACzD,qBAAaE,CAAS;AAEtB,cAAMC,IAAU,KAAK,IAAA,GACfC,IAAyB;AAAA,UAC7B,WAAAN;AAAA,UACA,SAAAK;AAAA,UACA,UAAUA,IAAUL;AAAA,QAAA;AAItB,YAAI,KAAK,eAAe,MAAM;AAC5B,gBAAMO,IAAmB;AAAA,YACvB,yBAAyBjD,EAAS,QAAQ,IAAI,uBAAuB,KAAK;AAAA,YAC1E,qBAAqBA,EAAS,QAAQ,IAAI,mBAAmB,KAAK;AAAA,YAClE,qBAAqBA,EAAS,QAAQ,IAAI,mBAAmB,KAAK;AAAA,YAClE,eAAeA,EAAS,QAAQ,IAAI,aAAa,KAAK;AAAA,UAAA;AAExD,eAAK,YAAY,kBAAkB7B,GAAK8E,CAAgB;AAAA,QAC1D;AAGA,YAAI,CAACjD,EAAS,IAAI;AAChB,gBAAMkD,IAAgB,MAAM,KAAK,mBAAmBlD,CAAQ,GACtD4B,IAAWpB;AAAA,YACfR,EAAS;AAAA,YACTkD,EAAc,WAAW,QAAQlD,EAAS,MAAM;AAAA,YAChD;AAAA,cACE,MAAMkD,EAAc;AAAA,cACpB,UAAUA;AAAA,cACV,SAASjF;AAAA,cACT,WAAAuD;AAAA,cACA,aAAa0B,EAAc;AAAA,YAAA;AAAA,UAC7B;AAIF,cAAIlD,EAAS,WAAW,OAAO,KAAK,eAAe,MAAM;AACvD,kBAAMmD,IAAanD,EAAS,QAAQ,IAAI,aAAa,KAAK;AAC1D,iBAAK,YAAY,UAAU7B,GAAKgF,CAAU;AAAA,UAC5C;AAGA,cACEnD,EAAS,WAAW,OACpB,KAAK,OAAO,oBACZ/B,EAAO,MAAM,aAAa;AAE1B,gBAAI;AACF,2BAAM,KAAK,aAAA,GAEJ,KAAK,eAA0BA,GAAQuD,GAAWgB,CAAO;AAAA,YAClE,QAAQ;AAAA,YAER;AAIF,cACEZ,EAAS,aACTY,IAAUjC,EAAY,cAAc,KACpCtC,EAAO,MAAM,cAAc,OAGzBsC,EAAY,eAAe,OAAOA,EAAY,YAAYqB,GAAUY,CAAO,IAAI,QAE7D,IAAM;AACxB,YAAAjC,EAAY,UAAUqB,GAAUY,CAAO;AACvC,kBAAMY,IAAQC;AAAA,cACZb;AAAA,cACAjC,EAAY;AAAA,cACZA,EAAY;AAAA,YAAA;AAEd,yBAAM,KAAK,MAAM6C,CAAK,GACf,KAAK,eAA0BnF,GAAQuD,GAAWgB,IAAU,CAAC;AAAA,UACtE;AAGF,gBAAMZ;AAAA,QACR;AAMA,YAAI0B,IAAsC;AAAA,UACxC,MAJW,MAAM,KAAK,cAAyBtD,GAAU/B,CAAM;AAAA,UAK/D,QAAQ+B,EAAS;AAAA,UACjB,YAAYA,EAAS;AAAA,UACrB,SAAS,KAAK,aAAaA,EAAS,OAAO;AAAA,UAC3C,SAAS/B;AAAA,UACT,QAAA+E;AAAA,QAAA;AAIF,eAAAM,IAAc,MAAM,KAAK,wBAAwBA,CAAW,GAE5D,KAAK,OAAO,aAAaA,CAAW,GAE7BA;AAAA,MACT,UAAA;AACE,qBAAaR,CAAS,GACtB,KAAK,iBAAiB,OAAOtB,CAAS;AAAA,MACxC;AAAA,IACF,SAAS5B,GAAO;AAId,UAHA,KAAK,iBAAiB,OAAO4B,CAAS,GAGlC5B,aAAiB,gBAAgBA,EAAM,SAAS,cAAc;AAChE,cAAMgC,IAAWpB,EAAe,GAAG,yBAAyB;AAAA,UAC1D,MAAM;AAAA,UACN,SAASvC;AAAA,UACT,WAAAuD;AAAA,QAAA,CACD;AACDI,cAAAA,EAAS,WAAW,aACpBA,EAAS,YAAY,IACfA;AAAAA,MACR;AAGA,UAAIhC,aAAiB,aAAaA,EAAM,QAAQ,SAAS,OAAO,GAAG;AACjE,cAAMgC,IAAWpB,EAAe,GAAG,0BAA0B;AAAA,UAC3D,MAAM;AAAA,UACN,SAASvC;AAAA,UACT,WAAAuD;AAAA,UACA,OAAO5B;AAAA,QAAA,CACR;AAID,YAHAgC,EAAS,WAAW,WAIlBrB,EAAY,wBAAwB,MACpCiC,IAAUjC,EAAY,cAAc,KACpCtC,EAAO,MAAM,cAAc,IAC3B;AACA,UAAAsC,EAAY,UAAUqB,GAAUY,CAAO;AACvC,gBAAMY,IAAQC;AAAA,YACZb;AAAA,YACAjC,EAAY;AAAA,YACZA,EAAY;AAAA,UAAA;AAEd,uBAAM,KAAK,MAAM6C,CAAK,GACf,KAAK,eAA0BnF,GAAQuD,GAAWgB,IAAU,CAAC;AAAA,QACtE;AAEA,cAAMZ;AAAAA,MACR;AAGA,UAAI,KAAK,WAAWhC,CAAK,GAAG;AAE1B,cAAM2D,IAAiB,MAAM,KAAK,qBAAqB3D,CAAK;AAC5D,mBAAK,OAAO,QAAQ2D,CAAc,GAClC,KAAK,OAAO,aAAaA,CAAc,GACjCA;AAAAA,MACR;AAGA,YAAM3B,IAAWpB,EAAe,GAAG,gCAAgC;AAAA,QACjE,MAAM;AAAA,QACN,SAASvC;AAAA,QACT,WAAAuD;AAAA,QACA,OAAO5B,aAAiB,QAAQA,IAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC;AAAA,MAAA,CAChE,GAEK2D,IAAiB,MAAM,KAAK,qBAAqB3B,CAAQ;AAC/D,iBAAK,OAAO,QAAQ2B,CAAc,GAClC,KAAK,OAAO,aAAaA,CAAc,GACjCA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,SAAStF,GAA+B;AAC9C,QAAI,EAAE,KAAAE,MAAQF;AAGd,QAAIA,EAAO;AACT,iBAAW,CAACW,GAAK4E,CAAK,KAAK,OAAO,QAAQvF,EAAO,UAAU;AACzD,QAAAE,IAAMA,EAAI,QAAQ,IAAIS,CAAG,IAAI,mBAAmB,OAAO4E,CAAK,CAAC,CAAC;AAKlE,UAAMC,IAAU,KAAK,OAAO,QAAQ,QAAQ,OAAO,EAAE,GAC/CC,IAAOvF,EAAI,WAAW,GAAG,IAAIA,IAAM,IAAIA,CAAG;AAChD,QAAIwF,IAAU,GAAGF,CAAO,GAAGC,CAAI;AAG/B,QAAIzF,EAAO,UAAU,OAAO,KAAKA,EAAO,MAAM,EAAE,SAAS,GAAG;AAC1D,YAAM2F,IAAe,KAAK,iBAAiB3F,EAAO,MAAM;AACxD,MAAA0F,IAAU,GAAGA,CAAO,IAAIC,CAAY;AAAA,IACtC;AAEA,WAAOD;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiBvF,GAA6B;AACpD,UAAMwF,IAAe,IAAI,gBAAA;AAEzB,eAAW,CAAChF,GAAK4E,CAAK,KAAK,OAAO,QAAQpF,CAAM;AAC9C,UAA2BoF,KAAU;AAIrC,YAAI,MAAM,QAAQA,CAAK;AACrB,qBAAWK,KAAQL;AACjB,YAAAI,EAAa,OAAOhF,GAAK,OAAOiF,CAAI,CAAC;AAAA;AAGvC,UAAAD,EAAa,IAAIhF,GAAK,OAAO4E,CAAK,CAAC;AAIvC,WAAOI,EAAa,SAAA;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAAa3F,GAAyC;AAClE,UAAM0E,IAAU,IAAI,QAAA;AAGpB,eAAW,CAAC/D,GAAK4E,CAAK,KAAK,OAAO,QAAQ,KAAK,OAAO,OAAO;AAC3D,MAAIA,KAAS,QAAQA,MAAU,MAC7Bb,EAAQ,IAAI/D,GAAK4E,CAAK;AAK1B,QAAIvF,EAAO,WAAW;AACpB,iBAAW,CAACW,GAAK4E,CAAK,KAAK,OAAO,QAAQvF,EAAO,OAAO;AACtD,QAAIuF,KAAS,QAAQA,MAAU,MAC7Bb,EAAQ,IAAI/D,GAAK4E,CAAK;AAW5B,QALIvF,EAAO,SAAS,UAAaA,EAAO,eAAe,QACrD0E,EAAQ,IAAI,gBAAgB1E,EAAO,WAAW,GAI5CA,EAAO,MAAM,aAAa,IAAM;AAClC,YAAM0B,IAAQ,MAAM,KAAK,cAAc,eAAA;AACvC,MAAIA,KAAS,QAAQA,MAAU,MAC7BgD,EAAQ,IAAI,iBAAiB,UAAUhD,CAAK,EAAE;AAAA,IAElD;AAGA,WAAI1B,EAAO,MAAM,aAAa,QAAQA,EAAO,KAAK,cAAc,MAC9D0E,EAAQ,IAAI,gBAAgB1E,EAAO,KAAK,SAAS,GAI/CA,EAAO,MAAM,iBAAiB,QAAQA,EAAO,KAAK,kBAAkB,MACtE0E,EAAQ,IAAI,oBAAoB1E,EAAO,KAAK,aAAa,GAIvDA,EAAO,MAAM,kBAAkB,QAAQA,EAAO,KAAK,mBAAmB,MACxE0E,EAAQ,IAAI,qBAAqB1E,EAAO,KAAK,cAAc,GAGtD0E;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc1E,GAA6C;AACjE,UAAM,EAAE,MAAAI,GAAM,aAAAyF,EAAA,IAAgB7F;AAE9B,QAAII,MAAS,QAoBb;AAAA,UAfIA,aAAgB,YAKhBA,aAAgB,QAKhBA,aAAgB,eAKhBA,aAAgB;AAClB,eAAOA;AAIT,cAAQyF,GAAA;AAAA,QACN,KAAK;AACH,iBAAO,IAAI,gBAAgBzF,CAA8B,EAAE,SAAA;AAAA,QAE7D,KAAK,uBAAuB;AAC1B,gBAAM0F,IAAW,IAAI,SAAA;AACrB,qBAAW,CAACnF,GAAK4E,CAAK,KAAK,OAAO,QAAQnF,CAA+B;AACvE,YAAImF,aAAiB,OACnBO,EAAS,OAAOnF,GAAK4E,CAAK,IAE1BO,EAAS,OAAOnF,GAAK,OAAO4E,CAAK,CAAC;AAGtC,iBAAOO;AAAA,QACT;AAAA,QAEA,KAAK;AACH,iBAAO,OAAO1F,KAAS,WAAWA,IAAO,KAAK,UAAUA,CAAI;AAAA,QAE9D,KAAK;AAAA,QACL;AACE,iBAAO,KAAK,UAAUA,CAAI;AAAA,MAAA;AAAA;AAAA,EAEhC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cAAiB2B,GAAoB/B,GAAmC;AAGpF,YAFqBA,EAAO,gBAAgB,QAEpC;AAAA,MACN,KAAK,QAAQ;AACX,cAAM+F,IAAO,MAAMhE,EAAS,KAAA;AAC5B,YAAI,CAACgE;AACH;AAEF,YAAI;AACF,iBAAO,KAAK,MAAMA,CAAI;AAAA,QACxB,QAAQ;AACN,iBAAOA;AAAA,QACT;AAAA,MACF;AAAA,MAEA,KAAK;AACH,eAAQ,MAAMhE,EAAS,KAAA;AAAA,MAEzB,KAAK;AACH,eAAQ,MAAMA,EAAS,KAAA;AAAA,MAEzB,KAAK;AACH,eAAQ,MAAMA,EAAS,YAAA;AAAA,MAEzB,KAAK;AACH,eAAOA,EAAS;AAAA,MAElB;AACE,eAAQ,MAAMA,EAAS,KAAA;AAAA,IAAK;AAAA,EAElC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,mBAAmBA,GAAgD;AAC/E,QAAI;AACF,YAAMgE,IAAO,MAAMhE,EAAS,KAAA;AAC5B,UAAI,CAACgE;AACH,eAAO,EAAE,SAAS,QAAQhE,EAAS,MAAM,GAAA;AAG3C,UAAI;AACF,cAAMiE,IAAO,KAAK,MAAMD,CAAI;AAC5B,eAAOpD,EAAiBqD,GAAMjE,EAAS,MAAM;AAAA,MAC/C,QAAQ;AACN,eAAO,EAAE,SAASgE,EAAA;AAAA,MACpB;AAAA,IACF,QAAQ;AACN,aAAO,EAAE,SAAS,QAAQhE,EAAS,MAAM,GAAA;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa2C,GAA0C;AAC7D,UAAMjD,IAAiC,CAAA;AACvC,WAAAiD,EAAQ,QAAQ,CAACa,GAAO5E,MAAQ;AAC9B,MAAAc,EAAOd,EAAI,YAAA,CAAa,IAAI4E;AAAA,IAC9B,CAAC,GACM9D;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,uBAAuBzB,GAA+C;AAClF,QAAIyB,IAASzB;AACb,eAAW4D,KAAe,KAAK;AAC7B,MAAAnC,IAAS,MAAMmC,EAAYnC,CAAM;AAEnC,WAAOA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,wBAA2BM,GAAmD;AAC1F,QAAIN,IAASM;AACb,eAAW6B,KAAe,KAAK;AAC7B,MAAAnC,IAAS,MAAMmC,EAAYnC,CAAM;AAEnC,WAAOA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,qBAAqBE,GAAoC;AACrE,QAAIF,IAASE;AACb,eAAWiC,KAAe,KAAK;AAC7B,MAAAnC,IAAS,MAAMmC,EAAYnC,CAAM;AAEnC,WAAOA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAA4B;AAClC,WAAO,OAAO,KAAK,IAAA,CAAK,IAAI,KAAK,OAAA,EAAS,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA,EAKQ,WAAWE,GAAmC;AACpD,WACEA,MAAU,QACV,OAAOA,KAAU,YACjB,UAAUA,KACTA,EAAmB,SAAS;AAAA,EAEjC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,MAAMsE,GAA2B;AAC7C,WAAO,IAAI,QAAQ,CAAC5B,MAAY,WAAWA,GAAS4B,CAAE,CAAC;AAAA,EACzD;AACF;AA8BO,SAASC,EAAgBlG,GAAoC;AAClE,SAAO,IAAImD,EAAUnD,CAAM;AAC7B;AASO,MAAMmG,KAAYD,EAAgB;AAAA,EACvC,SAASrG,EAAW;AAAA,EACpB,SAASA,EAAW,QAAQ;AAAA,EAC5B,SAASA,EAAW;AAAA,EACpB,OAAO;AAAA,IACL,aAAaA,EAAW,MAAM;AAAA,IAC9B,WAAWA,EAAW,MAAM;AAAA,IAC5B,UAAUA,EAAW,MAAM;AAAA,EAAA;AAE/B,CAAC;"}