@gzl10/ts-helpers 4.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +320 -0
- package/README.md +233 -0
- package/USAGE-GUIDE.md +800 -0
- package/dist/browser/async.js +15 -0
- package/dist/browser/async.js.map +1 -0
- package/dist/browser/chunk-4O7ZPIJN.js +383 -0
- package/dist/browser/chunk-4O7ZPIJN.js.map +1 -0
- package/dist/browser/chunk-75XNTC34.js +60 -0
- package/dist/browser/chunk-75XNTC34.js.map +1 -0
- package/dist/browser/chunk-C3D7YZVE.js +299 -0
- package/dist/browser/chunk-C3D7YZVE.js.map +1 -0
- package/dist/browser/chunk-CZL6C2EI.js +452 -0
- package/dist/browser/chunk-CZL6C2EI.js.map +1 -0
- package/dist/browser/chunk-D4FZFIVA.js +240 -0
- package/dist/browser/chunk-D4FZFIVA.js.map +1 -0
- package/dist/browser/chunk-IL7NG7IC.js +72 -0
- package/dist/browser/chunk-IL7NG7IC.js.map +1 -0
- package/dist/browser/chunk-NSBPE2FW.js +17 -0
- package/dist/browser/chunk-NSBPE2FW.js.map +1 -0
- package/dist/browser/chunk-SLQVNPTH.js +27 -0
- package/dist/browser/chunk-SLQVNPTH.js.map +1 -0
- package/dist/browser/chunk-WG7ILCUB.js +195 -0
- package/dist/browser/chunk-WG7ILCUB.js.map +1 -0
- package/dist/browser/chunk-WJA4JDMZ.js +278 -0
- package/dist/browser/chunk-WJA4JDMZ.js.map +1 -0
- package/dist/browser/chunk-ZFVYLUTT.js +65 -0
- package/dist/browser/chunk-ZFVYLUTT.js.map +1 -0
- package/dist/browser/chunk-ZYTSVMTI.js +263 -0
- package/dist/browser/chunk-ZYTSVMTI.js.map +1 -0
- package/dist/browser/dates.js +78 -0
- package/dist/browser/dates.js.map +1 -0
- package/dist/browser/environment-detection.js +21 -0
- package/dist/browser/environment-detection.js.map +1 -0
- package/dist/browser/environment.js +34 -0
- package/dist/browser/environment.js.map +1 -0
- package/dist/browser/errors.js +18 -0
- package/dist/browser/errors.js.map +1 -0
- package/dist/browser/index.js +412 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/browser/math.js +51 -0
- package/dist/browser/math.js.map +1 -0
- package/dist/browser/number.js +10 -0
- package/dist/browser/number.js.map +1 -0
- package/dist/browser/objects.js +31 -0
- package/dist/browser/objects.js.map +1 -0
- package/dist/browser/strings.js +80 -0
- package/dist/browser/strings.js.map +1 -0
- package/dist/browser/validation-core.js +54 -0
- package/dist/browser/validation-core.js.map +1 -0
- package/dist/browser/validation-crypto.js +28 -0
- package/dist/browser/validation-crypto.js.map +1 -0
- package/dist/browser/validators.js +98 -0
- package/dist/browser/validators.js.map +1 -0
- package/dist/cjs/async.js +86 -0
- package/dist/cjs/async.js.map +1 -0
- package/dist/cjs/dates.js +285 -0
- package/dist/cjs/dates.js.map +1 -0
- package/dist/cjs/environment-detection.js +84 -0
- package/dist/cjs/environment-detection.js.map +1 -0
- package/dist/cjs/environment.js +261 -0
- package/dist/cjs/environment.js.map +1 -0
- package/dist/cjs/errors.js +80 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/index.js +2035 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/math.js +388 -0
- package/dist/cjs/math.js.map +1 -0
- package/dist/cjs/number.js +37 -0
- package/dist/cjs/number.js.map +1 -0
- package/dist/cjs/objects.js +249 -0
- package/dist/cjs/objects.js.map +1 -0
- package/dist/cjs/strings.js +253 -0
- package/dist/cjs/strings.js.map +1 -0
- package/dist/cjs/validation.js +450 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/async.js +15 -0
- package/dist/esm/async.js.map +1 -0
- package/dist/esm/chunk-4O7ZPIJN.js +383 -0
- package/dist/esm/chunk-4O7ZPIJN.js.map +1 -0
- package/dist/esm/chunk-75XNTC34.js +60 -0
- package/dist/esm/chunk-75XNTC34.js.map +1 -0
- package/dist/esm/chunk-BDOBKBKA.js +72 -0
- package/dist/esm/chunk-BDOBKBKA.js.map +1 -0
- package/dist/esm/chunk-C3D7YZVE.js +299 -0
- package/dist/esm/chunk-C3D7YZVE.js.map +1 -0
- package/dist/esm/chunk-CZL6C2EI.js +452 -0
- package/dist/esm/chunk-CZL6C2EI.js.map +1 -0
- package/dist/esm/chunk-EBLSTOEC.js +263 -0
- package/dist/esm/chunk-EBLSTOEC.js.map +1 -0
- package/dist/esm/chunk-NSBPE2FW.js +17 -0
- package/dist/esm/chunk-NSBPE2FW.js.map +1 -0
- package/dist/esm/chunk-SLQVNPTH.js +27 -0
- package/dist/esm/chunk-SLQVNPTH.js.map +1 -0
- package/dist/esm/chunk-WG7ILCUB.js +195 -0
- package/dist/esm/chunk-WG7ILCUB.js.map +1 -0
- package/dist/esm/chunk-WJA4JDMZ.js +278 -0
- package/dist/esm/chunk-WJA4JDMZ.js.map +1 -0
- package/dist/esm/chunk-ZFVYLUTT.js +65 -0
- package/dist/esm/chunk-ZFVYLUTT.js.map +1 -0
- package/dist/esm/dates.js +78 -0
- package/dist/esm/dates.js.map +1 -0
- package/dist/esm/environment-detection.js +21 -0
- package/dist/esm/environment-detection.js.map +1 -0
- package/dist/esm/environment.js +34 -0
- package/dist/esm/environment.js.map +1 -0
- package/dist/esm/errors.js +18 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/index.js +380 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/math.js +51 -0
- package/dist/esm/math.js.map +1 -0
- package/dist/esm/number.js +10 -0
- package/dist/esm/number.js.map +1 -0
- package/dist/esm/objects.js +31 -0
- package/dist/esm/objects.js.map +1 -0
- package/dist/esm/strings.js +80 -0
- package/dist/esm/strings.js.map +1 -0
- package/dist/esm/validation.js +54 -0
- package/dist/esm/validation.js.map +1 -0
- package/dist/node/async.js +93 -0
- package/dist/node/async.js.map +1 -0
- package/dist/node/csv.js +102 -0
- package/dist/node/csv.js.map +1 -0
- package/dist/node/data.js +880 -0
- package/dist/node/data.js.map +1 -0
- package/dist/node/dates.js +324 -0
- package/dist/node/dates.js.map +1 -0
- package/dist/node/environment.js +278 -0
- package/dist/node/environment.js.map +1 -0
- package/dist/node/errors.js +89 -0
- package/dist/node/errors.js.map +1 -0
- package/dist/node/index.js +3151 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/json.js +107 -0
- package/dist/node/json.js.map +1 -0
- package/dist/node/math.js +413 -0
- package/dist/node/math.js.map +1 -0
- package/dist/node/number.js +42 -0
- package/dist/node/number.js.map +1 -0
- package/dist/node/objects.js +264 -0
- package/dist/node/objects.js.map +1 -0
- package/dist/node/strings.js +293 -0
- package/dist/node/strings.js.map +1 -0
- package/dist/node/tree.js +89 -0
- package/dist/node/tree.js.map +1 -0
- package/dist/node/validation-core.js +477 -0
- package/dist/node/validation-core.js.map +1 -0
- package/dist/node/validation-crypto.js +179 -0
- package/dist/node/validation-crypto.js.map +1 -0
- package/dist/node/validation.js +677 -0
- package/dist/node/validation.js.map +1 -0
- package/dist/node/validators.js +123 -0
- package/dist/node/validators.js.map +1 -0
- package/dist/node-esm/async.js +15 -0
- package/dist/node-esm/async.js.map +1 -0
- package/dist/node-esm/chunk-3YOF7NPT.js +299 -0
- package/dist/node-esm/chunk-3YOF7NPT.js.map +1 -0
- package/dist/node-esm/chunk-64TBXJQS.js +263 -0
- package/dist/node-esm/chunk-64TBXJQS.js.map +1 -0
- package/dist/node-esm/chunk-75XNTC34.js +60 -0
- package/dist/node-esm/chunk-75XNTC34.js.map +1 -0
- package/dist/node-esm/chunk-C4PKXIPB.js +278 -0
- package/dist/node-esm/chunk-C4PKXIPB.js.map +1 -0
- package/dist/node-esm/chunk-CMDFZME3.js +452 -0
- package/dist/node-esm/chunk-CMDFZME3.js.map +1 -0
- package/dist/node-esm/chunk-DZZPUYMP.js +74 -0
- package/dist/node-esm/chunk-DZZPUYMP.js.map +1 -0
- package/dist/node-esm/chunk-HTSEHRHI.js +195 -0
- package/dist/node-esm/chunk-HTSEHRHI.js.map +1 -0
- package/dist/node-esm/chunk-JCAUVOPH.js +27 -0
- package/dist/node-esm/chunk-JCAUVOPH.js.map +1 -0
- package/dist/node-esm/chunk-KBHE3K2F.js +505 -0
- package/dist/node-esm/chunk-KBHE3K2F.js.map +1 -0
- package/dist/node-esm/chunk-LYTET5NX.js +65 -0
- package/dist/node-esm/chunk-LYTET5NX.js.map +1 -0
- package/dist/node-esm/chunk-PZ5AY32C.js +10 -0
- package/dist/node-esm/chunk-PZ5AY32C.js.map +1 -0
- package/dist/node-esm/chunk-UKGXL2QO.js +383 -0
- package/dist/node-esm/chunk-UKGXL2QO.js.map +1 -0
- package/dist/node-esm/chunk-XAEYT23H.js +164 -0
- package/dist/node-esm/chunk-XAEYT23H.js.map +1 -0
- package/dist/node-esm/csv.js +63 -0
- package/dist/node-esm/csv.js.map +1 -0
- package/dist/node-esm/data.js +32 -0
- package/dist/node-esm/data.js.map +1 -0
- package/dist/node-esm/dates.js +78 -0
- package/dist/node-esm/dates.js.map +1 -0
- package/dist/node-esm/environment.js +34 -0
- package/dist/node-esm/environment.js.map +1 -0
- package/dist/node-esm/errors.js +18 -0
- package/dist/node-esm/errors.js.map +1 -0
- package/dist/node-esm/index.js +426 -0
- package/dist/node-esm/index.js.map +1 -0
- package/dist/node-esm/json.js +68 -0
- package/dist/node-esm/json.js.map +1 -0
- package/dist/node-esm/math.js +51 -0
- package/dist/node-esm/math.js.map +1 -0
- package/dist/node-esm/number.js +10 -0
- package/dist/node-esm/number.js.map +1 -0
- package/dist/node-esm/objects.js +31 -0
- package/dist/node-esm/objects.js.map +1 -0
- package/dist/node-esm/strings.js +80 -0
- package/dist/node-esm/strings.js.map +1 -0
- package/dist/node-esm/tree.js +8 -0
- package/dist/node-esm/tree.js.map +1 -0
- package/dist/node-esm/validation-core.js +54 -0
- package/dist/node-esm/validation-core.js.map +1 -0
- package/dist/node-esm/validation-crypto.js +26 -0
- package/dist/node-esm/validation-crypto.js.map +1 -0
- package/dist/node-esm/validation.js +606 -0
- package/dist/node-esm/validation.js.map +1 -0
- package/dist/node-esm/validators.js +98 -0
- package/dist/node-esm/validators.js.map +1 -0
- package/dist/types/async-C8gvbSG-.d.ts +453 -0
- package/dist/types/async.d.ts +1 -0
- package/dist/types/csv.d.ts +226 -0
- package/dist/types/data.d.ts +1561 -0
- package/dist/types/dates-hTiE0Z11.d.ts +298 -0
- package/dist/types/dates.d.ts +1 -0
- package/dist/types/environment-B8eLS7KT.d.ts +420 -0
- package/dist/types/environment-detection.d.ts +102 -0
- package/dist/types/environment.d.ts +1 -0
- package/dist/types/errors.d.ts +147 -0
- package/dist/types/index.d.ts +211 -0
- package/dist/types/json.d.ts +284 -0
- package/dist/types/math-BQ9Lwdp7.d.ts +2060 -0
- package/dist/types/math.d.ts +1 -0
- package/dist/types/number-CYnQfLWj.d.ts +44 -0
- package/dist/types/number.d.ts +1 -0
- package/dist/types/objects-BohS8GCS.d.ts +1185 -0
- package/dist/types/objects.d.ts +1 -0
- package/dist/types/strings-CiqRPYLL.d.ts +1349 -0
- package/dist/types/strings.d.ts +1 -0
- package/dist/types/tree.d.ts +284 -0
- package/dist/types/validation-core-DfHF8rCG.d.ts +238 -0
- package/dist/types/validation-crypto-browser.d.ts +56 -0
- package/dist/types/validation-crypto-node.d.ts +31 -0
- package/dist/types/validation.d.ts +1 -0
- package/dist/types/validators.d.ts +216 -0
- package/package.json +253 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/environment.ts","../../src/tree.ts","../../src/validators.ts","../../src/csv.ts","../../src/json.ts","../../src/node/index.ts","../../src/universal/validation-core.ts","../../src/strings.ts","../../src/objects.ts","../../src/dates.ts","../../src/math.ts","../../src/number.ts","../../src/async.ts","../../src/errors.ts","../../src/data.ts","../../src/node/validation-crypto.ts"],"sourcesContent":["/**\n * Environment detection utilities for universal browser/Node.js compatibility\n */\n\n/**\n * Detailed criteria used for environment debugging and analysis\n */\nexport interface EnvironmentCriteria {\n /** True if hostname is localhost, 127.0.0.1, ::1, or .localhost/.local domain */\n isLocalhost: boolean\n /** True if hostname is within private IP ranges (10.x, 192.168.x, 172.16-31.x) */\n isPrivateIP: boolean\n /** True if port is in development range (3000-9999) */\n isDevelopmentPort: boolean\n /** True if development tools are detected (Vue DevTools, __DEV__ global) */\n hasDevtools: boolean\n /** Current NODE_ENV value (Node.js only) */\n nodeEnv?: string\n}\n\n/**\n * Complete environment information with platform detection and debugging criteria\n */\nexport interface EnvironmentInfo {\n /** Runtime platform: 'browser', 'node', or 'unknown' */\n platform: 'browser' | 'node' | 'unknown'\n /** Detected environment: 'development', 'production', or 'test' */\n environment: 'development' | 'production' | 'test'\n /** Protocol used (http/https) - from location or request headers */\n protocol?: string\n /** Hostname - from location or request headers */\n hostname?: string\n /** Browser user agent string (browser only) */\n userAgent?: string\n /** Detailed debugging criteria */\n criteria?: EnvironmentCriteria\n}\n\n/**\n * Detects if the current runtime is Node.js environment\n *\n * Checks for the presence of Node.js-specific globals (process, process.versions.node)\n * and absence of browser globals (window).\n *\n * @returns True if running in Node.js, false otherwise\n *\n * @example\n * ```typescript\n * if (isNodeEnvironment()) {\n * // Node.js specific code\n * const fs = require('fs')\n * }\n * ```\n */\nexport function isNodeEnvironment(): boolean {\n return typeof window === 'undefined' && typeof process !== 'undefined' && !!process.versions?.node\n}\n\n/**\n * Detects if the current runtime is a browser environment\n *\n * Checks for the presence of browser-specific globals (window, document).\n * Also handles testing environments that may mock these globals.\n *\n * @returns True if running in browser, false otherwise\n *\n * @example\n * ```typescript\n * if (isBrowserEnvironment()) {\n * // Browser specific code\n * const url = window.location.href\n * }\n * ```\n */\nexport function isBrowserEnvironment(): boolean {\n // Check both global.window (for tests) and window (for actual browser)\n const win = typeof window !== 'undefined' ? window : (global as any).window\n const doc = typeof document !== 'undefined' ? document : (global as any).document\n return typeof win !== 'undefined' && win !== null && typeof doc !== 'undefined' && doc !== null\n}\n\n/**\n * Detects if the application is running in development mode\n *\n * Uses sophisticated detection logic based on multiple criteria:\n * - Node.js: NODE_ENV variable, request headers (for Express), hostname/protocol analysis\n * - Browser: __DEV__ global, development ports (3000-9999), localhost/private IPs, dev tools\n *\n * Handles reverse proxies correctly by checking forwarded headers.\n *\n * @param req - Optional Express request object for server-side detection\n * @returns True if in development mode, false if production\n *\n * @example\n * ```typescript\n * // Node.js - simple check\n * if (isDevelopment()) {\n * console.log('Development mode')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Express - with request context\n * app.get('/api/status', (req, res) => {\n * const isDev = isDevelopment(req)\n * res.json({ environment: isDev ? 'dev' : 'prod' })\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Browser - automatic detection\n * if (isDevelopment()) {\n * // Enable debug logging, dev tools, etc.\n * enableDebugMode()\n * }\n * ```\n */\nexport function isDevelopment(req?: any): boolean {\n if (isNodeEnvironment()) {\n // En Node.js, verificar NODE_ENV primero\n if (process.env.NODE_ENV === 'production') {\n return false\n }\n if (process.env.NODE_ENV === 'development') {\n return true\n }\n\n // Si hay request object (Express), usar lógica de servidor\n if (req) {\n const protocol = detectProtocol(req)\n const hostname = detectHostname(req)\n\n return protocol === 'http' || isLocalhost(hostname) || isPrivateIP(hostname)\n }\n\n // Fallback para Node.js sin request\n // NODE_ENV undefined se asume como development\n return !process.env.NODE_ENV || process.env.NODE_ENV === 'development'\n }\n\n if (isBrowserEnvironment()) {\n // Verificar variable global de desarrollo (webpack/vite)\n if (\n typeof (globalThis as any).__DEV__ !== 'undefined' &&\n (globalThis as any).__DEV__ === true\n ) {\n return true\n }\n\n // Verificar si hay herramientas de desarrollo activas\n if (\n typeof window !== 'undefined' &&\n (window as any).__VUE_DEVTOOLS_GLOBAL_HOOK__ &&\n typeof location !== 'undefined' &&\n isLocalhost(location.hostname)\n ) {\n return true\n }\n\n // Si location no está disponible, considerar como producción\n if (typeof location === 'undefined') {\n return false\n }\n\n const hostname = location.hostname || ''\n const port = parseInt(location.port || '80')\n\n // Criterios basados en hostname y puerto\n const isDevelopmentPort = port >= 3000 && port <= 9999\n\n // Solo considerar HTTP como desarrollo si el hostname también lo indica\n const isHttpDevelopment =\n location.protocol === 'http:' && (isLocalhost(hostname) || isPrivateIP(hostname))\n\n return isLocalhost(hostname) || isPrivateIP(hostname) || isDevelopmentPort || isHttpDevelopment\n }\n\n return false\n}\n\n/**\n * Detects if the application is running in production mode\n *\n * Simple inverse of isDevelopment() with additional NODE_ENV validation for Node.js.\n *\n * @returns True if in production mode, false if development\n *\n * @example\n * ```typescript\n * if (isProduction()) {\n * // Enable performance optimizations\n * enableProductionMode()\n * }\n * ```\n */\nexport function isProduction(): boolean {\n if (isNodeEnvironment()) {\n return process.env.NODE_ENV === 'production'\n }\n\n // Browser: inverso de isDevelopment (que ya excluye test)\n return !isDevelopment()\n}\n\n/**\n * Detects if the application is running in test mode\n *\n * Checks explicitly for NODE_ENV === 'test' in Node.js environments.\n * Vitest and Jest automatically set this value when running tests.\n *\n * @returns True if NODE_ENV is 'test', false otherwise\n *\n * @example\n * ```typescript\n * if (isTest()) {\n * // Test-specific behavior (mocks, fixtures, etc.)\n * enableTestMode()\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Conditional imports for testing\n * if (isTest()) {\n * const { mockAPI } = await import('./test/mocks')\n * mockAPI.setup()\n * }\n * ```\n */\nexport function isTest(): boolean {\n if (isNodeEnvironment()) {\n return process.env.NODE_ENV === 'test'\n }\n\n return false\n}\n\n/**\n * Detects if the application is NOT running in production mode\n *\n * Returns true for development, test, undefined, or any non-production environment.\n * Useful for enabling debugging, logging, or development-only features\n * across all non-production environments.\n *\n * @returns True if not in production (development, test, or undefined)\n *\n * @example\n * ```typescript\n * if (isNonProduction()) {\n * // Enable debug logging for dev and test\n * console.log('Debug mode enabled')\n * enableVerboseLogging()\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Security: Disable strict checks in non-production\n * if (isNonProduction()) {\n * allowSelfSignedCertificates()\n * disableCSRFProtection()\n * }\n * ```\n */\nexport function isNonProduction(): boolean {\n if (isNodeEnvironment()) {\n return process.env.NODE_ENV !== 'production'\n }\n\n return !isProduction()\n}\n\n/**\n * Detects the protocol (HTTP/HTTPS) from browser location or request headers\n *\n * Handles reverse proxies correctly by checking forwarded headers in priority order:\n * 1. X-Forwarded-Proto (most common)\n * 2. X-Forwarded-Protocol\n * 3. X-Url-Scheme\n * 4. Front-End-Https\n * 5. CF-Visitor (Cloudflare specific)\n *\n * @param req - Optional Express request object with headers\n * @returns Protocol as 'http' or 'https'\n *\n * @example\n * ```typescript\n * // Browser usage\n * const protocol = detectProtocol() // 'https' from window.location\n * ```\n *\n * @example\n * ```typescript\n * // Express server with proxy\n * app.get('/api', (req, res) => {\n * const protocol = detectProtocol(req) // Detects from X-Forwarded-Proto\n * const fullUrl = `${protocol}://${req.get('host')}${req.path}`\n * })\n * ```\n */\nexport function detectProtocol(req?: any): 'http' | 'https' {\n if (isBrowserEnvironment()) {\n if (typeof location !== 'undefined') {\n return location.protocol === 'https:' ? 'https' : 'http'\n }\n return 'https' // Default seguro para browser\n }\n\n if (req) {\n // Headers comunes de proxies reversos en orden de prioridad\n const forwardedProto = req.get?.('X-Forwarded-Proto') || req.headers?.['x-forwarded-proto']\n const forwardedProtocol =\n req.get?.('X-Forwarded-Protocol') || req.headers?.['x-forwarded-protocol']\n const urlScheme = req.get?.('X-Url-Scheme') || req.headers?.['x-url-scheme']\n const frontEndHttps = req.get?.('Front-End-Https') || req.headers?.['front-end-https']\n const cloudflareVisitor = req.get?.('CF-Visitor') || req.headers?.['cf-visitor']\n\n // Verificar headers de proxy\n if (forwardedProto) {\n return forwardedProto.split(',')[0].trim().toLowerCase() as 'http' | 'https'\n }\n if (forwardedProtocol) {\n return forwardedProtocol.toLowerCase() as 'http' | 'https'\n }\n if (urlScheme) {\n return urlScheme.toLowerCase() as 'http' | 'https'\n }\n if (frontEndHttps === 'on') {\n return 'https'\n }\n if (cloudflareVisitor) {\n try {\n const visitor = JSON.parse(cloudflareVisitor)\n if (visitor.scheme) {\n return visitor.scheme.toLowerCase() as 'http' | 'https'\n }\n } catch (_e) {\n // Ignorar errores de parsing JSON\n }\n }\n\n // Fallback al protocolo directo\n if (req.protocol) return req.protocol\n if (req.secure) return 'https'\n }\n\n // Default para Node.js sin request context\n return 'http'\n}\n\n/**\n * Extracts hostname from browser location or request headers\n *\n * Handles reverse proxies by checking forwarded headers in priority order:\n * 1. X-Forwarded-Host (most common, supports multiple hosts)\n * 2. X-Original-Host\n * 3. Host header\n *\n * Automatically strips port numbers and handles multiple comma-separated hosts.\n *\n * @param req - Optional Express request object with headers\n * @returns Hostname without port number\n *\n * @example\n * ```typescript\n * // Browser usage\n * const hostname = detectHostname() // 'example.com' from window.location\n * ```\n *\n * @example\n * ```typescript\n * // Express server behind proxy\n * app.get('/api', (req, res) => {\n * const hostname = detectHostname(req) // 'api.example.com' from X-Forwarded-Host\n * const isLocal = isLocalhost(hostname)\n * })\n * ```\n */\nexport function detectHostname(req?: any): string {\n if (isBrowserEnvironment()) {\n if (typeof location !== 'undefined') {\n return location.hostname\n }\n return 'localhost'\n }\n\n if (req) {\n // Headers comunes de proxies reversos en orden de prioridad\n const forwardedHost = req.get?.('X-Forwarded-Host') || req.headers?.['x-forwarded-host']\n const originalHost = req.get?.('X-Original-Host') || req.headers?.['x-original-host']\n const host = req.get?.('Host') || req.headers?.['host']\n\n // Verificar headers de proxy\n if (forwardedHost) {\n return forwardedHost.split(',')[0].trim().split(':')[0]\n }\n if (originalHost) {\n return originalHost.split(':')[0]\n }\n if (host) {\n return host.split(':')[0]\n }\n\n // Fallback al hostname directo\n if (req.hostname) return req.hostname\n }\n\n // Default para Node.js sin request context\n return 'localhost'\n}\n\n/**\n * Checks if a hostname represents localhost or local development\n *\n * Recognizes various localhost representations:\n * - 'localhost' (standard)\n * - '127.0.0.1' (IPv4 loopback)\n * - '::1' (IPv6 loopback)\n * - '*.localhost' (local development domains)\n * - '*.local' (mDNS local domains)\n *\n * @param hostname - Hostname to check\n * @returns True if hostname represents localhost\n *\n * @example\n * ```typescript\n * isLocalhost('localhost') // true\n * isLocalhost('127.0.0.1') // true\n * isLocalhost('app.localhost') // true\n * isLocalhost('macbook.local') // true\n * isLocalhost('example.com') // false\n * ```\n */\nexport function isLocalhost(hostname: string): boolean {\n return (\n hostname === 'localhost' ||\n hostname === '127.0.0.1' ||\n hostname === '::1' ||\n hostname.endsWith('.localhost') ||\n hostname.endsWith('.local')\n )\n}\n\n/**\n * Checks if a hostname is within private IP address ranges\n *\n * Recognizes private/internal IP ranges according to RFC 1918:\n * - IPv4: 10.x.x.x, 192.168.x.x, 172.16-31.x.x, 127.x.x.x (loopback)\n * - IPv6: ::1 (loopback), fc00::/7 (unique local), fe80::/10 (link-local)\n * - Also includes localhost detection\n *\n * @param hostname - Hostname or IP address to check\n * @returns True if hostname is private/local, false if public\n *\n * @example\n * ```typescript\n * isPrivateIP('192.168.1.1') // true\n * isPrivateIP('10.0.0.1') // true\n * isPrivateIP('172.16.0.1') // true\n * isPrivateIP('localhost') // true\n * isPrivateIP('8.8.8.8') // false\n * isPrivateIP('example.com') // false\n * ```\n */\nexport function isPrivateIP(hostname: string): boolean {\n // IPv4 private ranges\n const ipv4Patterns = [\n /^10\\./, // 10.0.0.0/8\n /^172\\.(1[6-9]|2[0-9]|3[0-1])\\./, // 172.16.0.0/12\n /^192\\.168\\./, // 192.168.0.0/16\n /^127\\./, // 127.0.0.0/8 (loopback)\n ]\n\n // IPv6 private/local ranges\n const ipv6Patterns = [\n /^::1$/, // IPv6 loopback\n /^fc[0-9a-f]{2}:/i, // Unique local addresses\n /^fd[0-9a-f]{2}:/i, // Unique local addresses\n /^fe80:/i, // Link-local addresses\n ]\n\n return (\n ipv4Patterns.some(pattern => pattern.test(hostname)) ||\n ipv6Patterns.some(pattern => pattern.test(hostname)) ||\n isLocalhost(hostname)\n )\n}\n\n/**\n * Gathers complete environment information for debugging and analysis\n *\n * Returns comprehensive environment data including platform detection,\n * development/production status, protocol/hostname information, and\n * detailed debugging criteria.\n *\n * @param req - Optional Express request object for server-side context\n * @returns Complete environment information object\n *\n * @example\n * ```typescript\n * // Basic usage\n * const env = getEnvironmentInfo()\n * console.log(env.platform) // 'node' | 'browser' | 'unknown'\n * console.log(env.environment) // 'development' | 'production' | 'test'\n * ```\n *\n * @example\n * ```typescript\n * // Express server usage\n * app.get('/api/debug', (req, res) => {\n * const envInfo = getEnvironmentInfo(req)\n * res.json({\n * platform: envInfo.platform,\n * isDev: envInfo.environment === 'development',\n * protocol: envInfo.protocol,\n * host: envInfo.hostname,\n * criteria: envInfo.criteria\n * })\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Conditional features based on environment\n * const env = getEnvironmentInfo()\n * if (env.criteria?.hasDevtools) {\n * enableVueDevtools()\n * }\n * if (env.criteria?.isDevelopmentPort) {\n * enableHotReload()\n * }\n * ```\n */\nexport function getEnvironmentInfo(req?: any): EnvironmentInfo {\n const platform = isNodeEnvironment() ? 'node' : isBrowserEnvironment() ? 'browser' : 'unknown'\n\n let environment: EnvironmentInfo['environment'] = 'production'\n if (isNodeEnvironment()) {\n const nodeEnv = process.env.NODE_ENV\n if (nodeEnv === 'development' || nodeEnv === 'test') {\n environment = nodeEnv\n }\n } else if (isDevelopment()) {\n environment = 'development'\n }\n\n const protocol = detectProtocol(req)\n const hostname = detectHostname(req)\n\n const info: EnvironmentInfo = {\n platform,\n environment,\n protocol,\n hostname,\n }\n\n if (isBrowserEnvironment() && typeof navigator !== 'undefined') {\n info.userAgent = navigator.userAgent\n }\n\n // Criterios detallados para debugging\n const criteria: EnvironmentCriteria = {\n isLocalhost: isLocalhost(hostname),\n isPrivateIP: isPrivateIP(hostname),\n isDevelopmentPort: false,\n hasDevtools: false,\n }\n\n if (isBrowserEnvironment() && typeof location !== 'undefined') {\n const port = parseInt(location.port || '80')\n criteria.isDevelopmentPort = port >= 3000 && port <= 9999\n criteria.hasDevtools = !!(\n typeof window !== 'undefined' && (window as any).__VUE_DEVTOOLS_GLOBAL_HOOK__\n )\n }\n\n if (isNodeEnvironment()) {\n criteria.nodeEnv = process.env.NODE_ENV || 'undefined'\n }\n\n info.criteria = criteria\n\n return info\n}\n\n/**\n * Alias for isNodeEnvironment() - detects Node.js runtime\n * @see {@link isNodeEnvironment}\n */\nexport const isNode = isNodeEnvironment\n\n/**\n * Alias for isBrowserEnvironment() - detects browser runtime\n * @see {@link isBrowserEnvironment}\n */\nexport const isBrowser = isBrowserEnvironment\n\n/**\n * Parses environment variable string values to their native JavaScript types\n *\n * Automatically detects and converts:\n * - Booleans: 'true', 'false', 'yes', 'no', '1', '0'\n * - Numbers: '42', '3.14', '-100'\n * - JSON arrays: '[1,2,3]', '[\"a\",\"b\"]'\n * - JSON objects: '{\"key\":\"value\"}'\n * - Comma-separated arrays: 'item1,item2,item3' (when not valid JSON)\n * - null/undefined: 'null', 'undefined', empty string\n *\n * Falls back to original string if no conversion applies.\n *\n * @param value - Environment variable string value to parse\n * @returns Parsed value with appropriate native type\n *\n * @example\n * ```typescript\n * // Boolean conversion\n * parseEnvValue('true') // true\n * parseEnvValue('false') // false\n * parseEnvValue('yes') // true\n * parseEnvValue('1') // true (as boolean)\n *\n * // Number conversion\n * parseEnvValue('42') // 42\n * parseEnvValue('3.14') // 3.14\n * parseEnvValue('-100') // -100\n *\n * // JSON arrays\n * parseEnvValue('[1,2,3]') // [1, 2, 3]\n * parseEnvValue('[\"a\",\"b\"]') // ['a', 'b']\n *\n * // JSON objects\n * parseEnvValue('{\"port\":3000,\"host\":\"localhost\"}')\n * // { port: 3000, host: 'localhost' }\n *\n * // Comma-separated arrays (fallback when not JSON)\n * parseEnvValue('red,green,blue') // ['red', 'green', 'blue']\n *\n * // Null/undefined\n * parseEnvValue('null') // null\n * parseEnvValue('undefined') // undefined\n * parseEnvValue('') // undefined\n *\n * // Strings (no conversion)\n * parseEnvValue('hello') // 'hello'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world usage with process.env\n * const config = {\n * debug: parseEnvValue(process.env.DEBUG), // 'true' → true\n * port: parseEnvValue(process.env.PORT), // '3000' → 3000\n * features: parseEnvValue(process.env.FEATURES), // 'auth,api' → ['auth', 'api']\n * database: parseEnvValue(process.env.DB_CONFIG), // '{\"host\":\"localhost\"}' → object\n * }\n * ```\n */\nexport function parseEnvValue(value: string | undefined): any {\n // Handle null/undefined/empty\n if (value === undefined || value === null || value === '') {\n return undefined\n }\n\n const trimmed = value.trim()\n\n // Handle explicit null/undefined strings\n if (trimmed === 'null') return null\n if (trimmed === 'undefined') return undefined\n\n // Handle booleans\n const lowerValue = trimmed.toLowerCase()\n if (lowerValue === 'true' || lowerValue === 'yes') return true\n if (lowerValue === 'false' || lowerValue === 'no') return false\n\n // Handle boolean-like numbers\n if (trimmed === '1') return true\n if (trimmed === '0') return false\n\n // Try parsing as number (but not if it starts with 0 and has more digits - could be octal/string)\n if (/^-?\\d+\\.?\\d*$/.test(trimmed)) {\n // Avoid treating leading-zero strings as numbers (e.g., postal codes '01234')\n if (trimmed.length > 1 && trimmed[0] === '0' && trimmed[1] !== '.') {\n return trimmed // Keep as string (e.g., '01234')\n }\n const num = Number(trimmed)\n if (!isNaN(num)) return num\n }\n\n // Try parsing as JSON (arrays, objects)\n if (\n (trimmed.startsWith('[') && trimmed.endsWith(']')) ||\n (trimmed.startsWith('{') && trimmed.endsWith('}'))\n ) {\n try {\n return JSON.parse(trimmed)\n } catch {\n // Not valid JSON, continue to next check\n }\n }\n\n // Try parsing comma-separated values as array\n if (trimmed.includes(',')) {\n const parts = trimmed.split(',').map(s => s.trim())\n // Only convert to array if all parts are non-empty\n if (parts.every(p => p.length > 0)) {\n return parts\n }\n }\n\n // Return as-is string\n return trimmed\n}\n","/**\n * Tree Structure Rendering Utilities\n *\n * Provides ASCII/Unicode tree visualization for hierarchical data structures.\n * Features:\n * - Customizable box-drawing characters (Unicode or ASCII)\n * - Flexible label extraction (field name or custom function)\n * - Recursive rendering with proper indentation\n * - Multiple root support\n * - Zero dependencies\n *\n * @module tree\n */\n\n/**\n * Configuration options for tree rendering\n *\n * Controls the visual appearance and label extraction strategy for ASCII/Unicode tree output.\n * All options have sensible defaults for immediate use with Unicode box-drawing characters.\n *\n * @property labelField - Object property name to use as node label (default: 'name')\n * @property verticalLine - Character sequence for vertical continuation (default: '│ ')\n * @property middleBranch - Character sequence for non-last child branch (default: '├── ')\n * @property lastBranch - Character sequence for last child branch (default: '└── ')\n * @property emptySpace - Character sequence for empty space after last branch (default: ' ')\n * @property labelFunction - Custom function to extract/format node labels (overrides labelField)\n *\n * @example\n * ```typescript\n * // Unicode box-drawing (default)\n * const unicodeOptions: TreeExportOptions = {\n * labelField: 'name',\n * verticalLine: '│ ',\n * middleBranch: '├── ',\n * lastBranch: '└── ',\n * emptySpace: ' '\n * }\n *\n * // ASCII alternative (better compatibility)\n * const asciiOptions: TreeExportOptions = {\n * verticalLine: '| ',\n * middleBranch: '+-- ',\n * lastBranch: '`-- ',\n * emptySpace: ' '\n * }\n *\n * // Custom label function\n * const customOptions: TreeExportOptions = {\n * labelFunction: (node) => `${node.type}: ${node.name} (${node.size})`\n * }\n * ```\n */\nexport interface TreeExportOptions {\n labelField?: string\n verticalLine?: string\n middleBranch?: string\n lastBranch?: string\n emptySpace?: string\n labelFunction?: (node: any) => string\n}\n\n/**\n * Renders hierarchical data as ASCII/Unicode tree visualization\n *\n * Converts nested object structures (with `children` arrays) into human-readable tree diagrams.\n * Supports multiple root nodes and customizable rendering styles.\n *\n * Features:\n * - **Recursive rendering**: Handles arbitrary depth\n * - **Unicode box-drawing**: Beautiful output by default (│ ├ └)\n * - **ASCII fallback**: Use simpler characters for compatibility\n * - **Flexible labels**: Extract from field name or custom function\n * - **Multiple roots**: Render forests (arrays of trees)\n *\n * Node Structure Requirements:\n * - Each node must have a label (via `labelField` property or `labelFunction`)\n * - Child nodes stored in `children` array property\n * - No `children` property = leaf node\n *\n * @param data - Array of root nodes (each with optional `children` property)\n * @param options - Rendering options (characters, label extraction)\n * @returns String containing the complete tree visualization with newlines\n *\n * @example\n * ```typescript\n * // Basic usage - Simple file tree\n * const fileTree = [\n * {\n * name: 'src',\n * children: [\n * { name: 'index.ts' },\n * { name: 'utils.ts' },\n * {\n * name: 'components',\n * children: [\n * { name: 'Button.tsx' },\n * { name: 'Input.tsx' }\n * ]\n * }\n * ]\n * }\n * ]\n *\n * console.log(renderTreeAsText(fileTree))\n * // Output:\n * // └── src\n * // ├── index.ts\n * // ├── utils.ts\n * // └── components\n * // ├── Button.tsx\n * // └── Input.tsx\n * ```\n *\n * @example\n * ```typescript\n * // Multiple roots - Project structure\n * const projectTree = [\n * {\n * name: 'packages',\n * children: [\n * { name: 'core' },\n * { name: 'ui' }\n * ]\n * },\n * {\n * name: 'apps',\n * children: [\n * { name: 'web' },\n * { name: 'mobile' }\n * ]\n * }\n * ]\n *\n * console.log(renderTreeAsText(projectTree))\n * // Output:\n * // ├── packages\n * // │ ├── core\n * // │ └── ui\n * // └── apps\n * // ├── web\n * // └── mobile\n * ```\n *\n * @example\n * ```typescript\n * // Custom label field - Organization chart\n * const orgChart = [\n * {\n * title: 'CEO',\n * children: [\n * {\n * title: 'CTO',\n * children: [\n * { title: 'Dev Lead' },\n * { title: 'QA Lead' }\n * ]\n * },\n * { title: 'CFO' }\n * ]\n * }\n * ]\n *\n * console.log(renderTreeAsText(orgChart, { labelField: 'title' }))\n * // Output:\n * // └── CEO\n * // ├── CTO\n * // │ ├── Dev Lead\n * // │ └── QA Lead\n * // └── CFO\n * ```\n *\n * @example\n * ```typescript\n * // Custom label function - Rich formatting\n * const tasks = [\n * {\n * name: 'Backend',\n * status: 'in-progress',\n * assignee: 'Alice',\n * children: [\n * { name: 'API', status: 'done', assignee: 'Bob' },\n * { name: 'Database', status: 'pending', assignee: 'Charlie' }\n * ]\n * }\n * ]\n *\n * const rendered = renderTreeAsText(tasks, {\n * labelFunction: (node) => `[${node.status}] ${node.name} (@${node.assignee})`\n * })\n *\n * console.log(rendered)\n * // Output:\n * // └── [in-progress] Backend (@Alice)\n * // ├── [done] API (@Bob)\n * // └── [pending] Database (@Charlie)\n * ```\n *\n * @example\n * ```typescript\n * // ASCII characters - Better terminal compatibility\n * const tree = [\n * {\n * name: 'root',\n * children: [\n * { name: 'child1' },\n * { name: 'child2' }\n * ]\n * }\n * ]\n *\n * console.log(renderTreeAsText(tree, {\n * verticalLine: '| ',\n * middleBranch: '+-- ',\n * lastBranch: '`-- ',\n * emptySpace: ' '\n * }))\n * // Output:\n * // `-- root\n * // +-- child1\n * // `-- child2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: File system visualization\n * async function visualizeDirectory(dirPath: string) {\n * const tree = await buildDirectoryTree(dirPath)\n *\n * console.log(`Directory structure of ${dirPath}:`)\n * console.log(renderTreeAsText(tree, {\n * labelFunction: (node) => {\n * const icon = node.type === 'dir' ? '📁' : '📄'\n * return `${icon} ${node.name}`\n * }\n * }))\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dependency tree analysis\n * function visualizeDependencies(packageName: string) {\n * const deps = analyzeDependencies(packageName)\n *\n * console.log(`Dependencies of ${packageName}:`)\n * console.log(renderTreeAsText(deps, {\n * labelFunction: (node) => `${node.name}@${node.version} (${node.size})`\n * }))\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Edge case: Empty tree\n * console.log(renderTreeAsText([])) // Returns empty string\n *\n * // Edge case: Leaf nodes only\n * const leaves = [{ name: 'item1' }, { name: 'item2' }]\n * console.log(renderTreeAsText(leaves))\n * // Output:\n * // ├── item1\n * // └── item2\n *\n * // Edge case: Deep nesting\n * const deep = [\n * {\n * name: 'level1',\n * children: [\n * {\n * name: 'level2',\n * children: [\n * { name: 'level3' }\n * ]\n * }\n * ]\n * }\n * ]\n * console.log(renderTreeAsText(deep))\n * // Handles arbitrary depth correctly\n * ```\n *\n * @see {@link TreeExportOptions} for configuration details\n */\nexport function renderTreeAsText(data: any[], options?: TreeExportOptions): string {\n // ✅ Input validation\n if (!data || !Array.isArray(data)) {\n return ''\n }\n\n if (data.length === 0) {\n return ''\n }\n\n const {\n labelField = 'name',\n verticalLine = '│ ',\n middleBranch = '├── ',\n lastBranch = '└── ',\n emptySpace = ' ',\n labelFunction,\n } = options || {}\n\n // ✅ Circular reference detection\n const visited = new WeakSet<any>()\n\n const getLabel = (node: any): string => {\n try {\n if (labelFunction) return String(labelFunction(node))\n if (node == null) return '[null]'\n if (typeof node !== 'object') return String(node)\n return node[labelField] != null ? String(node[labelField]) : String(node)\n } catch (_error) {\n // ✅ Error handling for labelFunction\n return '[error]'\n }\n }\n\n const renderNode = (\n node: any,\n prefix: string = '',\n isLast: boolean = true,\n depth: number = 0\n ): string => {\n // ✅ Null/undefined node handling\n if (node == null) {\n return ''\n }\n\n // ✅ Circular reference detection\n if (typeof node === 'object' && visited.has(node)) {\n return `${prefix + (isLast ? lastBranch : middleBranch)}[circular reference]`\n }\n\n // ✅ Max depth protection (prevent stack overflow)\n if (depth > 100) {\n return `${prefix + (isLast ? lastBranch : middleBranch)}[max depth exceeded]`\n }\n\n if (typeof node === 'object') {\n visited.add(node)\n }\n\n const lines: string[] = []\n const currentPrefix = isLast ? lastBranch : middleBranch\n lines.push(prefix + currentPrefix + getLabel(node))\n\n // ✅ Children validation\n const children = Array.isArray(node.children)\n ? node.children.filter((child: any) => child != null) // Filter null/undefined\n : []\n\n const nextPrefix = prefix + (isLast ? emptySpace : verticalLine)\n\n children.forEach((child: any, index: number) => {\n const isLastChild = index === children.length - 1\n const childOutput = renderNode(child, nextPrefix, isLastChild, depth + 1)\n if (childOutput) {\n lines.push(childOutput)\n }\n })\n\n return lines.join('\\n')\n }\n\n // ✅ Filter null/undefined roots\n const validRoots = data.filter(root => root != null)\n\n if (validRoots.length === 0) {\n return ''\n }\n\n return validRoots\n .map((root, index) => renderNode(root, '', index === validRoots.length - 1))\n .join('\\n')\n}\n","/**\n * File and security validators\n *\n * This module provides validation functions for file operations and content security.\n * Functions implement basic security checks to prevent common attack vectors:\n * - Path traversal attacks (../, ..\\)\n * - XSS injection (script tags, javascript: URLs)\n * - File size limits\n *\n * ⚠️ WARNING: These are basic validations. For production systems, consider:\n * - Additional OS-specific path validation\n * - Symbolic link resolution checking\n * - Comprehensive XSS prevention libraries (e.g., DOMPurify)\n * - Content-Type validation\n * - Virus scanning for uploaded files\n */\n\n/**\n * Validates file path for security vulnerabilities\n *\n * Protects against common path traversal attacks by checking for:\n * - Parent directory references (../, ..\\)\n * - Mixed path separators (//\\, \\\\)\n * - Excessive path length (>1000 chars)\n * - Empty or null paths\n *\n * ⚠️ SECURITY NOTE: This is basic validation. For production use, consider:\n * - Validating against an allowed directory whitelist\n * - Resolving symbolic links\n * - OS-specific path rules (Windows vs Unix)\n * - Canonicalization before validation\n *\n * @param filePath - File path string to validate\n * @returns True if path appears safe, false if potentially dangerous\n *\n * @example\n * ```typescript\n * // Safe paths - Allowed\n * isValidFilePath('./data/users.json') // true\n * isValidFilePath('data/users.json') // true\n * isValidFilePath('/absolute/path/file.txt') // true\n * isValidFilePath('C:\\\\Users\\\\data\\\\file.txt') // true\n *\n * // Dangerous paths - Path traversal attacks\n * isValidFilePath('../../../etc/passwd') // false\n * isValidFilePath('data/../../../etc/passwd') // false\n * isValidFilePath('..\\\\..\\\\..\\\\windows\\\\system32\\\\config') // false\n * isValidFilePath('data//\\\\..//config') // false\n *\n * // Invalid paths - Malformed\n * isValidFilePath('') // false\n * isValidFilePath(null as any) // false\n * isValidFilePath(undefined as any) // false\n * isValidFilePath('x'.repeat(1001)) // false (too long)\n *\n * // Real-world usage in file operations\n * async function readUserFile(userPath: string) {\n * if (!isValidFilePath(userPath)) {\n * throw new Error('Invalid or unsafe file path detected')\n * }\n *\n * // Additional check: ensure path is within allowed directory\n * const allowedDir = '/var/app/uploads'\n * const fullPath = path.join(allowedDir, userPath)\n *\n * return fs.readFile(fullPath, 'utf-8')\n * }\n * ```\n *\n * @see {@link isValidTextContent} for content security validation\n * @see {@link isValidFileSize} for file size validation\n */\nexport function isValidFilePath(filePath: string): boolean {\n // ✅ Type and null checks\n if (!filePath || typeof filePath !== 'string') return false\n\n // ✅ Handle type coercion attempts\n if (typeof filePath === 'object') return false\n\n // ✅ Length limits (DoS prevention)\n if (filePath.length === 0 || filePath.length > 1000) return false\n\n // ✅ Path traversal patterns (Unix and Windows)\n // Reject parent directory traversal (..)\n if (filePath.includes('../') || filePath.includes('..\\\\')) return false\n\n // Reject mixed/double slashes (but allow ./ and .\\ at start for relative paths)\n const suspiciousPatterns = ['//', '\\\\\\\\', '//\\\\', '\\\\//', '/./', '\\\\.\\\\']\n if (suspiciousPatterns.some(pattern => filePath.includes(pattern))) return false\n\n // ✅ URL-encoded path traversal\n const encodedPatterns = [\n '%2e%2e%2f', // ../\n '%2e%2e/', // ../\n '%2e%2e%5c', // ..\\\n '%252e', // double-encoded\n ]\n if (encodedPatterns.some(pattern => filePath.toLowerCase().includes(pattern))) return false\n\n // ✅ Null byte injection\n if (filePath.includes('\\x00')) return false\n\n // ✅ Command injection characters\n const commandChars = [';', '&', '|', '`', '$', '(', ')', '{', '}']\n if (commandChars.some(char => filePath.includes(char))) return false\n\n // ✅ SQL injection attempts\n const sqlPatterns = [\"'\", '\"', '--', '/*', '*/', 'DROP', 'DELETE', 'UNION', 'SELECT']\n const lowerPath = filePath.toLowerCase()\n if (\n sqlPatterns.some(\n pattern =>\n lowerPath.includes(pattern.toLowerCase()) &&\n (pattern === \"'\" || pattern === '\"' || lowerPath.includes(` ${pattern.toLowerCase()}`))\n )\n )\n return false\n\n // ✅ Unicode attacks (RTL override, zero-width)\n const dangerousUnicode = [\n '\\u202E', // Right-to-left override\n '\\u200B', // Zero-width space\n '\\u200C', // Zero-width non-joiner\n '\\u200D', // Zero-width joiner\n '\\uFEFF', // Zero-width no-break space\n ]\n if (dangerousUnicode.some(char => filePath.includes(char))) return false\n\n // ✅ Absolute Windows paths trying to escape\n if (/^[A-Za-z]:\\\\.*\\\\\\.\\./.test(filePath)) return false\n\n return true\n}\n\n/**\n * Validates file size against a maximum limit\n *\n * Checks if a file size is valid (non-negative) and within acceptable limits.\n * Used to prevent:\n * - Denial of Service (DoS) attacks via large file uploads\n * - Disk space exhaustion\n * - Memory overflow during file processing\n *\n * @param size - File size in bytes to validate\n * @param maxSize - Maximum allowed size in bytes\n * @returns True if size is valid and within limit, false otherwise\n *\n * @example\n * ```typescript\n * // Common size limits\n * const KB = 1024\n * const MB = 1024 * KB\n * const GB = 1024 * MB\n *\n * // Image upload validation (5 MB limit)\n * const imageSize = 4 * MB\n * isValidFileSize(imageSize, 5 * MB) // true\n *\n * // Document upload validation (10 MB limit)\n * const docSize = 12 * MB\n * isValidFileSize(docSize, 10 * MB) // false (exceeds limit)\n *\n * // Video upload validation (1 GB limit)\n * const videoSize = 500 * MB\n * isValidFileSize(videoSize, 1 * GB) // true\n *\n * // Invalid sizes\n * isValidFileSize(-100, 1 * MB) // false (negative size)\n * isValidFileSize(NaN, 1 * MB) // false (invalid number)\n * isValidFileSize('1000' as any, 1 * MB) // false (not a number)\n *\n * // Real-world usage in file upload handler\n * app.post('/upload', (req, res) => {\n * const file = req.files.document\n * const maxSize = 10 * 1024 * 1024 // 10 MB\n *\n * if (!isValidFileSize(file.size, maxSize)) {\n * return res.status(413).json({\n * error: 'File too large',\n * maxSize: '10 MB',\n * received: `${(file.size / (1024 * 1024)).toFixed(2)} MB`\n * })\n * }\n *\n * // Process file...\n * })\n * ```\n *\n * @see {@link isValidFilePath} for path security validation\n */\nexport function isValidFileSize(size: number, maxSize: number): boolean {\n return typeof size === 'number' && size >= 0 && size <= maxSize\n}\n\n/**\n * Validates text content for security vulnerabilities and size limits\n *\n * Performs basic security checks on text content to detect common XSS attack vectors:\n * - Script tags (<script>)\n * - JavaScript URLs (javascript:)\n * - Data URLs with HTML (data:text/html)\n * - VBScript URLs (vbscript:)\n *\n * Also enforces maximum content length to prevent DoS attacks.\n *\n * ⚠️ WARNING: This is basic XSS detection. For production systems:\n * - Use dedicated sanitization libraries (DOMPurify, sanitize-html)\n * - Implement Content Security Policy (CSP)\n * - Apply output encoding based on context (HTML, JS, URL)\n * - Validate against allowlists, not just blocklists\n *\n * @param content - Text content to validate\n * @param options - Validation options\n * @param options.maxLength - Maximum content length in characters (default: 1,000,000)\n * @returns True if content appears safe, false if dangerous patterns detected\n *\n * @example\n * ```typescript\n * // Safe content - Allowed\n * isValidTextContent('Hello, world!') // true\n * isValidTextContent('User input: <b>bold</b>') // true\n * isValidTextContent('Email: user@example.com') // true\n *\n * // Dangerous content - XSS vectors detected\n * isValidTextContent('<script>alert(\"XSS\")</script>') // false\n * isValidTextContent('<img src=x onerror=\"alert(1)\">') // false (contains 'script' in onerror)\n * isValidTextContent('<a href=\"javascript:void(0)\">') // false\n * isValidTextContent('<iframe src=\"data:text/html,...\"') // false\n * isValidTextContent('vbscript:msgbox(\"XSS\")') // false\n *\n * // Size limit validation\n * isValidTextContent('x'.repeat(999_999)) // true (under default 1M limit)\n * isValidTextContent('x'.repeat(1_000_001)) // false (exceeds default limit)\n * isValidTextContent('x'.repeat(5000), { maxLength: 1000 }) // false (custom limit)\n *\n * // Edge cases\n * isValidTextContent('') // true (empty is valid)\n * isValidTextContent(null as any) // false (not a string)\n * isValidTextContent(undefined as any) // false (not a string)\n * isValidTextContent(123 as any) // false (not a string)\n *\n * // Real-world usage in comment system\n * app.post('/api/comments', (req, res) => {\n * const { content } = req.body\n *\n * if (!isValidTextContent(content, { maxLength: 5000 })) {\n * return res.status(400).json({\n * error: 'Invalid comment content',\n * details: 'Content contains dangerous patterns or exceeds 5000 characters'\n * })\n * }\n *\n * // Additional sanitization recommended\n * const sanitized = DOMPurify.sanitize(content)\n *\n * // Save to database...\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Form validation with custom limits\n * function validateUserBio(bio: string): { valid: boolean; error?: string } {\n * if (!isValidTextContent(bio, { maxLength: 500 })) {\n * return {\n * valid: false,\n * error: 'Bio must be less than 500 characters and cannot contain scripts'\n * }\n * }\n * return { valid: true }\n * }\n * ```\n *\n * @see {@link isValidFilePath} for file path validation\n * @see sanitizeHtml from validation module for HTML sanitization\n */\nexport function isValidTextContent(content: string, options: { maxLength?: number } = {}): boolean {\n const { maxLength = 1_000_000 } = options\n\n // ✅ Type validation\n if (typeof content !== 'string') return false\n\n // ✅ Length validation (DoS prevention)\n if (content.length > maxLength) return false\n\n const lowerContent = content.toLowerCase()\n\n // ✅ Script tag detection (case-insensitive, with variants)\n const scriptPatterns = ['<script', '</script', '<scr<script>ipt', '<scr\\x00ipt']\n if (scriptPatterns.some(pattern => lowerContent.includes(pattern))) return false\n\n // ✅ Event handler attributes (XSS vectors)\n const eventHandlers = [\n 'onerror',\n 'onload',\n 'onclick',\n 'onmouseover',\n 'onfocus',\n 'onblur',\n 'oninput',\n ]\n if (eventHandlers.some(handler => lowerContent.includes(handler))) return false\n\n // ✅ Protocol handlers (javascript:, data:, vbscript:, file:)\n const protocolPatterns = [\n 'javascript:',\n 'data:text/html',\n 'data:text/javascript',\n 'data:application',\n 'vbscript:',\n 'file:///',\n 'steam://',\n 'slack://',\n ]\n if (protocolPatterns.some(pattern => lowerContent.includes(pattern))) return false\n\n // ✅ Encoded script attempts\n const encodedPatterns = [\n '<script', // < = <\n '%3cscript', // %3c = <\n '\\\\x3cscript', // \\x3c = <\n '\\\\u003cscript', // \\u003c = <\n ]\n if (encodedPatterns.some(pattern => lowerContent.includes(pattern))) return false\n\n // ✅ SVG-based XSS\n if (lowerContent.includes('<svg') && lowerContent.includes('onload')) return false\n\n // ✅ iframe injection\n if (lowerContent.includes('<iframe')) return false\n\n return true\n}\n","/**\n * CSV Import/Export utilities\n *\n * Provides reliable CSV operations for both Node.js and Browser environments using PapaParse.\n * Features:\n * - UTF-8 BOM encoding for Excel compatibility\n * - Semicolon delimiter by default (European standard)\n * - Automatic header detection\n * - Dual-mode: filesystem (Node.js) vs download trigger (Browser)\n *\n * @module csv\n */\n\nimport Papa from 'papaparse'\nimport { isNode } from './environment'\n\n/**\n * Exports data as CSV file with UTF-8 BOM encoding\n *\n * Works in both Node.js (writes to filesystem) and Browser (triggers download).\n * Uses PapaParse library for reliable CSV generation with proper escaping and formatting.\n *\n * Features:\n * - UTF-8 BOM prepended (\\\\ufeff) for Excel compatibility\n * - Semicolon delimiter by default (European/Spanish standard)\n * - Automatic header row from object keys\n * - Custom delimiters and options via PapaParse config\n *\n * Environment behavior:\n * - **Node.js**: Writes file to filesystem at specified path\n * - **Browser**: Triggers automatic download with filename extracted from path\n *\n * @param data - Array of objects or array of arrays to export as CSV\n * @param filePath - File path (Node.js) or download filename (Browser)\n * @param options - PapaParse unparse options (optional)\n * @param options.delimiter - Column separator (default: ';' semicolon)\n * @param options.header - Include header row (default: true)\n * @param options.quotes - Quote all fields (default: false)\n * @param options.newline - Line ending (default: '\\\\r\\\\n')\n * @returns Promise that resolves when export completes\n *\n * @example\n * ```typescript\n * // Basic export - Array of objects\n * const users = [\n * { name: 'Alice', age: 30, city: 'Madrid' },\n * { name: 'Bob', age: 25, city: 'Barcelona' },\n * { name: 'Carlos', age: 35, city: 'Valencia' }\n * ]\n *\n * // Node.js - Write to file\n * await exportCSV(users, './reports/users.csv')\n * // Creates: ./reports/users.csv with BOM and semicolon delimiter\n *\n * // Browser - Trigger download\n * await exportCSV(users, 'users.csv')\n * // Downloads: users.csv to browser's download folder\n *\n * // Custom delimiter (comma for international)\n * await exportCSV(users, 'users_intl.csv', { delimiter: ',' })\n * ```\n *\n * @example\n * ```typescript\n * // Array of arrays (no header auto-detection)\n * const matrix = [\n * ['Name', 'Age', 'City'], // Header row\n * ['Alice', 30, 'Madrid'],\n * ['Bob', 25, 'Barcelona']\n * ]\n * await exportCSV(matrix, 'matrix.csv')\n *\n * // Without header row\n * const data = [['A1', 'B1'], ['A2', 'B2']]\n * await exportCSV(data, 'no_header.csv', { header: false })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Export sales report\n * async function exportSalesReport(sales: Sale[]) {\n * const reportData = sales.map(sale => ({\n * Fecha: formatDate(sale.date),\n * Cliente: sale.customerName,\n * Producto: sale.productName,\n * Cantidad: sale.quantity,\n * Total: `${sale.total.toFixed(2)}€`\n * }))\n *\n * const filename = `ventas_${new Date().toISOString().split('T')[0]}.csv`\n * await exportCSV(reportData, filename)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Custom PapaParse options\n * await exportCSV(data, 'quotes.csv', {\n * delimiter: ',',\n * quotes: true, // Quote all fields\n * quoteChar: '\"',\n * escapeChar: '\"',\n * newline: '\\\\n' // Unix line endings\n * })\n * ```\n *\n * @throws {Error} If file write fails in Node.js\n * @see {@link importCSV} for importing CSV files\n * @see {@link https://www.papaparse.com/docs#unparse PapaParse Unparse Documentation}\n */\nexport async function exportCSV(data: any[], filePath: string, options?: any): Promise<void> {\n // ✅ Input validation\n if (data == null) {\n throw new TypeError('Data cannot be null or undefined')\n }\n\n if (!Array.isArray(data)) {\n throw new TypeError('Data must be an array')\n }\n\n if (data.length === 0) {\n throw new Error('Data array cannot be empty')\n }\n\n if (!filePath || typeof filePath !== 'string' || filePath.trim() === '') {\n throw new TypeError('File path must be a non-empty string')\n }\n\n const csvText = Papa.unparse(data, {\n delimiter: ';',\n header: true,\n ...options,\n })\n\n if (isNode()) {\n const fs = await import('fs/promises')\n await fs.writeFile(filePath, `\\ufeff${csvText}`, { encoding: 'utf-8' })\n } else {\n const blob = new Blob([`\\ufeff${csvText}`], { type: 'text/csv;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = filePath.split('/').pop() || 'data.csv'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n }\n}\n\n/**\n * Imports CSV file and parses it to array of objects\n *\n * Reads CSV file from filesystem (Node.js only) and parses using PapaParse.\n * Automatically detects headers and converts rows to objects.\n *\n * Features:\n * - Automatic header detection from first row\n * - Semicolon delimiter by default (European standard)\n * - Empty line skipping\n * - Type inference for numbers and booleans\n * - UTF-8 BOM handling\n *\n * ⚠️ BROWSER LIMITATION: File reading from filesystem is not supported in browsers\n * for security reasons. For browser file uploads, use `readFileAsText()` with a File object\n * obtained from an input[type=\"file\"] element.\n *\n * @param filePath - Path to CSV file (Node.js only)\n * @param options - PapaParse parse options (optional)\n * @param options.delimiter - Column separator (default: ';' semicolon)\n * @param options.header - Parse first row as headers (default: true)\n * @param options.skipEmptyLines - Skip empty rows (default: true)\n * @param options.dynamicTyping - Convert numeric/boolean values (default: false)\n * @returns Promise<Array<Object>> Array of objects with keys from header row\n *\n * @example\n * ```typescript\n * // Basic import - Node.js only\n * const users = await importCSV('./data/users.csv')\n * // Returns: [\n * // { name: 'Alice', age: '30', city: 'Madrid' },\n * // { name: 'Bob', age: '25', city: 'Barcelona' }\n * // ]\n *\n * // Custom delimiter (comma)\n * const intlData = await importCSV('./data/users_intl.csv', {\n * delimiter: ','\n * })\n *\n * // With type conversion\n * const typed = await importCSV('./data/sales.csv', {\n * dynamicTyping: true // Converts '123' → 123, 'true' → true\n * })\n * // Returns: { quantity: 10, total: 299.99, active: true }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Import and process sales data\n * async function importSalesReport(filePath: string) {\n * try {\n * const sales = await importCSV(filePath, {\n * delimiter: ';',\n * dynamicTyping: true,\n * skipEmptyLines: true\n * })\n *\n * // Process imported data\n * const totalSales = sales.reduce((sum, sale) =>\n * sum + (sale.total || 0), 0\n * )\n *\n * console.log(`Imported ${sales.length} sales, total: €${totalSales}`)\n * return sales\n * } catch (error) {\n * console.error('Failed to import CSV:', error)\n * throw error\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Browser alternative using File API\n * // HTML: <input type=\"file\" id=\"csvFile\" accept=\".csv\">\n *\n * document.getElementById('csvFile').addEventListener('change', async (e) => {\n * const file = e.target.files[0]\n *\n * // Read file content\n * const content = await readFileAsText(file)\n *\n * // Parse with PapaParse\n * const parsed = Papa.parse(content, {\n * header: true,\n * delimiter: ';',\n * skipEmptyLines: true\n * })\n *\n * const data = parsed.data\n * console.log('Imported data:', data)\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Handle parsing errors\n * const result = await importCSV('./malformed.csv')\n * .catch(error => {\n * if (error.message.includes('not supported in browser')) {\n * console.error('Use File API for browser uploads')\n * } else if (error.code === 'ENOENT') {\n * console.error('File not found')\n * } else {\n * console.error('CSV parsing failed:', error)\n * }\n * return [] // Return empty array as fallback\n * })\n * ```\n *\n * @throws {Error} 'CSV import not supported in browser' when called in browser environment\n * @throws {Error} File system errors (ENOENT, EACCES, etc.) in Node.js\n * @see {@link exportCSV} for exporting CSV files\n * @see {@link readFileAsText} for browser file reading\n * @see {@link https://www.papaparse.com/docs#parse PapaParse Parse Documentation}\n */\nexport async function importCSV(filePath: string, options?: any): Promise<any[]> {\n // ✅ Input validation\n if (!filePath || typeof filePath !== 'string' || filePath.trim() === '') {\n throw new TypeError('File path must be a non-empty string')\n }\n\n if (isNode()) {\n const fs = await import('fs/promises')\n const content = await fs.readFile(filePath, { encoding: 'utf-8' })\n const parseResult = Papa.parse(content, {\n header: true,\n delimiter: ';',\n skipEmptyLines: true,\n ...options,\n }) as any\n return parseResult.data || []\n } else {\n throw new Error('CSV import not supported in browser. Use readFileAsText() with a File object.')\n }\n}\n","/**\n * JSON Import/Export utilities\n *\n * Provides reliable JSON file operations for both Node.js and Browser environments.\n * Features:\n * - UTF-8 encoding for international character support\n * - Pretty-printing with configurable indentation\n * - Dual-mode: filesystem (Node.js) vs download trigger (Browser)\n * - Native JSON.stringify/parse for maximum compatibility\n *\n * @module json\n */\n\nimport { isNode } from './environment'\n\n/**\n * Exports data as JSON file with UTF-8 encoding\n *\n * Works in both Node.js (writes to filesystem) and Browser (triggers download).\n * Uses native JSON.stringify for serialization with optional pretty-printing.\n *\n * Features:\n * - UTF-8 encoding for international characters\n * - Configurable indentation (default: 2 spaces)\n * - Automatic filename extraction in browser\n * - Pretty-printed by default for readability\n *\n * Environment behavior:\n * - **Node.js**: Writes file to filesystem at specified path\n * - **Browser**: Triggers automatic download with filename extracted from path\n *\n * ⚠️ WARNING: Cannot serialize:\n * - Functions (removed silently)\n * - Symbols (removed silently)\n * - Circular references (throws TypeError)\n * - undefined values (removed from objects, converted to null in arrays)\n * - BigInt values (throws TypeError unless custom replacer provided)\n *\n * @param data - Any serializable JavaScript value (object, array, primitive)\n * @param filePath - File path (Node.js) or download filename (Browser)\n * @param options - Export options (optional)\n * @param options.indent - Number of spaces for indentation (default: 2, use 0 for compact)\n * @returns Promise that resolves when export completes\n *\n * @example\n * ```typescript\n * // Basic export - Object\n * const config = {\n * database: { host: 'localhost', port: 5432 },\n * features: { auth: true, payments: false }\n * }\n *\n * // Node.js - Write to file\n * await exportJSON(config, './config/app.json')\n * // Creates: ./config/app.json with 2-space indentation\n *\n * // Browser - Trigger download\n * await exportJSON(config, 'app-config.json')\n * // Downloads: app-config.json to browser's download folder\n *\n * // Compact output (no pretty-printing)\n * await exportJSON(config, 'config.json', { indent: 0 })\n * // Single-line JSON: {\"database\":{\"host\":\"localhost\",\"port\":5432}}\n * ```\n *\n * @example\n * ```typescript\n * // Array export\n * const users = [\n * { id: 1, name: 'Alice', email: 'alice@example.com' },\n * { id: 2, name: 'Bob', email: 'bob@example.com' }\n * ]\n * await exportJSON(users, 'users.json')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Configuration backup system\n * async function backupConfiguration(config: AppConfig) {\n * const timestamp = new Date().toISOString().split('T')[0]\n * const filename = `config-backup-${timestamp}.json`\n *\n * try {\n * await exportJSON(config, `./backups/${filename}`, { indent: 2 })\n * console.log(`✅ Configuration backed up to ${filename}`)\n * } catch (error) {\n * console.error('❌ Backup failed:', error)\n * throw error\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Export API response for debugging\n * async function debugApiResponse(endpoint: string, data: any) {\n * const filename = `api-${endpoint.replace(/\\//g, '-')}.json`\n * await exportJSON({\n * endpoint,\n * timestamp: new Date().toISOString(),\n * data\n * }, filename)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Handle circular references\n * const obj = { name: 'test' }\n * obj.self = obj // Circular reference\n *\n * try {\n * await exportJSON(obj, 'circular.json')\n * } catch (error) {\n * console.error('Cannot serialize circular structure')\n * // Use custom replacer to handle circular refs\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Different indentation levels\n * await exportJSON(data, 'compact.json', { indent: 0 }) // Single line\n * await exportJSON(data, 'readable.json', { indent: 2 }) // 2 spaces (default)\n * await exportJSON(data, 'spacious.json', { indent: 4 }) // 4 spaces\n * ```\n *\n * @throws {TypeError} If data contains circular references or BigInt values\n * @throws {Error} If file write fails in Node.js (permissions, disk space, etc.)\n * @see {@link importJSON} for importing JSON files\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify JSON.stringify Documentation}\n */\nexport async function exportJSON(\n data: any,\n filePath: string,\n options?: { indent?: number }\n): Promise<void> {\n // ✅ Input validation\n if (data === null || data === undefined) {\n throw new TypeError('Data cannot be null or undefined')\n }\n\n if (!filePath || typeof filePath !== 'string' || filePath.trim() === '') {\n throw new TypeError('File path must be a non-empty string')\n }\n\n const { indent = 2 } = options || {}\n\n // ✅ Detect circular references before stringify\n let jsonText: string\n try {\n jsonText = JSON.stringify(data, null, indent)\n } catch (error) {\n if (error instanceof TypeError && error.message.includes('circular')) {\n throw new TypeError('Cannot serialize data with circular references')\n }\n throw error\n }\n\n if (isNode()) {\n const fs = await import('fs/promises')\n await fs.writeFile(filePath, jsonText, { encoding: 'utf-8' })\n } else {\n const blob = new Blob([jsonText], { type: 'application/json;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n const link = document.createElement('a')\n link.href = url\n link.download = filePath.split('/').pop() || 'data.json'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n }\n}\n\n/**\n * Imports JSON file and parses it to JavaScript value\n *\n * Reads JSON file from filesystem (Node.js only) and parses using native JSON.parse.\n * Returns the parsed JavaScript value (object, array, primitive).\n *\n * Features:\n * - UTF-8 encoding support for international characters\n * - Native JSON.parse for standard-compliant parsing\n * - Automatic type inference\n * - Whitespace and comment tolerance (standard JSON only)\n *\n * ⚠️ BROWSER LIMITATION: File reading from filesystem is not supported in browsers\n * for security reasons. For browser file uploads, use `readFileAsText()` with a File object\n * obtained from an input[type=\"file\"] element.\n *\n * @param filePath - Path to JSON file (Node.js only)\n * @param _options - Reserved for future options (currently unused)\n * @returns Promise<any> Parsed JavaScript value (object, array, primitive, null)\n *\n * @example\n * ```typescript\n * // Basic import - Node.js only\n * const config = await importJSON('./config/app.json')\n * // Returns: { database: { host: 'localhost', port: 5432 }, ... }\n *\n * console.log(config.database.host) // 'localhost'\n *\n * // Array import\n * const users = await importJSON('./data/users.json')\n * // Returns: [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]\n *\n * // Primitive values (valid JSON)\n * const version = await importJSON('./version.json') // \"1.2.3\"\n * const enabled = await importJSON('./feature.json') // true\n * const count = await importJSON('./count.json') // 42\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Load configuration with fallback\n * async function loadConfiguration(configPath: string): Promise<AppConfig> {\n * try {\n * const config = await importJSON(configPath)\n *\n * // Validate loaded config\n * if (!config.database || !config.database.host) {\n * throw new Error('Invalid configuration: missing database.host')\n * }\n *\n * return config\n * } catch (error) {\n * console.warn(`Failed to load config from ${configPath}:`, error)\n * console.log('Using default configuration')\n * return getDefaultConfig()\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Restore configuration backup\n * async function restoreBackup(backupFile: string) {\n * console.log(`Restoring configuration from ${backupFile}...`)\n *\n * const backup = await importJSON(`./backups/${backupFile}`)\n *\n * // Verify backup integrity\n * if (!backup.timestamp || !backup.config) {\n * throw new Error('Invalid backup file format')\n * }\n *\n * // Restore configuration\n * await saveConfiguration(backup.config)\n *\n * console.log(`✅ Configuration restored from ${backup.timestamp}`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Browser alternative using File API\n * // HTML: <input type=\"file\" id=\"jsonFile\" accept=\".json\">\n *\n * document.getElementById('jsonFile').addEventListener('change', async (e) => {\n * const file = e.target.files[0]\n *\n * // Read file content\n * const content = await readFileAsText(file)\n *\n * // Parse JSON\n * try {\n * const data = JSON.parse(content)\n * console.log('Imported JSON:', data)\n * } catch (error) {\n * console.error('Invalid JSON file:', error)\n * }\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Handle parsing errors\n * async function safeImportJSON(filePath: string): Promise<any | null> {\n * try {\n * return await importJSON(filePath)\n * } catch (error) {\n * if (error.message.includes('not supported in browser')) {\n * console.error('Use File API for browser uploads')\n * } else if (error.code === 'ENOENT') {\n * console.error(`File not found: ${filePath}`)\n * } else if (error instanceof SyntaxError) {\n * console.error(`Invalid JSON syntax in ${filePath}:`, error.message)\n * } else {\n * console.error('JSON import failed:', error)\n * }\n * return null\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Type-safe import with validation\n * interface DatabaseConfig {\n * host: string\n * port: number\n * database: string\n * }\n *\n * async function loadDatabaseConfig(path: string): Promise<DatabaseConfig> {\n * const raw = await importJSON(path)\n *\n * // Runtime validation\n * if (typeof raw.host !== 'string' || typeof raw.port !== 'number') {\n * throw new Error('Invalid database configuration structure')\n * }\n *\n * return raw as DatabaseConfig\n * }\n * ```\n *\n * @throws {Error} 'JSON import not supported in browser' when called in browser environment\n * @throws {SyntaxError} If file contains invalid JSON syntax\n * @throws {Error} File system errors (ENOENT, EACCES, etc.) in Node.js\n * @see {@link exportJSON} for exporting JSON files\n * @see {@link readFileAsText} for browser file reading\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse JSON.parse Documentation}\n */\nexport async function importJSON(filePath: string, _options?: any): Promise<any> {\n // ✅ Input validation\n if (!filePath || typeof filePath !== 'string' || filePath.trim() === '') {\n throw new TypeError('File path must be a non-empty string')\n }\n\n if (isNode()) {\n const fs = await import('fs/promises')\n const content = await fs.readFile(filePath, { encoding: 'utf-8' })\n\n // ✅ Validate content is not empty\n const trimmed = content.trim()\n if (trimmed === '') {\n throw new SyntaxError('JSON file is empty')\n }\n\n // ✅ Better error message for invalid JSON\n try {\n return JSON.parse(content)\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new SyntaxError(`Invalid JSON in file ${filePath}: ${error.message}`)\n }\n throw error\n }\n } else {\n throw new Error(\n 'JSON import not supported in browser. Use readFileAsText() with a File object.'\n )\n }\n}\n","/**\n * Node.js-specific exports - Full functionality with crypto support\n * Uses Node.js crypto module for secure operations\n */\n\n// Import universal modules\nimport * as validationCore from '../universal/validation-core'\nimport * as stringFunctions from '../strings'\nimport * as objectFunctions from '../objects'\nimport * as dateFunctions from '../dates'\nimport * as mathFunctions from '../math'\nimport * as asyncFunctions from '../async'\nimport * as dataFunctions from '../data'\nimport * as environmentModule from '../environment'\nimport * as numberModule from '../number'\nimport * as treeModule from '../tree'\n\n// Import Node.js-specific crypto functions\nimport * as validationCrypto from './validation-crypto'\n\n// Merge core validation with crypto functions for Node.js\nconst validationFunctions = {\n ...validationCore,\n ...validationCrypto,\n}\n\n// Create flat API object with full Node.js functionality\nconst g = {\n // Full validation functions (core + crypto)\n ...validationFunctions,\n\n // String functions\n ...stringFunctions,\n\n // Object/Array functions\n ...objectFunctions,\n\n // Date functions\n ...dateFunctions,\n\n // Math functions\n ...mathFunctions,\n\n // Async functions\n ...asyncFunctions,\n\n // Data functions\n ...dataFunctions,\n\n // Number utilities\n ...numberModule,\n\n // Tree utilities\n ...treeModule,\n\n // Environment utilities\n ...environmentModule,\n}\n\n// Export both default and named exports\nexport default g\n\n// Named exports for specific imports\nexport {\n validationFunctions as validation,\n stringFunctions as strings,\n objectFunctions as objects,\n dateFunctions as dates,\n mathFunctions as math,\n asyncFunctions as async,\n dataFunctions as data,\n environmentModule as environment,\n numberModule as number,\n treeModule as tree,\n}\n\n// Re-export individual functions for tree-shaking\nexport * from '../universal/validation-core'\nexport * from './validation-crypto'\nexport * from '../strings'\nexport * from '../objects'\nexport * from '../dates'\nexport * from '../math'\nexport * from '../async'\nexport * from '../data'\nexport * from '../environment'\nexport * from '../number'\n// Note: tree module exports conflict with data module, so importing through named export\nexport { renderTreeAsText, TreeExportOptions as TreeOnlyExportOptions } from '../tree'\n","/**\n * Core validation utilities - Universal (Browser + Node.js compatible)\n * NO crypto dependencies - safe for all environments\n */\n\nimport validator from 'validator'\n\n// =============================================================================\n// RANDOM GENERATORS (crypto-free)\n// =============================================================================\n\nconst randomInteger = (min: number, max: number): number => {\n return Math.floor(Math.random() * (max - min + 1)) + min\n}\n\nconst randomString = (length: number, pool?: string): string => {\n const chars = pool || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n let result = ''\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length))\n }\n return result\n}\n\nconst randomAlphaString = (length: number, casing?: 'upper' | 'lower'): string => {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'\n let result = randomString(length, chars)\n if (casing === 'upper') result = result.toUpperCase()\n if (casing === 'lower') result = result.toLowerCase()\n return result\n}\n\nconst randomAlphaNumericString = (length: number, casing?: 'upper' | 'lower'): string => {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n let result = randomString(length, chars)\n if (casing === 'upper') result = result.toUpperCase()\n if (casing === 'lower') result = result.toLowerCase()\n return result\n}\n\nconst pickone = <T>(array: T[]): T => {\n return array[Math.floor(Math.random() * array.length)]\n}\n\nconst randomBool = (likelihood = 50): boolean => {\n return Math.random() * 100 < likelihood\n}\n\n// =============================================================================\n// GENERATORS - Random data generators (crypto-free)\n// =============================================================================\n\n/**\n * Generates a random integer between min and max (inclusive)\n * @param min - Minimum value (default: 0)\n * @param max - Maximum value (default: 100)\n * @returns Random integer between min and max\n * @example\n * ```ts\n * const dice = generateRandomInteger(1, 6) // 1, 2, 3, 4, 5, or 6\n * const percent = generateRandomInteger(0, 100) // 0 to 100\n * const id = generateRandomInteger(1000, 9999) // 4-digit ID\n * ```\n */\nexport const generateRandomInteger = (min = 0, max = 100): number => {\n return randomInteger(min, max)\n}\n\n/**\n * Generates a random alphabetic string (letters only)\n * @param options - Configuration object\n * @param options.length - Length of the string (default: 10)\n * @param options.casing - Case transformation: 'upper', 'lower', or undefined\n * @returns Random alphabetic string\n * @example\n * ```ts\n * const name = generateAlphaString({ length: 8 }) // \"AbCdEfGh\"\n * const upper = generateAlphaString({ length: 5, casing: 'upper' }) // \"ABCDE\"\n * const lower = generateAlphaString({ length: 3, casing: 'lower' }) // \"abc\"\n * ```\n */\nexport const generateAlphaString = (\n options: { length?: number; casing?: 'upper' | 'lower' | undefined } = {}\n): string => {\n const { length = 10, casing = undefined } = options\n return randomAlphaString(length, casing)\n}\n\n/**\n * Generates a random alphanumeric string (letters and numbers)\n * @param options - Configuration object\n * @param options.length - Length of the string (default: 10)\n * @param options.casing - Case transformation: 'upper', 'lower', or undefined\n * @returns Random alphanumeric string\n * @example\n * ```ts\n * const token = generateAlphaNumericString({ length: 12 }) // \"aB3cD4eF5gH6\"\n * const code = generateAlphaNumericString({ length: 6, casing: 'upper' }) // \"A1B2C3\"\n * const key = generateAlphaNumericString({ length: 8, casing: 'lower' }) // \"a1b2c3d4\"\n * ```\n */\nexport const generateAlphaNumericString = (\n options: { length?: number; casing?: 'upper' | 'lower' | undefined } = {}\n): string => {\n const { length = 10, casing = undefined } = options\n return randomAlphaNumericString(length, casing)\n}\n\n/**\n * Generates a random complex string with all characters (letters, numbers, symbols)\n * @param options - Configuration object\n * @param options.length - Length of the string (default: 10)\n * @param options.casing - Case transformation (currently not applied to symbols)\n * @returns Random complex string\n * @example\n * ```ts\n * const password = generateComplexString({ length: 16 }) // \"aB3#cD4$eF5%gH6\"\n * const secret = generateComplexString({ length: 32 }) // Complex 32-char string\n * const temp = generateComplexString() // 10 characters by default\n * ```\n */\nexport const generateComplexString = (\n options: { length?: number; casing?: 'upper' | 'lower' | undefined } = {}\n): string => {\n const { length = 10, casing: _casing = undefined } = options\n return randomString(length)\n}\n\n/**\n * Generates a username from an email address\n * @param email - Email address to extract username from\n * @param randomDigits - Number of random digits to append (default: 1)\n * @returns Username derived from email with random suffix\n * @example\n * ```ts\n * const user1 = generateUsernameFromEmail('john.doe@example.com', 2) // \"johndoe47\"\n * const user2 = generateUsernameFromEmail('maria-garcia@test.org', 3) // \"mariagarcia823\"\n * const fallback = generateUsernameFromEmail('invalid-email', 2) // \"user42\"\n * ```\n */\nexport const generateUsernameFromEmail = (email: string, randomDigits = 1): string => {\n if (!email || !email.includes('@'))\n return `user${Math.floor(Math.random() * Math.pow(10, randomDigits))}`\n\n const localPart = email.split('@')[0]\n const username = localPart\n .toLowerCase()\n .replace(/[^a-z0-9]/g, '')\n .substring(0, 12)\n\n const randomSuffix = Math.floor(Math.random() * Math.pow(10, randomDigits))\n return username + randomSuffix\n}\n\n/**\n * Generates a random username with adjective + noun pattern\n * @param separator - Character to separate adjective and noun (default: '')\n * @param randomDigits - Number of random digits to append (default: 1)\n * @param length - Maximum length of username (default: 8)\n * @returns Random username like \"coolcat5\" or \"brave_wolf3\"\n * @example\n * ```ts\n * const user1 = generateUsername() // \"coolcat5\"\n * const user2 = generateUsername('_', 2) // \"brave_wolf83\"\n * const user3 = generateUsername('-', 3, 15) // \"smart-eagle247\"\n * ```\n */\nexport const generateUsername = (separator = '', randomDigits = 1, length = 8): string => {\n const adjectives = [\n 'cool',\n 'happy',\n 'smart',\n 'fast',\n 'nice',\n 'wild',\n 'free',\n 'bold',\n 'calm',\n 'brave',\n ]\n const nouns = ['cat', 'dog', 'bird', 'fish', 'lion', 'bear', 'wolf', 'tiger', 'eagle', 'shark']\n\n const adjective = adjectives[Math.floor(Math.random() * adjectives.length)]\n const noun = nouns[Math.floor(Math.random() * nouns.length)]\n const randomSuffix = Math.floor(Math.random() * Math.pow(10, randomDigits))\n\n const username = adjective + separator + noun + randomSuffix\n\n return username.length > length ? username.substring(0, length) : username\n}\n\n// =============================================================================\n// SPANISH GENERATORS\n// =============================================================================\n\n/**\n * Generates a valid Spanish NIF (Número de Identificación Fiscal)\n * @returns A valid NIF string in format '12345678Z'\n * @example\n * ```ts\n * const nif1 = generateSpanishNIF() // \"87654321T\"\n * const nif2 = generateSpanishNIF() // \"12345678Z\"\n *\n * // Verify it's valid\n * const nif = generateSpanishNIF()\n * console.log(validateNIF(nif)) // true\n * ```\n */\nexport const generateSpanishNIF = (): string => {\n const number = randomInteger(10000000, 99999999)\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const letter = letters[number % 23]\n return `${number}${letter}`\n}\n\n/**\n * Generates a valid Spanish NIE (Número de Identidad de Extranjero)\n * @returns A valid NIE string in format 'X1234567L'\n * @example\n * ```ts\n * const nie1 = generateSpanishNIE() // \"X1234567L\"\n * const nie2 = generateSpanishNIE() // \"Y9876543R\"\n * const nie3 = generateSpanishNIE() // \"Z2468135T\"\n *\n * // Verify it's valid\n * const nie = generateSpanishNIE()\n * console.log(isValidNIE(nie)) // true\n * ```\n */\nexport const generateSpanishNIE = (): string => {\n const prefixes = ['X', 'Y', 'Z']\n const selectedPrefix = pickone(prefixes)\n const prefixValue = selectedPrefix === 'X' ? 0 : selectedPrefix === 'Y' ? 1 : 2\n const number = randomInteger(1000000, 9999999)\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const calculationNumber = prefixValue * 10000000 + number\n const letter = letters[calculationNumber % 23]\n return `${selectedPrefix}${number}${letter}`\n}\n\n/**\n * Generates a valid Spanish CIF (Código de Identificación Fiscal)\n * @returns A valid CIF string in format 'A12345674' or 'B87654321'\n * @example\n * ```ts\n * const cif1 = generateSpanishCIF() // \"A12345674\"\n * const cif2 = generateSpanishCIF() // \"B87654321\"\n * const cif3 = generateSpanishCIF() // \"G28456789\"\n *\n * // Verify it's valid\n * const cif = generateSpanishCIF()\n * console.log(isValidCIF(cif)) // true\n *\n * // Different organization types\n * // A,B,E,H = Sociedades Anónimas/Limitadas\n * // G,U = Fundaciones, asociaciones\n * // N,P,Q,R,S,W = Organismos públicos\n * ```\n */\nexport const generateSpanishCIF = (): string => {\n const organizationTypes = [\n 'A',\n 'B',\n 'C',\n 'D',\n 'E',\n 'F',\n 'G',\n 'H',\n 'J',\n 'N',\n 'P',\n 'Q',\n 'R',\n 'S',\n 'U',\n 'V',\n 'W',\n ]\n const organizationType = pickone(organizationTypes)\n const number = randomInteger(1000000, 9999999).toString().padStart(7, '0')\n\n // Calculate control digit\n let sum = 0\n for (let i = 0; i < 7; i++) {\n let digit = parseInt(number[i])\n if (i % 2 === 0) {\n digit *= 2\n if (digit > 9) digit = Math.floor(digit / 10) + (digit % 10)\n }\n sum += digit\n }\n\n const controlDigit = (10 - (sum % 10)) % 10\n const controlLetter = 'JABCDEFGHI'[controlDigit]\n const control = ['N', 'P', 'Q', 'R', 'S', 'W'].includes(organizationType)\n ? controlLetter\n : randomBool()\n ? controlDigit.toString()\n : controlLetter\n\n return `${organizationType}${number}${control}`\n}\n\nexport const generateSpanishPostalCode = (): string => {\n const validPrefixes = [\n '01',\n '02',\n '03',\n '04',\n '05',\n '06',\n '07',\n '08',\n '09',\n '10',\n '11',\n '12',\n '13',\n '14',\n '15',\n '16',\n '17',\n '18',\n '19',\n '20',\n '21',\n '22',\n '23',\n '24',\n '25',\n '26',\n '27',\n '28',\n '29',\n '30',\n '31',\n '32',\n '33',\n '34',\n '35',\n '36',\n '37',\n '38',\n '39',\n '40',\n '41',\n '42',\n '43',\n '44',\n '45',\n '46',\n '47',\n '48',\n '49',\n '50',\n '51',\n '52',\n ]\n\n const firstDigit = pickone(validPrefixes)\n const remainingDigits = randomString(3, '0123456789')\n return `${firstDigit}${remainingDigits}`\n}\n\nexport const generateSpanishIBAN = (): string => {\n const bankCode = randomString(4, '0123456789')\n const branchCode = randomString(4, '0123456789')\n const controlDigits = randomString(2, '0123456789')\n const accountNumber = randomString(10, '0123456789')\n\n // Calculate IBAN check digits\n const accountPart = `${bankCode}${branchCode}${controlDigits}${accountNumber}`\n const rearranged = `${accountPart}142800`\n\n // Calculate mod 97\n const checkDigits = String(98n - (BigInt(rearranged) % 97n)).padStart(2, '0')\n\n return `ES${checkDigits}${bankCode}${branchCode}${controlDigits}${accountNumber}`\n}\n\n// =============================================================================\n// GENERAL GENERATORS\n// =============================================================================\n\nexport const generateEmail = (domain?: string): string => {\n const firstNames = [\n 'Ana',\n 'Carlos',\n 'María',\n 'José',\n 'Laura',\n 'David',\n 'Carmen',\n 'Antonio',\n 'Isabel',\n 'Manuel',\n ]\n const lastNames = [\n 'García',\n 'González',\n 'López',\n 'Martínez',\n 'Sánchez',\n 'Pérez',\n 'Gómez',\n 'Martín',\n 'Jiménez',\n 'Ruiz',\n ]\n const domains = ['gmail.com', 'hotmail.com', 'yahoo.es', 'outlook.com', 'test.com']\n\n const firstName = pickone(firstNames)\n const lastName = pickone(lastNames)\n const emailDomain = domain || pickone(domains)\n\n const formats = [\n `${firstName.toLowerCase()}.${lastName.toLowerCase()}@${emailDomain}`,\n `${firstName.toLowerCase()}${randomInteger(1, 99)}@${emailDomain}`,\n `${firstName.toLowerCase()}.${lastName.toLowerCase()}${randomInteger(1, 9)}@${emailDomain}`,\n `${firstName.toLowerCase()}${lastName.toLowerCase()}@${emailDomain}`,\n ]\n\n const username = pickone(formats)\n return username.toLowerCase()\n}\n\nexport const generatePassword = (\n options: {\n length?: number\n includeUppercase?: boolean\n includeLowercase?: boolean\n includeNumbers?: boolean\n includeSymbols?: boolean\n } = {}\n): string => {\n const {\n length = 12,\n includeUppercase = true,\n includeLowercase = true,\n includeNumbers = true,\n includeSymbols = true,\n } = options\n\n const minLength = 4\n const maxLength = 30\n const targetLength = length || randomInteger(minLength, maxLength)\n\n const upperChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n const lowerChars = 'abcdefghijklmnopqrstuvwxyz'\n const numberChars = '0123456789'\n const symbolChars = '!@#$%^&*()_+-=[]{}|;:,.<>?'\n\n let charset = ''\n let requiredChars = ''\n\n if (includeUppercase) {\n charset += upperChars\n requiredChars += upperChars.charAt(Math.floor(Math.random() * upperChars.length))\n }\n if (includeLowercase) {\n charset += lowerChars\n requiredChars += lowerChars.charAt(Math.floor(Math.random() * lowerChars.length))\n }\n if (includeNumbers) {\n charset += numberChars\n requiredChars += numberChars.charAt(Math.floor(Math.random() * numberChars.length))\n }\n if (includeSymbols) {\n charset += symbolChars\n requiredChars += symbolChars.charAt(Math.floor(Math.random() * symbolChars.length))\n }\n\n if (!charset) charset = 'abcdefghijklmnopqrstuvwxyz'\n\n let password = requiredChars\n const remainingLength = targetLength - requiredChars.length\n\n for (let i = 0; i < remainingLength; i++) {\n password += charset.charAt(Math.floor(Math.random() * charset.length))\n }\n\n return password\n .split('')\n .sort(() => Math.random() - 0.5)\n .join('')\n}\n\nexport const generateHexColor = (shortFormat?: boolean): string => {\n const hexChars = '0123456789ABCDEF'\n const useShortFormat = shortFormat !== undefined ? shortFormat : randomBool()\n\n if (useShortFormat) {\n const r = pickone(hexChars.split(''))\n const g = pickone(hexChars.split(''))\n const b = pickone(hexChars.split(''))\n return `#${r}${g}${b}`\n } else {\n const color = randomString(6, hexChars)\n return `#${color}`\n }\n}\n\n// =============================================================================\n// VALIDATORS\n// =============================================================================\n\n/**\n * Validates a Spanish NIF (Número de Identificación Fiscal)\n * @param nif - The NIF string to validate\n * @returns true if the NIF is valid, false otherwise\n * @example\n * ```ts\n * console.log(isValidNIF('12345678Z')) // true\n * console.log(isValidNIF('87654321T')) // true\n * console.log(isValidNIF('12345678A')) // false (wrong letter)\n * console.log(isValidNIF('1234567Z')) // false (wrong length)\n * console.log(isValidNIF('')) // false (empty)\n *\n * // Case insensitive and handles whitespace\n * console.log(isValidNIF(' 12345678z ')) // true\n * ```\n */\nexport const isValidNIF = (nif: string): boolean => {\n if (!nif || typeof nif !== 'string') return false\n\n const cleanNif = nif.trim().toUpperCase()\n const nifRegex = /^[0-9]{8}[TRWAGMYFPDXBNJZSQVHLCKE]$/\n\n if (!nifRegex.test(cleanNif)) return false\n\n const number = parseInt(cleanNif.substring(0, 8))\n const letter = cleanNif.charAt(8)\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const expectedLetter = letters[number % 23]\n\n return letter === expectedLetter\n}\n\n/**\n * Alias for isValidNIF - validates a Spanish NIF\n * @param nif - The NIF string to validate\n * @returns true if the NIF is valid, false otherwise\n * @example\n * ```ts\n * console.log(validateNIF('12345678Z')) // true\n * // Same functionality as isValidNIF\n * ```\n */\nexport const validateNIF = isValidNIF\n\n/**\n * Validates a Spanish NIE (Número de Identidad de Extranjero)\n * @param nie - The NIE string to validate\n * @returns true if the NIE is valid, false otherwise\n * @example\n * ```ts\n * console.log(isValidNIE('X1234567L')) // true\n * console.log(isValidNIE('Y9876543R')) // true\n * console.log(isValidNIE('Z2468135T')) // true\n * console.log(isValidNIE('X1234567A')) // false (wrong letter)\n * console.log(isValidNIE('W1234567L')) // false (invalid prefix)\n * console.log(isValidNIE('X123456L')) // false (wrong length)\n *\n * // Case insensitive and handles whitespace\n * console.log(isValidNIE(' x1234567l ')) // true\n * ```\n */\nexport const isValidNIE = (nie: string): boolean => {\n if (!nie || typeof nie !== 'string') return false\n\n const cleanNie = nie.trim().toUpperCase()\n const nieRegex = /^[XYZ][0-9]{7}[TRWAGMYFPDXBNJZSQVHLCKE]$/\n\n if (!nieRegex.test(cleanNie)) return false\n\n const prefix = cleanNie.charAt(0)\n const number = parseInt(cleanNie.substring(1, 8))\n const letter = cleanNie.charAt(8)\n\n const prefixValue = prefix === 'X' ? 0 : prefix === 'Y' ? 1 : 2\n const calculationNumber = prefixValue * 10000000 + number\n const letters = 'TRWAGMYFPDXBNJZSQVHLCKE'\n const expectedLetter = letters[calculationNumber % 23]\n\n return letter === expectedLetter\n}\n\nexport const isValidCIF = (cif: string): boolean => {\n if (!cif || typeof cif !== 'string') return false\n\n const cleanCif = cif.trim().toUpperCase()\n const cifRegex = /^[ABCDEFGHJNPQRSUVW][0-9]{7}[0-9A-J]$/\n\n if (!cifRegex.test(cleanCif)) return false\n\n const organizationType = cleanCif.charAt(0)\n const number = cleanCif.substring(1, 8)\n const control = cleanCif.charAt(8)\n\n let sum = 0\n for (let i = 0; i < 7; i++) {\n let digit = parseInt(number[i])\n if (i % 2 === 0) {\n digit *= 2\n if (digit > 9) digit = Math.floor(digit / 10) + (digit % 10)\n }\n sum += digit\n }\n\n const controlDigit = (10 - (sum % 10)) % 10\n const controlLetter = 'JABCDEFGHI'[controlDigit]\n\n if (['N', 'P', 'Q', 'R', 'S', 'W'].includes(organizationType)) {\n return control === controlLetter\n } else {\n return control === controlDigit.toString() || control === controlLetter\n }\n}\n\nexport const isValidSpanishPostalCode = (postalCode: string): boolean => {\n if (!postalCode || typeof postalCode !== 'string') return false\n\n const cleanCode = postalCode.trim()\n const postalCodeRegex = /^(0[1-9]|[1-4][0-9]|5[0-2])[0-9]{3}$/\n\n return postalCodeRegex.test(cleanCode)\n}\n\nexport const isValidSpanishPhone = (phone: string): boolean => {\n if (!phone || typeof phone !== 'string') return false\n\n const cleanPhone = phone.replace(/[\\s\\-()]/g, '')\n const phoneRegex = /^(?:\\+34|0034|34)?([679][0-9]{8})$/\n\n return phoneRegex.test(cleanPhone)\n}\n\nexport const isValidEmail = (email: string): boolean => {\n if (!email || typeof email !== 'string') return false\n return validator.isEmail(email)\n}\n\nexport const isValidURL = (url: string): boolean => {\n if (!url || typeof url !== 'string') return false\n\n if (validator.isURL(url, { require_protocol: true })) {\n return true\n }\n\n try {\n const urlObj = new URL(url)\n return urlObj.hostname === 'localhost' || urlObj.hostname === '127.0.0.1'\n } catch {\n return false\n }\n}\n\nexport const isValidJSON = (str: string): boolean => {\n if (!str || typeof str !== 'string') return false\n try {\n JSON.parse(str)\n return true\n } catch {\n return false\n }\n}\n\nexport const isValidSpanishIBAN = (iban: string): boolean => {\n if (!iban || typeof iban !== 'string') return false\n\n const cleanIban = iban.replace(/\\s/g, '').toUpperCase()\n const ibanRegex = /^ES[0-9]{22}$/\n\n if (!ibanRegex.test(cleanIban)) return false\n\n const rearranged = cleanIban.substring(4) + cleanIban.substring(0, 4)\n const numericString = rearranged.replace(/[A-Z]/g, letter => {\n return (letter.charCodeAt(0) - 55).toString()\n })\n\n let remainder = 0\n for (let i = 0; i < numericString.length; i++) {\n remainder = (remainder * 10 + parseInt(numericString[i])) % 97\n }\n\n return remainder === 1\n}\n","/**\n * String manipulation utilities\n * Consolidated from primitives/string module\n */\n\n/**\n * Sanitizes a string by removing special characters and converting to lowercase with dashes\n *\n * Produces clean, URL-friendly strings by removing special characters and normalizing whitespace.\n * Useful for slugs, IDs, CSS class names, and filename generation.\n *\n * Transformation rules:\n * 1. Remove all non-alphanumeric characters except spaces\n * 2. Remove additional punctuation (`~!@#$%^&*()_|+-=?;:'\",.<>{}[]\\\\/`)\n * 3. Replace spaces with dashes\n * 4. Convert to lowercase\n *\n * @param instr - Input string to sanitize (null returns empty string)\n * @returns Sanitized string in lowercase with dashes replacing spaces\n *\n * @example\n * ```typescript\n * // Basic sanitization\n * sanitizeString('Hello World!') // 'hello-world'\n * sanitizeString('user@example.com') // 'userexamplecom'\n * sanitizeString('Price: $19.99') // 'price-1999'\n *\n * // Remove accents and special chars\n * sanitizeString('Café Münchën') // 'caf-mnchen'\n * sanitizeString('北京 2024') // '2024'\n *\n * // Multiple spaces/dashes\n * sanitizeString('hello world') // 'hello---world'\n * sanitizeString('foo-bar_baz') // 'foo-barbaz'\n *\n * // Edge cases\n * sanitizeString(null) // ''\n * sanitizeString('') // ''\n * sanitizeString(' ') // '---'\n * sanitizeString('123') // '123'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate CSS class names from user input\n * function generateClassName(userInput: string): string {\n * return `custom-${sanitizeString(userInput)}`\n * }\n *\n * generateClassName('My Component!') // 'custom-my-component'\n * generateClassName('Button (Primary)') // 'custom-button-primary'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Clean product names for file export\n * const products = [\n * { name: 'T-Shirt (Blue)', sku: 'TS-001' },\n * { name: 'Shoes & Accessories', sku: 'SH-042' }\n * ]\n *\n * products.forEach(p => {\n * const filename = `${sanitizeString(p.name)}-${p.sku}.json`\n * console.log(filename)\n * // 't-shirt-blue-TS-001.json'\n * // 'shoes-accessories-SH-042.json'\n * })\n * ```\n *\n * @see {@link toUrlSlug} for more sophisticated URL slug generation with accent removal\n * @see {@link toKebabCase} for case conversion to kebab-case\n */\nexport const sanitizeString = (instr: string | null): string => {\n if (!instr) return ''\n return addDash(instr.replace(/[^a-zA-Z0-9 ]/g, '')).toLowerCase()\n}\n\nfunction addDash(str: string): string {\n const str2 = str.replace(/[`~!@#$%^&*()_|+\\-=?;:'\",.<>{}[\\]\\\\/]/gi, '')\n return str2.replace(/ /g, '-')\n}\n\n/**\n * Removes JSON-like characters and HTML entities from a string\n * @param texto Input string to clean\n * @returns String with JSON characters and HTML entities removed\n */\nexport const cleanJsonChars = (texto: string | null): string => {\n if (!texto) return ''\n return texto.replace(/({|}|&|amp;|gt;)/g, '')\n}\n\n/**\n * Truncates a string to a specified maximum length with optional suffix\n *\n * Shortens long strings for display in UI components, tables, previews, and tooltips.\n * Preserves readability while fitting space constraints.\n *\n * Behavior:\n * - If string length ≤ maxlength: returns original string unchanged\n * - If string length > maxlength: returns `str.substring(0, maxlength) + suffix`\n * - Suffix is included in addition to maxlength (not counted within limit)\n * - Null/empty strings return empty string\n *\n * @param str - String to truncate (null/empty returns '')\n * @param maxlength - Maximum length before truncation (default: 80 characters)\n * @param suffix - Suffix to append when truncated (default: '...')\n * @returns Truncated string with suffix if needed, original string if shorter\n *\n * @example\n * ```typescript\n * // Basic truncation (default 80 chars)\n * truncateString('Short text') // 'Short text' (no truncation)\n *\n * const long = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'\n * truncateString(long, 20) // 'Lorem ipsum dolor si...' (20 + 3 = 23 chars total)\n *\n * // Custom max length\n * truncateString('Hello World', 5) // 'Hello...'\n * truncateString('Hello World', 11) // 'Hello World' (no truncation)\n *\n * // Custom suffix\n * truncateString('Long text here', 8, '…') // 'Long tex…'\n * truncateString('Long text here', 8, ' [more]') // 'Long tex [more]'\n * truncateString('Long text here', 8, '') // 'Long tex' (no suffix)\n *\n * // Edge cases\n * truncateString('', 10) // ''\n * truncateString(null as any, 10) // '' (graceful handling)\n * truncateString('Hi', 0) // '...' (edge case: 0 maxlength)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Truncate product descriptions in table\n * const products = [\n * { name: 'Laptop', description: 'High-performance laptop with 16GB RAM and 512GB SSD' },\n * { name: 'Mouse', description: 'Wireless ergonomic mouse' }\n * ]\n *\n * products.forEach(p => {\n * console.log(`${p.name}: ${truncateString(p.description, 30)}`)\n * })\n * // Output:\n * // Laptop: High-performance laptop with 1...\n * // Mouse: Wireless ergonomic mouse\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Truncate user comments for preview\n * function renderCommentPreview(comment: string): string {\n * return `<div class=\"preview\">${truncateString(comment, 100)}</div>`\n * }\n *\n * renderCommentPreview('This is a very long comment that needs to be shortened for display...')\n * // '<div class=\"preview\">This is a very long comment that needs to be shortened for display in the UI without taking too m...</div>'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Email subject line truncation\n * function formatEmailSubject(subject: string): string {\n * // Gmail displays ~60 chars on desktop\n * return truncateString(subject, 60, '…')\n * }\n *\n * formatEmailSubject('Re: Important meeting about Q4 planning and budget review')\n * // 'Re: Important meeting about Q4 planning and budget review' (fits)\n *\n * formatEmailSubject('Re: [URGENT] Critical system outage affecting all production servers and databases')\n * // 'Re: [URGENT] Critical system outage affecting all production…'\n * ```\n *\n * @see {@link isEmpty} for checking empty strings\n */\nexport const truncateString = (str: string, maxlength = 80, suffix = '...'): string => {\n if (!str) return ''\n return str.length > maxlength ? str.substring(0, maxlength) + suffix : str\n}\n\n/**\n * Converts Unicode escape sequences to their actual characters\n * @param input String containing Unicode escape sequences\n * @returns String with escape sequences converted to actual characters\n */\nexport const unescapeUnicode = (input: string): string => {\n return JSON.stringify(JSON.parse(`\"${input}\"`)).replace(/^\"(.*)\"$/, '$1')\n}\n\n/**\n * Ensures a string ends with a specific suffix, adding it if not present\n * @param str Input string to check\n * @param trailing Suffix string to ensure is present at the end\n * @returns String guaranteed to end with the trailing string\n */\nexport const ensureEndsWith = (str: string, trailing: string): string => {\n return str.endsWith(trailing) ? str : `${str}${trailing}`\n}\n\n/**\n * Removes a specific suffix from the end of a string if present\n * @param str Input string to process\n * @param trailing Suffix string to remove from the end\n * @returns String with trailing suffix removed, original if suffix not found\n */\nexport const stripFromEnd = (str: string, trailing: string): string => {\n return str.endsWith(trailing) ? str.slice(0, -1 * trailing.length) : str\n}\n\n/**\n * Ensures a string starts with a specific prefix, adding it if not present\n * @param str Input string to check\n * @param leading Prefix string to ensure is present at the start\n * @returns String guaranteed to start with the leading string\n */\nexport const ensureStartsWith = (str: string, leading: string): string => {\n return str.startsWith(leading) ? str : `${leading}${str}`\n}\n\n/**\n * Removes a specific prefix from the start of a string if present\n * @param str Input string to process\n * @param leading Prefix string to remove from the start\n * @returns String with leading prefix removed, original if prefix not found\n */\nexport const stripFromStart = (str: string, leading: string): string => {\n return str.startsWith(leading) ? str.slice(leading.length) : str\n}\n\n/**\n * Converts all characters in a string to lowercase\n * @param str Input string to convert\n * @returns String with all characters in lowercase\n */\nexport const toLowerCase = (str: string): string => {\n return str.toLowerCase()\n}\n\n/**\n * Converts all characters in a string to uppercase\n * @param str Input string to convert\n * @returns String with all characters in uppercase\n */\nexport const toUpperCase = (str: string): string => {\n return str.toUpperCase()\n}\n\n/**\n * Capitalizes the first letter of a string and lowercases the rest\n * @param str Input string to capitalize\n * @returns String with first letter capitalized and rest in lowercase\n */\nexport const capitalizeFirst = (str: string): string => {\n if (!str) return ''\n return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase()\n}\n\n/**\n * Capitalizes the first letter of each word in a string\n * @param str Input string with words separated by spaces\n * @returns String with each word's first letter capitalized\n */\nexport const capitalizeEachWord = (str: string): string => {\n if (!str) return ''\n return str\n .split(' ')\n .map(word => capitalizeFirst(word))\n .join(' ')\n}\n\n/**\n * Converts a string to camelCase format\n *\n * Transforms strings from any case convention (kebab-case, snake_case, PascalCase, spaces)\n * to camelCase following JavaScript/TypeScript naming conventions.\n *\n * Algorithm:\n * 1. Detect word boundaries (spaces, hyphens, underscores, case transitions)\n * 2. Split into words and normalize to lowercase\n * 3. First word: keep lowercase\n * 4. Remaining words: capitalize first letter\n * 5. Join without separators\n *\n * Format: `firstWordSecondWordThirdWord`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in camelCase format\n *\n * @example\n * ```typescript\n * // From kebab-case\n * toCamelCase('hello-world') // 'helloWorld'\n * toCamelCase('user-profile-page') // 'userProfilePage'\n *\n * // From snake_case\n * toCamelCase('hello_world') // 'helloWorld'\n * toCamelCase('user_first_name') // 'userFirstName'\n *\n * // From PascalCase\n * toCamelCase('HelloWorld') // 'helloWorld'\n * toCamelCase('UserProfile') // 'userProfile'\n *\n * // From space-separated\n * toCamelCase('hello world') // 'helloWorld'\n * toCamelCase('First Name') // 'firstName'\n *\n * // Mixed formats\n * toCamelCase('hello-World_test') // 'helloWorldTest'\n * toCamelCase('API_Response-data') // 'apiResponseData'\n *\n * // Edge cases\n * toCamelCase('') // ''\n * toCamelCase('a') // 'a'\n * toCamelCase('UPPERCASE') // 'uppercase'\n * toCamelCase('123-test') // '123Test'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert database column names to JS properties\n * const dbColumns = ['user_id', 'first_name', 'last_name', 'created_at']\n *\n * const jsProperties = dbColumns.map(toCamelCase)\n * console.log(jsProperties)\n * // ['userId', 'firstName', 'lastName', 'createdAt']\n *\n * // Transform database row to JS object\n * function transformRow(row: Record<string, any>): Record<string, any> {\n * return Object.fromEntries(\n * Object.entries(row).map(([key, value]) => [toCamelCase(key), value])\n * )\n * }\n *\n * transformRow({ user_id: 123, first_name: 'Alice' })\n * // { userId: 123, firstName: 'Alice' }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert CSS property names to JS style properties\n * const cssProperties = [\n * 'background-color',\n * 'font-size',\n * 'margin-top',\n * 'border-bottom-width'\n * ]\n *\n * cssProperties.forEach(prop => {\n * const jsProp = toCamelCase(prop)\n * console.log(`${prop} → ${jsProp}`)\n * })\n * // background-color → backgroundColor\n * // font-size → fontSize\n * // margin-top → marginTop\n * // border-bottom-width → borderBottomWidth\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: API response transformation\n * interface ApiUser {\n * user_id: number\n * first_name: string\n * last_name: string\n * created_at: string\n * }\n *\n * function transformApiResponse(apiData: ApiUser) {\n * return {\n * userId: apiData.user_id,\n * firstName: apiData.first_name,\n * lastName: apiData.last_name,\n * createdAt: new Date(apiData.created_at)\n * }\n * }\n *\n * // Or generically:\n * function autoTransformKeys<T extends Record<string, any>>(obj: T) {\n * return Object.fromEntries(\n * Object.entries(obj).map(([k, v]) => [toCamelCase(k), v])\n * )\n * }\n * ```\n *\n * @see {@link toPascalCase} for PascalCase conversion (first letter uppercase)\n * @see {@link toSnakeCase} for snake_case conversion\n * @see {@link toKebabCase} for kebab-case conversion\n */\nexport const toCamelCase = (str: string): string => {\n if (!str) return ''\n\n // Split by word boundaries (spaces, hyphens, underscores, camelCase boundaries)\n const words = str\n .replace(/([a-z])([A-Z])/g, '$1 $2') // Split camelCase\n .split(/[-_\\s]+/) // Split by separators\n .filter(word => word.length > 0)\n .map(word => word.toLowerCase())\n\n if (words.length === 0) return ''\n\n // First word lowercase, rest capitalize first letter\n return (\n words[0] +\n words\n .slice(1)\n .map(word => word.charAt(0).toUpperCase() + word.slice(1))\n .join('')\n )\n}\n\n/**\n * Converts a string to snake_case format\n *\n * Transforms strings from any case convention to snake_case, commonly used in\n * Python, Ruby, database column names, and environment variables.\n *\n * Algorithm:\n * 1. Replace non-word characters with spaces\n * 2. Split on spaces and camelCase boundaries\n * 3. Convert all words to lowercase\n * 4. Join with underscores\n *\n * Format: `first_word_second_word_third_word`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in snake_case format\n *\n * @example\n * ```typescript\n * // From camelCase\n * toSnakeCase('helloWorld') // 'hello_world'\n * toSnakeCase('userFirstName') // 'user_first_name'\n *\n * // From PascalCase\n * toSnakeCase('HelloWorld') // 'hello_world'\n * toSnakeCase('UserProfile') // 'user_profile'\n *\n * // From kebab-case\n * toSnakeCase('hello-world') // 'hello_world'\n * toSnakeCase('user-profile-page') // 'user_profile_page'\n *\n * // From space-separated\n * toSnakeCase('hello world') // 'hello_world'\n * toSnakeCase('First Name') // 'first_name'\n *\n * // Mixed formats\n * toSnakeCase('helloWorld-test') // 'hello_world_test'\n * toSnakeCase('APIResponse') // 'a_p_i_response'\n *\n * // Edge cases\n * toSnakeCase('') // ''\n * toSnakeCase('a') // 'a'\n * toSnakeCase('UPPERCASE') // 'u_p_p_e_r_c_a_s_e'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert JS properties to database column names\n * const jsObject = {\n * userId: 123,\n * firstName: 'Alice',\n * lastName: 'Smith',\n * createdAt: new Date()\n * }\n *\n * const dbColumns = Object.keys(jsObject).map(toSnakeCase)\n * console.log(dbColumns)\n * // ['user_id', 'first_name', 'last_name', 'created_at']\n *\n * // Generate SQL INSERT statement\n * const columns = Object.keys(jsObject).map(toSnakeCase).join(', ')\n * const sql = `INSERT INTO users (${columns}) VALUES (?)`\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Environment variable generation\n * const configKeys = ['databaseHost', 'databasePort', 'apiBaseUrl']\n *\n * configKeys.forEach(key => {\n * const envVar = toSnakeCase(key).toUpperCase()\n * console.log(`${envVar}=value`)\n * })\n * // DATABASE_HOST=value\n * // DATABASE_PORT=value\n * // API_BASE_URL=value\n * ```\n *\n * @see {@link toCamelCase} for camelCase conversion\n * @see {@link toKebabCase} for kebab-case conversion\n * @see {@link toPascalCase} for PascalCase conversion\n */\nexport const toSnakeCase = (str: string): string => {\n if (!str) return ''\n return str\n .replace(/\\W+/g, ' ')\n .split(/ |\\B(?=[A-Z])/)\n .map(word => word.toLowerCase())\n .join('_')\n}\n\n/**\n * Converts a string to kebab-case format\n *\n * Transforms strings from any case convention to kebab-case (also called dash-case or hyphen-case).\n * Widely used in URLs, HTML attributes, CSS classes, and file names.\n *\n * Algorithm:\n * 1. Replace underscores and spaces with hyphens\n * 2. Insert hyphens before uppercase letters (handle camelCase)\n * 3. Convert all to lowercase\n * 4. Remove non-alphanumeric characters (except hyphens)\n * 5. Collapse multiple consecutive hyphens\n * 6. Remove leading/trailing hyphens\n *\n * Format: `first-word-second-word-third-word`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in kebab-case format\n *\n * @example\n * ```typescript\n * // From camelCase\n * toKebabCase('helloWorld') // 'hello-world'\n * toKebabCase('userFirstName') // 'user-first-name'\n *\n * // From PascalCase\n * toKebabCase('HelloWorld') // 'hello-world'\n * toKebabCase('UserProfile') // 'user-profile'\n *\n * // From snake_case\n * toKebabCase('hello_world') // 'hello-world'\n * toKebabCase('user_first_name') // 'user-first-name'\n *\n * // From space-separated\n * toKebabCase('hello world') // 'hello-world'\n * toKebabCase('First Name') // 'first-name'\n *\n * // Mixed formats\n * toKebabCase('helloWorld_test') // 'hello-world-test'\n * toKebabCase('API-Response') // 'api-response'\n *\n * // Edge cases\n * toKebabCase('') // ''\n * toKebabCase('a') // 'a'\n * toKebabCase('UPPERCASE') // 'uppercase'\n * toKebabCase('123Test') // '123-test'\n * toKebabCase('--multiple--dashes--') // 'multiple-dashes'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate URL slugs from page titles\n * const pageTitle = 'My Awesome Blog Post'\n * const urlSlug = toKebabCase(pageTitle)\n * const url = `https://example.com/blog/${urlSlug}`\n * // https://example.com/blog/my-awesome-blog-post\n *\n * // Multiple pages\n * const pages = [\n * { title: 'Getting Started', component: 'GettingStarted' },\n * { title: 'API Reference', component: 'ApiReference' },\n * { title: 'Best Practices', component: 'BestPractices' }\n * ]\n *\n * const routes = pages.map(p => ({\n * path: `/${toKebabCase(p.title)}`,\n * component: p.component\n * }))\n * // [\n * // { path: '/getting-started', component: 'GettingStarted' },\n * // { path: '/api-reference', component: 'ApiReference' },\n * // { path: '/best-practices', component: 'BestPractices' }\n * // ]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: CSS class name generation\n * function generateClassName(componentName: string, modifier?: string): string {\n * const base = `component-${toKebabCase(componentName)}`\n * return modifier ? `${base}--${toKebabCase(modifier)}` : base\n * }\n *\n * generateClassName('UserProfile') // 'component-user-profile'\n * generateClassName('UserProfile', 'isActive') // 'component-user-profile--is-active'\n * generateClassName('ButtonPrimary', 'largeSize') // 'component-button-primary--large-size'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: HTML attribute generation\n * function generateDataAttribute(key: string, value: string): string {\n * return `data-${toKebabCase(key)}=\"${value}\"`\n * }\n *\n * generateDataAttribute('userId', '123') // 'data-user-id=\"123\"'\n * generateDataAttribute('testEnvironment', 'staging') // 'data-test-environment=\"staging\"'\n * ```\n *\n * @see {@link toCamelCase} for camelCase conversion\n * @see {@link toSnakeCase} for snake_case conversion\n * @see {@link toPascalCase} for PascalCase conversion\n * @see {@link toUrlSlug} for URL-safe slug generation with accent removal\n */\nexport const toKebabCase = (str: string): string => {\n if (!str) return ''\n return str\n .replace(/[_\\s]+/g, '-')\n .replace(/([a-z0-9])([A-Z])/g, '$1-$2') // Handle numbers before capitals too\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n}\n\n/**\n * Converts a string to PascalCase format\n *\n * Transforms strings from any case convention to PascalCase (also called UpperCamelCase).\n * Commonly used for class names, component names, type names, and constructor functions\n * in JavaScript/TypeScript.\n *\n * Algorithm:\n * 1. Split on word boundaries (hyphens, underscores, spaces)\n * 2. Capitalize first letter of each word\n * 3. Join without separators\n * 4. Ensure first character is uppercase\n *\n * Format: `FirstWordSecondWordThirdWord`\n *\n * @param str - Input string in any case format (empty returns '')\n * @returns String in PascalCase format\n *\n * @example\n * ```typescript\n * // From camelCase\n * toPascalCase('helloWorld') // 'HelloWorld'\n * toPascalCase('userFirstName') // 'UserFirstName'\n *\n * // From kebab-case\n * toPascalCase('hello-world') // 'HelloWorld'\n * toPascalCase('user-profile-page') // 'UserProfilePage'\n *\n * // From snake_case\n * toPascalCase('hello_world') // 'HelloWorld'\n * toPascalCase('user_first_name') // 'UserFirstName'\n *\n * // From space-separated\n * toPascalCase('hello world') // 'HelloWorld'\n * toPascalCase('first name') // 'FirstName'\n *\n * // Mixed formats\n * toPascalCase('hello-World_test') // 'HelloWorldTest'\n * toPascalCase('api_response-data') // 'ApiResponseData'\n *\n * // Edge cases\n * toPascalCase('') // ''\n * toPascalCase('a') // 'A'\n * toPascalCase('UPPERCASE') // 'UPPERCASE'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate React component names\n * const componentNames = ['user-profile', 'navigation-bar', 'footer-links']\n *\n * componentNames.forEach(name => {\n * const pascalName = toPascalCase(name)\n * console.log(`export function ${pascalName}() { ... }`)\n * })\n * // export function UserProfile() { ... }\n * // export function NavigationBar() { ... }\n * // export function FooterLinks() { ... }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: TypeScript type name generation\n * interface GenerateTypeOptions {\n * name: string\n * fields: Array<{ name: string; type: string }>\n * }\n *\n * function generateTypeDefinition(options: GenerateTypeOptions): string {\n * const typeName = toPascalCase(options.name)\n * const fields = options.fields\n * .map(f => ` ${f.name}: ${f.type}`)\n * .join('\\n')\n *\n * return `interface ${typeName} {\\n${fields}\\n}`\n * }\n *\n * generateTypeDefinition({\n * name: 'user-profile',\n * fields: [\n * { name: 'userId', type: 'number' },\n * { name: 'name', type: 'string' }\n * ]\n * })\n * // interface UserProfile {\n * // userId: number\n * // name: string\n * // }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Class name generation for dynamic imports\n * async function loadService(serviceName: string) {\n * const className = toPascalCase(serviceName)\n * const module = await import(`./services/${serviceName}`)\n * return new module[className]()\n * }\n *\n * await loadService('user-service') // new UserService()\n * await loadService('payment-gateway') // new PaymentGateway()\n * ```\n *\n * @see {@link toCamelCase} for camelCase conversion (first letter lowercase)\n * @see {@link toSnakeCase} for snake_case conversion\n * @see {@link toKebabCase} for kebab-case conversion\n */\nexport const toPascalCase = (str: string): string => {\n if (!str) return ''\n return str\n .replace(/[-_\\s]+(.)?/g, (_, char) => (char ? char.toUpperCase() : ''))\n .replace(/^./, char => char.toUpperCase())\n}\n\n/**\n * Checks if a string contains another string with optional case sensitivity\n * @param str String to search within\n * @param searchStr Substring to search for\n * @param caseSensitive Whether to perform case-sensitive search (default: false)\n * @returns True if the string contains the search string, false otherwise\n */\nexport const contains = (str: string, searchStr: string, caseSensitive = false): boolean => {\n if (caseSensitive) {\n return str.includes(searchStr)\n }\n return str.toLowerCase().includes(searchStr.toLowerCase())\n}\n\n/**\n * Checks if a string starts with another string with optional case sensitivity\n * @param str String to check\n * @param searchStr Prefix to search for\n * @param caseSensitive Whether to perform case-sensitive search (default: false)\n * @returns True if the string starts with the search string, false otherwise\n */\nexport const startsWith = (str: string, searchStr: string, caseSensitive = false): boolean => {\n if (caseSensitive) {\n return str.startsWith(searchStr)\n }\n return str.toLowerCase().startsWith(searchStr.toLowerCase())\n}\n\n/**\n * Checks if a string ends with another string with optional case sensitivity\n * @param str String to check\n * @param searchStr Suffix to search for\n * @param caseSensitive Whether to perform case-sensitive search (default: false)\n * @returns True if the string ends with the search string, false otherwise\n */\nexport const endsWith = (str: string, searchStr: string, caseSensitive = false): boolean => {\n if (caseSensitive) {\n return str.endsWith(searchStr)\n }\n return str.toLowerCase().endsWith(searchStr.toLowerCase())\n}\n\n/**\n * Pads a string at the start (left) with a specific character to reach target length\n * @param str String to pad\n * @param length Target length for the resulting string\n * @param padChar Character to use for padding (default: space)\n * @returns String padded to target length, original if already longer\n */\nexport const padStart = (str: string, length: number, padChar = ' '): string => {\n return str.padStart(length, padChar)\n}\n\n/**\n * Pads a string at the end (right) with a specific character to reach target length\n * @param str String to pad\n * @param length Target length for the resulting string\n * @param padChar Character to use for padding (default: space)\n * @returns String padded to target length, original if already longer\n */\nexport const padEnd = (str: string, length: number, padChar = ' '): string => {\n if (str.length >= length) return str\n return str + padChar.repeat(length - str.length)\n}\n\n/**\n * Removes leading and trailing whitespace from a string\n * @param str String to trim\n * @returns String with leading and trailing whitespace removed\n */\nexport const trim = (str: string): string => {\n return str.trim()\n}\n\n/**\n * Removes leading (start) whitespace from a string\n * @param str String to trim\n * @returns String with leading whitespace removed\n */\nexport const trimStart = (str: string): string => {\n return str.trimStart()\n}\n\n/**\n * Removes trailing (end) whitespace from a string\n * @param str String to trim\n * @returns String with trailing whitespace removed\n */\nexport const trimEnd = (str: string): string => {\n return str.trimEnd()\n}\n\n/**\n * Reverses the character order in a string\n * @param str String to reverse\n * @returns String with characters in reverse order\n */\nexport const reverseString = (str: string): string => {\n return str.split('').reverse().join('')\n}\n\n/**\n * Repeats a string a specified number of times\n * @param str String to repeat\n * @param times Number of times to repeat the string\n * @returns String repeated the specified number of times\n */\nexport const repeatString = (str: string, times: number): string => {\n return str.repeat(times)\n}\n\n/**\n * Replaces all occurrences of a substring with a replacement string\n * @param str String to search in\n * @param searchStr Substring to find and replace\n * @param replaceStr String to replace each occurrence with\n * @returns String with all occurrences replaced\n */\nexport const replaceAllOccurrences = (\n str: string,\n searchStr: string,\n replaceStr: string\n): string => {\n return str.split(searchStr).join(replaceStr)\n}\n\n/**\n * Counts the number of occurrences of a substring within a string\n * @param str String to search within\n * @param searchStr Substring to count occurrences of\n * @returns Number of times the substring appears in the string\n */\nexport const countOccurrences = (str: string, searchStr: string): number => {\n if (!searchStr) return 0\n let count = 0\n let position = 0\n\n while ((position = str.indexOf(searchStr, position)) !== -1) {\n count++\n position += 1 // Move only 1 position to allow overlapping matches\n }\n\n return count\n}\n\n/**\n * Checks if a string is empty, null, undefined, or contains only whitespace\n * @param str String to check (can be null or undefined)\n * @returns True if string is empty/null/undefined or only whitespace, false otherwise\n */\nexport const isEmpty = (str: string | null | undefined): boolean => {\n return !str || str.trim().length === 0\n}\n\n/**\n * Validates if a string is a properly formatted email address\n * @param str String to validate as email\n * @returns True if string matches email format, false otherwise\n */\nexport const isEmail = (str: string): boolean => {\n const re =\n /^(([^<>()[\\]\\\\.,;:\\s@\"]+(\\.[^<>()[\\]\\\\.,;:\\s@\"]+)*)|(\".+\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])|(([a-zA-Z\\-0-9]+\\.)+[a-zA-Z]{2,}))$/\n return re.test(str.toLowerCase())\n}\n\n/**\n * Generates a URL-friendly slug from a string\n *\n * Creates clean, SEO-friendly URL slugs by normalizing strings for use in web addresses.\n * Removes special characters, normalizes whitespace, and converts to lowercase with hyphens.\n *\n * Algorithm:\n * 1. Convert to lowercase\n * 2. Trim leading/trailing whitespace\n * 3. Remove non-word characters (except spaces, hyphens, underscores)\n * 4. Replace spaces/underscores/multiple-hyphens with single hyphen\n * 5. Remove leading/trailing hyphens\n *\n * Format: `url-friendly-slug-text`\n *\n * ⚠️ NOTE: Does NOT remove accents. For accent removal, use {@link removeAccents} first.\n *\n * @param str - String to convert to URL slug (special chars removed)\n * @returns URL-friendly slug string in lowercase with hyphens\n *\n * @example\n * ```typescript\n * // Basic slug generation\n * toUrlSlug('Hello World') // 'hello-world'\n * toUrlSlug('My Blog Post Title') // 'my-blog-post-title'\n *\n * // Remove special characters\n * toUrlSlug('User: John Doe!') // 'user-john-doe'\n * toUrlSlug('Price: $19.99') // 'price-1999'\n * toUrlSlug('Hello @ World #2024') // 'hello-world-2024'\n *\n * // Normalize whitespace and separators\n * toUrlSlug('hello world') // 'hello-world'\n * toUrlSlug('hello_world_test') // 'hello-world-test'\n * toUrlSlug('---multiple---dashes---') // 'multiple-dashes'\n *\n * // Preserve numbers and hyphens\n * toUrlSlug('Article 123') // 'article-123'\n * toUrlSlug('ES6-Features') // 'es6-features'\n *\n * // Edge cases\n * toUrlSlug('') // ''\n * toUrlSlug(' ') // ''\n * toUrlSlug('123') // '123'\n * toUrlSlug('a-b-c') // 'a-b-c'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate blog post URL from title\n * function createBlogPostUrl(title: string, id: number): string {\n * const slug = toUrlSlug(title)\n * return `/blog/${id}/${slug}`\n * }\n *\n * createBlogPostUrl('10 Tips for TypeScript', 42)\n * // '/blog/42/10-tips-for-typescript'\n *\n * createBlogPostUrl('Getting Started with React!', 1)\n * // '/blog/1/getting-started-with-react'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate product URLs for e-commerce\n * interface Product {\n * id: string\n * name: string\n * category: string\n * }\n *\n * function getProductUrl(product: Product): string {\n * const categorySlug = toUrlSlug(product.category)\n * const nameSlug = toUrlSlug(product.name)\n * return `/products/${categorySlug}/${product.id}/${nameSlug}`\n * }\n *\n * getProductUrl({\n * id: 'SKU-123',\n * name: 'Wireless Mouse (Ergonomic)',\n * category: 'Computer Accessories'\n * })\n * // '/products/computer-accessories/SKU-123/wireless-mouse-ergonomic'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: SEO-friendly URLs with accent handling\n * function createSeoUrl(title: string): string {\n * // Remove accents BEFORE slug generation for better URL compatibility\n * return toUrlSlug(removeAccents(title))\n * }\n *\n * createSeoUrl('Café Münchën 2024')\n * // 'cafe-munchen-2024' (accents removed)\n *\n * // Without accent removal:\n * toUrlSlug('Café Münchën 2024')\n * // 'caf-mnchen-2024' (accents become invalid chars, get removed)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate unique slugs for duplicate titles\n * const existingSlugs = new Set(['hello-world', 'hello-world-1'])\n *\n * function generateUniqueSlug(title: string): string {\n * let slug = toUrlSlug(title)\n * let counter = 1\n *\n * while (existingSlugs.has(slug)) {\n * slug = `${toUrlSlug(title)}-${counter}`\n * counter++\n * }\n *\n * existingSlugs.add(slug)\n * return slug\n * }\n *\n * generateUniqueSlug('Hello World') // 'hello-world-2' (avoiding existing)\n * generateUniqueSlug('New Article') // 'new-article'\n * ```\n *\n * @see {@link toKebabCase} for case conversion to kebab-case\n * @see {@link removeAccents} for removing accents before slug generation\n * @see {@link sanitizeString} for basic string sanitization\n */\nexport const toUrlSlug = (str: string): string => {\n return str\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\n/**\n * Removes accents and diacritical marks from characters in a string\n *\n * Uses Unicode normalization (NFD) to decompose accented characters, then removes\n * combining diacritical marks. Essential for search, sorting, URL slugs, and ASCII compatibility.\n *\n * Algorithm:\n * 1. Normalize string to NFD (Normalization Form Decomposed)\n * 2. Remove Unicode combining diacritical marks (U+0300–U+036F)\n * 3. Return ASCII-compatible base characters\n *\n * Supported diacritics: acute (´), grave (`), circumflex (^), tilde (~), umlaut (¨),\n * cedilla (¸), and many more.\n *\n * @param str - String containing accented characters (e.g., 'café', 'Münchën')\n * @returns String with accents removed to base ASCII characters (e.g., 'cafe', 'Munchen')\n *\n * @example\n * ```typescript\n * // Basic accent removal - Romance languages\n * removeAccents('café') // 'cafe'\n * removeAccents('naïve') // 'naive'\n * removeAccents('résumé') // 'resume'\n * removeAccents('à côté') // 'a cote'\n *\n * // Spanish accents\n * removeAccents('Español') // 'Espanol'\n * removeAccents('niño') // 'nino'\n * removeAccents('José María') // 'Jose Maria'\n *\n * // German umlauts\n * removeAccents('Münchën') // 'Munchen'\n * removeAccents('Köln') // 'Koln'\n * removeAccents('Zürich') // 'Zurich'\n *\n * // Portuguese\n * removeAccents('São Paulo') // 'Sao Paulo'\n * removeAccents('Brasília') // 'Brasilia'\n *\n * // French\n * removeAccents('Côte d'Ivoire') // 'Cote d'Ivoire'\n * removeAccents('Françoise') // 'Francoise'\n *\n * // Mixed\n * removeAccents('Crème brûlée') // 'Creme brulee'\n * removeAccents('Åre, Malmö') // 'Are, Malmo'\n *\n * // Edge cases\n * removeAccents('') // ''\n * removeAccents('ASCII text') // 'ASCII text' (unchanged)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Search normalization (case + accent insensitive)\n * function normalizeForSearch(text: string): string {\n * return removeAccents(text.toLowerCase().trim())\n * }\n *\n * const searchQuery = normalizeForSearch('Café') // 'cafe'\n * const productName = normalizeForSearch('CAFÉ PREMIUM') // 'cafe premium'\n *\n * if (productName.includes(searchQuery)) {\n * console.log('Match found!')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate SEO-friendly URLs\n * function createSeoUrl(title: string): string {\n * return toUrlSlug(removeAccents(title))\n * }\n *\n * createSeoUrl('Guía de Español')\n * // 'guia-de-espanol'\n *\n * createSeoUrl('Café Münchën 2024')\n * // 'cafe-munchen-2024'\n *\n * createSeoUrl('São Paulo: Best Restaurants')\n * // 'sao-paulo-best-restaurants'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sort names alphabetically (accent-insensitive)\n * const names = ['Álvarez', 'Andersen', 'Ängel', 'Adams']\n *\n * const sorted = names.sort((a, b) =>\n * removeAccents(a).localeCompare(removeAccents(b))\n * )\n * // ['Adams', 'Álvarez', 'Andersen', 'Ängel']\n * // (sorted by: Adams, Alvarez, Andersen, Angel)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Filename sanitization\n * function sanitizeFilename(filename: string): string {\n * // Remove accents, then sanitize\n * const withoutAccents = removeAccents(filename)\n * return sanitizeString(withoutAccents)\n * }\n *\n * sanitizeFilename('Presentación_2024.pdf')\n * // 'presentacion-2024pdf'\n *\n * sanitizeFilename('Föräldrar & Barn.docx')\n * // 'foraldrar-barn-docx'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Email address generation\n * function generateEmail(firstName: string, lastName: string): string {\n * const first = removeAccents(firstName.toLowerCase())\n * const last = removeAccents(lastName.toLowerCase())\n * return `${first}.${last}@company.com`\n * }\n *\n * generateEmail('José', 'García')\n * // 'jose.garcia@company.com'\n *\n * generateEmail('François', 'Müller')\n * // 'francois.muller@company.com'\n * ```\n *\n * @see {@link toUrlSlug} for URL slug generation (combine with removeAccents for best results)\n * @see {@link sanitizeString} for string sanitization\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize String.normalize() Documentation}\n */\nexport const removeAccents = (str: string): string => {\n return str.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '')\n}\n\n/**\n * Escapes HTML special characters to prevent XSS and display issues\n *\n * Converts dangerous HTML characters to their HTML entity equivalents, preventing\n * script injection (XSS) and ensuring proper text display in HTML contexts.\n *\n * Escaped characters:\n * - `&` → `&` (must be first to avoid double-escaping)\n * - `<` → `<` (prevents opening tags)\n * - `>` → `>` (prevents closing tags)\n * - `\"` → `"` (prevents attribute injection)\n * - `'` → `'` (prevents attribute injection)\n *\n * ⚠️ SECURITY WARNING: This provides basic XSS protection but is NOT a complete solution.\n * For production HTML sanitization, use DOMPurify or similar dedicated libraries.\n * This function is safe for:\n * - Displaying user input as plain text in HTML\n * - Escaping attribute values in HTML\n * - Simple content rendering\n *\n * NOT sufficient for:\n * - Rich HTML content (use DOMPurify)\n * - JavaScript context (use different escaping)\n * - URL context (use encodeURIComponent)\n * - CSS context (use CSS-specific escaping)\n *\n * @param str - String containing HTML characters to escape\n * @returns String with HTML characters safely escaped as HTML entities\n *\n * @example\n * ```typescript\n * // Basic escaping\n * escapeHtmlChars('<script>alert(\"XSS\")</script>')\n * // '<script>alert("XSS")</script>'\n *\n * escapeHtmlChars('5 < 10 & 10 > 5')\n * // '5 < 10 & 10 > 5'\n *\n * escapeHtmlChars('Say \"Hello\" & \\'Goodbye\\'')\n * // 'Say "Hello" & 'Goodbye''\n *\n * // Edge cases\n * escapeHtmlChars('') // ''\n * escapeHtmlChars('No special chars') // 'No special chars'\n * escapeHtmlChars('<') // '&lt;' (escapes already-escaped)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Safely display user comments in HTML\n * interface Comment {\n * author: string\n * content: string\n * }\n *\n * function renderComment(comment: Comment): string {\n * const safeAuthor = escapeHtmlChars(comment.author)\n * const safeContent = escapeHtmlChars(comment.content)\n *\n * return `\n * <div class=\"comment\">\n * <strong>${safeAuthor}</strong>\n * <p>${safeContent}</p>\n * </div>\n * `\n * }\n *\n * renderComment({\n * author: '<script>alert(\"XSS\")</script>',\n * content: 'Great post! <3'\n * })\n * // Safe HTML output with escaped tags\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate safe HTML attributes\n * function generateDataAttribute(key: string, value: string): string {\n * const safeKey = toKebabCase(key)\n * const safeValue = escapeHtmlChars(value)\n * return `data-${safeKey}=\"${safeValue}\"`\n * }\n *\n * generateDataAttribute('userInput', '<script>alert(1)</script>')\n * // 'data-user-input=\"<script>alert(1)</script>\"'\n *\n * generateDataAttribute('description', 'Product \"Premium\" & more')\n * // 'data-description=\"Product "Premium" & more\"'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Escape user search query for display\n * function displaySearchResults(query: string, results: any[]): string {\n * const safeQuery = escapeHtmlChars(query)\n *\n * return `\n * <div class=\"search-results\">\n * <h2>Results for: ${safeQuery}</h2>\n * <p>${results.length} results found</p>\n * </div>\n * `\n * }\n *\n * displaySearchResults('<img src=x onerror=alert(1)>', [])\n * // Safe display: \"Results for: <img src=x onerror=alert(1)>\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: CSV to HTML table with safe content\n * function csvRowToHtmlRow(cells: string[]): string {\n * const safeCells = cells.map(cell => escapeHtmlChars(cell))\n * const tdElements = safeCells.map(cell => `<td>${cell}</td>`).join('')\n * return `<tr>${tdElements}</tr>`\n * }\n *\n * csvRowToHtmlRow(['Alice', '<script>evil</script>', '25'])\n * // '<tr><td>Alice</td><td><script>evil</script></td><td>25</td></tr>'\n * ```\n *\n * @example\n * ```typescript\n * // Edge case: Preventing double-escaping\n * const userInput = 'Hello & Goodbye'\n * const escaped = escapeHtmlChars(userInput)\n * // 'Hello & Goodbye'\n *\n * const doubleEscaped = escapeHtmlChars(escaped)\n * // 'Hello &amp; Goodbye' ⚠️ Over-escaped!\n *\n * // Solution: Only escape once, track escaped state\n * interface SafeString {\n * value: string\n * isEscaped: boolean\n * }\n *\n * function safeEscape(str: string | SafeString): SafeString {\n * if (typeof str === 'object' && str.isEscaped) {\n * return str\n * }\n * const value = typeof str === 'string' ? str : str.value\n * return { value: escapeHtmlChars(value), isEscaped: true }\n * }\n * ```\n *\n * @see {@link unescapeHtmlChars} for reversing HTML entity escaping\n * @see {@link sanitizeString} for basic string sanitization\n * @see {@link https://owasp.org/www-community/attacks/xss/ OWASP XSS Prevention Cheat Sheet}\n * @see {@link https://github.com/cure53/DOMPurify DOMPurify for production HTML sanitization}\n */\nexport const escapeHtmlChars = (str: string): string => {\n const htmlEscapes: { [key: string]: string } = {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": ''',\n }\n return str.replace(/[&<>\"']/g, match => htmlEscapes[match])\n}\n\n/**\n * Converts HTML entities back to their original characters\n * @param str String containing HTML entities to unescape\n * @returns String with HTML entities converted back to original characters\n */\nexport const unescapeHtmlChars = (str: string): string => {\n const htmlUnescapes: { [key: string]: string } = {\n '&': '&',\n '<': '<',\n '>': '>',\n '"': '\"',\n ''': \"'\",\n }\n return str.replace(/&|<|>|"|'/g, match => htmlUnescapes[match])\n}\n\n/**\n * Checks if a path matches a wildcard pattern using dot notation\n *\n * Supports wildcards (*) to match any segment at that position.\n * Useful for configuration paths, routing, permissions, and feature flags.\n *\n * @param path - Dot-notation path to test (e.g., 'features.auth.enabled')\n * @param pattern - Pattern with optional wildcards (e.g., 'features.*', 'features.*.enabled')\n * @returns True if path matches pattern, false otherwise\n *\n * @example\n * ```typescript\n * // Exact match\n * matchPathPattern('features.auth', 'features.auth') // true\n *\n * // Wildcard at end\n * matchPathPattern('features.auth', 'features.*') // true\n * matchPathPattern('features.payments', 'features.*') // true\n * matchPathPattern('other.value', 'features.*') // false\n *\n * // Wildcard in middle\n * matchPathPattern('features.auth.enabled', 'features.*.enabled') // true\n * matchPathPattern('features.payments.enabled', 'features.*.enabled') // true\n * matchPathPattern('features.auth.disabled', 'features.*.enabled') // false\n *\n * // Multiple wildcards\n * matchPathPattern('app.features.auth.oauth', 'app.*.*.oauth') // true\n * matchPathPattern('app.features.auth.saml', 'app.*.*.oauth') // false\n *\n * // No wildcard\n * matchPathPattern('exact.path.match', 'exact.path.match') // true\n * matchPathPattern('exact.path.nomatch', 'exact.path.match') // false\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Feature flag matching\n * const enabledFeatures = [\n * 'features.auth.oauth',\n * 'features.auth.saml',\n * 'features.payments.stripe',\n * ]\n *\n * const hasAuth = enabledFeatures.some(f =>\n * matchPathPattern(f, 'features.auth.*')\n * ) // true\n *\n * const hasPayments = enabledFeatures.some(f =>\n * matchPathPattern(f, 'features.payments.*')\n * ) // true\n *\n * // Permission matching\n * const userPermissions = ['admin.users.read', 'admin.users.write']\n * const canManageUsers = userPermissions.some(p =>\n * matchPathPattern(p, 'admin.users.*')\n * ) // true\n * ```\n */\nexport function matchPathPattern(path: string, pattern: string): boolean {\n if (!path || typeof path !== 'string' || !pattern || typeof pattern !== 'string') {\n return false\n }\n\n // Exact match\n if (path === pattern) {\n return true\n }\n\n // No wildcard in pattern\n if (!pattern.includes('*')) {\n return path === pattern\n }\n\n // Convert pattern to regex\n // Escape special regex characters except *\n const regexPattern = pattern\n .split('.')\n .map(segment => {\n if (segment === '*') {\n return '[^.]+'\n }\n // Escape special regex chars\n return segment.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n })\n .join('\\\\.')\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(path)\n}\n\n/**\n * Converts an environment variable key to dot-notation path\n *\n * Transforms uppercase underscore-separated env var names to lowercase\n * dot-notation paths. Optionally removes a prefix.\n *\n * Common convention: ENV_VAR_NAME → env.var.name\n *\n * @param envKey - Environment variable key (e.g., 'NX_FEATURES_AUTH', 'APP_DATABASE_HOST')\n * @param prefix - Optional prefix to remove (e.g., 'NX', 'APP'). Default: 'NX'\n * @returns Dot-notation path in lowercase\n *\n * @example\n * ```typescript\n * // Default prefix (NX)\n * envKeyToPath('NX_FEATURES_AUTH') // 'features.auth'\n * envKeyToPath('NX_FEATURES_PAYMENTS') // 'features.payments'\n * envKeyToPath('NX_DATABASE_HOST') // 'database.host'\n *\n * // Custom prefix\n * envKeyToPath('APP_DATABASE_HOST', 'APP') // 'database.host'\n * envKeyToPath('MY_CONFIG_VALUE', 'MY') // 'config.value'\n *\n * // No prefix\n * envKeyToPath('DATABASE_HOST', '') // 'database.host'\n * envKeyToPath('FEATURES_AUTH', '') // 'features.auth'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Parse environment variables to config object\n * const envVars = {\n * 'APP_DATABASE_HOST': 'localhost',\n * 'APP_DATABASE_PORT': '5432',\n * 'APP_CACHE_TTL': '3600',\n * }\n *\n * const config = {}\n * Object.entries(envVars).forEach(([key, value]) => {\n * const path = envKeyToPath(key, 'APP')\n * // Use with setDeepValue: setDeepValue(config, path, value)\n * })\n * // Paths: 'database.host', 'database.port', 'cache.ttl'\n * ```\n */\nexport function envKeyToPath(envKey: string, prefix: string = 'NX'): string {\n if (!envKey || typeof envKey !== 'string') {\n return ''\n }\n\n let key = envKey.trim()\n\n // Remove prefix if provided and matches\n if (prefix && key.startsWith(`${prefix}_`)) {\n key = key.substring(prefix.length + 1)\n }\n\n // Convert to lowercase and replace underscores with dots\n return key.toLowerCase().replace(/_/g, '.')\n}\n\n/**\n * Converts a dot-notation path to environment variable key format\n *\n * Transforms lowercase dot-notation paths to uppercase underscore-separated\n * env var names. Optionally adds a prefix.\n *\n * Common convention: env.var.name → ENV_VAR_NAME\n *\n * @param path - Dot-notation path (e.g., 'features.auth', 'database.host')\n * @param prefix - Optional prefix to add (e.g., 'NX', 'APP'). Default: 'NX'\n * @returns Environment variable key in uppercase\n *\n * @example\n * ```typescript\n * // Default prefix (NX)\n * pathToEnvKey('features.auth') // 'NX_FEATURES_AUTH'\n * pathToEnvKey('features.payments') // 'NX_FEATURES_PAYMENTS'\n * pathToEnvKey('database.host') // 'NX_DATABASE_HOST'\n *\n * // Custom prefix\n * pathToEnvKey('database.host', 'APP') // 'APP_DATABASE_HOST'\n * pathToEnvKey('config.value', 'MY') // 'MY_CONFIG_VALUE'\n *\n * // No prefix\n * pathToEnvKey('database.host', '') // 'DATABASE_HOST'\n * pathToEnvKey('features.auth', '') // 'FEATURES_AUTH'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate .env file from config object\n * const config = {\n * database: { host: 'localhost', port: 5432 },\n * cache: { ttl: 3600 }\n * }\n *\n * const envVars = [\n * `${pathToEnvKey('database.host', 'APP')}=localhost`,\n * `${pathToEnvKey('database.port', 'APP')}=5432`,\n * `${pathToEnvKey('cache.ttl', 'APP')}=3600`,\n * ]\n * // Output:\n * // APP_DATABASE_HOST=localhost\n * // APP_DATABASE_PORT=5432\n * // APP_CACHE_TTL=3600\n * ```\n */\nexport function pathToEnvKey(path: string, prefix: string = 'NX'): string {\n if (!path || typeof path !== 'string') {\n return ''\n }\n\n // Convert dots to underscores and uppercase\n const key = path.trim().toUpperCase().replace(/\\./g, '_')\n\n // Return empty if path was just whitespace\n if (key.length === 0) {\n return ''\n }\n\n // Add prefix if provided\n if (prefix && prefix.length > 0) {\n return `${prefix.toUpperCase()}_${key}`\n }\n\n return key\n}\n","/**\n * Object manipulation and comparison utilities\n * Consolidated from primitives/object and array modules\n */\n\nimport crc32 from 'crc/crc32'\nimport * as lodash from 'lodash'\nconst {\n isArray,\n isArrayBuffer,\n isBoolean,\n isBuffer,\n isEqual,\n isNil,\n isNumber,\n isObject,\n isPlainObject,\n isString,\n isTypedArray,\n transform,\n} = lodash\nimport fastEqual from 'fast-deep-equal'\nimport { areDatesEqualWithTolerance, isDateTime, toDate } from './dates'\n\n// Native implementations to replace lodash functions\nconst nativeFilter = <T>(array: T[], predicate: Partial<T>): T[] => {\n return array.filter(item => {\n return Object.keys(predicate).every(key => item[key as keyof T] === predicate[key as keyof T])\n })\n}\n\nconst nativeAssign = <T extends object>(target: T, source: Partial<T>): T => {\n return Object.assign(target, source)\n}\n\nconst nativePick = <T extends object, K extends keyof T>(object: T, keys: K[]): Pick<T, K> => {\n const result = {} as Pick<T, K>\n keys.forEach(key => {\n if (key in object) {\n result[key] = object[key]\n }\n })\n return result\n}\n\nconst nativeRemove = <T>(array: T[], predicate: (item: T) => boolean): T[] => {\n const removed: T[] = []\n for (let i = array.length - 1; i >= 0; i--) {\n if (predicate(array[i])) {\n removed.unshift(array.splice(i, 1)[0])\n }\n }\n return removed\n}\n\n/**\n * Compares two objects utilizing lodash deep comparison\n * @deprecated Use `deepEqual` instead for consistency\n * @param data1 First object to compare\n * @param data2 Second object to compare\n * @returns True if objects are deeply equal, false otherwise\n */\nexport const comparator = (data1: any, data2: any) => isEqual(data1, data2)\n\n/**\n * Performs fast deep comparison between two values\n *\n * Compares values recursively including nested objects, arrays, dates, RegExp, and primitives.\n * Uses fast-deep-equal library for optimal performance (~5-10x faster than JSON.stringify).\n *\n * Comparison rules:\n * - Primitives: strict equality (===)\n * - Objects: recursive key-value comparison\n * - Arrays: length + element-by-element comparison\n * - Dates: compares timestamps\n * - RegExp: compares source and flags\n * - null/undefined: strict equality\n *\n * Use cases: Testing, change detection, cache invalidation, data validation\n *\n * @param data1 - First value to compare (any type)\n * @param data2 - Second value to compare (any type)\n * @returns True if values are deeply equal, false otherwise\n *\n * @example\n * ```typescript\n * // Primitive values\n * deepEqual(42, 42) // true\n * deepEqual('hello', 'hello') // true\n * deepEqual(null, null) // true\n * deepEqual(42, '42') // false (different types)\n *\n * // Objects\n * deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 }) // true\n * deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 }) // true (order doesn't matter)\n * deepEqual({ a: 1 }, { a: 1, b: undefined }) // false\n *\n * // Arrays\n * deepEqual([1, 2, 3], [1, 2, 3]) // true\n * deepEqual([1, 2, 3], [3, 2, 1]) // false (order matters)\n *\n * // Nested structures\n * deepEqual(\n * { user: { name: 'Alice', tags: ['admin'] } },\n * { user: { name: 'Alice', tags: ['admin'] } }\n * ) // true\n *\n * // Dates\n * deepEqual(new Date('2024-01-01'), new Date('2024-01-01')) // true\n * deepEqual(new Date('2024-01-01'), new Date('2024-01-02')) // false\n *\n * // RegExp\n * deepEqual(/test/gi, /test/gi) // true\n * deepEqual(/test/g, /test/i) // false\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect if form data changed\n * const originalData = {\n * name: 'John Doe',\n * email: 'john@example.com',\n * preferences: { theme: 'dark', notifications: true }\n * }\n *\n * const currentData = {\n * name: 'John Doe',\n * email: 'john.doe@example.com', // Changed!\n * preferences: { theme: 'dark', notifications: true }\n * }\n *\n * const hasChanges = !deepEqual(originalData, currentData)\n * if (hasChanges) {\n * console.log('⚠️ You have unsaved changes')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Cache invalidation\n * const cache = new Map<string, { params: any; result: any }>()\n *\n * function cachedApiCall(params: any) {\n * const cacheKey = 'api-call'\n * const cached = cache.get(cacheKey)\n *\n * // Check if cached params match current params\n * if (cached && deepEqual(cached.params, params)) {\n * console.log('✅ Cache hit')\n * return cached.result\n * }\n *\n * console.log('❌ Cache miss - fetching')\n * const result = fetchData(params)\n * cache.set(cacheKey, { params, result })\n * return result\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: React shouldComponentUpdate optimization\n * class UserProfile extends React.Component {\n * shouldComponentUpdate(nextProps: any) {\n * // Only re-render if props actually changed\n * return !deepEqual(this.props, nextProps)\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Testing\n * import { deepEqual } from '@g10/ts-helpers'\n *\n * test('API returns expected user structure', async () => {\n * const response = await api.getUser(123)\n *\n * const expected = {\n * id: 123,\n * name: 'Alice',\n * roles: ['user', 'admin'],\n * metadata: { lastLogin: expect.any(Date) }\n * }\n *\n * // Deep comparison ignoring date instance\n * expect(deepEqual(\n * { ...response, metadata: { ...response.metadata, lastLogin: null } },\n * { ...expected, metadata: { ...expected.metadata, lastLogin: null } }\n * )).toBe(true)\n * })\n * ```\n *\n * @see {@link calculateDifferences} for finding specific differences between objects\n * @see {@link comparator} for lodash-based comparison (deprecated)\n * @see {@link https://github.com/epoberezkin/fast-deep-equal fast-deep-equal library}\n */\nexport const deepEqual = (data1: any, data2: any) => fastEqual(data1, data2)\n\n/**\n * Converts an object to a human-readable string representation\n *\n * Transforms JSON object to clean, readable text by removing braces, quotes, and\n * adding spacing. Useful for logging, debugging, UI displays, and error messages.\n *\n * Transformation:\n * 1. Stringify object to JSON\n * 2. Remove braces `{}` and quotes `\"`\n * 3. Replace commas with comma+space for readability\n *\n * @param data - Object to format (must be JSON-serializable)\n * @returns Human-readable string representation\n *\n * @example\n * ```typescript\n * // Simple object\n * formatToReadableString({ name: 'Alice', age: 25 })\n * // 'name: Alice, age: 25'\n *\n * // Multiple properties\n * formatToReadableString({ id: 1, status: 'active', verified: true })\n * // 'id: 1, status: active, verified: true'\n *\n * // Nested objects (flattened)\n * formatToReadableString({ user: { name: 'Bob' }, role: 'admin' })\n * // 'user: name: Bob, role: admin'\n *\n * // Empty object\n * formatToReadableString({})\n * // ''\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Log request parameters\n * function logApiRequest(endpoint: string, params: any) {\n * const paramsStr = formatToReadableString(params)\n * console.log(`API Request: ${endpoint} | Params: ${paramsStr}`)\n * }\n *\n * logApiRequest('/users', { page: 1, limit: 20, role: 'admin' })\n * // API Request: /users | Params: page: 1, limit: 20, role: admin\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Display validation errors\n * const errors = { email: 'Invalid format', password: 'Too short' }\n * const message = `Validation failed: ${formatToReadableString(errors)}`\n * console.log(message)\n * // Validation failed: email: Invalid format, password: Too short\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Format metadata for display\n * const metadata = {\n * author: 'John Doe',\n * created: '2024-01-01',\n * tags: ['javascript', 'typescript']\n * }\n *\n * const metadataDisplay = formatToReadableString(metadata)\n * // 'author: John Doe, created: 2024-01-01, tags: javascript, typescript'\n * ```\n *\n * @see {@link JSON.stringify} for full JSON serialization\n */\nexport const formatToReadableString = (data: { [key: string]: any }): string =>\n JSON.stringify(data).replace(/[{}\"]/g, '').replace(/,/g, ', ')\n\n/**\n * Extracts only top-level primitive properties from an object\n *\n * Filters out nested objects, arrays, and functions, returning only primitive values\n * (string, number, boolean, null, undefined, symbol). Useful for serialization,\n * API payloads, and database operations.\n *\n * Included types: string, number, boolean, null, undefined, symbol\n * Excluded types: object, array, function\n *\n * @param obj - Object from which to extract properties (null/undefined returns {})\n * @returns New object containing only primitive top-level properties\n *\n * @example\n * ```typescript\n * // Mixed types object\n * const user = {\n * id: 123,\n * name: 'Alice',\n * email: 'alice@example.com',\n * age: 25,\n * active: true,\n * metadata: { lastLogin: '2024-01-01' }, // Excluded (object)\n * roles: ['admin', 'user'], // Excluded (array)\n * save: () => {} // Excluded (function)\n * }\n *\n * getShallowProperties(user)\n * // { id: 123, name: 'Alice', email: 'alice@example.com', age: 25, active: true }\n *\n * // Only primitives\n * const config = { host: 'localhost', port: 5432, ssl: false }\n * getShallowProperties(config)\n * // { host: 'localhost', port: 5432, ssl: false } (unchanged)\n *\n * // Null/undefined values preserved\n * const partial = { a: 1, b: null, c: undefined, d: { nested: true } }\n * getShallowProperties(partial)\n * // { a: 1, b: null, c: undefined }\n *\n * // Empty/null input\n * getShallowProperties({}) // {}\n * getShallowProperties(null) // {}\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Prepare data for SQL insert (exclude nested objects)\n * const formData = {\n * firstName: 'John',\n * lastName: 'Doe',\n * email: 'john@example.com',\n * age: 30,\n * address: { street: '123 Main St', city: 'NYC' }, // Excluded\n * preferences: { theme: 'dark' } // Excluded\n * }\n *\n * const insertData = getShallowProperties(formData)\n * // { firstName: 'John', lastName: 'Doe', email: 'john@example.com', age: 30 }\n *\n * // Now safe to insert into flat database table\n * await db.insert('users', insertData)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Extract searchable fields for indexing\n * const product = {\n * sku: 'ABC123',\n * name: 'Widget',\n * price: 29.99,\n * inStock: true,\n * category: { id: 1, name: 'Electronics' }, // Excluded\n * reviews: [{ rating: 5 }], // Excluded\n * images: ['img1.jpg', 'img2.jpg'] // Excluded\n * }\n *\n * const searchableFields = getShallowProperties(product)\n * // { sku: 'ABC123', name: 'Widget', price: 29.99, inStock: true }\n *\n * // Index only primitive fields for search\n * searchIndex.add(product.sku, searchableFields)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Extract flat properties for CSV export\n * const users = [\n * {\n * id: 1,\n * name: 'Alice',\n * email: 'alice@example.com',\n * profile: { bio: 'Developer' },\n * tags: ['admin']\n * },\n * {\n * id: 2,\n * name: 'Bob',\n * email: 'bob@example.com',\n * profile: { bio: 'Designer' },\n * tags: ['user']\n * }\n * ]\n *\n * const csvData = users.map(getShallowProperties)\n * // [\n * // { id: 1, name: 'Alice', email: 'alice@example.com' },\n * // { id: 2, name: 'Bob', email: 'bob@example.com' }\n * // ]\n * // Now safe to convert to CSV\n * ```\n *\n * @see {@link calculateDifferences} for comparing objects\n * @see {@link deepEqual} for deep comparison including nested objects\n */\nexport const getShallowProperties = (obj: any): any => {\n if (!obj) return {}\n const topLevelProps: any = {}\n for (const prop in obj) {\n if (Object.hasOwnProperty.call(obj, prop)) {\n const value = obj[prop]\n const type = typeof value\n // Include primitives: string, number, boolean, undefined, symbol, and null\n if ((type !== 'object' && type !== 'function') || value === null) {\n topLevelProps[prop] = value\n }\n }\n }\n return topLevelProps\n}\n\n/**\n * Calculates differences between two objects\n *\n * Compares two objects and returns only the properties that differ. Useful for\n * change tracking, audit logs, delta updates, and optimistic UI updates.\n *\n * Special features:\n * - Date comparison: Compares dates ignoring milliseconds (tolerance-based)\n * - Shallow comparison: Only checks top-level properties\n * - One-way diff: Returns changed properties from newObj (not deletions)\n *\n * @param oldObj - Original object to compare against (baseline)\n * @param newObj - New object to compare (current state)\n * @returns Object containing only properties that changed in newObj\n *\n * @example\n * ```typescript\n * // Simple property changes\n * const old = { name: 'Alice', age: 25, city: 'NYC' }\n * const updated = { name: 'Alice', age: 26, city: 'NYC' }\n *\n * calculateDifferences(old, updated)\n * // { age: 26 } - only changed property\n *\n * // Multiple changes\n * const old2 = { a: 1, b: 2, c: 3 }\n * const new2 = { a: 1, b: 999, c: 3 }\n * calculateDifferences(old2, new2)\n * // { b: 999 }\n *\n * // No changes\n * const old3 = { x: 10 }\n * const new3 = { x: 10 }\n * calculateDifferences(old3, new3)\n * // {} - empty object\n *\n * // Date comparison (ignores milliseconds)\n * const oldDate = { timestamp: new Date('2024-01-01T10:00:00.123Z') }\n * const newDate = { timestamp: new Date('2024-01-01T10:00:00.456Z') }\n * calculateDifferences(oldDate, newDate)\n * // {} - dates considered equal (same second)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Track form changes for audit log\n * const originalUser = {\n * name: 'John Doe',\n * email: 'john@example.com',\n * role: 'user',\n * lastLogin: new Date('2024-01-01')\n * }\n *\n * const updatedUser = {\n * name: 'John Doe',\n * email: 'john.doe@company.com', // Changed\n * role: 'admin', // Changed\n * lastLogin: new Date('2024-01-01')\n * }\n *\n * const changes = calculateDifferences(originalUser, updatedUser)\n * console.log('User changes:', changes)\n * // { email: 'john.doe@company.com', role: 'admin' }\n *\n * // Save to audit log\n * auditLog.push({\n * userId: user.id,\n * timestamp: new Date(),\n * changes: changes\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Optimistic UI updates (send only changed fields)\n * function updateUserProfile(userId: string, formData: any) {\n * const originalData = getCurrentUserData(userId)\n *\n * // Only send changed fields to API\n * const delta = calculateDifferences(originalData, formData)\n *\n * if (Object.keys(delta).length === 0) {\n * console.log('✅ No changes to save')\n * return\n * }\n *\n * // Send PATCH request with only changed fields\n * return api.patch(`/users/${userId}`, delta)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Configuration change detection\n * const previousConfig = {\n * database: { host: 'localhost', port: 5432 },\n * cache: { ttl: 3600 },\n * features: { darkMode: true }\n * }\n *\n * const newConfig = {\n * database: { host: 'prod-db.example.com', port: 5432 },\n * cache: { ttl: 7200 },\n * features: { darkMode: true }\n * }\n *\n * const configChanges = calculateDifferences(previousConfig, newConfig)\n * // {\n * // database: { host: 'prod-db.example.com', port: 5432 },\n * // cache: { ttl: 7200 }\n * // }\n *\n * // Note: Returns entire nested object if any property changed\n * if (configChanges.database) {\n * console.log('⚠️ Database configuration changed - restart required')\n * }\n * ```\n *\n * @see {@link deepEqual} for full equality check\n * @see {@link getShallowProperties} for extracting only primitive properties\n */\nexport const calculateDifferences = (oldObj: any, newObj: any): any => {\n return transform(\n newObj,\n (result, value, key) => {\n const oldValue = oldObj[key]\n // If both values are dates, compare them ignoring milliseconds\n if (isDateTime(value) && isDateTime(oldValue)) {\n if (!areDatesEqualWithTolerance(toDate(value), toDate(oldValue))) {\n result[key] = value\n }\n } else if (!isEqual(value, oldValue)) {\n result[key] = value\n }\n },\n {}\n )\n}\n\n/**\n * Generates CRC32 hash from various input types\n *\n * Creates a 32-bit cyclic redundancy check (CRC32) hash as hexadecimal string.\n * Fast, deterministic fingerprinting for data integrity, caching, and change detection.\n *\n * Supported types:\n * - String: Direct hash\n * - Buffer/Uint8Array/ArrayBuffer: Binary hash\n * - Number: Converts to string then hash\n * - Boolean: 'true'/'false' then hash\n * - Object/Array: JSON.stringify then hash\n * - null/undefined: Hash of '-'\n *\n * Use cases: Content fingerprinting, ETags, cache keys, data deduplication\n *\n * ⚠️ NOTE: CRC32 is NOT cryptographically secure. Use for checksums, not security.\n *\n * @param str - Input data of any type (string, Buffer, object, array, primitive)\n * @returns CRC32 hash as hexadecimal string (8 characters)\n *\n * @example\n * ```typescript\n * // String inputs\n * generateCrcHash('hello') // '3610a686'\n * generateCrcHash('Hello') // 'f7d18982' (case-sensitive)\n * generateCrcHash('') // '0'\n *\n * // Numbers\n * generateCrcHash(123) // '884863d2' (hashes '123')\n * generateCrcHash(0) // 'f4dbdf21'\n *\n * // Booleans\n * generateCrcHash(true) // 'cc2c5c10' (hashes 'true')\n * generateCrcHash(false) // 'cc0c5c10' (hashes 'false')\n *\n * // Objects (deterministic)\n * generateCrcHash({ a: 1, b: 2 }) // Same hash for same object\n * generateCrcHash({ b: 2, a: 1 }) // Different hash (key order matters)\n *\n * // Arrays\n * generateCrcHash([1, 2, 3]) // Consistent hash\n *\n * // null/undefined\n * generateCrcHash(null) // '4e08bfb4' (hashes '-')\n * generateCrcHash(undefined) // '4e08bfb4' (hashes '-')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Generate ETag for HTTP caching\n * function generateETag(content: string): string {\n * const hash = generateCrcHash(content)\n * return `\"${hash}\"`\n * }\n *\n * const html = '<html><body>Hello World</body></html>'\n * const etag = generateETag(html)\n * // \"a3c2f1b8\"\n *\n * // Client sends: If-None-Match: \"a3c2f1b8\"\n * // Server compares ETags, returns 304 Not Modified if match\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Content-based cache key\n * const cache = new Map<string, any>()\n *\n * function cacheApiResponse(params: any, response: any) {\n * const cacheKey = generateCrcHash(JSON.stringify(params))\n * cache.set(cacheKey, response)\n * }\n *\n * function getCachedResponse(params: any) {\n * const cacheKey = generateCrcHash(JSON.stringify(params))\n * return cache.get(cacheKey)\n * }\n *\n * // Same params = same hash = cache hit\n * cacheApiResponse({ userId: 123, page: 1 }, { data: [...] })\n * const cached = getCachedResponse({ userId: 123, page: 1 })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect duplicate content\n * const seen = new Set<string>()\n *\n * function isDuplicate(content: string): boolean {\n * const hash = generateCrcHash(content)\n * if (seen.has(hash)) {\n * return true\n * }\n * seen.add(hash)\n * return false\n * }\n *\n * isDuplicate('Hello') // false (first time)\n * isDuplicate('World') // false\n * isDuplicate('Hello') // true (duplicate!)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: File versioning/fingerprinting\n * const fileContents = [\n * { path: 'app.js', content: 'console.log(\"v1\")' },\n * { path: 'style.css', content: 'body { color: red; }' }\n * ]\n *\n * const manifest = fileContents.map(file => ({\n * path: file.path,\n * hash: generateCrcHash(file.content),\n * url: `${file.path}?v=${generateCrcHash(file.content)}`\n * }))\n *\n * // [\n * // { path: 'app.js', hash: 'a3c2f1b8', url: 'app.js?v=a3c2f1b8' },\n * // { path: 'style.css', hash: 'b4d3e2c1', url: 'style.css?v=b4d3e2c1' }\n * // ]\n * // Cache-busting URLs change only when content changes\n * ```\n *\n * @see {@link deepEqual} for comparing objects for equality\n * @see {@link https://en.wikipedia.org/wiki/Cyclic_redundancy_check CRC32 Algorithm}\n */\nexport const generateCrcHash = (str: string | Buffer | Uint8Array | any): string => {\n if (isNil(str)) return crc32('-').toString(16)\n if (isString(str)) return crc32(str).toString(16)\n if (isBuffer(str)) return crc32(str).toString(16)\n if (isArrayBuffer(str)) return crc32(str).toString(16)\n if (isBoolean(str)) return crc32(str ? 'true' : 'false').toString(16)\n if (isNumber(str)) return crc32(str.toString()).toString(16)\n if (isArray(str) || isObject(str)) return generateCrcHash(JSON.stringify(str))\n return crc32(str || '').toString(16)\n}\n\n/**\n * Verifies if two variables have the same type\n *\n * Performs strict type comparison with special handling for arrays, typed arrays,\n * plain objects, and primitives. Uses runtime type checking for accurate validation.\n *\n * Type detection hierarchy:\n * 1. Arrays: Standard Array.isArray() check\n * 2. Typed Arrays: Int8Array, Uint8Array, Float32Array, etc. (checks exact typed array class)\n * 3. Plain Objects: Object literals (not class instances or built-in objects)\n * 4. Primitives: typeof comparison (string, number, boolean, undefined, symbol)\n *\n * Special features:\n * - Differentiates between arrays and typed arrays\n * - Typed array class matching (Int8Array ≠ Uint8Array)\n * - Plain object vs class instance detection\n * - null/undefined handling\n *\n * @param sourceTarget - First value to check type\n * @param destinationTarget - Second value to check type\n * @returns True if both values have the same type, false otherwise\n *\n * @example\n * ```typescript\n * // Basic types - Primitives\n * hasSameType('hello', 'world') // true (both string)\n * hasSameType(42, 100) // true (both number)\n * hasSameType(true, false) // true (both boolean)\n * hasSameType('hello', 42) // false (string vs number)\n * hasSameType(null, undefined) // false (different types)\n * ```\n *\n * @example\n * ```typescript\n * // Arrays and objects\n * hasSameType([1, 2, 3], [4, 5]) // true (both arrays)\n * hasSameType({ a: 1 }, { b: 2 }) // true (both plain objects)\n * hasSameType([1, 2], { a: 1 }) // false (array vs object)\n * hasSameType([], {}) // false (array vs object)\n * ```\n *\n * @example\n * ```typescript\n * // Typed arrays - Strict class matching\n * const int8 = new Int8Array([1, 2, 3])\n * const int8_2 = new Int8Array([4, 5])\n * const uint8 = new Uint8Array([1, 2, 3])\n * const float32 = new Float32Array([1.5, 2.5])\n *\n * hasSameType(int8, int8_2) // true (both Int8Array)\n * hasSameType(int8, uint8) // false (Int8Array vs Uint8Array)\n * hasSameType(uint8, float32) // false (Uint8Array vs Float32Array)\n * hasSameType(int8, [1, 2, 3]) // false (typed array vs regular array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Type-safe data merging\n * function safeMerge<T>(source: T, updates: any): T | null {\n * if (!hasSameType(source, updates)) {\n * console.error('❌ Type mismatch: cannot merge incompatible types')\n * return null\n * }\n *\n * if (Array.isArray(source)) {\n * return [...source, ...updates] as T\n * }\n *\n * if (typeof source === 'object' && source !== null) {\n * return { ...source, ...updates }\n * }\n *\n * return updates // Replace primitive values\n * }\n *\n * // Valid merges\n * const user = { name: 'John', age: 30 }\n * const updated = safeMerge(user, { age: 31, city: 'NYC' })\n * // { name: 'John', age: 31, city: 'NYC' }\n *\n * // Type mismatch prevented\n * const invalid = safeMerge(user, [1, 2, 3])\n * // null (with error logged)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: API response validation\n * function validateResponseShape(expected: any, actual: any): boolean {\n * // Check if response has the same structure\n * if (!hasSameType(expected, actual)) {\n * console.error('Invalid response type:', {\n * expected: typeof expected,\n * actual: typeof actual\n * })\n * return false\n * }\n *\n * // Additional validation for objects/arrays\n * if (typeof expected === 'object' && expected !== null) {\n * for (const key of Object.keys(expected)) {\n * if (!hasSameType(expected[key], actual[key])) {\n * console.error(`Type mismatch at key \"${key}\"`)\n * return false\n * }\n * }\n * }\n *\n * return true\n * }\n *\n * const expectedUser = {\n * id: 0,\n * name: '',\n * active: false,\n * tags: [] as string[]\n * }\n *\n * const validResponse = {\n * id: 123,\n * name: 'Alice',\n * active: true,\n * tags: ['admin', 'verified']\n * }\n *\n * validateResponseShape(expectedUser, validResponse) // true\n *\n * const invalidResponse = {\n * id: '123', // ❌ string instead of number\n * name: 'Alice',\n * active: true,\n * tags: ['admin']\n * }\n *\n * validateResponseShape(expectedUser, invalidResponse) // false\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Buffer/TypedArray validation before processing\n * function processImageBuffer(buffer: Uint8Array | Uint8ClampedArray): void {\n * const validBufferTypes = [\n * new Uint8Array(0),\n * new Uint8ClampedArray(0)\n * ]\n *\n * const isValidType = validBufferTypes.some(validType =>\n * hasSameType(buffer, validType)\n * )\n *\n * if (!isValidType) {\n * throw new TypeError('Expected Uint8Array or Uint8ClampedArray for image data')\n * }\n *\n * // Safe to process buffer\n * console.log(`Processing ${buffer.length} bytes of image data`)\n * }\n *\n * // Valid buffers\n * const imageData = new Uint8ClampedArray([255, 0, 0, 255]) // RGBA pixel\n * processImageBuffer(imageData) // ✅ Works\n *\n * // Invalid buffer type\n * const float32Buffer = new Float32Array([1.0, 0.5])\n * processImageBuffer(float32Buffer) // ❌ TypeError\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * hasSameType(null, null) // true (both null)\n * hasSameType(undefined, undefined) // true (both undefined)\n * hasSameType(null, undefined) // false (different types)\n * hasSameType(NaN, NaN) // true (both number)\n * hasSameType(Infinity, -Infinity) // true (both number)\n *\n * // Class instances vs plain objects\n * class User { name = 'John' }\n * const userInstance = new User()\n * const plainUser = { name: 'John' }\n * hasSameType(userInstance, plainUser) // false (class instance vs plain object)\n *\n * // Functions\n * const fn1 = () => {}\n * const fn2 = function() {}\n * hasSameType(fn1, fn2) // true (both functions)\n * ```\n *\n * @see {@link deepEqual} for value comparison (not just type)\n * @see {@link isArray} for array checking\n * @see {@link isPlainObject} for plain object detection\n */\nexport const hasSameType = (sourceTarget: any, destinationTarget: any) => {\n if (isArray(sourceTarget) && isArray(destinationTarget)) return true\n if (isArray(sourceTarget) !== isArray(destinationTarget)) return false\n if (isTypedArray(sourceTarget) && isTypedArray(destinationTarget)) {\n if (\n Object.prototype.toString.call(sourceTarget) ===\n Object.prototype.toString.call(destinationTarget)\n )\n return true\n else return false\n }\n if (isTypedArray(sourceTarget) !== isTypedArray(destinationTarget)) return false\n if (isPlainObject(sourceTarget) && isPlainObject(destinationTarget)) return true\n\n // Check if one is object and the other is not\n if (isPlainObject(sourceTarget) !== isPlainObject(destinationTarget)) return false\n\n return typeof sourceTarget === typeof destinationTarget\n}\n\n/**\n * Updates array elements that match search criteria\n *\n * Finds all elements matching the search criteria and merges update object into them.\n * Mutates the original array. Useful for batch updates on filtered data.\n *\n * Algorithm:\n * 1. Filter array to find elements matching objSearch\n * 2. For each match, merge objUpd properties using Object.assign\n * 3. Return the mutated array\n *\n * @param data - Array to update (will be mutated)\n * @param objUpd - Object with properties to merge into matching elements\n * @param objSearch - Object with search criteria (all properties must match)\n * @returns The mutated array with updated elements\n *\n * @example\n * ```typescript\n * // Update all users with role 'user' to 'member'\n * const users = [\n * { id: 1, name: 'Alice', role: 'user', active: true },\n * { id: 2, name: 'Bob', role: 'admin', active: true },\n * { id: 3, name: 'Charlie', role: 'user', active: false }\n * ]\n *\n * updateArrayElementsBy(users, { role: 'member' }, { role: 'user' })\n * // users is now:\n * // [\n * // { id: 1, name: 'Alice', role: 'member', active: true },\n * // { id: 2, name: 'Bob', role: 'admin', active: true },\n * // { id: 3, name: 'Charlie', role: 'member', active: false }\n * // ]\n *\n * // Update multiple properties\n * const products = [\n * { sku: 'A1', status: 'draft', published: false },\n * { sku: 'A2', status: 'draft', published: false },\n * { sku: 'B1', status: 'active', published: true }\n * ]\n *\n * updateArrayElementsBy(\n * products,\n * { status: 'active', published: true },\n * { status: 'draft' }\n * )\n * // All draft products now active and published\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Bulk activate pending users\n * const pendingUsers = [\n * { email: 'user1@example.com', status: 'pending', verified: false },\n * { email: 'user2@example.com', status: 'pending', verified: false },\n * { email: 'user3@example.com', status: 'active', verified: true }\n * ]\n *\n * // Activate all pending users\n * updateArrayElementsBy(\n * pendingUsers,\n * { status: 'active', verified: true, activatedAt: new Date() },\n * { status: 'pending' }\n * )\n *\n * console.log(pendingUsers.filter(u => u.status === 'active').length)\n * // 3 (all users now active)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Mark completed tasks as archived\n * const tasks = [\n * { id: 1, title: 'Task 1', completed: true, archived: false },\n * { id: 2, title: 'Task 2', completed: false, archived: false },\n * { id: 3, title: 'Task 3', completed: true, archived: false }\n * ]\n *\n * updateArrayElementsBy(\n * tasks,\n * { archived: true, archivedAt: new Date() },\n * { completed: true }\n * )\n *\n * const archivedCount = tasks.filter(t => t.archived).length\n * console.log(`Archived ${archivedCount} completed tasks`)\n * ```\n *\n * @see {@link updateArrayElementById} for updating single element by ID\n * @see {@link deleteArrayElementsBy} for deleting elements by criteria\n */\nexport const updateArrayElementsBy = (data: any[], objUpd: any, objSearch: any) => {\n nativeFilter(data, objSearch).forEach(element => nativeAssign(element, objUpd))\n return data\n}\n\n/**\n * Updates a single array element by its ID field\n *\n * Finds element by matching ID field value and replaces entire element with new object.\n * Mutates the original array. Use for updating single records by primary key.\n *\n * Algorithm:\n * 1. Find index of element where element[idField] === objUpd[idField]\n * 2. If found, replace entire element with objUpd\n * 3. If not found, array remains unchanged\n *\n * @param data - Array to update (will be mutated)\n * @param objUpd - New object to replace the found element (must contain idField)\n * @param idField - Name of field to use as identifier (default: 'id')\n * @returns void (modifies array in-place)\n *\n * @example\n * ```typescript\n * // Update user by ID\n * const users = [\n * { id: 1, name: 'Alice', email: 'alice@example.com' },\n * { id: 2, name: 'Bob', email: 'bob@example.com' },\n * { id: 3, name: 'Charlie', email: 'charlie@example.com' }\n * ]\n *\n * updateArrayElementById(\n * users,\n * { id: 2, name: 'Robert', email: 'robert@example.com', verified: true },\n * 'id'\n * )\n * // users[1] is now: { id: 2, name: 'Robert', email: 'robert@example.com', verified: true }\n *\n * // ID not found - no change\n * updateArrayElementById(users, { id: 999, name: 'Unknown' }, 'id')\n * // users array unchanged\n *\n * // Custom ID field\n * const products = [\n * { sku: 'ABC123', name: 'Widget', price: 10 },\n * { sku: 'DEF456', name: 'Gadget', price: 20 }\n * ]\n *\n * updateArrayElementById(\n * products,\n * { sku: 'ABC123', name: 'Super Widget', price: 15 },\n * 'sku'\n * )\n * // products[0] is now: { sku: 'ABC123', name: 'Super Widget', price: 15 }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Update cached user after API response\n * const userCache = [\n * { id: 1, name: 'Alice', role: 'user' },\n * { id: 2, name: 'Bob', role: 'admin' },\n * ]\n *\n * async function updateUser(userId: number, updates: any) {\n * // API call\n * const response = await api.patch(`/users/${userId}`, updates)\n *\n * // Update local cache with full response\n * updateArrayElementById(userCache, response.data, 'id')\n *\n * console.log('✅ Cache updated')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Replace product in shopping cart\n * const cart = [\n * { productId: 'P1', name: 'Laptop', qty: 1, price: 1000 },\n * { productId: 'P2', name: 'Mouse', qty: 2, price: 25 }\n * ]\n *\n * function updateCartItem(updatedItem: any) {\n * updateArrayElementById(cart, updatedItem, 'productId')\n * recalculateTotal()\n * }\n *\n * // User changes laptop quantity\n * updateCartItem({ productId: 'P1', name: 'Laptop', qty: 2, price: 1000 })\n * ```\n *\n * @see {@link updateArrayElementsBy} for updating multiple elements by criteria\n * @see {@link deleteArrayElementsBy} for deleting elements\n */\nexport const updateArrayElementById = (data: any[], objUpd: any, idField: string) => {\n const index = data.findIndex(x => x[idField] === objUpd[idField])\n if (index !== -1) data.splice(index, 1, objUpd)\n}\n\n/**\n * Removes array elements that match search criteria\n *\n * Filters out elements matching all properties in the search object.\n * Mutates the original array. Useful for batch deletions based on criteria.\n *\n * Algorithm:\n * 1. Pick properties from each element matching objSearch keys\n * 2. Deep compare picked properties with objSearch\n * 3. Remove element if all properties match\n * 4. Return the mutated array\n *\n * @param data - Array to modify (will be mutated)\n * @param objSearch - Object with search criteria (all properties must match for deletion)\n * @returns The mutated array with matching elements removed\n *\n * @example\n * ```typescript\n * // Delete users with role 'guest'\n * const users = [\n * { id: 1, name: 'Alice', role: 'admin' },\n * { id: 2, name: 'Bob', role: 'guest' },\n * { id: 3, name: 'Charlie', role: 'guest' },\n * { id: 4, name: 'Dave', role: 'user' }\n * ]\n *\n * deleteArrayElementsBy(users, { role: 'guest' })\n * // users is now: [\n * // { id: 1, name: 'Alice', role: 'admin' },\n * // { id: 4, name: 'Dave', role: 'user' }\n * // ]\n *\n * // Multiple criteria (AND condition)\n * const tasks = [\n * { id: 1, status: 'done', archived: true },\n * { id: 2, status: 'done', archived: false },\n * { id: 3, status: 'pending', archived: false }\n * ]\n *\n * deleteArrayElementsBy(tasks, { status: 'done', archived: true })\n * // Removes only tasks that are BOTH done AND archived\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Clean up expired sessions\n * const sessions = [\n * { sessionId: 'abc', userId: 1, expired: false },\n * { sessionId: 'def', userId: 2, expired: true },\n * { sessionId: 'ghi', userId: 3, expired: true },\n * { sessionId: 'jkl', userId: 4, expired: false }\n * ]\n *\n * // Remove all expired sessions\n * deleteArrayElementsBy(sessions, { expired: true })\n *\n * console.log(`Active sessions: ${sessions.length}`)\n * // Active sessions: 2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Remove cancelled orders from pending list\n * const orders = [\n * { orderId: 'O1', status: 'pending', cancelled: false },\n * { orderId: 'O2', status: 'pending', cancelled: true },\n * { orderId: 'O3', status: 'shipped', cancelled: false },\n * { orderId: 'O4', status: 'pending', cancelled: true }\n * ]\n *\n * // Clean up cancelled pending orders\n * deleteArrayElementsBy(orders, { status: 'pending', cancelled: true })\n *\n * // orders now only has valid pending and shipped orders\n * console.log(orders.length) // 2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Clear failed upload queue\n * const uploadQueue = [\n * { fileId: 'F1', status: 'uploading', retries: 0 },\n * { fileId: 'F2', status: 'failed', retries: 3 },\n * { fileId: 'F3', status: 'failed', retries: 3 },\n * { fileId: 'F4', status: 'completed', retries: 0 }\n * ]\n *\n * // Remove permanently failed uploads (max retries reached)\n * deleteArrayElementsBy(uploadQueue, { status: 'failed', retries: 3 })\n *\n * console.log(`Remaining in queue: ${uploadQueue.length}`)\n * // Remaining in queue: 2 (uploading + completed)\n * ```\n *\n * @see {@link updateArrayElementsBy} for updating elements by criteria\n * @see {@link updateArrayElementById} for updating single element by ID\n */\nexport const deleteArrayElementsBy = (data: any[], objSearch: any) => {\n nativeRemove(data, x => deepEqual(nativePick(x, Object.keys(objSearch) as any), objSearch))\n return data\n}\n\n/**\n * Sets a value at a deep path in an object using dot notation\n *\n * Creates intermediate objects/arrays as needed. Supports nested paths\n * and array indices. Mutates the original object.\n *\n * @param obj - Object to modify (will be mutated)\n * @param path - Dot-notation path (e.g., 'database.connection.timeout')\n * @param value - Value to set at the path\n * @returns The modified object (same reference as input)\n *\n * @example\n * ```typescript\n * // Simple nested path\n * const config = {}\n * setDeepValue(config, 'database.host', 'localhost')\n * // config = { database: { host: 'localhost' } }\n *\n * // Multi-level nesting\n * const obj = {}\n * setDeepValue(obj, 'app.server.port', 3000)\n * // obj = { app: { server: { port: 3000 } } }\n *\n * // Array indices\n * const data = { users: [] }\n * setDeepValue(data, 'users.0.name', 'Alice')\n * // data = { users: [{ name: 'Alice' }] }\n *\n * // Overwriting existing values\n * const settings = { database: { host: 'old' } }\n * setDeepValue(settings, 'database.host', 'new')\n * // settings = { database: { host: 'new' } }\n *\n * // Complex paths\n * const complex = {}\n * setDeepValue(complex, 'features.authentication.oauth.providers.0', 'google')\n * // complex = { features: { authentication: { oauth: { providers: ['google'] } } } }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dynamic configuration\n * const config = {}\n * const envVars = {\n * 'DATABASE_HOST': 'localhost',\n * 'DATABASE_PORT': '5432',\n * 'CACHE_TTL': '3600'\n * }\n *\n * // Convert flat env vars to nested config\n * setDeepValue(config, 'database.host', envVars.DATABASE_HOST)\n * setDeepValue(config, 'database.port', parseInt(envVars.DATABASE_PORT))\n * setDeepValue(config, 'cache.ttl', parseInt(envVars.CACHE_TTL))\n * // config = {\n * // database: { host: 'localhost', port: 5432 },\n * // cache: { ttl: 3600 }\n * // }\n * ```\n */\nexport function setDeepValue<T = any>(obj: T, path: string, value: any): T {\n if (!obj || typeof obj !== 'object') {\n throw new TypeError('setDeepValue: target must be an object')\n }\n\n if (!path || typeof path !== 'string') {\n throw new TypeError('setDeepValue: path must be a non-empty string')\n }\n\n const keys = path.split('.')\n let current: any = obj\n\n for (let i = 0; i < keys.length - 1; i++) {\n const key = keys[i]\n const nextKey = keys[i + 1]\n\n // Determine if next level should be an array or object\n const isNextArray = /^\\d+$/.test(nextKey)\n\n // Create intermediate level if it doesn't exist\n if (!(key in current) || typeof current[key] !== 'object') {\n current[key] = isNextArray ? [] : {}\n }\n\n current = current[key]\n }\n\n // Set the final value\n const lastKey = keys[keys.length - 1]\n current[lastKey] = value\n\n return obj\n}\n\n/**\n * Gets a value at a deep path in an object using dot notation\n *\n * Safely retrieves values from nested objects/arrays. Returns undefined\n * or a default value if path doesn't exist.\n *\n * @param obj - Object to read from\n * @param path - Dot-notation path (e.g., 'database.connection.timeout')\n * @param defaultValue - Value to return if path doesn't exist (default: undefined)\n * @returns Value at the path, or defaultValue if not found\n *\n * @example\n * ```typescript\n * // Simple nested access\n * const config = { database: { host: 'localhost' } }\n * getDeepValue(config, 'database.host') // 'localhost'\n *\n * // Non-existent path returns undefined\n * getDeepValue(config, 'database.port') // undefined\n *\n * // With default value\n * getDeepValue(config, 'database.port', 5432) // 5432\n *\n * // Array access\n * const data = { users: [{ name: 'Alice' }, { name: 'Bob' }] }\n * getDeepValue(data, 'users.0.name') // 'Alice'\n * getDeepValue(data, 'users.1.name') // 'Bob'\n *\n * // Deep paths\n * const app = { features: { auth: { enabled: true } } }\n * getDeepValue(app, 'features.auth.enabled') // true\n * getDeepValue(app, 'features.payments.enabled', false) // false (default)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Safe config access\n * const config = {\n * database: { host: 'localhost' },\n * cache: { ttl: 3600 }\n * }\n *\n * const dbHost = getDeepValue(config, 'database.host', '127.0.0.1')\n * const dbPort = getDeepValue(config, 'database.port', 5432)\n * const cacheTtl = getDeepValue(config, 'cache.ttl', 1800)\n * const redisHost = getDeepValue(config, 'redis.host', 'localhost')\n *\n * // All values are safely retrieved with fallbacks\n * ```\n */\nexport function getDeepValue<T = any>(obj: any, path: string, defaultValue?: T): T | undefined {\n if (!obj || typeof obj !== 'object') {\n return defaultValue\n }\n\n if (!path || typeof path !== 'string') {\n return defaultValue\n }\n\n const keys = path.split('.')\n let current = obj\n\n for (const key of keys) {\n if (current === null || current === undefined || typeof current !== 'object') {\n return defaultValue\n }\n\n if (!(key in current)) {\n return defaultValue\n }\n\n current = current[key]\n }\n\n return current !== undefined ? current : defaultValue\n}\n","/**\n * Date manipulation and formatting utilities\n * Consolidated from specialized/date module\n */\n\nimport dayjs from 'dayjs'\nimport utc from 'dayjs/plugin/utc.js'\nimport relativeTime from 'dayjs/plugin/relativeTime.js'\nimport weekOfYearPlugin from 'dayjs/plugin/weekOfYear.js'\nimport customParseFormat from 'dayjs/plugin/customParseFormat.js'\nimport isSameOrAfter from 'dayjs/plugin/isSameOrAfter.js'\nimport isSameOrBefore from 'dayjs/plugin/isSameOrBefore.js'\nimport weekday from 'dayjs/plugin/weekday.js'\nimport localeData from 'dayjs/plugin/localeData.js'\nimport localizedFormat from 'dayjs/plugin/localizedFormat.js'\nimport 'dayjs/locale/es.js'\nimport * as dateValidator from 'iso-datestring-validator'\nconst { isValidDate, isValidISODateString } = dateValidator\n\n// Configure dayjs plugins\ndayjs.extend(utc)\ndayjs.extend(relativeTime)\ndayjs.extend(weekOfYearPlugin)\ndayjs.extend(customParseFormat)\ndayjs.extend(isSameOrAfter)\ndayjs.extend(isSameOrBefore)\ndayjs.extend(weekday)\ndayjs.extend(localeData)\ndayjs.extend(localizedFormat)\n\n// Set default locale to Spanish\ndayjs.locale('es')\n\n/**\n * Formats current date with specified format\n */\nexport const formatNow = (formatStr = 'DD/MM/YYYY'): string => dayjs().format(formatStr)\n\n/**\n * Formats date with specified format string (Spanish locale by default)\n *\n * Flexible date formatter with special support for week-of-year formats.\n * Uses dayjs Spanish locale for month/day names.\n *\n * @param value - Date value to format (Date, string, timestamp, dayjs)\n * @param formatStr - Format string (default: 'DD/MM/YYYY' for Spanish dates)\n * @returns Formatted date string, empty string if value is null/undefined\n *\n * @example\n * ```typescript\n * const date = new Date('2024-03-15')\n *\n * format(date) // '15/03/2024' (Spanish default)\n * format(date, 'DD-MM-YYYY') // '15-03-2024'\n * format(date, 'YYYY/MM/DD') // '2024/03/15'\n * format(date, 'DD MMM YYYY') // '15 mar 2024' (Spanish month)\n * format(date, 'dddd, DD MMMM') // 'viernes, 15 marzo' (Spanish)\n * format(date, 'gg') // '11' (week of year)\n * format(date, 'gggg') // '2411' (year + week)\n * ```\n *\n * @see {@link longString} for localized long format\n * @see {@link formatNow} for current date formatting\n */\nexport const format = (value: any, formatStr = 'DD/MM/YYYY'): string => {\n if (!value) return ''\n if (formatStr.toLowerCase() === 'gg') return weekOfYear(value)\n else if (formatStr.toLowerCase() === 'gggg') return dayjs(value).format('YY') + weekOfYear(value)\n return dayjs(value).format(formatStr)\n}\n\n/**\n * Converts date to localized long string format (Spanish)\n *\n * Formats date as human-readable string with full month name in Spanish locale.\n * Uses dayjs 'LL' format: \"15 de marzo de 2024\"\n *\n * @param value - Date value to format (null returns empty string)\n * @returns Localized long format date string (e.g., \"15 de marzo de 2024\")\n *\n * @example\n * ```typescript\n * longString(new Date('2024-03-15')) // \"15 de marzo de 2024\"\n * longString('2024-12-25') // \"25 de diciembre de 2024\"\n * longString(null) // \"\"\n *\n * // Real-world: Document headers\n * const reportDate = longString(new Date())\n * console.log(`Informe generado el ${reportDate}`)\n * // \"Informe generado el 15 de marzo de 2024\"\n * ```\n *\n * @see {@link format} for custom format strings\n */\nexport const longString = (value: any = null) => {\n if (!value) return ''\n return dayjs(value).format('LL')\n}\n\n/**\n * Converts value to native JavaScript Date object\n */\nexport const toDate = (value: any, isUtc?: boolean) => {\n if (isUtc === undefined) return dayjs(value).toDate()\n return isUtc ? dayjs.utc(value).toDate() : dayjs(value).toDate()\n}\n\ntype DateStringFormat =\n | 'DD/MM/YYYY'\n | 'YYYY-MM-DD'\n | 'MM/DD/YYYY'\n | 'YYYY/MM/DD'\n | 'DD-MM-YYYY'\n | 'MM-DD-YYYY'\n | 'YYYYMMDD'\n | 'DDMMYYYY'\n | 'MMDDYYYY'\n | 'YYYY.MM.DD'\n | 'DD.MM.YYYY'\n | 'MM.DD.YYYY'\n\n/**\n * Parses date string with specific format to native Date object\n *\n * Strict parser that validates format and creates Date from structured date strings.\n * Supports 12 common date formats with validation.\n *\n * @param dateString - Date string to parse\n * @param format - Expected format (DD/MM/YYYY, YYYY-MM-DD, etc.)\n * @returns Date object or null if invalid\n *\n * @example\n * ```typescript\n * toDateFromString('15/03/2024', 'DD/MM/YYYY') // Date object\n * toDateFromString('2024-03-15', 'YYYY-MM-DD') // Date object\n * toDateFromString('invalid', 'DD/MM/YYYY') // null\n * ```\n *\n * @see {@link format} for formatting dates\n */\nexport const toDateFromString = (dateString: string, format: DateStringFormat): Date | null => {\n const formatRegex: Record<string, RegExp> = {\n 'DD/MM/YYYY': /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n 'YYYY-MM-DD': /^(\\d{4})-(\\d{2})-(\\d{2})$/,\n 'MM/DD/YYYY': /^(\\d{2})\\/(\\d{2})\\/(\\d{4})$/,\n 'YYYY/MM/DD': /^(\\d{4})\\/(\\d{2})\\/(\\d{2})$/,\n 'DD-MM-YYYY': /^(\\d{2})-(\\d{2})-(\\d{4})$/,\n 'MM-DD-YYYY': /^(\\d{2})-(\\d{2})-(\\d{4})$/,\n YYYYMMDD: /^(\\d{4})(\\d{2})(\\d{2})$/,\n DDMMYYYY: /^(\\d{2})(\\d{2})(\\d{4})$/,\n MMDDYYYY: /^(\\d{2})(\\d{2})(\\d{4})$/,\n 'YYYY.MM.DD': /^(\\d{4})\\.(\\d{2})\\.(\\d{2})$/,\n 'DD.MM.YYYY': /^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/,\n 'MM.DD.YYYY': /^(\\d{2})\\.(\\d{2})\\.(\\d{4})$/,\n }\n\n const regex = formatRegex[format]\n if (!regex) return null\n\n const match = dateString.match(regex)\n if (match) {\n let year: number, month: number, day: number\n\n if (format.startsWith('YYYY')) {\n year = parseInt(match[1], 10)\n month = parseInt(match[2], 10) - 1\n day = parseInt(match[3], 10)\n } else if (format.startsWith('DD')) {\n day = parseInt(match[1], 10)\n month = parseInt(match[2], 10) - 1\n year = parseInt(match[3], 10)\n } else if (format.startsWith('MM')) {\n month = parseInt(match[1], 10) - 1\n day = parseInt(match[2], 10)\n year = parseInt(match[3], 10)\n } else {\n return null\n }\n\n return new Date(year, month, day)\n }\n\n return null\n}\n\n/**\n * Returns current date\n */\nexport const now = () => dayjs().toDate()\n\n/**\n * Checks if date is considered \"new\" based on days threshold\n */\nexport const isNew = (value: any, daysnew = 1) =>\n dayjs().isSameOrBefore(dayjs(value).add(daysnew, 'days'))\n\n/**\n * Converts date to ISO 8601 string (YYYY-MM-DDTHH:mm:ss.sssZ)\n *\n * Standard ISO format for API communication and storage.\n *\n * @param value - Date to convert (null = now)\n * @param isUtc - Force UTC timezone (default: false, uses local)\n * @returns ISO 8601 formatted string\n *\n * @example\n * ```typescript\n * toISO() // \"2024-03-15T10:30:00.000+01:00\" (now, local time)\n * toISO(new Date('2024-03-15')) // \"2024-03-15T00:00:00.000+01:00\"\n * toISO(new Date('2024-03-15'), true) // \"2024-03-14T23:00:00.000Z\" (UTC)\n * ```\n */\nexport const toISO = (value: any = null, isUtc = false) => {\n if (!value) return dayjs().toISOString()\n return isUtc ? dayjs.utc(value).toISOString() : dayjs(value).toISOString()\n}\n\n/**\n * Returns relative time from now in Spanish (e.g., \"hace 2 horas\")\n *\n * @param value - Date to compare with now\n * @returns Relative time string in Spanish\n *\n * @example\n * ```typescript\n * const twoHoursAgo = new Date(Date.now() - 2 * 60 * 60 * 1000)\n * fromNow(twoHoursAgo) // \"hace 2 horas\"\n * ```\n */\nexport const fromNow = (value: any) => dayjs(value).fromNow()\n\n/**\n * Returns day of week (0-6, Sunday is 0)\n */\nexport const dayOfWeek = (value: any = null) => {\n if (!value) return dayjs().format('d')\n return dayjs(value).format('d')\n}\n\n/**\n * Returns week of year with zero padding\n */\nexport const weekOfYear = (value: any = null) => {\n if (!value) return dayjs().locale('es').week().toString().padStart(2, '0')\n return dayjs(value).locale('es').week().toString().padStart(2, '0')\n}\n\n/**\n * Calculates difference in days between two dates\n */\nexport const diffDays = (start: any, end: any = null, precise = false) => {\n const v2 = !end ? dayjs() : dayjs(end)\n return dayjs(start).diff(v2, 'days', precise)\n}\n\n/**\n * Calculates difference in business days (weekdays only, excludes weekends)\n *\n * Counts Mon-Fri between two dates, excluding Saturdays and Sundays.\n * Does NOT account for holidays.\n *\n * @param start - Start date\n * @param end - End date (null = now)\n * @param precise - Include fractional days (default: false)\n * @returns Number of business days (Mon-Fri)\n *\n * @example\n * ```typescript\n * // Monday to Friday (same week)\n * diffBusinessDays('2024-03-11', '2024-03-15') // 4 business days\n *\n * // Including weekend (skip Sat/Sun)\n * diffBusinessDays('2024-03-15', '2024-03-18') // 1 (Fri to Mon)\n *\n * // Real-world: SLA calculation\n * const ticketCreated = new Date('2024-03-11')\n * const businessDays = diffBusinessDays(ticketCreated)\n * if (businessDays > 5) {\n * console.log('⚠️ SLA violation: > 5 business days')\n * }\n * ```\n */\nexport const diffBusinessDays = (start: any, end: any = null, precise = false) => {\n let startDate = dayjs(start).startOf('day')\n let endDate = end ? dayjs(end).startOf('day') : dayjs().startOf('day')\n\n if (startDate.isAfter(endDate)) {\n ;[startDate, endDate] = [endDate, startDate]\n }\n\n let businessDays = 0\n let currentDate = startDate\n\n while (currentDate.isBefore(endDate)) {\n if (isWeekday(currentDate)) {\n businessDays++\n }\n currentDate = currentDate.add(1, 'day')\n }\n\n if (precise) {\n const fractionalDay = endDate.diff(currentDate, 'hours') / 24\n businessDays += fractionalDay\n }\n\n return businessDays\n}\n\n/**\n * Calculates difference in months between two dates\n */\nexport const diffMonths = (value: any, valueRefOrNow: any = null, precise = false) => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n return dayjs(value).diff(v2, 'months', precise)\n}\n\n/**\n * Calculates difference in years between two dates\n */\nexport const diffYears = (value: any, valueRefOrNow: any = null, precise = false) => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n return dayjs(value).diff(v2, 'years', precise)\n}\n\n/**\n * Calculates difference in milliseconds between two dates\n */\nexport const diffMilliSeconds = (value: any, valueRefOrNow: any = null) => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n return dayjs(value).diff(v2, 'milliseconds', true)\n}\n\n/**\n * Adds days to a date\n */\nexport const addDays = (value: any, nDays: number = 1) => dayjs(value).add(nDays, 'days').toDate()\n\n/**\n * Adds seconds to a date\n */\nexport const addSeconds = (value: any, nSeconds: number = 1) =>\n dayjs(value).add(nSeconds, 'seconds').toDate()\n\n/**\n * Compares two dates with ± 2 seconds tolerance\n */\nexport const areDatesEqualWithTolerance = (date1: Date, date2: Date): boolean => {\n const tolerance = 2 * 1000 // 2 seconds in milliseconds\n return Math.abs(dayjs(date1).diff(dayjs(date2))) <= tolerance\n}\n\n/**\n * Adds days to current date\n */\nexport const addNowDays = (nDays: number = 1) => dayjs().add(nDays, 'days').toDate()\n\n/**\n * Adds seconds to current date\n */\nexport const addNowSeconds = (nSeconds: number = 60) => dayjs().add(nSeconds, 'seconds').toDate()\n\n/**\n * Adds months to a date\n */\nexport const addMonths = (value: any, nMonths: number = 1) =>\n dayjs(value).add(nMonths, 'months').toDate()\n\n/**\n * Adds months to current date\n */\nexport const addNowMonths = (nMonths: number = 1) => dayjs().add(nMonths, 'months').toDate()\n\n/**\n * Adds years to a date\n */\nexport const addYears = (value: any, nYears: number = 1) =>\n dayjs(value).add(nYears, 'years').toDate()\n\n/**\n * Adds years to current date\n */\nexport const addNowYears = (nYears: number = 1) => dayjs().add(nYears, 'years').toDate()\n\n/**\n * Converts Excel serial number to Date\n * JavaScript dates can be constructed by passing milliseconds since Unix epoch\n */\nexport const excelToDate = (value: any) => {\n try {\n const d: number = Number(value)\n if (d >= 18000 && d <= 300000) return new Date(Math.round((d - 25569) * 86400 * 1000))\n return null\n } catch (_err) {\n return null\n }\n}\n\n/**\n * Detects if a variable contains a valid date\n */\nexport const isDateTime = (value: any): boolean => {\n try {\n if (!value) return false\n if (typeof value === 'number') return false\n else if (typeof value === 'boolean') return false\n else if (\n typeof value === 'string' &&\n !isValidISODateString(value) &&\n !isValidDate(value) &&\n !isValidDate(value, '')\n )\n return false\n else if (typeof value === 'object' && !(value instanceof Date) && !dayjs.isDayjs(value))\n return false\n return dayjs(value).isValid()\n } catch (_err) {\n return false\n }\n}\n\n/**\n * Compares dates by day\n */\nexport const isEqualsDateTimeByDay = (value1: any, value2: any): boolean => {\n if (!isDateTime(value1)) return false\n if (!isDateTime(value2)) return false\n return dayjs(value1).isSame(dayjs(value2), 'day')\n}\n\n/**\n * Checks if a date has expired relative to current time\n */\nexport const isExpired = (value: any, valueRefOrNow: any = null): boolean => {\n const v2 = !valueRefOrNow ? dayjs() : dayjs(valueRefOrNow)\n if (isDateTime(value)) {\n return v2.isAfter(value)\n }\n return true\n}\n\n/**\n * Formats date for MySQL database\n */\nexport const formatForMysql = (fecha: Date | null) => {\n if (!fecha) return null\n fecha.setMinutes(fecha.getMinutes() - fecha.getTimezoneOffset())\n return fecha.toISOString().slice(0, 19).replace('T', ' ')\n}\n\n/**\n * Gets first workday of month\n */\nexport const getFirstWorkdayOfMonth = (month?: number) => {\n const monthToUse = month === undefined ? dayjs().month() : month\n let firstDay = dayjs().month(monthToUse).startOf('month')\n while (firstDay.day() === 0 || firstDay.day() === 6) {\n firstDay = firstDay.add(1, 'day')\n }\n return firstDay.toDate()\n}\n\n/**\n * Gets last workday of month\n */\nexport const getLastWorkdayOfMonth = (month?: number) => {\n const monthToUse = month === undefined ? dayjs().month() : month\n let lastDay = dayjs().month(monthToUse).endOf('month')\n while (lastDay.day() === 0 || lastDay.day() === 6) {\n lastDay = lastDay.subtract(1, 'day')\n }\n return lastDay.toDate()\n}\n\n/**\n * Gets first workday after adding specified months\n */\nexport const getFirstWorkdayAfterMonths = (initialDate: Date, n: number) => {\n const startDate = dayjs(initialDate)\n const monthsToAdd = n\n const targetDate = startDate.add(monthsToAdd, 'months')\n\n let firstWorkday = targetDate.startOf('month')\n while (firstWorkday.day() === 0 || firstWorkday.day() === 6) {\n firstWorkday = firstWorkday.add(1, 'day')\n }\n return firstWorkday.toDate()\n}\n\n/**\n * Gets first day of current year\n */\nexport const getFirstDayOfYear = () => dayjs().startOf('year').toDate()\n\n/**\n * Gets last day of current year\n */\nexport const getLastDayOfYear = () => dayjs().endOf('year').toDate()\n\n/**\n * Checks if date is a weekday (not Saturday or Sunday)\n */\nexport const isWeekday = (date: any) => {\n const d = dayjs(date)\n const dayOfWeek = d.day() // 0 = Sunday, 1 = Monday, ..., 6 = Saturday\n return dayOfWeek !== 0 && dayOfWeek !== 6 // Exclude Saturdays and Sundays\n}\n","/**\n * Mathematical calculations, statistics, and financial utilities\n * Consolidated from specialized/math module\n */\n\nimport * as lodash from 'lodash'\nconst { map, round, sumBy, get, meanBy, maxBy, some, minBy, uniq, size, sum, zipObject, groupBy } =\n lodash\nimport { roundToDecimals } from './number'\n\n/**\n * Mathematical operations configuration for data aggregation\n * @template T - The type of objects being processed\n * @example\n * ```ts\n * // Simple operations configuration\n * const ops: IMathOp = {\n * $sum: ['amount', 'quantity'],\n * $avg: ['price', 'rating'],\n * $count: ['name'],\n * $max: ['sales'],\n * $min: ['cost']\n * }\n *\n * // For sales data\n * const salesOps: IMathOp<SalesRecord> = {\n * $sum: ['revenue', 'units'],\n * $avg: ['unitPrice'],\n * $countUniq: ['customerId']\n * }\n * ```\n */\nexport interface IMathOp<T = any> {\n /** Calculate average of numeric fields */\n $avg?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Count occurrences of string fields */\n $count?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends string\n ? K\n : never\n : never\n : never)[]\n /** Count unique values in fields */\n $countUniq?: (keyof T)[]\n /** Check if field exists (1/0) */\n $exist?: (keyof T)[]\n /** Find maximum value in numeric fields */\n $max?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Find minimum value in numeric fields */\n $min?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Sum numeric fields */\n $sum?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n /** Calculate trend slope for numeric fields */\n $trend?: (keyof T extends infer K\n ? K extends keyof T\n ? T[K] extends number\n ? K\n : never\n : never\n : never)[]\n}\n\n/**\n * Calculates mathematical operations on an array of objects with optional grouping\n * Supports statistical operations like sum, average, count, etc. with grouping capability\n * @param operations - Mathematical operations to perform on data fields\n * @param pgroupBy - Array of field names to group by (empty array for no grouping)\n * @param inData - Input data array to process\n * @param appendOperationToField - Whether to append operation name to result field names\n * @returns Aggregated data with calculated values\n * @example\n * ```ts\n * // Sales data aggregation\n * const sales = [\n * { region: 'North', product: 'Laptop', amount: 1000, quantity: 2 },\n * { region: 'North', product: 'Mouse', amount: 50, quantity: 5 },\n * { region: 'South', product: 'Laptop', amount: 1200, quantity: 3 }\n * ]\n *\n * // Group by region and calculate totals\n * const regionTotals = calculateAggregations(\n * { $sum: ['amount', 'quantity'], $avg: ['amount'] },\n * ['region'],\n * sales\n * )\n * // Result: [\n * // { region: 'North', amount$sum: 1050, quantity$sum: 7, amount$avg: 525 },\n * // { region: 'South', amount$sum: 1200, quantity$sum: 3, amount$avg: 1200 }\n * // ]\n *\n * // Overall totals (no grouping)\n * const totals = calculateAggregations(\n * { $sum: ['amount'], $count: ['product'], $countUniq: ['region'] },\n * [],\n * sales,\n * false\n * )\n * // Result: { amount: 2250, product: 3, region: 2 }\n * ```\n */\nexport const calculateAggregations = (\n operations: IMathOp,\n pgroupBy: string[],\n inData: any[],\n appendOperationToField = true\n) => {\n let data: any = []\n if (pgroupBy?.length) {\n const groupedData = groupBy(inData, item =>\n pgroupBy.map(field => get(item, field)).join('$|marca|@')\n )\n data = map(groupedData, (items, groupKey) => {\n const obj: any = zipObject(pgroupBy, groupKey.split('$|marca|@'))\n for (const operation in operations) {\n const fields = operations[operation]\n fields.forEach(field => {\n const resultField = appendOperationToField ? field + operation : field\n switch (operation) {\n case '$count':\n obj[resultField] = items.length\n break\n case '$sum':\n obj[resultField] = sumBy(items, item => get(item, field))\n break\n case '$avg':\n obj[resultField] = round(\n meanBy(items, item => get(item, field)),\n 1\n )\n break\n case '$max': {\n const maxItem = maxBy(items, item => get(item, field))\n obj[resultField] = maxItem ? get(maxItem, field) : undefined\n break\n }\n case '$min': {\n const minItem = minBy(items, item => get(item, field))\n obj[resultField] = minItem ? get(minItem, field) : undefined\n break\n }\n case '$exist':\n obj[resultField] = some(items, item => get(item, field)) ? 1 : 0\n break\n case '$trend':\n obj[resultField] = calculateTrendSlope(\n items.map(item => get(item, field)),\n items.map((_item, index) => index + 1)\n )\n break\n case '$countUniq':\n obj[resultField] = uniq(items.map(item => get(item, field))).length\n break\n }\n })\n }\n return obj\n })\n } else {\n const results: { [key: string]: number } = {}\n for (const operation in operations) {\n const fields = operations[operation]\n fields.forEach(field => {\n const resultField = appendOperationToField ? field + operation : field\n switch (operation) {\n case '$count':\n results[resultField] = inData.length\n break\n case '$sum':\n results[resultField] = sumBy(inData, field)\n break\n case '$avg':\n results[resultField] = round(meanBy(inData, field), 1)\n break\n case '$max':\n if (Array.isArray(inData)) {\n const maxItem = maxBy(inData, field)\n results[resultField] = maxItem ? maxItem[field] : undefined\n }\n break\n case '$min':\n if (Array.isArray(inData)) {\n const minItem = minBy(inData, field)\n results[resultField] = minItem ? minItem[field] : undefined\n }\n break\n case '$exist':\n results[resultField] = some(inData, { [field]: true }) ? 1 : 0\n break\n case '$trend':\n results[resultField] = calculateTrendSlope(\n inData.map(item => get(item, field)),\n inData.map((_item, index) => index + 1)\n )\n break\n case '$countUniq':\n results[resultField] = uniq(inData.map(item => get(item, field))).length\n break\n }\n })\n }\n data = results\n }\n return data\n}\n\n/**\n * Calculates the slope of a linear trend line using least squares regression\n *\n * Computes the \"rise over run\" coefficient that best fits the data points.\n * Uses the least squares method to find the line y = mx + b, returning only m (slope).\n *\n * Slope interpretation:\n * - **Positive slope**: Y increases as X increases (upward trend)\n * - **Negative slope**: Y decreases as X increases (downward trend)\n * - **Zero slope**: No trend, flat line\n * - **Magnitude**: How steep the trend is (larger = steeper)\n *\n * Algorithm (Least Squares):\n * 1. Calculate Σx, Σy, Σx², Σxy\n * 2. Compute slope: m = (n·Σxy - Σx·Σy) / (n·Σx² - (Σx)²)\n * 3. Handle division by zero (constant x values)\n * 4. Round to 1 decimal place\n *\n * @param y - Dependent variable values (response variable)\n * @param x - Independent variable values (predictor variable)\n * @returns Slope value rounded to 1 decimal (0 if denominator is zero)\n *\n * @example\n * ```typescript\n * // Basic trend slope calculation\n * const sales = [100, 120, 140, 160, 180]\n * const months = [1, 2, 3, 4, 5]\n * calculateTrendSlope(sales, months) // 20.0 (sales increase 20 units/month)\n *\n * const declining = [100, 90, 80, 70, 60]\n * calculateTrendSlope(declining, months) // -10.0 (decreasing 10 units/month)\n *\n * const flat = [100, 100, 100, 100, 100]\n * calculateTrendSlope(flat, months) // 0.0 (no trend)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sales forecasting and trend analysis\n * interface MonthlySales {\n * month: number\n * revenue: number\n * }\n *\n * function analyzeSalesTrend(data: MonthlySales[]): void {\n * const months = data.map(d => d.month)\n * const revenue = data.map(d => d.revenue)\n * const slope = calculateTrendSlope(revenue, months)\n *\n * console.log(`📈 Sales Trend Analysis:`)\n * console.log(` Slope: ${slope} per month`)\n *\n * if (slope > 0) {\n * const annualGrowth = slope * 12\n * console.log(`✅ Growing trend: $${annualGrowth.toLocaleString()}/year projected`)\n * } else if (slope < 0) {\n * console.log(`⚠️ Declining trend: ${slope} per month`)\n * console.log(`Action: Investigate causes and intervene`)\n * } else {\n * console.log(`➡️ Flat trend: No significant growth or decline`)\n * }\n * }\n *\n * const salesData = [\n * { month: 1, revenue: 50000 },\n * { month: 2, revenue: 52000 },\n * { month: 3, revenue: 54000 },\n * { month: 4, revenue: 56000 }\n * ]\n * analyzeSalesTrend(salesData)\n * // Slope: 2000 per month\n * // ✅ Growing: $24,000/year projected\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: User engagement trending\n * function trackUserEngagement(dailyActiveUsers: number[]): string {\n * const days = Array.from({ length: dailyActiveUsers.length }, (_, i) => i + 1)\n * const slope = calculateTrendSlope(dailyActiveUsers, days)\n *\n * const avgUsers = dailyActiveUsers.reduce((a, b) => a + b) / dailyActiveUsers.length\n * const changePercent = ((slope * 30) / avgUsers) * 100\n *\n * if (changePercent > 5) {\n * return `🚀 Strong growth: ${changePercent.toFixed(1)}% monthly increase`\n * } else if (changePercent < -5) {\n * return `📉 Declining: ${changePercent.toFixed(1)}% monthly decrease (ALERT!)`\n * } else {\n * return `➡️ Stable: ${changePercent.toFixed(1)}% monthly change`\n * }\n * }\n *\n * const dau = [1000, 1020, 1050, 1080, 1100, 1120, 1150]\n * trackUserEngagement(dau)\n * // \"🚀 Strong growth: 12.8% monthly increase\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Server response time degradation detection\n * function monitorPerformanceDegradation(\n * responseTimes: number[],\n * timestamps: number[]\n * ): void {\n * const slope = calculateTrendSlope(responseTimes, timestamps)\n *\n * console.log(`⏱️ Performance Trend: ${slope}ms per time unit`)\n *\n * if (slope > 5) {\n * console.log('🚨 ALERT: Response times degrading')\n * console.log(`Degradation rate: ${slope}ms per unit`)\n * console.log('Action: Investigate server load, memory leaks, database queries')\n * } else if (slope < -5) {\n * console.log('✅ Performance improving')\n * } else {\n * console.log('➡️ Performance stable')\n * }\n * }\n *\n * const times = [120, 125, 135, 150, 170, 200]\n * const hours = [1, 2, 3, 4, 5, 6]\n * monitorPerformanceDegradation(times, hours)\n * // 🚨 ALERT: Response times degrading (16ms/hour)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Stock price momentum indicator\n * function calculatePriceMomentum(prices: number[], days: number[]): string {\n * const slope = calculateTrendSlope(prices, days)\n * const avgPrice = prices.reduce((a, b) => a + b) / prices.length\n * const momentum = (slope / avgPrice) * 100\n *\n * if (momentum > 1) {\n * return `🟢 BULLISH (${momentum.toFixed(2)}% daily momentum)`\n * } else if (momentum < -1) {\n * return `🔴 BEARISH (${momentum.toFixed(2)}% daily momentum)`\n * } else {\n * return `🟡 NEUTRAL (${momentum.toFixed(2)}% daily momentum)`\n * }\n * }\n *\n * const stockPrices = [100, 102, 105, 108, 112, 115]\n * const tradingDays = [1, 2, 3, 4, 5, 6]\n * calculatePriceMomentum(stockPrices, tradingDays)\n * // \"🟢 BULLISH (2.86% daily momentum)\"\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculateTrendSlope([1, 2, 3], [1, 2, 3]) // 1.0 (perfect positive correlation)\n * calculateTrendSlope([3, 2, 1], [1, 2, 3]) // -1.0 (perfect negative)\n * calculateTrendSlope([5, 5, 5], [1, 2, 3]) // 0.0 (flat line)\n * calculateTrendSlope([1, 2, 3], [1, 1, 1]) // 0.0 (constant X, div by zero)\n * calculateTrendSlope([10, 20], [1, 2]) // 10.0 (two points)\n * ```\n *\n * @see {@link calculateCorrelation} for correlation strength (not just slope)\n * @see {@link calculateAverage} for mean calculation\n */\nexport function calculateTrendSlope(y: number[], x: number[]) {\n const n = size(y)\n const sum_x = sum(x)\n const sum_y = sum(y)\n const sum_x2 = sum(map(x, val => val * val))\n const sum_xy = sum(map(x, (val, i) => val * y[i]))\n\n const denominator = n * sum_x2 - sum_x * sum_x\n if (denominator === 0) {\n return 0\n }\n\n const slope = (n * sum_xy - sum_x * sum_y) / denominator\n return roundToDecimals(slope, 1)\n}\n\n// =============================================================================\n// ADVANCED STATISTICAL FUNCTIONS\n// =============================================================================\n\n/**\n * Calculates the median of an array of numbers\n *\n * The median is the middle value in a sorted dataset. More robust than mean for\n * skewed distributions or datasets with outliers. For even-length arrays, returns\n * the average of the two middle values.\n *\n * Algorithm:\n * 1. Sort array in ascending order\n * 2. If odd length: return middle value\n * 3. If even length: return average of two middle values\n * 4. Empty array returns 0\n *\n * Use cases: Income analysis, response times, test scores, real estate prices\n *\n * @param values - Array of numbers to calculate median from (empty array returns 0)\n * @returns Median value, or 0 if array is empty\n *\n * @example\n * ```typescript\n * // Odd number of values\n * calculateMedian([1, 2, 3, 4, 5]) // 3 (middle value)\n * calculateMedian([10, 5, 15]) // 10 (after sorting: [5, 10, 15])\n *\n * // Even number of values\n * calculateMedian([1, 2, 3, 4]) // 2.5 (average of 2 and 3)\n * calculateMedian([10, 20, 30, 40]) // 25 (average of 20 and 30)\n *\n * // Edge cases\n * calculateMedian([]) // 0\n * calculateMedian([42]) // 42\n * calculateMedian([5, 5, 5]) // 5\n *\n * // Handles negative numbers\n * calculateMedian([-10, -5, 0, 5, 10]) // 0\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Analyze salary data (median better than mean for skewed data)\n * const salaries = [30000, 35000, 40000, 45000, 50000, 250000]\n *\n * const mean = salaries.reduce((a, b) => a + b) / salaries.length\n * const median = calculateMedian(salaries)\n *\n * console.log(`Mean: $${mean}`) // $75,000 (skewed by outlier)\n * console.log(`Median: $${median}`) // $42,500 (more representative)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Website response time analysis\n * const responseTimes = [120, 150, 180, 200, 220, 5000] // milliseconds\n *\n * const medianResponseTime = calculateMedian(responseTimes)\n * console.log(`Median response: ${medianResponseTime}ms`) // 190ms\n * // More useful than mean (946ms) which is skewed by one slow request\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Grade distribution analysis\n * const grades = [65, 70, 75, 80, 85, 90, 95]\n *\n * const median = calculateMedian(grades)\n * const Q1 = calculatePercentile(grades, 25)\n * const Q3 = calculatePercentile(grades, 75)\n *\n * console.log(`Median grade: ${median}`) // 80\n * console.log(`25th percentile: ${Q1}`) // 70\n * console.log(`75th percentile: ${Q3}`) // 90\n * ```\n *\n * @see {@link calculateAverage} for arithmetic mean calculation\n * @see {@link calculatePercentile} for other percentiles (median is 50th percentile)\n * @see {@link calculateQuartiles} for Q1, Q2 (median), Q3\n * @see {@link calculateMode} for most frequent value\n */\nexport const calculateMedian = (values: number[]): number => {\n if (!values.length) return 0\n\n const sorted = [...values].sort((a, b) => a - b)\n const middle = Math.floor(sorted.length / 2)\n\n if (sorted.length % 2 === 0) {\n return (sorted[middle - 1] + sorted[middle]) / 2\n }\n\n return sorted[middle]\n}\n\n/**\n * Calculates the mode (most frequent value) in an array of numbers\n *\n * The mode is the value that appears most frequently in a dataset. Returns null\n * if the array is empty or if there are multiple modes (multimodal distribution).\n *\n * Algorithm:\n * 1. Count frequency of each value using hash map\n * 2. Track maximum frequency and corresponding value\n * 3. Detect multimodal distributions (multiple values with same max frequency)\n * 4. Return single mode or null if multimodal/empty\n *\n * Behavior:\n * - Empty array → null\n * - Single mode → returns that value\n * - Multiple modes (tie) → null\n * - All unique values → null (no mode)\n *\n * @param values - Array of numbers to analyze\n * @returns The mode (most frequent value) or null if multimodal/empty\n *\n * @example\n * ```typescript\n * // Basic mode calculation\n * calculateMode([1, 2, 2, 3, 3, 3, 4]) // 3 (appears 3 times)\n * calculateMode([5, 5, 5, 1, 2, 3]) // 5 (most frequent)\n * calculateMode([10, 20, 30]) // null (all unique, no mode)\n * calculateMode([1, 1, 2, 2, 3]) // null (multimodal: 1 and 2 tie)\n * calculateMode([]) // null (empty array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Find most common response time in API logs\n * const responseTimes = [\n * 150, 200, 150, 300, 150, // 150ms appears most\n * 200, 400, 150, 200, 150\n * ]\n * const commonResponseTime = calculateMode(responseTimes)\n * // 150 (appears 5 times)\n *\n * if (commonResponseTime !== null) {\n * console.log(`Most common response time: ${commonResponseTime}ms`)\n * console.log('💡 Optimize for this latency profile')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect most frequent error code in logs\n * function analyzeErrorCodes(errorLogs: { code: number }[]): void {\n * const codes = errorLogs.map(log => log.code)\n * const mostFrequentCode = calculateMode(codes)\n *\n * if (mostFrequentCode !== null) {\n * console.log(`🚨 Most frequent error: ${mostFrequentCode}`)\n * console.log('Priority fix needed for this error type')\n * } else {\n * console.log('✅ No dominant error pattern (good distribution)')\n * }\n * }\n *\n * // Example usage\n * const errors = [\n * { code: 404 }, { code: 500 }, { code: 404 },\n * { code: 404 }, { code: 503 }, { code: 404 }\n * ]\n * analyzeErrorCodes(errors)\n * // 🚨 Most frequent error: 404\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Find most popular product rating\n * interface ProductReview {\n * productId: string\n * rating: number // 1-5 stars\n * userId: string\n * }\n *\n * function getMostCommonRating(reviews: ProductReview[]): string {\n * const ratings = reviews.map(r => r.rating)\n * const mode = calculateMode(ratings)\n *\n * if (mode === null) {\n * return 'Ratings are evenly distributed'\n * }\n *\n * const sentiment = mode >= 4 ? '😊 Positive' : mode <= 2 ? '😞 Negative' : '😐 Neutral'\n * return `Most common rating: ${mode}⭐ (${sentiment})`\n * }\n *\n * const reviews = [\n * { productId: 'A1', rating: 5, userId: 'U1' },\n * { productId: 'A1', rating: 5, userId: 'U2' },\n * { productId: 'A1', rating: 4, userId: 'U3' },\n * { productId: 'A1', rating: 5, userId: 'U4' }\n * ]\n *\n * getMostCommonRating(reviews)\n * // \"Most common rating: 5⭐ (😊 Positive)\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect most frequent user action in analytics\n * const userActions = [\n * 'click', 'scroll', 'click', 'click',\n * 'scroll', 'click', 'submit', 'click'\n * ].map(action => {\n * const actionMap = { click: 1, scroll: 2, submit: 3 }\n * return actionMap[action as keyof typeof actionMap]\n * })\n *\n * const dominantAction = calculateMode(userActions)\n * const actionNames = { 1: 'click', 2: 'scroll', 3: 'submit' }\n *\n * if (dominantAction !== null) {\n * console.log(`Most frequent action: ${actionNames[dominantAction as keyof typeof actionNames]}`)\n * // \"Most frequent action: click\"\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculateMode([42]) // 42 (single value)\n * calculateMode([1, 1]) // 1 (all same)\n * calculateMode([1, 2, 3, 4, 5]) // null (all unique)\n * calculateMode([1, 1, 2, 2]) // null (bimodal)\n * calculateMode([1, 1, 1, 2, 2, 2]) // null (bimodal tie)\n * calculateMode([NaN, NaN, 1]) // NaN (NaN counted as value)\n * calculateMode([Infinity, Infinity]) // Infinity\n * ```\n *\n * @see {@link calculateMedian} for middle value (resistant to outliers)\n * @see {@link calculateAverage} for mean value\n * @see {@link calculateStandardDeviation} for data spread measurement\n */\nexport const calculateMode = (values: number[]): number | null => {\n if (!values.length) return null\n\n const frequency: { [key: number]: number } = {}\n let maxFreq = 0\n let mode: number | null = null\n let hasMultipleModes = false\n\n for (const value of values) {\n frequency[value] = (frequency[value] || 0) + 1\n\n if (frequency[value] > maxFreq) {\n maxFreq = frequency[value]\n mode = value\n hasMultipleModes = false\n } else if (frequency[value] === maxFreq && value !== mode) {\n hasMultipleModes = true\n }\n }\n\n return hasMultipleModes ? null : mode\n}\n\n/**\n * Calculates the standard deviation of an array of numbers\n *\n * Measures the amount of variation or dispersion in a dataset. Low standard deviation\n * means values are close to the mean; high standard deviation means values are spread out.\n *\n * Algorithm:\n * 1. Calculate mean (average)\n * 2. Calculate squared differences from mean\n * 3. Calculate variance (average of squared differences)\n * 4. Return square root of variance\n *\n * Formula:\n * - Population: σ = √(Σ(x - μ)² / N)\n * - Sample: s = √(Σ(x - x̄)² / (N - 1))\n *\n * @param values - Array of numbers (empty array returns 0)\n * @param sample - If true, uses sample standard deviation (N-1). If false, uses population (N). Default: false\n * @returns Standard deviation, or 0 if array is empty\n *\n * @example\n * ```typescript\n * // Low standard deviation (values close together)\n * calculateStandardDeviation([10, 11, 12, 13, 14])\n * // ~1.41 (values tightly clustered)\n *\n * // High standard deviation (values spread out)\n * calculateStandardDeviation([1, 5, 20, 50, 100])\n * // ~35.96 (values widely dispersed)\n *\n * // Population vs Sample\n * const data = [2, 4, 6, 8, 10]\n * calculateStandardDeviation(data, false) // 2.83 (population)\n * calculateStandardDeviation(data, true) // 3.16 (sample, Bessel's correction)\n *\n * // Edge cases\n * calculateStandardDeviation([]) // 0\n * calculateStandardDeviation([5]) // 0\n * calculateStandardDeviation([5, 5, 5]) // 0 (no variation)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Quality control - manufacturing consistency\n * const widgetWeights = [98.5, 99.2, 100.1, 99.8, 100.3, 98.9]\n * const targetWeight = 100\n *\n * const mean = widgetWeights.reduce((a, b) => a + b) / widgetWeights.length\n * const stdDev = calculateStandardDeviation(widgetWeights, true)\n *\n * console.log(`Mean weight: ${mean.toFixed(2)}g`)\n * console.log(`Std deviation: ${stdDev.toFixed(2)}g`)\n * // Low std dev = consistent manufacturing\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Investment volatility analysis\n * const monthlyReturns = [2.3, -1.5, 4.2, 0.8, -2.1, 3.5, 1.2] // %\n *\n * const avgReturn = monthlyReturns.reduce((a, b) => a + b) / monthlyReturns.length\n * const volatility = calculateStandardDeviation(monthlyReturns, true)\n *\n * console.log(`Average return: ${avgReturn.toFixed(2)}%`)\n * console.log(`Volatility (std dev): ${volatility.toFixed(2)}%`)\n * // High volatility = riskier investment\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Student performance analysis\n * const testScores = [75, 82, 68, 90, 78, 85, 72, 88, 80, 77]\n *\n * const mean = testScores.reduce((a, b) => a + b) / testScores.length\n * const stdDev = calculateStandardDeviation(testScores, true)\n *\n * // Identify outliers (beyond 2 standard deviations)\n * const outliers = testScores.filter(score =>\n * Math.abs(score - mean) > 2 * stdDev\n * )\n *\n * console.log(`Mean: ${mean.toFixed(1)}`)\n * console.log(`Std Dev: ${stdDev.toFixed(1)}`)\n * console.log(`Outliers:`, outliers)\n * ```\n *\n * @see {@link calculateVariance} for variance (σ²)\n * @see {@link detectOutliers} for IQR-based outlier detection\n * @see {@link calculateMedian} for central tendency (robust to outliers)\n */\nexport const calculateStandardDeviation = (values: number[], sample = false): number => {\n if (!values.length) return 0\n\n const mean = values.reduce((sum, val) => sum + val, 0) / values.length\n const squaredDiffs = values.map(val => Math.pow(val - mean, 2))\n const variance =\n squaredDiffs.reduce((sum, val) => sum + val, 0) / (sample ? values.length - 1 : values.length)\n\n return Math.sqrt(variance)\n}\n\n/**\n * Calculates the variance of an array of numbers\n *\n * Variance measures how spread out numbers are from their mean (average).\n * It's the average of squared differences from the mean. Higher variance = more spread.\n *\n * Algorithm:\n * 1. Calculate mean (average) of all values\n * 2. Compute squared difference from mean for each value: (value - mean)²\n * 3. Sum all squared differences\n * 4. Divide by N (population) or N-1 (sample) depending on `sample` flag\n *\n * Population vs Sample variance:\n * - **Population (sample=false)**: Use when you have ALL data (divide by N)\n * - **Sample (sample=true)**: Use when you have a subset (divide by N-1, Bessel's correction)\n *\n * @param values - Array of numbers to analyze\n * @param sample - If true, uses sample variance (N-1). If false, uses population variance (N). Default: false\n * @returns Variance value (0 if empty array)\n *\n * @example\n * ```typescript\n * // Basic variance calculation\n * calculateVariance([1, 2, 3, 4, 5]) // 2 (population variance)\n * calculateVariance([1, 2, 3, 4, 5], true) // 2.5 (sample variance)\n * calculateVariance([10, 10, 10, 10]) // 0 (no variance, all same)\n * calculateVariance([1, 100]) // 2450.5 (high variance)\n * calculateVariance([]) // 0 (empty array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Analyze server response time consistency\n * const responseTimes = [120, 150, 130, 145, 125, 140, 135] // milliseconds\n * const variance = calculateVariance(responseTimes)\n * const stdDev = Math.sqrt(variance)\n *\n * console.log(`Variance: ${variance.toFixed(2)}ms²`)\n * console.log(`Std Dev: ${stdDev.toFixed(2)}ms`)\n *\n * if (stdDev < 20) {\n * console.log('✅ Consistent performance')\n * } else {\n * console.log('⚠️ High variability - investigate outliers')\n * }\n * // Variance: 110.20ms²\n * // Std Dev: 10.50ms\n * // ✅ Consistent performance\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Quality control in manufacturing\n * interface Measurement {\n * batchId: string\n * weight: number // grams\n * }\n *\n * function checkBatchQuality(measurements: Measurement[]): boolean {\n * const weights = measurements.map(m => m.weight)\n * const variance = calculateVariance(weights)\n * const maxAcceptableVariance = 5 // Quality threshold\n *\n * if (variance <= maxAcceptableVariance) {\n * console.log('✅ Batch passes quality control')\n * console.log(`Variance: ${variance.toFixed(2)}g² (within tolerance)`)\n * return true\n * } else {\n * console.log('❌ Batch REJECTED - excessive variance')\n * console.log(`Variance: ${variance.toFixed(2)}g² (exceeds ${maxAcceptableVariance}g²)`)\n * return false\n * }\n * }\n *\n * const batch = [\n * { batchId: 'B001', weight: 100.2 },\n * { batchId: 'B001', weight: 100.5 },\n * { batchId: 'B001', weight: 99.8 },\n * { batchId: 'B001', weight: 100.1 }\n * ]\n *\n * checkBatchQuality(batch)\n * // ✅ Batch passes quality control\n * // Variance: 0.09g² (within tolerance)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Stock price volatility analysis\n * function analyzeStockVolatility(prices: number[]): string {\n * const variance = calculateVariance(prices, true) // Sample variance\n * const stdDev = Math.sqrt(variance)\n * const mean = prices.reduce((sum, p) => sum + p, 0) / prices.length\n * const coefficientOfVariation = (stdDev / mean) * 100\n *\n * if (coefficientOfVariation < 5) {\n * return `Low volatility (${coefficientOfVariation.toFixed(1)}% CV) - Stable stock`\n * } else if (coefficientOfVariation < 15) {\n * return `Moderate volatility (${coefficientOfVariation.toFixed(1)}% CV) - Normal fluctuation`\n * } else {\n * return `High volatility (${coefficientOfVariation.toFixed(1)}% CV) - Risky investment`\n * }\n * }\n *\n * const stockPrices = [100, 102, 98, 101, 99, 103, 97] // Daily closing prices\n * analyzeStockVolatility(stockPrices)\n * // \"Moderate volatility (2.1% CV) - Normal fluctuation\"\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: A/B test result significance\n * function compareVariability(groupA: number[], groupB: number[]): void {\n * const varA = calculateVariance(groupA, true)\n * const varB = calculateVariance(groupB, true)\n * const ratio = varA / varB\n *\n * console.log(`Group A variance: ${varA.toFixed(2)}`)\n * console.log(`Group B variance: ${varB.toFixed(2)}`)\n * console.log(`Variance ratio: ${ratio.toFixed(2)}`)\n *\n * if (ratio > 2 || ratio < 0.5) {\n * console.log('⚠️ Groups have significantly different variability')\n * console.log('Consider using Welch\\'s t-test instead of Student\\'s t-test')\n * } else {\n * console.log('✅ Groups have similar variability')\n * }\n * }\n *\n * const conversionRatesA = [0.12, 0.15, 0.13, 0.14, 0.12]\n * const conversionRatesB = [0.18, 0.22, 0.19, 0.21, 0.20]\n *\n * compareVariability(conversionRatesA, conversionRatesB)\n * // Group A variance: 0.00013\n * // Group B variance: 0.00025\n * // Variance ratio: 0.52\n * // ✅ Groups have similar variability\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculateVariance([5]) // 0 (single value)\n * calculateVariance([5], true) // NaN (sample size 1, division by 0)\n * calculateVariance([1, 1, 1]) // 0 (no variation)\n * calculateVariance([0, 0, 0]) // 0 (all zeros)\n * calculateVariance([-5, 0, 5]) // 16.67 (symmetric around 0)\n * calculateVariance([1e10, 1e10 + 1]) // 0.25 (large numbers)\n * ```\n *\n * @see {@link calculateStandardDeviation} for square root of variance (same units as data)\n * @see {@link calculateIQR} for robust spread measure (resistant to outliers)\n * @see {@link detectOutliers} for finding extreme values\n */\nexport const calculateVariance = (values: number[], sample = false): number => {\n if (!values.length) return 0\n\n const mean = values.reduce((sum, val) => sum + val, 0) / values.length\n const squaredDiffs = values.map(val => Math.pow(val - mean, 2))\n\n return (\n squaredDiffs.reduce((sum, val) => sum + val, 0) / (sample ? values.length - 1 : values.length)\n )\n}\n\n/**\n * Calculates a specific percentile from an array of numbers\n *\n * Percentiles indicate the value below which a given percentage of observations fall.\n * For example, the 75th percentile is the value below which 75% of the data lies.\n *\n * Algorithm:\n * 1. Sort values in ascending order\n * 2. Calculate position: (percentile / 100) × (n - 1)\n * 3. If position is integer, return value at that index\n * 4. Otherwise, interpolate between lower and upper values using linear interpolation\n *\n * Common percentiles:\n * - 25th (Q1): First quartile\n * - 50th (Q2): Median\n * - 75th (Q3): Third quartile\n * - 90th: Top 10% threshold\n * - 95th: Top 5% threshold\n * - 99th: Top 1% threshold\n *\n * @param values - Array of numbers to analyze\n * @param percentile - Percentile to calculate (0-100)\n * @returns Value at the specified percentile (0 if empty array)\n * @throws {Error} If percentile is not between 0 and 100\n *\n * @example\n * ```typescript\n * // Basic percentile calculation\n * const scores = [55, 60, 65, 70, 75, 80, 85, 90, 95, 100]\n *\n * calculatePercentile(scores, 25) // 66.25 (Q1 - 25% below this)\n * calculatePercentile(scores, 50) // 77.5 (Median - 50% below this)\n * calculatePercentile(scores, 75) // 88.75 (Q3 - 75% below this)\n * calculatePercentile(scores, 90) // 95.5 (90% below this)\n * calculatePercentile(scores, 100) // 100 (Maximum)\n * calculatePercentile(scores, 0) // 55 (Minimum)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: API response time SLA monitoring\n * const responseTimes = [\n * 120, 150, 180, 200, 250, 300, 350, 400, 450, 500,\n * 600, 700, 800, 1000, 1200\n * ]\n *\n * const p50 = calculatePercentile(responseTimes, 50) // Median\n * const p95 = calculatePercentile(responseTimes, 95) // 95th percentile\n * const p99 = calculatePercentile(responseTimes, 99) // 99th percentile\n *\n * console.log(`📊 Response Time SLA:`)\n * console.log(` 50th (median): ${p50}ms`)\n * console.log(` 95th: ${p95}ms`)\n * console.log(` 99th: ${p99}ms`)\n *\n * if (p95 < 500) {\n * console.log('✅ SLA met: 95% of requests under 500ms')\n * } else {\n * console.log(`⚠️ SLA breach: p95=${p95}ms exceeds 500ms target`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Grade distribution analysis\n * function analyzeExamResults(scores: number[]): void {\n * const p10 = calculatePercentile(scores, 10)\n * const p25 = calculatePercentile(scores, 25)\n * const p50 = calculatePercentile(scores, 50)\n * const p75 = calculatePercentile(scores, 75)\n * const p90 = calculatePercentile(scores, 90)\n *\n * console.log('📈 Exam Score Distribution:')\n * console.log(` Bottom 10%: ≤ ${p10.toFixed(1)}`)\n * console.log(` Q1 (25th): ${p25.toFixed(1)}`)\n * console.log(` Median (50th): ${p50.toFixed(1)}`)\n * console.log(` Q3 (75th): ${p75.toFixed(1)}`)\n * console.log(` Top 10%: ≥ ${p90.toFixed(1)}`)\n *\n * // Identify struggling students\n * if (p25 < 60) {\n * console.log('⚠️ Warning: 25% of students scored below 60')\n * console.log('Recommendation: Provide additional support')\n * }\n * }\n *\n * const examScores = [45, 52, 58, 63, 67, 72, 75, 78, 82, 85, 88, 92, 95]\n * analyzeExamResults(examScores)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Server load capacity planning\n * interface ServerMetrics {\n * timestamp: Date\n * cpuUsage: number // percentage\n * }\n *\n * function determineCapacityThreshold(metrics: ServerMetrics[]): number {\n * const cpuUsages = metrics.map(m => m.cpuUsage)\n * const p95 = calculatePercentile(cpuUsages, 95)\n *\n * console.log(`Current p95 CPU usage: ${p95.toFixed(1)}%`)\n *\n * if (p95 > 80) {\n * console.log('🚨 CRITICAL: Scale up immediately')\n * return 100 // Emergency threshold\n * } else if (p95 > 60) {\n * console.log('⚠️ WARNING: Plan scaling in next 24h')\n * return 80\n * } else {\n * console.log('✅ Healthy capacity')\n * return 70\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Income inequality analysis (Gini coefficient context)\n * const householdIncomes = [\n * 25000, 30000, 35000, 40000, 45000, 50000, 55000,\n * 60000, 70000, 80000, 90000, 120000, 150000, 200000\n * ]\n *\n * const p10 = calculatePercentile(householdIncomes, 10)\n * const p50 = calculatePercentile(householdIncomes, 50)\n * const p90 = calculatePercentile(householdIncomes, 90)\n *\n * const p90p10Ratio = p90 / p10\n *\n * console.log(`Income distribution:`)\n * console.log(` Bottom 10%: ≤$${p10.toLocaleString()}`)\n * console.log(` Median: $${p50.toLocaleString()}`)\n * console.log(` Top 10%: ≥$${p90.toLocaleString()}`)\n * console.log(` P90/P10 ratio: ${p90p10Ratio.toFixed(2)}x`)\n *\n * if (p90p10Ratio > 5) {\n * console.log('⚠️ High income inequality detected')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * calculatePercentile([10], 50) // 10 (single value)\n * calculatePercentile([1, 2, 3, 4], 0) // 1 (minimum)\n * calculatePercentile([1, 2, 3, 4], 100) // 4 (maximum)\n * calculatePercentile([], 50) // 0 (empty array)\n * calculatePercentile([5, 5, 5], 75) // 5 (all same values)\n *\n * // Error cases\n * calculatePercentile([1, 2, 3], -1) // throws Error\n * calculatePercentile([1, 2, 3], 101) // throws Error\n * ```\n *\n * @see {@link calculateQuartiles} for Q1, Q2, Q3 in one call\n * @see {@link calculateIQR} for interquartile range (Q3 - Q1)\n * @see {@link calculateMedian} for 50th percentile specifically\n * @see {@link detectOutliers} for finding extreme values using IQR method\n */\nexport const calculatePercentile = (values: number[], percentile: number): number => {\n if (!values.length) return 0\n if (percentile < 0 || percentile > 100) throw new Error('Percentile must be between 0 and 100')\n\n const sorted = [...values].sort((a, b) => a - b)\n const index = (percentile / 100) * (sorted.length - 1)\n\n if (Math.floor(index) === index) {\n return sorted[index]\n }\n\n const lower = sorted[Math.floor(index)]\n const upper = sorted[Math.ceil(index)]\n const weight = index - Math.floor(index)\n\n return lower * (1 - weight) + upper * weight\n}\n\n/**\n * Calculates quartiles (Q1, Q2, Q3) of an array of numbers\n *\n * Quartiles divide a sorted dataset into four equal parts. Returns the three cut points:\n * - **Q1 (25th percentile)**: 25% of data below, 75% above\n * - **Q2 (50th percentile)**: Median - 50% below, 50% above\n * - **Q3 (75th percentile)**: 75% below, 25% above\n *\n * Useful for:\n * - Box plot visualization\n * - Outlier detection (IQR method)\n * - Understanding data spread and skewness\n * - Five-number summary (min, Q1, Q2, Q3, max)\n *\n * @param values - Array of numbers to analyze\n * @returns Object with Q1, Q2 (median), Q3 values\n *\n * @example\n * ```typescript\n * // Basic quartiles\n * const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * calculateQuartiles(data)\n * // { Q1: 3.25, Q2: 5.5, Q3: 7.75 }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Salary distribution analysis\n * const salaries = [\n * 30000, 35000, 40000, 45000, 50000, 55000, 60000,\n * 65000, 70000, 80000, 90000, 120000\n * ]\n *\n * const { Q1, Q2, Q3 } = calculateQuartiles(salaries)\n *\n * console.log(`📊 Salary Distribution:`)\n * console.log(` Q1 (25th): $${Q1.toLocaleString()}`)\n * console.log(` Q2 (Median): $${Q2.toLocaleString()}`)\n * console.log(` Q3 (75th): $${Q3.toLocaleString()}`)\n * console.log(` IQR: $${(Q3 - Q1).toLocaleString()}`)\n * // Q1: $43,750, Q2: $57,500, Q3: $72,500, IQR: $28,750\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Performance monitoring box plot\n * function createBoxPlot(responseTimes: number[]): void {\n * const { Q1, Q2, Q3 } = calculateQuartiles(responseTimes)\n * const min = Math.min(...responseTimes)\n * const max = Math.max(...responseTimes)\n * const iqr = Q3 - Q1\n *\n * console.log('📦 Response Time Box Plot:')\n * console.log(` Min: ${min}ms`)\n * console.log(` Q1: ${Q1}ms ├───┐`)\n * console.log(` Q2: ${Q2}ms │ █ │ (median)`)\n * console.log(` Q3: ${Q3}ms └───┤`)\n * console.log(` Max: ${max}ms`)\n * console.log(` IQR: ${iqr}ms (middle 50%)`)\n * }\n *\n * const times = [120, 150, 180, 200, 220, 250, 300, 350, 400]\n * createBoxPlot(times)\n * ```\n *\n * @see {@link calculatePercentile} for calculating any percentile\n * @see {@link calculateIQR} for interquartile range (Q3 - Q1)\n * @see {@link detectOutliers} for outlier detection using quartiles\n * @see {@link calculateMedian} for Q2 specifically\n */\nexport const calculateQuartiles = (values: number[]): { Q1: number; Q2: number; Q3: number } => {\n return {\n Q1: calculatePercentile(values, 25),\n Q2: calculatePercentile(values, 50), // median\n Q3: calculatePercentile(values, 75),\n }\n}\n\n/**\n * Calculates the interquartile range (IQR) of an array of numbers\n *\n * IQR is the range of the middle 50% of data, calculated as Q3 - Q1.\n * It's a robust measure of statistical dispersion, resistant to outliers.\n *\n * IQR interpretation:\n * - **Small IQR**: Data tightly clustered around median (low variability)\n * - **Large IQR**: Data widely spread (high variability)\n * - **IQR = 0**: All middle 50% values identical\n *\n * Key uses:\n * - Outlier detection (values outside Q1 - 1.5×IQR to Q3 + 1.5×IQR)\n * - Box plot whiskers calculation\n * - Robust alternative to standard deviation (less affected by extremes)\n *\n * @param values - Array of numbers to analyze\n * @returns Interquartile range (Q3 - Q1)\n *\n * @example\n * ```typescript\n * // Basic IQR calculation\n * const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * calculateIQR(data) // 4.5 (middle 50% spans 4.5 units)\n *\n * const tightData = [10, 10.5, 11, 11.5, 12]\n * calculateIQR(tightData) // 1 (low variability)\n *\n * const spreadData = [10, 20, 30, 40, 50, 60, 70, 80, 90]\n * calculateIQR(spreadData) // 40 (high variability)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Compare consistency between two groups\n * const teamA_responseTimes = [100, 110, 120, 130, 140, 150]\n * const teamB_responseTimes = [80, 120, 130, 140, 180, 250]\n *\n * const iqrA = calculateIQR(teamA_responseTimes) // 30ms\n * const iqrB = calculateIQR(teamB_responseTimes) // 60ms\n *\n * console.log(`Team A IQR: ${iqrA}ms (consistent)`)\n * console.log(`Team B IQR: ${iqrB}ms (inconsistent)`)\n *\n * if (iqrB > iqrA * 1.5) {\n * console.log('⚠️ Team B shows high variability - investigate')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Quality control tolerance check\n * function checkProductQuality(measurements: number[]): boolean {\n * const iqr = calculateIQR(measurements)\n * const maxAllowedIQR = 5 // mm tolerance\n *\n * console.log(`IQR: ${iqr.toFixed(2)}mm`)\n *\n * if (iqr <= maxAllowedIQR) {\n * console.log('✅ Manufacturing process within tolerance')\n * return true\n * } else {\n * console.log(`❌ IQR ${iqr}mm exceeds ${maxAllowedIQR}mm tolerance`)\n * console.log('Action: Recalibrate machinery')\n * return false\n * }\n * }\n *\n * const partLengths = [99.8, 100.0, 100.1, 100.2, 100.3]\n * checkProductQuality(partLengths)\n * ```\n *\n * @see {@link calculateQuartiles} for Q1, Q2, Q3 values\n * @see {@link detectOutliers} for IQR-based outlier detection\n * @see {@link calculateStandardDeviation} for parametric dispersion measure\n */\nexport const calculateIQR = (values: number[]): number => {\n const quartiles = calculateQuartiles(values)\n return quartiles.Q3 - quartiles.Q1\n}\n\n/**\n * Detects outliers using the IQR (Interquartile Range) method\n *\n * Identifies values that fall outside the \"normal\" range defined by quartiles.\n * Uses Tukey's fences method, commonly used in box plots.\n *\n * Algorithm:\n * 1. Calculate Q1, Q3, and IQR (Q3 - Q1)\n * 2. Compute lower fence: Q1 - (multiplier × IQR)\n * 3. Compute upper fence: Q3 + (multiplier × IQR)\n * 4. Values outside fences are outliers\n *\n * Common multipliers:\n * - **1.5** (default): Standard outliers (Tukey's rule)\n * - **3.0**: Extreme outliers only (more conservative)\n *\n * @param values - Array of numbers to analyze\n * @param multiplier - IQR multiplier for fence calculation (default: 1.5)\n * @returns Array of outlier values\n *\n * @example\n * ```typescript\n * // Basic outlier detection\n * const data = [10, 12, 14, 15, 16, 18, 20, 22, 100]\n * detectOutliers(data) // [100] (extreme high value)\n *\n * const normal = [10, 12, 14, 15, 16, 18, 20, 22, 24]\n * detectOutliers(normal) // [] (no outliers)\n *\n * const withExtremes = [1, 10, 12, 14, 15, 16, 18, 20, 100]\n * detectOutliers(withExtremes) // [1, 100] (both low and high outliers)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Detect anomalous response times\n * function analyzeResponseTimes(times: number[]): void {\n * const outliers = detectOutliers(times)\n *\n * if (outliers.length === 0) {\n * console.log('✅ No anomalous response times detected')\n * return\n * }\n *\n * const { Q1, Q3 } = calculateQuartiles(times)\n * const iqr = Q3 - Q1\n *\n * console.log(`⚠️ Found ${outliers.length} outliers:`)\n * outliers.forEach(outlier => {\n * const severity = outlier > Q3 + 3 * iqr ? 'EXTREME' : 'MODERATE'\n * console.log(` - ${outlier}ms (${severity})`)\n * })\n *\n * console.log('Recommendation: Investigate these requests')\n * }\n *\n * const apiTimes = [100, 120, 130, 140, 150, 160, 180, 200, 5000]\n * analyzeResponseTimes(apiTimes)\n * // ⚠️ Found 1 outliers:\n * // - 5000ms (EXTREME)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Fraud detection in transaction amounts\n * interface Transaction {\n * id: string\n * amount: number\n * userId: string\n * }\n *\n * function detectSuspiciousTransactions(\n * transactions: Transaction[]\n * ): Transaction[] {\n * const amounts = transactions.map(t => t.amount)\n * const outlierAmounts = detectOutliers(amounts, 3) // More conservative\n *\n * const suspicious = transactions.filter(t =>\n * outlierAmounts.includes(t.amount)\n * )\n *\n * if (suspicious.length > 0) {\n * console.log(`🚨 ${suspicious.length} suspicious transactions:`)\n * suspicious.forEach(t => {\n * console.log(` ID: ${t.id}, Amount: $${t.amount}, User: ${t.userId}`)\n * })\n * console.log('Action: Flag for manual review')\n * }\n *\n * return suspicious\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sensor data cleaning\n * function cleanSensorReadings(readings: number[]): number[] {\n * const outliers = detectOutliers(readings)\n * const cleaned = readings.filter(r => !outliers.includes(r))\n *\n * console.log(`Original readings: ${readings.length}`)\n * console.log(`Outliers removed: ${outliers.length}`)\n * console.log(`Cleaned readings: ${cleaned.length}`)\n *\n * if (outliers.length > readings.length * 0.1) {\n * console.log('⚠️ Warning: >10% outliers - sensor malfunction?')\n * }\n *\n * return cleaned\n * }\n *\n * const tempReadings = [20.1, 20.5, 20.8, 21.0, 85.0, 20.9, 21.2]\n * const clean = cleanSensorReadings(tempReadings)\n * // Original: 7, Outliers: 1 (85.0°C), Cleaned: 6\n * ```\n *\n * @example\n * ```typescript\n * // Comparing multipliers\n * const data = [1, 5, 10, 12, 14, 15, 16, 18, 20, 25, 100]\n *\n * detectOutliers(data, 1.5) // [1, 100] (standard)\n * detectOutliers(data, 3.0) // [100] (extreme only)\n * ```\n *\n * @see {@link calculateIQR} for IQR calculation\n * @see {@link calculateQuartiles} for quartile values\n * @see {@link calculateStandardDeviation} for parametric outlier detection (z-score method)\n */\nexport const detectOutliers = (values: number[], multiplier = 1.5): number[] => {\n const quartiles = calculateQuartiles(values)\n const iqr = quartiles.Q3 - quartiles.Q1\n const lowerBound = quartiles.Q1 - multiplier * iqr\n const upperBound = quartiles.Q3 + multiplier * iqr\n\n return values.filter(value => value < lowerBound || value > upperBound)\n}\n\n/**\n * Calculates Pearson correlation coefficient between two arrays of numbers\n *\n * Measures linear correlation between two variables. Returns value between -1 and +1:\n * - +1: Perfect positive correlation (as X increases, Y increases proportionally)\n * - 0: No linear correlation\n * - -1: Perfect negative correlation (as X increases, Y decreases proportionally)\n *\n * Formula (Pearson's r):\n * r = [n∑(xy) - ∑x∑y] / √{[n∑x² - (∑x)²][n∑y² - (∑y)²]}\n *\n * Use cases: A/B testing, feature selection, risk analysis, data validation\n *\n * ⚠️ NOTE: Measures LINEAR correlation only. May miss non-linear relationships.\n *\n * @param x - First array of numbers (must match length of y)\n * @param y - Second array of numbers (must match length of x)\n * @returns Correlation coefficient (-1 to +1), or 0 if arrays empty/mismatched/no variance\n *\n * @example\n * ```typescript\n * // Perfect positive correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [2, 4, 6, 8, 10])\n * // 1.0 (perfect linear relationship: y = 2x)\n *\n * // Perfect negative correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [10, 8, 6, 4, 2])\n * // -1.0 (perfect inverse relationship)\n *\n * // No correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [5, 3, 5, 3, 5])\n * // ~0 (no linear relationship)\n *\n * // Moderate positive correlation\n * calculateCorrelation([1, 2, 3, 4, 5], [2, 3, 5, 7, 9])\n * // ~0.98 (strong positive correlation)\n *\n * // Edge cases\n * calculateCorrelation([], []) // 0\n * calculateCorrelation([1, 2], [1]) // 0 (length mismatch)\n * calculateCorrelation([5, 5, 5], [1, 2, 3]) // 0 (no variance in x)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Analyze relationship between ad spend and sales\n * const adSpend = [1000, 1500, 2000, 2500, 3000, 3500] // $ thousands\n * const sales = [20, 28, 35, 42, 48, 55] // $ thousands\n *\n * const correlation = calculateCorrelation(adSpend, sales)\n * console.log(`Correlation: ${correlation.toFixed(3)}`)\n * // 0.998 (strong positive correlation - more ad spend → more sales)\n *\n * if (correlation > 0.7) {\n * console.log('✅ Strong relationship: Ad spend drives sales')\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Website traffic vs conversion rate analysis\n * const dailyVisitors = [1200, 1500, 1800, 2000, 2200, 2500]\n * const conversionRate = [3.2, 3.0, 2.9, 2.7, 2.6, 2.4]\n *\n * const correlation = calculateCorrelation(dailyVisitors, conversionRate)\n * console.log(`Correlation: ${correlation.toFixed(3)}`)\n * // -0.995 (strong negative correlation - more traffic → lower conversion %)\n * // Suggests traffic quality decreasing or server overload\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Feature selection for ML model\n * interface DataPoint {\n * temperature: number\n * humidity: number\n * windSpeed: number\n * rainfall: number\n * }\n *\n * const weatherData: DataPoint[] = [\n * { temperature: 25, humidity: 60, windSpeed: 10, rainfall: 0 },\n * { temperature: 30, humidity: 50, windSpeed: 15, rainfall: 2 },\n * { temperature: 20, humidity: 80, windSpeed: 5, rainfall: 10 },\n * // ... more data\n * ]\n *\n * // Find which features correlate with rainfall\n * const temp = weatherData.map(d => d.temperature)\n * const humidity = weatherData.map(d => d.humidity)\n * const wind = weatherData.map(d => d.windSpeed)\n * const rain = weatherData.map(d => d.rainfall)\n *\n * const correlations = {\n * temperature: calculateCorrelation(temp, rain),\n * humidity: calculateCorrelation(humidity, rain),\n * windSpeed: calculateCorrelation(wind, rain)\n * }\n *\n * console.log('Rainfall correlations:', correlations)\n * // { temperature: -0.45, humidity: 0.82, windSpeed: -0.23 }\n * // Humidity strongly predicts rainfall\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Portfolio diversification analysis\n * const stock1Returns = [2.3, -1.5, 4.2, 0.8, -2.1, 3.5]\n * const stock2Returns = [1.8, 2.1, -0.5, 1.2, 3.4, -1.8]\n *\n * const correlation = calculateCorrelation(stock1Returns, stock2Returns)\n * console.log(`Portfolio correlation: ${correlation.toFixed(3)}`)\n *\n * if (Math.abs(correlation) < 0.3) {\n * console.log('✅ Good diversification: Stocks move independently')\n * } else if (correlation > 0.7) {\n * console.log('⚠️ High correlation: Portfolio not diversified')\n * }\n * ```\n *\n * @see {@link calculateStandardDeviation} for measuring spread\n * @see {@link calculateTrendSlope} for linear regression slope\n * @see {@link https://en.wikipedia.org/wiki/Pearson_correlation_coefficient Pearson Correlation}\n */\nexport const calculateCorrelation = (x: number[], y: number[]): number => {\n if (x.length !== y.length || x.length === 0) return 0\n\n const n = x.length\n const sumX = sum(x)\n const sumY = sum(y)\n const sumXY = sum(map(x, (val, i) => val * y[i]))\n const sumX2 = sum(map(x, val => val * val))\n const sumY2 = sum(map(y, val => val * val))\n\n const numerator = n * sumXY - sumX * sumY\n const denominator = Math.sqrt((n * sumX2 - sumX * sumX) * (n * sumY2 - sumY * sumY))\n\n if (denominator === 0) return 0\n\n return numerator / denominator\n}\n\n// =============================================================================\n// FINANCIAL FUNCTIONS\n// =============================================================================\n\n/**\n * Calculates Net Present Value (NPV) of cash flows using discounted cash flow method\n *\n * Evaluates investment profitability by discounting future cash flows to present value.\n * Formula: NPV = CF₀ + CF₁/(1+r) + CF₂/(1+r)² + ... + CFₙ/(1+r)ⁿ\n *\n * Decision rules:\n * - NPV > 0: Investment profitable, accept project\n * - NPV = 0: Break-even, neutral decision\n * - NPV < 0: Investment unprofitable, reject project\n *\n * @param cashFlows - Array of cash flows [initial investment (negative), period 1, period 2, ...]\n * @param discountRate - Discount rate as decimal (e.g., 0.1 for 10% WACC/hurdle rate)\n * @returns Net Present Value in currency units\n *\n * @example\n * ```typescript\n * // Investment: -10000€ initial, then +3000€/year for 4 years\n * const npv = calculateNPV([-10000, 3000, 3000, 3000, 3000], 0.10)\n * console.log(npv) // 1509.67€ (profitable investment)\n *\n * // Real-world: Software project ROI analysis\n * const projectCashFlows = [\n * -50000, // Year 0: Development cost\n * 15000, // Year 1: Revenue\n * 20000, // Year 2: Revenue\n * 25000, // Year 3: Revenue\n * 30000 // Year 4: Revenue\n * ]\n * const wacc = 0.12 // 12% weighted average cost of capital\n * const projectNPV = calculateNPV(projectCashFlows, wacc)\n * if (projectNPV > 0) {\n * console.log(`✅ Project approved. NPV: ${projectNPV.toFixed(2)}€`)\n * }\n * ```\n *\n * @see {@link calculateIRR} for internal rate of return\n * @see {@link https://en.wikipedia.org/wiki/Net_present_value NPV Formula}\n */\nexport const calculateNPV = (cashFlows: number[], discountRate: number): number => {\n return cashFlows.reduce((npv, cashFlow, index) => {\n // Initial cash flow (usually investment) is not discounted\n // Subsequent cash flows are discounted by their period\n const discountFactor = index === 0 ? 1 : Math.pow(1 + discountRate, index)\n return npv + cashFlow / discountFactor\n }, 0)\n}\n\n/**\n * Calculates Internal Rate of Return (IRR) using Newton-Raphson iterative method\n *\n * Finds discount rate that makes NPV = 0. IRR represents the annualized effective return rate.\n * Uses Newton-Raphson numerical method with configurable tolerance and iterations.\n *\n * Decision rules:\n * - IRR > Required Rate: Accept project (returns exceed cost of capital)\n * - IRR < Required Rate: Reject project (insufficient returns)\n *\n * @param cashFlows - Array of cash flows [initial investment, period 1, period 2, ...]\n * @param initialGuess - Starting guess for IRR (default: 0.1 = 10%)\n * @param maxIterations - Maximum iterations for convergence (default: 100)\n * @param tolerance - Convergence tolerance (default: 1e-6)\n * @returns Internal Rate of Return as decimal (e.g., 0.15 = 15% annual return)\n *\n * @example\n * ```typescript\n * // Investment: -1000€, returns +400€, +500€, +300€\n * const irr = calculateIRR([-1000, 400, 500, 300])\n * console.log(`${(irr * 100).toFixed(2)}%`) // ~16.17% annual return\n *\n * // Real-world: Compare to required return rate\n * const cashFlows = [-50000, 15000, 20000, 25000, 30000]\n * const irr = calculateIRR(cashFlows)\n * const requiredRate = 0.12 // 12% hurdle rate\n *\n * if (irr > requiredRate) {\n * console.log(`✅ IRR ${(irr*100).toFixed(1)}% exceeds ${(requiredRate*100)}% requirement`)\n * } else {\n * console.log(`❌ IRR ${(irr*100).toFixed(1)}% below ${(requiredRate*100)}% requirement`)\n * }\n * ```\n *\n * @see {@link calculateNPV} for net present value calculation\n * @see {@link https://en.wikipedia.org/wiki/Internal_rate_of_return IRR Formula}\n */\nexport const calculateIRR = (\n cashFlows: number[],\n initialGuess = 0.1,\n maxIterations = 100,\n tolerance = 1e-6\n): number => {\n let rate = initialGuess\n\n for (let i = 0; i < maxIterations; i++) {\n const npv = calculateNPV(cashFlows, rate)\n const npvDerivative = cashFlows.reduce((sum, cashFlow, index) => {\n return sum - (index * cashFlow) / Math.pow(1 + rate, index + 1)\n }, 0)\n\n if (Math.abs(npv) < tolerance) return rate\n if (Math.abs(npvDerivative) < tolerance) break\n\n rate = rate - npv / npvDerivative\n }\n\n return rate\n}\n\n/**\n * Calculates future value (FV) with compound interest\n *\n * Formula: FV = PV × (1 + r)ⁿ\n *\n * @param presentValue - Initial investment amount\n * @param interestRate - Interest rate per period as decimal (e.g., 0.05 for 5%)\n * @param periods - Number of compounding periods\n * @returns Future value after n periods\n *\n * @example\n * ```typescript\n * // 1000€ at 5% annual interest for 10 years\n * const fv = calculateFutureValue(1000, 0.05, 10) // 1628.89€\n *\n * // Retirement planning: 10000€ invested for 30 years at 7%\n * const retirement = calculateFutureValue(10000, 0.07, 30) // 76,122.55€\n * ```\n *\n * @see {@link calculatePresentValue}\n */\nexport const calculateFutureValue = (\n presentValue: number,\n interestRate: number,\n periods: number\n): number => {\n return presentValue * Math.pow(1 + interestRate, periods)\n}\n\n/**\n * Calculates present value (PV) of future amount\n *\n * Formula: PV = FV / (1 + r)ⁿ\n *\n * @param futureValue - Future amount to discount\n * @param interestRate - Discount rate as decimal (e.g., 0.05 for 5%)\n * @param periods - Number of periods\n * @returns Present value today\n *\n * @example\n * ```typescript\n * // What's 10000€ in 5 years worth today at 6% discount?\n * const pv = calculatePresentValue(10000, 0.06, 5) // 7,472.58€\n * ```\n *\n * @see {@link calculateFutureValue}\n */\nexport const calculatePresentValue = (\n futureValue: number,\n interestRate: number,\n periods: number\n): number => {\n return futureValue / Math.pow(1 + interestRate, periods)\n}\n\n/**\n * Calculates periodic payment for annuity (loans, mortgages)\n *\n * Formula: PMT = PV × [r(1+r)ⁿ] / [(1+r)ⁿ - 1]\n *\n * @param presentValue - Loan/mortgage principal amount\n * @param interestRate - Interest rate per period as decimal\n * @param periods - Total number of payment periods\n * @returns Periodic payment amount\n *\n * @example\n * ```typescript\n * // 200000€ mortgage at 3% annual for 30 years (360 months)\n * const monthlyRate = 0.03 / 12 // 0.0025\n * const payment = calculateAnnuityPayment(200000, monthlyRate, 360) // 843.21€/month\n *\n * // Car loan: 25000€ at 5% for 5 years\n * const carPayment = calculateAnnuityPayment(25000, 0.05/12, 60) // 471.78€/month\n * ```\n */\nexport const calculateAnnuityPayment = (\n presentValue: number,\n interestRate: number,\n periods: number\n): number => {\n if (interestRate === 0) return presentValue / periods\n\n return (\n (presentValue * (interestRate * Math.pow(1 + interestRate, periods))) /\n (Math.pow(1 + interestRate, periods) - 1)\n )\n}\n\n// =============================================================================\n// DATA VISUALIZATION UTILITIES\n// =============================================================================\n\n/**\n * Normalizes an array of numbers to [0, 1] range using min-max normalization\n *\n * Transforms values to a common scale where:\n * - Minimum value → 0\n * - Maximum value → 1\n * - Other values → proportional between 0 and 1\n *\n * Formula: normalized = (value - min) / (max - min)\n *\n * Use cases:\n * - Machine learning feature scaling\n * - Comparing datasets with different scales\n * - Data visualization (heatmaps, gradients)\n * - Neural network input preprocessing\n *\n * @param values - Array of numbers to normalize\n * @returns Array normalized to [0, 1] range (empty array returns [], all equal returns all 0s)\n *\n * @example\n * ```typescript\n * // Basic normalization\n * normalizeToRange([10, 20, 30, 40, 50])\n * // [0, 0.25, 0.5, 0.75, 1]\n *\n * normalizeToRange([100, 200, 150])\n * // [0, 1, 0.5]\n *\n * normalizeToRange([5, 5, 5])\n * // [0, 0, 0] (all equal, no range)\n *\n * normalizeToRange([])\n * // [] (empty array)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Student grade normalization for comparison\n * interface StudentScore {\n * name: string\n * rawScore: number\n * }\n *\n * function normalizeScores(students: StudentScore[]): void {\n * const rawScores = students.map(s => s.rawScore)\n * const normalized = normalizeToRange(rawScores)\n *\n * students.forEach((student, i) => {\n * const normalizedScore = (normalized[i] * 100).toFixed(1)\n * console.log(`${student.name}: ${student.rawScore} → ${normalizedScore}%`)\n * })\n * }\n *\n * normalizeScores([\n * { name: 'Alice', rawScore: 85 },\n * { name: 'Bob', rawScore: 72 },\n * { name: 'Charlie', rawScore: 95 }\n * ])\n * // Alice: 85 → 56.5%\n * // Bob: 72 → 0.0%\n * // Charlie: 95 → 100.0%\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sensor data visualization (temperature heatmap)\n * function generateHeatmapColors(temperatures: number[]): string[] {\n * const normalized = normalizeToRange(temperatures)\n *\n * return normalized.map(value => {\n * const intensity = Math.round(value * 255)\n * return `rgb(${intensity}, 0, ${255 - intensity})`\n * })\n * }\n *\n * const temps = [18, 22, 25, 30, 35]\n * generateHeatmapColors(temps)\n * // ['rgb(0, 0, 255)', 'rgb(60, 0, 195)', ...]\n * // Blue (cold) → Red (hot)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: ML feature scaling for neural network\n * interface HouseData {\n * sqft: number // 500-5000\n * price: number // 100000-1000000\n * bedrooms: number // 1-6\n * }\n *\n * function prepareMLFeatures(houses: HouseData[]): number[][] {\n * const sqfts = normalizeToRange(houses.map(h => h.sqft))\n * const prices = normalizeToRange(houses.map(h => h.price))\n * const bedrooms = normalizeToRange(houses.map(h => h.bedrooms))\n *\n * return sqfts.map((_, i) => [sqfts[i], prices[i], bedrooms[i]])\n * }\n *\n * // All features now in [0, 1] range for training\n * ```\n *\n * @see {@link scaleToRange} for normalizing to custom [min, max] range\n * @see {@link calculateStandardDeviation} for z-score normalization alternative\n */\nexport const normalizeToRange = (values: number[]): number[] => {\n if (!values.length) return []\n\n const min = Math.min(...values)\n const max = Math.max(...values)\n const range = max - min\n\n if (range === 0) return values.map(() => 0)\n\n return values.map(value => (value - min) / range)\n}\n\n/**\n * Scales an array of numbers to a custom [min, max] range\n *\n * Transforms values to specified range while preserving proportions.\n * Uses min-max normalization internally, then scales to target range.\n *\n * Formula:\n * 1. Normalize to [0, 1]: norm = (value - min) / (max - min)\n * 2. Scale to [minRange, maxRange]: scaled = minRange + norm × (maxRange - minRange)\n *\n * Use cases:\n * - Image pixel values (0-255)\n * - Audio amplitude (-1 to 1)\n * - Progress bars (0-100%)\n * - Rating systems (1-5 stars)\n *\n * @param values - Array of numbers to scale\n * @param minRange - Target minimum value\n * @param maxRange - Target maximum value\n * @returns Array scaled to [minRange, maxRange]\n *\n * @example\n * ```typescript\n * // Basic scaling\n * scaleToRange([10, 20, 30, 40, 50], 0, 100)\n * // [0, 25, 50, 75, 100]\n *\n * scaleToRange([1, 2, 3, 4, 5], 1, 5)\n * // [1, 2, 3, 4, 5] (already in range)\n *\n * scaleToRange([0, 0.5, 1], 0, 255)\n * // [0, 127.5, 255] (grayscale pixel values)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Convert arbitrary scores to 1-5 star rating\n * function convertToStarRating(scores: number[]): number[] {\n * const stars = scaleToRange(scores, 1, 5)\n * return stars.map(s => Math.round(s * 2) / 2) // Round to 0.5\n * }\n *\n * const reviewScores = [45, 67, 89, 92, 100]\n * convertToStarRating(reviewScores)\n * // [1, 2.5, 4, 4.5, 5]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Progress bar percentage\n * function calculateProgress(completedTasks: number[]): number[] {\n * return scaleToRange(completedTasks, 0, 100).map(p => Math.round(p))\n * }\n *\n * const tasksCompleted = [2, 5, 8, 10]\n * calculateProgress(tasksCompleted)\n * // [0, 38, 75, 100] (percentage progress)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Audio normalization to [-1, 1] range\n * function normalizeAudioSamples(samples: number[]): Float32Array {\n * const normalized = scaleToRange(samples, -1, 1)\n * return new Float32Array(normalized)\n * }\n *\n * const audioData = [0, 1000, 2000, 3000, 4000]\n * normalizeAudioSamples(audioData)\n * // Float32Array [-1, -0.5, 0, 0.5, 1]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Sensor calibration to voltage range\n * interface SensorReading {\n * timestamp: Date\n * rawValue: number\n * }\n *\n * function calibrateSensor(readings: SensorReading[]): number[] {\n * const rawValues = readings.map(r => r.rawValue)\n * // Calibrate to 0-5V range\n * return scaleToRange(rawValues, 0, 5)\n * }\n *\n * const sensorData = [\n * { timestamp: new Date(), rawValue: 100 },\n * { timestamp: new Date(), rawValue: 300 },\n * { timestamp: new Date(), rawValue: 500 }\n * ]\n * calibrateSensor(sensorData)\n * // [0, 2.5, 5] volts\n * ```\n *\n * @see {@link normalizeToRange} for [0, 1] normalization\n */\nexport const scaleToRange = (values: number[], minRange: number, maxRange: number): number[] => {\n const normalized = normalizeToRange(values)\n const scale = maxRange - minRange\n\n return normalized.map(value => minRange + value * scale)\n}\n\n/**\n * Calculates histogram by dividing data into equal-width bins\n *\n * Groups values into intervals (bins) and counts frequency in each bin.\n * Useful for understanding data distribution, finding patterns, and visualization.\n *\n * Algorithm:\n * 1. Find min/max values\n * 2. Calculate bin width: (max - min) / bins\n * 3. Create bins with ranges [start, end)\n * 4. Count values in each bin\n * 5. Last bin includes max value (closed interval)\n *\n * @param values - Array of numbers to analyze\n * @param bins - Number of bins/intervals to divide data into\n * @returns Array of objects with {range: [min, max], count: frequency}\n *\n * @example\n * ```typescript\n * // Basic histogram\n * const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n * calculateHistogram(data, 5)\n * // [\n * // { range: [1, 2.8], count: 2 },\n * // { range: [2.8, 4.6], count: 2 },\n * // { range: [4.6, 6.4], count: 2 },\n * // { range: [6.4, 8.2], count: 2 },\n * // { range: [8.2, 10], count: 2 }\n * // ]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Response time distribution analysis\n * function analyzeResponseTimes(times: number[]): void {\n * const histogram = calculateHistogram(times, 5)\n *\n * console.log('📊 Response Time Distribution:')\n * histogram.forEach(({ range, count }) => {\n * const bar = '█'.repeat(count)\n * console.log(`${range[0]}-${range[1]}ms: ${bar} (${count})`)\n * })\n *\n * // Identify slow requests\n * const slowBin = histogram[histogram.length - 1]\n * if (slowBin.count > histogram.length * 0.1) {\n * console.log(`⚠️ Warning: ${slowBin.count} requests in slowest bin`)\n * }\n * }\n *\n * const responseTimes = [\n * 120, 150, 180, 200, 220,\n * 250, 300, 350, 400, 5000\n * ]\n * analyzeResponseTimes(responseTimes)\n * // 120-1096ms: ████████ (8)\n * // ...\n * // 4024-5000ms: █ (1)\n * // ⚠️ Warning: 1 requests in slowest bin\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Salary distribution for HR analysis\n * interface Employee {\n * name: string\n * salary: number\n * }\n *\n * function analyzeSalaryDistribution(employees: Employee[]): void {\n * const salaries = employees.map(e => e.salary)\n * const histogram = calculateHistogram(salaries, 4)\n *\n * console.log('💰 Salary Distribution:')\n * histogram.forEach(({ range, count }, i) => {\n * const percentage = ((count / employees.length) * 100).toFixed(1)\n * console.log(`Band ${i + 1}: $${range[0].toLocaleString()}-$${range[1].toLocaleString()}`)\n * console.log(` Employees: ${count} (${percentage}%)`)\n * })\n * }\n *\n * const employees = [\n * { name: 'Alice', salary: 50000 },\n * { name: 'Bob', salary: 60000 },\n * { name: 'Charlie', salary: 75000 },\n * { name: 'David', salary: 90000 },\n * { name: 'Eve', salary: 120000 }\n * ]\n * analyzeSalaryDistribution(employees)\n * // Band 1: $50,000-$67,500 (2 employees - 40%)\n * // Band 2: $67,500-$85,000 (1 employee - 20%)\n * // ...\n * ```\n *\n * @see {@link calculatePercentile} for quantile analysis\n * @see {@link calculateQuartiles} for quartile-based binning\n */\nexport const calculateHistogram = (\n values: number[],\n bins: number\n): Array<{ range: [number, number]; count: number }> => {\n if (!values.length || bins <= 0) return []\n\n const min = Math.min(...values)\n const max = Math.max(...values)\n const binWidth = (max - min) / bins\n\n const histogram: Array<{ range: [number, number]; count: number }> = []\n\n for (let i = 0; i < bins; i++) {\n const rangeStart = min + i * binWidth\n const rangeEnd = i === bins - 1 ? max : rangeStart + binWidth\n\n const count = values.filter(\n value => value >= rangeStart && (i === bins - 1 ? value <= rangeEnd : value < rangeEnd)\n ).length\n\n histogram.push({\n range: [roundToDecimals(rangeStart, 2), roundToDecimals(rangeEnd, 2)],\n count,\n })\n }\n\n return histogram\n}\n\n// =============================================================================\n// BASIC MACHINE LEARNING UTILITIES\n// =============================================================================\n\n/**\n * Calculates Euclidean distance (straight-line distance) between two n-dimensional points\n *\n * Euclidean distance is the \"ordinary\" straight-line distance between two points.\n * Formula: √Σ(p1ᵢ - p2ᵢ)² for all dimensions\n *\n * Use cases:\n * - Machine learning (K-NN, K-Means clustering)\n * - Similarity measurement\n * - Computer vision (object detection)\n * - Geospatial calculations (2D/3D coordinates)\n *\n * @param point1 - First n-dimensional point [x, y, z, ...]\n * @param point2 - Second n-dimensional point [x, y, z, ...]\n * @returns Euclidean distance between the two points\n * @throws {Error} If points have different dimensions\n *\n * @example\n * ```typescript\n * // 2D distance (x, y coordinates)\n * calculateEuclideanDistance([0, 0], [3, 4]) // 5 (3-4-5 triangle)\n * calculateEuclideanDistance([1, 2], [4, 6]) // 5\n *\n * // 3D distance\n * calculateEuclideanDistance([0, 0, 0], [1, 1, 1]) // ~1.73 (√3)\n *\n * // High-dimensional (ML features)\n * calculateEuclideanDistance([1, 2, 3, 4], [2, 3, 4, 5]) // 2\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: K-Nearest Neighbors classification\n * interface User {\n * age: number\n * income: number\n * }\n *\n * function findNearestUsers(target: User, candidates: User[], k: number): User[] {\n * const distances = candidates.map(candidate => ({\n * user: candidate,\n * distance: calculateEuclideanDistance(\n * [target.age, target.income],\n * [candidate.age, candidate.income]\n * )\n * }))\n *\n * return distances\n * .sort((a, b) => a.distance - b.distance)\n * .slice(0, k)\n * .map(d => d.user)\n * }\n *\n * const target = { age: 30, income: 50000 }\n * const users = [\n * { age: 28, income: 48000 },\n * { age: 45, income: 80000 },\n * { age: 32, income: 52000 }\n * ]\n * findNearestUsers(target, users, 2)\n * // Returns 2 closest users by age/income\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Product recommendation similarity\n * interface Product {\n * price: number\n * rating: number\n * reviews: number\n * }\n *\n * function findSimilarProducts(\n * current: Product,\n * catalog: Product[]\n * ): Product[] {\n * const similarities = catalog.map(product => {\n * const distance = calculateEuclideanDistance(\n * [current.price, current.rating * 20, Math.log(current.reviews)],\n * [product.price, product.rating * 20, Math.log(product.reviews)]\n * )\n * return { product, similarity: 1 / (1 + distance) }\n * })\n *\n * return similarities\n * .sort((a, b) => b.similarity - a.similarity)\n * .slice(0, 5)\n * .map(s => s.product)\n * }\n * ```\n *\n * @see {@link calculateManhattanDistance} for taxicab distance (sum of absolute differences)\n * @see {@link simpleKMeans} for K-Means clustering using Euclidean distance\n */\nexport const calculateEuclideanDistance = (point1: number[], point2: number[]): number => {\n if (point1.length !== point2.length) {\n throw new Error('Points must have the same number of dimensions')\n }\n\n const squaredDiffs = point1.map((val, index) => Math.pow(val - point2[index], 2))\n return Math.sqrt(sum(squaredDiffs))\n}\n\n/**\n * Calculates Manhattan distance (taxicab/city block distance) between two n-dimensional points\n *\n * Manhattan distance is the sum of absolute differences in each dimension.\n * Formula: Σ|p1ᵢ - p2ᵢ| for all dimensions\n *\n * Named after Manhattan grid layout where you can only travel along streets (not diagonally).\n * Often more appropriate than Euclidean for grid-based movement or high-dimensional data.\n *\n * Use cases:\n * - Grid-based pathfinding (chess, robots)\n * - High-dimensional ML (less affected by curse of dimensionality)\n * - City distance calculations (street blocks)\n * - Outlier detection in sparse data\n *\n * @param point1 - First n-dimensional point [x, y, z, ...]\n * @param point2 - Second n-dimensional point [x, y, z, ...]\n * @returns Manhattan distance between the two points\n * @throws {Error} If points have different dimensions\n *\n * @example\n * ```typescript\n * // 2D Manhattan distance\n * calculateManhattanDistance([0, 0], [3, 4]) // 7 (3 + 4)\n * calculateManhattanDistance([1, 2], [4, 6]) // 7 (3 + 4)\n *\n * // Compare with Euclidean\n * calculateEuclideanDistance([0, 0], [3, 4]) // 5\n * calculateManhattanDistance([0, 0], [3, 4]) // 7\n *\n * // 3D distance\n * calculateManhattanDistance([0, 0, 0], [1, 1, 1]) // 3 (1+1+1)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: City block distance (taxi routing)\n * interface Location {\n * avenue: number // East-West\n * street: number // North-South\n * }\n *\n * function calculateTaxiFare(from: Location, to: Location): number {\n * const blocks = calculateManhattanDistance(\n * [from.avenue, from.street],\n * [to.avenue, to.street]\n * )\n * const baseFare = 3.50\n * const perBlock = 0.70\n * return baseFare + blocks * perBlock\n * }\n *\n * const start = { avenue: 5, street: 10 }\n * const end = { avenue: 12, street: 20 }\n * calculateTaxiFare(start, end)\n * // Blocks: 17, Fare: $15.40\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Chess king moves (Chebyshev) vs rook moves (Manhattan)\n * function calculateRookMoves(from: [number, number], to: [number, number]): number {\n * // Rook can move straight, so Manhattan distance = moves needed\n * return calculateManhattanDistance(from, to)\n * }\n *\n * calculateRookMoves([0, 0], [3, 4]) // 7 moves minimum\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: High-dimensional text similarity\n * function compareDocuments(doc1Vector: number[], doc2Vector: number[]): number {\n * // Manhattan often works better than Euclidean for sparse high-dim data\n * return calculateManhattanDistance(doc1Vector, doc2Vector)\n * }\n *\n * const doc1 = [0, 3, 0, 5, 0, 2] // Word frequency vector\n * const doc2 = [1, 2, 0, 4, 0, 3]\n * compareDocuments(doc1, doc2) // 5 (difference in word frequencies)\n * ```\n *\n * @see {@link calculateEuclideanDistance} for straight-line distance\n * @see {@link simpleKMeans} for clustering algorithm\n */\nexport const calculateManhattanDistance = (point1: number[], point2: number[]): number => {\n if (point1.length !== point2.length) {\n throw new Error('Points must have the same number of dimensions')\n }\n\n return sum(point1.map((val, index) => Math.abs(val - point2[index])))\n}\n\n/**\n * Implements simple K-Means clustering algorithm\n *\n * Groups data points into K clusters by minimizing within-cluster variance.\n * Uses Euclidean distance and iterative centroid updates until convergence.\n *\n * Algorithm:\n * 1. Initialize K centroids randomly from data points\n * 2. Assign each point to nearest centroid (Euclidean distance)\n * 3. Recalculate centroids as mean of assigned points\n * 4. Repeat steps 2-3 until convergence or max iterations\n *\n * Limitations:\n * - Requires knowing K in advance\n * - Sensitive to initial centroid placement (random)\n * - Assumes spherical clusters\n * - Can get stuck in local minima\n *\n * @param points - Array of n-dimensional points to cluster\n * @param k - Number of clusters to create\n * @param maxIterations - Maximum iterations before stopping (default: 100)\n * @returns Object with {centroids: K cluster centers, clusters: array mapping point index → cluster ID}\n *\n * @example\n * ```typescript\n * // Basic 2D clustering\n * const points = [\n * [1, 1], [2, 1], [1, 2], // Cluster 1 (bottom-left)\n * [8, 8], [9, 8], [8, 9] // Cluster 2 (top-right)\n * ]\n *\n * const { centroids, clusters } = simpleKMeans(points, 2)\n * console.log(centroids) // [[1.33, 1.33], [8.33, 8.33]]\n * console.log(clusters) // [0, 0, 0, 1, 1, 1]\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Customer segmentation\n * interface Customer {\n * age: number\n * income: number\n * spendingScore: number\n * }\n *\n * function segmentCustomers(customers: Customer[], segments: number) {\n * const points = customers.map(c => [c.age, c.income / 1000, c.spendingScore])\n * const { centroids, clusters } = simpleKMeans(points, segments)\n *\n * const segmented = customers.map((customer, i) => ({\n * ...customer,\n * segment: clusters[i]\n * }))\n *\n * console.log('📊 Customer Segments:')\n * centroids.forEach((centroid, i) => {\n * const count = clusters.filter(c => c === i).length\n * console.log(`Segment ${i + 1}: ${count} customers`)\n * console.log(` Avg age: ${centroid[0].toFixed(1)}`)\n * console.log(` Avg income: $${(centroid[1] * 1000).toLocaleString()}`)\n * console.log(` Avg spending: ${centroid[2].toFixed(1)}/100`)\n * })\n *\n * return segmented\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Image color quantization (reduce colors)\n * function quantizeColors(pixels: [number, number, number][], colors: number) {\n * // Each pixel is [R, G, B]\n * const { centroids, clusters } = simpleKMeans(pixels, colors)\n *\n * // Replace each pixel with its cluster centroid color\n * return pixels.map((_, i) => {\n * const cluster = clusters[i]\n * return centroids[cluster].map(Math.round) as [number, number, number]\n * })\n * }\n *\n * // Reduce 16M colors to 8 dominant colors\n * const pixels: [number, number, number][] = [\n * [255, 100, 50], [250, 110, 55], // Similar reds\n * [50, 200, 100], [55, 210, 105] // Similar greens\n * ]\n * quantizeColors(pixels, 2)\n * // Groups similar colors into 2 clusters\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Anomaly detection in server metrics\n * interface ServerMetrics {\n * cpuUsage: number // 0-100%\n * memoryUsage: number // 0-100%\n * responseTime: number // ms\n * }\n *\n * function detectAnomalies(metrics: ServerMetrics[]): number[] {\n * const points = metrics.map(m => [\n * m.cpuUsage,\n * m.memoryUsage,\n * m.responseTime / 10 // Scale to similar range\n * ])\n *\n * const { centroids, clusters } = simpleKMeans(points, 3)\n *\n * // Find cluster with highest avg response time\n * const clusterAvgs = centroids.map(c => c[2] * 10)\n * const anomalyCluster = clusterAvgs.indexOf(Math.max(...clusterAvgs))\n *\n * // Return indices of anomalous metrics\n * return clusters\n * .map((cluster, i) => cluster === anomalyCluster ? i : -1)\n * .filter(i => i !== -1)\n * }\n * ```\n *\n * @see {@link calculateEuclideanDistance} for distance metric used\n * @see {@link normalizeToRange} for feature scaling before clustering\n */\nexport const simpleKMeans = (\n points: number[][],\n k: number,\n maxIterations = 100\n): { centroids: number[][]; clusters: number[] } => {\n if (points.length === 0 || k <= 0) {\n return { centroids: [], clusters: [] }\n }\n\n const dimensions = points[0].length\n\n // Initialize centroids randomly\n let centroids: number[][] = []\n for (let i = 0; i < k; i++) {\n const randomPoint = points[Math.floor(Math.random() * points.length)]\n centroids.push([...randomPoint])\n }\n\n const clusters: number[] = new Array(points.length)\n\n for (let iteration = 0; iteration < maxIterations; iteration++) {\n let hasChanged = false\n\n // Assign points to clusters\n for (let i = 0; i < points.length; i++) {\n let minDistance = Infinity\n let closestCentroid = 0\n\n for (let j = 0; j < centroids.length; j++) {\n const distance = calculateEuclideanDistance(points[i], centroids[j])\n if (distance < minDistance) {\n minDistance = distance\n closestCentroid = j\n }\n }\n\n if (clusters[i] !== closestCentroid) {\n hasChanged = true\n clusters[i] = closestCentroid\n }\n }\n\n // Update centroids\n const newCentroids: number[][] = new Array(k).fill(0).map(() => new Array(dimensions).fill(0))\n const clusterCounts: number[] = new Array(k).fill(0)\n\n for (let i = 0; i < points.length; i++) {\n const cluster = clusters[i]\n clusterCounts[cluster]++\n\n for (let dim = 0; dim < dimensions; dim++) {\n newCentroids[cluster][dim] += points[i][dim]\n }\n }\n\n for (let i = 0; i < k; i++) {\n if (clusterCounts[i] > 0) {\n for (let dim = 0; dim < dimensions; dim++) {\n newCentroids[i][dim] /= clusterCounts[i]\n }\n }\n }\n\n centroids = newCentroids\n\n if (!hasChanged) break\n }\n\n return { centroids, clusters }\n}\n","/**\n * Number utilities\n */\n\n/**\n * Verifica si un valor es numéricamente válido o convertible a número.\n * Acepta números y cadenas que representan números válidos.\n * @param value - El valor a verificar.\n * @returns true si el valor es numéricamente válido, false en caso contrario.\n * @example\n * ```ts\n * isNumericValue(5) // true\n * isNumericValue(\"5\") // true\n * isNumericValue(\"12.34\") // true\n * isNumericValue(\"-42\") // true\n * isNumericValue(\"abc\") // false\n * isNumericValue(\"\") // false\n * isNumericValue(\" \") // false\n * isNumericValue(null) // false\n * isNumericValue(undefined) // false\n * isNumericValue(NaN) // false\n * isNumericValue(Infinity) // false\n * ```\n */\nexport function isNumericValue(value: any): boolean {\n if (value === null || value === undefined) return false\n if (typeof value === 'number') return !isNaN(value) && isFinite(value)\n if (typeof value === 'string') return value.trim() !== '' && !isNaN(Number(value))\n return false\n}\n\n/**\n * Rounds a number to a specified number of decimal places\n * @param num - The number to round\n * @param decimals - Number of decimal places (default: 2)\n * @returns The rounded number\n * @example\n * ```ts\n * roundToDecimals(3.14159, 2) // 3.14\n * roundToDecimals(-2.7182, 3) // -2.718\n * ```\n */\nexport function roundToDecimals(num: number, decimals: number = 2): number {\n const factor = Math.pow(10, decimals)\n // Use sign-aware rounding to handle negative numbers correctly\n return num >= 0 ? Math.round(num * factor) / factor : -Math.round(Math.abs(num) * factor) / factor\n}\n","/**\n * Asynchronous utilities and operations\n * Consolidated from core/async module\n */\n\n/* eslint-disable no-await-in-loop */\n\nimport { TsHelpersError, TsHelpersErrorCode } from './errors'\n\n// =============================================================================\n// DELAY UTILITIES\n// =============================================================================\n\n/**\n * Creates an asynchronous delay for the specified number of milliseconds\n *\n * Pauses async execution without blocking the event loop. Uses Promise with setTimeout\n * internally to schedule resumption after the specified delay.\n *\n * Common use cases:\n * - Rate limiting API calls\n * - Retry delays with exponential backoff\n * - Animation/transition timing\n * - Polling intervals\n * - Debouncing operations\n *\n * @param ms - Milliseconds to sleep (delay duration)\n * @returns Promise that resolves after the specified delay\n *\n * @example\n * ```typescript\n * // Basic delay\n * console.log('Starting...')\n * await sleep(2000) // Wait 2 seconds\n * console.log('Done!')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Rate-limited API calls\n * async function fetchAllUsers(userIds: string[]): Promise<User[]> {\n * const users: User[] = []\n *\n * for (const id of userIds) {\n * const user = await api.getUser(id)\n * users.push(user)\n *\n * // Rate limit: 100ms between requests (max 10 req/sec)\n * await sleep(100)\n * }\n *\n * return users\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Exponential backoff retry\n * async function fetchWithRetry(url: string, maxRetries = 3): Promise<Response> {\n * let lastError: Error | null = null\n *\n * for (let attempt = 0; attempt < maxRetries; attempt++) {\n * try {\n * return await fetch(url)\n * } catch (error) {\n * lastError = error as Error\n * const delay = Math.pow(2, attempt) * 1000 // 1s, 2s, 4s\n * console.log(`Retry ${attempt + 1}/${maxRetries} in ${delay}ms`)\n * await sleep(delay)\n * }\n * }\n *\n * throw lastError\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Polling with timeout\n * async function pollUntilReady(\n * checkFn: () => Promise<boolean>,\n * timeoutMs = 30000\n * ): Promise<boolean> {\n * const startTime = Date.now()\n *\n * while (Date.now() - startTime < timeoutMs) {\n * if (await checkFn()) {\n * return true\n * }\n * await sleep(1000) // Poll every second\n * }\n *\n * throw new Error('Timeout waiting for ready state')\n * }\n *\n * // Usage: Wait for service to be ready\n * await pollUntilReady(async () => {\n * const response = await fetch('/health')\n * return response.ok\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Animated progress bar\n * async function animateProgress(element: HTMLElement): Promise<void> {\n * for (let i = 0; i <= 100; i += 5) {\n * element.style.width = `${i}%`\n * await sleep(50) // 50ms per step = 1 second total\n * }\n * }\n * ```\n *\n * @see {@link wait} for alias with same functionality\n * @see {@link runBatch} for controlled concurrent execution\n */\nexport const sleep = (ms: number): Promise<void> => {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * Simple alias for sleep - Pauses execution for specified milliseconds\n *\n * Identical to {@link sleep}, provided for semantic clarity in code.\n * Use `wait` when the context emphasizes waiting for a condition or event.\n *\n * @param ms - Milliseconds to wait\n * @returns Promise that resolves after the specified delay\n *\n * @example\n * ```typescript\n * // Semantically clearer in some contexts\n * await wait(1000) // Wait 1 second before continuing\n *\n * // vs sleep (implies intentional delay)\n * await sleep(1000) // Sleep for 1 second\n * ```\n *\n * @see {@link sleep} for full documentation and examples\n */\nexport const wait = (ms: number): Promise<void> => sleep(ms)\n\n// =============================================================================\n// BATCH PROCESSING\n// =============================================================================\n\n/**\n * Executes an array of Promises in batches to control concurrency\n *\n * Processes promises in sequential batches, waiting for each batch to complete before\n * starting the next. Prevents overwhelming systems with too many concurrent requests.\n *\n * Algorithm:\n * 1. Divide promises into batches of size `batchSize`\n * 2. Execute each batch with Promise.all (parallel within batch)\n * 3. Wait for batch completion before starting next batch\n * 4. Collect and return all results in original order\n *\n * Use cases:\n * - Rate-limited API calls (respect API quotas)\n * - Database bulk operations (avoid connection pool exhaustion)\n * - File system operations (prevent file descriptor limits)\n * - Memory-intensive operations (control memory usage)\n *\n * @param jobs - Array of Promises to execute\n * @param batchSize - Number of promises to execute concurrently per batch (default: 50)\n * @returns Promise resolving to array of all results in original order\n *\n * @example\n * ```typescript\n * // Basic batch processing\n * const urls = ['url1', 'url2', ..., 'url100'] // 100 URLs\n * const fetchPromises = urls.map(url => fetch(url))\n *\n * // Execute 10 at a time instead of all 100 simultaneously\n * const responses = await runBatch(fetchPromises, 10)\n * // Batch 1: urls 0-9 (parallel)\n * // Batch 2: urls 10-19 (parallel) - starts after batch 1 completes\n * // ... 10 batches total\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Bulk user data fetch respecting API rate limits\n * async function fetchUsersInBatches(userIds: string[]): Promise<User[]> {\n * console.log(`Fetching ${userIds.length} users in batches of 20...`)\n *\n * const fetchPromises = userIds.map(id =>\n * fetch(`/api/users/${id}`).then(res => res.json())\n * )\n *\n * const users = await runBatch(fetchPromises, 20)\n *\n * console.log(`✅ Fetched ${users.length} users`)\n * return users\n * }\n *\n * // Fetches 1000 users: 50 batches of 20, not 1000 simultaneous requests\n * const allUsers = await fetchUsersInBatches(userIdArray)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Database bulk insert with connection pool limits\n * async function bulkInsertUsers(users: User[]): Promise<void> {\n * // Database pool has 10 connections, use batch size of 5 for safety\n * const insertPromises = users.map(user =>\n * db.query('INSERT INTO users VALUES ($1, $2)', [user.name, user.email])\n * )\n *\n * await runBatch(insertPromises, 5)\n * console.log(`✅ Inserted ${users.length} users`)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Image processing pipeline\n * async function processImages(imagePaths: string[]): Promise<Buffer[]> {\n * console.log(`Processing ${imagePaths.length} images...`)\n *\n * const processingPromises = imagePaths.map(async path => {\n * const img = await loadImage(path)\n * const resized = await resize(img, { width: 800, height: 600 })\n * const compressed = await compress(resized, { quality: 80 })\n * return compressed\n * })\n *\n * // Process 3 images at a time to avoid memory exhaustion\n * const processed = await runBatch(processingPromises, 3)\n *\n * console.log(`✅ Processed ${processed.length} images`)\n * return processed\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Parallel file uploads with progress tracking\n * async function uploadFilesWithProgress(\n * files: File[]\n * ): Promise<UploadResult[]> {\n * let completed = 0\n *\n * const uploadPromises = files.map(async file => {\n * const result = await uploadToS3(file)\n * completed++\n * console.log(`Progress: ${completed}/${files.length} (${((completed/files.length)*100).toFixed(1)}%)`)\n * return result\n * })\n *\n * // Upload 5 files at a time\n * return await runBatch(uploadPromises, 5)\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Scraping with politeness delay\n * async function scrapeWebsites(urls: string[]): Promise<ScrapedData[]> {\n * const scrapePromises = urls.map(async url => {\n * const html = await fetch(url).then(r => r.text())\n * const data = parseHTML(html)\n *\n * // Polite delay between requests in same batch\n * await sleep(200)\n *\n * return data\n * })\n *\n * // Only 3 concurrent requests to avoid overwhelming target server\n * return await runBatch(scrapePromises, 3)\n * }\n * ```\n *\n * @see {@link sleep} for adding delays between operations\n * @see {@link handleOperation} for dynamic operation execution\n */\nexport async function runBatch<T>(jobs: Promise<T>[], batchSize: number = 50): Promise<T[]> {\n if (batchSize <= 0) {\n throw new TsHelpersError('Batch size must be greater than 0', {\n code: TsHelpersErrorCode.INVALID_OPERATION,\n data: { batchSize },\n })\n }\n\n const results: T[] = []\n const batches = Math.ceil(jobs.length / batchSize)\n\n for (let i = 0; i < batches; i++) {\n const batchStart = i * batchSize\n const batchEnd = batchStart + batchSize\n const batch = jobs.slice(batchStart, batchEnd)\n\n const batchResults = await Promise.all(batch.map(job => job))\n results.push(...batchResults)\n }\n\n return results\n}\n\n// =============================================================================\n// DYNAMIC OPERATION UTILITIES\n// =============================================================================\n\n/**\n * Dynamically executes an operation on a target object by name\n *\n * Invokes methods on objects using string-based operation names. Supports nested\n * method access using 'parent/child' slash notation for organized operation namespacing.\n *\n * Features:\n * - Dynamic method invocation by string name\n * - Nested method access with '/' separator (e.g., 'api/getUser')\n * - Automatic error handling with descriptive messages\n * - Type-safe return value with generics\n *\n * Use cases:\n * - Dynamic API route handlers\n * - Plugin architectures with string-based commands\n * - RPC (Remote Procedure Call) implementations\n * - Command pattern implementations\n * - Configuration-driven operations\n *\n * @param target - Object containing methods to execute\n * @param operation - Method name or 'parent/child' path to execute\n * @param args - Arguments to pass to the operation\n * @returns Promise resolving to operation result\n * @throws {TsHelpersError} If operation doesn't exist on target\n *\n * @example\n * ```typescript\n * // Basic operation execution\n * const api = {\n * getUser: async (id: string) => ({ id, name: 'John' }),\n * createUser: async (data: any) => ({ id: '123', ...data })\n * }\n *\n * const user = await handleOperation<User>(api, 'getUser', 'user-123')\n * // { id: 'user-123', name: 'John' }\n * ```\n *\n * @example\n * ```typescript\n * // Nested operations with slash notation\n * const service = {\n * users: {\n * list: async () => [{ id: '1' }, { id: '2' }],\n * create: async (data: any) => ({ id: 'new', ...data }),\n * delete: async (id: string) => ({ success: true })\n * },\n * posts: {\n * list: async () => [{ id: 'post-1' }],\n * create: async (data: any) => ({ id: 'new-post', ...data })\n * }\n * }\n *\n * // Execute nested operation\n * const users = await handleOperation(service, 'users/list')\n * const newUser = await handleOperation(service, 'users/create', { name: 'Alice' })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dynamic API router\n * interface ApiRequest {\n * operation: string\n * params: any[]\n * }\n *\n * const apiHandlers = {\n * user: {\n * get: async (id: string) => db.users.findById(id),\n * create: async (data: UserInput) => db.users.create(data),\n * update: async (id: string, data: Partial<UserInput>) =>\n * db.users.update(id, data),\n * delete: async (id: string) => db.users.delete(id)\n * },\n * product: {\n * search: async (query: string) => db.products.search(query),\n * list: async (page: number) => db.products.list(page)\n * }\n * }\n *\n * async function handleApiRequest(req: ApiRequest): Promise<any> {\n * try {\n * return await handleOperation(\n * apiHandlers,\n * req.operation,\n * ...req.params\n * )\n * } catch (error) {\n * console.error(`Failed to execute ${req.operation}:`, error)\n * throw error\n * }\n * }\n *\n * // Usage\n * await handleApiRequest({ operation: 'user/get', params: ['user-123'] })\n * await handleApiRequest({ operation: 'product/search', params: ['laptop'] })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Plugin system with dynamic commands\n * interface Plugin {\n * name: string\n * commands: Record<string, (...args: any[]) => Promise<any>>\n * }\n *\n * class PluginManager {\n * private plugins: Map<string, Plugin> = new Map()\n *\n * register(plugin: Plugin): void {\n * this.plugins.set(plugin.name, plugin)\n * }\n *\n * async executeCommand(\n * pluginName: string,\n * command: string,\n * ...args: any[]\n * ): Promise<any> {\n * const plugin = this.plugins.get(pluginName)\n * if (!plugin) throw new Error(`Plugin ${pluginName} not found`)\n *\n * return handleOperation(plugin.commands, command, ...args)\n * }\n * }\n *\n * // Register plugins\n * const manager = new PluginManager()\n * manager.register({\n * name: 'fileOps',\n * commands: {\n * read: async (path: string) => fs.readFile(path, 'utf-8'),\n * write: async (path: string, content: string) =>\n * fs.writeFile(path, content)\n * }\n * })\n *\n * // Execute plugin commands dynamically\n * await manager.executeCommand('fileOps', 'read', './config.json')\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: RPC-style service calls\n * const rpcService = {\n * math: {\n * add: async (a: number, b: number) => a + b,\n * multiply: async (a: number, b: number) => a * b\n * },\n * string: {\n * reverse: async (s: string) => s.split('').reverse().join(''),\n * uppercase: async (s: string) => s.toUpperCase()\n * }\n * }\n *\n * async function rpcCall(method: string, ...params: any[]): Promise<any> {\n * console.log(`RPC Call: ${method}(${params.join(', ')})`)\n * const result = await handleOperation(rpcService, method, ...params)\n * console.log(`RPC Result: ${result}`)\n * return result\n * }\n *\n * await rpcCall('math/add', 5, 3) // RPC Result: 8\n * await rpcCall('string/reverse', 'hello') // RPC Result: olleh\n * ```\n *\n * @example\n * ```typescript\n * // Error handling\n * try {\n * await handleOperation(api, 'nonexistent/method')\n * } catch (error) {\n * console.error(error.message)\n * // \"Operation [nonexistent/method] does not exist\"\n * console.error(error.code)\n * // TsHelpersErrorCode.INVALID_OPERATION\n * }\n * ```\n *\n * @see {@link TsHelpersError} for error structure\n * @see {@link TsHelpersErrorCode} for error codes\n */\nexport function handleOperation<T>(\n target: Record<string, any>,\n operation: string,\n ...args: any[]\n): Promise<T> {\n if (operation.includes('/')) {\n const [parentOp, childOp] = operation.split('/')\n\n if (!target[parentOp] || !target[parentOp][childOp]) {\n throw new TsHelpersError(`Operation [${operation}] does not exist`, {\n code: TsHelpersErrorCode.INVALID_OPERATION,\n data: { operation, parentOp, childOp },\n })\n }\n\n return target[parentOp][childOp](...args)\n }\n\n if (!target[operation]) {\n throw new TsHelpersError(`Operation [${operation}] does not exist`, {\n code: TsHelpersErrorCode.INVALID_OPERATION,\n data: { operation },\n })\n }\n\n return target[operation](...args)\n}\n","/**\n * Error handling utilities with specific error types and codes\n * Provides structured error handling for validation, data processing, and environment issues\n */\n\n/**\n * Enumeration of specific error codes for different failure scenarios\n * @example\n * ```ts\n * // Using error codes for type-safe error handling\n * try {\n * validateNIF('invalid')\n * } catch (error) {\n * if (error.code === TsHelpersErrorCode.VALIDATION_FAILED) {\n * console.log('Validation error:', error.data)\n * }\n * }\n * ```\n */\nexport enum TsHelpersErrorCode {\n /** Validation of input data failed (NIF, email, etc.) */\n VALIDATION_FAILED = 'VALIDATION_FAILED',\n /** Error processing data (CSV, JSON, aggregations, etc.) */\n DATA_PROCESSING_FAILED = 'DATA_PROCESSING_FAILED',\n /** Current environment doesn't support the operation */\n ENVIRONMENT_NOT_SUPPORTED = 'ENVIRONMENT_NOT_SUPPORTED',\n /** File format not supported for import/export */\n UNSUPPORTED_FORMAT = 'UNSUPPORTED_FORMAT',\n /** File system operation failed */\n FILE_ERROR = 'FILE_ERROR',\n /** Network or fetch operation failed */\n NETWORK_ERROR = 'NETWORK_ERROR',\n /** Invalid operation or function call */\n INVALID_OPERATION = 'INVALID_OPERATION',\n /** Crypto operation failed (hash, token generation) */\n CRYPTO_ERROR = 'CRYPTO_ERROR',\n /** Math calculation failed (invalid input, division by zero) */\n MATH_ERROR = 'MATH_ERROR',\n /** Generic unknown error */\n UNKNOWN_ERROR = 'UNKNOWN_ERROR',\n}\n\n/**\n * Options for creating TsHelpersError instances\n */\nexport interface TsHelpersErrorOptions {\n /** Specific error code for categorization */\n code?: TsHelpersErrorCode\n /** Additional data about the error context */\n data?: any\n /** Original error that caused this error */\n cause?: Error\n}\n\n/**\n * Main error class for @g10/ts-helpers with structured error information\n * @example\n * ```ts\n * // Creating structured errors\n * throw new TsHelpersError('Invalid NIF format', {\n * code: TsHelpersErrorCode.VALIDATION_FAILED,\n * data: { input: '12345', expected: '8 digits + letter' }\n * })\n *\n * // Error handling with type checking\n * try {\n * someOperation()\n * } catch (error) {\n * if (error instanceof TsHelpersError) {\n * console.log('Error code:', error.code)\n * console.log('Error data:', error.data)\n * }\n * }\n * ```\n */\nexport class TsHelpersError extends Error {\n public readonly code?: TsHelpersErrorCode\n public readonly data?: any\n public readonly cause?: Error\n\n constructor(message: string, options: TsHelpersErrorOptions = {}) {\n super(message)\n this.name = 'TsHelpersError'\n this.code = options.code\n this.data = options.data\n this.cause = options.cause\n\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, TsHelpersError)\n }\n }\n}\n\n/**\n * Specialized error class for data processing operations\n * @example\n * ```ts\n * // Data processing errors\n * throw new DataError(\n * 'Failed to parse CSV',\n * TsHelpersErrorCode.DATA_PROCESSING_FAILED,\n * { line: 5, column: 'amount' }\n * )\n * ```\n */\nexport class DataError extends TsHelpersError {\n constructor(message: string, code?: TsHelpersErrorCode, data?: any) {\n super(message, { code, data })\n this.name = 'DataError'\n }\n}\n\n/**\n * Creates a validation error with structured information\n * @param message - Descriptive error message\n * @param field - Field name that failed validation\n * @param value - Value that failed validation\n * @returns TsHelpersError with validation context\n * @example\n * ```ts\n * // Using in validation functions\n * if (!isValidEmail(email)) {\n * throw createValidationError('Invalid email format', 'email', email)\n * }\n *\n * // Error contains structured data\n * // error.code === TsHelpersErrorCode.VALIDATION_FAILED\n * // error.data === { field: 'email', value: 'invalid-email' }\n * ```\n */\nexport function createValidationError(message: string, field: string, value: any): TsHelpersError {\n return new TsHelpersError(`Validation failed: ${message}`, {\n code: TsHelpersErrorCode.VALIDATION_FAILED,\n data: { field, value },\n })\n}\n\n/**\n * Creates a crypto operation error\n * @param message - Descriptive error message\n * @param operation - Crypto operation that failed\n * @param details - Additional error details\n * @returns TsHelpersError with crypto context\n * @example\n * ```ts\n * // Using in crypto functions\n * if (!crypto.getRandomValues) {\n * throw createCryptoError('Web Crypto API not available', 'generateSecureToken', {\n * environment: 'browser',\n * fallback: 'Math.random'\n * })\n * }\n * ```\n */\nexport function createCryptoError(\n message: string,\n operation: string,\n details?: any\n): TsHelpersError {\n return new TsHelpersError(`Crypto error: ${message}`, {\n code: TsHelpersErrorCode.CRYPTO_ERROR,\n data: { operation, details },\n })\n}\n\n/**\n * Creates a math calculation error\n * @param message - Descriptive error message\n * @param operation - Math operation that failed\n * @param input - Input data that caused the error\n * @returns TsHelpersError with math context\n * @example\n * ```ts\n * // Using in math functions\n * if (values.length === 0) {\n * throw createMathError('Cannot calculate median of empty array', 'calculateMedian', values)\n * }\n * ```\n */\nexport function createMathError(message: string, operation: string, input?: any): TsHelpersError {\n return new TsHelpersError(`Math error: ${message}`, {\n code: TsHelpersErrorCode.MATH_ERROR,\n data: { operation, input },\n })\n}\n","/**\n * Data manipulation utilities for multiple formats with automatic detection\n * Consolidated from data/index module\n */\n\n/* eslint-disable max-lines-per-function */\n\nimport { DataError, TsHelpersErrorCode, createValidationError } from './errors'\nimport { isNode, isBrowser } from './environment'\n\n// =============================================================================\n// SHARED TYPES\n// =============================================================================\n\n/**\n * Type for data - array of objects or array of arrays (for CSV, etc.)\n */\nexport type ExportData = Record<string, any>[] | string[][]\n\n/**\n * Type for imported data - can include string for .tree files\n */\nexport type ImportData = ExportData | string | any\n\n/**\n * Type for CSV data (backward compatibility)\n */\nexport type CSVData = ExportData\n\n/**\n * Supported format types\n */\nexport type ExportFormat = 'csv' | 'json' | 'tree' | 'txt'\n\n/**\n * Universal file format detection - detects any file extension\n */\nexport type FileFormat = string\n\n// =============================================================================\n// ENVIRONMENT UTILITIES\n// =============================================================================\n\n/**\n * Reads a file as text in any environment (Node.js or Browser)\n *\n * Universal file reading utility that adapts to the runtime environment.\n * In Node.js, reads from filesystem. In Browser, reads from File object.\n *\n * Environment behavior:\n * - **Node.js**: Pass file path as string, reads from filesystem\n * - **Browser**: Pass File object (from input[type=\"file\"]), reads with FileReader API\n *\n * @param fileOrPath - File path string (Node.js) or File object (Browser)\n * @param encoding - Text encoding for Node.js filesystem read (default: 'utf8')\n * @returns Promise<string> File contents as text\n *\n * @example\n * ```typescript\n * // Node.js - Read from filesystem\n * const config = await readFileAsText('./config.json')\n * const data = JSON.parse(config)\n *\n * // Browser - Read from File input\n * // HTML: <input type=\"file\" id=\"fileInput\">\n * const input = document.getElementById('fileInput') as HTMLInputElement\n * input.addEventListener('change', async (e) => {\n * const file = e.target.files[0]\n * const content = await readFileAsText(file)\n * console.log('File content:', content)\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Load and parse CSV from user upload (Browser)\n * async function handleCSVUpload(file: File) {\n * const csvText = await readFileAsText(file)\n * const rows = csvText.split('\\n').map(row => row.split(';'))\n * console.log(`Loaded ${rows.length} rows`)\n * return rows\n * }\n * ```\n *\n * @throws {DataError} If called with invalid parameter for current environment\n * @see {@link importData} for format-aware file importing\n */\nexport const readFileAsText = async (\n fileOrPath: string | File,\n encoding: BufferEncoding = 'utf8'\n): Promise<string> => {\n if (isNode() && typeof fileOrPath === 'string') {\n // Node.js environment - read from filesystem\n const fs = await import('fs/promises')\n return fs.readFile(fileOrPath, encoding)\n } else if (isBrowser() && fileOrPath instanceof File) {\n // Browser environment - read File object\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = e => resolve(e.target?.result as string)\n reader.onerror = () => reject(new Error('Error reading file'))\n reader.readAsText(fileOrPath)\n })\n } else {\n throw new DataError(\n 'Invalid parameter for current environment',\n TsHelpersErrorCode.ENVIRONMENT_NOT_SUPPORTED,\n {\n data: {\n isNodeEnv: isNode(),\n isBrowserEnv: isBrowser(),\n parameterType: typeof fileOrPath,\n },\n }\n )\n }\n}\n\n// =============================================================================\n// DATA VALIDATION\n// =============================================================================\n\n/**\n * Validates that data is exportable (array of objects or array of arrays)\n *\n * Ensures data structure is compatible with export formats (CSV, JSON).\n * Validates consistency: all elements must be same type, arrays must have equal length.\n *\n * Validation rules:\n * - Must be non-empty array\n * - If first element is object → all must be objects (no arrays/primitives)\n * - If first element is array → all must be arrays with equal length\n * - Null/undefined not allowed\n *\n * @param data - Data to validate for export\n * @returns `true` if data is valid (type guard for ExportData)\n *\n * @example\n * ```typescript\n * // Valid: Array of objects (typical use case)\n * const users = [\n * { id: 1, name: 'Alice', role: 'Admin' },\n * { id: 2, name: 'Bob', role: 'User' }\n * ]\n * validateExportData(users) // ✅ true\n * await exportData(users, 'users.csv')\n * ```\n *\n * @example\n * ```typescript\n * // Valid: Array of arrays (matrix/tabular data)\n * const matrix = [\n * ['Name', 'Age', 'City'],\n * ['Alice', 25, 'Madrid'],\n * ['Bob', 30, 'Barcelona']\n * ]\n * validateExportData(matrix) // ✅ true\n * await exportData(matrix, 'data.csv')\n * ```\n *\n * @example\n * ```typescript\n * // Invalid: Mixed types - throws ValidationError\n * const mixed = [\n * { id: 1, name: 'Alice' },\n * ['Bob', 30] // ❌ Array mixed with object\n * ]\n * try {\n * validateExportData(mixed)\n * } catch (error) {\n * console.error(error.message)\n * // 'All elements must be objects if first one is an object'\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Invalid: Inconsistent array lengths - throws ValidationError\n * const uneven = [\n * ['Alice', 25, 'Madrid'],\n * ['Bob', 30] // ❌ Missing city\n * ]\n * try {\n * validateExportData(uneven)\n * } catch (error) {\n * console.error(error.message)\n * // 'Row 1 has 2 columns, but first has 3'\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Pre-export validation with error handling\n * async function safeExportUsers(users: any[], filename: string) {\n * try {\n * // Validate before export\n * validateExportData(users)\n * await exportData(users, filename)\n * console.log(`✅ Exported ${users.length} users to ${filename}`)\n * } catch (error) {\n * console.error('Export failed:', error.message)\n * // Log validation errors for debugging\n * if (error.code === 'VALIDATION_ERROR') {\n * console.error('Invalid data structure:', error.details)\n * }\n * }\n * }\n * ```\n *\n * @throws {ValidationError} If data is not an array\n * @throws {ValidationError} If array is empty\n * @throws {ValidationError} If elements have inconsistent types\n * @throws {ValidationError} If array rows have different lengths\n *\n * @see {@link exportData} for universal export using validated data\n * @see {@link ExportData} for type definition\n */\nexport function validateExportData(data: any): data is ExportData {\n if (!Array.isArray(data)) {\n throw createValidationError('Data must be an array', 'data', typeof data)\n }\n\n if (data.length === 0) {\n throw createValidationError('Data array cannot be empty', 'data.length', data.length)\n }\n\n const firstItem = data[0]\n const isObjectArray =\n typeof firstItem === 'object' && firstItem !== null && !Array.isArray(firstItem)\n const isArrayOfArrays = Array.isArray(firstItem)\n\n if (!isObjectArray && !isArrayOfArrays) {\n throw createValidationError(\n 'Data must be an array of objects or an array of arrays',\n 'data[0]',\n typeof firstItem\n )\n }\n\n // Validate consistency according to first element type\n if (isObjectArray) {\n // If first element is object, all must be objects\n for (let i = 1; i < data.length; i++) {\n const item = data[i]\n if (typeof item !== 'object' || item === null || Array.isArray(item)) {\n throw createValidationError(\n 'All elements must be objects if first one is an object',\n `data[${i}]`,\n typeof item\n )\n }\n }\n } else if (isArrayOfArrays) {\n // If first element is array, all must be arrays with equal length\n const firstRowLength = firstItem.length\n for (let i = 1; i < data.length; i++) {\n if (!Array.isArray(data[i])) {\n throw createValidationError(`Row ${i} is not an array`, `data[${i}]`, typeof data[i])\n }\n if (data[i].length !== firstRowLength) {\n throw createValidationError(\n `Row ${i} has ${data[i].length} columns, but first has ${firstRowLength}`,\n `data[${i}].length`,\n { expected: firstRowLength, actual: data[i].length }\n )\n }\n }\n }\n\n return true\n}\n\n/**\n * Alias for validateExportData for CSV backward compatibility\n */\nexport const validateCSVData = validateExportData\n\n// =============================================================================\n// FORMAT DETECTION\n// =============================================================================\n\n/**\n * Detects file format based on filename extension\n *\n * Analyzes filename to determine export format for automatic format selection.\n * Supports CSV, JSON, Tree, and TXT formats. Case-insensitive.\n *\n * @param filename - Filename with extension\n * @returns Detected format ('csv' | 'json' | 'tree' | 'txt')\n *\n * @example\n * ```typescript\n * // CSV detection\n * detectFormatFromFilename('users.csv') // 'csv'\n * detectFormatFromFilename('DATA.CSV') // 'csv' (case-insensitive)\n * ```\n *\n * @example\n * ```typescript\n * // JSON detection\n * detectFormatFromFilename('config.json') // 'json'\n * detectFormatFromFilename('data.JSON') // 'json'\n * ```\n *\n * @example\n * ```typescript\n * // Tree structure detection\n * detectFormatFromFilename('structure.tree') // 'tree'\n * ```\n *\n * @example\n * ```typescript\n * // Plain text detection\n * detectFormatFromFilename('notes.txt') // 'txt'\n * detectFormatFromFilename('log.TXT') // 'txt'\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dynamic export routing\n * async function smartExport(data: any[], filename: string) {\n * const format = detectFormatFromFilename(filename)\n * console.log(`Exporting as ${format.toUpperCase()}...`)\n *\n * await exportData(data, filename)\n * console.log(`✅ Export completed: ${filename}`)\n * }\n *\n * smartExport(users, 'users.csv') // Exports as CSV\n * smartExport(config, 'config.json') // Exports as JSON\n * ```\n *\n * @throws {DataError} If filename has no extension\n * @throws {DataError} If extension is not supported (.csv, .json, .tree, .txt)\n *\n * @see {@link detectFileExtension} for universal extension detection (any file type)\n * @see {@link detectUniversalFormat} for detailed format metadata\n * @see {@link exportData} for universal export using detected format\n *\n * @deprecated Use detectFileExtension for universal detection, or use exportData directly (auto-detects)\n */\nexport function detectFormatFromFilename(filename: string): ExportFormat {\n const parts = filename.toLowerCase().split('.')\n const extension = parts.length > 1 ? parts.pop() : undefined\n\n switch (extension) {\n case 'csv':\n return 'csv'\n case 'json':\n return 'json'\n case 'tree':\n return 'tree'\n case 'txt':\n return 'txt'\n default:\n if (!extension) {\n throw new DataError(\n 'Could not detect file format. Must have a valid extension (.csv, .json, .tree, .txt)',\n TsHelpersErrorCode.UNSUPPORTED_FORMAT,\n { data: { filename } }\n )\n }\n throw new DataError(\n `Unsupported file format: .${extension}. Use .csv, .json, .tree or .txt`,\n TsHelpersErrorCode.UNSUPPORTED_FORMAT,\n { data: { filename, extension } }\n )\n }\n}\n\n/**\n * Universal file extension detector - detects any file extension\n *\n * Extracts file extension from filename (without dot) for any file type.\n * Returns last extension for compound extensions (e.g., '.tar.gz' → 'gz').\n * Case-insensitive, trims whitespace, returns null if no extension found.\n *\n * @param filename - Filename with extension\n * @returns File extension (lowercase, without dot) or `null` if no extension\n *\n * @example\n * ```typescript\n * // Common file types\n * detectFileExtension('document.pdf') // 'pdf'\n * detectFileExtension('image.jpg') // 'jpg'\n * detectFileExtension('data.json') // 'json'\n * detectFileExtension('styles.css') // 'css'\n * ```\n *\n * @example\n * ```typescript\n * // Compound extensions (returns last extension)\n * detectFileExtension('archive.tar.gz') // 'gz'\n * detectFileExtension('backup.sql.bz2') // 'bz2'\n * detectFileExtension('file.test.ts') // 'ts'\n * ```\n *\n * @example\n * ```typescript\n * // Edge cases\n * detectFileExtension('noextension') // null\n * detectFileExtension('.hidden') // 'hidden' (Unix hidden files)\n * detectFileExtension('file.') // '' (empty string)\n * detectFileExtension(' file.txt ') // 'txt' (trims whitespace)\n * detectFileExtension('FILE.PDF') // 'pdf' (case-insensitive)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Conditional file processing\n * async function processUploadedFile(filename: string, data: any) {\n * const ext = detectFileExtension(filename)\n *\n * switch (ext) {\n * case 'csv':\n * return await importCSV(filename)\n * case 'json':\n * return await importJSON(filename)\n * case 'pdf':\n * return await extractPdfText(filename)\n * case null:\n * throw new Error('File must have an extension')\n * default:\n * throw new Error(`Unsupported file type: .${ext}`)\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: File type validation\n * function validateUpload(file: File) {\n * const ext = detectFileExtension(file.name)\n * const allowedExtensions = ['jpg', 'jpeg', 'png', 'gif']\n *\n * if (!ext) {\n * return { valid: false, error: 'File must have an extension' }\n * }\n *\n * if (!allowedExtensions.includes(ext)) {\n * return {\n * valid: false,\n * error: `Invalid file type .${ext}. Allowed: ${allowedExtensions.join(', ')}`\n * }\n * }\n *\n * return { valid: true }\n * }\n * ```\n *\n * @see {@link detectUniversalFormat} for detailed format metadata (category, MIME type)\n * @see {@link detectFormatFromFilename} for export format detection (csv/json/tree/txt only)\n */\nexport function detectFileExtension(filename: string): FileFormat | null {\n if (!filename || typeof filename !== 'string') {\n return null\n }\n\n const parts = filename.trim().split('.')\n\n if (parts.length < 2) {\n return null\n }\n\n const extension = parts.pop()?.toLowerCase()\n return extension || null\n}\n\n/**\n * Universal filename format detection with comprehensive extension support\n *\n * Analyzes filename extension and returns detailed format metadata including:\n * category, MIME type, text/binary classification. Supports 80+ file formats\n * across data, code, documents, images, audio, video, archives, and fonts.\n *\n * @param filename - Filename with extension\n * @returns Object with extension, category, isText, isBinary, mimeType properties\n *\n * @example\n * ```typescript\n * // Data formats\n * detectUniversalFormat('config.json')\n * // { extension: 'json', category: 'data', isText: true, isBinary: false, mimeType: 'application/json' }\n *\n * detectUniversalFormat('users.csv')\n * // { extension: 'csv', category: 'data', isText: true, isBinary: false, mimeType: 'text/csv' }\n * ```\n *\n * @example\n * ```typescript\n * // Programming languages\n * detectUniversalFormat('app.ts')\n * // { extension: 'ts', category: 'code', isText: true, isBinary: false, mimeType: 'application/typescript' }\n *\n * detectUniversalFormat('main.py')\n * // { extension: 'py', category: 'code', isText: true, isBinary: false, mimeType: 'text/x-python' }\n * ```\n *\n * @example\n * ```typescript\n * // Documents\n * detectUniversalFormat('report.pdf')\n * // { extension: 'pdf', category: 'document', isText: false, isBinary: true, mimeType: 'application/pdf' }\n *\n * detectUniversalFormat('doc.docx')\n * // { extension: 'docx', category: 'document', isText: false, isBinary: true, mimeType: '...' }\n * ```\n *\n * @example\n * ```typescript\n * // Images\n * detectUniversalFormat('photo.jpg')\n * // { extension: 'jpg', category: 'image', isText: false, isBinary: true, mimeType: 'image/jpeg' }\n *\n * detectUniversalFormat('icon.svg')\n * // { extension: 'svg', category: 'image', isText: true, isBinary: false, mimeType: 'image/svg+xml' }\n * ```\n *\n * @example\n * ```typescript\n * // Archives\n * detectUniversalFormat('backup.zip')\n * // { extension: 'zip', category: 'archive', isText: false, isBinary: true, mimeType: 'application/zip' }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Smart file processing routing\n * async function processFile(filename: string, content: any) {\n * const format = detectUniversalFormat(filename)\n *\n * console.log(`Processing ${format.extension} file (${format.category})`)\n *\n * if (format.isText) {\n * // Can read as text\n * const text = await readFileAsText(filename)\n * return parseTextFormat(text, format.extension)\n * } else if (format.isBinary) {\n * // Needs binary processing\n * return processBinaryFile(filename, format.mimeType)\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Content-Type header generation\n * function getResponseHeaders(filename: string) {\n * const format = detectUniversalFormat(filename)\n *\n * return {\n * 'Content-Type': format.mimeType || 'application/octet-stream',\n * 'Content-Disposition': `attachment; filename=\"${filename}\"`,\n * 'X-File-Category': format.category\n * }\n * }\n * ```\n *\n * @see {@link detectFileExtension} for simple extension extraction\n * @see {@link detectFormatFromFilename} for export format detection\n */\nexport function detectUniversalFormat(filename: string) {\n const extension = detectFileExtension(filename)\n\n if (!extension) {\n return {\n extension: null,\n category: 'unknown',\n isText: false,\n isBinary: false,\n mimeType: null,\n }\n }\n\n // Comprehensive file format database with 80+ common formats\n const formatInfo = {\n // Data formats\n json: { category: 'data', isText: true, isBinary: false, mimeType: 'application/json' },\n csv: { category: 'data', isText: true, isBinary: false, mimeType: 'text/csv' },\n xml: { category: 'data', isText: true, isBinary: false, mimeType: 'application/xml' },\n yaml: { category: 'data', isText: true, isBinary: false, mimeType: 'application/yaml' },\n yml: { category: 'data', isText: true, isBinary: false, mimeType: 'application/yaml' },\n tree: { category: 'data', isText: true, isBinary: false, mimeType: 'text/plain' },\n tsv: { category: 'data', isText: true, isBinary: false, mimeType: 'text/tab-separated-values' },\n sql: { category: 'data', isText: true, isBinary: false, mimeType: 'application/sql' },\n db: { category: 'data', isText: false, isBinary: true, mimeType: 'application/x-sqlite3' },\n sqlite: { category: 'data', isText: false, isBinary: true, mimeType: 'application/x-sqlite3' },\n\n // Text and code formats\n txt: { category: 'text', isText: true, isBinary: false, mimeType: 'text/plain' },\n md: { category: 'text', isText: true, isBinary: false, mimeType: 'text/markdown' },\n rst: { category: 'text', isText: true, isBinary: false, mimeType: 'text/x-rst' },\n rtf: { category: 'text', isText: true, isBinary: false, mimeType: 'application/rtf' },\n log: { category: 'text', isText: true, isBinary: false, mimeType: 'text/plain' },\n\n // Web formats\n html: { category: 'web', isText: true, isBinary: false, mimeType: 'text/html' },\n htm: { category: 'web', isText: true, isBinary: false, mimeType: 'text/html' },\n css: { category: 'web', isText: true, isBinary: false, mimeType: 'text/css' },\n scss: { category: 'web', isText: true, isBinary: false, mimeType: 'text/x-scss' },\n sass: { category: 'web', isText: true, isBinary: false, mimeType: 'text/x-sass' },\n less: { category: 'web', isText: true, isBinary: false, mimeType: 'text/x-less' },\n\n // Programming languages\n js: { category: 'code', isText: true, isBinary: false, mimeType: 'application/javascript' },\n mjs: { category: 'code', isText: true, isBinary: false, mimeType: 'application/javascript' },\n jsx: { category: 'code', isText: true, isBinary: false, mimeType: 'text/jsx' },\n ts: { category: 'code', isText: true, isBinary: false, mimeType: 'application/typescript' },\n tsx: { category: 'code', isText: true, isBinary: false, mimeType: 'text/tsx' },\n py: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-python' },\n java: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-java-source' },\n php: { category: 'code', isText: true, isBinary: false, mimeType: 'application/x-httpd-php' },\n rb: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-ruby' },\n go: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-go' },\n rs: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-rust' },\n c: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-c' },\n cpp: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-c++' },\n cc: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-c++' },\n h: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-c' },\n cs: { category: 'code', isText: true, isBinary: false, mimeType: 'text/x-csharp' },\n sh: { category: 'code', isText: true, isBinary: false, mimeType: 'application/x-sh' },\n bash: { category: 'code', isText: true, isBinary: false, mimeType: 'application/x-sh' },\n ps1: { category: 'code', isText: true, isBinary: false, mimeType: 'application/x-powershell' },\n\n // Microsoft Office documents\n doc: { category: 'document', isText: false, isBinary: true, mimeType: 'application/msword' },\n docx: {\n category: 'document',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n },\n xls: {\n category: 'spreadsheet',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.ms-excel',\n },\n xlsx: {\n category: 'spreadsheet',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n },\n ppt: {\n category: 'presentation',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.ms-powerpoint',\n },\n pptx: {\n category: 'presentation',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n },\n\n // LibreOffice/OpenOffice\n odt: {\n category: 'document',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.oasis.opendocument.text',\n },\n ods: {\n category: 'spreadsheet',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.oasis.opendocument.spreadsheet',\n },\n odp: {\n category: 'presentation',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.oasis.opendocument.presentation',\n },\n\n // Other document formats\n pdf: { category: 'document', isText: false, isBinary: true, mimeType: 'application/pdf' },\n epub: { category: 'document', isText: false, isBinary: true, mimeType: 'application/epub+zip' },\n mobi: {\n category: 'document',\n isText: false,\n isBinary: true,\n mimeType: 'application/x-mobipocket-ebook',\n },\n\n // Image formats\n jpg: { category: 'image', isText: false, isBinary: true, mimeType: 'image/jpeg' },\n jpeg: { category: 'image', isText: false, isBinary: true, mimeType: 'image/jpeg' },\n png: { category: 'image', isText: false, isBinary: true, mimeType: 'image/png' },\n gif: { category: 'image', isText: false, isBinary: true, mimeType: 'image/gif' },\n svg: { category: 'image', isText: true, isBinary: false, mimeType: 'image/svg+xml' },\n webp: { category: 'image', isText: false, isBinary: true, mimeType: 'image/webp' },\n avif: { category: 'image', isText: false, isBinary: true, mimeType: 'image/avif' },\n bmp: { category: 'image', isText: false, isBinary: true, mimeType: 'image/bmp' },\n tiff: { category: 'image', isText: false, isBinary: true, mimeType: 'image/tiff' },\n tif: { category: 'image', isText: false, isBinary: true, mimeType: 'image/tiff' },\n ico: { category: 'image', isText: false, isBinary: true, mimeType: 'image/x-icon' },\n psd: {\n category: 'image',\n isText: false,\n isBinary: true,\n mimeType: 'image/vnd.adobe.photoshop',\n },\n\n // Audio formats\n mp3: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/mpeg' },\n wav: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/wav' },\n flac: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/flac' },\n ogg: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/ogg' },\n aac: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/aac' },\n m4a: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/m4a' },\n wma: { category: 'audio', isText: false, isBinary: true, mimeType: 'audio/x-ms-wma' },\n\n // Video formats\n mp4: { category: 'video', isText: false, isBinary: true, mimeType: 'video/mp4' },\n avi: { category: 'video', isText: false, isBinary: true, mimeType: 'video/x-msvideo' },\n mov: { category: 'video', isText: false, isBinary: true, mimeType: 'video/quicktime' },\n wmv: { category: 'video', isText: false, isBinary: true, mimeType: 'video/x-ms-wmv' },\n flv: { category: 'video', isText: false, isBinary: true, mimeType: 'video/x-flv' },\n webm: { category: 'video', isText: false, isBinary: true, mimeType: 'video/webm' },\n mkv: { category: 'video', isText: false, isBinary: true, mimeType: 'video/x-matroska' },\n '3gp': { category: 'video', isText: false, isBinary: true, mimeType: 'video/3gpp' },\n\n // Archive formats\n zip: { category: 'archive', isText: false, isBinary: true, mimeType: 'application/zip' },\n rar: {\n category: 'archive',\n isText: false,\n isBinary: true,\n mimeType: 'application/x-rar-compressed',\n },\n '7z': {\n category: 'archive',\n isText: false,\n isBinary: true,\n mimeType: 'application/x-7z-compressed',\n },\n tar: { category: 'archive', isText: false, isBinary: true, mimeType: 'application/x-tar' },\n gz: { category: 'archive', isText: false, isBinary: true, mimeType: 'application/gzip' },\n bz2: { category: 'archive', isText: false, isBinary: true, mimeType: 'application/x-bzip2' },\n xz: { category: 'archive', isText: false, isBinary: true, mimeType: 'application/x-xz' },\n\n // Configuration files\n ini: { category: 'config', isText: true, isBinary: false, mimeType: 'text/plain' },\n cfg: { category: 'config', isText: true, isBinary: false, mimeType: 'text/plain' },\n conf: { category: 'config', isText: true, isBinary: false, mimeType: 'text/plain' },\n toml: { category: 'config', isText: true, isBinary: false, mimeType: 'application/toml' },\n env: { category: 'config', isText: true, isBinary: false, mimeType: 'text/plain' },\n\n // Font formats\n ttf: { category: 'font', isText: false, isBinary: true, mimeType: 'font/ttf' },\n otf: { category: 'font', isText: false, isBinary: true, mimeType: 'font/otf' },\n woff: { category: 'font', isText: false, isBinary: true, mimeType: 'font/woff' },\n woff2: { category: 'font', isText: false, isBinary: true, mimeType: 'font/woff2' },\n eot: {\n category: 'font',\n isText: false,\n isBinary: true,\n mimeType: 'application/vnd.ms-fontobject',\n },\n } as const\n\n const info = formatInfo[extension as keyof typeof formatInfo] || {\n category: 'unknown',\n isText: false,\n isBinary: false,\n mimeType: null,\n }\n\n return {\n extension,\n ...info,\n }\n}\n\n// =============================================================================\n// TREE EXPORT OPTIONS\n// =============================================================================\n\nexport interface TreeExportOptions {\n /** Property to display as node name (default: 'name') */\n labelField?: string\n /** Characters for vertical line (default: '│ ') */\n verticalLine?: string\n /** Characters for middle branch (default: '├── ') */\n middleBranch?: string\n /** Characters for last branch (default: '└── ') */\n lastBranch?: string\n /** Spacing for nodes without vertical line (default: ' ') */\n emptySpace?: string\n /** Custom function to get node label */\n labelFunction?: (node: any) => string\n}\n\n/**\n * Exports a tree structure as a text file with visual format\n *\n * Converts hierarchical data (nodes with `children` arrays) into ASCII/Unicode tree\n * visualization and saves as .tree file. Supports Node.js (filesystem) and Browser (download).\n *\n * @param data - Array of root nodes (each with optional `children` property)\n * @param filePath - Output file path (Node.js) or filename (Browser)\n * @param options - Tree rendering options (labelField, box-drawing characters, labelFunction)\n *\n * @example\n * ```typescript\n * // Basic tree export - File structure\n * const fileTree = [\n * {\n * name: 'src',\n * children: [\n * { name: 'index.ts' },\n * { name: 'utils.ts' },\n * {\n * name: 'components',\n * children: [\n * { name: 'Button.tsx' },\n * { name: 'Input.tsx' }\n * ]\n * }\n * ]\n * }\n * ]\n *\n * await exportTree(fileTree, 'structure.tree')\n * // Creates file:\n * // └── src\n * // ├── index.ts\n * // ├── utils.ts\n * // └── components\n * // ├── Button.tsx\n * // └── Input.tsx\n * ```\n *\n * @example\n * ```typescript\n * // Custom label field - Organization chart\n * const orgChart = [\n * {\n * title: 'CEO',\n * children: [\n * {\n * title: 'CTO',\n * children: [\n * { title: 'Dev Lead' },\n * { title: 'QA Lead' }\n * ]\n * },\n * { title: 'CFO' }\n * ]\n * }\n * ]\n *\n * await exportTree(orgChart, 'org-chart.tree', { labelField: 'title' })\n * ```\n *\n * @example\n * ```typescript\n * // ASCII characters - Better terminal compatibility\n * await exportTree(data, 'structure.tree', {\n * verticalLine: '| ',\n * middleBranch: '+-- ',\n * lastBranch: '`-- ',\n * emptySpace: ' '\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Custom label function - Rich formatting\n * const tasks = [\n * {\n * name: 'Backend',\n * status: 'in-progress',\n * assignee: 'Alice',\n * children: [\n * { name: 'API', status: 'done', assignee: 'Bob' },\n * { name: 'Database', status: 'pending', assignee: 'Charlie' }\n * ]\n * }\n * ]\n *\n * await exportTree(tasks, 'tasks.tree', {\n * labelFunction: (node) => `[${node.status}] ${node.name} (@${node.assignee})`\n * })\n * // Output:\n * // └── [in-progress] Backend (@Alice)\n * // ├── [done] API (@Bob)\n * // └── [pending] Database (@Charlie)\n * ```\n *\n * @throws {ValidationError} If data is not an array of nodes\n *\n * @see {@link importTree} for importing .tree files as text\n * @see {@link renderTreeAsText} for tree rendering without file export\n * @see {@link TreeExportOptions} for configuration options\n */\nexport async function exportTree(\n data: any[],\n filePath: string,\n options?: TreeExportOptions\n): Promise<void> {\n if (!Array.isArray(data)) {\n throw createValidationError(\n 'Data for tree format must be an array of nodes',\n 'data',\n typeof data\n )\n }\n\n // Import render function from specialized/tree\n const { renderTreeAsText } = await import('./tree')\n\n // Render tree as text\n const treeText = renderTreeAsText(data, options)\n\n // Write file according to environment\n if (isNode()) {\n // Node.js - write file to system\n const fs = await import('fs/promises')\n await fs.writeFile(filePath, treeText, { encoding: 'utf-8' })\n } else {\n // Browser - download as file\n const blob = new Blob([treeText], { type: 'text/plain;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n\n const link = document.createElement('a')\n link.href = url\n link.download = filePath.split('/').pop() || 'tree.tree'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(url)\n }\n}\n\n/**\n * Imports a .tree file as plain text (Node.js only)\n *\n * Reads tree structure visualization files created with exportTree() as plain text.\n * Returns the ASCII/Unicode tree diagram as string. Only supported in Node.js environment.\n *\n * @param filePath - Path to .tree file (Node.js only)\n * @param _options - Reserved for future use\n * @returns Promise<string> Tree structure as text\n *\n * @example\n * ```typescript\n * // Import tree structure\n * const treeText = await importTree('./structure.tree')\n * console.log(treeText)\n * // Output:\n * // └── src\n * // ├── index.ts\n * // ├── utils.ts\n * // └── components\n * // ├── Button.tsx\n * // └── Input.tsx\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Display tree structure in terminal\n * async function showProjectStructure(filePath: string) {\n * try {\n * const structure = await importTree(filePath)\n * console.log('📁 Project Structure:')\n * console.log(structure)\n * } catch (error) {\n * console.error('Failed to load structure:', error.message)\n * }\n * }\n * ```\n *\n * @throws {DataError} If called in Browser environment (use readFileAsText with File object instead)\n *\n * @see {@link exportTree} for creating .tree files\n * @see {@link readFileAsText} for browser-compatible file reading\n */\nexport async function importTree(filePath: string, _options?: any): Promise<string> {\n if (isNode()) {\n // Node.js - read file from system\n const fs = await import('fs/promises')\n return fs.readFile(filePath, { encoding: 'utf-8' })\n } else {\n // Browser - cannot read files from system directly\n throw new DataError(\n '.tree file import is not supported in browser. Use readFileAsText() with a File object.',\n TsHelpersErrorCode.ENVIRONMENT_NOT_SUPPORTED,\n { data: { environment: 'browser', operation: 'importTree' } }\n )\n }\n}\n\n// =============================================================================\n// TEXT EXPORT OPTIONS\n// =============================================================================\n\nexport interface TxtExportOptions {\n /** Separator between array elements (default: '\\n') */\n separator?: string\n /** Custom function to convert objects to string */\n stringify?: (obj: any) => string\n /** Indentation for JSON objects (default: 2) */\n indent?: number\n}\n\n/**\n * Exports any type of data as plain text file\n *\n * Universal text file exporter supporting strings, arrays, objects, and primitives.\n * Automatically formats data based on type. Supports Node.js (filesystem) and Browser (download).\n *\n * Features:\n * - **Strings**: Direct output\n * - **Arrays**: One element per line (or custom separator)\n * - **Objects**: Formatted JSON with indentation\n * - **Primitives**: String conversion\n * - **Custom stringify**: Optional transform function\n *\n * @param data - Data to export (string, array, object, or primitive)\n * @param filePath - Output file path (Node.js) or filename (Browser)\n * @param options - Export options (separator, stringify function, indent)\n *\n * @example\n * ```typescript\n * // Export string - Direct output\n * await exportTxt('Hello, World!', 'message.txt')\n * // Creates: Hello, World!\n * ```\n *\n * @example\n * ```typescript\n * // Export array - One per line\n * const logs = [\n * '[INFO] Server started',\n * '[WARN] High memory usage',\n * '[ERROR] Connection failed'\n * ]\n * await exportTxt(logs, 'server.log')\n * // Creates:\n * // [INFO] Server started\n * // [WARN] High memory usage\n * // [ERROR] Connection failed\n * ```\n *\n * @example\n * ```typescript\n * // Export object - Formatted JSON\n * const config = {\n * server: { host: 'localhost', port: 3000 },\n * database: { url: 'mongodb://localhost' }\n * }\n * await exportTxt(config, 'config.txt', { indent: 2 })\n * // Creates formatted JSON\n * ```\n *\n * @example\n * ```typescript\n * // Custom separator - Comma-separated list\n * const tags = ['typescript', 'nodejs', 'express', 'mongodb']\n * await exportTxt(tags, 'tags.txt', { separator: ', ' })\n * // Creates: typescript, nodejs, express, mongodb\n * ```\n *\n * @example\n * ```typescript\n * // Custom stringify function - Markdown list\n * const tasks = [\n * { id: 1, title: 'Setup project', done: true },\n * { id: 2, title: 'Write tests', done: false }\n * ]\n * await exportTxt(tasks, 'tasks.txt', {\n * stringify: (tasks) =>\n * tasks.map(t => `- [${t.done ? 'x' : ' '}] ${t.title}`).join('\\n')\n * })\n * // Creates:\n * // - [x] Setup project\n * // - [ ] Write tests\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Export error log with timestamps\n * async function exportErrorLog(errors: Error[]) {\n * const timestamp = new Date().toISOString()\n * const filename = `errors-${timestamp}.txt`\n *\n * await exportTxt(errors, filename, {\n * stringify: (errors) =>\n * errors.map(e => `[${new Date().toISOString()}] ${e.message}\\n${e.stack}`).join('\\n\\n')\n * })\n *\n * console.log(`✅ Exported ${errors.length} errors to ${filename}`)\n * }\n * ```\n *\n * @see {@link importTxt} for importing text files with security validations\n * @see {@link TxtExportOptions} for configuration options\n */\nexport async function exportTxt(\n data: any,\n filePath: string,\n options?: TxtExportOptions\n): Promise<void> {\n const { separator = '\\n', stringify, indent = 2 } = options || {}\n\n let textContent: string\n\n if (stringify) {\n // Use custom function\n textContent = stringify(data)\n } else if (typeof data === 'string') {\n // Already string\n textContent = data\n } else if (Array.isArray(data)) {\n // Array: each element on a line (or custom separator)\n textContent = data\n .map(item => (typeof item === 'string' ? item : JSON.stringify(item, null, indent)))\n .join(separator)\n } else if (typeof data === 'object' && data !== null) {\n // Object: formatted JSON\n textContent = JSON.stringify(data, null, indent)\n } else {\n // Primitives: convert to string\n textContent = String(data)\n }\n\n // Write file according to environment\n if (isNode()) {\n // Node.js - write file to system\n const fs = await import('fs/promises')\n await fs.writeFile(filePath, textContent, { encoding: 'utf-8' })\n } else {\n // Browser - download as file\n const blob = new Blob([textContent], { type: 'text/plain;charset=utf-8' })\n const url = URL.createObjectURL(blob)\n\n const link = document.createElement('a')\n link.href = url\n link.download = filePath.split('/').pop() || 'file.txt'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n\n URL.revokeObjectURL(url)\n }\n}\n\nexport interface TxtImportOptions {\n /** Maximum file size in bytes (default: 10MB) */\n maxFileSize?: number\n /** Maximum content length in characters (default: 1M characters) */\n maxLength?: number\n /** Whether to validate content for security (default: true) */\n validateSecurity?: boolean\n /** Whether to sanitize content (default: true) */\n sanitize?: boolean\n}\n\n/**\n * Sanitizes text content removing problematic characters\n */\nfunction sanitizeTextContent(content: string): string {\n return (\n content\n // Normalize different types of line breaks\n .replace(/\\r\\n|\\r/g, '\\n')\n // Remove dangerous control characters (keep \\n, \\t)\n // eslint-disable-next-line no-control-regex\n .replace(/[\\x00-\\x08\\x0E-\\x1F\\x7F]/g, '')\n // Limit multiple consecutive line breaks\n .replace(/\\n{4,}/g, '\\n\\n\\n')\n // Remove trailing spaces from lines\n .replace(/[ \\t]+$/gm, '')\n )\n}\n\n/**\n * Imports a .txt file as plain text with security validations (Node.js only)\n *\n * Reads text files with comprehensive security checks: file size limits, content length validation,\n * path traversal prevention, and dangerous character sanitization. Only supported in Node.js.\n *\n * Security features:\n * - **File size limit**: Default 10MB (configurable)\n * - **Content length limit**: Default 1M characters (configurable)\n * - **Path validation**: Prevents directory traversal attacks\n * - **Content sanitization**: Removes dangerous control characters\n * - **Line break normalization**: Standardizes to \\n\n *\n * @param filePath - Path to .txt file (Node.js only)\n * @param options - Security and sanitization options\n *\n * @example\n * ```typescript\n * // Basic import - Default security settings\n * const content = await importTxt('./notes.txt')\n * console.log(content)\n * ```\n *\n * @example\n * ```typescript\n * // Custom size limits - Large file support\n * const largeFile = await importTxt('./large-log.txt', {\n * maxFileSize: 50 * 1024 * 1024, // 50MB\n * maxLength: 10_000_000 // 10M characters\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Disable sanitization - Raw content\n * const rawContent = await importTxt('./data.txt', {\n * sanitize: false,\n * validateSecurity: false\n * })\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Safe log file reader with error handling\n * async function readServerLog(logPath: string) {\n * try {\n * const log = await importTxt(logPath, {\n * maxFileSize: 100 * 1024 * 1024, // 100MB logs\n * maxLength: 50_000_000, // 50M chars\n * sanitize: true,\n * validateSecurity: true\n * })\n *\n * const lines = log.split('\\n')\n * const errors = lines.filter(line => line.includes('[ERROR]'))\n *\n * console.log(`📊 Log stats:`)\n * console.log(` Total lines: ${lines.length}`)\n * console.log(` Errors: ${errors.length}`)\n *\n * return { lines, errors }\n * } catch (error) {\n * if (error.message.includes('too large')) {\n * console.error('Log file exceeds size limit')\n * } else if (error.message.includes('not found')) {\n * console.error('Log file does not exist')\n * } else {\n * console.error('Failed to read log:', error.message)\n * }\n * throw error\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Secure user file upload processing\n * async function processUserUpload(uploadedFilePath: string) {\n * // Enforce strict limits for user-uploaded files\n * const content = await importTxt(uploadedFilePath, {\n * maxFileSize: 5 * 1024 * 1024, // 5MB max\n * maxLength: 1_000_000, // 1M chars max\n * validateSecurity: true, // Check for dangerous content\n * sanitize: true // Remove control chars\n * })\n *\n * // Process sanitized content safely\n * return analyzeText(content)\n * }\n * ```\n *\n * @throws {Error} If file exceeds maxFileSize\n * @throws {Error} If content exceeds maxLength\n * @throws {Error} If file path is invalid or unsafe\n * @throws {Error} If file not found\n * @throws {Error} If called in Browser environment\n *\n * @see {@link exportTxt} for creating text files\n * @see {@link TxtImportOptions} for configuration options\n * @see {@link readFileAsText} for browser-compatible file reading\n */\nexport async function importTxt(filePath: string, options: TxtImportOptions = {}): Promise<string> {\n const {\n maxFileSize = 10 * 1024 * 1024, // 10MB default\n maxLength = 1_000_000, // 1M characters default\n validateSecurity = true,\n sanitize = true,\n } = options\n\n if (isNode()) {\n // Node.js - read file from system with validations\n const fs = await import('fs/promises')\n const path = await import('path')\n\n // Validate file path for security using our validator\n const { isValidFilePath, isValidFileSize, isValidTextContent } = await import('./validators')\n\n if (!isValidFilePath(filePath)) {\n throw new Error('Invalid or unsafe file path')\n }\n\n const resolvedPath = path.resolve(filePath)\n\n // Check file size before reading\n try {\n const stats = await fs.stat(resolvedPath)\n\n if (!isValidFileSize(stats.size, maxFileSize)) {\n throw new Error(`File too large: ${stats.size} bytes (max: ${maxFileSize})`)\n }\n } catch (error) {\n if ((error as any).code === 'ENOENT') {\n throw new Error(`File not found: ${filePath}`)\n }\n throw error\n }\n\n // Read and validate content\n const content = await fs.readFile(resolvedPath, { encoding: 'utf-8' })\n\n // Validate content security using our validator\n if (validateSecurity && !isValidTextContent(content, { maxLength })) {\n throw new Error('File contains potentially dangerous content or exceeds security limits')\n }\n\n return sanitize ? sanitizeTextContent(content) : content\n } else {\n // Browser - cannot read files from system directly\n throw new Error(\n '.txt file import is not supported in browser. Use readFileAsText() with a File object.'\n )\n }\n}\n\n// =============================================================================\n// UNIVERSAL FUNCTIONS\n// =============================================================================\n\n/**\n * Exports data in specified format based on file extension (Universal dispatcher)\n *\n * Universal export function that automatically detects format from filename extension\n * and delegates to specialized exporters (CSV, JSON, Tree, TXT). Simplifies data export\n * with a single unified API for all formats.\n *\n * Automatic format detection:\n * - **.csv** → exportCSV (PapaParse, UTF-8 BOM, semicolon delimiter)\n * - **.json** → exportJSON (pretty-printed JSON)\n * - **.tree** → exportTree (ASCII/Unicode tree visualization)\n * - **.txt** → exportTxt (plain text with auto-formatting)\n *\n * Environment support:\n * - **Node.js**: Writes to filesystem\n * - **Browser**: Triggers download\n *\n * @param data - Data to export (structure depends on format)\n * @param filePath - Output file path with extension (determines format)\n * @param options - Format-specific options (passed to specialized exporter)\n *\n * @example\n * ```typescript\n * // CSV export - Array of objects\n * const users = [\n * { id: 1, name: 'Alice', email: 'alice@example.com' },\n * { id: 2, name: 'Bob', email: 'bob@example.com' }\n * ]\n * await exportData(users, 'users.csv')\n * // Auto-detects CSV format, exports with semicolon delimiter\n * ```\n *\n * @example\n * ```typescript\n * // JSON export - Any data structure\n * const config = {\n * server: { host: 'localhost', port: 3000 },\n * database: { url: 'mongodb://localhost' },\n * features: { auth: true, cache: false }\n * }\n * await exportData(config, 'config.json', { indent: 2 })\n * // Auto-detects JSON format, pretty-prints with 2-space indent\n * ```\n *\n * @example\n * ```typescript\n * // Tree export - Hierarchical structure\n * const fileTree = [\n * {\n * name: 'src',\n * children: [\n * { name: 'index.ts' },\n * { name: 'utils.ts' },\n * {\n * name: 'components',\n * children: [\n * { name: 'Button.tsx' },\n * { name: 'Input.tsx' }\n * ]\n * }\n * ]\n * }\n * ]\n * await exportData(fileTree, 'structure.tree')\n * // Auto-detects tree format, renders as ASCII tree\n * ```\n *\n * @example\n * ```typescript\n * // Text export - Logs/strings\n * const logs = [\n * '[2024-01-15 10:30:00] Server started',\n * '[2024-01-15 10:30:15] Connected to database',\n * '[2024-01-15 10:31:00] Ready to accept connections'\n * ]\n * await exportData(logs, 'server.log')\n * // Auto-detects txt format, one line per array element\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Multi-format export function\n * async function exportReport(data: any[], format: 'csv' | 'json' | 'txt') {\n * const timestamp = new Date().toISOString().split('T')[0]\n * const filename = `report-${timestamp}.${format}`\n *\n * try {\n * await exportData(data, filename)\n * console.log(`✅ Report exported: ${filename}`)\n * return { success: true, filename }\n * } catch (error) {\n * console.error(`❌ Export failed:`, error.message)\n * return { success: false, error: error.message }\n * }\n * }\n *\n * // Usage\n * exportReport(users, 'csv') // users-2024-01-15.csv\n * exportReport(stats, 'json') // report-2024-01-15.json\n * exportReport(logs, 'txt') // report-2024-01-15.txt\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: User-selected format export\n * async function exportWithUserChoice(data: any[], filename: string) {\n * // User provides filename with desired extension\n * // exportData automatically routes to correct exporter\n *\n * await exportData(data, filename)\n *\n * const format = detectFormatFromFilename(filename)\n * console.log(`Exported as ${format.toUpperCase()}`)\n * }\n *\n * // Works with any supported extension\n * exportWithUserChoice(data, 'data.csv')\n * exportWithUserChoice(data, 'data.json')\n * exportWithUserChoice(data, 'data.txt')\n * ```\n *\n * @throws {DataError} If file extension is not supported\n * @throws {ValidationError} If data structure is invalid for format (e.g., CSV requires array)\n *\n * @see {@link importData} for universal import\n * @see {@link exportCSV} for CSV-specific export\n * @see {@link exportJSON} for JSON-specific export\n * @see {@link exportTree} for tree-specific export\n * @see {@link exportTxt} for text-specific export\n */\nexport async function exportData(data: any, filePath: string, options?: any): Promise<void> {\n const format = detectFormatFromFilename(filePath)\n\n // Only validate as ExportData for formats that require it (CSV)\n if (format === 'csv') {\n validateExportData(data)\n }\n\n switch (format) {\n case 'csv': {\n const { exportCSV } = await import('./csv')\n return exportCSV(data, filePath, options)\n }\n case 'json': {\n const { exportJSON } = await import('./json')\n return exportJSON(data, filePath, options)\n }\n case 'tree': {\n return exportTree(data, filePath, options)\n }\n case 'txt': {\n return exportTxt(data, filePath, options)\n }\n default:\n throw new Error(`Unsupported format: ${format}`)\n }\n}\n\n/**\n * Imports data from specified file based on extension (Universal dispatcher)\n *\n * Universal import function that automatically detects format from filename extension\n * and delegates to specialized importers (CSV, JSON, Tree, TXT). Simplifies data import\n * with a single unified API for all formats. Node.js only.\n *\n * Automatic format detection:\n * - **.csv** → importCSV (PapaParse with header detection)\n * - **.json** → importJSON (native JSON.parse)\n * - **.tree** → importTree (plain text tree visualization)\n * - **.txt** → importTxt (plain text with security validations)\n *\n * @param filePath - Input file path with extension (determines format)\n * @param options - Format-specific options (passed to specialized importer)\n * @returns Promise<ImportData> Imported data (type depends on format)\n *\n * @example\n * ```typescript\n * // CSV import - Returns array of objects\n * const users = await importData('./users.csv')\n * // [\n * // { id: '1', name: 'Alice', email: 'alice@example.com' },\n * // { id: '2', name: 'Bob', email: 'bob@example.com' }\n * // ]\n * ```\n *\n * @example\n * ```typescript\n * // JSON import - Returns original data structure\n * const config = await importData('./config.json')\n * console.log(config.server.host) // 'localhost'\n * console.log(config.server.port) // 3000\n * ```\n *\n * @example\n * ```typescript\n * // Tree import - Returns plain text visualization\n * const treeText = await importData('./structure.tree')\n * console.log(treeText)\n * // └── src\n * // ├── index.ts\n * // ├── utils.ts\n * // └── components\n * ```\n *\n * @example\n * ```typescript\n * // Text import - Returns file content as string\n * const log = await importData('./server.log')\n * const lines = log.split('\\n')\n * const errors = lines.filter(line => line.includes('[ERROR]'))\n * console.log(`Found ${errors.length} errors`)\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Dynamic file processor\n * async function processFile(filePath: string) {\n * const ext = detectFileExtension(filePath)\n * console.log(`Processing ${ext} file...`)\n *\n * const data = await importData(filePath)\n *\n * switch (ext) {\n * case 'csv':\n * return processCSVData(data as any[])\n * case 'json':\n * return processJSONData(data)\n * case 'txt':\n * return processTextData(data as string)\n * default:\n * throw new Error(`Unsupported format: ${ext}`)\n * }\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Batch file import with error handling\n * async function importAllFiles(directory: string) {\n * const files = await fs.readdir(directory)\n * const results = []\n *\n * for (const file of files) {\n * const filePath = path.join(directory, file)\n * const ext = detectFileExtension(file)\n *\n * // Skip unsupported formats\n * if (!['csv', 'json', 'txt', 'tree'].includes(ext || '')) {\n * console.log(`⏭️ Skipping unsupported file: ${file}`)\n * continue\n * }\n *\n * try {\n * const data = await importData(filePath)\n * results.push({ file, data, success: true })\n * console.log(`✅ Imported: ${file}`)\n * } catch (error) {\n * results.push({ file, error: error.message, success: false })\n * console.error(`❌ Failed: ${file} - ${error.message}`)\n * }\n * }\n *\n * return results\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Real-world: Import with custom options per format\n * async function smartImport(filePath: string) {\n * const format = detectFormatFromFilename(filePath)\n *\n * let options: any = {}\n *\n * if (format === 'csv') {\n * options = { delimiter: ';', header: true }\n * } else if (format === 'json') {\n * options = { reviver: (key, value) => key === 'date' ? new Date(value) : value }\n * } else if (format === 'txt') {\n * options = { maxFileSize: 50 * 1024 * 1024, sanitize: true }\n * }\n *\n * return await importData(filePath, options)\n * }\n * ```\n *\n * @throws {DataError} If file extension is not supported\n * @throws {Error} If file not found or cannot be read\n * @throws {Error} If file format is invalid\n * @throws {DataError} If called in Browser environment (use readFileAsText with File object instead)\n *\n * @see {@link exportData} for universal export\n * @see {@link importCSV} for CSV-specific import\n * @see {@link importJSON} for JSON-specific import\n * @see {@link importTree} for tree-specific import\n * @see {@link importTxt} for text-specific import\n */\nexport async function importData(filePath: string, options?: any): Promise<ImportData> {\n const format = detectFormatFromFilename(filePath)\n\n switch (format) {\n case 'csv': {\n const { importCSV } = await import('./csv')\n return importCSV(filePath, options)\n }\n case 'json': {\n const { importJSON } = await import('./json')\n return importJSON(filePath, options)\n }\n case 'tree': {\n return importTree(filePath, options)\n }\n case 'txt': {\n return importTxt(filePath, options)\n }\n default:\n throw new Error(`Unsupported format: ${format}`)\n }\n}\n","/**\n * Node.js-specific validation utilities with crypto support\n * Uses Node.js crypto module for secure operations\n */\n\n/* eslint-disable complexity */\n\nimport { createHash, randomBytes } from 'crypto'\n\n// =============================================================================\n// PASSWORD VALIDATION (Node.js with crypto)\n// =============================================================================\n\nexport interface PasswordCriteria {\n minLength?: number\n requireUppercase?: boolean\n requireLowercase?: boolean\n requireNumbers?: boolean\n requireSpecialChars?: boolean\n maxLength?: number\n forbiddenPatterns?: string[]\n}\n\nexport interface PasswordValidationResult {\n isValid: boolean\n errors: string[]\n strength: 'weak' | 'fair' | 'good' | 'strong'\n score: number // 0-100\n}\n\nexport const validatePassword = (\n password: string,\n criteria: PasswordCriteria = {}\n): PasswordValidationResult => {\n const {\n minLength = 8,\n requireUppercase = true,\n requireLowercase = true,\n requireNumbers = true,\n requireSpecialChars = true,\n maxLength = 128,\n forbiddenPatterns = [],\n } = criteria\n\n const errors: string[] = []\n let score = 0\n\n if (password.length < minLength) {\n errors.push(`La contraseña debe tener al menos ${minLength} caracteres`)\n } else {\n score += 20\n }\n\n if (password.length > maxLength) {\n errors.push(`La contraseña no puede tener más de ${maxLength} caracteres`)\n }\n\n if (requireUppercase && !/[A-Z]/.test(password)) {\n errors.push('La contraseña debe contener al menos una letra mayúscula')\n } else if (/[A-Z]/.test(password)) {\n score += 15\n }\n\n if (requireLowercase && !/[a-z]/.test(password)) {\n errors.push('La contraseña debe contener al menos una letra minúscula')\n } else if (/[a-z]/.test(password)) {\n score += 15\n }\n\n if (requireNumbers && !/\\d/.test(password)) {\n errors.push('La contraseña debe contener al menos un número')\n } else if (/\\d/.test(password)) {\n score += 15\n }\n\n if (requireSpecialChars && !/[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/.test(password)) {\n errors.push('La contraseña debe contener al menos un caracter especial')\n } else if (/[!@#$%^&*()_+\\-=[\\]{};':\"\\\\|,.<>/?]/.test(password)) {\n score += 15\n }\n\n for (const pattern of forbiddenPatterns) {\n if (password.toLowerCase().includes(pattern.toLowerCase())) {\n errors.push(`La contraseña no puede contener: ${pattern}`)\n }\n }\n\n if (password.length >= 12) score += 10\n if (password.length >= 16) score += 10\n\n if (/(.)\\\\1{2,}/.test(password)) score -= 10\n if (/123|abc|qwe/i.test(password)) score -= 15\n\n score = Math.max(0, Math.min(100, score))\n\n let strength: 'weak' | 'fair' | 'good' | 'strong'\n if (score < 30) strength = 'weak'\n else if (score < 60) strength = 'fair'\n else if (score < 80) strength = 'good'\n else strength = 'strong'\n\n return {\n isValid: errors.length === 0,\n errors,\n strength,\n score,\n }\n}\n\n// =============================================================================\n// SECURITY FUNCTIONS (Node.js crypto)\n// =============================================================================\n\nexport const sanitizeHtml = (html: string): string => {\n if (!html) return ''\n\n let sanitized = html\n .replace(/<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi, '')\n .replace(/<style\\b[^<]*(?:(?!<\\/style>)<[^<]*)*<\\/style>/gi, '')\n\n sanitized = sanitized.replace(/ on\\w+=\"[^\"]*\"/gi, '')\n sanitized = sanitized.replace(/ on\\w+='[^']*'/gi, '')\n sanitized = sanitized.replace(/javascript:/gi, '')\n sanitized = sanitized.replace(/<iframe\\b[^<]*(?:(?!<\\/iframe>)<[^<]*)*<\\/iframe>/gi, '')\n sanitized = sanitized.replace(/<object\\b[^<]*(?:(?!<\\/object>)<[^<]*)*<\\/object>/gi, '')\n sanitized = sanitized.replace(/<embed\\b[^>]*>/gi, '')\n\n return sanitized.trim()\n}\n\nexport const isValidJWTFormat = (token: string): boolean => {\n if (!token || typeof token !== 'string') return false\n\n const parts = token.split('.')\n if (parts.length !== 3) return false\n\n try {\n for (const part of parts) {\n if (!part || !/^[A-Za-z0-9_-]+$/.test(part)) return false\n atob(part.replace(/-/g, '+').replace(/_/g, '/'))\n }\n return true\n } catch {\n return false\n }\n}\n\nexport const hashString = (input: string, salt = ''): string => {\n return createHash('sha256')\n .update(input + salt)\n .digest('hex')\n}\n\nexport const generateSecureToken = (length = 32): string => {\n return randomBytes(length).toString('hex')\n}\n\nexport const isValidBase64 = (input: string): boolean => {\n if (!input || typeof input !== 'string') return false\n\n if (!/^[A-Za-z0-9+/]*={0,2}$/.test(input)) return false\n\n try {\n const decoded = atob(input)\n const reencoded = btoa(decoded)\n return reencoded === input\n } catch {\n return false\n }\n}\n\nexport const escapeShellCommand = (input: string): string => {\n if (!input) return ''\n\n return input\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/'/g, \"\\\\'\")\n .replace(/\"/g, '\\\\\"')\n .replace(/;/g, '\\\\;')\n .replace(/&/g, '\\\\&')\n .replace(/\\|/g, '\\\\|')\n .replace(/`/g, '\\\\`')\n .replace(/\\$/g, '\\\\$')\n .replace(/\\(/g, '\\\\(')\n .replace(/\\)/g, '\\\\)')\n .replace(/</g, '\\\\\\\\<')\n .replace(/>/g, '\\\\\\\\>')\n}\n\nexport const isSecureUrl = (url: string): boolean => {\n if (!url || typeof url !== 'string') return false\n\n try {\n const parsed = new URL(url)\n return (\n parsed.protocol === 'https:' ||\n (parsed.protocol === 'http:' &&\n (parsed.hostname === 'localhost' || parsed.hostname === '127.0.0.1'))\n )\n } catch {\n return false\n }\n}\n\nexport const removeDangerousChars = (input: string, replacement = ''): string => {\n if (!input) return ''\n\n return input\n .replace(/[<>]/g, replacement)\n .replace(/['\"]/g, replacement)\n .replace(/[&]/g, replacement)\n .replace(/[\\\\x00-\\\\x1f\\\\x7f]/g, replacement)\n}\n\nexport const generateNonce = (length = 32): string => {\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'\n let result = ''\n\n const bytes = randomBytes(length)\n for (let i = 0; i < length; i++) {\n result += chars[bytes[i] % chars.length]\n }\n\n return result\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAsDO,SAAS,oBAA6B;AAC3C,SAAO,OAAO,WAAW,eAAe,OAAO,YAAY,eAAe,CAAC,CAAC,QAAQ,UAAU;AAChG;AAkBO,SAAS,uBAAgC;AAE9C,QAAM,MAAM,OAAO,WAAW,cAAc,SAAU,OAAe;AACrE,QAAM,MAAM,OAAO,aAAa,cAAc,WAAY,OAAe;AACzE,SAAO,OAAO,QAAQ,eAAe,QAAQ,QAAQ,OAAO,QAAQ,eAAe,QAAQ;AAC7F;AAwCO,SAAS,cAAc,KAAoB;AAChD,MAAI,kBAAkB,GAAG;AAEvB,QAAI,QAAQ,IAAI,aAAa,cAAc;AACzC,aAAO;AAAA,IACT;AACA,QAAI,QAAQ,IAAI,aAAa,eAAe;AAC1C,aAAO;AAAA,IACT;AAGA,QAAI,KAAK;AACP,YAAM,WAAW,eAAe,GAAG;AACnC,YAAM,WAAW,eAAe,GAAG;AAEnC,aAAO,aAAa,UAAU,YAAY,QAAQ,KAAK,YAAY,QAAQ;AAAA,IAC7E;AAIA,WAAO,CAAC,QAAQ,IAAI,YAAY,QAAQ,IAAI,aAAa;AAAA,EAC3D;AAEA,MAAI,qBAAqB,GAAG;AAE1B,QACE,OAAQ,WAAmB,YAAY,eACtC,WAAmB,YAAY,MAChC;AACA,aAAO;AAAA,IACT;AAGA,QACE,OAAO,WAAW,eACjB,OAAe,gCAChB,OAAO,aAAa,eACpB,YAAY,SAAS,QAAQ,GAC7B;AACA,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,aAAa,aAAa;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,SAAS,YAAY;AACtC,UAAM,OAAO,SAAS,SAAS,QAAQ,IAAI;AAG3C,UAAM,oBAAoB,QAAQ,OAAQ,QAAQ;AAGlD,UAAM,oBACJ,SAAS,aAAa,YAAY,YAAY,QAAQ,KAAK,YAAY,QAAQ;AAEjF,WAAO,YAAY,QAAQ,KAAK,YAAY,QAAQ,KAAK,qBAAqB;AAAA,EAChF;AAEA,SAAO;AACT;AAiBO,SAAS,eAAwB;AACtC,MAAI,kBAAkB,GAAG;AACvB,WAAO,QAAQ,IAAI,aAAa;AAAA,EAClC;AAGA,SAAO,CAAC,cAAc;AACxB;AA2BO,SAAS,SAAkB;AAChC,MAAI,kBAAkB,GAAG;AACvB,WAAO,QAAQ,IAAI,aAAa;AAAA,EAClC;AAEA,SAAO;AACT;AA6BO,SAAS,kBAA2B;AACzC,MAAI,kBAAkB,GAAG;AACvB,WAAO,QAAQ,IAAI,aAAa;AAAA,EAClC;AAEA,SAAO,CAAC,aAAa;AACvB;AA8BO,SAAS,eAAe,KAA6B;AAC1D,MAAI,qBAAqB,GAAG;AAC1B,QAAI,OAAO,aAAa,aAAa;AACnC,aAAO,SAAS,aAAa,WAAW,UAAU;AAAA,IACpD;AACA,WAAO;AAAA,EACT;AAEA,MAAI,KAAK;AAEP,UAAM,iBAAiB,IAAI,MAAM,mBAAmB,KAAK,IAAI,UAAU,mBAAmB;AAC1F,UAAM,oBACJ,IAAI,MAAM,sBAAsB,KAAK,IAAI,UAAU,sBAAsB;AAC3E,UAAM,YAAY,IAAI,MAAM,cAAc,KAAK,IAAI,UAAU,cAAc;AAC3E,UAAM,gBAAgB,IAAI,MAAM,iBAAiB,KAAK,IAAI,UAAU,iBAAiB;AACrF,UAAM,oBAAoB,IAAI,MAAM,YAAY,KAAK,IAAI,UAAU,YAAY;AAG/E,QAAI,gBAAgB;AAClB,aAAO,eAAe,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY;AAAA,IACzD;AACA,QAAI,mBAAmB;AACrB,aAAO,kBAAkB,YAAY;AAAA,IACvC;AACA,QAAI,WAAW;AACb,aAAO,UAAU,YAAY;AAAA,IAC/B;AACA,QAAI,kBAAkB,MAAM;AAC1B,aAAO;AAAA,IACT;AACA,QAAI,mBAAmB;AACrB,UAAI;AACF,cAAM,UAAU,KAAK,MAAM,iBAAiB;AAC5C,YAAI,QAAQ,QAAQ;AAClB,iBAAO,QAAQ,OAAO,YAAY;AAAA,QACpC;AAAA,MACF,SAAS,IAAI;AAAA,MAEb;AAAA,IACF;AAGA,QAAI,IAAI,SAAU,QAAO,IAAI;AAC7B,QAAI,IAAI,OAAQ,QAAO;AAAA,EACzB;AAGA,SAAO;AACT;AA8BO,SAAS,eAAe,KAAmB;AAChD,MAAI,qBAAqB,GAAG;AAC1B,QAAI,OAAO,aAAa,aAAa;AACnC,aAAO,SAAS;AAAA,IAClB;AACA,WAAO;AAAA,EACT;AAEA,MAAI,KAAK;AAEP,UAAM,gBAAgB,IAAI,MAAM,kBAAkB,KAAK,IAAI,UAAU,kBAAkB;AACvF,UAAM,eAAe,IAAI,MAAM,iBAAiB,KAAK,IAAI,UAAU,iBAAiB;AACpF,UAAM,OAAO,IAAI,MAAM,MAAM,KAAK,IAAI,UAAU,MAAM;AAGtD,QAAI,eAAe;AACjB,aAAO,cAAc,MAAM,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC;AAAA,IACxD;AACA,QAAI,cAAc;AAChB,aAAO,aAAa,MAAM,GAAG,EAAE,CAAC;AAAA,IAClC;AACA,QAAI,MAAM;AACR,aAAO,KAAK,MAAM,GAAG,EAAE,CAAC;AAAA,IAC1B;AAGA,QAAI,IAAI,SAAU,QAAO,IAAI;AAAA,EAC/B;AAGA,SAAO;AACT;AAwBO,SAAS,YAAY,UAA2B;AACrD,SACE,aAAa,eACb,aAAa,eACb,aAAa,SACb,SAAS,SAAS,YAAY,KAC9B,SAAS,SAAS,QAAQ;AAE9B;AAuBO,SAAS,YAAY,UAA2B;AAErD,QAAM,eAAe;AAAA,IACnB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AAGA,QAAM,eAAe;AAAA,IACnB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AAEA,SACE,aAAa,KAAK,aAAW,QAAQ,KAAK,QAAQ,CAAC,KACnD,aAAa,KAAK,aAAW,QAAQ,KAAK,QAAQ,CAAC,KACnD,YAAY,QAAQ;AAExB;AA+CO,SAAS,mBAAmB,KAA4B;AAC7D,QAAM,WAAW,kBAAkB,IAAI,SAAS,qBAAqB,IAAI,YAAY;AAErF,MAAI,cAA8C;AAClD,MAAI,kBAAkB,GAAG;AACvB,UAAM,UAAU,QAAQ,IAAI;AAC5B,QAAI,YAAY,iBAAiB,YAAY,QAAQ;AACnD,oBAAc;AAAA,IAChB;AAAA,EACF,WAAW,cAAc,GAAG;AAC1B,kBAAc;AAAA,EAChB;AAEA,QAAM,WAAW,eAAe,GAAG;AACnC,QAAM,WAAW,eAAe,GAAG;AAEnC,QAAM,OAAwB;AAAA,IAC5B;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,MAAI,qBAAqB,KAAK,OAAO,cAAc,aAAa;AAC9D,SAAK,YAAY,UAAU;AAAA,EAC7B;AAGA,QAAM,WAAgC;AAAA,IACpC,aAAa,YAAY,QAAQ;AAAA,IACjC,aAAa,YAAY,QAAQ;AAAA,IACjC,mBAAmB;AAAA,IACnB,aAAa;AAAA,EACf;AAEA,MAAI,qBAAqB,KAAK,OAAO,aAAa,aAAa;AAC7D,UAAM,OAAO,SAAS,SAAS,QAAQ,IAAI;AAC3C,aAAS,oBAAoB,QAAQ,OAAQ,QAAQ;AACrD,aAAS,cAAc,CAAC,EACtB,OAAO,WAAW,eAAgB,OAAe;AAAA,EAErD;AAEA,MAAI,kBAAkB,GAAG;AACvB,aAAS,UAAU,QAAQ,IAAI,YAAY;AAAA,EAC7C;AAEA,OAAK,WAAW;AAEhB,SAAO;AACT;AA0EO,SAAS,cAAc,OAAgC;AAE5D,MAAI,UAAU,UAAa,UAAU,QAAQ,UAAU,IAAI;AACzD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,KAAK;AAG3B,MAAI,YAAY,OAAQ,QAAO;AAC/B,MAAI,YAAY,YAAa,QAAO;AAGpC,QAAM,aAAa,QAAQ,YAAY;AACvC,MAAI,eAAe,UAAU,eAAe,MAAO,QAAO;AAC1D,MAAI,eAAe,WAAW,eAAe,KAAM,QAAO;AAG1D,MAAI,YAAY,IAAK,QAAO;AAC5B,MAAI,YAAY,IAAK,QAAO;AAG5B,MAAI,gBAAgB,KAAK,OAAO,GAAG;AAEjC,QAAI,QAAQ,SAAS,KAAK,QAAQ,CAAC,MAAM,OAAO,QAAQ,CAAC,MAAM,KAAK;AAClE,aAAO;AAAA,IACT;AACA,UAAM,MAAM,OAAO,OAAO;AAC1B,QAAI,CAAC,MAAM,GAAG,EAAG,QAAO;AAAA,EAC1B;AAGA,MACG,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,KAC/C,QAAQ,WAAW,GAAG,KAAK,QAAQ,SAAS,GAAG,GAChD;AACA,QAAI;AACF,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,MAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,UAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC;AAElD,QAAI,MAAM,MAAM,OAAK,EAAE,SAAS,CAAC,GAAG;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AAGA,SAAO;AACT;AAzsBA,IA+kBa,QAMA;AArlBb;AAAA;AAAA;AA+kBO,IAAM,SAAS;AAMf,IAAM,YAAY;AAAA;AAAA;;;ACrlBzB;AAAA;AAAA;AAAA;AA2RO,SAAS,iBAAiB,MAAa,SAAqC;AAEjF,MAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,GAAG;AACjC,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM;AAAA,IACJ,aAAa;AAAA,IACb,eAAe;AAAA,IACf,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb;AAAA,EACF,IAAI,WAAW,CAAC;AAGhB,QAAM,UAAU,oBAAI,QAAa;AAEjC,QAAM,WAAW,CAAC,SAAsB;AACtC,QAAI;AACF,UAAI,cAAe,QAAO,OAAO,cAAc,IAAI,CAAC;AACpD,UAAI,QAAQ,KAAM,QAAO;AACzB,UAAI,OAAO,SAAS,SAAU,QAAO,OAAO,IAAI;AAChD,aAAO,KAAK,UAAU,KAAK,OAAO,OAAO,KAAK,UAAU,CAAC,IAAI,OAAO,IAAI;AAAA,IAC1E,SAAS,QAAQ;AAEf,aAAO;AAAA,IACT;AAAA,EACF;AAEA,QAAM,aAAa,CACjB,MACA,SAAiB,IACjB,SAAkB,MAClB,QAAgB,MACL;AAEX,QAAI,QAAQ,MAAM;AAChB,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,SAAS,YAAY,QAAQ,IAAI,IAAI,GAAG;AACjD,aAAO,GAAG,UAAU,SAAS,aAAa,aAAa;AAAA,IACzD;AAGA,QAAI,QAAQ,KAAK;AACf,aAAO,GAAG,UAAU,SAAS,aAAa,aAAa;AAAA,IACzD;AAEA,QAAI,OAAO,SAAS,UAAU;AAC5B,cAAQ,IAAI,IAAI;AAAA,IAClB;AAEA,UAAM,QAAkB,CAAC;AACzB,UAAM,gBAAgB,SAAS,aAAa;AAC5C,UAAM,KAAK,SAAS,gBAAgB,SAAS,IAAI,CAAC;AAGlD,UAAM,WAAW,MAAM,QAAQ,KAAK,QAAQ,IACxC,KAAK,SAAS,OAAO,CAAC,UAAe,SAAS,IAAI,IAClD,CAAC;AAEL,UAAM,aAAa,UAAU,SAAS,aAAa;AAEnD,aAAS,QAAQ,CAAC,OAAY,UAAkB;AAC9C,YAAM,cAAc,UAAU,SAAS,SAAS;AAChD,YAAM,cAAc,WAAW,OAAO,YAAY,aAAa,QAAQ,CAAC;AACxE,UAAI,aAAa;AACf,cAAM,KAAK,WAAW;AAAA,MACxB;AAAA,IACF,CAAC;AAED,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAGA,QAAM,aAAa,KAAK,OAAO,UAAQ,QAAQ,IAAI;AAEnD,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO;AAAA,EACT;AAEA,SAAO,WACJ,IAAI,CAAC,MAAM,UAAU,WAAW,MAAM,IAAI,UAAU,WAAW,SAAS,CAAC,CAAC,EAC1E,KAAK,IAAI;AACd;AAtXA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwEO,SAAS,gBAAgB,UAA2B;AAEzD,MAAI,CAAC,YAAY,OAAO,aAAa,SAAU,QAAO;AAGtD,MAAI,OAAO,aAAa,SAAU,QAAO;AAGzC,MAAI,SAAS,WAAW,KAAK,SAAS,SAAS,IAAM,QAAO;AAI5D,MAAI,SAAS,SAAS,KAAK,KAAK,SAAS,SAAS,MAAM,EAAG,QAAO;AAGlE,QAAM,qBAAqB,CAAC,MAAM,QAAQ,QAAQ,QAAQ,OAAO,OAAO;AACxE,MAAI,mBAAmB,KAAK,aAAW,SAAS,SAAS,OAAO,CAAC,EAAG,QAAO;AAG3E,QAAM,kBAAkB;AAAA,IACtB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACA,MAAI,gBAAgB,KAAK,aAAW,SAAS,YAAY,EAAE,SAAS,OAAO,CAAC,EAAG,QAAO;AAGtF,MAAI,SAAS,SAAS,IAAM,EAAG,QAAO;AAGtC,QAAM,eAAe,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AACjE,MAAI,aAAa,KAAK,UAAQ,SAAS,SAAS,IAAI,CAAC,EAAG,QAAO;AAG/D,QAAM,cAAc,CAAC,KAAK,KAAK,MAAM,MAAM,MAAM,QAAQ,UAAU,SAAS,QAAQ;AACpF,QAAM,YAAY,SAAS,YAAY;AACvC,MACE,YAAY;AAAA,IACV,aACE,UAAU,SAAS,QAAQ,YAAY,CAAC,MACvC,YAAY,OAAO,YAAY,OAAO,UAAU,SAAS,IAAI,QAAQ,YAAY,CAAC,EAAE;AAAA,EACzF;AAEA,WAAO;AAGT,QAAM,mBAAmB;AAAA,IACvB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACA,MAAI,iBAAiB,KAAK,UAAQ,SAAS,SAAS,IAAI,CAAC,EAAG,QAAO;AAGnE,MAAI,uBAAuB,KAAK,QAAQ,EAAG,QAAO;AAElD,SAAO;AACT;AA0DO,SAAS,gBAAgBA,OAAc,SAA0B;AACtE,SAAO,OAAOA,UAAS,YAAYA,SAAQ,KAAKA,SAAQ;AAC1D;AAoFO,SAAS,mBAAmB,SAAiB,UAAkC,CAAC,GAAY;AACjG,QAAM,EAAE,YAAY,IAAU,IAAI;AAGlC,MAAI,OAAO,YAAY,SAAU,QAAO;AAGxC,MAAI,QAAQ,SAAS,UAAW,QAAO;AAEvC,QAAM,eAAe,QAAQ,YAAY;AAGzC,QAAM,iBAAiB,CAAC,WAAW,YAAY,mBAAmB,WAAa;AAC/E,MAAI,eAAe,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG3E,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,cAAc,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG1E,QAAM,mBAAmB;AAAA,IACvB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,MAAI,iBAAiB,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG7E,QAAM,kBAAkB;AAAA,IACtB;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,IACA;AAAA;AAAA,EACF;AACA,MAAI,gBAAgB,KAAK,aAAW,aAAa,SAAS,OAAO,CAAC,EAAG,QAAO;AAG5E,MAAI,aAAa,SAAS,MAAM,KAAK,aAAa,SAAS,QAAQ,EAAG,QAAO;AAG7E,MAAI,aAAa,SAAS,SAAS,EAAG,QAAO;AAE7C,SAAO;AACT;AA5UA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AA8GA,eAAsB,UAAU,MAAa,UAAkB,SAA8B;AAE3F,MAAI,QAAQ,MAAM;AAChB,UAAM,IAAI,UAAU,kCAAkC;AAAA,EACxD;AAEA,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,UAAM,IAAI,UAAU,uBAAuB;AAAA,EAC7C;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,IAAI,MAAM,4BAA4B;AAAA,EAC9C;AAEA,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,IAAI;AACvE,UAAM,IAAI,UAAU,sCAAsC;AAAA,EAC5D;AAEA,QAAM,UAAU,iBAAAC,QAAK,QAAQ,MAAM;AAAA,IACjC,WAAW;AAAA,IACX,QAAQ;AAAA,IACR,GAAG;AAAA,EACL,CAAC;AAED,MAAI,OAAO,GAAG;AACZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,GAAG,UAAU,UAAU,SAAS,OAAO,IAAI,EAAE,UAAU,QAAQ,CAAC;AAAA,EACxE,OAAO;AACL,UAAM,OAAO,IAAI,KAAK,CAAC,SAAS,OAAO,EAAE,GAAG,EAAE,MAAM,yBAAyB,CAAC;AAC9E,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,OAAO;AACZ,SAAK,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAC7C,aAAS,KAAK,YAAY,IAAI;AAC9B,SAAK,MAAM;AACX,aAAS,KAAK,YAAY,IAAI;AAC9B,QAAI,gBAAgB,GAAG;AAAA,EACzB;AACF;AAsHA,eAAsB,UAAU,UAAkB,SAA+B;AAE/E,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,IAAI;AACvE,UAAM,IAAI,UAAU,sCAAsC;AAAA,EAC5D;AAEA,MAAI,OAAO,GAAG;AACZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,UAAU,MAAM,GAAG,SAAS,UAAU,EAAE,UAAU,QAAQ,CAAC;AACjE,UAAM,cAAc,iBAAAA,QAAK,MAAM,SAAS;AAAA,MACtC,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,gBAAgB;AAAA,MAChB,GAAG;AAAA,IACL,CAAC;AACD,WAAO,YAAY,QAAQ,CAAC;AAAA,EAC9B,OAAO;AACL,UAAM,IAAI,MAAM,+EAA+E;AAAA,EACjG;AACF;AA7RA,IAaA;AAbA;AAAA;AAAA;AAaA,uBAAiB;AACjB;AAAA;AAAA;;;ACdA;AAAA;AAAA;AAAA;AAAA;AAoIA,eAAsB,WACpB,MACA,UACA,SACe;AAEf,MAAI,SAAS,QAAQ,SAAS,QAAW;AACvC,UAAM,IAAI,UAAU,kCAAkC;AAAA,EACxD;AAEA,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,IAAI;AACvE,UAAM,IAAI,UAAU,sCAAsC;AAAA,EAC5D;AAEA,QAAM,EAAE,SAAS,EAAE,IAAI,WAAW,CAAC;AAGnC,MAAI;AACJ,MAAI;AACF,eAAW,KAAK,UAAU,MAAM,MAAM,MAAM;AAAA,EAC9C,SAAS,OAAO;AACd,QAAI,iBAAiB,aAAa,MAAM,QAAQ,SAAS,UAAU,GAAG;AACpE,YAAM,IAAI,UAAU,gDAAgD;AAAA,IACtE;AACA,UAAM;AAAA,EACR;AAEA,MAAI,OAAO,GAAG;AACZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,GAAG,UAAU,UAAU,UAAU,EAAE,UAAU,QAAQ,CAAC;AAAA,EAC9D,OAAO;AACL,UAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,GAAG,EAAE,MAAM,iCAAiC,CAAC;AAC5E,UAAM,MAAM,IAAI,gBAAgB,IAAI;AACpC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,OAAO;AACZ,SAAK,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAC7C,aAAS,KAAK,YAAY,IAAI;AAC9B,SAAK,MAAM;AACX,aAAS,KAAK,YAAY,IAAI;AAC9B,QAAI,gBAAgB,GAAG;AAAA,EACzB;AACF;AAuJA,eAAsB,WAAW,UAAkB,UAA8B;AAE/E,MAAI,CAAC,YAAY,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,IAAI;AACvE,UAAM,IAAI,UAAU,sCAAsC;AAAA,EAC5D;AAEA,MAAI,OAAO,GAAG;AACZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,UAAU,MAAM,GAAG,SAAS,UAAU,EAAE,UAAU,QAAQ,CAAC;AAGjE,UAAM,UAAU,QAAQ,KAAK;AAC7B,QAAI,YAAY,IAAI;AAClB,YAAM,IAAI,YAAY,oBAAoB;AAAA,IAC5C;AAGA,QAAI;AACF,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM,IAAI,YAAY,wBAAwB,QAAQ,KAAK,MAAM,OAAO,EAAE;AAAA,MAC5E;AACA,YAAM;AAAA,IACR;AAAA,EACF,OAAO;AACL,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAlWA;AAAA;AAAA;AAaA;AAAA;AAAA;;;ACbA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,uBAAsB;AAMtB,IAAM,gBAAgB,CAAC,KAAa,QAAwB;AAC1D,SAAO,KAAK,MAAM,KAAK,OAAO,KAAK,MAAM,MAAM,EAAE,IAAI;AACvD;AAEA,IAAM,eAAe,CAAC,QAAgB,SAA0B;AAC9D,QAAM,QAAQ,QAAQ;AACtB,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAU,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AAAA,EACjE;AACA,SAAO;AACT;AAEA,IAAM,oBAAoB,CAAC,QAAgB,WAAuC;AAChF,QAAM,QAAQ;AACd,MAAI,SAAS,aAAa,QAAQ,KAAK;AACvC,MAAI,WAAW,QAAS,UAAS,OAAO,YAAY;AACpD,MAAI,WAAW,QAAS,UAAS,OAAO,YAAY;AACpD,SAAO;AACT;AAEA,IAAM,2BAA2B,CAAC,QAAgB,WAAuC;AACvF,QAAM,QAAQ;AACd,MAAI,SAAS,aAAa,QAAQ,KAAK;AACvC,MAAI,WAAW,QAAS,UAAS,OAAO,YAAY;AACpD,MAAI,WAAW,QAAS,UAAS,OAAO,YAAY;AACpD,SAAO;AACT;AAEA,IAAM,UAAU,CAAI,UAAkB;AACpC,SAAO,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AACvD;AAEA,IAAM,aAAa,CAAC,aAAa,OAAgB;AAC/C,SAAO,KAAK,OAAO,IAAI,MAAM;AAC/B;AAkBO,IAAM,wBAAwB,CAAC,MAAM,GAAG,MAAM,QAAgB;AACnE,SAAO,cAAc,KAAK,GAAG;AAC/B;AAeO,IAAM,sBAAsB,CACjC,UAAuE,CAAC,MAC7D;AACX,QAAM,EAAE,SAAS,IAAI,SAAS,OAAU,IAAI;AAC5C,SAAO,kBAAkB,QAAQ,MAAM;AACzC;AAeO,IAAM,6BAA6B,CACxC,UAAuE,CAAC,MAC7D;AACX,QAAM,EAAE,SAAS,IAAI,SAAS,OAAU,IAAI;AAC5C,SAAO,yBAAyB,QAAQ,MAAM;AAChD;AAeO,IAAM,wBAAwB,CACnC,UAAuE,CAAC,MAC7D;AACX,QAAM,EAAE,SAAS,IAAI,QAAQ,UAAU,OAAU,IAAI;AACrD,SAAO,aAAa,MAAM;AAC5B;AAcO,IAAM,4BAA4B,CAAC,OAAe,eAAe,MAAc;AACpF,MAAI,CAAC,SAAS,CAAC,MAAM,SAAS,GAAG;AAC/B,WAAO,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,IAAI,YAAY,CAAC,CAAC;AAEtE,QAAM,YAAY,MAAM,MAAM,GAAG,EAAE,CAAC;AACpC,QAAM,WAAW,UACd,YAAY,EACZ,QAAQ,cAAc,EAAE,EACxB,UAAU,GAAG,EAAE;AAElB,QAAM,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,IAAI,YAAY,CAAC;AAC1E,SAAO,WAAW;AACpB;AAeO,IAAM,mBAAmB,CAAC,YAAY,IAAI,eAAe,GAAG,SAAS,MAAc;AACxF,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,QAAQ,CAAC,OAAO,OAAO,QAAQ,QAAQ,QAAQ,QAAQ,QAAQ,SAAS,SAAS,OAAO;AAE9F,QAAM,YAAY,WAAW,KAAK,MAAM,KAAK,OAAO,IAAI,WAAW,MAAM,CAAC;AAC1E,QAAM,OAAO,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AAC3D,QAAM,eAAe,KAAK,MAAM,KAAK,OAAO,IAAI,KAAK,IAAI,IAAI,YAAY,CAAC;AAE1E,QAAM,WAAW,YAAY,YAAY,OAAO;AAEhD,SAAO,SAAS,SAAS,SAAS,SAAS,UAAU,GAAG,MAAM,IAAI;AACpE;AAmBO,IAAM,qBAAqB,MAAc;AAC9C,QAAM,SAAS,cAAc,KAAU,QAAQ;AAC/C,QAAM,UAAU;AAChB,QAAM,SAAS,QAAQ,SAAS,EAAE;AAClC,SAAO,GAAG,MAAM,GAAG,MAAM;AAC3B;AAgBO,IAAM,qBAAqB,MAAc;AAC9C,QAAM,WAAW,CAAC,KAAK,KAAK,GAAG;AAC/B,QAAM,iBAAiB,QAAQ,QAAQ;AACvC,QAAM,cAAc,mBAAmB,MAAM,IAAI,mBAAmB,MAAM,IAAI;AAC9E,QAAM,SAAS,cAAc,KAAS,OAAO;AAC7C,QAAM,UAAU;AAChB,QAAM,oBAAoB,cAAc,MAAW;AACnD,QAAM,SAAS,QAAQ,oBAAoB,EAAE;AAC7C,SAAO,GAAG,cAAc,GAAG,MAAM,GAAG,MAAM;AAC5C;AAqBO,IAAM,qBAAqB,MAAc;AAC9C,QAAM,oBAAoB;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,mBAAmB,QAAQ,iBAAiB;AAClD,QAAM,SAAS,cAAc,KAAS,OAAO,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AAGzE,MAAIC,OAAM;AACV,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,QAAQ,SAAS,OAAO,CAAC,CAAC;AAC9B,QAAI,IAAI,MAAM,GAAG;AACf,eAAS;AACT,UAAI,QAAQ,EAAG,SAAQ,KAAK,MAAM,QAAQ,EAAE,IAAK,QAAQ;AAAA,IAC3D;AACA,IAAAA,QAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,KAAMA,OAAM,MAAO;AACzC,QAAM,gBAAgB,aAAa,YAAY;AAC/C,QAAM,UAAU,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,EAAE,SAAS,gBAAgB,IACpE,gBACA,WAAW,IACT,aAAa,SAAS,IACtB;AAEN,SAAO,GAAG,gBAAgB,GAAG,MAAM,GAAG,OAAO;AAC/C;AAEO,IAAM,4BAA4B,MAAc;AACrD,QAAM,gBAAgB;AAAA,IACpB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,QAAM,aAAa,QAAQ,aAAa;AACxC,QAAM,kBAAkB,aAAa,GAAG,YAAY;AACpD,SAAO,GAAG,UAAU,GAAG,eAAe;AACxC;AAEO,IAAM,sBAAsB,MAAc;AAC/C,QAAM,WAAW,aAAa,GAAG,YAAY;AAC7C,QAAM,aAAa,aAAa,GAAG,YAAY;AAC/C,QAAM,gBAAgB,aAAa,GAAG,YAAY;AAClD,QAAM,gBAAgB,aAAa,IAAI,YAAY;AAGnD,QAAM,cAAc,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,GAAG,aAAa;AAC5E,QAAM,aAAa,GAAG,WAAW;AAGjC,QAAM,cAAc,OAAO,MAAO,OAAO,UAAU,IAAI,GAAI,EAAE,SAAS,GAAG,GAAG;AAE5E,SAAO,KAAK,WAAW,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,GAAG,aAAa;AACjF;AAMO,IAAM,gBAAgB,CAAC,WAA4B;AACxD,QAAM,aAAa;AAAA,IACjB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,YAAY;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,CAAC,aAAa,eAAe,YAAY,eAAe,UAAU;AAElF,QAAM,YAAY,QAAQ,UAAU;AACpC,QAAM,WAAW,QAAQ,SAAS;AAClC,QAAM,cAAc,UAAU,QAAQ,OAAO;AAE7C,QAAM,UAAU;AAAA,IACd,GAAG,UAAU,YAAY,CAAC,IAAI,SAAS,YAAY,CAAC,IAAI,WAAW;AAAA,IACnE,GAAG,UAAU,YAAY,CAAC,GAAG,cAAc,GAAG,EAAE,CAAC,IAAI,WAAW;AAAA,IAChE,GAAG,UAAU,YAAY,CAAC,IAAI,SAAS,YAAY,CAAC,GAAG,cAAc,GAAG,CAAC,CAAC,IAAI,WAAW;AAAA,IACzF,GAAG,UAAU,YAAY,CAAC,GAAG,SAAS,YAAY,CAAC,IAAI,WAAW;AAAA,EACpE;AAEA,QAAM,WAAW,QAAQ,OAAO;AAChC,SAAO,SAAS,YAAY;AAC9B;AAEO,IAAM,mBAAmB,CAC9B,UAMI,CAAC,MACM;AACX,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,EACnB,IAAI;AAEJ,QAAM,YAAY;AAClB,QAAM,YAAY;AAClB,QAAM,eAAe,UAAU,cAAc,WAAW,SAAS;AAEjE,QAAM,aAAa;AACnB,QAAM,aAAa;AACnB,QAAM,cAAc;AACpB,QAAM,cAAc;AAEpB,MAAI,UAAU;AACd,MAAI,gBAAgB;AAEpB,MAAI,kBAAkB;AACpB,eAAW;AACX,qBAAiB,WAAW,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,WAAW,MAAM,CAAC;AAAA,EAClF;AACA,MAAI,kBAAkB;AACpB,eAAW;AACX,qBAAiB,WAAW,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,WAAW,MAAM,CAAC;AAAA,EAClF;AACA,MAAI,gBAAgB;AAClB,eAAW;AACX,qBAAiB,YAAY,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,YAAY,MAAM,CAAC;AAAA,EACpF;AACA,MAAI,gBAAgB;AAClB,eAAW;AACX,qBAAiB,YAAY,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,YAAY,MAAM,CAAC;AAAA,EACpF;AAEA,MAAI,CAAC,QAAS,WAAU;AAExB,MAAI,WAAW;AACf,QAAM,kBAAkB,eAAe,cAAc;AAErD,WAAS,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACxC,gBAAY,QAAQ,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,QAAQ,MAAM,CAAC;AAAA,EACvE;AAEA,SAAO,SACJ,MAAM,EAAE,EACR,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG,EAC9B,KAAK,EAAE;AACZ;AAEO,IAAM,mBAAmB,CAAC,gBAAkC;AACjE,QAAM,WAAW;AACjB,QAAM,iBAAiB,gBAAgB,SAAY,cAAc,WAAW;AAE5E,MAAI,gBAAgB;AAClB,UAAM,IAAI,QAAQ,SAAS,MAAM,EAAE,CAAC;AACpC,UAAMC,KAAI,QAAQ,SAAS,MAAM,EAAE,CAAC;AACpC,UAAM,IAAI,QAAQ,SAAS,MAAM,EAAE,CAAC;AACpC,WAAO,IAAI,CAAC,GAAGA,EAAC,GAAG,CAAC;AAAA,EACtB,OAAO;AACL,UAAM,QAAQ,aAAa,GAAG,QAAQ;AACtC,WAAO,IAAI,KAAK;AAAA,EAClB;AACF;AAsBO,IAAM,aAAa,CAAC,QAAyB;AAClD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAE5C,QAAM,WAAW,IAAI,KAAK,EAAE,YAAY;AACxC,QAAM,WAAW;AAEjB,MAAI,CAAC,SAAS,KAAK,QAAQ,EAAG,QAAO;AAErC,QAAM,SAAS,SAAS,SAAS,UAAU,GAAG,CAAC,CAAC;AAChD,QAAM,SAAS,SAAS,OAAO,CAAC;AAChC,QAAM,UAAU;AAChB,QAAM,iBAAiB,QAAQ,SAAS,EAAE;AAE1C,SAAO,WAAW;AACpB;AAYO,IAAM,cAAc;AAmBpB,IAAM,aAAa,CAAC,QAAyB;AAClD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAE5C,QAAM,WAAW,IAAI,KAAK,EAAE,YAAY;AACxC,QAAM,WAAW;AAEjB,MAAI,CAAC,SAAS,KAAK,QAAQ,EAAG,QAAO;AAErC,QAAM,SAAS,SAAS,OAAO,CAAC;AAChC,QAAM,SAAS,SAAS,SAAS,UAAU,GAAG,CAAC,CAAC;AAChD,QAAM,SAAS,SAAS,OAAO,CAAC;AAEhC,QAAM,cAAc,WAAW,MAAM,IAAI,WAAW,MAAM,IAAI;AAC9D,QAAM,oBAAoB,cAAc,MAAW;AACnD,QAAM,UAAU;AAChB,QAAM,iBAAiB,QAAQ,oBAAoB,EAAE;AAErD,SAAO,WAAW;AACpB;AAEO,IAAM,aAAa,CAAC,QAAyB;AAClD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAE5C,QAAM,WAAW,IAAI,KAAK,EAAE,YAAY;AACxC,QAAM,WAAW;AAEjB,MAAI,CAAC,SAAS,KAAK,QAAQ,EAAG,QAAO;AAErC,QAAM,mBAAmB,SAAS,OAAO,CAAC;AAC1C,QAAM,SAAS,SAAS,UAAU,GAAG,CAAC;AACtC,QAAM,UAAU,SAAS,OAAO,CAAC;AAEjC,MAAID,OAAM;AACV,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,QAAI,QAAQ,SAAS,OAAO,CAAC,CAAC;AAC9B,QAAI,IAAI,MAAM,GAAG;AACf,eAAS;AACT,UAAI,QAAQ,EAAG,SAAQ,KAAK,MAAM,QAAQ,EAAE,IAAK,QAAQ;AAAA,IAC3D;AACA,IAAAA,QAAO;AAAA,EACT;AAEA,QAAM,gBAAgB,KAAMA,OAAM,MAAO;AACzC,QAAM,gBAAgB,aAAa,YAAY;AAE/C,MAAI,CAAC,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG,EAAE,SAAS,gBAAgB,GAAG;AAC7D,WAAO,YAAY;AAAA,EACrB,OAAO;AACL,WAAO,YAAY,aAAa,SAAS,KAAK,YAAY;AAAA,EAC5D;AACF;AAEO,IAAM,2BAA2B,CAAC,eAAgC;AACvE,MAAI,CAAC,cAAc,OAAO,eAAe,SAAU,QAAO;AAE1D,QAAM,YAAY,WAAW,KAAK;AAClC,QAAM,kBAAkB;AAExB,SAAO,gBAAgB,KAAK,SAAS;AACvC;AAEO,IAAM,sBAAsB,CAAC,UAA2B;AAC7D,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAEhD,QAAM,aAAa,MAAM,QAAQ,aAAa,EAAE;AAChD,QAAM,aAAa;AAEnB,SAAO,WAAW,KAAK,UAAU;AACnC;AAEO,IAAM,eAAe,CAAC,UAA2B;AACtD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAChD,SAAO,iBAAAE,QAAU,QAAQ,KAAK;AAChC;AAEO,IAAM,aAAa,CAAC,QAAyB;AAClD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAE5C,MAAI,iBAAAA,QAAU,MAAM,KAAK,EAAE,kBAAkB,KAAK,CAAC,GAAG;AACpD,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,WAAO,OAAO,aAAa,eAAe,OAAO,aAAa;AAAA,EAChE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,cAAc,CAAC,QAAyB;AACnD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAC5C,MAAI;AACF,SAAK,MAAM,GAAG;AACd,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,qBAAqB,CAAC,SAA0B;AAC3D,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAE9C,QAAM,YAAY,KAAK,QAAQ,OAAO,EAAE,EAAE,YAAY;AACtD,QAAM,YAAY;AAElB,MAAI,CAAC,UAAU,KAAK,SAAS,EAAG,QAAO;AAEvC,QAAM,aAAa,UAAU,UAAU,CAAC,IAAI,UAAU,UAAU,GAAG,CAAC;AACpE,QAAM,gBAAgB,WAAW,QAAQ,UAAU,YAAU;AAC3D,YAAQ,OAAO,WAAW,CAAC,IAAI,IAAI,SAAS;AAAA,EAC9C,CAAC;AAED,MAAI,YAAY;AAChB,WAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AAC7C,iBAAa,YAAY,KAAK,SAAS,cAAc,CAAC,CAAC,KAAK;AAAA,EAC9D;AAEA,SAAO,cAAc;AACvB;;;AC/qBA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwEO,IAAM,iBAAiB,CAAC,UAAiC;AAC9D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,QAAQ,MAAM,QAAQ,kBAAkB,EAAE,CAAC,EAAE,YAAY;AAClE;AAEA,SAAS,QAAQ,KAAqB;AACpC,QAAM,OAAO,IAAI,QAAQ,2CAA2C,EAAE;AACtE,SAAO,KAAK,QAAQ,MAAM,GAAG;AAC/B;AAOO,IAAM,iBAAiB,CAAC,UAAiC;AAC9D,MAAI,CAAC,MAAO,QAAO;AACnB,SAAO,MAAM,QAAQ,yBAAyB,EAAE;AAClD;AAsFO,IAAM,iBAAiB,CAAC,KAAa,YAAY,IAAI,SAAS,UAAkB;AACrF,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IAAI,SAAS,YAAY,IAAI,UAAU,GAAG,SAAS,IAAI,SAAS;AACzE;AAOO,IAAM,kBAAkB,CAAC,UAA0B;AACxD,SAAO,KAAK,UAAU,KAAK,MAAM,IAAI,KAAK,GAAG,CAAC,EAAE,QAAQ,YAAY,IAAI;AAC1E;AAQO,IAAM,iBAAiB,CAAC,KAAa,aAA6B;AACvE,SAAO,IAAI,SAAS,QAAQ,IAAI,MAAM,GAAG,GAAG,GAAG,QAAQ;AACzD;AAQO,IAAM,eAAe,CAAC,KAAa,aAA6B;AACrE,SAAO,IAAI,SAAS,QAAQ,IAAI,IAAI,MAAM,GAAG,KAAK,SAAS,MAAM,IAAI;AACvE;AAQO,IAAM,mBAAmB,CAAC,KAAa,YAA4B;AACxE,SAAO,IAAI,WAAW,OAAO,IAAI,MAAM,GAAG,OAAO,GAAG,GAAG;AACzD;AAQO,IAAM,iBAAiB,CAAC,KAAa,YAA4B;AACtE,SAAO,IAAI,WAAW,OAAO,IAAI,IAAI,MAAM,QAAQ,MAAM,IAAI;AAC/D;AAOO,IAAM,cAAc,CAAC,QAAwB;AAClD,SAAO,IAAI,YAAY;AACzB;AAOO,IAAM,cAAc,CAAC,QAAwB;AAClD,SAAO,IAAI,YAAY;AACzB;AAOO,IAAM,kBAAkB,CAAC,QAAwB;AACtD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IAAI,OAAO,CAAC,EAAE,YAAY,IAAI,IAAI,MAAM,CAAC,EAAE,YAAY;AAChE;AAOO,IAAM,qBAAqB,CAAC,QAAwB;AACzD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IACJ,MAAM,GAAG,EACT,IAAI,UAAQ,gBAAgB,IAAI,CAAC,EACjC,KAAK,GAAG;AACb;AAwHO,IAAM,cAAc,CAAC,QAAwB;AAClD,MAAI,CAAC,IAAK,QAAO;AAGjB,QAAM,QAAQ,IACX,QAAQ,mBAAmB,OAAO,EAClC,MAAM,SAAS,EACf,OAAO,UAAQ,KAAK,SAAS,CAAC,EAC9B,IAAI,UAAQ,KAAK,YAAY,CAAC;AAEjC,MAAI,MAAM,WAAW,EAAG,QAAO;AAG/B,SACE,MAAM,CAAC,IACP,MACG,MAAM,CAAC,EACP,IAAI,UAAQ,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,EACxD,KAAK,EAAE;AAEd;AAoFO,IAAM,cAAc,CAAC,QAAwB;AAClD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IACJ,QAAQ,QAAQ,GAAG,EACnB,MAAM,eAAe,EACrB,IAAI,UAAQ,KAAK,YAAY,CAAC,EAC9B,KAAK,GAAG;AACb;AA0GO,IAAM,cAAc,CAAC,QAAwB;AAClD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IACJ,QAAQ,WAAW,GAAG,EACtB,QAAQ,sBAAsB,OAAO,EACrC,YAAY,EACZ,QAAQ,eAAe,GAAG,EAC1B,QAAQ,OAAO,GAAG,EAClB,QAAQ,UAAU,EAAE;AACzB;AA6GO,IAAM,eAAe,CAAC,QAAwB;AACnD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IACJ,QAAQ,gBAAgB,CAAC,GAAG,SAAU,OAAO,KAAK,YAAY,IAAI,EAAG,EACrE,QAAQ,MAAM,UAAQ,KAAK,YAAY,CAAC;AAC7C;AASO,IAAM,WAAW,CAAC,KAAa,WAAmB,gBAAgB,UAAmB;AAC1F,MAAI,eAAe;AACjB,WAAO,IAAI,SAAS,SAAS;AAAA,EAC/B;AACA,SAAO,IAAI,YAAY,EAAE,SAAS,UAAU,YAAY,CAAC;AAC3D;AASO,IAAM,aAAa,CAAC,KAAa,WAAmB,gBAAgB,UAAmB;AAC5F,MAAI,eAAe;AACjB,WAAO,IAAI,WAAW,SAAS;AAAA,EACjC;AACA,SAAO,IAAI,YAAY,EAAE,WAAW,UAAU,YAAY,CAAC;AAC7D;AASO,IAAM,WAAW,CAAC,KAAa,WAAmB,gBAAgB,UAAmB;AAC1F,MAAI,eAAe;AACjB,WAAO,IAAI,SAAS,SAAS;AAAA,EAC/B;AACA,SAAO,IAAI,YAAY,EAAE,SAAS,UAAU,YAAY,CAAC;AAC3D;AASO,IAAM,WAAW,CAAC,KAAa,QAAgB,UAAU,QAAgB;AAC9E,SAAO,IAAI,SAAS,QAAQ,OAAO;AACrC;AASO,IAAM,SAAS,CAAC,KAAa,QAAgB,UAAU,QAAgB;AAC5E,MAAI,IAAI,UAAU,OAAQ,QAAO;AACjC,SAAO,MAAM,QAAQ,OAAO,SAAS,IAAI,MAAM;AACjD;AAOO,IAAM,OAAO,CAAC,QAAwB;AAC3C,SAAO,IAAI,KAAK;AAClB;AAOO,IAAM,YAAY,CAAC,QAAwB;AAChD,SAAO,IAAI,UAAU;AACvB;AAOO,IAAM,UAAU,CAAC,QAAwB;AAC9C,SAAO,IAAI,QAAQ;AACrB;AAOO,IAAM,gBAAgB,CAAC,QAAwB;AACpD,SAAO,IAAI,MAAM,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE;AACxC;AAQO,IAAM,eAAe,CAAC,KAAa,UAA0B;AAClE,SAAO,IAAI,OAAO,KAAK;AACzB;AASO,IAAM,wBAAwB,CACnC,KACA,WACA,eACW;AACX,SAAO,IAAI,MAAM,SAAS,EAAE,KAAK,UAAU;AAC7C;AAQO,IAAM,mBAAmB,CAAC,KAAa,cAA8B;AAC1E,MAAI,CAAC,UAAW,QAAO;AACvB,MAAI,QAAQ;AACZ,MAAI,WAAW;AAEf,UAAQ,WAAW,IAAI,QAAQ,WAAW,QAAQ,OAAO,IAAI;AAC3D;AACA,gBAAY;AAAA,EACd;AAEA,SAAO;AACT;AAOO,IAAM,UAAU,CAAC,QAA4C;AAClE,SAAO,CAAC,OAAO,IAAI,KAAK,EAAE,WAAW;AACvC;AAOO,IAAM,UAAU,CAAC,QAAyB;AAC/C,QAAM,KACJ;AACF,SAAO,GAAG,KAAK,IAAI,YAAY,CAAC;AAClC;AAiIO,IAAM,YAAY,CAAC,QAAwB;AAChD,SAAO,IACJ,YAAY,EACZ,KAAK,EACL,QAAQ,aAAa,EAAE,EACvB,QAAQ,YAAY,GAAG,EACvB,QAAQ,YAAY,EAAE;AAC3B;AAsIO,IAAM,gBAAgB,CAAC,QAAwB;AACpD,SAAO,IAAI,UAAU,KAAK,EAAE,QAAQ,oBAAoB,EAAE;AAC5D;AAyJO,IAAM,kBAAkB,CAAC,QAAwB;AACtD,QAAM,cAAyC;AAAA,IAC7C,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AACA,SAAO,IAAI,QAAQ,YAAY,WAAS,YAAY,KAAK,CAAC;AAC5D;AAOO,IAAM,oBAAoB,CAAC,QAAwB;AACxD,QAAM,gBAA2C;AAAA,IAC/C,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AACA,SAAO,IAAI,QAAQ,iCAAiC,WAAS,cAAc,KAAK,CAAC;AACnF;AA4DO,SAAS,iBAAiB,MAAc,SAA0B;AACvE,MAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,CAAC,WAAW,OAAO,YAAY,UAAU;AAChF,WAAO;AAAA,EACT;AAGA,MAAI,SAAS,SAAS;AACpB,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,QAAQ,SAAS,GAAG,GAAG;AAC1B,WAAO,SAAS;AAAA,EAClB;AAIA,QAAM,eAAe,QAClB,MAAM,GAAG,EACT,IAAI,aAAW;AACd,QAAI,YAAY,KAAK;AACnB,aAAO;AAAA,IACT;AAEA,WAAO,QAAQ,QAAQ,uBAAuB,MAAM;AAAA,EACtD,CAAC,EACA,KAAK,KAAK;AAEb,QAAM,QAAQ,IAAI,OAAO,IAAI,YAAY,GAAG;AAC5C,SAAO,MAAM,KAAK,IAAI;AACxB;AA+CO,SAAS,aAAa,QAAgB,SAAiB,MAAc;AAC1E,MAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,WAAO;AAAA,EACT;AAEA,MAAI,MAAM,OAAO,KAAK;AAGtB,MAAI,UAAU,IAAI,WAAW,GAAG,MAAM,GAAG,GAAG;AAC1C,UAAM,IAAI,UAAU,OAAO,SAAS,CAAC;AAAA,EACvC;AAGA,SAAO,IAAI,YAAY,EAAE,QAAQ,MAAM,GAAG;AAC5C;AAiDO,SAAS,aAAa,MAAc,SAAiB,MAAc;AACxE,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AAGA,QAAM,MAAM,KAAK,KAAK,EAAE,YAAY,EAAE,QAAQ,OAAO,GAAG;AAGxD,MAAI,IAAI,WAAW,GAAG;AACpB,WAAO;AAAA,EACT;AAGA,MAAI,UAAU,OAAO,SAAS,GAAG;AAC/B,WAAO,GAAG,OAAO,YAAY,CAAC,IAAI,GAAG;AAAA,EACvC;AAEA,SAAO;AACT;;;AC3hDA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,mBAAkB;AAClB,aAAwB;AAexB,6BAAsB;;;ACrBtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,mBAAkB;AAClB,iBAAgB;AAChB,0BAAyB;AACzB,wBAA6B;AAC7B,+BAA8B;AAC9B,2BAA0B;AAC1B,4BAA2B;AAC3B,qBAAoB;AACpB,wBAAuB;AACvB,6BAA4B;AAC5B,gBAAO;AACP,oBAA+B;AAC/B,IAAM,EAAE,aAAa,qBAAqB,IAAI;AAG9C,aAAAC,QAAM,OAAO,WAAAC,OAAG;AAChB,aAAAD,QAAM,OAAO,oBAAAE,OAAY;AACzB,aAAAF,QAAM,OAAO,kBAAAG,OAAgB;AAC7B,aAAAH,QAAM,OAAO,yBAAAI,OAAiB;AAC9B,aAAAJ,QAAM,OAAO,qBAAAK,OAAa;AAC1B,aAAAL,QAAM,OAAO,sBAAAM,OAAc;AAC3B,aAAAN,QAAM,OAAO,eAAAO,OAAO;AACpB,aAAAP,QAAM,OAAO,kBAAAQ,OAAU;AACvB,aAAAR,QAAM,OAAO,uBAAAS,OAAe;AAG5B,aAAAT,QAAM,OAAO,IAAI;AAKV,IAAM,YAAY,CAAC,YAAY,qBAAyB,aAAAA,SAAM,EAAE,OAAO,SAAS;AA4BhF,IAAM,SAAS,CAAC,OAAY,YAAY,iBAAyB;AACtE,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,UAAU,YAAY,MAAM,KAAM,QAAO,WAAW,KAAK;AAAA,WACpD,UAAU,YAAY,MAAM,OAAQ,YAAO,aAAAA,SAAM,KAAK,EAAE,OAAO,IAAI,IAAI,WAAW,KAAK;AAChG,aAAO,aAAAA,SAAM,KAAK,EAAE,OAAO,SAAS;AACtC;AAyBO,IAAM,aAAa,CAAC,QAAa,SAAS;AAC/C,MAAI,CAAC,MAAO,QAAO;AACnB,aAAO,aAAAA,SAAM,KAAK,EAAE,OAAO,IAAI;AACjC;AAKO,IAAM,SAAS,CAAC,OAAY,UAAoB;AACrD,MAAI,UAAU,OAAW,YAAO,aAAAA,SAAM,KAAK,EAAE,OAAO;AACpD,SAAO,QAAQ,aAAAA,QAAM,IAAI,KAAK,EAAE,OAAO,QAAI,aAAAA,SAAM,KAAK,EAAE,OAAO;AACjE;AAmCO,IAAM,mBAAmB,CAAC,YAAoBU,YAA0C;AAC7F,QAAM,cAAsC;AAAA,IAC1C,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,UAAU;AAAA,IACV,UAAU;AAAA,IACV,UAAU;AAAA,IACV,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,EAChB;AAEA,QAAM,QAAQ,YAAYA,OAAM;AAChC,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAQ,WAAW,MAAM,KAAK;AACpC,MAAI,OAAO;AACT,QAAI,MAAc,OAAe;AAEjC,QAAIA,QAAO,WAAW,MAAM,GAAG;AAC7B,aAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAC5B,cAAQ,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI;AACjC,YAAM,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC7B,WAAWA,QAAO,WAAW,IAAI,GAAG;AAClC,YAAM,SAAS,MAAM,CAAC,GAAG,EAAE;AAC3B,cAAQ,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI;AACjC,aAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC9B,WAAWA,QAAO,WAAW,IAAI,GAAG;AAClC,cAAQ,SAAS,MAAM,CAAC,GAAG,EAAE,IAAI;AACjC,YAAM,SAAS,MAAM,CAAC,GAAG,EAAE;AAC3B,aAAO,SAAS,MAAM,CAAC,GAAG,EAAE;AAAA,IAC9B,OAAO;AACL,aAAO;AAAA,IACT;AAEA,WAAO,IAAI,KAAK,MAAM,OAAO,GAAG;AAAA,EAClC;AAEA,SAAO;AACT;AAKO,IAAM,MAAM,UAAM,aAAAV,SAAM,EAAE,OAAO;AAKjC,IAAM,QAAQ,CAAC,OAAY,UAAU,UAC1C,aAAAA,SAAM,EAAE,mBAAe,aAAAA,SAAM,KAAK,EAAE,IAAI,SAAS,MAAM,CAAC;AAkBnD,IAAM,QAAQ,CAAC,QAAa,MAAM,QAAQ,UAAU;AACzD,MAAI,CAAC,MAAO,YAAO,aAAAA,SAAM,EAAE,YAAY;AACvC,SAAO,QAAQ,aAAAA,QAAM,IAAI,KAAK,EAAE,YAAY,QAAI,aAAAA,SAAM,KAAK,EAAE,YAAY;AAC3E;AAcO,IAAM,UAAU,CAAC,cAAe,aAAAA,SAAM,KAAK,EAAE,QAAQ;AAKrD,IAAM,YAAY,CAAC,QAAa,SAAS;AAC9C,MAAI,CAAC,MAAO,YAAO,aAAAA,SAAM,EAAE,OAAO,GAAG;AACrC,aAAO,aAAAA,SAAM,KAAK,EAAE,OAAO,GAAG;AAChC;AAKO,IAAM,aAAa,CAAC,QAAa,SAAS;AAC/C,MAAI,CAAC,MAAO,YAAO,aAAAA,SAAM,EAAE,OAAO,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACzE,aAAO,aAAAA,SAAM,KAAK,EAAE,OAAO,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,GAAG;AACpE;AAKO,IAAM,WAAW,CAAC,OAAY,MAAW,MAAM,UAAU,UAAU;AACxE,QAAM,KAAK,CAAC,UAAM,aAAAA,SAAM,QAAI,aAAAA,SAAM,GAAG;AACrC,aAAO,aAAAA,SAAM,KAAK,EAAE,KAAK,IAAI,QAAQ,OAAO;AAC9C;AA6BO,IAAM,mBAAmB,CAAC,OAAY,MAAW,MAAM,UAAU,UAAU;AAChF,MAAI,gBAAY,aAAAA,SAAM,KAAK,EAAE,QAAQ,KAAK;AAC1C,MAAI,UAAU,UAAM,aAAAA,SAAM,GAAG,EAAE,QAAQ,KAAK,QAAI,aAAAA,SAAM,EAAE,QAAQ,KAAK;AAErE,MAAI,UAAU,QAAQ,OAAO,GAAG;AAC9B;AAAC,KAAC,WAAW,OAAO,IAAI,CAAC,SAAS,SAAS;AAAA,EAC7C;AAEA,MAAI,eAAe;AACnB,MAAI,cAAc;AAElB,SAAO,YAAY,SAAS,OAAO,GAAG;AACpC,QAAI,UAAU,WAAW,GAAG;AAC1B;AAAA,IACF;AACA,kBAAc,YAAY,IAAI,GAAG,KAAK;AAAA,EACxC;AAEA,MAAI,SAAS;AACX,UAAM,gBAAgB,QAAQ,KAAK,aAAa,OAAO,IAAI;AAC3D,oBAAgB;AAAA,EAClB;AAEA,SAAO;AACT;AAKO,IAAM,aAAa,CAAC,OAAY,gBAAqB,MAAM,UAAU,UAAU;AACpF,QAAM,KAAK,CAAC,oBAAgB,aAAAA,SAAM,QAAI,aAAAA,SAAM,aAAa;AACzD,aAAO,aAAAA,SAAM,KAAK,EAAE,KAAK,IAAI,UAAU,OAAO;AAChD;AAKO,IAAM,YAAY,CAAC,OAAY,gBAAqB,MAAM,UAAU,UAAU;AACnF,QAAM,KAAK,CAAC,oBAAgB,aAAAA,SAAM,QAAI,aAAAA,SAAM,aAAa;AACzD,aAAO,aAAAA,SAAM,KAAK,EAAE,KAAK,IAAI,SAAS,OAAO;AAC/C;AAKO,IAAM,mBAAmB,CAAC,OAAY,gBAAqB,SAAS;AACzE,QAAM,KAAK,CAAC,oBAAgB,aAAAA,SAAM,QAAI,aAAAA,SAAM,aAAa;AACzD,aAAO,aAAAA,SAAM,KAAK,EAAE,KAAK,IAAI,gBAAgB,IAAI;AACnD;AAKO,IAAM,UAAU,CAAC,OAAY,QAAgB,UAAM,aAAAA,SAAM,KAAK,EAAE,IAAI,OAAO,MAAM,EAAE,OAAO;AAK1F,IAAM,aAAa,CAAC,OAAY,WAAmB,UACxD,aAAAA,SAAM,KAAK,EAAE,IAAI,UAAU,SAAS,EAAE,OAAO;AAKxC,IAAM,6BAA6B,CAAC,OAAa,UAAyB;AAC/E,QAAM,YAAY,IAAI;AACtB,SAAO,KAAK,QAAI,aAAAA,SAAM,KAAK,EAAE,SAAK,aAAAA,SAAM,KAAK,CAAC,CAAC,KAAK;AACtD;AAKO,IAAM,aAAa,CAAC,QAAgB,UAAM,aAAAA,SAAM,EAAE,IAAI,OAAO,MAAM,EAAE,OAAO;AAK5E,IAAM,gBAAgB,CAAC,WAAmB,WAAO,aAAAA,SAAM,EAAE,IAAI,UAAU,SAAS,EAAE,OAAO;AAKzF,IAAM,YAAY,CAAC,OAAY,UAAkB,UACtD,aAAAA,SAAM,KAAK,EAAE,IAAI,SAAS,QAAQ,EAAE,OAAO;AAKtC,IAAM,eAAe,CAAC,UAAkB,UAAM,aAAAA,SAAM,EAAE,IAAI,SAAS,QAAQ,EAAE,OAAO;AAKpF,IAAM,WAAW,CAAC,OAAY,SAAiB,UACpD,aAAAA,SAAM,KAAK,EAAE,IAAI,QAAQ,OAAO,EAAE,OAAO;AAKpC,IAAM,cAAc,CAAC,SAAiB,UAAM,aAAAA,SAAM,EAAE,IAAI,QAAQ,OAAO,EAAE,OAAO;AAMhF,IAAM,cAAc,CAAC,UAAe;AACzC,MAAI;AACF,UAAM,IAAY,OAAO,KAAK;AAC9B,QAAI,KAAK,QAAS,KAAK,IAAQ,QAAO,IAAI,KAAK,KAAK,OAAO,IAAI,SAAS,QAAQ,GAAI,CAAC;AACrF,WAAO;AAAA,EACT,SAAS,MAAM;AACb,WAAO;AAAA,EACT;AACF;AAKO,IAAM,aAAa,CAAC,UAAwB;AACjD,MAAI;AACF,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,OAAO,UAAU,SAAU,QAAO;AAAA,aAC7B,OAAO,UAAU,UAAW,QAAO;AAAA,aAE1C,OAAO,UAAU,YACjB,CAAC,qBAAqB,KAAK,KAC3B,CAAC,YAAY,KAAK,KAClB,CAAC,YAAY,OAAO,EAAE;AAEtB,aAAO;AAAA,aACA,OAAO,UAAU,YAAY,EAAE,iBAAiB,SAAS,CAAC,aAAAA,QAAM,QAAQ,KAAK;AACpF,aAAO;AACT,eAAO,aAAAA,SAAM,KAAK,EAAE,QAAQ;AAAA,EAC9B,SAAS,MAAM;AACb,WAAO;AAAA,EACT;AACF;AAKO,IAAM,wBAAwB,CAAC,QAAa,WAAyB;AAC1E,MAAI,CAAC,WAAW,MAAM,EAAG,QAAO;AAChC,MAAI,CAAC,WAAW,MAAM,EAAG,QAAO;AAChC,aAAO,aAAAA,SAAM,MAAM,EAAE,WAAO,aAAAA,SAAM,MAAM,GAAG,KAAK;AAClD;AAKO,IAAM,YAAY,CAAC,OAAY,gBAAqB,SAAkB;AAC3E,QAAM,KAAK,CAAC,oBAAgB,aAAAA,SAAM,QAAI,aAAAA,SAAM,aAAa;AACzD,MAAI,WAAW,KAAK,GAAG;AACrB,WAAO,GAAG,QAAQ,KAAK;AAAA,EACzB;AACA,SAAO;AACT;AAKO,IAAM,iBAAiB,CAAC,UAAuB;AACpD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,WAAW,MAAM,WAAW,IAAI,MAAM,kBAAkB,CAAC;AAC/D,SAAO,MAAM,YAAY,EAAE,MAAM,GAAG,EAAE,EAAE,QAAQ,KAAK,GAAG;AAC1D;AAKO,IAAM,yBAAyB,CAAC,UAAmB;AACxD,QAAM,aAAa,UAAU,aAAY,aAAAA,SAAM,EAAE,MAAM,IAAI;AAC3D,MAAI,eAAW,aAAAA,SAAM,EAAE,MAAM,UAAU,EAAE,QAAQ,OAAO;AACxD,SAAO,SAAS,IAAI,MAAM,KAAK,SAAS,IAAI,MAAM,GAAG;AACnD,eAAW,SAAS,IAAI,GAAG,KAAK;AAAA,EAClC;AACA,SAAO,SAAS,OAAO;AACzB;AAKO,IAAM,wBAAwB,CAAC,UAAmB;AACvD,QAAM,aAAa,UAAU,aAAY,aAAAA,SAAM,EAAE,MAAM,IAAI;AAC3D,MAAI,cAAU,aAAAA,SAAM,EAAE,MAAM,UAAU,EAAE,MAAM,OAAO;AACrD,SAAO,QAAQ,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,GAAG;AACjD,cAAU,QAAQ,SAAS,GAAG,KAAK;AAAA,EACrC;AACA,SAAO,QAAQ,OAAO;AACxB;AAKO,IAAM,6BAA6B,CAAC,aAAmB,MAAc;AAC1E,QAAM,gBAAY,aAAAA,SAAM,WAAW;AACnC,QAAM,cAAc;AACpB,QAAM,aAAa,UAAU,IAAI,aAAa,QAAQ;AAEtD,MAAI,eAAe,WAAW,QAAQ,OAAO;AAC7C,SAAO,aAAa,IAAI,MAAM,KAAK,aAAa,IAAI,MAAM,GAAG;AAC3D,mBAAe,aAAa,IAAI,GAAG,KAAK;AAAA,EAC1C;AACA,SAAO,aAAa,OAAO;AAC7B;AAKO,IAAM,oBAAoB,UAAM,aAAAA,SAAM,EAAE,QAAQ,MAAM,EAAE,OAAO;AAK/D,IAAM,mBAAmB,UAAM,aAAAA,SAAM,EAAE,MAAM,MAAM,EAAE,OAAO;AAK5D,IAAM,YAAY,CAAC,SAAc;AACtC,QAAM,QAAI,aAAAA,SAAM,IAAI;AACpB,QAAMW,aAAY,EAAE,IAAI;AACxB,SAAOA,eAAc,KAAKA,eAAc;AAC1C;;;ADlfA,IAAM;AAAA,EACJ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,IAAI;AAKJ,IAAM,eAAe,CAAI,OAAY,cAA+B;AAClE,SAAO,MAAM,OAAO,UAAQ;AAC1B,WAAO,OAAO,KAAK,SAAS,EAAE,MAAM,SAAO,KAAK,GAAc,MAAM,UAAU,GAAc,CAAC;AAAA,EAC/F,CAAC;AACH;AAEA,IAAM,eAAe,CAAmB,QAAW,WAA0B;AAC3E,SAAO,OAAO,OAAO,QAAQ,MAAM;AACrC;AAEA,IAAM,aAAa,CAAsC,QAAW,SAA0B;AAC5F,QAAM,SAAS,CAAC;AAChB,OAAK,QAAQ,SAAO;AAClB,QAAI,OAAO,QAAQ;AACjB,aAAO,GAAG,IAAI,OAAO,GAAG;AAAA,IAC1B;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEA,IAAM,eAAe,CAAI,OAAY,cAAyC;AAC5E,QAAM,UAAe,CAAC;AACtB,WAAS,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC1C,QAAI,UAAU,MAAM,CAAC,CAAC,GAAG;AACvB,cAAQ,QAAQ,MAAM,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC;AAAA,IACvC;AAAA,EACF;AACA,SAAO;AACT;AASO,IAAM,aAAa,CAAC,OAAY,UAAe,QAAQ,OAAO,KAAK;AAuInE,IAAM,YAAY,CAAC,OAAY,cAAe,uBAAAC,SAAU,OAAO,KAAK;AAuEpE,IAAM,yBAAyB,CAAC,SACrC,KAAK,UAAU,IAAI,EAAE,QAAQ,UAAU,EAAE,EAAE,QAAQ,MAAM,IAAI;AAqHxD,IAAM,uBAAuB,CAAC,QAAkB;AACrD,MAAI,CAAC,IAAK,QAAO,CAAC;AAClB,QAAM,gBAAqB,CAAC;AAC5B,aAAW,QAAQ,KAAK;AACtB,QAAI,OAAO,eAAe,KAAK,KAAK,IAAI,GAAG;AACzC,YAAM,QAAQ,IAAI,IAAI;AACtB,YAAM,OAAO,OAAO;AAEpB,UAAK,SAAS,YAAY,SAAS,cAAe,UAAU,MAAM;AAChE,sBAAc,IAAI,IAAI;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AA2HO,IAAM,uBAAuB,CAAC,QAAa,WAAqB;AACrE,SAAO;AAAA,IACL;AAAA,IACA,CAAC,QAAQ,OAAO,QAAQ;AACtB,YAAM,WAAW,OAAO,GAAG;AAE3B,UAAI,WAAW,KAAK,KAAK,WAAW,QAAQ,GAAG;AAC7C,YAAI,CAAC,2BAA2B,OAAO,KAAK,GAAG,OAAO,QAAQ,CAAC,GAAG;AAChE,iBAAO,GAAG,IAAI;AAAA,QAChB;AAAA,MACF,WAAW,CAAC,QAAQ,OAAO,QAAQ,GAAG;AACpC,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AAAA,IACA,CAAC;AAAA,EACH;AACF;AAiIO,IAAM,kBAAkB,CAAC,QAAoD;AAClF,MAAI,MAAM,GAAG,EAAG,YAAO,aAAAC,SAAM,GAAG,EAAE,SAAS,EAAE;AAC7C,MAAI,SAAS,GAAG,EAAG,YAAO,aAAAA,SAAM,GAAG,EAAE,SAAS,EAAE;AAChD,MAAI,SAAS,GAAG,EAAG,YAAO,aAAAA,SAAM,GAAG,EAAE,SAAS,EAAE;AAChD,MAAI,cAAc,GAAG,EAAG,YAAO,aAAAA,SAAM,GAAG,EAAE,SAAS,EAAE;AACrD,MAAI,UAAU,GAAG,EAAG,YAAO,aAAAA,SAAM,MAAM,SAAS,OAAO,EAAE,SAAS,EAAE;AACpE,MAAI,SAAS,GAAG,EAAG,YAAO,aAAAA,SAAM,IAAI,SAAS,CAAC,EAAE,SAAS,EAAE;AAC3D,MAAI,QAAQ,GAAG,KAAK,SAAS,GAAG,EAAG,QAAO,gBAAgB,KAAK,UAAU,GAAG,CAAC;AAC7E,aAAO,aAAAA,SAAM,OAAO,EAAE,EAAE,SAAS,EAAE;AACrC;AAkMO,IAAM,cAAc,CAAC,cAAmB,sBAA2B;AACxE,MAAI,QAAQ,YAAY,KAAK,QAAQ,iBAAiB,EAAG,QAAO;AAChE,MAAI,QAAQ,YAAY,MAAM,QAAQ,iBAAiB,EAAG,QAAO;AACjE,MAAI,aAAa,YAAY,KAAK,aAAa,iBAAiB,GAAG;AACjE,QACE,OAAO,UAAU,SAAS,KAAK,YAAY,MAC3C,OAAO,UAAU,SAAS,KAAK,iBAAiB;AAEhD,aAAO;AAAA,QACJ,QAAO;AAAA,EACd;AACA,MAAI,aAAa,YAAY,MAAM,aAAa,iBAAiB,EAAG,QAAO;AAC3E,MAAI,cAAc,YAAY,KAAK,cAAc,iBAAiB,EAAG,QAAO;AAG5E,MAAI,cAAc,YAAY,MAAM,cAAc,iBAAiB,EAAG,QAAO;AAE7E,SAAO,OAAO,iBAAiB,OAAO;AACxC;AA4FO,IAAM,wBAAwB,CAAC,MAAa,QAAa,cAAmB;AACjF,eAAa,MAAM,SAAS,EAAE,QAAQ,aAAW,aAAa,SAAS,MAAM,CAAC;AAC9E,SAAO;AACT;AA2FO,IAAM,yBAAyB,CAAC,MAAa,QAAa,YAAoB;AACnF,QAAM,QAAQ,KAAK,UAAU,OAAK,EAAE,OAAO,MAAM,OAAO,OAAO,CAAC;AAChE,MAAI,UAAU,GAAI,MAAK,OAAO,OAAO,GAAG,MAAM;AAChD;AAmGO,IAAM,wBAAwB,CAAC,MAAa,cAAmB;AACpE,eAAa,MAAM,OAAK,UAAU,WAAW,GAAG,OAAO,KAAK,SAAS,CAAQ,GAAG,SAAS,CAAC;AAC1F,SAAO;AACT;AA6DO,SAAS,aAAsB,KAAQ,MAAc,OAAe;AACzE,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,UAAM,IAAI,UAAU,wCAAwC;AAAA,EAC9D;AAEA,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,UAAM,IAAI,UAAU,+CAA+C;AAAA,EACrE;AAEA,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,MAAI,UAAe;AAEnB,WAAS,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACxC,UAAM,MAAM,KAAK,CAAC;AAClB,UAAM,UAAU,KAAK,IAAI,CAAC;AAG1B,UAAM,cAAc,QAAQ,KAAK,OAAO;AAGxC,QAAI,EAAE,OAAO,YAAY,OAAO,QAAQ,GAAG,MAAM,UAAU;AACzD,cAAQ,GAAG,IAAI,cAAc,CAAC,IAAI,CAAC;AAAA,IACrC;AAEA,cAAU,QAAQ,GAAG;AAAA,EACvB;AAGA,QAAM,UAAU,KAAK,KAAK,SAAS,CAAC;AACpC,UAAQ,OAAO,IAAI;AAEnB,SAAO;AACT;AAoDO,SAAS,aAAsB,KAAU,MAAc,cAAiC;AAC7F,MAAI,CAAC,OAAO,OAAO,QAAQ,UAAU;AACnC,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,KAAK,MAAM,GAAG;AAC3B,MAAI,UAAU;AAEd,aAAW,OAAO,MAAM;AACtB,QAAI,YAAY,QAAQ,YAAY,UAAa,OAAO,YAAY,UAAU;AAC5E,aAAO;AAAA,IACT;AAEA,QAAI,EAAE,OAAO,UAAU;AACrB,aAAO;AAAA,IACT;AAEA,cAAU,QAAQ,GAAG;AAAA,EACvB;AAEA,SAAO,YAAY,SAAY,UAAU;AAC3C;;;AEt0CA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,IAAAC,UAAwB;;;ACLxB;AAAA;AAAA;AAAA;AAAA;AAwBO,SAAS,eAAe,OAAqB;AAClD,MAAI,UAAU,QAAQ,UAAU,OAAW,QAAO;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,CAAC,MAAM,KAAK,KAAK,SAAS,KAAK;AACrE,MAAI,OAAO,UAAU,SAAU,QAAO,MAAM,KAAK,MAAM,MAAM,CAAC,MAAM,OAAO,KAAK,CAAC;AACjF,SAAO;AACT;AAaO,SAAS,gBAAgB,KAAa,WAAmB,GAAW;AACzE,QAAM,SAAS,KAAK,IAAI,IAAI,QAAQ;AAEpC,SAAO,OAAO,IAAI,KAAK,MAAM,MAAM,MAAM,IAAI,SAAS,CAAC,KAAK,MAAM,KAAK,IAAI,GAAG,IAAI,MAAM,IAAI;AAC9F;;;ADxCA,IAAM,EAAE,KAAK,OAAO,OAAO,KAAK,QAAQ,OAAO,MAAM,OAAO,MAAM,MAAM,KAAK,WAAW,QAAQ,IAC9FC;AAsHK,IAAM,wBAAwB,CACnC,YACA,UACA,QACA,yBAAyB,SACtB;AACH,MAAI,OAAY,CAAC;AACjB,MAAI,UAAU,QAAQ;AACpB,UAAM,cAAc;AAAA,MAAQ;AAAA,MAAQ,UAClC,SAAS,IAAI,WAAS,IAAI,MAAM,KAAK,CAAC,EAAE,KAAK,WAAW;AAAA,IAC1D;AACA,WAAO,IAAI,aAAa,CAAC,OAAO,aAAa;AAC3C,YAAM,MAAW,UAAU,UAAU,SAAS,MAAM,WAAW,CAAC;AAChE,iBAAW,aAAa,YAAY;AAClC,cAAM,SAAS,WAAW,SAAS;AACnC,eAAO,QAAQ,WAAS;AACtB,gBAAM,cAAc,yBAAyB,QAAQ,YAAY;AACjE,kBAAQ,WAAW;AAAA,YACjB,KAAK;AACH,kBAAI,WAAW,IAAI,MAAM;AACzB;AAAA,YACF,KAAK;AACH,kBAAI,WAAW,IAAI,MAAM,OAAO,UAAQ,IAAI,MAAM,KAAK,CAAC;AACxD;AAAA,YACF,KAAK;AACH,kBAAI,WAAW,IAAI;AAAA,gBACjB,OAAO,OAAO,UAAQ,IAAI,MAAM,KAAK,CAAC;AAAA,gBACtC;AAAA,cACF;AACA;AAAA,YACF,KAAK,QAAQ;AACX,oBAAM,UAAU,MAAM,OAAO,UAAQ,IAAI,MAAM,KAAK,CAAC;AACrD,kBAAI,WAAW,IAAI,UAAU,IAAI,SAAS,KAAK,IAAI;AACnD;AAAA,YACF;AAAA,YACA,KAAK,QAAQ;AACX,oBAAM,UAAU,MAAM,OAAO,UAAQ,IAAI,MAAM,KAAK,CAAC;AACrD,kBAAI,WAAW,IAAI,UAAU,IAAI,SAAS,KAAK,IAAI;AACnD;AAAA,YACF;AAAA,YACA,KAAK;AACH,kBAAI,WAAW,IAAI,KAAK,OAAO,UAAQ,IAAI,MAAM,KAAK,CAAC,IAAI,IAAI;AAC/D;AAAA,YACF,KAAK;AACH,kBAAI,WAAW,IAAI;AAAA,gBACjB,MAAM,IAAI,UAAQ,IAAI,MAAM,KAAK,CAAC;AAAA,gBAClC,MAAM,IAAI,CAAC,OAAO,UAAU,QAAQ,CAAC;AAAA,cACvC;AACA;AAAA,YACF,KAAK;AACH,kBAAI,WAAW,IAAI,KAAK,MAAM,IAAI,UAAQ,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE;AAC7D;AAAA,UACJ;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO;AAAA,IACT,CAAC;AAAA,EACH,OAAO;AACL,UAAM,UAAqC,CAAC;AAC5C,eAAW,aAAa,YAAY;AAClC,YAAM,SAAS,WAAW,SAAS;AACnC,aAAO,QAAQ,WAAS;AACtB,cAAM,cAAc,yBAAyB,QAAQ,YAAY;AACjE,gBAAQ,WAAW;AAAA,UACjB,KAAK;AACH,oBAAQ,WAAW,IAAI,OAAO;AAC9B;AAAA,UACF,KAAK;AACH,oBAAQ,WAAW,IAAI,MAAM,QAAQ,KAAK;AAC1C;AAAA,UACF,KAAK;AACH,oBAAQ,WAAW,IAAI,MAAM,OAAO,QAAQ,KAAK,GAAG,CAAC;AACrD;AAAA,UACF,KAAK;AACH,gBAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,oBAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,sBAAQ,WAAW,IAAI,UAAU,QAAQ,KAAK,IAAI;AAAA,YACpD;AACA;AAAA,UACF,KAAK;AACH,gBAAI,MAAM,QAAQ,MAAM,GAAG;AACzB,oBAAM,UAAU,MAAM,QAAQ,KAAK;AACnC,sBAAQ,WAAW,IAAI,UAAU,QAAQ,KAAK,IAAI;AAAA,YACpD;AACA;AAAA,UACF,KAAK;AACH,oBAAQ,WAAW,IAAI,KAAK,QAAQ,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,IAAI;AAC7D;AAAA,UACF,KAAK;AACH,oBAAQ,WAAW,IAAI;AAAA,cACrB,OAAO,IAAI,UAAQ,IAAI,MAAM,KAAK,CAAC;AAAA,cACnC,OAAO,IAAI,CAAC,OAAO,UAAU,QAAQ,CAAC;AAAA,YACxC;AACA;AAAA,UACF,KAAK;AACH,oBAAQ,WAAW,IAAI,KAAK,OAAO,IAAI,UAAQ,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE;AAClE;AAAA,QACJ;AAAA,MACF,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAoKO,SAAS,oBAAoB,GAAa,GAAa;AAC5D,QAAM,IAAI,KAAK,CAAC;AAChB,QAAM,QAAQ,IAAI,CAAC;AACnB,QAAM,QAAQ,IAAI,CAAC;AACnB,QAAM,SAAS,IAAI,IAAI,GAAG,SAAO,MAAM,GAAG,CAAC;AAC3C,QAAM,SAAS,IAAI,IAAI,GAAG,CAAC,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC;AAEjD,QAAM,cAAc,IAAI,SAAS,QAAQ;AACzC,MAAI,gBAAgB,GAAG;AACrB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,IAAI,SAAS,QAAQ,SAAS;AAC7C,SAAO,gBAAgB,OAAO,CAAC;AACjC;AAoFO,IAAM,kBAAkB,CAAC,WAA6B;AAC3D,MAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,QAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC/C,QAAM,SAAS,KAAK,MAAM,OAAO,SAAS,CAAC;AAE3C,MAAI,OAAO,SAAS,MAAM,GAAG;AAC3B,YAAQ,OAAO,SAAS,CAAC,IAAI,OAAO,MAAM,KAAK;AAAA,EACjD;AAEA,SAAO,OAAO,MAAM;AACtB;AA6IO,IAAM,gBAAgB,CAAC,WAAoC;AAChE,MAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,QAAM,YAAuC,CAAC;AAC9C,MAAI,UAAU;AACd,MAAI,OAAsB;AAC1B,MAAI,mBAAmB;AAEvB,aAAW,SAAS,QAAQ;AAC1B,cAAU,KAAK,KAAK,UAAU,KAAK,KAAK,KAAK;AAE7C,QAAI,UAAU,KAAK,IAAI,SAAS;AAC9B,gBAAU,UAAU,KAAK;AACzB,aAAO;AACP,yBAAmB;AAAA,IACrB,WAAW,UAAU,KAAK,MAAM,WAAW,UAAU,MAAM;AACzD,yBAAmB;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,mBAAmB,OAAO;AACnC;AA4FO,IAAM,6BAA6B,CAAC,QAAkB,SAAS,UAAkB;AACtF,MAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,QAAM,OAAO,OAAO,OAAO,CAACC,MAAK,QAAQA,OAAM,KAAK,CAAC,IAAI,OAAO;AAChE,QAAM,eAAe,OAAO,IAAI,SAAO,KAAK,IAAI,MAAM,MAAM,CAAC,CAAC;AAC9D,QAAM,WACJ,aAAa,OAAO,CAACA,MAAK,QAAQA,OAAM,KAAK,CAAC,KAAK,SAAS,OAAO,SAAS,IAAI,OAAO;AAEzF,SAAO,KAAK,KAAK,QAAQ;AAC3B;AA4JO,IAAM,oBAAoB,CAAC,QAAkB,SAAS,UAAkB;AAC7E,MAAI,CAAC,OAAO,OAAQ,QAAO;AAE3B,QAAM,OAAO,OAAO,OAAO,CAACA,MAAK,QAAQA,OAAM,KAAK,CAAC,IAAI,OAAO;AAChE,QAAM,eAAe,OAAO,IAAI,SAAO,KAAK,IAAI,MAAM,MAAM,CAAC,CAAC;AAE9D,SACE,aAAa,OAAO,CAACA,MAAK,QAAQA,OAAM,KAAK,CAAC,KAAK,SAAS,OAAO,SAAS,IAAI,OAAO;AAE3F;AAmKO,IAAM,sBAAsB,CAAC,QAAkB,eAA+B;AACnF,MAAI,CAAC,OAAO,OAAQ,QAAO;AAC3B,MAAI,aAAa,KAAK,aAAa,IAAK,OAAM,IAAI,MAAM,sCAAsC;AAE9F,QAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC/C,QAAM,QAAS,aAAa,OAAQ,OAAO,SAAS;AAEpD,MAAI,KAAK,MAAM,KAAK,MAAM,OAAO;AAC/B,WAAO,OAAO,KAAK;AAAA,EACrB;AAEA,QAAM,QAAQ,OAAO,KAAK,MAAM,KAAK,CAAC;AACtC,QAAM,QAAQ,OAAO,KAAK,KAAK,KAAK,CAAC;AACrC,QAAM,SAAS,QAAQ,KAAK,MAAM,KAAK;AAEvC,SAAO,SAAS,IAAI,UAAU,QAAQ;AACxC;AAwEO,IAAM,qBAAqB,CAAC,WAA6D;AAC9F,SAAO;AAAA,IACL,IAAI,oBAAoB,QAAQ,EAAE;AAAA,IAClC,IAAI,oBAAoB,QAAQ,EAAE;AAAA;AAAA,IAClC,IAAI,oBAAoB,QAAQ,EAAE;AAAA,EACpC;AACF;AA8EO,IAAM,eAAe,CAAC,WAA6B;AACxD,QAAM,YAAY,mBAAmB,MAAM;AAC3C,SAAO,UAAU,KAAK,UAAU;AAClC;AAmIO,IAAM,iBAAiB,CAAC,QAAkB,aAAa,QAAkB;AAC9E,QAAM,YAAY,mBAAmB,MAAM;AAC3C,QAAM,MAAM,UAAU,KAAK,UAAU;AACrC,QAAM,aAAa,UAAU,KAAK,aAAa;AAC/C,QAAM,aAAa,UAAU,KAAK,aAAa;AAE/C,SAAO,OAAO,OAAO,WAAS,QAAQ,cAAc,QAAQ,UAAU;AACxE;AA8HO,IAAM,uBAAuB,CAAC,GAAa,MAAwB;AACxE,MAAI,EAAE,WAAW,EAAE,UAAU,EAAE,WAAW,EAAG,QAAO;AAEpD,QAAM,IAAI,EAAE;AACZ,QAAM,OAAO,IAAI,CAAC;AAClB,QAAM,OAAO,IAAI,CAAC;AAClB,QAAM,QAAQ,IAAI,IAAI,GAAG,CAAC,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC;AAChD,QAAM,QAAQ,IAAI,IAAI,GAAG,SAAO,MAAM,GAAG,CAAC;AAC1C,QAAM,QAAQ,IAAI,IAAI,GAAG,SAAO,MAAM,GAAG,CAAC;AAE1C,QAAM,YAAY,IAAI,QAAQ,OAAO;AACrC,QAAM,cAAc,KAAK,MAAM,IAAI,QAAQ,OAAO,SAAS,IAAI,QAAQ,OAAO,KAAK;AAEnF,MAAI,gBAAgB,EAAG,QAAO;AAE9B,SAAO,YAAY;AACrB;AA6CO,IAAM,eAAe,CAAC,WAAqB,iBAAiC;AACjF,SAAO,UAAU,OAAO,CAAC,KAAK,UAAU,UAAU;AAGhD,UAAM,iBAAiB,UAAU,IAAI,IAAI,KAAK,IAAI,IAAI,cAAc,KAAK;AACzE,WAAO,MAAM,WAAW;AAAA,EAC1B,GAAG,CAAC;AACN;AAuCO,IAAM,eAAe,CAC1B,WACA,eAAe,KACf,gBAAgB,KAChB,YAAY,SACD;AACX,MAAI,OAAO;AAEX,WAAS,IAAI,GAAG,IAAI,eAAe,KAAK;AACtC,UAAM,MAAM,aAAa,WAAW,IAAI;AACxC,UAAM,gBAAgB,UAAU,OAAO,CAACA,MAAK,UAAU,UAAU;AAC/D,aAAOA,OAAO,QAAQ,WAAY,KAAK,IAAI,IAAI,MAAM,QAAQ,CAAC;AAAA,IAChE,GAAG,CAAC;AAEJ,QAAI,KAAK,IAAI,GAAG,IAAI,UAAW,QAAO;AACtC,QAAI,KAAK,IAAI,aAAa,IAAI,UAAW;AAEzC,WAAO,OAAO,MAAM;AAAA,EACtB;AAEA,SAAO;AACT;AAuBO,IAAM,uBAAuB,CAClC,cACA,cACA,YACW;AACX,SAAO,eAAe,KAAK,IAAI,IAAI,cAAc,OAAO;AAC1D;AAoBO,IAAM,wBAAwB,CACnC,aACA,cACA,YACW;AACX,SAAO,cAAc,KAAK,IAAI,IAAI,cAAc,OAAO;AACzD;AAsBO,IAAM,0BAA0B,CACrC,cACA,cACA,YACW;AACX,MAAI,iBAAiB,EAAG,QAAO,eAAe;AAE9C,SACG,gBAAgB,eAAe,KAAK,IAAI,IAAI,cAAc,OAAO,MACjE,KAAK,IAAI,IAAI,cAAc,OAAO,IAAI;AAE3C;AA8GO,IAAM,mBAAmB,CAAC,WAA+B;AAC9D,MAAI,CAAC,OAAO,OAAQ,QAAO,CAAC;AAE5B,QAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,QAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,QAAM,QAAQ,MAAM;AAEpB,MAAI,UAAU,EAAG,QAAO,OAAO,IAAI,MAAM,CAAC;AAE1C,SAAO,OAAO,IAAI,YAAU,QAAQ,OAAO,KAAK;AAClD;AAmGO,IAAM,eAAe,CAAC,QAAkB,UAAkB,aAA+B;AAC9F,QAAM,aAAa,iBAAiB,MAAM;AAC1C,QAAM,QAAQ,WAAW;AAEzB,SAAO,WAAW,IAAI,WAAS,WAAW,QAAQ,KAAK;AACzD;AAmGO,IAAM,qBAAqB,CAChC,QACA,SACsD;AACtD,MAAI,CAAC,OAAO,UAAU,QAAQ,EAAG,QAAO,CAAC;AAEzC,QAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,QAAM,MAAM,KAAK,IAAI,GAAG,MAAM;AAC9B,QAAM,YAAY,MAAM,OAAO;AAE/B,QAAM,YAA+D,CAAC;AAEtE,WAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,UAAM,aAAa,MAAM,IAAI;AAC7B,UAAM,WAAW,MAAM,OAAO,IAAI,MAAM,aAAa;AAErD,UAAM,QAAQ,OAAO;AAAA,MACnB,WAAS,SAAS,eAAe,MAAM,OAAO,IAAI,SAAS,WAAW,QAAQ;AAAA,IAChF,EAAE;AAEF,cAAU,KAAK;AAAA,MACb,OAAO,CAAC,gBAAgB,YAAY,CAAC,GAAG,gBAAgB,UAAU,CAAC,CAAC;AAAA,MACpE;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAoGO,IAAM,6BAA6B,CAAC,QAAkB,WAA6B;AACxF,MAAI,OAAO,WAAW,OAAO,QAAQ;AACnC,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,QAAM,eAAe,OAAO,IAAI,CAAC,KAAK,UAAU,KAAK,IAAI,MAAM,OAAO,KAAK,GAAG,CAAC,CAAC;AAChF,SAAO,KAAK,KAAK,IAAI,YAAY,CAAC;AACpC;AAuFO,IAAM,6BAA6B,CAAC,QAAkB,WAA6B;AACxF,MAAI,OAAO,WAAW,OAAO,QAAQ;AACnC,UAAM,IAAI,MAAM,gDAAgD;AAAA,EAClE;AAEA,SAAO,IAAI,OAAO,IAAI,CAAC,KAAK,UAAU,KAAK,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC,CAAC;AACtE;AA4HO,IAAM,eAAe,CAC1B,QACA,GACA,gBAAgB,QACkC;AAClD,MAAI,OAAO,WAAW,KAAK,KAAK,GAAG;AACjC,WAAO,EAAE,WAAW,CAAC,GAAG,UAAU,CAAC,EAAE;AAAA,EACvC;AAEA,QAAM,aAAa,OAAO,CAAC,EAAE;AAG7B,MAAI,YAAwB,CAAC;AAC7B,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,cAAc,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,OAAO,MAAM,CAAC;AACpE,cAAU,KAAK,CAAC,GAAG,WAAW,CAAC;AAAA,EACjC;AAEA,QAAM,WAAqB,IAAI,MAAM,OAAO,MAAM;AAElD,WAAS,YAAY,GAAG,YAAY,eAAe,aAAa;AAC9D,QAAI,aAAa;AAGjB,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,UAAI,cAAc;AAClB,UAAI,kBAAkB;AAEtB,eAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,cAAM,WAAW,2BAA2B,OAAO,CAAC,GAAG,UAAU,CAAC,CAAC;AACnE,YAAI,WAAW,aAAa;AAC1B,wBAAc;AACd,4BAAkB;AAAA,QACpB;AAAA,MACF;AAEA,UAAI,SAAS,CAAC,MAAM,iBAAiB;AACnC,qBAAa;AACb,iBAAS,CAAC,IAAI;AAAA,MAChB;AAAA,IACF;AAGA,UAAM,eAA2B,IAAI,MAAM,CAAC,EAAE,KAAK,CAAC,EAAE,IAAI,MAAM,IAAI,MAAM,UAAU,EAAE,KAAK,CAAC,CAAC;AAC7F,UAAM,gBAA0B,IAAI,MAAM,CAAC,EAAE,KAAK,CAAC;AAEnD,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAM,UAAU,SAAS,CAAC;AAC1B,oBAAc,OAAO;AAErB,eAAS,MAAM,GAAG,MAAM,YAAY,OAAO;AACzC,qBAAa,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,EAAE,GAAG;AAAA,MAC7C;AAAA,IACF;AAEA,aAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAI,cAAc,CAAC,IAAI,GAAG;AACxB,iBAAS,MAAM,GAAG,MAAM,YAAY,OAAO;AACzC,uBAAa,CAAC,EAAE,GAAG,KAAK,cAAc,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,gBAAY;AAEZ,QAAI,CAAC,WAAY;AAAA,EACnB;AAEA,SAAO,EAAE,WAAW,SAAS;AAC/B;;;AE17EA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC2EO,IAAM,iBAAN,MAAM,wBAAuB,MAAM;AAAA,EAKxC,YAAY,SAAiB,UAAiC,CAAC,GAAG;AAChE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO,QAAQ;AACpB,SAAK,OAAO,QAAQ;AACpB,SAAK,QAAQ,QAAQ;AAErB,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,eAAc;AAAA,IAC9C;AAAA,EACF;AACF;AAcO,IAAM,YAAN,cAAwB,eAAe;AAAA,EAC5C,YAAY,SAAiB,MAA2B,MAAY;AAClE,UAAM,SAAS,EAAE,MAAM,KAAK,CAAC;AAC7B,SAAK,OAAO;AAAA,EACd;AACF;AAoBO,SAAS,sBAAsB,SAAiB,OAAe,OAA4B;AAChG,SAAO,IAAI,eAAe,sBAAsB,OAAO,IAAI;AAAA,IACzD,MAAM;AAAA,IACN,MAAM,EAAE,OAAO,MAAM;AAAA,EACvB,CAAC;AACH;;;ADnBO,IAAM,QAAQ,CAAC,OAA8B;AAClD,SAAO,IAAI,QAAQ,aAAW,WAAW,SAAS,EAAE,CAAC;AACvD;AAsBO,IAAM,OAAO,CAAC,OAA8B,MAAM,EAAE;AA0I3D,eAAsB,SAAY,MAAoB,YAAoB,IAAkB;AAC1F,MAAI,aAAa,GAAG;AAClB,UAAM,IAAI,eAAe,qCAAqC;AAAA,MAC5D;AAAA,MACA,MAAM,EAAE,UAAU;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,QAAM,UAAe,CAAC;AACtB,QAAM,UAAU,KAAK,KAAK,KAAK,SAAS,SAAS;AAEjD,WAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,UAAM,aAAa,IAAI;AACvB,UAAM,WAAW,aAAa;AAC9B,UAAM,QAAQ,KAAK,MAAM,YAAY,QAAQ;AAE7C,UAAM,eAAe,MAAM,QAAQ,IAAI,MAAM,IAAI,SAAO,GAAG,CAAC;AAC5D,YAAQ,KAAK,GAAG,YAAY;AAAA,EAC9B;AAEA,SAAO;AACT;AA0LO,SAAS,gBACd,QACA,cACG,MACS;AACZ,MAAI,UAAU,SAAS,GAAG,GAAG;AAC3B,UAAM,CAAC,UAAU,OAAO,IAAI,UAAU,MAAM,GAAG;AAE/C,QAAI,CAAC,OAAO,QAAQ,KAAK,CAAC,OAAO,QAAQ,EAAE,OAAO,GAAG;AACnD,YAAM,IAAI,eAAe,cAAc,SAAS,oBAAoB;AAAA,QAClE;AAAA,QACA,MAAM,EAAE,WAAW,UAAU,QAAQ;AAAA,MACvC,CAAC;AAAA,IACH;AAEA,WAAO,OAAO,QAAQ,EAAE,OAAO,EAAE,GAAG,IAAI;AAAA,EAC1C;AAEA,MAAI,CAAC,OAAO,SAAS,GAAG;AACtB,UAAM,IAAI,eAAe,cAAc,SAAS,oBAAoB;AAAA,MAClE;AAAA,MACA,MAAM,EAAE,UAAU;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,SAAO,OAAO,SAAS,EAAE,GAAG,IAAI;AAClC;;;AE/fA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA;AA+EO,IAAM,iBAAiB,OAC5B,YACA,WAA2B,WACP;AACpB,MAAI,OAAO,KAAK,OAAO,eAAe,UAAU;AAE9C,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,WAAO,GAAG,SAAS,YAAY,QAAQ;AAAA,EACzC,WAAW,UAAU,KAAK,sBAAsB,MAAM;AAEpD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,SAAS,IAAI,WAAW;AAC9B,aAAO,SAAS,OAAK,QAAQ,EAAE,QAAQ,MAAgB;AACvD,aAAO,UAAU,MAAM,OAAO,IAAI,MAAM,oBAAoB,CAAC;AAC7D,aAAO,WAAW,UAAU;AAAA,IAC9B,CAAC;AAAA,EACH,OAAO;AACL,UAAM,IAAI;AAAA,MACR;AAAA;AAAA,MAEA;AAAA,QACE,MAAM;AAAA,UACJ,WAAW,OAAO;AAAA,UAClB,cAAc,UAAU;AAAA,UACxB,eAAe,OAAO;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAqGO,SAAS,mBAAmB,MAA+B;AAChE,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,UAAM,sBAAsB,yBAAyB,QAAQ,OAAO,IAAI;AAAA,EAC1E;AAEA,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,sBAAsB,8BAA8B,eAAe,KAAK,MAAM;AAAA,EACtF;AAEA,QAAM,YAAY,KAAK,CAAC;AACxB,QAAM,gBACJ,OAAO,cAAc,YAAY,cAAc,QAAQ,CAAC,MAAM,QAAQ,SAAS;AACjF,QAAM,kBAAkB,MAAM,QAAQ,SAAS;AAE/C,MAAI,CAAC,iBAAiB,CAAC,iBAAiB;AACtC,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAGA,MAAI,eAAe;AAEjB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,OAAO,KAAK,CAAC;AACnB,UAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GAAG;AACpE,cAAM;AAAA,UACJ;AAAA,UACA,QAAQ,CAAC;AAAA,UACT,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF,WAAW,iBAAiB;AAE1B,UAAM,iBAAiB,UAAU;AACjC,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAI,CAAC,MAAM,QAAQ,KAAK,CAAC,CAAC,GAAG;AAC3B,cAAM,sBAAsB,OAAO,CAAC,oBAAoB,QAAQ,CAAC,KAAK,OAAO,KAAK,CAAC,CAAC;AAAA,MACtF;AACA,UAAI,KAAK,CAAC,EAAE,WAAW,gBAAgB;AACrC,cAAM;AAAA,UACJ,OAAO,CAAC,QAAQ,KAAK,CAAC,EAAE,MAAM,2BAA2B,cAAc;AAAA,UACvE,QAAQ,CAAC;AAAA,UACT,EAAE,UAAU,gBAAgB,QAAQ,KAAK,CAAC,EAAE,OAAO;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,IAAM,kBAAkB;AAkExB,SAAS,yBAAyB,UAAgC;AACvE,QAAM,QAAQ,SAAS,YAAY,EAAE,MAAM,GAAG;AAC9C,QAAM,YAAY,MAAM,SAAS,IAAI,MAAM,IAAI,IAAI;AAEnD,UAAQ,WAAW;AAAA,IACjB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,UAAI,CAAC,WAAW;AACd,cAAM,IAAI;AAAA,UACR;AAAA;AAAA,UAEA,EAAE,MAAM,EAAE,SAAS,EAAE;AAAA,QACvB;AAAA,MACF;AACA,YAAM,IAAI;AAAA,QACR,6BAA6B,SAAS;AAAA;AAAA,QAEtC,EAAE,MAAM,EAAE,UAAU,UAAU,EAAE;AAAA,MAClC;AAAA,EACJ;AACF;AAqFO,SAAS,oBAAoB,UAAqC;AACvE,MAAI,CAAC,YAAY,OAAO,aAAa,UAAU;AAC7C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,SAAS,KAAK,EAAE,MAAM,GAAG;AAEvC,MAAI,MAAM,SAAS,GAAG;AACpB,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,IAAI,GAAG,YAAY;AAC3C,SAAO,aAAa;AACtB;AA+FO,SAAS,sBAAsB,UAAkB;AACtD,QAAM,YAAY,oBAAoB,QAAQ;AAE9C,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,MACL,WAAW;AAAA,MACX,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AAGA,QAAM,aAAa;AAAA;AAAA,IAEjB,MAAM,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,mBAAmB;AAAA,IACtF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW;AAAA,IAC7E,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,kBAAkB;AAAA,IACpF,MAAM,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,mBAAmB;AAAA,IACtF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,mBAAmB;AAAA,IACrF,MAAM,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IAChF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,4BAA4B;AAAA,IAC9F,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,kBAAkB;AAAA,IACpF,IAAI,EAAE,UAAU,QAAQ,QAAQ,OAAO,UAAU,MAAM,UAAU,wBAAwB;AAAA,IACzF,QAAQ,EAAE,UAAU,QAAQ,QAAQ,OAAO,UAAU,MAAM,UAAU,wBAAwB;AAAA;AAAA,IAG7F,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IAC/E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,gBAAgB;AAAA,IACjF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IAC/E,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,kBAAkB;AAAA,IACpF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA;AAAA,IAG/E,MAAM,EAAE,UAAU,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,YAAY;AAAA,IAC9E,KAAK,EAAE,UAAU,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,YAAY;AAAA,IAC7E,KAAK,EAAE,UAAU,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW;AAAA,IAC5E,MAAM,EAAE,UAAU,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,cAAc;AAAA,IAChF,MAAM,EAAE,UAAU,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,cAAc;AAAA,IAChF,MAAM,EAAE,UAAU,OAAO,QAAQ,MAAM,UAAU,OAAO,UAAU,cAAc;AAAA;AAAA,IAGhF,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,yBAAyB;AAAA,IAC1F,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,yBAAyB;AAAA,IAC3F,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW;AAAA,IAC7E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,yBAAyB;AAAA,IAC1F,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW;AAAA,IAC7E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,gBAAgB;AAAA,IACjF,MAAM,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,qBAAqB;AAAA,IACxF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,0BAA0B;AAAA,IAC5F,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,cAAc;AAAA,IAC/E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,YAAY;AAAA,IAC7E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,cAAc;AAAA,IAC/E,GAAG,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW;AAAA,IAC3E,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IAC/E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IAC9E,GAAG,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,WAAW;AAAA,IAC3E,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,gBAAgB;AAAA,IACjF,IAAI,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,mBAAmB;AAAA,IACpF,MAAM,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,mBAAmB;AAAA,IACtF,KAAK,EAAE,UAAU,QAAQ,QAAQ,MAAM,UAAU,OAAO,UAAU,2BAA2B;AAAA;AAAA,IAG7F,KAAK,EAAE,UAAU,YAAY,QAAQ,OAAO,UAAU,MAAM,UAAU,qBAAqB;AAAA,IAC3F,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA;AAAA,IAGA,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA;AAAA,IAGA,KAAK,EAAE,UAAU,YAAY,QAAQ,OAAO,UAAU,MAAM,UAAU,kBAAkB;AAAA,IACxF,MAAM,EAAE,UAAU,YAAY,QAAQ,OAAO,UAAU,MAAM,UAAU,uBAAuB;AAAA,IAC9F,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA;AAAA,IAGA,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IAChF,MAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,KAAK,EAAE,UAAU,SAAS,QAAQ,MAAM,UAAU,OAAO,UAAU,gBAAgB;AAAA,IACnF,MAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,MAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,MAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IAChF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,eAAe;AAAA,IAClF,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA;AAAA,IAGA,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IAChF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,MAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,iBAAiB;AAAA;AAAA,IAGpF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,kBAAkB;AAAA,IACrF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,kBAAkB;AAAA,IACrF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,iBAAiB;AAAA,IACpF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,cAAc;AAAA,IACjF,MAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,KAAK,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,mBAAmB;AAAA,IACtF,OAAO,EAAE,UAAU,SAAS,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA;AAAA,IAGlF,KAAK,EAAE,UAAU,WAAW,QAAQ,OAAO,UAAU,MAAM,UAAU,kBAAkB;AAAA,IACvF,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,MAAM;AAAA,MACJ,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,IACA,KAAK,EAAE,UAAU,WAAW,QAAQ,OAAO,UAAU,MAAM,UAAU,oBAAoB;AAAA,IACzF,IAAI,EAAE,UAAU,WAAW,QAAQ,OAAO,UAAU,MAAM,UAAU,mBAAmB;AAAA,IACvF,KAAK,EAAE,UAAU,WAAW,QAAQ,OAAO,UAAU,MAAM,UAAU,sBAAsB;AAAA,IAC3F,IAAI,EAAE,UAAU,WAAW,QAAQ,OAAO,UAAU,MAAM,UAAU,mBAAmB;AAAA;AAAA,IAGvF,KAAK,EAAE,UAAU,UAAU,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IACjF,KAAK,EAAE,UAAU,UAAU,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IACjF,MAAM,EAAE,UAAU,UAAU,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA,IAClF,MAAM,EAAE,UAAU,UAAU,QAAQ,MAAM,UAAU,OAAO,UAAU,mBAAmB;AAAA,IACxF,KAAK,EAAE,UAAU,UAAU,QAAQ,MAAM,UAAU,OAAO,UAAU,aAAa;AAAA;AAAA,IAGjF,KAAK,EAAE,UAAU,QAAQ,QAAQ,OAAO,UAAU,MAAM,UAAU,WAAW;AAAA,IAC7E,KAAK,EAAE,UAAU,QAAQ,QAAQ,OAAO,UAAU,MAAM,UAAU,WAAW;AAAA,IAC7E,MAAM,EAAE,UAAU,QAAQ,QAAQ,OAAO,UAAU,MAAM,UAAU,YAAY;AAAA,IAC/E,OAAO,EAAE,UAAU,QAAQ,QAAQ,OAAO,UAAU,MAAM,UAAU,aAAa;AAAA,IACjF,KAAK;AAAA,MACH,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AAEA,QAAM,OAAO,WAAW,SAAoC,KAAK;AAAA,IAC/D,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAEA,SAAO;AAAA,IACL;AAAA,IACA,GAAG;AAAA,EACL;AACF;AA4HA,eAAsB,WACpB,MACA,UACA,SACe;AACf,MAAI,CAAC,MAAM,QAAQ,IAAI,GAAG;AACxB,UAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,EAAE,kBAAAC,kBAAiB,IAAI,MAAM;AAGnC,QAAM,WAAWA,kBAAiB,MAAM,OAAO;AAG/C,MAAI,OAAO,GAAG;AAEZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,GAAG,UAAU,UAAU,UAAU,EAAE,UAAU,QAAQ,CAAC;AAAA,EAC9D,OAAO;AAEL,UAAM,OAAO,IAAI,KAAK,CAAC,QAAQ,GAAG,EAAE,MAAM,2BAA2B,CAAC;AACtE,UAAM,MAAM,IAAI,gBAAgB,IAAI;AAEpC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,OAAO;AACZ,SAAK,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAC7C,aAAS,KAAK,YAAY,IAAI;AAC9B,SAAK,MAAM;AACX,aAAS,KAAK,YAAY,IAAI;AAE9B,QAAI,gBAAgB,GAAG;AAAA,EACzB;AACF;AA6CA,eAAsB,WAAW,UAAkB,UAAiC;AAClF,MAAI,OAAO,GAAG;AAEZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,WAAO,GAAG,SAAS,UAAU,EAAE,UAAU,QAAQ,CAAC;AAAA,EACpD,OAAO;AAEL,UAAM,IAAI;AAAA,MACR;AAAA;AAAA,MAEA,EAAE,MAAM,EAAE,aAAa,WAAW,WAAW,aAAa,EAAE;AAAA,IAC9D;AAAA,EACF;AACF;AA4GA,eAAsB,UACpB,MACA,UACA,SACe;AACf,QAAM,EAAE,YAAY,MAAM,WAAW,SAAS,EAAE,IAAI,WAAW,CAAC;AAEhE,MAAI;AAEJ,MAAI,WAAW;AAEb,kBAAc,UAAU,IAAI;AAAA,EAC9B,WAAW,OAAO,SAAS,UAAU;AAEnC,kBAAc;AAAA,EAChB,WAAW,MAAM,QAAQ,IAAI,GAAG;AAE9B,kBAAc,KACX,IAAI,UAAS,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,MAAM,MAAM,MAAM,CAAE,EAClF,KAAK,SAAS;AAAA,EACnB,WAAW,OAAO,SAAS,YAAY,SAAS,MAAM;AAEpD,kBAAc,KAAK,UAAU,MAAM,MAAM,MAAM;AAAA,EACjD,OAAO;AAEL,kBAAc,OAAO,IAAI;AAAA,EAC3B;AAGA,MAAI,OAAO,GAAG;AAEZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,GAAG,UAAU,UAAU,aAAa,EAAE,UAAU,QAAQ,CAAC;AAAA,EACjE,OAAO;AAEL,UAAM,OAAO,IAAI,KAAK,CAAC,WAAW,GAAG,EAAE,MAAM,2BAA2B,CAAC;AACzE,UAAM,MAAM,IAAI,gBAAgB,IAAI;AAEpC,UAAM,OAAO,SAAS,cAAc,GAAG;AACvC,SAAK,OAAO;AACZ,SAAK,WAAW,SAAS,MAAM,GAAG,EAAE,IAAI,KAAK;AAC7C,aAAS,KAAK,YAAY,IAAI;AAC9B,SAAK,MAAM;AACX,aAAS,KAAK,YAAY,IAAI;AAE9B,QAAI,gBAAgB,GAAG;AAAA,EACzB;AACF;AAgBA,SAAS,oBAAoB,SAAyB;AACpD,SACE,QAEG,QAAQ,YAAY,IAAI,EAGxB,QAAQ,6BAA6B,EAAE,EAEvC,QAAQ,WAAW,QAAQ,EAE3B,QAAQ,aAAa,EAAE;AAE9B;AAuGA,eAAsB,UAAU,UAAkB,UAA4B,CAAC,GAAoB;AACjG,QAAM;AAAA,IACJ,cAAc,KAAK,OAAO;AAAA;AAAA,IAC1B,YAAY;AAAA;AAAA,IACZ,mBAAmB;AAAA,IACnB,WAAW;AAAA,EACb,IAAI;AAEJ,MAAI,OAAO,GAAG;AAEZ,UAAM,KAAK,MAAM,OAAO,aAAa;AACrC,UAAM,OAAO,MAAM,OAAO,MAAM;AAGhC,UAAM,EAAE,iBAAAC,kBAAiB,iBAAAC,kBAAiB,oBAAAC,oBAAmB,IAAI,MAAM;AAEvE,QAAI,CAACF,iBAAgB,QAAQ,GAAG;AAC9B,YAAM,IAAI,MAAM,6BAA6B;AAAA,IAC/C;AAEA,UAAM,eAAe,KAAK,QAAQ,QAAQ;AAG1C,QAAI;AACF,YAAM,QAAQ,MAAM,GAAG,KAAK,YAAY;AAExC,UAAI,CAACC,iBAAgB,MAAM,MAAM,WAAW,GAAG;AAC7C,cAAM,IAAI,MAAM,mBAAmB,MAAM,IAAI,gBAAgB,WAAW,GAAG;AAAA,MAC7E;AAAA,IACF,SAAS,OAAO;AACd,UAAK,MAAc,SAAS,UAAU;AACpC,cAAM,IAAI,MAAM,mBAAmB,QAAQ,EAAE;AAAA,MAC/C;AACA,YAAM;AAAA,IACR;AAGA,UAAM,UAAU,MAAM,GAAG,SAAS,cAAc,EAAE,UAAU,QAAQ,CAAC;AAGrE,QAAI,oBAAoB,CAACC,oBAAmB,SAAS,EAAE,UAAU,CAAC,GAAG;AACnE,YAAM,IAAI,MAAM,wEAAwE;AAAA,IAC1F;AAEA,WAAO,WAAW,oBAAoB,OAAO,IAAI;AAAA,EACnD,OAAO;AAEL,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACF;AAwIA,eAAsB,WAAW,MAAW,UAAkB,SAA8B;AAC1F,QAAMC,UAAS,yBAAyB,QAAQ;AAGhD,MAAIA,YAAW,OAAO;AACpB,uBAAmB,IAAI;AAAA,EACzB;AAEA,UAAQA,SAAQ;AAAA,IACd,KAAK,OAAO;AACV,YAAM,EAAE,WAAAC,WAAU,IAAI,MAAM;AAC5B,aAAOA,WAAU,MAAM,UAAU,OAAO;AAAA,IAC1C;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAC7B,aAAOA,YAAW,MAAM,UAAU,OAAO;AAAA,IAC3C;AAAA,IACA,KAAK,QAAQ;AACX,aAAO,WAAW,MAAM,UAAU,OAAO;AAAA,IAC3C;AAAA,IACA,KAAK,OAAO;AACV,aAAO,UAAU,MAAM,UAAU,OAAO;AAAA,IAC1C;AAAA,IACA;AACE,YAAM,IAAI,MAAM,uBAAuBF,OAAM,EAAE;AAAA,EACnD;AACF;AA6IA,eAAsB,WAAW,UAAkB,SAAoC;AACrF,QAAMA,UAAS,yBAAyB,QAAQ;AAEhD,UAAQA,SAAQ;AAAA,IACd,KAAK,OAAO;AACV,YAAM,EAAE,WAAAG,WAAU,IAAI,MAAM;AAC5B,aAAOA,WAAU,UAAU,OAAO;AAAA,IACpC;AAAA,IACA,KAAK,QAAQ;AACX,YAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAC7B,aAAOA,YAAW,UAAU,OAAO;AAAA,IACrC;AAAA,IACA,KAAK,QAAQ;AACX,aAAO,WAAW,UAAU,OAAO;AAAA,IACrC;AAAA,IACA,KAAK,OAAO;AACV,aAAO,UAAU,UAAU,OAAO;AAAA,IACpC;AAAA,IACA;AACE,YAAM,IAAI,MAAM,uBAAuBJ,OAAM,EAAE;AAAA,EACnD;AACF;;;AT5mDA;AAEA;;;AUfA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,oBAAwC;AAuBjC,IAAM,mBAAmB,CAC9B,UACA,WAA6B,CAAC,MACD;AAC7B,QAAM;AAAA,IACJ,YAAY;AAAA,IACZ,mBAAmB;AAAA,IACnB,mBAAmB;AAAA,IACnB,iBAAiB;AAAA,IACjB,sBAAsB;AAAA,IACtB,YAAY;AAAA,IACZ,oBAAoB,CAAC;AAAA,EACvB,IAAI;AAEJ,QAAM,SAAmB,CAAC;AAC1B,MAAI,QAAQ;AAEZ,MAAI,SAAS,SAAS,WAAW;AAC/B,WAAO,KAAK,wCAAqC,SAAS,aAAa;AAAA,EACzE,OAAO;AACL,aAAS;AAAA,EACX;AAEA,MAAI,SAAS,SAAS,WAAW;AAC/B,WAAO,KAAK,6CAAuC,SAAS,aAAa;AAAA,EAC3E;AAEA,MAAI,oBAAoB,CAAC,QAAQ,KAAK,QAAQ,GAAG;AAC/C,WAAO,KAAK,gEAA0D;AAAA,EACxE,WAAW,QAAQ,KAAK,QAAQ,GAAG;AACjC,aAAS;AAAA,EACX;AAEA,MAAI,oBAAoB,CAAC,QAAQ,KAAK,QAAQ,GAAG;AAC/C,WAAO,KAAK,gEAA0D;AAAA,EACxE,WAAW,QAAQ,KAAK,QAAQ,GAAG;AACjC,aAAS;AAAA,EACX;AAEA,MAAI,kBAAkB,CAAC,KAAK,KAAK,QAAQ,GAAG;AAC1C,WAAO,KAAK,sDAAgD;AAAA,EAC9D,WAAW,KAAK,KAAK,QAAQ,GAAG;AAC9B,aAAS;AAAA,EACX;AAEA,MAAI,uBAAuB,CAAC,sCAAsC,KAAK,QAAQ,GAAG;AAChF,WAAO,KAAK,8DAA2D;AAAA,EACzE,WAAW,sCAAsC,KAAK,QAAQ,GAAG;AAC/D,aAAS;AAAA,EACX;AAEA,aAAW,WAAW,mBAAmB;AACvC,QAAI,SAAS,YAAY,EAAE,SAAS,QAAQ,YAAY,CAAC,GAAG;AAC1D,aAAO,KAAK,uCAAoC,OAAO,EAAE;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,SAAS,UAAU,GAAI,UAAS;AACpC,MAAI,SAAS,UAAU,GAAI,UAAS;AAEpC,MAAI,aAAa,KAAK,QAAQ,EAAG,UAAS;AAC1C,MAAI,eAAe,KAAK,QAAQ,EAAG,UAAS;AAE5C,UAAQ,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,CAAC;AAExC,MAAI;AACJ,MAAI,QAAQ,GAAI,YAAW;AAAA,WAClB,QAAQ,GAAI,YAAW;AAAA,WACvB,QAAQ,GAAI,YAAW;AAAA,MAC3B,YAAW;AAEhB,SAAO;AAAA,IACL,SAAS,OAAO,WAAW;AAAA,IAC3B;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAMO,IAAM,eAAe,CAAC,SAAyB;AACpD,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI,YAAY,KACb,QAAQ,uDAAuD,EAAE,EACjE,QAAQ,oDAAoD,EAAE;AAEjE,cAAY,UAAU,QAAQ,oBAAoB,EAAE;AACpD,cAAY,UAAU,QAAQ,oBAAoB,EAAE;AACpD,cAAY,UAAU,QAAQ,iBAAiB,EAAE;AACjD,cAAY,UAAU,QAAQ,uDAAuD,EAAE;AACvF,cAAY,UAAU,QAAQ,uDAAuD,EAAE;AACvF,cAAY,UAAU,QAAQ,oBAAoB,EAAE;AAEpD,SAAO,UAAU,KAAK;AACxB;AAEO,IAAM,mBAAmB,CAAC,UAA2B;AAC1D,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAEhD,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,MAAI;AACF,eAAW,QAAQ,OAAO;AACxB,UAAI,CAAC,QAAQ,CAAC,mBAAmB,KAAK,IAAI,EAAG,QAAO;AACpD,WAAK,KAAK,QAAQ,MAAM,GAAG,EAAE,QAAQ,MAAM,GAAG,CAAC;AAAA,IACjD;AACA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,aAAa,CAAC,OAAe,OAAO,OAAe;AAC9D,aAAO,0BAAW,QAAQ,EACvB,OAAO,QAAQ,IAAI,EACnB,OAAO,KAAK;AACjB;AAEO,IAAM,sBAAsB,CAAC,SAAS,OAAe;AAC1D,aAAO,2BAAY,MAAM,EAAE,SAAS,KAAK;AAC3C;AAEO,IAAM,gBAAgB,CAAC,UAA2B;AACvD,MAAI,CAAC,SAAS,OAAO,UAAU,SAAU,QAAO;AAEhD,MAAI,CAAC,yBAAyB,KAAK,KAAK,EAAG,QAAO;AAElD,MAAI;AACF,UAAM,UAAU,KAAK,KAAK;AAC1B,UAAM,YAAY,KAAK,OAAO;AAC9B,WAAO,cAAc;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,qBAAqB,CAAC,UAA0B;AAC3D,MAAI,CAAC,MAAO,QAAO;AAEnB,SAAO,MACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK,EACnB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK,EACpB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,OAAO,KAAK,EACpB,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,OAAO;AAC1B;AAEO,IAAM,cAAc,CAAC,QAAyB;AACnD,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;AAE5C,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,WACE,OAAO,aAAa,YACnB,OAAO,aAAa,YAClB,OAAO,aAAa,eAAe,OAAO,aAAa;AAAA,EAE9D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,uBAAuB,CAAC,OAAe,cAAc,OAAe;AAC/E,MAAI,CAAC,MAAO,QAAO;AAEnB,SAAO,MACJ,QAAQ,SAAS,WAAW,EAC5B,QAAQ,SAAS,WAAW,EAC5B,QAAQ,QAAQ,WAAW,EAC3B,QAAQ,uBAAuB,WAAW;AAC/C;AAEO,IAAM,gBAAgB,CAAC,SAAS,OAAe;AACpD,QAAM,QAAQ;AACd,MAAI,SAAS;AAEb,QAAM,YAAQ,2BAAY,MAAM;AAChC,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAU,MAAM,MAAM,CAAC,IAAI,MAAM,MAAM;AAAA,EACzC;AAEA,SAAO;AACT;;;AV3IA;AAGA;AAnEA,IAAM,sBAAsB;AAAA,EAC1B,GAAG;AAAA,EACH,GAAG;AACL;AAGA,IAAM,IAAI;AAAA;AAAA,EAER,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AAAA;AAAA,EAGH,GAAG;AACL;AAGA,IAAO,eAAQ;","names":["size","Papa","sum","g","validator","dayjs","utc","relativeTime","weekOfYearPlugin","customParseFormat","isSameOrAfter","isSameOrBefore","weekday","localeData","localizedFormat","format","dayOfWeek","fastEqual","crc32","lodash","lodash","sum","renderTreeAsText","isValidFilePath","isValidFileSize","isValidTextContent","format","exportCSV","exportJSON","importCSV","importJSON"]}
|