@eigenpal/docx-js-editor 0.0.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/LICENSE +21 -0
- package/README.md +191 -0
- package/dist/colorResolver-C-tITrbI.d.cts +1037 -0
- package/dist/colorResolver-Yakhydrt.d.ts +1037 -0
- package/dist/core-plugins.cjs +7131 -0
- package/dist/core-plugins.cjs.map +1 -0
- package/dist/core-plugins.d.cts +27 -0
- package/dist/core-plugins.d.ts +27 -0
- package/dist/core-plugins.js +7102 -0
- package/dist/core-plugins.js.map +1 -0
- package/dist/headless.cjs +10984 -0
- package/dist/headless.cjs.map +1 -0
- package/dist/headless.d.cts +361 -0
- package/dist/headless.d.ts +361 -0
- package/dist/headless.js +10852 -0
- package/dist/headless.js.map +1 -0
- package/dist/index.cjs +45026 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +369 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +4579 -0
- package/dist/index.d.ts +4579 -0
- package/dist/index.js +44701 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-cli.js +9657 -0
- package/dist/mcp-cli.js.map +1 -0
- package/dist/mcp.cjs +8715 -0
- package/dist/mcp.cjs.map +1 -0
- package/dist/mcp.d.cts +155 -0
- package/dist/mcp.d.ts +155 -0
- package/dist/mcp.js +8667 -0
- package/dist/mcp.js.map +1 -0
- package/dist/registry-D3zhko7n.d.ts +165 -0
- package/dist/registry-DeeU0bQB.d.cts +165 -0
- package/dist/styles.css +1 -0
- package/dist/types-BJXChtaM.d.cts +2216 -0
- package/dist/types-BJXChtaM.d.ts +2216 -0
- package/package.json +132 -0
package/dist/mcp.cjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcp/index.ts","../src/core-plugins/registry.ts","../src/docx/unzip.ts","../src/docx/xmlParser.ts","../src/docx/relsParser.ts","../src/docx/themeParser.ts","../src/docx/styleParser.ts","../src/docx/numberingParser.ts","../src/docx/imageParser.ts","../src/docx/runParser.ts","../src/docx/hyperlinkParser.ts","../src/docx/bookmarkParser.ts","../src/docx/tableParser.ts","../src/docx/headerFooterParser.ts","../src/docx/footnoteParser.ts","../src/docx/sectionParser.ts","../src/docx/runConsolidator.ts","../src/docx/paragraphParser.ts","../src/docx/documentParser.ts","../src/utils/fontLoader.ts","../src/docx/parser.ts","../src/docx/rezip.ts","../src/docx/serializer/runSerializer.ts","../src/docx/serializer/paragraphSerializer.ts","../src/docx/serializer/tableSerializer.ts","../src/docx/serializer/documentSerializer.ts","../src/agent/executor.ts","../src/mcp/core-tools.ts","../src/mcp/server.ts"],"sourcesContent":["/**\n * MCP Server Module\n *\n * Model Context Protocol server for exposing document editing tools to AI clients.\n *\n * @example\n * ```ts\n * import { createMcpServer, startStdioServer } from '@eigenpal/docx-editor/mcp';\n *\n * // Create server instance\n * const server = createMcpServer({ debug: true });\n *\n * // List available tools\n * console.log(server.listTools());\n *\n * // Call a tool programmatically\n * const result = await server.handleToolCall('docx_load', { content: base64 });\n * ```\n */\n\n// ============================================================================\n// SERVER\n// ============================================================================\n\nexport {\n createMcpServer,\n startStdioServer,\n handleJsonRpcRequest,\n type McpServer,\n type McpServerConfig,\n type McpToolInfo,\n} from './server';\n\n// ============================================================================\n// CORE TOOLS\n// ============================================================================\n\nexport {\n coreMcpTools,\n loadDocumentTool,\n saveDocumentTool,\n closeDocumentTool,\n getDocumentInfoTool,\n getDocumentTextTool,\n insertTextTool,\n replaceTextTool,\n deleteTextTool,\n formatTextTool,\n applyStyleTool,\n} from './core-tools';\n\n// ============================================================================\n// DEFAULT EXPORT\n// ============================================================================\n\nexport { createMcpServer as default } from './server';\n","/**\n * Plugin Registry\n *\n * Central registry for core plugins. Manages plugin lifecycle,\n * collects command handlers from all plugins, and aggregates\n * MCP tool definitions for the MCP server.\n */\n\nimport type {\n CorePlugin,\n CommandHandler,\n McpToolDefinition,\n PluginEvent,\n PluginEventListener,\n PluginRegistrationResult,\n PluginOptions,\n} from './types';\n\n// ============================================================================\n// PLUGIN REGISTRY\n// ============================================================================\n\n/**\n * Plugin Registry - manages core plugins\n *\n * @example\n * ```ts\n * import { pluginRegistry, docxtemplaterPlugin } from '@eigenpal/docx-editor/core-plugins';\n *\n * // Register plugins\n * pluginRegistry.register(docxtemplaterPlugin);\n *\n * // Get all MCP tools for MCP server\n * const tools = pluginRegistry.getMcpTools();\n *\n * // Get command handler for executor\n * const handler = pluginRegistry.getCommandHandler('insertTemplateVariable');\n * ```\n */\nexport class PluginRegistry {\n private plugins: Map<string, CorePlugin> = new Map();\n private commandHandlers: Map<string, { pluginId: string; handler: CommandHandler }> = new Map();\n private eventListeners: Set<PluginEventListener> = new Set();\n private initialized: Set<string> = new Set();\n\n // ==========================================================================\n // REGISTRATION\n // ==========================================================================\n\n /**\n * Register a plugin\n *\n * @param plugin - The plugin to register\n * @param options - Optional configuration\n * @returns Registration result\n */\n register(plugin: CorePlugin, options?: PluginOptions): PluginRegistrationResult {\n const warnings: string[] = [];\n\n // Validate plugin\n if (!plugin.id) {\n return { success: false, error: 'Plugin must have an id' };\n }\n\n if (this.plugins.has(plugin.id)) {\n return { success: false, error: `Plugin '${plugin.id}' is already registered` };\n }\n\n // Check dependencies\n if (plugin.dependencies) {\n for (const depId of plugin.dependencies) {\n if (!this.plugins.has(depId)) {\n return {\n success: false,\n error: `Plugin '${plugin.id}' requires '${depId}' which is not registered`,\n };\n }\n }\n }\n\n // Register command handlers\n if (plugin.commandHandlers) {\n for (const [commandType, handler] of Object.entries(plugin.commandHandlers)) {\n if (this.commandHandlers.has(commandType)) {\n const existing = this.commandHandlers.get(commandType)!;\n warnings.push(\n `Command '${commandType}' from '${plugin.id}' overrides handler from '${existing.pluginId}'`\n );\n }\n this.commandHandlers.set(commandType, { pluginId: plugin.id, handler });\n }\n }\n\n // Store plugin\n this.plugins.set(plugin.id, plugin);\n\n // Initialize if needed\n if (plugin.initialize && !this.initialized.has(plugin.id)) {\n try {\n const result = plugin.initialize();\n if (result instanceof Promise) {\n // Handle async initialization\n result\n .then(() => {\n this.initialized.add(plugin.id);\n })\n .catch((err) => {\n this.emit({ type: 'error', pluginId: plugin.id, error: err as Error });\n });\n } else {\n this.initialized.add(plugin.id);\n }\n } catch (err) {\n this.emit({ type: 'error', pluginId: plugin.id, error: err as Error });\n }\n }\n\n // Log if debug enabled\n if (options?.debug) {\n console.log(`[PluginRegistry] Registered plugin: ${plugin.id}`);\n }\n\n // Emit event\n this.emit({ type: 'registered', plugin });\n\n return {\n success: true,\n plugin,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n }\n\n /**\n * Unregister a plugin\n *\n * @param pluginId - ID of the plugin to unregister\n * @returns Whether unregistration succeeded\n */\n unregister(pluginId: string): boolean {\n const plugin = this.plugins.get(pluginId);\n if (!plugin) {\n return false;\n }\n\n // Check if other plugins depend on this one\n for (const [id, p] of this.plugins) {\n if (p.dependencies?.includes(pluginId)) {\n console.warn(`Cannot unregister '${pluginId}': '${id}' depends on it`);\n return false;\n }\n }\n\n // Remove command handlers\n for (const [commandType, { pluginId: pid }] of this.commandHandlers) {\n if (pid === pluginId) {\n this.commandHandlers.delete(commandType);\n }\n }\n\n // Call destroy if available\n if (plugin.destroy) {\n try {\n const result = plugin.destroy();\n if (result instanceof Promise) {\n result.catch((err) => {\n this.emit({ type: 'error', pluginId, error: err as Error });\n });\n }\n } catch (err) {\n this.emit({ type: 'error', pluginId, error: err as Error });\n }\n }\n\n // Remove plugin\n this.plugins.delete(pluginId);\n this.initialized.delete(pluginId);\n\n // Emit event\n this.emit({ type: 'unregistered', pluginId });\n\n return true;\n }\n\n // ==========================================================================\n // QUERIES\n // ==========================================================================\n\n /**\n * Get a registered plugin by ID\n *\n * @param id - Plugin ID\n * @returns The plugin or undefined\n */\n get(id: string): CorePlugin | undefined {\n return this.plugins.get(id);\n }\n\n /**\n * Get all registered plugins\n *\n * @returns Array of all plugins\n */\n getAll(): CorePlugin[] {\n return Array.from(this.plugins.values());\n }\n\n /**\n * Check if a plugin is registered\n *\n * @param id - Plugin ID\n * @returns Whether the plugin is registered\n */\n has(id: string): boolean {\n return this.plugins.has(id);\n }\n\n /**\n * Get number of registered plugins\n */\n get size(): number {\n return this.plugins.size;\n }\n\n // ==========================================================================\n // COMMAND HANDLERS\n // ==========================================================================\n\n /**\n * Get a command handler for a command type\n *\n * @param commandType - The command type\n * @returns The handler or undefined\n */\n getCommandHandler(commandType: string): CommandHandler | undefined {\n const entry = this.commandHandlers.get(commandType);\n return entry?.handler;\n }\n\n /**\n * Get all registered command types\n *\n * @returns Array of command type strings\n */\n getCommandTypes(): string[] {\n return Array.from(this.commandHandlers.keys());\n }\n\n /**\n * Check if a command type has a handler\n *\n * @param commandType - The command type\n * @returns Whether a handler exists\n */\n hasCommandHandler(commandType: string): boolean {\n return this.commandHandlers.has(commandType);\n }\n\n // ==========================================================================\n // MCP TOOLS\n // ==========================================================================\n\n /**\n * Get all MCP tools from all registered plugins\n *\n * @returns Array of MCP tool definitions\n */\n getMcpTools(): McpToolDefinition[] {\n const tools: McpToolDefinition[] = [];\n\n for (const plugin of this.plugins.values()) {\n if (plugin.mcpTools) {\n tools.push(...plugin.mcpTools);\n }\n }\n\n return tools;\n }\n\n /**\n * Get MCP tools from a specific plugin\n *\n * @param pluginId - Plugin ID\n * @returns Array of MCP tool definitions\n */\n getMcpToolsForPlugin(pluginId: string): McpToolDefinition[] {\n const plugin = this.plugins.get(pluginId);\n return plugin?.mcpTools || [];\n }\n\n /**\n * Get an MCP tool by name\n *\n * @param toolName - Tool name\n * @returns The tool definition or undefined\n */\n getMcpTool(toolName: string): McpToolDefinition | undefined {\n for (const plugin of this.plugins.values()) {\n if (plugin.mcpTools) {\n const tool = plugin.mcpTools.find((t) => t.name === toolName);\n if (tool) return tool;\n }\n }\n return undefined;\n }\n\n // ==========================================================================\n // EVENTS\n // ==========================================================================\n\n /**\n * Add an event listener\n *\n * @param listener - Event listener function\n */\n addEventListener(listener: PluginEventListener): void {\n this.eventListeners.add(listener);\n }\n\n /**\n * Remove an event listener\n *\n * @param listener - Event listener function\n */\n removeEventListener(listener: PluginEventListener): void {\n this.eventListeners.delete(listener);\n }\n\n /**\n * Emit an event to all listeners\n */\n private emit(event: PluginEvent): void {\n for (const listener of this.eventListeners) {\n try {\n listener(event);\n } catch (err) {\n console.error('[PluginRegistry] Event listener error:', err);\n }\n }\n }\n\n // ==========================================================================\n // UTILITIES\n // ==========================================================================\n\n /**\n * Clear all registered plugins\n *\n * Useful for testing or resetting state.\n */\n clear(): void {\n // Call destroy on all plugins\n for (const plugin of this.plugins.values()) {\n if (plugin.destroy) {\n try {\n plugin.destroy();\n } catch {\n // Ignore errors during clear\n }\n }\n }\n\n this.plugins.clear();\n this.commandHandlers.clear();\n this.initialized.clear();\n }\n\n /**\n * Get registry state for debugging\n */\n getDebugInfo(): {\n plugins: string[];\n commandTypes: string[];\n mcpTools: string[];\n initialized: string[];\n } {\n return {\n plugins: Array.from(this.plugins.keys()),\n commandTypes: Array.from(this.commandHandlers.keys()),\n mcpTools: this.getMcpTools().map((t) => t.name),\n initialized: Array.from(this.initialized),\n };\n }\n}\n\n// ============================================================================\n// GLOBAL INSTANCE\n// ============================================================================\n\n/**\n * Global plugin registry instance\n *\n * Use this for registering plugins and accessing their capabilities.\n */\nexport const pluginRegistry = new PluginRegistry();\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Register multiple plugins at once\n *\n * @param plugins - Array of plugins to register\n * @returns Array of registration results\n */\nexport function registerPlugins(\n plugins: CorePlugin[],\n options?: PluginOptions\n): PluginRegistrationResult[] {\n return plugins.map((plugin) => pluginRegistry.register(plugin, options));\n}\n\n/**\n * Create a plugin registration helper with options pre-configured\n *\n * @param options - Default options for plugin registration\n * @returns Registration function\n */\nexport function createPluginRegistrar(options: PluginOptions) {\n return (plugin: CorePlugin) => pluginRegistry.register(plugin, options);\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport default pluginRegistry;\n","/**\n * DOCX Unzipper\n *\n * Extracts all files from a DOCX ZIP archive and organizes them\n * into a structured format for further processing.\n *\n * A DOCX file is a ZIP archive containing:\n * - [Content_Types].xml - Content type declarations\n * - word/document.xml - Main document content\n * - word/styles.xml - Style definitions\n * - word/theme/theme1.xml - Theme colors and fonts\n * - word/numbering.xml - List/numbering definitions\n * - word/fontTable.xml - Font declarations\n * - word/settings.xml - Document settings\n * - word/webSettings.xml - Web settings\n * - word/header*.xml - Header content\n * - word/footer*.xml - Footer content\n * - word/footnotes.xml - Footnotes\n * - word/endnotes.xml - Endnotes\n * - word/media/* - Embedded images and media\n * - word/_rels/document.xml.rels - Relationships\n * - _rels/.rels - Package relationships\n * - docProps/core.xml - Core properties\n * - docProps/app.xml - Application properties\n */\n\nimport JSZip from 'jszip';\n\n/**\n * Raw extracted content from a DOCX file\n */\nexport interface RawDocxContent {\n // Main document\n documentXml: string | null;\n\n // Styles and formatting\n stylesXml: string | null;\n themeXml: string | null;\n numberingXml: string | null;\n fontTableXml: string | null;\n settingsXml: string | null;\n webSettingsXml: string | null;\n\n // Headers and footers (keyed by filename, e.g., \"header1.xml\")\n headers: Map<string, string>;\n footers: Map<string, string>;\n\n // Footnotes and endnotes\n footnotesXml: string | null;\n endnotesXml: string | null;\n\n // Comments\n commentsXml: string | null;\n\n // Relationships\n documentRels: string | null;\n packageRels: string | null;\n\n // Content types\n contentTypesXml: string | null;\n\n // Document properties\n corePropsXml: string | null;\n appPropsXml: string | null;\n customPropsXml: string | null;\n\n // Media files (images, etc.) - keyed by path, e.g., \"word/media/image1.png\"\n media: Map<string, ArrayBuffer>;\n\n // Embedded fonts - keyed by path\n fonts: Map<string, ArrayBuffer>;\n\n // All XML files (for any we might have missed)\n allXml: Map<string, string>;\n\n // Original ZIP for round-trip preservation\n originalZip: JSZip;\n\n // Original buffer for round-trip\n originalBuffer: ArrayBuffer;\n}\n\n/**\n * Extract all content from a DOCX file\n *\n * @param buffer - DOCX file as ArrayBuffer\n * @returns Promise resolving to extracted content\n */\nexport async function unzipDocx(buffer: ArrayBuffer): Promise<RawDocxContent> {\n const zip = await JSZip.loadAsync(buffer);\n\n const content: RawDocxContent = {\n documentXml: null,\n stylesXml: null,\n themeXml: null,\n numberingXml: null,\n fontTableXml: null,\n settingsXml: null,\n webSettingsXml: null,\n headers: new Map(),\n footers: new Map(),\n footnotesXml: null,\n endnotesXml: null,\n commentsXml: null,\n documentRels: null,\n packageRels: null,\n contentTypesXml: null,\n corePropsXml: null,\n appPropsXml: null,\n customPropsXml: null,\n media: new Map(),\n fonts: new Map(),\n allXml: new Map(),\n originalZip: zip,\n originalBuffer: buffer,\n };\n\n // Process each file in the ZIP\n for (const [path, file] of Object.entries(zip.files)) {\n // Skip directories\n if (file.dir) continue;\n\n const lowerPath = path.toLowerCase();\n\n // Determine file type and extract\n if (lowerPath.endsWith('.xml') || lowerPath.endsWith('.rels')) {\n const xmlContent = await file.async('text');\n content.allXml.set(path, xmlContent);\n\n // Categorize known XML files\n if (lowerPath === 'word/document.xml') {\n content.documentXml = xmlContent;\n } else if (lowerPath === 'word/styles.xml') {\n content.stylesXml = xmlContent;\n } else if (lowerPath === 'word/theme/theme1.xml') {\n content.themeXml = xmlContent;\n } else if (lowerPath === 'word/numbering.xml') {\n content.numberingXml = xmlContent;\n } else if (lowerPath === 'word/fonttable.xml') {\n content.fontTableXml = xmlContent;\n } else if (lowerPath === 'word/settings.xml') {\n content.settingsXml = xmlContent;\n } else if (lowerPath === 'word/websettings.xml') {\n content.webSettingsXml = xmlContent;\n } else if (lowerPath === 'word/footnotes.xml') {\n content.footnotesXml = xmlContent;\n } else if (lowerPath === 'word/endnotes.xml') {\n content.endnotesXml = xmlContent;\n } else if (lowerPath === 'word/comments.xml') {\n content.commentsXml = xmlContent;\n } else if (lowerPath === 'word/_rels/document.xml.rels') {\n content.documentRels = xmlContent;\n } else if (lowerPath === '_rels/.rels') {\n content.packageRels = xmlContent;\n } else if (lowerPath === '[content_types].xml') {\n content.contentTypesXml = xmlContent;\n } else if (lowerPath === 'docprops/core.xml') {\n content.corePropsXml = xmlContent;\n } else if (lowerPath === 'docprops/app.xml') {\n content.appPropsXml = xmlContent;\n } else if (lowerPath === 'docprops/custom.xml') {\n content.customPropsXml = xmlContent;\n } else if (lowerPath.match(/^word\\/header\\d+\\.xml$/)) {\n const filename = path.split('/').pop() || path;\n content.headers.set(filename, xmlContent);\n } else if (lowerPath.match(/^word\\/footer\\d+\\.xml$/)) {\n const filename = path.split('/').pop() || path;\n content.footers.set(filename, xmlContent);\n }\n } else if (lowerPath.startsWith('word/media/')) {\n // Media files (images, etc.)\n const binaryContent = await file.async('arraybuffer');\n content.media.set(path, binaryContent);\n } else if (lowerPath.startsWith('word/fonts/')) {\n // Embedded fonts\n const binaryContent = await file.async('arraybuffer');\n content.fonts.set(path, binaryContent);\n }\n }\n\n return content;\n}\n\n/**\n * Get a list of all files in the DOCX\n *\n * @param content - Extracted DOCX content\n * @returns Array of file paths\n */\nexport function getFileList(content: RawDocxContent): string[] {\n const files: string[] = [];\n\n for (const path of Object.keys(content.originalZip.files)) {\n if (!content.originalZip.files[path].dir) {\n files.push(path);\n }\n }\n\n return files.sort();\n}\n\n/**\n * Get the MIME type for a media file based on extension\n *\n * @param path - File path\n * @returns MIME type string\n */\nexport function getMediaMimeType(path: string): string {\n const ext = path.toLowerCase().split('.').pop();\n\n switch (ext) {\n case 'png':\n return 'image/png';\n case 'jpg':\n case 'jpeg':\n return 'image/jpeg';\n case 'gif':\n return 'image/gif';\n case 'bmp':\n return 'image/bmp';\n case 'tif':\n case 'tiff':\n return 'image/tiff';\n case 'wmf':\n return 'image/x-wmf';\n case 'emf':\n return 'image/x-emf';\n case 'svg':\n return 'image/svg+xml';\n case 'webp':\n return 'image/webp';\n default:\n return 'application/octet-stream';\n }\n}\n\n/**\n * Convert media file to data URL\n *\n * @param data - Binary data\n * @param mimeType - MIME type\n * @returns Data URL string\n */\nexport function mediaToDataUrl(data: ArrayBuffer, mimeType: string): string {\n const bytes = new Uint8Array(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n return `data:${mimeType};base64,${base64}`;\n}\n\n/**\n * Extract a specific file from the original ZIP\n *\n * @param content - Extracted DOCX content\n * @param path - File path within the ZIP\n * @returns File content as string or ArrayBuffer, or null if not found\n */\nexport async function extractFile(\n content: RawDocxContent,\n path: string\n): Promise<string | ArrayBuffer | null> {\n const file = content.originalZip.file(path);\n if (!file) return null;\n\n const lowerPath = path.toLowerCase();\n if (lowerPath.endsWith('.xml') || lowerPath.endsWith('.rels')) {\n return file.async('text');\n } else {\n return file.async('arraybuffer');\n }\n}\n\n/**\n * Check if a file exists in the DOCX\n *\n * @param content - Extracted DOCX content\n * @param path - File path to check\n * @returns true if file exists\n */\nexport function hasFile(content: RawDocxContent, path: string): boolean {\n return content.originalZip.file(path) !== null;\n}\n\n/**\n * Get summary of DOCX content\n *\n * @param content - Extracted DOCX content\n * @returns Object with file counts and presence flags\n */\nexport function getContentSummary(content: RawDocxContent): {\n hasDocument: boolean;\n hasStyles: boolean;\n hasTheme: boolean;\n hasNumbering: boolean;\n hasFontTable: boolean;\n hasFootnotes: boolean;\n hasEndnotes: boolean;\n hasComments: boolean;\n headerCount: number;\n footerCount: number;\n mediaCount: number;\n fontCount: number;\n totalFiles: number;\n} {\n return {\n hasDocument: content.documentXml !== null,\n hasStyles: content.stylesXml !== null,\n hasTheme: content.themeXml !== null,\n hasNumbering: content.numberingXml !== null,\n hasFontTable: content.fontTableXml !== null,\n hasFootnotes: content.footnotesXml !== null,\n hasEndnotes: content.endnotesXml !== null,\n hasComments: content.commentsXml !== null,\n headerCount: content.headers.size,\n footerCount: content.footers.size,\n mediaCount: content.media.size,\n fontCount: content.fonts.size,\n totalFiles: Object.keys(content.originalZip.files).filter(\n (p) => !content.originalZip.files[p].dir\n ).length,\n };\n}\n","/**\n * XML Parser Utilities for OOXML\n *\n * Provides helper functions for parsing Office Open XML (OOXML) content\n * with proper namespace handling.\n *\n * OOXML uses many namespaces:\n * - w: WordprocessingML (main document content)\n * - a: DrawingML (graphics)\n * - r: Relationships\n * - wp: Word Drawing positioning\n * - wps: Word Drawing shapes\n * - wpc: Word Drawing canvas\n * - wpg: Word Drawing group\n * - m: Math\n * - mc: Markup Compatibility\n * - v: VML (legacy vector graphics)\n * - o: Office (extensions)\n * - pic: Pictures\n */\n\nimport { xml2js, type Element as XmlElement } from 'xml-js';\n\n// Re-export Element type for consumers\nexport type { Element as XmlElement } from 'xml-js';\n\n/**\n * Common OOXML namespace URIs\n */\nexport const NAMESPACES = {\n // Main namespaces\n w: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',\n a: 'http://schemas.openxmlformats.org/drawingml/2006/main',\n r: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',\n\n // Drawing namespaces\n wp: 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',\n wp14: 'http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing',\n wps: 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape',\n wpc: 'http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas',\n wpg: 'http://schemas.microsoft.com/office/word/2010/wordprocessingGroup',\n\n // Picture namespace\n pic: 'http://schemas.openxmlformats.org/drawingml/2006/picture',\n\n // Math namespace\n m: 'http://schemas.openxmlformats.org/officeDocument/2006/math',\n\n // Markup Compatibility\n mc: 'http://schemas.openxmlformats.org/markup-compatibility/2006',\n\n // Legacy VML\n v: 'urn:schemas-microsoft-com:vml',\n o: 'urn:schemas-microsoft-com:office:office',\n\n // Other\n w14: 'http://schemas.microsoft.com/office/word/2010/wordml',\n w15: 'http://schemas.microsoft.com/office/word/2012/wordml',\n\n // Content Types\n ct: 'http://schemas.openxmlformats.org/package/2006/content-types',\n\n // Relationships\n pr: 'http://schemas.openxmlformats.org/package/2006/relationships',\n} as const;\n\n/**\n * Parse XML string into element tree\n *\n * @param xml - XML string to parse\n * @returns Parsed element tree\n */\nexport function parseXml(xml: string): XmlElement {\n const result = xml2js(xml, {\n compact: false,\n ignoreComment: true,\n ignoreInstruction: true,\n ignoreDoctype: true,\n alwaysArray: false,\n // IMPORTANT: Do NOT trim whitespace - it strips significant spaces\n // around hyperlinks and other inline elements. DOCX uses xml:space=\"preserve\"\n // to indicate significant whitespace, but we need to preserve all text as-is.\n trim: false,\n attributesKey: 'attributes',\n textKey: 'text',\n }) as XmlElement;\n\n return result;\n}\n\n/**\n * Parse XML string to a more convenient format\n */\nexport function parseXmlDocument(xml: string): XmlElement | null {\n try {\n const parsed = parseXml(xml);\n\n // The root is typically the declaration + elements array\n if (parsed.elements && parsed.elements.length > 0) {\n // Return the first real element (skip declarations)\n return parsed.elements.find((e) => e.type === 'element') ?? null;\n }\n\n return parsed;\n } catch (error) {\n console.warn('Failed to parse XML:', error);\n return null;\n }\n}\n\n/**\n * Get local name from a prefixed element name\n * e.g., \"w:p\" -> \"p\", \"a:graphic\" -> \"graphic\"\n */\nexport function getLocalName(name: string): string {\n const colonIndex = name.indexOf(':');\n return colonIndex >= 0 ? name.substring(colonIndex + 1) : name;\n}\n\n/**\n * Get namespace prefix from an element name\n * e.g., \"w:p\" -> \"w\", \"a:graphic\" -> \"a\"\n */\nexport function getNamespacePrefix(name: string): string | null {\n const colonIndex = name.indexOf(':');\n return colonIndex >= 0 ? name.substring(0, colonIndex) : null;\n}\n\n/**\n * Check if an element matches a given namespaced name\n *\n * @param element - Element to check\n * @param namespace - Namespace prefix (e.g., \"w\", \"a\")\n * @param localName - Local element name (e.g., \"p\", \"r\")\n */\nexport function matchesName(element: XmlElement, namespace: string, localName: string): boolean {\n if (!element.name) return false;\n\n const fullName = `${namespace}:${localName}`;\n if (element.name === fullName) return true;\n\n // Also check just the local name if no namespace prefix in element\n if (getLocalName(element.name) === localName) return true;\n\n return false;\n}\n\n/**\n * Find first child element matching the given namespaced name\n *\n * @param parent - Parent element\n * @param namespace - Namespace prefix (e.g., \"w\")\n * @param localName - Local element name (e.g., \"p\")\n * @returns First matching child or null\n */\nexport function findChild(\n parent: XmlElement | null | undefined,\n namespace: string,\n localName: string\n): XmlElement | null {\n if (!parent || !parent.elements) return null;\n\n const fullName = `${namespace}:${localName}`;\n\n for (const child of parent.elements) {\n if (child.type !== 'element') continue;\n\n if (child.name === fullName) {\n return child;\n }\n\n // Check local name match\n if (getLocalName(child.name || '') === localName) {\n return child;\n }\n }\n\n return null;\n}\n\n/**\n * Find all child elements matching the given namespaced name\n *\n * @param parent - Parent element\n * @param namespace - Namespace prefix\n * @param localName - Local element name\n * @returns Array of matching children\n */\nexport function findChildren(\n parent: XmlElement | null | undefined,\n namespace: string,\n localName: string\n): XmlElement[] {\n if (!parent || !parent.elements) return [];\n\n const fullName = `${namespace}:${localName}`;\n const results: XmlElement[] = [];\n\n for (const child of parent.elements) {\n if (child.type !== 'element') continue;\n\n if (child.name === fullName || getLocalName(child.name || '') === localName) {\n results.push(child);\n }\n }\n\n return results;\n}\n\n/**\n * Find first child element by local name only (ignoring namespace)\n *\n * @param parent - Parent element\n * @param localName - Local element name\n * @returns First matching child or null\n */\nexport function findChildByLocalName(\n parent: XmlElement | null | undefined,\n localName: string\n): XmlElement | null {\n if (!parent || !parent.elements) return null;\n\n for (const child of parent.elements) {\n if (child.type !== 'element') continue;\n\n if (getLocalName(child.name || '') === localName) {\n return child;\n }\n }\n\n return null;\n}\n\n/**\n * Find all child elements by local name only\n *\n * @param parent - Parent element\n * @param localName - Local element name\n * @returns Array of matching children\n */\nexport function findChildrenByLocalName(\n parent: XmlElement | null | undefined,\n localName: string\n): XmlElement[] {\n if (!parent || !parent.elements) return [];\n\n return parent.elements.filter(\n (child) => child.type === 'element' && getLocalName(child.name || '') === localName\n );\n}\n\n/**\n * Get all child elements (excludes text nodes, etc.)\n *\n * @param parent - Parent element\n * @returns Array of child elements\n */\nexport function getChildElements(parent: XmlElement | null | undefined): XmlElement[] {\n if (!parent || !parent.elements) return [];\n return parent.elements.filter((child) => child.type === 'element');\n}\n\n/**\n * Get an attribute value from an element\n *\n * @param element - Element to get attribute from\n * @param namespace - Namespace prefix for the attribute (or null for no namespace)\n * @param name - Attribute name\n * @returns Attribute value or null if not found\n */\nexport function getAttribute(\n element: XmlElement | null | undefined,\n namespace: string | null,\n name: string\n): string | null {\n if (!element || !element.attributes) return null;\n\n const attrs = element.attributes as Record<string, string>;\n\n // Try with namespace prefix first\n if (namespace) {\n const prefixedName = `${namespace}:${name}`;\n if (prefixedName in attrs) {\n return attrs[prefixedName];\n }\n }\n\n // Try without namespace\n if (name in attrs) {\n return attrs[name];\n }\n\n return null;\n}\n\n/**\n * Get an attribute value, trying multiple possible names\n *\n * @param element - Element to get attribute from\n * @param names - Array of possible attribute names (with or without namespace)\n * @returns First found attribute value or null\n */\nexport function getAttributeAny(\n element: XmlElement | null | undefined,\n names: string[]\n): string | null {\n if (!element || !element.attributes) return null;\n\n const attrs = element.attributes as Record<string, string>;\n\n for (const name of names) {\n if (name in attrs) {\n return attrs[name];\n }\n }\n\n return null;\n}\n\n/**\n * Get all attributes from an element\n *\n * @param element - Element to get attributes from\n * @returns Record of attribute name -> value\n */\nexport function getAttributes(element: XmlElement | null | undefined): Record<string, string> {\n if (!element || !element.attributes) return {};\n return element.attributes as Record<string, string>;\n}\n\n/**\n * Get the text content of an element (concatenates all text nodes)\n *\n * @param element - Element to get text from\n * @returns Text content or empty string\n */\nexport function getTextContent(element: XmlElement | null | undefined): string {\n if (!element) return '';\n\n // Check for direct text property\n if ('text' in element && typeof element.text === 'string') {\n return element.text;\n }\n\n // Check elements array for text nodes\n if (!element.elements) return '';\n\n let text = '';\n for (const child of element.elements) {\n if (child.type === 'text' && 'text' in child) {\n text += child.text ?? '';\n } else if (child.type === 'element') {\n // Recurse into child elements\n text += getTextContent(child);\n }\n }\n\n return text;\n}\n\n/**\n * Check if an element has a specific attribute with value \"true\" or \"1\"\n *\n * @param element - Element to check\n * @param namespace - Attribute namespace\n * @param name - Attribute name\n * @returns true if attribute exists and is truthy\n */\nexport function hasFlag(\n element: XmlElement | null | undefined,\n namespace: string | null,\n name: string\n): boolean {\n const value = getAttribute(element, namespace, name);\n\n // In OOXML, presence of element often means true, absence means false\n // If value is null, check if the element itself exists\n if (value === null) {\n return false;\n }\n\n // Explicitly false\n if (value === '0' || value === 'false' || value === 'off') {\n return false;\n }\n\n // Any other value (including \"1\", \"true\", \"on\", or empty string) means true\n return true;\n}\n\n/**\n * Check if a child element exists (used for boolean flags in OOXML)\n *\n * @param parent - Parent element\n * @param namespace - Namespace prefix\n * @param localName - Local element name\n * @returns true if child element exists\n */\nexport function hasChild(\n parent: XmlElement | null | undefined,\n namespace: string,\n localName: string\n): boolean {\n return findChild(parent, namespace, localName) !== null;\n}\n\n/**\n * Parse an OOXML color value\n *\n * @param element - Color element (e.g., w:color)\n * @returns Object with val, themeColor, themeTint, themeShade\n */\nexport function parseColorElement(element: XmlElement | null | undefined): {\n val?: string;\n themeColor?: string;\n themeTint?: string;\n themeShade?: string;\n} | null {\n if (!element) return null;\n\n return {\n val: getAttribute(element, 'w', 'val') ?? undefined,\n themeColor: getAttribute(element, 'w', 'themeColor') ?? undefined,\n themeTint: getAttribute(element, 'w', 'themeTint') ?? undefined,\n themeShade: getAttribute(element, 'w', 'themeShade') ?? undefined,\n };\n}\n\n/**\n * Parse a numeric value from an attribute, with optional scale\n *\n * @param element - Element containing the attribute\n * @param namespace - Attribute namespace\n * @param name - Attribute name\n * @param scale - Optional scale factor (e.g., 20 for twips to points)\n * @returns Parsed number or undefined\n */\nexport function parseNumericAttribute(\n element: XmlElement | null | undefined,\n namespace: string | null,\n name: string,\n scale: number = 1\n): number | undefined {\n const value = getAttribute(element, namespace, name);\n if (value === null) return undefined;\n\n const num = parseInt(value, 10);\n if (isNaN(num)) return undefined;\n\n return num * scale;\n}\n\n/**\n * Parse a boolean value from an attribute or element presence\n *\n * OOXML boolean conventions:\n * - Element presence with no val attribute = true\n * - w:val=\"true\" or w:val=\"1\" = true\n * - w:val=\"false\" or w:val=\"0\" = false\n *\n * @param element - Element to check\n * @param namespace - Namespace for val attribute\n * @returns boolean value\n */\nexport function parseBooleanElement(\n element: XmlElement | null | undefined,\n namespace: string = 'w'\n): boolean {\n if (!element) return false;\n\n const val = getAttribute(element, namespace, 'val');\n\n // No val attribute = true (element presence implies true)\n if (val === null) return true;\n\n // Explicit false values\n if (val === '0' || val === 'false' || val === 'off') {\n return false;\n }\n\n return true;\n}\n\n/**\n * Deep find - search recursively for an element\n *\n * @param root - Root element to search from\n * @param namespace - Namespace prefix\n * @param localName - Local element name\n * @returns First matching element found or null\n */\nexport function findDeep(\n root: XmlElement | null | undefined,\n namespace: string,\n localName: string\n): XmlElement | null {\n if (!root) return null;\n\n // Check if this element matches\n if (matchesName(root, namespace, localName)) {\n return root;\n }\n\n // Search children\n if (root.elements) {\n for (const child of root.elements) {\n if (child.type !== 'element') continue;\n\n const found = findDeep(child, namespace, localName);\n if (found) return found;\n }\n }\n\n return null;\n}\n\n/**\n * Find all elements matching name, searching recursively\n *\n * @param root - Root element to search from\n * @param namespace - Namespace prefix\n * @param localName - Local element name\n * @returns Array of all matching elements\n */\nexport function findAllDeep(\n root: XmlElement | null | undefined,\n namespace: string,\n localName: string\n): XmlElement[] {\n const results: XmlElement[] = [];\n\n function search(element: XmlElement | null | undefined): void {\n if (!element) return;\n\n if (matchesName(element, namespace, localName)) {\n results.push(element);\n }\n\n if (element.elements) {\n for (const child of element.elements) {\n if (child.type === 'element') {\n search(child);\n }\n }\n }\n }\n\n search(root);\n return results;\n}\n","/**\n * Relationship Parser\n *\n * Parses .rels files from DOCX packages to map relationship IDs (rId)\n * to their targets (images, hyperlinks, headers, footers, etc.).\n *\n * .rels files are XML with structure:\n * <Relationships xmlns=\"...\">\n * <Relationship Id=\"rId1\" Type=\"...\" Target=\"...\" TargetMode=\"External|Internal\"/>\n * </Relationships>\n *\n * Key relationship types:\n * - image: Embedded images (word/media/*)\n * - hyperlink: External URLs (TargetMode=\"External\")\n * - header: Header XML files\n * - footer: Footer XML files\n * - footnotes: Footnotes XML\n * - endnotes: Endnotes XML\n * - styles: styles.xml\n * - numbering: numbering.xml\n * - fontTable: fontTable.xml\n * - theme: theme/theme1.xml\n */\n\nimport { parseXmlDocument, getChildElements, getAttribute } from './xmlParser';\nimport type { Relationship, RelationshipMap, RelationshipType } from '../types';\n\n/**\n * Relationship type constants for common types\n */\nexport const RELATIONSHIP_TYPES = {\n image: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',\n hyperlink: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink',\n header: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/header',\n footer: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer',\n footnotes: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes',\n endnotes: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes',\n styles: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles',\n numbering: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering',\n fontTable: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable',\n theme: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme',\n settings: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings',\n webSettings: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings',\n oleObject: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject',\n chart: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart',\n diagramData: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/diagramData',\n officeDocument:\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument',\n coreProperties:\n 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties',\n extendedProperties:\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties',\n customProperties:\n 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties',\n customXml: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml',\n} as const;\n\n/**\n * Parse a .rels XML file into a RelationshipMap\n *\n * @param relsXml - XML content of a .rels file\n * @returns Map of relationship ID to Relationship object\n */\nexport function parseRelationships(relsXml: string): RelationshipMap {\n const map: RelationshipMap = new Map();\n\n if (!relsXml || relsXml.trim().length === 0) {\n return map;\n }\n\n const root = parseXmlDocument(relsXml);\n if (!root) {\n console.warn('Failed to parse relationships XML');\n return map;\n }\n\n // Get all Relationship elements\n const children = getChildElements(root);\n\n for (const child of children) {\n // Check if this is a Relationship element\n const name = child.name || '';\n if (!name.endsWith('Relationship') && !name.includes(':Relationship')) {\n continue;\n }\n\n // Extract attributes\n const id = getAttribute(child, null, 'Id');\n const type = getAttribute(child, null, 'Type');\n const target = getAttribute(child, null, 'Target');\n const targetMode = getAttribute(child, null, 'TargetMode');\n\n if (!id || !type || !target) {\n console.warn('Relationship missing required attributes:', { id, type, target });\n continue;\n }\n\n const relationship: Relationship = {\n id,\n type: type as RelationshipType,\n target,\n };\n\n if (targetMode === 'External') {\n relationship.targetMode = 'External';\n } else if (targetMode === 'Internal') {\n relationship.targetMode = 'Internal';\n }\n // If not specified, default is Internal (we don't set it explicitly)\n\n map.set(id, relationship);\n }\n\n return map;\n}\n\n/**\n * Get the short type name from a full relationship type URI\n *\n * @param typeUri - Full relationship type URI\n * @returns Short type name (e.g., \"image\", \"hyperlink\") or \"unknown\"\n */\nexport function getRelationshipTypeName(typeUri: string): string {\n for (const [name, uri] of Object.entries(RELATIONSHIP_TYPES)) {\n if (uri === typeUri) {\n return name;\n }\n }\n\n // Try to extract from URI\n const lastSlash = typeUri.lastIndexOf('/');\n if (lastSlash >= 0) {\n return typeUri.substring(lastSlash + 1);\n }\n\n return 'unknown';\n}\n\n/**\n * Check if a relationship type is an external link (hyperlink)\n *\n * @param rel - Relationship to check\n * @returns true if this is an external hyperlink\n */\nexport function isExternalHyperlink(rel: Relationship): boolean {\n return rel.type === RELATIONSHIP_TYPES.hyperlink && rel.targetMode === 'External';\n}\n\n/**\n * Check if a relationship type is an image\n *\n * @param rel - Relationship to check\n * @returns true if this is an image relationship\n */\nexport function isImageRelationship(rel: Relationship): boolean {\n return rel.type === RELATIONSHIP_TYPES.image;\n}\n\n/**\n * Check if a relationship type is a header\n *\n * @param rel - Relationship to check\n * @returns true if this is a header relationship\n */\nexport function isHeaderRelationship(rel: Relationship): boolean {\n return rel.type === RELATIONSHIP_TYPES.header;\n}\n\n/**\n * Check if a relationship type is a footer\n *\n * @param rel - Relationship to check\n * @returns true if this is a footer relationship\n */\nexport function isFooterRelationship(rel: Relationship): boolean {\n return rel.type === RELATIONSHIP_TYPES.footer;\n}\n\n/**\n * Filter relationships by type\n *\n * @param map - RelationshipMap to filter\n * @param type - Relationship type URI to filter by\n * @returns Array of matching relationships\n */\nexport function filterByType(map: RelationshipMap, type: RelationshipType): Relationship[] {\n const results: Relationship[] = [];\n for (const rel of map.values()) {\n if (rel.type === type) {\n results.push(rel);\n }\n }\n return results;\n}\n\n/**\n * Get all images from a relationship map\n *\n * @param map - RelationshipMap to search\n * @returns Array of image relationships\n */\nexport function getImages(map: RelationshipMap): Relationship[] {\n return filterByType(map, RELATIONSHIP_TYPES.image);\n}\n\n/**\n * Get all hyperlinks from a relationship map\n *\n * @param map - RelationshipMap to search\n * @returns Array of hyperlink relationships\n */\nexport function getHyperlinks(map: RelationshipMap): Relationship[] {\n return filterByType(map, RELATIONSHIP_TYPES.hyperlink);\n}\n\n/**\n * Get all headers from a relationship map\n *\n * @param map - RelationshipMap to search\n * @returns Array of header relationships\n */\nexport function getHeaders(map: RelationshipMap): Relationship[] {\n return filterByType(map, RELATIONSHIP_TYPES.header);\n}\n\n/**\n * Get all footers from a relationship map\n *\n * @param map - RelationshipMap to search\n * @returns Array of footer relationships\n */\nexport function getFooters(map: RelationshipMap): Relationship[] {\n return filterByType(map, RELATIONSHIP_TYPES.footer);\n}\n\n/**\n * Resolve a relationship ID to a target path\n *\n * @param map - RelationshipMap to search\n * @param rId - Relationship ID (e.g., \"rId1\")\n * @returns Target path or undefined if not found\n */\nexport function resolveTarget(map: RelationshipMap, rId: string): string | undefined {\n const rel = map.get(rId);\n return rel?.target;\n}\n\n/**\n * Resolve a relationship ID to a full relationship\n *\n * @param map - RelationshipMap to search\n * @param rId - Relationship ID (e.g., \"rId1\")\n * @returns Relationship or undefined if not found\n */\nexport function resolveRelationship(map: RelationshipMap, rId: string): Relationship | undefined {\n return map.get(rId);\n}\n\n/**\n * Resolve a relative target path to an absolute path within the DOCX\n *\n * For example, if basePath is \"word/_rels/document.xml.rels\" and\n * target is \"media/image1.png\", the result is \"word/media/image1.png\"\n *\n * @param basePath - Path of the .rels file\n * @param target - Relative target from the relationship\n * @returns Absolute path within the DOCX\n */\nexport function resolveRelativePath(basePath: string, target: string): string {\n // If target starts with /, it's already absolute\n if (target.startsWith('/')) {\n return target.substring(1); // Remove leading /\n }\n\n // Get the directory of the .rels file\n // e.g., \"word/_rels/document.xml.rels\" -> \"word/_rels\"\n const lastSlash = basePath.lastIndexOf('/');\n let directory = lastSlash >= 0 ? basePath.substring(0, lastSlash) : '';\n\n // The .rels file is in _rels subdirectory, go up one level\n // e.g., \"word/_rels\" -> \"word\"\n if (directory.endsWith('/_rels')) {\n directory = directory.substring(0, directory.length - 6);\n } else if (directory === '_rels') {\n directory = '';\n }\n\n // Handle ../ in target\n const parts = target.split('/');\n const dirParts = directory ? directory.split('/') : [];\n\n for (const part of parts) {\n if (part === '..') {\n dirParts.pop();\n } else if (part !== '.') {\n dirParts.push(part);\n }\n }\n\n return dirParts.join('/');\n}\n\n/**\n * Parse document.xml.rels specifically\n *\n * This is a convenience wrapper for the main document relationships.\n *\n * @param relsXml - XML content of word/_rels/document.xml.rels\n * @returns RelationshipMap\n */\nexport function parseDocumentRelationships(relsXml: string): RelationshipMap {\n return parseRelationships(relsXml);\n}\n\n/**\n * Parse package-level .rels\n *\n * This is a convenience wrapper for the package relationships (_rels/.rels)\n *\n * @param relsXml - XML content of _rels/.rels\n * @returns RelationshipMap\n */\nexport function parsePackageRelationships(relsXml: string): RelationshipMap {\n return parseRelationships(relsXml);\n}\n\n/**\n * Debug: Print all relationships in a map\n *\n * @param map - RelationshipMap to print\n */\nexport function printRelationships(map: RelationshipMap): void {\n /* eslint-disable no-console */\n console.log('Relationships:');\n for (const [id, rel] of map.entries()) {\n const typeName = getRelationshipTypeName(rel.type);\n console.log(\n ` ${id}: ${typeName} -> ${rel.target}${rel.targetMode === 'External' ? ' (External)' : ''}`\n );\n }\n /* eslint-enable no-console */\n}\n","/**\n * Theme Parser - Parse theme1.xml for colors and fonts\n *\n * Extracts color scheme (dk1, lt1, dk2, lt2, accent1-6, hlink, folHlink)\n * and font scheme (majorFont, minorFont) from the theme.\n *\n * OOXML Reference:\n * - Theme file is at: word/theme/theme1.xml\n * - Uses DrawingML namespace (a:)\n * - Colors can be srgbClr, sysClr, or schemeClr\n */\n\nimport type { Theme, ThemeColorScheme, ThemeFontScheme, ThemeFont } from '../types/document';\nimport {\n parseXmlDocument,\n findChild,\n findChildren,\n getAttribute,\n getChildElements,\n getLocalName,\n type XmlElement,\n} from './xmlParser';\n\n/**\n * Default theme colors (Office 2016 default theme)\n * Used when theme1.xml is missing or malformed\n */\nconst DEFAULT_COLORS: ThemeColorScheme = {\n dk1: '000000', // Black\n lt1: 'FFFFFF', // White\n dk2: '44546A', // Dark blue-gray\n lt2: 'E7E6E6', // Light gray\n accent1: '4472C4', // Blue\n accent2: 'ED7D31', // Orange\n accent3: 'A5A5A5', // Gray\n accent4: 'FFC000', // Gold\n accent5: '5B9BD5', // Light blue\n accent6: '70AD47', // Green\n hlink: '0563C1', // Hyperlink blue\n folHlink: '954F72', // Followed hyperlink purple\n};\n\n/**\n * Default font scheme\n */\nconst DEFAULT_FONTS: ThemeFontScheme = {\n majorFont: {\n latin: 'Calibri Light',\n ea: '',\n cs: '',\n fonts: {},\n },\n minorFont: {\n latin: 'Calibri',\n ea: '',\n cs: '',\n fonts: {},\n },\n};\n\n/**\n * Default theme when no theme1.xml exists\n */\nconst DEFAULT_THEME: Theme = {\n name: 'Office Theme',\n colorScheme: DEFAULT_COLORS,\n fontScheme: DEFAULT_FONTS,\n};\n\n/**\n * Color slot names in theme\n */\nconst COLOR_SLOTS = [\n 'dk1',\n 'lt1',\n 'dk2',\n 'lt2',\n 'accent1',\n 'accent2',\n 'accent3',\n 'accent4',\n 'accent5',\n 'accent6',\n 'hlink',\n 'folHlink',\n] as const;\n\n/**\n * Parse a color element (srgbClr, sysClr, or schemeClr)\n *\n * @param element - Color child element\n * @returns Hex color value (6 characters, no #)\n */\nfunction parseColorElement(element: XmlElement | null): string | null {\n if (!element) return null;\n\n const localName = getLocalName(element.name || '');\n\n switch (localName) {\n case 'srgbClr': {\n // Direct RGB color: <a:srgbClr val=\"4472C4\"/>\n const val = getAttribute(element, 'a', 'val') ?? getAttribute(element, null, 'val');\n return val ?? null;\n }\n\n case 'sysClr': {\n // System color with fallback: <a:sysClr val=\"windowText\" lastClr=\"000000\"/>\n // Use lastClr as the fallback since we can't access actual system colors\n const lastClr =\n getAttribute(element, 'a', 'lastClr') ?? getAttribute(element, null, 'lastClr');\n if (lastClr) return lastClr;\n\n // Fallback based on common system color names\n const val = getAttribute(element, 'a', 'val') ?? getAttribute(element, null, 'val');\n switch (val) {\n case 'windowText':\n case 'menuText':\n case 'captionText':\n case 'btnText':\n return '000000';\n case 'window':\n case 'menu':\n case 'btnFace':\n case 'btnHighlight':\n return 'FFFFFF';\n case 'highlight':\n return '0078D7';\n case 'highlightText':\n return 'FFFFFF';\n case 'grayText':\n return '808080';\n default:\n return null;\n }\n }\n\n case 'schemeClr': {\n // Reference to another scheme color - rare in color scheme itself\n // Usually found in fill/line definitions with modifiers\n // For the color scheme, we just need the val\n const val = getAttribute(element, 'a', 'val') ?? getAttribute(element, null, 'val');\n // This is a reference, not a final color - return null for now\n // The actual resolution would need the full color scheme\n return val === 'phClr' ? null : null;\n }\n\n default:\n return null;\n }\n}\n\n/**\n * Parse the color scheme from a:clrScheme element\n *\n * @param clrScheme - The a:clrScheme element\n * @returns ThemeColorScheme with resolved hex colors\n */\nfunction parseColorScheme(clrScheme: XmlElement | null): ThemeColorScheme {\n const result: ThemeColorScheme = { ...DEFAULT_COLORS };\n\n if (!clrScheme) return result;\n\n // Each color slot has a child element with the slot name\n for (const slot of COLOR_SLOTS) {\n // Find the slot element (e.g., a:dk1, a:accent1)\n const slotElement = findChild(clrScheme, 'a', slot);\n\n if (slotElement) {\n // The actual color is a child (srgbClr, sysClr, or schemeClr)\n const children = getChildElements(slotElement);\n if (children.length > 0) {\n const color = parseColorElement(children[0]);\n if (color) {\n result[slot] = color;\n }\n }\n }\n }\n\n return result;\n}\n\n/**\n * Parse a font definition (majorFont or minorFont)\n *\n * @param fontElement - The a:majorFont or a:minorFont element\n * @returns ThemeFont with font family names\n */\nfunction parseThemeFonts(fontElement: XmlElement | null): ThemeFont {\n const result: ThemeFont = {\n latin: '',\n ea: '',\n cs: '',\n fonts: {},\n };\n\n if (!fontElement) return result;\n\n // Parse main font elements\n const latinEl = findChild(fontElement, 'a', 'latin');\n if (latinEl) {\n result.latin =\n getAttribute(latinEl, 'a', 'typeface') ?? getAttribute(latinEl, null, 'typeface') ?? '';\n }\n\n const eaEl = findChild(fontElement, 'a', 'ea');\n if (eaEl) {\n result.ea = getAttribute(eaEl, 'a', 'typeface') ?? getAttribute(eaEl, null, 'typeface') ?? '';\n }\n\n const csEl = findChild(fontElement, 'a', 'cs');\n if (csEl) {\n result.cs = getAttribute(csEl, 'a', 'typeface') ?? getAttribute(csEl, null, 'typeface') ?? '';\n }\n\n // Parse script-specific fonts (a:font elements with script attribute)\n const fontElements = findChildren(fontElement, 'a', 'font');\n for (const font of fontElements) {\n const script = getAttribute(font, 'a', 'script') ?? getAttribute(font, null, 'script');\n const typeface = getAttribute(font, 'a', 'typeface') ?? getAttribute(font, null, 'typeface');\n\n if (script && typeface) {\n result.fonts = result.fonts || {};\n result.fonts[script] = typeface;\n }\n }\n\n return result;\n}\n\n/**\n * Parse the font scheme from a:fontScheme element\n *\n * @param fontScheme - The a:fontScheme element\n * @returns ThemeFontScheme with major and minor fonts\n */\nfunction parseFontScheme(fontScheme: XmlElement | null): ThemeFontScheme {\n const result: ThemeFontScheme = { ...DEFAULT_FONTS };\n\n if (!fontScheme) return result;\n\n const majorFontEl = findChild(fontScheme, 'a', 'majorFont');\n if (majorFontEl) {\n result.majorFont = parseThemeFonts(majorFontEl);\n }\n\n const minorFontEl = findChild(fontScheme, 'a', 'minorFont');\n if (minorFontEl) {\n result.minorFont = parseThemeFonts(minorFontEl);\n }\n\n return result;\n}\n\n/**\n * Parse theme1.xml content\n *\n * @param themeXml - XML content of theme1.xml, or null if not present\n * @returns Parsed Theme object with colors and fonts\n */\nexport function parseTheme(themeXml: string | null): Theme {\n // Return defaults if no theme XML\n if (!themeXml) {\n return { ...DEFAULT_THEME };\n }\n\n try {\n const doc = parseXmlDocument(themeXml);\n if (!doc) {\n return { ...DEFAULT_THEME };\n }\n\n // Get theme name from root element\n const themeName =\n getAttribute(doc, 'a', 'name') ?? getAttribute(doc, null, 'name') ?? 'Office Theme';\n\n // Find a:themeElements which contains clrScheme and fontScheme\n const themeElements = findChild(doc, 'a', 'themeElements');\n\n // Parse color scheme\n const clrScheme = findChild(themeElements, 'a', 'clrScheme');\n const colorScheme = parseColorScheme(clrScheme);\n\n // Parse font scheme\n const fontSchemeEl = findChild(themeElements, 'a', 'fontScheme');\n const fontScheme = parseFontScheme(fontSchemeEl);\n\n return {\n name: themeName,\n colorScheme,\n fontScheme,\n };\n } catch (error) {\n console.warn('Failed to parse theme:', error);\n return { ...DEFAULT_THEME };\n }\n}\n\n/**\n * Get a color from the theme by slot name\n *\n * @param theme - Parsed theme\n * @param slot - Color slot name (dk1, lt1, accent1, etc.)\n * @returns Hex color value (6 characters, no #)\n */\nexport function getThemeColor(\n theme: Theme | null | undefined,\n slot: keyof ThemeColorScheme\n): string {\n if (!theme?.colorScheme) {\n return DEFAULT_COLORS[slot] ?? '000000';\n }\n\n return theme.colorScheme[slot] ?? DEFAULT_COLORS[slot] ?? '000000';\n}\n\n/**\n * Get the major font (heading font) from theme\n *\n * @param theme - Parsed theme\n * @param script - Optional script code (defaults to latin)\n * @returns Font family name\n */\nexport function getMajorFont(theme: Theme | null | undefined, script: string = 'latin'): string {\n if (!theme?.fontScheme?.majorFont) {\n return DEFAULT_FONTS.majorFont?.latin ?? 'Calibri Light';\n }\n\n const majorFont = theme.fontScheme.majorFont;\n\n if (script === 'latin') return majorFont.latin || 'Calibri Light';\n if (script === 'ea') return majorFont.ea || '';\n if (script === 'cs') return majorFont.cs || '';\n\n // Check script-specific fonts\n if (majorFont.fonts?.[script]) {\n return majorFont.fonts[script];\n }\n\n // Default to latin\n return majorFont.latin || 'Calibri Light';\n}\n\n/**\n * Get the minor font (body font) from theme\n *\n * @param theme - Parsed theme\n * @param script - Optional script code (defaults to latin)\n * @returns Font family name\n */\nexport function getMinorFont(theme: Theme | null | undefined, script: string = 'latin'): string {\n if (!theme?.fontScheme?.minorFont) {\n return DEFAULT_FONTS.minorFont?.latin ?? 'Calibri';\n }\n\n const minorFont = theme.fontScheme.minorFont;\n\n if (script === 'latin') return minorFont.latin || 'Calibri';\n if (script === 'ea') return minorFont.ea || '';\n if (script === 'cs') return minorFont.cs || '';\n\n // Check script-specific fonts\n if (minorFont.fonts?.[script]) {\n return minorFont.fonts[script];\n }\n\n // Default to latin\n return minorFont.latin || 'Calibri';\n}\n\n/**\n * Resolve a theme font reference to an actual font name\n *\n * Theme font references are like: majorAscii, majorHAnsi, minorAscii, minorHAnsi, etc.\n *\n * @param theme - Parsed theme\n * @param themeRef - Theme font reference\n * @returns Font family name\n */\nexport function resolveThemeFontRef(theme: Theme | null | undefined, themeRef: string): string {\n if (!themeRef) return 'Calibri';\n\n // Parse the reference: major/minor + script type\n const isMajor = themeRef.toLowerCase().includes('major');\n const isMinor = themeRef.toLowerCase().includes('minor');\n\n // Determine script from reference\n let script = 'latin';\n const lowerRef = themeRef.toLowerCase();\n\n if (lowerRef.includes('eastasia')) {\n script = 'ea';\n } else if (lowerRef.includes('bidi') || lowerRef.includes('cs')) {\n script = 'cs';\n }\n // ascii and hAnsi both map to latin\n\n if (isMajor) {\n return getMajorFont(theme, script);\n } else if (isMinor) {\n return getMinorFont(theme, script);\n }\n\n // Default to minor latin\n return getMinorFont(theme, 'latin');\n}\n\n/**\n * Get all font families from the theme for preloading\n *\n * @param theme - Parsed theme\n * @returns Array of unique font family names\n */\nexport function getThemeFonts(theme: Theme | null | undefined): string[] {\n const fonts = new Set<string>();\n\n if (theme?.fontScheme) {\n const { majorFont, minorFont } = theme.fontScheme;\n\n // Add main fonts\n if (majorFont?.latin) fonts.add(majorFont.latin);\n if (majorFont?.ea) fonts.add(majorFont.ea);\n if (majorFont?.cs) fonts.add(majorFont.cs);\n\n if (minorFont?.latin) fonts.add(minorFont.latin);\n if (minorFont?.ea) fonts.add(minorFont.ea);\n if (minorFont?.cs) fonts.add(minorFont.cs);\n\n // Add script-specific fonts\n if (majorFont?.fonts) {\n for (const font of Object.values(majorFont.fonts)) {\n if (font) fonts.add(font);\n }\n }\n\n if (minorFont?.fonts) {\n for (const font of Object.values(minorFont.fonts)) {\n if (font) fonts.add(font);\n }\n }\n }\n\n // Remove empty strings\n fonts.delete('');\n\n return Array.from(fonts);\n}\n\n/**\n * Get the default theme (Office 2016 theme)\n *\n * @returns Default Theme object\n */\nexport function getDefaultTheme(): Theme {\n return { ...DEFAULT_THEME };\n}\n","/**\n * Style Parser - Parse styles.xml with full inheritance resolution\n *\n * Parses all style types (paragraph, character, table, list) with\n * complete basedOn inheritance chain resolution.\n *\n * OOXML Reference:\n * - Style file is at: word/styles.xml\n * - Uses WordprocessingML namespace (w:)\n *\n * Style Cascade (lowest to highest priority):\n * 1. Document defaults (w:docDefaults)\n * 2. Parent style properties (w:basedOn chain)\n * 3. Current style properties\n * 4. Direct formatting in document\n */\n\nimport type {\n Theme,\n Style,\n StyleType,\n StyleDefinitions,\n DocDefaults,\n TextFormatting,\n ParagraphFormatting,\n TableFormatting,\n TableRowFormatting,\n TableCellFormatting,\n ColorValue,\n BorderSpec,\n ShadingProperties,\n TabStop,\n TabStopAlignment,\n TabLeader,\n UnderlineStyle,\n TableBorders,\n CellMargins,\n TableLook,\n TableMeasurement,\n} from '../types/document';\nimport {\n parseXmlDocument,\n findChild,\n findChildren,\n getAttribute,\n parseBooleanElement,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\nimport { resolveThemeFontRef } from './themeParser';\n\n/**\n * Style map keyed by styleId\n */\nexport type StyleMap = Map<string, Style>;\n\n/**\n * Parse text formatting properties (w:rPr)\n */\nfunction parseRunProperties(\n rPr: XmlElement | null,\n theme: Theme | null\n): TextFormatting | undefined {\n if (!rPr) return undefined;\n\n const formatting: TextFormatting = {};\n\n // Bold\n const b = findChild(rPr, 'w', 'b');\n if (b) formatting.bold = parseBooleanElement(b);\n\n const bCs = findChild(rPr, 'w', 'bCs');\n if (bCs) formatting.boldCs = parseBooleanElement(bCs);\n\n // Italic\n const i = findChild(rPr, 'w', 'i');\n if (i) formatting.italic = parseBooleanElement(i);\n\n const iCs = findChild(rPr, 'w', 'iCs');\n if (iCs) formatting.italicCs = parseBooleanElement(iCs);\n\n // Underline\n const u = findChild(rPr, 'w', 'u');\n if (u) {\n const style = getAttribute(u, 'w', 'val') as UnderlineStyle | null;\n if (style) {\n formatting.underline = { style };\n const colorVal = getAttribute(u, 'w', 'color');\n const themeColor = getAttribute(u, 'w', 'themeColor');\n if (colorVal || themeColor) {\n formatting.underline.color = parseColorValue(\n colorVal,\n themeColor,\n getAttribute(u, 'w', 'themeTint'),\n getAttribute(u, 'w', 'themeShade')\n );\n }\n }\n }\n\n // Strikethrough\n const strike = findChild(rPr, 'w', 'strike');\n if (strike) formatting.strike = parseBooleanElement(strike);\n\n const dstrike = findChild(rPr, 'w', 'dstrike');\n if (dstrike) formatting.doubleStrike = parseBooleanElement(dstrike);\n\n // Vertical alignment (superscript/subscript)\n const vertAlign = findChild(rPr, 'w', 'vertAlign');\n if (vertAlign) {\n const val = getAttribute(vertAlign, 'w', 'val');\n if (val === 'superscript' || val === 'subscript' || val === 'baseline') {\n formatting.vertAlign = val;\n }\n }\n\n // Capitalization\n const smallCaps = findChild(rPr, 'w', 'smallCaps');\n if (smallCaps) formatting.smallCaps = parseBooleanElement(smallCaps);\n\n const caps = findChild(rPr, 'w', 'caps');\n if (caps) formatting.allCaps = parseBooleanElement(caps);\n\n // Hidden\n const vanish = findChild(rPr, 'w', 'vanish');\n if (vanish) formatting.hidden = parseBooleanElement(vanish);\n\n // Color\n const color = findChild(rPr, 'w', 'color');\n if (color) {\n formatting.color = parseColorValue(\n getAttribute(color, 'w', 'val'),\n getAttribute(color, 'w', 'themeColor'),\n getAttribute(color, 'w', 'themeTint'),\n getAttribute(color, 'w', 'themeShade')\n );\n }\n\n // Highlight\n const highlight = findChild(rPr, 'w', 'highlight');\n if (highlight) {\n const val = getAttribute(highlight, 'w', 'val');\n if (val) {\n formatting.highlight = val as TextFormatting['highlight'];\n }\n }\n\n // Character shading\n const shd = findChild(rPr, 'w', 'shd');\n if (shd) {\n formatting.shading = parseShadingProperties(shd);\n }\n\n // Font size (in half-points)\n const sz = findChild(rPr, 'w', 'sz');\n if (sz) {\n const val = parseNumericAttribute(sz, 'w', 'val');\n if (val !== undefined) formatting.fontSize = val;\n }\n\n const szCs = findChild(rPr, 'w', 'szCs');\n if (szCs) {\n const val = parseNumericAttribute(szCs, 'w', 'val');\n if (val !== undefined) formatting.fontSizeCs = val;\n }\n\n // Font family\n const rFonts = findChild(rPr, 'w', 'rFonts');\n if (rFonts) {\n formatting.fontFamily = {\n ascii: getAttribute(rFonts, 'w', 'ascii') ?? undefined,\n hAnsi: getAttribute(rFonts, 'w', 'hAnsi') ?? undefined,\n eastAsia: getAttribute(rFonts, 'w', 'eastAsia') ?? undefined,\n cs: getAttribute(rFonts, 'w', 'cs') ?? undefined,\n };\n\n // Theme font references - resolve to actual font names\n const asciiTheme = getAttribute(rFonts, 'w', 'asciiTheme');\n if (asciiTheme) {\n formatting.fontFamily.asciiTheme = asciiTheme as TextFormatting['fontFamily'] extends {\n asciiTheme?: infer T;\n }\n ? T\n : never;\n // Also resolve the actual font name for convenience\n if (theme && !formatting.fontFamily.ascii) {\n formatting.fontFamily.ascii = resolveThemeFontRef(theme, asciiTheme);\n }\n }\n const hAnsiTheme = getAttribute(rFonts, 'w', 'hAnsiTheme');\n if (hAnsiTheme) {\n formatting.fontFamily.hAnsiTheme = hAnsiTheme;\n if (theme && !formatting.fontFamily.hAnsi) {\n formatting.fontFamily.hAnsi = resolveThemeFontRef(theme, hAnsiTheme);\n }\n }\n const eastAsiaTheme = getAttribute(rFonts, 'w', 'eastAsiaTheme');\n if (eastAsiaTheme) {\n formatting.fontFamily.eastAsiaTheme = eastAsiaTheme;\n if (theme && !formatting.fontFamily.eastAsia) {\n formatting.fontFamily.eastAsia = resolveThemeFontRef(theme, eastAsiaTheme);\n }\n }\n const csTheme = getAttribute(rFonts, 'w', 'cstheme');\n if (csTheme) {\n formatting.fontFamily.csTheme = csTheme;\n if (theme && !formatting.fontFamily.cs) {\n formatting.fontFamily.cs = resolveThemeFontRef(theme, csTheme);\n }\n }\n }\n\n // Character spacing (in twips)\n const spacing = findChild(rPr, 'w', 'spacing');\n if (spacing) {\n const val = parseNumericAttribute(spacing, 'w', 'val');\n if (val !== undefined) formatting.spacing = val;\n }\n\n // Position (raised/lowered in half-points)\n const position = findChild(rPr, 'w', 'position');\n if (position) {\n const val = parseNumericAttribute(position, 'w', 'val');\n if (val !== undefined) formatting.position = val;\n }\n\n // Scale (horizontal text scale percentage)\n const w = findChild(rPr, 'w', 'w');\n if (w) {\n const val = parseNumericAttribute(w, 'w', 'val');\n if (val !== undefined) formatting.scale = val;\n }\n\n // Kerning\n const kern = findChild(rPr, 'w', 'kern');\n if (kern) {\n const val = parseNumericAttribute(kern, 'w', 'val');\n if (val !== undefined) formatting.kerning = val;\n }\n\n // Text effects\n const effect = findChild(rPr, 'w', 'effect');\n if (effect) {\n const val = getAttribute(effect, 'w', 'val');\n if (val) formatting.effect = val as TextFormatting['effect'];\n }\n\n // Emphasis mark\n const em = findChild(rPr, 'w', 'em');\n if (em) {\n const val = getAttribute(em, 'w', 'val');\n if (val) formatting.emphasisMark = val as TextFormatting['emphasisMark'];\n }\n\n // Other effects\n const emboss = findChild(rPr, 'w', 'emboss');\n if (emboss) formatting.emboss = parseBooleanElement(emboss);\n\n const imprint = findChild(rPr, 'w', 'imprint');\n if (imprint) formatting.imprint = parseBooleanElement(imprint);\n\n const outline = findChild(rPr, 'w', 'outline');\n if (outline) formatting.outline = parseBooleanElement(outline);\n\n const shadow = findChild(rPr, 'w', 'shadow');\n if (shadow) formatting.shadow = parseBooleanElement(shadow);\n\n // RTL and complex script\n const rtl = findChild(rPr, 'w', 'rtl');\n if (rtl) formatting.rtl = parseBooleanElement(rtl);\n\n const cs = findChild(rPr, 'w', 'cs');\n if (cs) formatting.cs = parseBooleanElement(cs);\n\n // Character style reference\n const rStyle = findChild(rPr, 'w', 'rStyle');\n if (rStyle) {\n const val = getAttribute(rStyle, 'w', 'val');\n if (val) formatting.styleId = val;\n }\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n/**\n * Parse color value from attributes\n */\nfunction parseColorValue(\n rgb: string | null,\n themeColor: string | null,\n themeTint: string | null,\n themeShade: string | null\n): ColorValue {\n const color: ColorValue = {};\n\n if (rgb && rgb !== 'auto') {\n color.rgb = rgb;\n } else if (rgb === 'auto') {\n color.auto = true;\n }\n\n if (themeColor) {\n color.themeColor = themeColor as ColorValue['themeColor'];\n }\n\n if (themeTint) {\n color.themeTint = themeTint;\n }\n\n if (themeShade) {\n color.themeShade = themeShade;\n }\n\n return color;\n}\n\n/**\n * Parse shading properties (w:shd)\n */\nfunction parseShadingProperties(shd: XmlElement | null): ShadingProperties | undefined {\n if (!shd) return undefined;\n\n const props: ShadingProperties = {};\n\n const color = getAttribute(shd, 'w', 'color');\n if (color && color !== 'auto') {\n props.color = { rgb: color };\n }\n\n const fill = getAttribute(shd, 'w', 'fill');\n if (fill && fill !== 'auto') {\n props.fill = { rgb: fill };\n }\n\n const themeFill = getAttribute(shd, 'w', 'themeFill');\n if (themeFill) {\n props.fill = props.fill || {};\n props.fill.themeColor = themeFill as ColorValue['themeColor'];\n }\n\n const themeFillTint = getAttribute(shd, 'w', 'themeFillTint');\n if (themeFillTint && props.fill) {\n props.fill.themeTint = themeFillTint;\n }\n\n const themeFillShade = getAttribute(shd, 'w', 'themeFillShade');\n if (themeFillShade && props.fill) {\n props.fill.themeShade = themeFillShade;\n }\n\n const pattern = getAttribute(shd, 'w', 'val');\n if (pattern) {\n props.pattern = pattern as ShadingProperties['pattern'];\n }\n\n return Object.keys(props).length > 0 ? props : undefined;\n}\n\n/**\n * Parse border specification\n */\nfunction parseBorderSpec(border: XmlElement | null): BorderSpec | undefined {\n if (!border) return undefined;\n\n const style = getAttribute(border, 'w', 'val');\n if (!style) return undefined;\n\n const spec: BorderSpec = {\n style: style as BorderSpec['style'],\n };\n\n const colorVal = getAttribute(border, 'w', 'color');\n const themeColor = getAttribute(border, 'w', 'themeColor');\n if (colorVal || themeColor) {\n spec.color = parseColorValue(\n colorVal,\n themeColor,\n getAttribute(border, 'w', 'themeTint'),\n getAttribute(border, 'w', 'themeShade')\n );\n }\n\n const sz = parseNumericAttribute(border, 'w', 'sz');\n if (sz !== undefined) spec.size = sz;\n\n const space = parseNumericAttribute(border, 'w', 'space');\n if (space !== undefined) spec.space = space;\n\n const shadowAttr = getAttribute(border, 'w', 'shadow');\n if (shadowAttr) spec.shadow = shadowAttr === '1' || shadowAttr === 'true';\n\n const frame = getAttribute(border, 'w', 'frame');\n if (frame) spec.frame = frame === '1' || frame === 'true';\n\n return spec;\n}\n\n/**\n * Parse tab stops (w:tabs)\n */\nfunction parseTabStops(tabs: XmlElement | null): TabStop[] | undefined {\n if (!tabs) return undefined;\n\n const tabElements = findChildren(tabs, 'w', 'tab');\n if (tabElements.length === 0) return undefined;\n\n const result: TabStop[] = [];\n\n for (const tab of tabElements) {\n const pos = parseNumericAttribute(tab, 'w', 'pos');\n const val = getAttribute(tab, 'w', 'val');\n\n if (pos !== undefined && val) {\n const tabStop: TabStop = {\n position: pos,\n alignment: val as TabStopAlignment,\n };\n\n const leader = getAttribute(tab, 'w', 'leader');\n if (leader) {\n tabStop.leader = leader as TabLeader;\n }\n\n result.push(tabStop);\n }\n }\n\n return result.length > 0 ? result : undefined;\n}\n\n/**\n * Parse paragraph formatting properties (w:pPr)\n */\nfunction parseParagraphProperties(\n pPr: XmlElement | null,\n theme: Theme | null\n): ParagraphFormatting | undefined {\n if (!pPr) return undefined;\n\n const formatting: ParagraphFormatting = {};\n\n // Alignment\n const jc = findChild(pPr, 'w', 'jc');\n if (jc) {\n const val = getAttribute(jc, 'w', 'val');\n if (val) formatting.alignment = val as ParagraphFormatting['alignment'];\n }\n\n // Bidi\n const bidi = findChild(pPr, 'w', 'bidi');\n if (bidi) formatting.bidi = parseBooleanElement(bidi);\n\n // Spacing\n const spacing = findChild(pPr, 'w', 'spacing');\n if (spacing) {\n const before = parseNumericAttribute(spacing, 'w', 'before');\n if (before !== undefined) formatting.spaceBefore = before;\n\n const after = parseNumericAttribute(spacing, 'w', 'after');\n if (after !== undefined) formatting.spaceAfter = after;\n\n const line = parseNumericAttribute(spacing, 'w', 'line');\n if (line !== undefined) formatting.lineSpacing = line;\n\n const lineRule = getAttribute(spacing, 'w', 'lineRule');\n if (lineRule) formatting.lineSpacingRule = lineRule as ParagraphFormatting['lineSpacingRule'];\n\n const beforeAuto = getAttribute(spacing, 'w', 'beforeAutospacing');\n if (beforeAuto) formatting.beforeAutospacing = beforeAuto === '1' || beforeAuto === 'true';\n\n const afterAuto = getAttribute(spacing, 'w', 'afterAutospacing');\n if (afterAuto) formatting.afterAutospacing = afterAuto === '1' || afterAuto === 'true';\n }\n\n // Indentation\n const ind = findChild(pPr, 'w', 'ind');\n if (ind) {\n const left = parseNumericAttribute(ind, 'w', 'left');\n if (left !== undefined) formatting.indentLeft = left;\n\n const right = parseNumericAttribute(ind, 'w', 'right');\n if (right !== undefined) formatting.indentRight = right;\n\n const firstLine = parseNumericAttribute(ind, 'w', 'firstLine');\n if (firstLine !== undefined) formatting.indentFirstLine = firstLine;\n\n const hanging = parseNumericAttribute(ind, 'w', 'hanging');\n if (hanging !== undefined) {\n formatting.indentFirstLine = -hanging;\n formatting.hangingIndent = true;\n }\n }\n\n // Borders\n const pBdr = findChild(pPr, 'w', 'pBdr');\n if (pBdr) {\n const borders: ParagraphFormatting['borders'] = {};\n const top = parseBorderSpec(findChild(pBdr, 'w', 'top'));\n if (top) borders.top = top;\n const bottom = parseBorderSpec(findChild(pBdr, 'w', 'bottom'));\n if (bottom) borders.bottom = bottom;\n const left = parseBorderSpec(findChild(pBdr, 'w', 'left'));\n if (left) borders.left = left;\n const right = parseBorderSpec(findChild(pBdr, 'w', 'right'));\n if (right) borders.right = right;\n const between = parseBorderSpec(findChild(pBdr, 'w', 'between'));\n if (between) borders.between = between;\n const bar = parseBorderSpec(findChild(pBdr, 'w', 'bar'));\n if (bar) borders.bar = bar;\n\n if (Object.keys(borders).length > 0) {\n formatting.borders = borders;\n }\n }\n\n // Shading\n const shd = findChild(pPr, 'w', 'shd');\n if (shd) {\n formatting.shading = parseShadingProperties(shd);\n }\n\n // Tab stops\n const tabs = findChild(pPr, 'w', 'tabs');\n if (tabs) {\n formatting.tabs = parseTabStops(tabs);\n }\n\n // Page break control\n const keepNext = findChild(pPr, 'w', 'keepNext');\n if (keepNext) formatting.keepNext = parseBooleanElement(keepNext);\n\n const keepLines = findChild(pPr, 'w', 'keepLines');\n if (keepLines) formatting.keepLines = parseBooleanElement(keepLines);\n\n const widowControl = findChild(pPr, 'w', 'widowControl');\n if (widowControl) formatting.widowControl = parseBooleanElement(widowControl);\n\n const pageBreakBefore = findChild(pPr, 'w', 'pageBreakBefore');\n if (pageBreakBefore) formatting.pageBreakBefore = parseBooleanElement(pageBreakBefore);\n\n // Numbering properties\n const numPr = findChild(pPr, 'w', 'numPr');\n if (numPr) {\n const numId = findChild(numPr, 'w', 'numId');\n const ilvl = findChild(numPr, 'w', 'ilvl');\n\n if (numId || ilvl) {\n formatting.numPr = {};\n if (numId) {\n const val = parseNumericAttribute(numId, 'w', 'val');\n if (val !== undefined) formatting.numPr.numId = val;\n }\n if (ilvl) {\n const val = parseNumericAttribute(ilvl, 'w', 'val');\n if (val !== undefined) formatting.numPr.ilvl = val;\n }\n }\n }\n\n // Outline level\n const outlineLvl = findChild(pPr, 'w', 'outlineLvl');\n if (outlineLvl) {\n const val = parseNumericAttribute(outlineLvl, 'w', 'val');\n if (val !== undefined) formatting.outlineLevel = val;\n }\n\n // Style reference\n const pStyle = findChild(pPr, 'w', 'pStyle');\n if (pStyle) {\n const val = getAttribute(pStyle, 'w', 'val');\n if (val) formatting.styleId = val;\n }\n\n // Suppress line numbers\n const suppressLineNumbers = findChild(pPr, 'w', 'suppressLineNumbers');\n if (suppressLineNumbers)\n formatting.suppressLineNumbers = parseBooleanElement(suppressLineNumbers);\n\n // Suppress auto hyphens\n const suppressAutoHyphens = findChild(pPr, 'w', 'suppressAutoHyphens');\n if (suppressAutoHyphens)\n formatting.suppressAutoHyphens = parseBooleanElement(suppressAutoHyphens);\n\n // Run properties for this paragraph (default run formatting)\n const rPr = findChild(pPr, 'w', 'rPr');\n if (rPr) {\n formatting.runProperties = parseRunProperties(rPr, theme);\n }\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n/**\n * Parse table measurement (width/height with type)\n */\nfunction parseTableMeasurement(element: XmlElement | null): TableMeasurement | undefined {\n if (!element) return undefined;\n\n const w = parseNumericAttribute(element, 'w', 'w');\n const type = getAttribute(element, 'w', 'type');\n\n if (w !== undefined && type) {\n return {\n value: w,\n type: type as TableMeasurement['type'],\n };\n }\n\n return undefined;\n}\n\n/**\n * Parse table borders\n */\nfunction parseTableBorders(tblBorders: XmlElement | null): TableBorders | undefined {\n if (!tblBorders) return undefined;\n\n const borders: TableBorders = {};\n\n const top = parseBorderSpec(findChild(tblBorders, 'w', 'top'));\n if (top) borders.top = top;\n\n const bottom = parseBorderSpec(findChild(tblBorders, 'w', 'bottom'));\n if (bottom) borders.bottom = bottom;\n\n const left = parseBorderSpec(findChild(tblBorders, 'w', 'left'));\n if (left) borders.left = left;\n\n const right = parseBorderSpec(findChild(tblBorders, 'w', 'right'));\n if (right) borders.right = right;\n\n const insideH = parseBorderSpec(findChild(tblBorders, 'w', 'insideH'));\n if (insideH) borders.insideH = insideH;\n\n const insideV = parseBorderSpec(findChild(tblBorders, 'w', 'insideV'));\n if (insideV) borders.insideV = insideV;\n\n return Object.keys(borders).length > 0 ? borders : undefined;\n}\n\n/**\n * Parse cell margins\n */\nfunction parseCellMargins(tblCellMar: XmlElement | null): CellMargins | undefined {\n if (!tblCellMar) return undefined;\n\n const margins: CellMargins = {};\n\n const top = parseTableMeasurement(findChild(tblCellMar, 'w', 'top'));\n if (top) margins.top = top;\n\n const bottom = parseTableMeasurement(findChild(tblCellMar, 'w', 'bottom'));\n if (bottom) margins.bottom = bottom;\n\n const left = parseTableMeasurement(findChild(tblCellMar, 'w', 'left'));\n if (left) margins.left = left;\n\n const right = parseTableMeasurement(findChild(tblCellMar, 'w', 'right'));\n if (right) margins.right = right;\n\n return Object.keys(margins).length > 0 ? margins : undefined;\n}\n\n/**\n * Parse table look flags\n */\nfunction parseTableLook(tblLook: XmlElement | null): TableLook | undefined {\n if (!tblLook) return undefined;\n\n const look: TableLook = {};\n\n // Can be specified as individual attributes or a single val attribute\n const val = getAttribute(tblLook, 'w', 'val');\n if (val) {\n // val is a hex bitmap: bit 0=firstRow, 1=lastRow, 2=firstCol, 3=lastCol, 4=noHBand, 5=noVBand\n const num = parseInt(val, 16);\n if (!isNaN(num)) {\n look.firstRow = (num & 0x0020) !== 0;\n look.lastRow = (num & 0x0040) !== 0;\n look.firstColumn = (num & 0x0080) !== 0;\n look.lastColumn = (num & 0x0100) !== 0;\n look.noHBand = (num & 0x0200) !== 0;\n look.noVBand = (num & 0x0400) !== 0;\n }\n }\n\n // Individual attributes override\n const firstColumn = getAttribute(tblLook, 'w', 'firstColumn');\n if (firstColumn) look.firstColumn = firstColumn === '1';\n\n const firstRow = getAttribute(tblLook, 'w', 'firstRow');\n if (firstRow) look.firstRow = firstRow === '1';\n\n const lastColumn = getAttribute(tblLook, 'w', 'lastColumn');\n if (lastColumn) look.lastColumn = lastColumn === '1';\n\n const lastRow = getAttribute(tblLook, 'w', 'lastRow');\n if (lastRow) look.lastRow = lastRow === '1';\n\n const noHBand = getAttribute(tblLook, 'w', 'noHBand');\n if (noHBand) look.noHBand = noHBand === '1';\n\n const noVBand = getAttribute(tblLook, 'w', 'noVBand');\n if (noVBand) look.noVBand = noVBand === '1';\n\n return Object.keys(look).length > 0 ? look : undefined;\n}\n\n/**\n * Parse table formatting properties (w:tblPr)\n */\nfunction parseTableProperties(\n tblPr: XmlElement | null,\n _theme: Theme | null\n): TableFormatting | undefined {\n if (!tblPr) return undefined;\n\n const formatting: TableFormatting = {};\n\n // Table width\n const tblW = findChild(tblPr, 'w', 'tblW');\n if (tblW) {\n formatting.width = parseTableMeasurement(tblW);\n }\n\n // Table alignment/justification\n const jc = findChild(tblPr, 'w', 'jc');\n if (jc) {\n const val = getAttribute(jc, 'w', 'val');\n if (val === 'left' || val === 'center' || val === 'right') {\n formatting.justification = val;\n }\n }\n\n // Cell spacing\n const tblCellSpacing = findChild(tblPr, 'w', 'tblCellSpacing');\n if (tblCellSpacing) {\n formatting.cellSpacing = parseTableMeasurement(tblCellSpacing);\n }\n\n // Table indent\n const tblInd = findChild(tblPr, 'w', 'tblInd');\n if (tblInd) {\n formatting.indent = parseTableMeasurement(tblInd);\n }\n\n // Table borders\n const tblBorders = findChild(tblPr, 'w', 'tblBorders');\n if (tblBorders) {\n formatting.borders = parseTableBorders(tblBorders);\n }\n\n // Cell margins\n const tblCellMar = findChild(tblPr, 'w', 'tblCellMar');\n if (tblCellMar) {\n formatting.cellMargins = parseCellMargins(tblCellMar);\n }\n\n // Table layout\n const tblLayout = findChild(tblPr, 'w', 'tblLayout');\n if (tblLayout) {\n const val = getAttribute(tblLayout, 'w', 'type');\n if (val === 'fixed' || val === 'autofit') {\n formatting.layout = val;\n }\n }\n\n // Table style\n const tblStyle = findChild(tblPr, 'w', 'tblStyle');\n if (tblStyle) {\n const val = getAttribute(tblStyle, 'w', 'val');\n if (val) formatting.styleId = val;\n }\n\n // Table look\n const tblLook = findChild(tblPr, 'w', 'tblLook');\n if (tblLook) {\n formatting.look = parseTableLook(tblLook);\n }\n\n // Shading\n const shd = findChild(tblPr, 'w', 'shd');\n if (shd) {\n formatting.shading = parseShadingProperties(shd);\n }\n\n // Bidi\n const bidiVisual = findChild(tblPr, 'w', 'bidiVisual');\n if (bidiVisual) formatting.bidi = parseBooleanElement(bidiVisual);\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n/**\n * Parse table row formatting properties (w:trPr)\n */\nfunction parseTableRowProperties(trPr: XmlElement | null): TableRowFormatting | undefined {\n if (!trPr) return undefined;\n\n const formatting: TableRowFormatting = {};\n\n // Row height\n const trHeight = findChild(trPr, 'w', 'trHeight');\n if (trHeight) {\n formatting.height = parseTableMeasurement(trHeight);\n const hRule = getAttribute(trHeight, 'w', 'hRule');\n if (hRule) {\n formatting.heightRule = hRule as TableRowFormatting['heightRule'];\n }\n }\n\n // Header row\n const tblHeader = findChild(trPr, 'w', 'tblHeader');\n if (tblHeader) formatting.header = parseBooleanElement(tblHeader);\n\n // Can't split\n const cantSplit = findChild(trPr, 'w', 'cantSplit');\n if (cantSplit) formatting.cantSplit = parseBooleanElement(cantSplit);\n\n // Row justification\n const jc = findChild(trPr, 'w', 'jc');\n if (jc) {\n const val = getAttribute(jc, 'w', 'val');\n if (val === 'left' || val === 'center' || val === 'right') {\n formatting.justification = val;\n }\n }\n\n // Hidden\n const hidden = findChild(trPr, 'w', 'hidden');\n if (hidden) formatting.hidden = parseBooleanElement(hidden);\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n/**\n * Parse table cell formatting properties (w:tcPr)\n */\nfunction parseTableCellProperties(\n tcPr: XmlElement | null,\n _theme: Theme | null\n): TableCellFormatting | undefined {\n if (!tcPr) return undefined;\n\n const formatting: TableCellFormatting = {};\n\n // Cell width\n const tcW = findChild(tcPr, 'w', 'tcW');\n if (tcW) {\n formatting.width = parseTableMeasurement(tcW);\n }\n\n // Cell borders\n const tcBorders = findChild(tcPr, 'w', 'tcBorders');\n if (tcBorders) {\n formatting.borders = parseTableBorders(tcBorders);\n }\n\n // Cell margins\n const tcMar = findChild(tcPr, 'w', 'tcMar');\n if (tcMar) {\n formatting.margins = parseCellMargins(tcMar);\n }\n\n // Shading\n const shd = findChild(tcPr, 'w', 'shd');\n if (shd) {\n formatting.shading = parseShadingProperties(shd);\n }\n\n // Vertical alignment\n const vAlign = findChild(tcPr, 'w', 'vAlign');\n if (vAlign) {\n const val = getAttribute(vAlign, 'w', 'val');\n if (val === 'top' || val === 'center' || val === 'bottom') {\n formatting.verticalAlign = val;\n }\n }\n\n // Text direction\n const textDirection = findChild(tcPr, 'w', 'textDirection');\n if (textDirection) {\n const val = getAttribute(textDirection, 'w', 'val');\n if (val) formatting.textDirection = val as TableCellFormatting['textDirection'];\n }\n\n // Grid span (horizontal merge)\n const gridSpan = findChild(tcPr, 'w', 'gridSpan');\n if (gridSpan) {\n const val = parseNumericAttribute(gridSpan, 'w', 'val');\n if (val !== undefined) formatting.gridSpan = val;\n }\n\n // Vertical merge\n const vMerge = findChild(tcPr, 'w', 'vMerge');\n if (vMerge) {\n const val = getAttribute(vMerge, 'w', 'val');\n formatting.vMerge = val === 'restart' ? 'restart' : 'continue';\n }\n\n // Fit text\n const tcFitText = findChild(tcPr, 'w', 'tcFitText');\n if (tcFitText) formatting.fitText = parseBooleanElement(tcFitText);\n\n // No wrap\n const noWrap = findChild(tcPr, 'w', 'noWrap');\n if (noWrap) formatting.noWrap = parseBooleanElement(noWrap);\n\n // Hide mark\n const hideMark = findChild(tcPr, 'w', 'hideMark');\n if (hideMark) formatting.hideMark = parseBooleanElement(hideMark);\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n/**\n * Parse a single style element (w:style)\n */\nfunction parseStyle(styleEl: XmlElement, theme: Theme | null): Style {\n const style: Style = {\n styleId: getAttribute(styleEl, 'w', 'styleId') ?? '',\n type: (getAttribute(styleEl, 'w', 'type') as StyleType) ?? 'paragraph',\n };\n\n // Default flag\n const defaultAttr = getAttribute(styleEl, 'w', 'default');\n if (defaultAttr) style.default = defaultAttr === '1' || defaultAttr === 'true';\n\n // Name\n const nameEl = findChild(styleEl, 'w', 'name');\n if (nameEl) {\n style.name = getAttribute(nameEl, 'w', 'val') ?? undefined;\n }\n\n // Based on (inheritance)\n const basedOn = findChild(styleEl, 'w', 'basedOn');\n if (basedOn) {\n style.basedOn = getAttribute(basedOn, 'w', 'val') ?? undefined;\n }\n\n // Next style\n const next = findChild(styleEl, 'w', 'next');\n if (next) {\n style.next = getAttribute(next, 'w', 'val') ?? undefined;\n }\n\n // Linked style\n const link = findChild(styleEl, 'w', 'link');\n if (link) {\n style.link = getAttribute(link, 'w', 'val') ?? undefined;\n }\n\n // UI Priority\n const uiPriority = findChild(styleEl, 'w', 'uiPriority');\n if (uiPriority) {\n const val = parseNumericAttribute(uiPriority, 'w', 'val');\n if (val !== undefined) style.uiPriority = val;\n }\n\n // Hidden/Semi-hidden\n const hidden = findChild(styleEl, 'w', 'hidden');\n if (hidden) style.hidden = parseBooleanElement(hidden);\n\n const semiHidden = findChild(styleEl, 'w', 'semiHidden');\n if (semiHidden) style.semiHidden = parseBooleanElement(semiHidden);\n\n // Unhide when used\n const unhideWhenUsed = findChild(styleEl, 'w', 'unhideWhenUsed');\n if (unhideWhenUsed) style.unhideWhenUsed = parseBooleanElement(unhideWhenUsed);\n\n // Quick format\n const qFormat = findChild(styleEl, 'w', 'qFormat');\n if (qFormat) style.qFormat = parseBooleanElement(qFormat);\n\n // Personal/custom style\n const personal = findChild(styleEl, 'w', 'personal');\n if (personal) style.personal = parseBooleanElement(personal);\n\n // Paragraph properties\n const pPr = findChild(styleEl, 'w', 'pPr');\n if (pPr) {\n style.pPr = parseParagraphProperties(pPr, theme);\n }\n\n // Run properties\n const rPr = findChild(styleEl, 'w', 'rPr');\n if (rPr) {\n style.rPr = parseRunProperties(rPr, theme);\n }\n\n // Table properties (for table styles)\n const tblPr = findChild(styleEl, 'w', 'tblPr');\n if (tblPr) {\n style.tblPr = parseTableProperties(tblPr, theme);\n }\n\n // Table row properties\n const trPr = findChild(styleEl, 'w', 'trPr');\n if (trPr) {\n style.trPr = parseTableRowProperties(trPr);\n }\n\n // Table cell properties\n const tcPr = findChild(styleEl, 'w', 'tcPr');\n if (tcPr) {\n style.tcPr = parseTableCellProperties(tcPr, theme);\n }\n\n // Table style conditional formatting (tblStylePr)\n const tblStylePrs = findChildren(styleEl, 'w', 'tblStylePr');\n if (tblStylePrs.length > 0) {\n style.tblStylePr = [];\n\n for (const tblStylePr of tblStylePrs) {\n const typeAttr = getAttribute(tblStylePr, 'w', 'type');\n if (typeAttr) {\n const conditionalStyle: NonNullable<Style['tblStylePr']>[number] = {\n type: typeAttr as any,\n };\n\n const condPPr = findChild(tblStylePr, 'w', 'pPr');\n if (condPPr) conditionalStyle.pPr = parseParagraphProperties(condPPr, theme);\n\n const condRPr = findChild(tblStylePr, 'w', 'rPr');\n if (condRPr) conditionalStyle.rPr = parseRunProperties(condRPr, theme);\n\n const condTblPr = findChild(tblStylePr, 'w', 'tblPr');\n if (condTblPr) conditionalStyle.tblPr = parseTableProperties(condTblPr, theme);\n\n const condTrPr = findChild(tblStylePr, 'w', 'trPr');\n if (condTrPr) conditionalStyle.trPr = parseTableRowProperties(condTrPr);\n\n const condTcPr = findChild(tblStylePr, 'w', 'tcPr');\n if (condTcPr) conditionalStyle.tcPr = parseTableCellProperties(condTcPr, theme);\n\n style.tblStylePr.push(conditionalStyle);\n }\n }\n }\n\n return style;\n}\n\n/**\n * Parse document defaults (w:docDefaults)\n */\nfunction parseDocDefaults(\n docDefaults: XmlElement | null,\n theme: Theme | null\n): DocDefaults | undefined {\n if (!docDefaults) return undefined;\n\n const result: DocDefaults = {};\n\n // Default run properties\n const rPrDefault = findChild(docDefaults, 'w', 'rPrDefault');\n if (rPrDefault) {\n const rPr = findChild(rPrDefault, 'w', 'rPr');\n if (rPr) {\n result.rPr = parseRunProperties(rPr, theme);\n }\n }\n\n // Default paragraph properties\n const pPrDefault = findChild(docDefaults, 'w', 'pPrDefault');\n if (pPrDefault) {\n const pPr = findChild(pPrDefault, 'w', 'pPr');\n if (pPr) {\n result.pPr = parseParagraphProperties(pPr, theme);\n }\n }\n\n return result.rPr || result.pPr ? result : undefined;\n}\n\n/**\n * Deep merge text formatting (source overrides target)\n */\nfunction mergeTextFormatting(\n target: TextFormatting | undefined,\n source: TextFormatting | undefined\n): TextFormatting | undefined {\n if (!source) return target;\n if (!target) return source ? { ...source } : undefined;\n\n const result = { ...target };\n\n // Copy all defined properties from source\n for (const key of Object.keys(source) as (keyof TextFormatting)[]) {\n const value = source[key];\n if (value !== undefined) {\n (result as any)[key] =\n typeof value === 'object' && value !== null\n ? { ...((result[key] as any) || {}), ...value }\n : value;\n }\n }\n\n return result;\n}\n\n/**\n * Deep merge paragraph formatting (source overrides target)\n */\nfunction mergeParagraphFormatting(\n target: ParagraphFormatting | undefined,\n source: ParagraphFormatting | undefined\n): ParagraphFormatting | undefined {\n if (!source) return target;\n if (!target) return source ? { ...source } : undefined;\n\n const result = { ...target };\n\n for (const key of Object.keys(source) as (keyof ParagraphFormatting)[]) {\n const value = source[key];\n if (value !== undefined) {\n if (key === 'runProperties') {\n result.runProperties = mergeTextFormatting(result.runProperties, source.runProperties);\n } else if (key === 'borders' || key === 'numPr' || key === 'frame') {\n const baseValue = result[key] as Record<string, unknown> | undefined;\n const sourceValue = value as Record<string, unknown> | undefined;\n (result as Record<string, unknown>)[key] = { ...(baseValue || {}), ...(sourceValue || {}) };\n } else if (key === 'tabs' && Array.isArray(value)) {\n result.tabs = [...value];\n } else {\n (result as any)[key] = value;\n }\n }\n }\n\n return result;\n}\n\n/**\n * Resolve style inheritance chain\n */\nfunction resolveStyleInheritance(\n style: Style,\n styleMap: StyleMap,\n theme: Theme | null,\n visited: Set<string> = new Set()\n): Style {\n // Prevent circular inheritance\n if (visited.has(style.styleId)) {\n return style;\n }\n visited.add(style.styleId);\n\n // If no basedOn, return as-is\n if (!style.basedOn) {\n return style;\n }\n\n // Get parent style\n const parentStyle = styleMap.get(style.basedOn);\n if (!parentStyle) {\n return style;\n }\n\n // Recursively resolve parent\n const resolvedParent = resolveStyleInheritance(parentStyle, styleMap, theme, visited);\n\n // Merge parent into this style (this style overrides parent)\n const resolved: Style = {\n ...style,\n pPr: mergeParagraphFormatting(resolvedParent.pPr, style.pPr),\n rPr: mergeTextFormatting(resolvedParent.rPr, style.rPr),\n };\n\n // Merge table properties if this is a table style\n if (style.type === 'table') {\n if (resolvedParent.tblPr || style.tblPr) {\n resolved.tblPr = { ...(resolvedParent.tblPr || {}), ...(style.tblPr || {}) };\n }\n if (resolvedParent.trPr || style.trPr) {\n resolved.trPr = { ...(resolvedParent.trPr || {}), ...(style.trPr || {}) };\n }\n if (resolvedParent.tcPr || style.tcPr) {\n resolved.tcPr = { ...(resolvedParent.tcPr || {}), ...(style.tcPr || {}) };\n }\n }\n\n return resolved;\n}\n\n/**\n * Parse styles.xml content\n *\n * @param stylesXml - XML content of styles.xml\n * @param theme - Parsed theme for resolving theme references\n * @returns StyleMap with resolved inheritance\n */\nexport function parseStyles(stylesXml: string, theme: Theme | null): StyleMap {\n const styleMap: StyleMap = new Map();\n\n try {\n const doc = parseXmlDocument(stylesXml);\n if (!doc) {\n return styleMap;\n }\n\n // First pass: parse all styles without inheritance resolution\n const styleElements = findChildren(doc, 'w', 'style');\n for (const styleEl of styleElements) {\n const style = parseStyle(styleEl, theme);\n if (style.styleId) {\n styleMap.set(style.styleId, style);\n }\n }\n\n // Second pass: resolve inheritance\n for (const [styleId, style] of styleMap) {\n const resolved = resolveStyleInheritance(style, styleMap, theme);\n styleMap.set(styleId, resolved);\n }\n } catch (error) {\n console.warn('Failed to parse styles:', error);\n }\n\n return styleMap;\n}\n\n/**\n * Parse complete style definitions including docDefaults\n *\n * @param stylesXml - XML content of styles.xml\n * @param theme - Parsed theme for resolving theme references\n * @returns StyleDefinitions with docDefaults and resolved styles\n */\nexport function parseStyleDefinitions(stylesXml: string, theme: Theme | null): StyleDefinitions {\n const result: StyleDefinitions = {\n styles: [],\n };\n\n try {\n const doc = parseXmlDocument(stylesXml);\n if (!doc) {\n return result;\n }\n\n // Parse document defaults\n const docDefaultsEl = findChild(doc, 'w', 'docDefaults');\n result.docDefaults = parseDocDefaults(docDefaultsEl, theme);\n\n // Parse latent styles\n const latentStylesEl = findChild(doc, 'w', 'latentStyles');\n if (latentStylesEl) {\n result.latentStyles = {\n defLockedState: getAttribute(latentStylesEl, 'w', 'defLockedState') === '1',\n defUIPriority: parseNumericAttribute(latentStylesEl, 'w', 'defUIPriority'),\n defSemiHidden: getAttribute(latentStylesEl, 'w', 'defSemiHidden') === '1',\n defUnhideWhenUsed: getAttribute(latentStylesEl, 'w', 'defUnhideWhenUsed') === '1',\n defQFormat: getAttribute(latentStylesEl, 'w', 'defQFormat') === '1',\n count: parseNumericAttribute(latentStylesEl, 'w', 'count'),\n };\n }\n\n // Parse styles with full inheritance resolution\n const styleMap = parseStyles(stylesXml, theme);\n result.styles = Array.from(styleMap.values());\n } catch (error) {\n console.warn('Failed to parse style definitions:', error);\n }\n\n return result;\n}\n\n/**\n * Get the resolved properties for a style\n *\n * @param styleId - Style ID to look up\n * @param styleMap - Style map from parseStyles\n * @returns Resolved style or undefined\n */\nexport function getResolvedStyle(styleId: string, styleMap: StyleMap): Style | undefined {\n return styleMap.get(styleId);\n}\n\n/**\n * Get the default paragraph style\n */\nexport function getDefaultParagraphStyle(styleMap: StyleMap): Style | undefined {\n for (const style of styleMap.values()) {\n if (style.type === 'paragraph' && style.default) {\n return style;\n }\n }\n // Fallback to \"Normal\" style\n return styleMap.get('Normal');\n}\n\n/**\n * Get the default character style\n */\nexport function getDefaultCharacterStyle(styleMap: StyleMap): Style | undefined {\n for (const style of styleMap.values()) {\n if (style.type === 'character' && style.default) {\n return style;\n }\n }\n return undefined;\n}\n\n/**\n * Get all styles of a specific type\n */\nexport function getStylesByType(styleMap: StyleMap, type: StyleType): Style[] {\n const result: Style[] = [];\n for (const style of styleMap.values()) {\n if (style.type === type) {\n result.push(style);\n }\n }\n return result;\n}\n","/**\n * Numbering/List Parser for DOCX\n *\n * Parses numbering.xml to extract:\n * - Abstract numbering definitions (templates with levels)\n * - Numbering instances (concrete references with optional overrides)\n *\n * OOXML Structure:\n * - w:abstractNum - Template definitions with 9 levels (0-8)\n * - w:num - Instances that reference abstractNum and can override levels\n * - w:lvl - Level definition with start, format, text pattern, etc.\n */\n\nimport type {\n NumberingDefinitions,\n AbstractNumbering,\n NumberingInstance,\n ListLevel,\n NumberFormat,\n LevelSuffix,\n ParagraphFormatting,\n TextFormatting,\n} from '../types/document';\n\nimport {\n parseXmlDocument,\n findChild,\n findChildren,\n getAttribute,\n parseBooleanElement,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\n\n/**\n * Map of rId to numbering definitions\n */\nexport type NumberingMap = {\n definitions: NumberingDefinitions;\n /** Get level info for a numId and ilvl */\n getLevel: (numId: number, ilvl: number) => ListLevel | null;\n /** Get abstract numbering by ID */\n getAbstract: (abstractNumId: number) => AbstractNumbering | null;\n /** Check if numId exists */\n hasNumbering: (numId: number) => boolean;\n};\n\n/**\n * Parse numbering.xml into NumberingDefinitions\n *\n * @param numberingXml - Raw XML string from word/numbering.xml (or null if not present)\n * @returns NumberingMap with definitions and helper functions\n */\nexport function parseNumbering(numberingXml: string | null): NumberingMap {\n const definitions: NumberingDefinitions = {\n abstractNums: [],\n nums: [],\n };\n\n if (!numberingXml) {\n return createNumberingMap(definitions);\n }\n\n const root = parseXmlDocument(numberingXml);\n if (!root) {\n return createNumberingMap(definitions);\n }\n\n // Parse abstract numbering definitions\n const abstractNumElements = findChildren(root, 'w', 'abstractNum');\n for (const abstractNum of abstractNumElements) {\n const parsed = parseAbstractNumbering(abstractNum);\n if (parsed) {\n definitions.abstractNums.push(parsed);\n }\n }\n\n // Parse numbering instances\n const numElements = findChildren(root, 'w', 'num');\n for (const num of numElements) {\n const parsed = parseNumberingInstance(num);\n if (parsed) {\n definitions.nums.push(parsed);\n }\n }\n\n return createNumberingMap(definitions);\n}\n\n/**\n * Parse a single w:abstractNum element\n */\nfunction parseAbstractNumbering(element: XmlElement): AbstractNumbering | null {\n const abstractNumIdStr = getAttribute(element, 'w', 'abstractNumId');\n if (abstractNumIdStr === null) return null;\n\n const abstractNumId = parseInt(abstractNumIdStr, 10);\n if (isNaN(abstractNumId)) return null;\n\n const abstractNum: AbstractNumbering = {\n abstractNumId,\n levels: [],\n };\n\n // Parse optional attributes/children\n const multiLevelTypeEl = findChild(element, 'w', 'multiLevelType');\n if (multiLevelTypeEl) {\n const mlType = getAttribute(multiLevelTypeEl, 'w', 'val');\n if (mlType === 'hybridMultilevel' || mlType === 'multilevel' || mlType === 'singleLevel') {\n abstractNum.multiLevelType = mlType;\n }\n }\n\n // Parse name\n const nameEl = findChild(element, 'w', 'name');\n if (nameEl) {\n abstractNum.name = getAttribute(nameEl, 'w', 'val') ?? undefined;\n }\n\n // Parse style links\n const numStyleLinkEl = findChild(element, 'w', 'numStyleLink');\n if (numStyleLinkEl) {\n abstractNum.numStyleLink = getAttribute(numStyleLinkEl, 'w', 'val') ?? undefined;\n }\n\n const styleLinkEl = findChild(element, 'w', 'styleLink');\n if (styleLinkEl) {\n abstractNum.styleLink = getAttribute(styleLinkEl, 'w', 'val') ?? undefined;\n }\n\n // Parse levels (w:lvl)\n const levelElements = findChildren(element, 'w', 'lvl');\n for (const lvlEl of levelElements) {\n const level = parseListLevel(lvlEl);\n if (level) {\n abstractNum.levels.push(level);\n }\n }\n\n // Sort levels by ilvl\n abstractNum.levels.sort((a, b) => a.ilvl - b.ilvl);\n\n return abstractNum;\n}\n\n/**\n * Parse a single w:num element (numbering instance)\n */\nfunction parseNumberingInstance(element: XmlElement): NumberingInstance | null {\n const numIdStr = getAttribute(element, 'w', 'numId');\n if (numIdStr === null) return null;\n\n const numId = parseInt(numIdStr, 10);\n if (isNaN(numId)) return null;\n\n // Get abstract numbering reference\n const abstractNumIdEl = findChild(element, 'w', 'abstractNumId');\n if (!abstractNumIdEl) return null;\n\n const abstractNumIdStr = getAttribute(abstractNumIdEl, 'w', 'val');\n if (abstractNumIdStr === null) return null;\n\n const abstractNumId = parseInt(abstractNumIdStr, 10);\n if (isNaN(abstractNumId)) return null;\n\n const instance: NumberingInstance = {\n numId,\n abstractNumId,\n };\n\n // Parse level overrides (w:lvlOverride)\n const overrideElements = findChildren(element, 'w', 'lvlOverride');\n if (overrideElements.length > 0) {\n instance.levelOverrides = [];\n\n for (const overrideEl of overrideElements) {\n const ilvlStr = getAttribute(overrideEl, 'w', 'ilvl');\n if (ilvlStr === null) continue;\n\n const ilvl = parseInt(ilvlStr, 10);\n if (isNaN(ilvl)) continue;\n\n const override: {\n ilvl: number;\n startOverride?: number;\n lvl?: ListLevel;\n } = { ilvl };\n\n // Check for start override\n const startOverrideEl = findChild(overrideEl, 'w', 'startOverride');\n if (startOverrideEl) {\n const startVal = getAttribute(startOverrideEl, 'w', 'val');\n if (startVal !== null) {\n const startNum = parseInt(startVal, 10);\n if (!isNaN(startNum)) {\n override.startOverride = startNum;\n }\n }\n }\n\n // Check for full level redefinition\n const lvlEl = findChild(overrideEl, 'w', 'lvl');\n if (lvlEl) {\n override.lvl = parseListLevel(lvlEl) ?? undefined;\n }\n\n instance.levelOverrides.push(override);\n }\n }\n\n return instance;\n}\n\n/**\n * Parse a single w:lvl element (list level definition)\n */\nfunction parseListLevel(element: XmlElement): ListLevel | null {\n const ilvlStr = getAttribute(element, 'w', 'ilvl');\n if (ilvlStr === null) return null;\n\n const ilvl = parseInt(ilvlStr, 10);\n if (isNaN(ilvl) || ilvl < 0 || ilvl > 8) return null;\n\n const level: ListLevel = {\n ilvl,\n numFmt: 'decimal', // Default\n lvlText: '',\n };\n\n // Parse start value\n const startEl = findChild(element, 'w', 'start');\n if (startEl) {\n const startVal = getAttribute(startEl, 'w', 'val');\n if (startVal !== null) {\n const startNum = parseInt(startVal, 10);\n if (!isNaN(startNum)) {\n level.start = startNum;\n }\n }\n }\n\n // Parse number format\n const numFmtEl = findChild(element, 'w', 'numFmt');\n if (numFmtEl) {\n const fmtVal = getAttribute(numFmtEl, 'w', 'val');\n if (fmtVal) {\n level.numFmt = parseNumberFormat(fmtVal);\n }\n }\n\n // Parse level text (the pattern like \"%1.\" or \"•\")\n const lvlTextEl = findChild(element, 'w', 'lvlText');\n if (lvlTextEl) {\n level.lvlText = getAttribute(lvlTextEl, 'w', 'val') ?? '';\n }\n\n // Parse justification\n const lvlJcEl = findChild(element, 'w', 'lvlJc');\n if (lvlJcEl) {\n const jcVal = getAttribute(lvlJcEl, 'w', 'val');\n if (jcVal === 'left' || jcVal === 'center' || jcVal === 'right') {\n level.lvlJc = jcVal;\n }\n }\n\n // Parse suffix\n const suffEl = findChild(element, 'w', 'suff');\n if (suffEl) {\n const suffVal = getAttribute(suffEl, 'w', 'val');\n if (suffVal === 'tab' || suffVal === 'space' || suffVal === 'nothing') {\n level.suffix = suffVal as LevelSuffix;\n }\n }\n\n // Parse isLgl (legal numbering)\n const isLglEl = findChild(element, 'w', 'isLgl');\n if (isLglEl) {\n level.isLgl = parseBooleanElement(isLglEl);\n }\n\n // Parse lvlRestart (restart numbering from a higher level)\n const lvlRestartEl = findChild(element, 'w', 'lvlRestart');\n if (lvlRestartEl) {\n const restartVal = getAttribute(lvlRestartEl, 'w', 'val');\n if (restartVal !== null) {\n const restartNum = parseInt(restartVal, 10);\n if (!isNaN(restartNum)) {\n level.lvlRestart = restartNum;\n }\n }\n }\n\n // Parse legacy settings\n const legacyEl = findChild(element, 'w', 'legacy');\n if (legacyEl) {\n level.legacy = {\n legacy: parseBooleanElement(legacyEl),\n legacySpace: parseNumericAttribute(legacyEl, 'w', 'legacySpace'),\n legacyIndent: parseNumericAttribute(legacyEl, 'w', 'legacyIndent'),\n };\n }\n\n // Parse paragraph properties (w:pPr)\n const pPrEl = findChild(element, 'w', 'pPr');\n if (pPrEl) {\n level.pPr = parseLevelParagraphProps(pPrEl);\n }\n\n // Parse run properties (w:rPr)\n const rPrEl = findChild(element, 'w', 'rPr');\n if (rPrEl) {\n level.rPr = parseLevelRunProps(rPrEl);\n }\n\n return level;\n}\n\n/**\n * Parse number format string to NumberFormat type\n */\nfunction parseNumberFormat(format: string): NumberFormat {\n // Map of known formats\n const formatMap: Record<string, NumberFormat> = {\n decimal: 'decimal',\n upperRoman: 'upperRoman',\n lowerRoman: 'lowerRoman',\n upperLetter: 'upperLetter',\n lowerLetter: 'lowerLetter',\n ordinal: 'ordinal',\n cardinalText: 'cardinalText',\n ordinalText: 'ordinalText',\n hex: 'hex',\n chicago: 'chicago',\n bullet: 'bullet',\n none: 'none',\n decimalZero: 'decimalZero',\n ganada: 'ganada',\n chosung: 'chosung',\n // CJK formats\n ideographDigital: 'ideographDigital',\n japaneseCounting: 'japaneseCounting',\n aiueo: 'aiueo',\n iroha: 'iroha',\n decimalFullWidth: 'decimalFullWidth',\n decimalHalfWidth: 'decimalHalfWidth',\n japaneseLegal: 'japaneseLegal',\n japaneseDigitalTenThousand: 'japaneseDigitalTenThousand',\n decimalEnclosedCircle: 'decimalEnclosedCircle',\n decimalFullWidth2: 'decimalFullWidth2',\n aiueoFullWidth: 'aiueoFullWidth',\n irohaFullWidth: 'irohaFullWidth',\n decimalEnclosedFullstop: 'decimalEnclosedFullstop',\n decimalEnclosedParen: 'decimalEnclosedParen',\n decimalEnclosedCircleChinese: 'decimalEnclosedCircleChinese',\n ideographEnclosedCircle: 'ideographEnclosedCircle',\n ideographTraditional: 'ideographTraditional',\n ideographZodiac: 'ideographZodiac',\n ideographZodiacTraditional: 'ideographZodiacTraditional',\n taiwaneseCounting: 'taiwaneseCounting',\n ideographLegalTraditional: 'ideographLegalTraditional',\n taiwaneseCountingThousand: 'taiwaneseCountingThousand',\n taiwaneseDigital: 'taiwaneseDigital',\n chineseCounting: 'chineseCounting',\n chineseLegalSimplified: 'chineseLegalSimplified',\n chineseCountingThousand: 'chineseCountingThousand',\n koreanDigital: 'koreanDigital',\n koreanCounting: 'koreanCounting',\n koreanLegal: 'koreanLegal',\n koreanDigital2: 'koreanDigital2',\n vietnameseCounting: 'vietnameseCounting',\n russianLower: 'russianLower',\n russianUpper: 'russianUpper',\n numberInDash: 'numberInDash',\n hebrew1: 'hebrew1',\n hebrew2: 'hebrew2',\n arabicAlpha: 'arabicAlpha',\n arabicAbjad: 'arabicAbjad',\n hindiVowels: 'hindiVowels',\n hindiConsonants: 'hindiConsonants',\n hindiNumbers: 'hindiNumbers',\n hindiCounting: 'hindiCounting',\n thaiLetters: 'thaiLetters',\n thaiNumbers: 'thaiNumbers',\n thaiCounting: 'thaiCounting',\n };\n\n return formatMap[format] ?? 'decimal';\n}\n\n/**\n * Parse paragraph properties for a list level (subset of full pPr)\n * Main concern: indentation and tabs\n */\nfunction parseLevelParagraphProps(pPr: XmlElement): ParagraphFormatting {\n const formatting: ParagraphFormatting = {};\n\n // Parse indentation (w:ind)\n const indEl = findChild(pPr, 'w', 'ind');\n if (indEl) {\n const left = parseNumericAttribute(indEl, 'w', 'left');\n const right = parseNumericAttribute(indEl, 'w', 'right');\n const firstLine = parseNumericAttribute(indEl, 'w', 'firstLine');\n const hanging = parseNumericAttribute(indEl, 'w', 'hanging');\n\n if (left !== undefined) formatting.indentLeft = left;\n if (right !== undefined) formatting.indentRight = right;\n\n if (hanging !== undefined) {\n formatting.indentFirstLine = -hanging;\n formatting.hangingIndent = true;\n } else if (firstLine !== undefined) {\n formatting.indentFirstLine = firstLine;\n }\n }\n\n // Parse tabs (w:tabs)\n const tabsEl = findChild(pPr, 'w', 'tabs');\n if (tabsEl) {\n formatting.tabs = [];\n const tabElements = findChildren(tabsEl, 'w', 'tab');\n for (const tabEl of tabElements) {\n const pos = parseNumericAttribute(tabEl, 'w', 'pos');\n const val = getAttribute(tabEl, 'w', 'val');\n const leader = getAttribute(tabEl, 'w', 'leader');\n\n if (pos !== undefined && val) {\n formatting.tabs.push({\n position: pos,\n alignment: parseTabAlignment(val),\n leader: parseTabLeader(leader),\n });\n }\n }\n }\n\n return formatting;\n}\n\n/**\n * Parse tab alignment value\n */\nfunction parseTabAlignment(\n val: string\n): 'left' | 'center' | 'right' | 'decimal' | 'bar' | 'clear' | 'num' {\n switch (val) {\n case 'left':\n return 'left';\n case 'center':\n return 'center';\n case 'right':\n return 'right';\n case 'decimal':\n return 'decimal';\n case 'bar':\n return 'bar';\n case 'clear':\n return 'clear';\n case 'num':\n return 'num';\n default:\n return 'left';\n }\n}\n\n/**\n * Parse tab leader value\n */\nfunction parseTabLeader(\n val: string | null\n): 'none' | 'dot' | 'hyphen' | 'underscore' | 'heavy' | 'middleDot' | undefined {\n if (!val) return undefined;\n switch (val) {\n case 'none':\n return 'none';\n case 'dot':\n return 'dot';\n case 'hyphen':\n return 'hyphen';\n case 'underscore':\n return 'underscore';\n case 'heavy':\n return 'heavy';\n case 'middleDot':\n return 'middleDot';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse run properties for a list level (subset of full rPr)\n * Main concern: fonts for bullet characters\n */\nfunction parseLevelRunProps(rPr: XmlElement): TextFormatting {\n const formatting: TextFormatting = {};\n\n // Parse fonts (w:rFonts) - important for bullet characters\n const rFontsEl = findChild(rPr, 'w', 'rFonts');\n if (rFontsEl) {\n formatting.fontFamily = {\n ascii: getAttribute(rFontsEl, 'w', 'ascii') ?? undefined,\n hAnsi: getAttribute(rFontsEl, 'w', 'hAnsi') ?? undefined,\n eastAsia: getAttribute(rFontsEl, 'w', 'eastAsia') ?? undefined,\n cs: getAttribute(rFontsEl, 'w', 'cs') ?? undefined,\n };\n }\n\n // Parse font size (w:sz)\n const szEl = findChild(rPr, 'w', 'sz');\n if (szEl) {\n const size = parseNumericAttribute(szEl, 'w', 'val');\n if (size !== undefined) {\n formatting.fontSize = size; // In half-points\n }\n }\n\n // Parse color (w:color)\n const colorEl = findChild(rPr, 'w', 'color');\n if (colorEl) {\n const val = getAttribute(colorEl, 'w', 'val');\n const themeColor = getAttribute(colorEl, 'w', 'themeColor');\n\n if (val === 'auto') {\n formatting.color = { auto: true };\n } else if (themeColor) {\n formatting.color = {\n themeColor: themeColor as any,\n themeTint: getAttribute(colorEl, 'w', 'themeTint') ?? undefined,\n themeShade: getAttribute(colorEl, 'w', 'themeShade') ?? undefined,\n };\n } else if (val) {\n formatting.color = { rgb: val };\n }\n }\n\n // Parse bold (w:b)\n const bEl = findChild(rPr, 'w', 'b');\n if (bEl) {\n formatting.bold = parseBooleanElement(bEl);\n }\n\n // Parse italic (w:i)\n const iEl = findChild(rPr, 'w', 'i');\n if (iEl) {\n formatting.italic = parseBooleanElement(iEl);\n }\n\n return formatting;\n}\n\n/**\n * Create a NumberingMap with helper functions\n */\nfunction createNumberingMap(definitions: NumberingDefinitions): NumberingMap {\n // Build lookup maps for efficient access\n const abstractMap = new Map<number, AbstractNumbering>();\n for (const abs of definitions.abstractNums) {\n abstractMap.set(abs.abstractNumId, abs);\n }\n\n const numMap = new Map<number, NumberingInstance>();\n for (const num of definitions.nums) {\n numMap.set(num.numId, num);\n }\n\n return {\n definitions,\n\n getLevel(numId: number, ilvl: number): ListLevel | null {\n const num = numMap.get(numId);\n if (!num) return null;\n\n // Check for level override first\n if (num.levelOverrides) {\n const override = num.levelOverrides.find((o) => o.ilvl === ilvl);\n if (override) {\n if (override.lvl) {\n // Full level redefinition\n return override.lvl;\n }\n // Start override - need to get base level and modify\n const abstractNum = abstractMap.get(num.abstractNumId);\n if (abstractNum) {\n const baseLevel = abstractNum.levels.find((l) => l.ilvl === ilvl);\n if (baseLevel && override.startOverride !== undefined) {\n return {\n ...baseLevel,\n start: override.startOverride,\n };\n }\n }\n }\n }\n\n // Get from abstract numbering\n const abstractNum = abstractMap.get(num.abstractNumId);\n if (!abstractNum) return null;\n\n return abstractNum.levels.find((l) => l.ilvl === ilvl) ?? null;\n },\n\n getAbstract(abstractNumId: number): AbstractNumbering | null {\n return abstractMap.get(abstractNumId) ?? null;\n },\n\n hasNumbering(numId: number): boolean {\n return numMap.has(numId);\n },\n };\n}\n\n/**\n * Format a number according to the specified format\n *\n * @param num - The number to format\n * @param format - The number format\n * @returns Formatted string\n */\nexport function formatNumber(num: number, format: NumberFormat): string {\n switch (format) {\n case 'decimal':\n case 'decimalZero':\n return num.toString();\n\n case 'upperRoman':\n return toRoman(num).toUpperCase();\n\n case 'lowerRoman':\n return toRoman(num).toLowerCase();\n\n case 'upperLetter':\n return toLetter(num).toUpperCase();\n\n case 'lowerLetter':\n return toLetter(num).toLowerCase();\n\n case 'ordinal':\n return toOrdinal(num);\n\n case 'bullet':\n return '•'; // Default bullet\n\n case 'none':\n return '';\n\n case 'decimalEnclosedParen':\n return `(${num})`;\n\n case 'numberInDash':\n return `-${num}-`;\n\n default:\n // For CJK and other special formats, fall back to decimal\n return num.toString();\n }\n}\n\n/**\n * Convert number to Roman numerals\n */\nfunction toRoman(num: number): string {\n if (num <= 0 || num > 3999) return num.toString();\n\n const romanNumerals: [number, string][] = [\n [1000, 'm'],\n [900, 'cm'],\n [500, 'd'],\n [400, 'cd'],\n [100, 'c'],\n [90, 'xc'],\n [50, 'l'],\n [40, 'xl'],\n [10, 'x'],\n [9, 'ix'],\n [5, 'v'],\n [4, 'iv'],\n [1, 'i'],\n ];\n\n let result = '';\n let remaining = num;\n\n for (const [value, numeral] of romanNumerals) {\n while (remaining >= value) {\n result += numeral;\n remaining -= value;\n }\n }\n\n return result;\n}\n\n/**\n * Convert number to letter (a, b, c, ... z, aa, ab, ...)\n */\nfunction toLetter(num: number): string {\n if (num <= 0) return '';\n\n let result = '';\n let remaining = num;\n\n while (remaining > 0) {\n remaining--;\n result = String.fromCharCode(97 + (remaining % 26)) + result;\n remaining = Math.floor(remaining / 26);\n }\n\n return result;\n}\n\n/**\n * Convert number to ordinal (1st, 2nd, 3rd, ...)\n */\nfunction toOrdinal(num: number): string {\n const suffix = ['th', 'st', 'nd', 'rd'];\n const v = num % 100;\n return num + (suffix[(v - 20) % 10] || suffix[v] || suffix[0]);\n}\n\n/**\n * Render list marker text by replacing placeholders with formatted numbers\n *\n * @param lvlText - The level text pattern (e.g., \"%1.\", \"%1.%2\")\n * @param counters - Array of counter values for each level (index 0 = level 0, etc.)\n * @param formats - Array of number formats for each level\n * @returns Rendered marker text\n */\nexport function renderListMarker(\n lvlText: string,\n counters: number[],\n formats: NumberFormat[]\n): string {\n let result = lvlText;\n\n // Replace %1 through %9 with formatted counter values\n for (let i = 1; i <= 9; i++) {\n const placeholder = `%${i}`;\n if (result.includes(placeholder)) {\n const counterIndex = i - 1;\n const counter = counters[counterIndex] ?? 1;\n const format = formats[counterIndex] ?? 'decimal';\n const formatted = formatNumber(counter, format);\n result = result.replace(placeholder, formatted);\n }\n }\n\n return result;\n}\n\n/**\n * Get the bullet character for a bullet list level\n *\n * @param level - The list level definition\n * @returns The bullet character to display\n */\nexport function getBulletCharacter(level: ListLevel): string {\n // If lvlText is set and not empty, use it\n if (level.lvlText) {\n return level.lvlText;\n }\n\n // Check font for common bullet font mappings\n const fontFamily = level.rPr?.fontFamily?.ascii || level.rPr?.fontFamily?.hAnsi;\n\n if (fontFamily) {\n const fontLower = fontFamily.toLowerCase();\n\n // Symbol font common bullets\n if (fontLower === 'symbol') {\n return '•'; // Standard bullet\n }\n\n // Wingdings common bullets\n if (fontLower.includes('wingding')) {\n return '❑'; // Square bullet\n }\n }\n\n // Default bullet\n return '•';\n}\n\n/**\n * Check if a list level is a bullet (not numbered)\n */\nexport function isBulletLevel(level: ListLevel): boolean {\n return level.numFmt === 'bullet' || level.numFmt === 'none';\n}\n","/**\n * Image Parser - Parse embedded images from w:drawing elements\n *\n * DOCX images are contained in <w:drawing> elements with either:\n * - wp:inline - Inline images that flow with text\n * - wp:anchor - Floating/anchored images with text wrapping\n *\n * OOXML Structure:\n * w:drawing\n * ├── wp:inline or wp:anchor\n * │ ├── wp:extent (size: cx, cy in EMUs)\n * │ ├── wp:effectExtent (effect margins)\n * │ ├── wp:docPr (document properties: id, name, descr, title)\n * │ ├── wp:positionH / wp:positionV (for anchor only)\n * │ ├── wp:wrap* (wrapping mode for anchor: wrapNone, wrapSquare, etc.)\n * │ └── a:graphic\n * │ └── a:graphicData\n * │ └── pic:pic\n * │ ├── pic:nvPicPr (non-visual properties)\n * │ ├── pic:blipFill\n * │ │ └── a:blip (r:embed = rId)\n * │ └── pic:spPr\n * │ └── a:xfrm (transform: rotation, flip)\n *\n * EMU (English Metric Units): 914400 EMU = 1 inch\n * Conversion: pixels = (emu * 96) / 914400\n */\n\nimport type {\n Image,\n ImageSize,\n ImageWrap,\n ImagePosition,\n ImageTransform,\n ImagePadding,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport {\n getChildElements,\n getAttribute,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\n\n// ============================================================================\n// EMU CONVERSIONS\n// ============================================================================\n\n/** EMUs per inch */\nconst EMU_PER_INCH = 914400;\n\n/** CSS pixels per inch (standard) */\nconst PIXELS_PER_INCH = 96;\n\n/**\n * Convert EMU to pixels\n *\n * @param emu - Value in EMUs\n * @returns Value in CSS pixels\n */\nexport function emuToPixels(emu: number | undefined | null): number {\n if (emu == null || isNaN(emu)) return 0;\n return Math.round((emu * PIXELS_PER_INCH) / EMU_PER_INCH);\n}\n\n/**\n * Convert pixels to EMU\n *\n * @param px - Value in pixels\n * @returns Value in EMUs\n */\nexport function pixelsToEmu(px: number): number {\n return Math.round((px * EMU_PER_INCH) / PIXELS_PER_INCH);\n}\n\n/**\n * Convert rotation value (1/60000 of a degree) to degrees\n *\n * @param rot - Rotation in 60000ths of a degree\n * @returns Rotation in degrees\n */\nfunction rotToDegrees(rot: string | null | undefined): number | undefined {\n if (!rot) return undefined;\n const val = parseInt(rot, 10);\n if (isNaN(val)) return undefined;\n return val / 60000;\n}\n\n// ============================================================================\n// ELEMENT FINDERS\n// ============================================================================\n\n/**\n * Find element by full name with namespace prefix\n */\nfunction findByFullName(parent: XmlElement, fullName: string): XmlElement | null {\n const children = getChildElements(parent);\n for (const child of children) {\n if (child.name === fullName) {\n return child;\n }\n }\n return null;\n}\n\n/**\n * Find any of the specified elements\n */\nfunction findAnyOf(parent: XmlElement, names: string[]): XmlElement | null {\n const children = getChildElements(parent);\n for (const child of children) {\n if (names.includes(child.name || '')) {\n return child;\n }\n }\n return null;\n}\n\n// ============================================================================\n// SIZE PARSING\n// ============================================================================\n\n/**\n * Parse extent element for image size\n *\n * @param extent - wp:extent element\n * @returns ImageSize in EMUs\n */\nfunction parseExtent(extent: XmlElement | null): ImageSize {\n if (!extent) {\n return { width: 0, height: 0 };\n }\n\n const cx = parseNumericAttribute(extent, null, 'cx') ?? 0;\n const cy = parseNumericAttribute(extent, null, 'cy') ?? 0;\n\n return { width: cx, height: cy };\n}\n\n/**\n * Parse effect extent for shadow/effect margins\n *\n * @param effectExtent - wp:effectExtent element\n * @returns Padding for effects\n */\nfunction parseEffectExtent(effectExtent: XmlElement | null): ImagePadding | undefined {\n if (!effectExtent) return undefined;\n\n const l = parseNumericAttribute(effectExtent, null, 'l') ?? 0;\n const t = parseNumericAttribute(effectExtent, null, 't') ?? 0;\n const r = parseNumericAttribute(effectExtent, null, 'r') ?? 0;\n const b = parseNumericAttribute(effectExtent, null, 'b') ?? 0;\n\n if (l === 0 && t === 0 && r === 0 && b === 0) {\n return undefined;\n }\n\n return {\n left: l,\n top: t,\n right: r,\n bottom: b,\n };\n}\n\n// ============================================================================\n// DOCUMENT PROPERTIES PARSING\n// ============================================================================\n\n/**\n * Parse document properties (wp:docPr)\n *\n * @param docPr - wp:docPr element\n * @returns Object with id, name, description, title\n */\nfunction parseDocProps(docPr: XmlElement | null): {\n id?: string;\n name?: string;\n alt?: string;\n title?: string;\n decorative?: boolean;\n} {\n if (!docPr) return {};\n\n const id = getAttribute(docPr, null, 'id') ?? undefined;\n const name = getAttribute(docPr, null, 'name') ?? undefined;\n const descr = getAttribute(docPr, null, 'descr') ?? undefined;\n const title = getAttribute(docPr, null, 'title') ?? undefined;\n\n // Check for decorative flag (accessibility)\n // In newer OOXML, this is indicated by a:decorative element or attribute\n const decorative = getAttribute(docPr, null, 'decorative') === '1';\n\n return {\n id,\n name,\n alt: descr,\n title,\n decorative: decorative || undefined,\n };\n}\n\n// ============================================================================\n// POSITION PARSING (for anchored images)\n// ============================================================================\n\n/**\n * Parse horizontal position (wp:positionH)\n */\nfunction parsePositionH(posH: XmlElement | null): ImagePosition['horizontal'] | undefined {\n if (!posH) return undefined;\n\n const relativeTo = getAttribute(posH, null, 'relativeFrom') ?? 'column';\n\n // Check for alignment child\n const alignEl = findByFullName(posH, 'wp:align');\n if (alignEl) {\n const alignment = alignEl.elements?.[0]?.text ?? null;\n return {\n relativeTo: relativeTo as ImagePosition['horizontal']['relativeTo'],\n alignment: alignment as ImagePosition['horizontal']['alignment'],\n };\n }\n\n // Check for posOffset child\n const posOffsetEl = findByFullName(posH, 'wp:posOffset');\n if (posOffsetEl) {\n const offsetText = String(posOffsetEl.elements?.[0]?.text ?? '0');\n const posOffset = parseInt(offsetText, 10);\n return {\n relativeTo: relativeTo as ImagePosition['horizontal']['relativeTo'],\n posOffset: isNaN(posOffset) ? 0 : posOffset,\n };\n }\n\n return {\n relativeTo: relativeTo as ImagePosition['horizontal']['relativeTo'],\n };\n}\n\n/**\n * Parse vertical position (wp:positionV)\n */\nfunction parsePositionV(posV: XmlElement | null): ImagePosition['vertical'] | undefined {\n if (!posV) return undefined;\n\n const relativeTo = getAttribute(posV, null, 'relativeFrom') ?? 'paragraph';\n\n // Check for alignment child\n const alignEl = findByFullName(posV, 'wp:align');\n if (alignEl) {\n const alignment = alignEl.elements?.[0]?.text ?? null;\n return {\n relativeTo: relativeTo as ImagePosition['vertical']['relativeTo'],\n alignment: alignment as ImagePosition['vertical']['alignment'],\n };\n }\n\n // Check for posOffset child\n const posOffsetEl = findByFullName(posV, 'wp:posOffset');\n if (posOffsetEl) {\n const offsetText = String(posOffsetEl.elements?.[0]?.text ?? '0');\n const posOffset = parseInt(offsetText, 10);\n return {\n relativeTo: relativeTo as ImagePosition['vertical']['relativeTo'],\n posOffset: isNaN(posOffset) ? 0 : posOffset,\n };\n }\n\n return {\n relativeTo: relativeTo as ImagePosition['vertical']['relativeTo'],\n };\n}\n\n// ============================================================================\n// WRAP PARSING (for anchored images)\n// ============================================================================\n\n/**\n * Wrap element names\n */\nconst WRAP_ELEMENTS = [\n 'wp:wrapNone',\n 'wp:wrapSquare',\n 'wp:wrapTight',\n 'wp:wrapThrough',\n 'wp:wrapTopAndBottom',\n];\n\n/**\n * Parse wrap element to ImageWrap\n */\nfunction parseWrapElement(wrapEl: XmlElement | null, behindDoc: boolean): ImageWrap {\n if (!wrapEl) {\n // No wrap element = wrapNone\n return {\n type: behindDoc ? 'behind' : 'inFront',\n };\n }\n\n const wrapName = wrapEl.name || '';\n const wrapType = wrapName.replace('wp:', '');\n\n // Parse common distance attributes\n const distT = parseNumericAttribute(wrapEl, null, 'distT') ?? undefined;\n const distB = parseNumericAttribute(wrapEl, null, 'distB') ?? undefined;\n const distL = parseNumericAttribute(wrapEl, null, 'distL') ?? undefined;\n const distR = parseNumericAttribute(wrapEl, null, 'distR') ?? undefined;\n\n // Parse wrapText attribute\n const wrapText = getAttribute(wrapEl, null, 'wrapText') ?? undefined;\n\n let type: ImageWrap['type'];\n switch (wrapType) {\n case 'wrapNone':\n type = behindDoc ? 'behind' : 'inFront';\n break;\n case 'wrapSquare':\n type = 'square';\n break;\n case 'wrapTight':\n type = 'tight';\n break;\n case 'wrapThrough':\n type = 'through';\n break;\n case 'wrapTopAndBottom':\n type = 'topAndBottom';\n break;\n default:\n type = 'square'; // Default fallback\n }\n\n const wrap: ImageWrap = { type };\n\n if (wrapText) {\n wrap.wrapText = wrapText as ImageWrap['wrapText'];\n }\n\n if (distT !== undefined) wrap.distT = distT;\n if (distB !== undefined) wrap.distB = distB;\n if (distL !== undefined) wrap.distL = distL;\n if (distR !== undefined) wrap.distR = distR;\n\n return wrap;\n}\n\n// ============================================================================\n// TRANSFORM PARSING\n// ============================================================================\n\n/**\n * Parse transform properties from a:xfrm\n */\nfunction parseTransform(xfrm: XmlElement | null): ImageTransform | undefined {\n if (!xfrm) return undefined;\n\n const rot = getAttribute(xfrm, null, 'rot');\n const flipH = getAttribute(xfrm, null, 'flipH') === '1';\n const flipV = getAttribute(xfrm, null, 'flipV') === '1';\n\n const rotation = rotToDegrees(rot);\n\n if (rotation === undefined && !flipH && !flipV) {\n return undefined;\n }\n\n const transform: ImageTransform = {};\n if (rotation !== undefined) transform.rotation = rotation;\n if (flipH) transform.flipH = true;\n if (flipV) transform.flipV = true;\n\n return transform;\n}\n\n// ============================================================================\n// BLIP EXTRACTION (image relationship ID)\n// ============================================================================\n\n/**\n * Find the a:blip element and extract the relationship ID\n *\n * Path: a:graphic > a:graphicData > pic:pic > pic:blipFill > a:blip\n */\nfunction findBlipElement(container: XmlElement): XmlElement | null {\n // Find a:graphic\n const graphic = findByFullName(container, 'a:graphic');\n if (!graphic) return null;\n\n // Find a:graphicData\n const graphicData = findByFullName(graphic, 'a:graphicData');\n if (!graphicData) return null;\n\n // Find pic:pic\n const pic = findByFullName(graphicData, 'pic:pic');\n if (!pic) return null;\n\n // Find pic:blipFill\n const blipFill = findByFullName(pic, 'pic:blipFill');\n if (!blipFill) return null;\n\n // Find a:blip\n const blip = findByFullName(blipFill, 'a:blip');\n return blip;\n}\n\n/**\n * Extract rId from a:blip element\n */\nfunction extractBlipRId(blip: XmlElement | null): string {\n if (!blip) return '';\n\n // The rId is in r:embed attribute\n const rEmbed = getAttribute(blip, 'r', 'embed');\n if (rEmbed) return rEmbed;\n\n // Sometimes it's just \"embed\" without namespace\n const embed = getAttribute(blip, null, 'embed');\n if (embed) return embed;\n\n // Check r:link for linked (not embedded) images\n const rLink = getAttribute(blip, 'r', 'link');\n if (rLink) return rLink;\n\n return '';\n}\n\n/**\n * Find transform (a:xfrm) from picture shape properties\n *\n * Path: a:graphic > a:graphicData > pic:pic > pic:spPr > a:xfrm\n */\nfunction findPictureTransform(container: XmlElement): XmlElement | null {\n const graphic = findByFullName(container, 'a:graphic');\n if (!graphic) return null;\n\n const graphicData = findByFullName(graphic, 'a:graphicData');\n if (!graphicData) return null;\n\n const pic = findByFullName(graphicData, 'pic:pic');\n if (!pic) return null;\n\n const spPr = findByFullName(pic, 'pic:spPr');\n if (!spPr) return null;\n\n const xfrm = findByFullName(spPr, 'a:xfrm');\n return xfrm;\n}\n\n// ============================================================================\n// MEDIA RESOLUTION\n// ============================================================================\n\n/**\n * Normalize a target path to the standard word/media/... format\n */\nfunction normalizeMediaPath(targetPath: string): string {\n if (!targetPath) return targetPath;\n\n // Remove leading slashes\n let normalized = targetPath.replace(/^\\/+/, '');\n\n // Ensure word/ prefix for media files\n if (normalized.startsWith('media/')) {\n normalized = `word/${normalized}`;\n } else if (!normalized.startsWith('word/')) {\n normalized = `word/${normalized}`;\n }\n\n return normalized;\n}\n\n/**\n * Get MIME type from file extension\n */\nfunction getMimeType(path: string): string {\n const ext = path.split('.').pop()?.toLowerCase() ?? '';\n\n const mimeTypes: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n bmp: 'image/bmp',\n tiff: 'image/tiff',\n tif: 'image/tiff',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n emf: 'image/x-emf',\n wmf: 'image/x-wmf',\n };\n\n return mimeTypes[ext] ?? 'application/octet-stream';\n}\n\n/**\n * Resolve image data from relationships and media map\n *\n * @param rId - Relationship ID (e.g., \"rId1\")\n * @param rels - Relationship map\n * @param media - Media files map\n * @returns Object with src (data URL or blob), mimeType, and filename\n */\nfunction resolveImageData(\n rId: string,\n rels: RelationshipMap | undefined,\n media: Map<string, MediaFile> | undefined\n): { src?: string; mimeType?: string; filename?: string } {\n if (!rId || !rels) {\n return {};\n }\n\n const rel = rels.get(rId);\n if (!rel) {\n return {};\n }\n\n // Get the target path\n const targetPath = rel.target;\n if (!targetPath) {\n return {};\n }\n\n // Normalize the path\n const normalizedPath = normalizeMediaPath(targetPath);\n const filename = targetPath.split('/').pop();\n\n // Case-insensitive lookup helper for media map\n const findMediaCaseInsensitive = (\n map: Map<string, MediaFile>,\n searchPath: string\n ): MediaFile | undefined => {\n const lowerPath = searchPath.toLowerCase();\n for (const [key, value] of map.entries()) {\n if (key.toLowerCase() === lowerPath) {\n return value;\n }\n }\n return undefined;\n };\n\n // Try to find the media file (case-insensitive)\n if (media) {\n // Try normalized path first\n const mediaFile = findMediaCaseInsensitive(media, normalizedPath);\n if (mediaFile) {\n return {\n src: mediaFile.dataUrl || mediaFile.base64, // Use data URL or base64\n mimeType: mediaFile.mimeType,\n filename,\n };\n }\n\n // Try without word/ prefix\n const altPath = targetPath.replace(/^\\/+/, '');\n const altMediaFile = findMediaCaseInsensitive(media, altPath);\n if (altMediaFile) {\n return {\n src: altMediaFile.dataUrl || altMediaFile.base64,\n mimeType: altMediaFile.mimeType,\n filename,\n };\n }\n\n // Try with word/ prefix added\n const withWordPrefix = `word/${altPath}`;\n const prefixedMediaFile = findMediaCaseInsensitive(media, withWordPrefix);\n if (prefixedMediaFile) {\n return {\n src: prefixedMediaFile.dataUrl || prefixedMediaFile.base64,\n mimeType: prefixedMediaFile.mimeType,\n filename,\n };\n }\n }\n\n // Return at least the MIME type based on extension\n return {\n mimeType: getMimeType(targetPath),\n filename,\n };\n}\n\n// ============================================================================\n// MAIN PARSING FUNCTIONS\n// ============================================================================\n\n/**\n * Parse a wp:inline element (inline image)\n *\n * @param inlineEl - The wp:inline element\n * @param rels - Relationship map for resolving rId\n * @param media - Media files map\n * @returns Parsed Image object\n */\nfunction parseInline(\n inlineEl: XmlElement,\n rels: RelationshipMap | undefined,\n media: Map<string, MediaFile> | undefined\n): Image {\n // Parse extent (size)\n const extent = findByFullName(inlineEl, 'wp:extent');\n const size = parseExtent(extent);\n\n // Parse effect extent\n const effectExtent = findByFullName(inlineEl, 'wp:effectExtent');\n const padding = parseEffectExtent(effectExtent);\n\n // Parse document properties\n const docPr = findByFullName(inlineEl, 'wp:docPr');\n const props = parseDocProps(docPr);\n\n // Find blip and extract rId\n const blip = findBlipElement(inlineEl);\n const rId = extractBlipRId(blip);\n\n // Resolve image data\n const imageData = resolveImageData(rId, rels, media);\n\n // Find transform\n const xfrm = findPictureTransform(inlineEl);\n const transform = parseTransform(xfrm);\n\n const image: Image = {\n type: 'image',\n rId,\n size,\n wrap: { type: 'inline' },\n };\n\n // Add optional properties\n if (props.id) image.id = props.id;\n if (props.alt) image.alt = props.alt;\n if (props.title) image.title = props.title;\n if (props.decorative) image.decorative = true;\n if (imageData.src) image.src = imageData.src;\n if (imageData.mimeType) image.mimeType = imageData.mimeType;\n if (imageData.filename) image.filename = imageData.filename;\n if (padding) image.padding = padding;\n if (transform) image.transform = transform;\n\n return image;\n}\n\n/**\n * Parse a wp:anchor element (floating/anchored image)\n *\n * @param anchorEl - The wp:anchor element\n * @param rels - Relationship map for resolving rId\n * @param media - Media files map\n * @returns Parsed Image object\n */\nfunction parseAnchor(\n anchorEl: XmlElement,\n rels: RelationshipMap | undefined,\n media: Map<string, MediaFile> | undefined\n): Image {\n // Parse extent (size)\n const extent = findByFullName(anchorEl, 'wp:extent');\n const size = parseExtent(extent);\n\n // Parse effect extent\n const effectExtent = findByFullName(anchorEl, 'wp:effectExtent');\n const padding = parseEffectExtent(effectExtent);\n\n // Parse document properties\n const docPr = findByFullName(anchorEl, 'wp:docPr');\n const props = parseDocProps(docPr);\n\n // Check behindDoc attribute\n const behindDoc = getAttribute(anchorEl, null, 'behindDoc') === '1';\n\n // Parse wrap element\n const wrapEl = findAnyOf(anchorEl, WRAP_ELEMENTS);\n const wrap = parseWrapElement(wrapEl, behindDoc);\n\n // Parse position\n const posH = findByFullName(anchorEl, 'wp:positionH');\n const posV = findByFullName(anchorEl, 'wp:positionV');\n const horizontal = parsePositionH(posH);\n const vertical = parsePositionV(posV);\n\n let position: ImagePosition | undefined;\n if (horizontal || vertical) {\n position = {\n horizontal: horizontal ?? { relativeTo: 'column' },\n vertical: vertical ?? { relativeTo: 'paragraph' },\n };\n }\n\n // Find blip and extract rId\n const blip = findBlipElement(anchorEl);\n const rId = extractBlipRId(blip);\n\n // Resolve image data\n const imageData = resolveImageData(rId, rels, media);\n\n // Find transform\n const xfrm = findPictureTransform(anchorEl);\n const transform = parseTransform(xfrm);\n\n const image: Image = {\n type: 'image',\n rId,\n size,\n wrap,\n };\n\n // Add optional properties\n if (props.id) image.id = props.id;\n if (props.alt) image.alt = props.alt;\n if (props.title) image.title = props.title;\n if (props.decorative) image.decorative = true;\n if (imageData.src) image.src = imageData.src;\n if (imageData.mimeType) image.mimeType = imageData.mimeType;\n if (imageData.filename) image.filename = imageData.filename;\n if (position) image.position = position;\n if (padding) image.padding = padding;\n if (transform) image.transform = transform;\n\n return image;\n}\n\n/**\n * Parse a w:drawing element\n *\n * The drawing element contains either wp:inline or wp:anchor.\n *\n * @param drawingEl - The w:drawing element\n * @param rels - Relationship map for resolving rId\n * @param media - Media files map\n * @returns Parsed Image object or null if not an image\n */\nexport function parseDrawing(\n drawingEl: XmlElement,\n rels: RelationshipMap | undefined,\n media: Map<string, MediaFile> | undefined\n): Image | null {\n const children = getChildElements(drawingEl);\n\n for (const child of children) {\n const name = child.name || '';\n\n if (name === 'wp:inline') {\n return parseInline(child, rels, media);\n }\n\n if (name === 'wp:anchor') {\n return parseAnchor(child, rels, media);\n }\n }\n\n return null;\n}\n\n/**\n * Parse an image from a w:drawing element\n *\n * This is the main entry point for image parsing.\n *\n * @param node - The w:drawing XML element\n * @param rels - Relationship map for resolving rId\n * @param media - Media files map\n * @returns Parsed Image object or null if parsing fails\n */\nexport function parseImage(\n node: XmlElement,\n rels: RelationshipMap | undefined,\n media: Map<string, MediaFile> | undefined\n): Image | null {\n return parseDrawing(node, rels, media);\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Check if an image is inline (not floating)\n */\nexport function isInlineImage(image: Image): boolean {\n return image.wrap.type === 'inline';\n}\n\n/**\n * Check if an image is floating (anchored)\n */\nexport function isFloatingImage(image: Image): boolean {\n return image.wrap.type !== 'inline';\n}\n\n/**\n * Check if an image is behind text\n */\nexport function isBehindText(image: Image): boolean {\n return image.wrap.type === 'behind';\n}\n\n/**\n * Check if an image is in front of text\n */\nexport function isInFrontOfText(image: Image): boolean {\n return image.wrap.type === 'inFront';\n}\n\n/**\n * Get image width in pixels\n */\nexport function getImageWidthPx(image: Image): number {\n return emuToPixels(image.size.width);\n}\n\n/**\n * Get image height in pixels\n */\nexport function getImageHeightPx(image: Image): number {\n return emuToPixels(image.size.height);\n}\n\n/**\n * Get image dimensions in pixels\n */\nexport function getImageDimensionsPx(image: Image): { width: number; height: number } {\n return {\n width: emuToPixels(image.size.width),\n height: emuToPixels(image.size.height),\n };\n}\n\n/**\n * Check if image has alt text (for accessibility)\n */\nexport function hasAltText(image: Image): boolean {\n return !!image.alt && image.alt.trim().length > 0;\n}\n\n/**\n * Check if image is decorative (should be ignored by screen readers)\n */\nexport function isDecorativeImage(image: Image): boolean {\n return image.decorative === true;\n}\n\n/**\n * Get wrap distances in pixels\n */\nexport function getWrapDistancesPx(image: Image): {\n top: number;\n bottom: number;\n left: number;\n right: number;\n} {\n return {\n top: emuToPixels(image.wrap.distT),\n bottom: emuToPixels(image.wrap.distB),\n left: emuToPixels(image.wrap.distL),\n right: emuToPixels(image.wrap.distR),\n };\n}\n\n/**\n * Check if image needs text wrapping\n */\nexport function needsTextWrapping(image: Image): boolean {\n const wrapTypes = ['square', 'tight', 'through', 'topAndBottom'];\n return wrapTypes.includes(image.wrap.type);\n}\n","/**\n * Run Parser - Parse text runs (w:r) with complete formatting\n *\n * A run is a contiguous region of text with the same character formatting.\n * Runs can contain:\n * - Text (w:t)\n * - Tabs (w:tab)\n * - Line breaks (w:br)\n * - Symbols (w:sym)\n * - Footnote/endnote references\n * - Field characters\n * - Drawings/images (w:drawing)\n * - And more...\n *\n * OOXML Reference:\n * - Run: w:r\n * - Run properties: w:rPr\n * - Text content: w:t\n */\n\nimport type {\n Run,\n RunContent,\n TextContent,\n TabContent,\n BreakContent,\n SymbolContent,\n NoteReferenceContent,\n FieldCharContent,\n InstrTextContent,\n SoftHyphenContent,\n NoBreakHyphenContent,\n DrawingContent,\n TextFormatting,\n ColorValue,\n ShadingProperties,\n UnderlineStyle,\n Theme,\n Image,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport {\n findChild,\n getAttribute,\n getChildElements,\n getTextContent,\n parseBooleanElement,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\nimport { resolveThemeFontRef } from './themeParser';\nimport { parseImage } from './imageParser';\n\n/**\n * Parse color value from attributes\n */\nfunction parseColorValue(\n rgb: string | null,\n themeColor: string | null,\n themeTint: string | null,\n themeShade: string | null\n): ColorValue {\n const color: ColorValue = {};\n\n if (rgb && rgb !== 'auto') {\n color.rgb = rgb;\n } else if (rgb === 'auto') {\n color.auto = true;\n }\n\n if (themeColor) {\n color.themeColor = themeColor as ColorValue['themeColor'];\n }\n\n if (themeTint) {\n color.themeTint = themeTint;\n }\n\n if (themeShade) {\n color.themeShade = themeShade;\n }\n\n return color;\n}\n\n/**\n * Parse shading properties (w:shd)\n */\nfunction parseShadingProperties(shd: XmlElement | null): ShadingProperties | undefined {\n if (!shd) return undefined;\n\n const props: ShadingProperties = {};\n\n const color = getAttribute(shd, 'w', 'color');\n if (color && color !== 'auto') {\n props.color = { rgb: color };\n }\n\n const fill = getAttribute(shd, 'w', 'fill');\n if (fill && fill !== 'auto') {\n props.fill = { rgb: fill };\n }\n\n const themeFill = getAttribute(shd, 'w', 'themeFill');\n if (themeFill) {\n props.fill = props.fill || {};\n props.fill.themeColor = themeFill as ColorValue['themeColor'];\n }\n\n const themeFillTint = getAttribute(shd, 'w', 'themeFillTint');\n if (themeFillTint && props.fill) {\n props.fill.themeTint = themeFillTint;\n }\n\n const themeFillShade = getAttribute(shd, 'w', 'themeFillShade');\n if (themeFillShade && props.fill) {\n props.fill.themeShade = themeFillShade;\n }\n\n const pattern = getAttribute(shd, 'w', 'val');\n if (pattern) {\n props.pattern = pattern as ShadingProperties['pattern'];\n }\n\n return Object.keys(props).length > 0 ? props : undefined;\n}\n\n/**\n * Parse run formatting properties (w:rPr)\n *\n * Handles ALL rPr properties:\n * - w:b (bold), w:i (italic), w:u (underline with style)\n * - w:strike (strikethrough), w:dstrike (double strike)\n * - w:vertAlign (superscript/subscript)\n * - w:smallCaps, w:caps (capitalization)\n * - w:highlight (text highlight color)\n * - w:shd (character shading)\n * - w:color (text color with theme resolution)\n * - w:sz (font size in half-points)\n * - w:rFonts (font family with theme resolution)\n * - w:spacing (character spacing)\n * - w:effect (text effects)\n * - And more...\n */\nexport function parseRunProperties(\n rPr: XmlElement | null,\n theme: Theme | null,\n _styles?: StyleMap\n): TextFormatting | undefined {\n if (!rPr) return undefined;\n\n const formatting: TextFormatting = {};\n\n // Bold (w:b)\n const b = findChild(rPr, 'w', 'b');\n if (b) formatting.bold = parseBooleanElement(b);\n\n const bCs = findChild(rPr, 'w', 'bCs');\n if (bCs) formatting.boldCs = parseBooleanElement(bCs);\n\n // Italic (w:i)\n const i = findChild(rPr, 'w', 'i');\n if (i) formatting.italic = parseBooleanElement(i);\n\n const iCs = findChild(rPr, 'w', 'iCs');\n if (iCs) formatting.italicCs = parseBooleanElement(iCs);\n\n // Underline (w:u)\n const u = findChild(rPr, 'w', 'u');\n if (u) {\n const style = getAttribute(u, 'w', 'val') as UnderlineStyle | null;\n if (style) {\n formatting.underline = { style };\n const colorVal = getAttribute(u, 'w', 'color');\n const themeColor = getAttribute(u, 'w', 'themeColor');\n if (colorVal || themeColor) {\n formatting.underline.color = parseColorValue(\n colorVal,\n themeColor,\n getAttribute(u, 'w', 'themeTint'),\n getAttribute(u, 'w', 'themeShade')\n );\n }\n }\n }\n\n // Strikethrough (w:strike)\n const strike = findChild(rPr, 'w', 'strike');\n if (strike) formatting.strike = parseBooleanElement(strike);\n\n // Double strikethrough (w:dstrike)\n const dstrike = findChild(rPr, 'w', 'dstrike');\n if (dstrike) formatting.doubleStrike = parseBooleanElement(dstrike);\n\n // Vertical alignment - superscript/subscript (w:vertAlign)\n const vertAlign = findChild(rPr, 'w', 'vertAlign');\n if (vertAlign) {\n const val = getAttribute(vertAlign, 'w', 'val');\n if (val === 'superscript' || val === 'subscript' || val === 'baseline') {\n formatting.vertAlign = val;\n }\n }\n\n // Small caps (w:smallCaps)\n const smallCaps = findChild(rPr, 'w', 'smallCaps');\n if (smallCaps) formatting.smallCaps = parseBooleanElement(smallCaps);\n\n // All caps (w:caps)\n const caps = findChild(rPr, 'w', 'caps');\n if (caps) formatting.allCaps = parseBooleanElement(caps);\n\n // Hidden text (w:vanish)\n const vanish = findChild(rPr, 'w', 'vanish');\n if (vanish) formatting.hidden = parseBooleanElement(vanish);\n\n // Text color (w:color)\n const color = findChild(rPr, 'w', 'color');\n if (color) {\n formatting.color = parseColorValue(\n getAttribute(color, 'w', 'val'),\n getAttribute(color, 'w', 'themeColor'),\n getAttribute(color, 'w', 'themeTint'),\n getAttribute(color, 'w', 'themeShade')\n );\n }\n\n // Highlight color (w:highlight)\n const highlight = findChild(rPr, 'w', 'highlight');\n if (highlight) {\n const val = getAttribute(highlight, 'w', 'val');\n if (val) {\n formatting.highlight = val as TextFormatting['highlight'];\n }\n }\n\n // Character shading (w:shd)\n const shd = findChild(rPr, 'w', 'shd');\n if (shd) {\n formatting.shading = parseShadingProperties(shd);\n }\n\n // Font size in half-points (w:sz)\n const sz = findChild(rPr, 'w', 'sz');\n if (sz) {\n const val = parseNumericAttribute(sz, 'w', 'val');\n if (val !== undefined) formatting.fontSize = val;\n }\n\n // Font size complex script (w:szCs)\n const szCs = findChild(rPr, 'w', 'szCs');\n if (szCs) {\n const val = parseNumericAttribute(szCs, 'w', 'val');\n if (val !== undefined) formatting.fontSizeCs = val;\n }\n\n // Font family (w:rFonts)\n const rFonts = findChild(rPr, 'w', 'rFonts');\n if (rFonts) {\n formatting.fontFamily = {\n ascii: getAttribute(rFonts, 'w', 'ascii') ?? undefined,\n hAnsi: getAttribute(rFonts, 'w', 'hAnsi') ?? undefined,\n eastAsia: getAttribute(rFonts, 'w', 'eastAsia') ?? undefined,\n cs: getAttribute(rFonts, 'w', 'cs') ?? undefined,\n };\n\n // Theme font references\n const asciiTheme = getAttribute(rFonts, 'w', 'asciiTheme');\n if (asciiTheme) {\n formatting.fontFamily.asciiTheme = asciiTheme as TextFormatting['fontFamily'] extends {\n asciiTheme?: infer T;\n }\n ? T\n : never;\n // Also resolve the actual font name for convenience\n if (theme && !formatting.fontFamily.ascii) {\n formatting.fontFamily.ascii = resolveThemeFontRef(theme, asciiTheme);\n }\n }\n\n const hAnsiTheme = getAttribute(rFonts, 'w', 'hAnsiTheme');\n if (hAnsiTheme) {\n formatting.fontFamily.hAnsiTheme = hAnsiTheme;\n if (theme && !formatting.fontFamily.hAnsi) {\n formatting.fontFamily.hAnsi = resolveThemeFontRef(theme, hAnsiTheme);\n }\n }\n\n const eastAsiaTheme = getAttribute(rFonts, 'w', 'eastAsiaTheme');\n if (eastAsiaTheme) {\n formatting.fontFamily.eastAsiaTheme = eastAsiaTheme;\n if (theme && !formatting.fontFamily.eastAsia) {\n formatting.fontFamily.eastAsia = resolveThemeFontRef(theme, eastAsiaTheme);\n }\n }\n\n const csTheme = getAttribute(rFonts, 'w', 'cstheme');\n if (csTheme) {\n formatting.fontFamily.csTheme = csTheme;\n if (theme && !formatting.fontFamily.cs) {\n formatting.fontFamily.cs = resolveThemeFontRef(theme, csTheme);\n }\n }\n }\n\n // Character spacing in twips (w:spacing)\n const spacing = findChild(rPr, 'w', 'spacing');\n if (spacing) {\n const val = parseNumericAttribute(spacing, 'w', 'val');\n if (val !== undefined) formatting.spacing = val;\n }\n\n // Position - raised/lowered in half-points (w:position)\n const position = findChild(rPr, 'w', 'position');\n if (position) {\n const val = parseNumericAttribute(position, 'w', 'val');\n if (val !== undefined) formatting.position = val;\n }\n\n // Horizontal text scale percentage (w:w)\n const w = findChild(rPr, 'w', 'w');\n if (w) {\n const val = parseNumericAttribute(w, 'w', 'val');\n if (val !== undefined) formatting.scale = val;\n }\n\n // Kerning threshold in half-points (w:kern)\n const kern = findChild(rPr, 'w', 'kern');\n if (kern) {\n const val = parseNumericAttribute(kern, 'w', 'val');\n if (val !== undefined) formatting.kerning = val;\n }\n\n // Text effect animation (w:effect)\n const effect = findChild(rPr, 'w', 'effect');\n if (effect) {\n const val = getAttribute(effect, 'w', 'val');\n if (val) formatting.effect = val as TextFormatting['effect'];\n }\n\n // Emphasis mark (w:em)\n const em = findChild(rPr, 'w', 'em');\n if (em) {\n const val = getAttribute(em, 'w', 'val');\n if (val) formatting.emphasisMark = val as TextFormatting['emphasisMark'];\n }\n\n // Emboss effect (w:emboss)\n const emboss = findChild(rPr, 'w', 'emboss');\n if (emboss) formatting.emboss = parseBooleanElement(emboss);\n\n // Imprint/engrave effect (w:imprint)\n const imprint = findChild(rPr, 'w', 'imprint');\n if (imprint) formatting.imprint = parseBooleanElement(imprint);\n\n // Outline effect (w:outline)\n const outline = findChild(rPr, 'w', 'outline');\n if (outline) formatting.outline = parseBooleanElement(outline);\n\n // Shadow effect (w:shadow)\n const shadow = findChild(rPr, 'w', 'shadow');\n if (shadow) formatting.shadow = parseBooleanElement(shadow);\n\n // Right-to-left text (w:rtl)\n const rtl = findChild(rPr, 'w', 'rtl');\n if (rtl) formatting.rtl = parseBooleanElement(rtl);\n\n // Complex script formatting (w:cs)\n const cs = findChild(rPr, 'w', 'cs');\n if (cs) formatting.cs = parseBooleanElement(cs);\n\n // Character style reference (w:rStyle)\n const rStyle = findChild(rPr, 'w', 'rStyle');\n if (rStyle) {\n const val = getAttribute(rStyle, 'w', 'val');\n if (val) formatting.styleId = val;\n }\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n/**\n * Parse text content (w:t)\n */\nfunction parseTextContent(element: XmlElement): TextContent {\n const text = getTextContent(element);\n const preserveSpace = getAttribute(element, 'xml', 'space') === 'preserve';\n\n return {\n type: 'text',\n text,\n preserveSpace: preserveSpace || undefined,\n };\n}\n\n/**\n * Parse tab element (w:tab)\n */\nfunction parseTabContent(): TabContent {\n return { type: 'tab' };\n}\n\n/**\n * Parse break element (w:br)\n */\nfunction parseBreakContent(element: XmlElement): BreakContent {\n const breakType = getAttribute(element, 'w', 'type');\n const clear = getAttribute(element, 'w', 'clear');\n\n const content: BreakContent = { type: 'break' };\n\n if (breakType === 'page' || breakType === 'column' || breakType === 'textWrapping') {\n content.breakType = breakType;\n }\n\n if (clear === 'none' || clear === 'left' || clear === 'right' || clear === 'all') {\n content.clear = clear;\n }\n\n return content;\n}\n\n/**\n * Parse symbol element (w:sym)\n */\nfunction parseSymbolContent(element: XmlElement): SymbolContent {\n const font = getAttribute(element, 'w', 'font') ?? '';\n const char = getAttribute(element, 'w', 'char') ?? '';\n\n return {\n type: 'symbol',\n font,\n char,\n };\n}\n\n/**\n * Parse footnote reference (w:footnoteReference)\n */\nfunction parseFootnoteReference(element: XmlElement): NoteReferenceContent {\n const id = parseNumericAttribute(element, 'w', 'id') ?? 0;\n\n return {\n type: 'footnoteRef',\n id,\n };\n}\n\n/**\n * Parse endnote reference (w:endnoteReference)\n */\nfunction parseEndnoteReference(element: XmlElement): NoteReferenceContent {\n const id = parseNumericAttribute(element, 'w', 'id') ?? 0;\n\n return {\n type: 'endnoteRef',\n id,\n };\n}\n\n/**\n * Parse field character (w:fldChar)\n */\nfunction parseFieldChar(element: XmlElement): FieldCharContent {\n const fldCharType = getAttribute(element, 'w', 'fldCharType');\n const fldLock =\n getAttribute(element, 'w', 'fldLock') === 'true' ||\n getAttribute(element, 'w', 'fldLock') === '1';\n const dirty =\n getAttribute(element, 'w', 'dirty') === 'true' || getAttribute(element, 'w', 'dirty') === '1';\n\n let charType: FieldCharContent['charType'] = 'begin';\n if (fldCharType === 'separate') charType = 'separate';\n else if (fldCharType === 'end') charType = 'end';\n\n return {\n type: 'fieldChar',\n charType,\n fldLock: fldLock || undefined,\n dirty: dirty || undefined,\n };\n}\n\n/**\n * Parse instruction text (w:instrText)\n */\nfunction parseInstrText(element: XmlElement): InstrTextContent {\n const text = getTextContent(element);\n\n return {\n type: 'instrText',\n text,\n };\n}\n\n/**\n * Parse drawing content (w:drawing)\n *\n * Uses imageParser to fully parse the drawing element including\n * image data resolution from relationships and media files.\n */\nfunction parseDrawingContent(\n element: XmlElement,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): DrawingContent | null {\n // Use the full imageParser to parse the drawing\n const image = parseImage(element, rels ?? undefined, media ?? undefined);\n\n if (!image) {\n return null;\n }\n\n return {\n type: 'drawing',\n image,\n };\n}\n\n/**\n * Get the local name of an element (without namespace prefix)\n */\nfunction getLocalName(name: string | undefined): string {\n if (!name) return '';\n const colonIndex = name.indexOf(':');\n return colonIndex >= 0 ? name.substring(colonIndex + 1) : name;\n}\n\n/**\n * Parse all content within a run element\n */\nfunction parseRunContents(\n runElement: XmlElement,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): RunContent[] {\n const contents: RunContent[] = [];\n const children = getChildElements(runElement);\n\n for (const child of children) {\n const localName = getLocalName(child.name);\n\n switch (localName) {\n case 't':\n // Text content\n contents.push(parseTextContent(child));\n break;\n\n case 'tab':\n // Tab character\n contents.push(parseTabContent());\n break;\n\n case 'br':\n // Line/page/column break\n contents.push(parseBreakContent(child));\n break;\n\n case 'sym':\n // Symbol character\n contents.push(parseSymbolContent(child));\n break;\n\n case 'footnoteReference':\n // Footnote reference\n contents.push(parseFootnoteReference(child));\n break;\n\n case 'endnoteReference':\n // Endnote reference\n contents.push(parseEndnoteReference(child));\n break;\n\n case 'fldChar':\n // Field character (begin/separate/end)\n contents.push(parseFieldChar(child));\n break;\n\n case 'instrText':\n // Field instruction text\n contents.push(parseInstrText(child));\n break;\n\n case 'softHyphen':\n // Soft hyphen\n contents.push({ type: 'softHyphen' } as SoftHyphenContent);\n break;\n\n case 'noBreakHyphen':\n // Non-breaking hyphen\n contents.push({ type: 'noBreakHyphen' } as NoBreakHyphenContent);\n break;\n\n case 'drawing':\n // Drawing/image\n const drawing = parseDrawingContent(child, rels, media);\n if (drawing) {\n contents.push(drawing);\n }\n break;\n\n case 'pict':\n case 'object':\n // Legacy VML pictures/objects - will handle in shape parser\n // For now, skip these\n break;\n\n case 'rPr':\n // Run properties - already handled separately\n break;\n\n case 'lastRenderedPageBreak':\n // Marker for last rendered page break - informational only\n break;\n\n case 'cr':\n // Carriage return - treat as line break\n contents.push({ type: 'break', breakType: 'textWrapping' } as BreakContent);\n break;\n\n case 'footnoteRef':\n case 'endnoteRef':\n // These are the actual footnote/endnote content markers (different from Reference)\n // They appear in the footnote/endnote text itself\n break;\n\n case 'separator':\n case 'continuationSeparator':\n // Footnote/endnote separators\n break;\n\n default:\n // Unknown element - log for debugging if needed\n // console.log(`Unknown run content element: ${localName}`);\n break;\n }\n }\n\n return contents;\n}\n\n/**\n * Parse a run element (w:r)\n *\n * @param node - The w:r XML element\n * @param styles - Style map for resolving style references\n * @param theme - Theme for resolving theme colors/fonts\n * @param rels - Relationship map for resolving image references\n * @param media - Media files map for image data\n * @returns Parsed Run object\n */\nexport function parseRun(\n node: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): Run {\n const run: Run = {\n type: 'run',\n content: [],\n };\n\n // Parse run properties (w:rPr)\n const rPr = findChild(node, 'w', 'rPr');\n if (rPr) {\n run.formatting = parseRunProperties(rPr, theme, styles ?? undefined);\n }\n\n // Parse run contents (text, tabs, breaks, images, etc.)\n run.content = parseRunContents(node, rels, media);\n\n return run;\n}\n\n/**\n * Get plain text from a run\n *\n * @param run - Parsed Run object\n * @returns Concatenated text content\n */\nexport function getRunText(run: Run): string {\n let text = '';\n\n for (const content of run.content) {\n if (content.type === 'text') {\n text += content.text;\n } else if (content.type === 'tab') {\n text += '\\t';\n } else if (content.type === 'break') {\n if (content.breakType === 'page') {\n text += '\\f'; // Form feed for page break\n } else {\n text += '\\n';\n }\n } else if (content.type === 'softHyphen') {\n text += '\\u00AD'; // Soft hyphen Unicode\n } else if (content.type === 'noBreakHyphen') {\n text += '\\u2011'; // Non-breaking hyphen Unicode\n }\n }\n\n return text;\n}\n\n/**\n * Check if a run contains any actual content\n *\n * @param run - Parsed Run object\n * @returns true if run has visible content\n */\nexport function hasContent(run: Run): boolean {\n return run.content.length > 0;\n}\n\n/**\n * Check if a run contains a drawing/image\n *\n * @param run - Parsed Run object\n * @returns true if run contains an image\n */\nexport function hasImage(run: Run): boolean {\n return run.content.some((c) => c.type === 'drawing');\n}\n\n/**\n * Get all images from a run\n *\n * @param run - Parsed Run object\n * @returns Array of Image objects\n */\nexport function getImages(run: Run): Image[] {\n return run.content.filter((c): c is DrawingContent => c.type === 'drawing').map((c) => c.image);\n}\n\n/**\n * Check if a run is part of a complex field\n *\n * @param run - Parsed Run object\n * @returns true if run contains field characters\n */\nexport function hasFieldChar(run: Run): boolean {\n return run.content.some((c) => c.type === 'fieldChar');\n}\n\n/**\n * Get field character type if present\n *\n * @param run - Parsed Run object\n * @returns Field character type or null\n */\nexport function getFieldCharType(run: Run): 'begin' | 'separate' | 'end' | null {\n const fieldChar = run.content.find((c): c is FieldCharContent => c.type === 'fieldChar');\n return fieldChar?.charType ?? null;\n}\n","/**\n * Hyperlink Parser - Parse hyperlinks (w:hyperlink) with URL resolution\n *\n * OOXML Reference:\n * - Hyperlink element: w:hyperlink\n * - Attributes:\n * - r:id - Relationship ID for external link (resolves via .rels)\n * - w:anchor - Internal bookmark name\n * - w:tooltip - Tooltip/title text\n * - w:tgtFrame - Target frame (_blank, _self, etc.)\n * - w:history - Whether to add to history\n * - w:docLocation - Location within a document\n *\n * External links use r:id to reference a relationship in document.xml.rels\n * Internal links use w:anchor to reference a bookmark in the same document\n */\n\nimport type {\n Hyperlink,\n Run,\n BookmarkStart,\n BookmarkEnd,\n Theme,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport {\n getAttribute,\n getChildElements,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\nimport { parseRun } from './runParser';\nimport { isExternalHyperlink } from './relsParser';\n\n// ============================================================================\n// HYPERLINK PARSER\n// ============================================================================\n\n/**\n * Get the local name of an element (without namespace prefix)\n */\nfunction getLocalName(name: string | undefined): string {\n if (!name) return '';\n const colonIndex = name.indexOf(':');\n return colonIndex >= 0 ? name.substring(colonIndex + 1) : name;\n}\n\n/**\n * Parse bookmark start (w:bookmarkStart)\n *\n * Used for internal hyperlink targets within the document.\n */\nfunction parseBookmarkStart(node: XmlElement): BookmarkStart {\n const id = parseNumericAttribute(node, 'w', 'id') ?? 0;\n const name = getAttribute(node, 'w', 'name') ?? '';\n\n const bookmark: BookmarkStart = {\n type: 'bookmarkStart',\n id,\n name,\n };\n\n // Table column bookmarks\n const colFirst = parseNumericAttribute(node, 'w', 'colFirst');\n if (colFirst !== undefined) bookmark.colFirst = colFirst;\n\n const colLast = parseNumericAttribute(node, 'w', 'colLast');\n if (colLast !== undefined) bookmark.colLast = colLast;\n\n return bookmark;\n}\n\n/**\n * Parse bookmark end (w:bookmarkEnd)\n */\nfunction parseBookmarkEnd(node: XmlElement): BookmarkEnd {\n const id = parseNumericAttribute(node, 'w', 'id') ?? 0;\n\n return {\n type: 'bookmarkEnd',\n id,\n };\n}\n\n/**\n * Parse a hyperlink element (w:hyperlink)\n *\n * Handles both external links (via r:id relationship) and internal\n * links (via w:anchor bookmark reference).\n *\n * @param node - The w:hyperlink XML element\n * @param rels - Relationship map to resolve r:id references\n * @param styles - Style map for resolving run styles\n * @param theme - Theme for resolving colors/fonts\n * @param media - Media files map for image data\n * @returns Parsed Hyperlink object\n */\nexport function parseHyperlink(\n node: XmlElement,\n rels: RelationshipMap | null,\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n media: Map<string, MediaFile> | null = null\n): Hyperlink {\n const hyperlink: Hyperlink = {\n type: 'hyperlink',\n children: [],\n };\n\n // === External Link (r:id) ===\n // Get relationship ID for external links\n const rId = getAttribute(node, 'r', 'id');\n if (rId) {\n hyperlink.rId = rId;\n\n // Resolve the relationship to get the actual URL\n if (rels) {\n const rel = rels.get(rId);\n if (rel) {\n // External hyperlinks have TargetMode=\"External\" and target is the URL\n if (isExternalHyperlink(rel)) {\n hyperlink.href = rel.target;\n } else {\n // Internal document link (to another part of the DOCX)\n hyperlink.href = rel.target;\n }\n }\n }\n }\n\n // === Internal Bookmark Link (w:anchor) ===\n // Get internal bookmark anchor\n const anchor = getAttribute(node, 'w', 'anchor');\n if (anchor) {\n hyperlink.anchor = anchor;\n // For internal links, create a fragment-style href\n if (!hyperlink.href) {\n hyperlink.href = `#${anchor}`;\n }\n }\n\n // === Tooltip ===\n const tooltip = getAttribute(node, 'w', 'tooltip');\n if (tooltip) {\n hyperlink.tooltip = tooltip;\n }\n\n // === Target Frame ===\n // Common values: _blank (new window), _self (same), _parent, _top\n const tgtFrame = getAttribute(node, 'w', 'tgtFrame');\n if (tgtFrame) {\n hyperlink.target = tgtFrame;\n }\n\n // === History ===\n // Whether to add to browser history\n const history = getAttribute(node, 'w', 'history');\n if (history === '1' || history === 'true') {\n hyperlink.history = true;\n }\n\n // === Document Location ===\n // Location within a linked document (like fragment for external doc)\n const docLocation = getAttribute(node, 'w', 'docLocation');\n if (docLocation) {\n hyperlink.docLocation = docLocation;\n }\n\n // === Parse Children ===\n // Hyperlinks contain runs for the display text, and possibly bookmarks\n const children = getChildElements(node);\n for (const child of children) {\n const localName = getLocalName(child.name);\n\n switch (localName) {\n case 'r':\n hyperlink.children.push(parseRun(child, styles, theme, rels, media));\n break;\n\n case 'bookmarkStart':\n hyperlink.children.push(parseBookmarkStart(child));\n break;\n\n case 'bookmarkEnd':\n hyperlink.children.push(parseBookmarkEnd(child));\n break;\n\n // Note: hyperlinks can technically contain other elements like\n // fldSimple, but these are rare. Add support as needed.\n }\n }\n\n return hyperlink;\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Get the display text of a hyperlink\n *\n * Concatenates text from all child runs.\n *\n * @param hyperlink - Parsed Hyperlink object\n * @returns Display text string\n */\nexport function getHyperlinkText(hyperlink: Hyperlink): string {\n let text = '';\n\n for (const child of hyperlink.children) {\n if (child.type === 'run') {\n for (const content of child.content) {\n if (content.type === 'text') {\n text += content.text;\n } else if (content.type === 'tab') {\n text += '\\t';\n }\n }\n }\n }\n\n return text;\n}\n\n/**\n * Check if a hyperlink is an external link\n *\n * @param hyperlink - Parsed Hyperlink object\n * @returns true if this links to an external URL\n */\nexport function isExternalLink(hyperlink: Hyperlink): boolean {\n // Has rId and resolved href that starts with a protocol\n if (hyperlink.href) {\n return /^https?:\\/\\/|^mailto:|^tel:|^ftp:/i.test(hyperlink.href);\n }\n // Has rId but not resolved (still counts as external attempt)\n return !!hyperlink.rId && !hyperlink.anchor;\n}\n\n/**\n * Check if a hyperlink is an internal bookmark link\n *\n * @param hyperlink - Parsed Hyperlink object\n * @returns true if this links to an internal bookmark\n */\nexport function isInternalLink(hyperlink: Hyperlink): boolean {\n return !!hyperlink.anchor;\n}\n\n/**\n * Get the resolved URL of a hyperlink\n *\n * For external links, returns the full URL.\n * For internal links, returns the anchor prefixed with #.\n * Returns undefined if the link couldn't be resolved.\n *\n * @param hyperlink - Parsed Hyperlink object\n * @returns Resolved URL or undefined\n */\nexport function getHyperlinkUrl(hyperlink: Hyperlink): string | undefined {\n return hyperlink.href;\n}\n\n/**\n * Check if a hyperlink has any content (runs)\n *\n * @param hyperlink - Parsed Hyperlink object\n * @returns true if hyperlink has child runs\n */\nexport function hasContent(hyperlink: Hyperlink): boolean {\n return hyperlink.children.some((child) => child.type === 'run');\n}\n\n/**\n * Get all runs from a hyperlink\n *\n * @param hyperlink - Parsed Hyperlink object\n * @returns Array of Run objects\n */\nexport function getHyperlinkRuns(hyperlink: Hyperlink): Run[] {\n return hyperlink.children.filter((child): child is Run => child.type === 'run');\n}\n\n/**\n * Resolve a hyperlink's rId to a URL using a relationship map\n *\n * This is useful when you have a hyperlink that was parsed without\n * relationship context and need to resolve it later.\n *\n * @param hyperlink - Parsed Hyperlink object (will be modified)\n * @param rels - Relationship map to resolve against\n * @returns The resolved URL or undefined\n */\nexport function resolveHyperlinkUrl(\n hyperlink: Hyperlink,\n rels: RelationshipMap\n): string | undefined {\n if (hyperlink.rId) {\n const rel = rels.get(hyperlink.rId);\n if (rel) {\n if (isExternalHyperlink(rel)) {\n hyperlink.href = rel.target;\n } else {\n hyperlink.href = rel.target;\n }\n return hyperlink.href;\n }\n }\n\n // If there's an anchor but no href yet, set it\n if (hyperlink.anchor && !hyperlink.href) {\n hyperlink.href = `#${hyperlink.anchor}`;\n return hyperlink.href;\n }\n\n return hyperlink.href;\n}\n\n/**\n * Create an internal hyperlink to a bookmark\n *\n * Utility function for creating hyperlinks programmatically.\n *\n * @param anchor - Bookmark name to link to\n * @param children - Child runs for display text\n * @param options - Optional properties (tooltip, etc.)\n * @returns New Hyperlink object\n */\nexport function createInternalHyperlink(\n anchor: string,\n children: Run[],\n options?: {\n tooltip?: string;\n }\n): Hyperlink {\n return {\n type: 'hyperlink',\n anchor,\n href: `#${anchor}`,\n tooltip: options?.tooltip,\n children,\n };\n}\n\n/**\n * Create an external hyperlink\n *\n * Utility function for creating hyperlinks programmatically.\n * Note: The rId would need to be assigned when serializing.\n *\n * @param url - External URL\n * @param children - Child runs for display text\n * @param options - Optional properties (tooltip, target, etc.)\n * @returns New Hyperlink object\n */\nexport function createExternalHyperlink(\n url: string,\n children: Run[],\n options?: {\n tooltip?: string;\n target?: string;\n }\n): Hyperlink {\n return {\n type: 'hyperlink',\n href: url,\n tooltip: options?.tooltip,\n target: options?.target,\n children,\n };\n}\n","/**\n * Bookmark Parser - Parse bookmark markers (w:bookmarkStart, w:bookmarkEnd)\n *\n * Bookmarks are named locations in a document that can be targeted by internal\n * hyperlinks. They consist of a start and end marker with matching IDs.\n *\n * OOXML Reference:\n * - Bookmark start: w:bookmarkStart (id, name, colFirst?, colLast?)\n * - Bookmark end: w:bookmarkEnd (id)\n * - Internal hyperlinks reference bookmarks by name via w:anchor attribute\n *\n * Bookmark Structure:\n * - Each bookmark has a unique numeric ID within the document\n * - The name is used for hyperlink references\n * - Start and end markers can span multiple paragraphs or be point bookmarks\n * - Table column bookmarks have colFirst/colLast for column ranges\n */\n\nimport type { BookmarkStart, BookmarkEnd } from '../types/document';\nimport { getAttribute, parseNumericAttribute, type XmlElement } from './xmlParser';\n\n// ============================================================================\n// BOOKMARK PARSING\n// ============================================================================\n\n/**\n * Parse a bookmark start element (w:bookmarkStart)\n *\n * Extracts:\n * - id: Numeric identifier (required, matches with bookmarkEnd)\n * - name: Bookmark name (required, used by hyperlinks)\n * - colFirst: First column for table bookmarks (optional)\n * - colLast: Last column for table bookmarks (optional)\n *\n * @param node - The w:bookmarkStart XML element\n * @returns Parsed BookmarkStart object\n */\nexport function parseBookmarkStart(node: XmlElement): BookmarkStart {\n const id = parseNumericAttribute(node, 'w', 'id') ?? 0;\n const name = getAttribute(node, 'w', 'name') ?? '';\n\n const bookmark: BookmarkStart = {\n type: 'bookmarkStart',\n id,\n name,\n };\n\n // Table column bookmarks (for bookmarks spanning table columns)\n const colFirst = parseNumericAttribute(node, 'w', 'colFirst');\n if (colFirst !== undefined) {\n bookmark.colFirst = colFirst;\n }\n\n const colLast = parseNumericAttribute(node, 'w', 'colLast');\n if (colLast !== undefined) {\n bookmark.colLast = colLast;\n }\n\n return bookmark;\n}\n\n/**\n * Parse a bookmark end element (w:bookmarkEnd)\n *\n * Bookmark ends only contain an ID that matches the corresponding start marker.\n *\n * @param node - The w:bookmarkEnd XML element\n * @returns Parsed BookmarkEnd object\n */\nexport function parseBookmarkEnd(node: XmlElement): BookmarkEnd {\n const id = parseNumericAttribute(node, 'w', 'id') ?? 0;\n\n return {\n type: 'bookmarkEnd',\n id,\n };\n}\n\n// ============================================================================\n// BOOKMARK COLLECTION & UTILITIES\n// ============================================================================\n\n/**\n * Bookmark map for quick lookup by ID or name\n */\nexport interface BookmarkMap {\n /** Lookup bookmark start by ID */\n byId: Map<number, BookmarkStart>;\n /** Lookup bookmark start by name (for hyperlink resolution) */\n byName: Map<string, BookmarkStart>;\n /** All bookmark starts in document order */\n bookmarks: BookmarkStart[];\n}\n\n/**\n * Create an empty bookmark map\n */\nexport function createBookmarkMap(): BookmarkMap {\n return {\n byId: new Map(),\n byName: new Map(),\n bookmarks: [],\n };\n}\n\n/**\n * Add a bookmark to the map\n *\n * @param map - The bookmark map to update\n * @param bookmark - The bookmark start to add\n */\nexport function addBookmark(map: BookmarkMap, bookmark: BookmarkStart): void {\n map.byId.set(bookmark.id, bookmark);\n if (bookmark.name) {\n map.byName.set(bookmark.name, bookmark);\n }\n map.bookmarks.push(bookmark);\n}\n\n/**\n * Get a bookmark by name (for resolving internal hyperlinks)\n *\n * @param map - The bookmark map to search\n * @param name - Bookmark name to find\n * @returns The BookmarkStart or undefined if not found\n */\nexport function getBookmarkByName(map: BookmarkMap, name: string): BookmarkStart | undefined {\n return map.byName.get(name);\n}\n\n/**\n * Get a bookmark by ID (for matching start/end pairs)\n *\n * @param map - The bookmark map to search\n * @param id - Bookmark ID to find\n * @returns The BookmarkStart or undefined if not found\n */\nexport function getBookmarkById(map: BookmarkMap, id: number): BookmarkStart | undefined {\n return map.byId.get(id);\n}\n\n/**\n * Check if a bookmark exists by name\n *\n * @param map - The bookmark map to search\n * @param name - Bookmark name to check\n * @returns true if bookmark exists\n */\nexport function hasBookmark(map: BookmarkMap, name: string): boolean {\n return map.byName.has(name);\n}\n\n/**\n * Get all bookmark names in the document\n *\n * @param map - The bookmark map\n * @returns Array of bookmark names\n */\nexport function getAllBookmarkNames(map: BookmarkMap): string[] {\n return Array.from(map.byName.keys());\n}\n\n/**\n * Check if a bookmark is a point bookmark (start and end at same location)\n *\n * Point bookmarks have no content between start and end markers.\n * This is commonly used for insertion points.\n *\n * @param start - The bookmark start\n * @param end - The bookmark end\n * @param contents - Content between them\n * @returns true if this is a point bookmark\n */\nexport function isPointBookmark(\n start: BookmarkStart,\n end: BookmarkEnd,\n contents: unknown[]\n): boolean {\n return start.id === end.id && contents.length === 0;\n}\n\n/**\n * Check if a bookmark is a table column bookmark\n *\n * Table bookmarks have colFirst and colLast attributes indicating\n * they span specific table columns.\n *\n * @param bookmark - The bookmark to check\n * @returns true if bookmark has column range info\n */\nexport function isTableBookmark(bookmark: BookmarkStart): boolean {\n return bookmark.colFirst !== undefined || bookmark.colLast !== undefined;\n}\n\n/**\n * Generate an internal hyperlink href from a bookmark name\n *\n * Internal hyperlinks use #anchor format.\n *\n * @param bookmarkName - The bookmark name to link to\n * @returns Href string (e.g., \"#BookmarkName\")\n */\nexport function bookmarkToHref(bookmarkName: string): string {\n return `#${bookmarkName}`;\n}\n\n/**\n * Extract bookmark name from an internal hyperlink href\n *\n * @param href - The href string\n * @returns Bookmark name or null if not an internal link\n */\nexport function hrefToBookmarkName(href: string): string | null {\n if (href.startsWith('#')) {\n return href.substring(1);\n }\n return null;\n}\n\n// ============================================================================\n// SPECIAL BOOKMARK TYPES\n// ============================================================================\n\n/**\n * Check if a bookmark is a built-in Word bookmark\n *\n * Word uses certain reserved bookmark names for special purposes:\n * - _GoBack: Last editing position\n * - _Toc*: Table of contents entries\n * - _Ref*: Cross-reference anchors\n * - _Hlt*: Highlight ranges\n *\n * @param name - Bookmark name to check\n * @returns true if this is a built-in bookmark\n */\nexport function isBuiltInBookmark(name: string): boolean {\n if (!name) return false;\n\n // Check for underscore prefix (Word internal bookmarks)\n if (name.startsWith('_')) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if a bookmark is a TOC entry bookmark\n *\n * @param name - Bookmark name to check\n * @returns true if bookmark is for TOC\n */\nexport function isTocBookmark(name: string): boolean {\n return name.startsWith('_Toc');\n}\n\n/**\n * Check if a bookmark is a cross-reference anchor\n *\n * @param name - Bookmark name to check\n * @returns true if bookmark is for cross-reference\n */\nexport function isRefBookmark(name: string): boolean {\n return name.startsWith('_Ref');\n}\n\n/**\n * Get bookmark type category\n *\n * @param name - Bookmark name\n * @returns Bookmark type\n */\nexport function getBookmarkType(name: string): 'user' | 'toc' | 'ref' | 'goBack' | 'internal' {\n if (name === '_GoBack') {\n return 'goBack';\n }\n if (isTocBookmark(name)) {\n return 'toc';\n }\n if (isRefBookmark(name)) {\n return 'ref';\n }\n if (isBuiltInBookmark(name)) {\n return 'internal';\n }\n return 'user';\n}\n\n// ============================================================================\n// BOOKMARK VALIDATION\n// ============================================================================\n\n/**\n * Validate that all bookmark starts have matching ends\n *\n * @param starts - Array of bookmark starts\n * @param ends - Array of bookmark ends\n * @returns Object with validation results\n */\nexport function validateBookmarkPairs(\n starts: BookmarkStart[],\n ends: BookmarkEnd[]\n): {\n valid: boolean;\n unmatchedStarts: BookmarkStart[];\n unmatchedEnds: BookmarkEnd[];\n} {\n const startIds = new Set(starts.map((s) => s.id));\n const endIds = new Set(ends.map((e) => e.id));\n\n const unmatchedStarts = starts.filter((s) => !endIds.has(s.id));\n const unmatchedEnds = ends.filter((e) => !startIds.has(e.id));\n\n return {\n valid: unmatchedStarts.length === 0 && unmatchedEnds.length === 0,\n unmatchedStarts,\n unmatchedEnds,\n };\n}\n\n/**\n * Validate a bookmark name (for creating new bookmarks)\n *\n * Valid bookmark names:\n * - Cannot be empty\n * - Must start with a letter or underscore\n * - Can contain letters, digits, and underscores\n * - Cannot exceed 40 characters\n *\n * @param name - Name to validate\n * @returns Object with validation result and error message if invalid\n */\nexport function validateBookmarkName(name: string): { valid: boolean; error?: string } {\n if (!name) {\n return { valid: false, error: 'Bookmark name cannot be empty' };\n }\n\n if (name.length > 40) {\n return { valid: false, error: 'Bookmark name cannot exceed 40 characters' };\n }\n\n // Check first character (letter or underscore)\n if (!/^[a-zA-Z_]/.test(name)) {\n return {\n valid: false,\n error: 'Bookmark name must start with a letter or underscore',\n };\n }\n\n // Check remaining characters (letters, digits, underscores)\n if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) {\n return {\n valid: false,\n error: 'Bookmark name can only contain letters, digits, and underscores',\n };\n }\n\n return { valid: true };\n}\n","/**\n * Table Parser - Parse tables with full OOXML structure\n *\n * OOXML tables consist of:\n * - w:tbl - Table element\n * - w:tblPr - Table properties (width, borders, style)\n * - w:tblGrid - Column width definitions\n * - w:tr - Table rows\n * - w:trPr - Row properties (height, header)\n * - w:tc - Table cells\n * - w:tcPr - Cell properties (width, borders, merge)\n *\n * Cell merging:\n * - Horizontal: w:gridSpan (how many grid columns this cell spans)\n * - Vertical: w:vMerge (restart = start of merge, continue = continuation)\n *\n * OOXML Reference:\n * - w:tbl contains w:tblPr, w:tblGrid, and w:tr elements\n * - w:tr contains w:trPr and w:tc elements\n * - w:tc contains w:tcPr and content (paragraphs, tables)\n */\n\nimport type {\n Table,\n TableRow,\n TableCell,\n TableFormatting,\n TableRowFormatting,\n TableCellFormatting,\n TableMeasurement,\n TableWidthType,\n TableBorders,\n TableLook,\n CellMargins,\n FloatingTableProperties,\n ConditionalFormatStyle,\n Paragraph,\n Theme,\n BorderSpec,\n ShadingProperties,\n ColorValue,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport type { NumberingMap } from './numberingParser';\nimport { parseParagraph } from './paragraphParser';\nimport {\n findChild,\n findChildren,\n getAttribute,\n parseNumericAttribute,\n parseBooleanElement,\n parseColorElement,\n type XmlElement,\n} from './xmlParser';\n\n// ============================================================================\n// TABLE MEASUREMENT PARSING\n// ============================================================================\n\n/**\n * Parse a table measurement (width, height, etc.)\n *\n * @param element - Element with w:w and w:type attributes\n * @returns Parsed measurement or undefined\n */\nexport function parseTableMeasurement(element: XmlElement | null): TableMeasurement | undefined {\n if (!element) return undefined;\n\n const value = parseNumericAttribute(element, 'w', 'w') ?? 0;\n const typeStr = getAttribute(element, 'w', 'type') ?? 'dxa';\n\n let type: TableWidthType = 'dxa';\n if (typeStr === 'auto' || typeStr === 'dxa' || typeStr === 'nil' || typeStr === 'pct') {\n type = typeStr;\n }\n\n return { value, type };\n}\n\n/**\n * Parse width from an element (shorthand for common case)\n */\nfunction parseWidth(element: XmlElement | null): TableMeasurement | undefined {\n return parseTableMeasurement(element);\n}\n\n// ============================================================================\n// BORDER PARSING\n// ============================================================================\n\n/**\n * Parse a single border specification\n *\n * @param element - Border element (w:top, w:bottom, etc.)\n * @returns Parsed border or undefined\n */\nexport function parseBorderSpec(element: XmlElement | null): BorderSpec | undefined {\n if (!element) return undefined;\n\n const styleStr = getAttribute(element, 'w', 'val') ?? 'none';\n const style = styleStr as BorderSpec['style'];\n\n const border: BorderSpec = { style };\n\n // Size in eighths of a point\n const sz = parseNumericAttribute(element, 'w', 'sz');\n if (sz !== undefined) {\n border.size = sz;\n }\n\n // Space from text in points\n const space = parseNumericAttribute(element, 'w', 'space');\n if (space !== undefined) {\n border.space = space;\n }\n\n // Color\n const colorData = parseColorElement(element);\n if (colorData) {\n border.color = {\n rgb: colorData.val,\n themeColor: colorData.themeColor as ColorValue['themeColor'],\n themeTint: colorData.themeTint,\n themeShade: colorData.themeShade,\n };\n }\n\n // Shadow effect\n const shadow = getAttribute(element, 'w', 'shadow');\n if (shadow === '1' || shadow === 'true') {\n border.shadow = true;\n }\n\n // Frame effect\n const frame = getAttribute(element, 'w', 'frame');\n if (frame === '1' || frame === 'true') {\n border.frame = true;\n }\n\n return border;\n}\n\n/**\n * Parse table borders (w:tblBorders or w:tcBorders)\n *\n * @param bordersElement - The borders container element\n * @returns Parsed borders or undefined\n */\nexport function parseTableBorders(bordersElement: XmlElement | null): TableBorders | undefined {\n if (!bordersElement) return undefined;\n\n const borders: TableBorders = {};\n\n const top = parseBorderSpec(findChild(bordersElement, 'w', 'top'));\n if (top) borders.top = top;\n\n const bottom = parseBorderSpec(findChild(bordersElement, 'w', 'bottom'));\n if (bottom) borders.bottom = bottom;\n\n const left = parseBorderSpec(\n findChild(bordersElement, 'w', 'left') ?? findChild(bordersElement, 'w', 'start')\n );\n if (left) borders.left = left;\n\n const right = parseBorderSpec(\n findChild(bordersElement, 'w', 'right') ?? findChild(bordersElement, 'w', 'end')\n );\n if (right) borders.right = right;\n\n const insideH = parseBorderSpec(findChild(bordersElement, 'w', 'insideH'));\n if (insideH) borders.insideH = insideH;\n\n const insideV = parseBorderSpec(findChild(bordersElement, 'w', 'insideV'));\n if (insideV) borders.insideV = insideV;\n\n // Return undefined if no borders were parsed\n if (Object.keys(borders).length === 0) return undefined;\n\n return borders;\n}\n\n// ============================================================================\n// CELL MARGINS PARSING\n// ============================================================================\n\n/**\n * Parse cell margins (w:tblCellMar or w:tcMar)\n *\n * @param marginsElement - The margins container element\n * @returns Parsed margins or undefined\n */\nexport function parseCellMargins(marginsElement: XmlElement | null): CellMargins | undefined {\n if (!marginsElement) return undefined;\n\n const margins: CellMargins = {};\n\n const top = parseWidth(findChild(marginsElement, 'w', 'top'));\n if (top) margins.top = top;\n\n const bottom = parseWidth(findChild(marginsElement, 'w', 'bottom'));\n if (bottom) margins.bottom = bottom;\n\n const left = parseWidth(\n findChild(marginsElement, 'w', 'left') ?? findChild(marginsElement, 'w', 'start')\n );\n if (left) margins.left = left;\n\n const right = parseWidth(\n findChild(marginsElement, 'w', 'right') ?? findChild(marginsElement, 'w', 'end')\n );\n if (right) margins.right = right;\n\n if (Object.keys(margins).length === 0) return undefined;\n\n return margins;\n}\n\n// ============================================================================\n// SHADING PARSING\n// ============================================================================\n\n/**\n * Parse shading properties (w:shd)\n *\n * @param shdElement - The w:shd element\n * @returns Parsed shading or undefined\n */\nexport function parseShading(shdElement: XmlElement | null): ShadingProperties | undefined {\n if (!shdElement) return undefined;\n\n const shading: ShadingProperties = {};\n\n // Fill color (background)\n const fillStr = getAttribute(shdElement, 'w', 'fill');\n if (fillStr && fillStr !== 'auto') {\n shading.fill = { rgb: fillStr };\n }\n\n // Theme fill\n const themeFill = getAttribute(shdElement, 'w', 'themeFill');\n if (themeFill) {\n shading.fill = { themeColor: themeFill as any };\n\n const themeFillTint = getAttribute(shdElement, 'w', 'themeFillTint');\n if (themeFillTint && shading.fill) {\n shading.fill.themeTint = themeFillTint;\n }\n\n const themeFillShade = getAttribute(shdElement, 'w', 'themeFillShade');\n if (themeFillShade && shading.fill) {\n shading.fill.themeShade = themeFillShade;\n }\n }\n\n // Pattern color\n const colorStr = getAttribute(shdElement, 'w', 'color');\n if (colorStr && colorStr !== 'auto') {\n shading.color = { rgb: colorStr };\n }\n\n // Pattern value\n const pattern = getAttribute(shdElement, 'w', 'val');\n if (pattern) {\n shading.pattern = pattern as ShadingProperties['pattern'];\n }\n\n if (Object.keys(shading).length === 0) return undefined;\n\n return shading;\n}\n\n// ============================================================================\n// TABLE LOOK PARSING\n// ============================================================================\n\n/**\n * Parse table look flags (w:tblLook)\n *\n * @param lookElement - The w:tblLook element\n * @returns Parsed table look or undefined\n */\nexport function parseTableLook(lookElement: XmlElement | null): TableLook | undefined {\n if (!lookElement) return undefined;\n\n const look: TableLook = {};\n\n // Parse individual flags\n const firstRow = getAttribute(lookElement, 'w', 'firstRow');\n if (firstRow === '1' || firstRow === 'true') look.firstRow = true;\n\n const lastRow = getAttribute(lookElement, 'w', 'lastRow');\n if (lastRow === '1' || lastRow === 'true') look.lastRow = true;\n\n const firstColumn = getAttribute(lookElement, 'w', 'firstColumn');\n if (firstColumn === '1' || firstColumn === 'true') look.firstColumn = true;\n\n const lastColumn = getAttribute(lookElement, 'w', 'lastColumn');\n if (lastColumn === '1' || lastColumn === 'true') look.lastColumn = true;\n\n const noHBand = getAttribute(lookElement, 'w', 'noHBand');\n if (noHBand === '1' || noHBand === 'true') look.noHBand = true;\n\n const noVBand = getAttribute(lookElement, 'w', 'noVBand');\n if (noVBand === '1' || noVBand === 'true') look.noVBand = true;\n\n // Also check for the val attribute (hexadecimal flags)\n const val = getAttribute(lookElement, 'w', 'val');\n if (val) {\n const flags = parseInt(val, 16);\n if (!isNaN(flags)) {\n if (flags & 0x0020) look.firstRow = true;\n if (flags & 0x0040) look.lastRow = true;\n if (flags & 0x0080) look.firstColumn = true;\n if (flags & 0x0100) look.lastColumn = true;\n if (flags & 0x0200) look.noHBand = true;\n if (flags & 0x0400) look.noVBand = true;\n }\n }\n\n if (Object.keys(look).length === 0) return undefined;\n\n return look;\n}\n\n// ============================================================================\n// FLOATING TABLE PROPERTIES\n// ============================================================================\n\n/**\n * Parse floating table properties (w:tblpPr)\n *\n * @param tblpPrElement - The w:tblpPr element\n * @returns Parsed floating properties or undefined\n */\nexport function parseFloatingTableProperties(\n tblpPrElement: XmlElement | null\n): FloatingTableProperties | undefined {\n if (!tblpPrElement) return undefined;\n\n const floating: FloatingTableProperties = {};\n\n // Horizontal anchor\n const horzAnchor = getAttribute(tblpPrElement, 'w', 'horzAnchor');\n if (horzAnchor === 'margin' || horzAnchor === 'page' || horzAnchor === 'text') {\n floating.horzAnchor = horzAnchor;\n }\n\n // Vertical anchor\n const vertAnchor = getAttribute(tblpPrElement, 'w', 'vertAnchor');\n if (vertAnchor === 'margin' || vertAnchor === 'page' || vertAnchor === 'text') {\n floating.vertAnchor = vertAnchor;\n }\n\n // Horizontal position\n const tblpX = parseNumericAttribute(tblpPrElement, 'w', 'tblpX');\n if (tblpX !== undefined) floating.tblpX = tblpX;\n\n const tblpXSpec = getAttribute(tblpPrElement, 'w', 'tblpXSpec');\n if (tblpXSpec) {\n floating.tblpXSpec = tblpXSpec as FloatingTableProperties['tblpXSpec'];\n }\n\n // Vertical position\n const tblpY = parseNumericAttribute(tblpPrElement, 'w', 'tblpY');\n if (tblpY !== undefined) floating.tblpY = tblpY;\n\n const tblpYSpec = getAttribute(tblpPrElement, 'w', 'tblpYSpec');\n if (tblpYSpec) {\n floating.tblpYSpec = tblpYSpec as FloatingTableProperties['tblpYSpec'];\n }\n\n // Distance from text\n const topFromText = parseNumericAttribute(tblpPrElement, 'w', 'topFromText');\n if (topFromText !== undefined) floating.topFromText = topFromText;\n\n const bottomFromText = parseNumericAttribute(tblpPrElement, 'w', 'bottomFromText');\n if (bottomFromText !== undefined) floating.bottomFromText = bottomFromText;\n\n const leftFromText = parseNumericAttribute(tblpPrElement, 'w', 'leftFromText');\n if (leftFromText !== undefined) floating.leftFromText = leftFromText;\n\n const rightFromText = parseNumericAttribute(tblpPrElement, 'w', 'rightFromText');\n if (rightFromText !== undefined) floating.rightFromText = rightFromText;\n\n if (Object.keys(floating).length === 0) return undefined;\n\n return floating;\n}\n\n// ============================================================================\n// TABLE PROPERTIES PARSING (w:tblPr)\n// ============================================================================\n\n/**\n * Parse table properties (w:tblPr)\n *\n * @param tblPrElement - The w:tblPr element\n * @returns Parsed table formatting\n */\nexport function parseTableProperties(tblPrElement: XmlElement | null): TableFormatting | undefined {\n if (!tblPrElement) return undefined;\n\n const formatting: TableFormatting = {};\n\n // Table width (w:tblW)\n const width = parseWidth(findChild(tblPrElement, 'w', 'tblW'));\n if (width) formatting.width = width;\n\n // Table justification (w:jc)\n const jcElement = findChild(tblPrElement, 'w', 'jc');\n if (jcElement) {\n const jcVal = getAttribute(jcElement, 'w', 'val');\n if (jcVal === 'left' || jcVal === 'center' || jcVal === 'right' || jcVal === 'start') {\n formatting.justification = jcVal === 'start' ? 'left' : jcVal;\n }\n }\n\n // Cell spacing (w:tblCellSpacing)\n const cellSpacing = parseWidth(findChild(tblPrElement, 'w', 'tblCellSpacing'));\n if (cellSpacing) formatting.cellSpacing = cellSpacing;\n\n // Table indent (w:tblInd)\n const indent = parseWidth(findChild(tblPrElement, 'w', 'tblInd'));\n if (indent) formatting.indent = indent;\n\n // Table borders (w:tblBorders)\n const borders = parseTableBorders(findChild(tblPrElement, 'w', 'tblBorders'));\n if (borders) formatting.borders = borders;\n\n // Default cell margins (w:tblCellMar)\n const cellMargins = parseCellMargins(findChild(tblPrElement, 'w', 'tblCellMar'));\n if (cellMargins) formatting.cellMargins = cellMargins;\n\n // Table layout (w:tblLayout)\n const layoutElement = findChild(tblPrElement, 'w', 'tblLayout');\n if (layoutElement) {\n const layoutVal = getAttribute(layoutElement, 'w', 'type');\n if (layoutVal === 'fixed' || layoutVal === 'autofit') {\n formatting.layout = layoutVal;\n }\n }\n\n // Table style (w:tblStyle)\n const styleElement = findChild(tblPrElement, 'w', 'tblStyle');\n if (styleElement) {\n const styleId = getAttribute(styleElement, 'w', 'val');\n if (styleId) formatting.styleId = styleId;\n }\n\n // Table look (w:tblLook)\n const look = parseTableLook(findChild(tblPrElement, 'w', 'tblLook'));\n if (look) formatting.look = look;\n\n // Shading (w:shd)\n const shading = parseShading(findChild(tblPrElement, 'w', 'shd'));\n if (shading) formatting.shading = shading;\n\n // Table overlap (w:tblOverlap)\n const overlapElement = findChild(tblPrElement, 'w', 'tblOverlap');\n if (overlapElement) {\n const overlapVal = getAttribute(overlapElement, 'w', 'val');\n if (overlapVal === 'never' || overlapVal === 'overlap') {\n formatting.overlap = overlapVal;\n }\n }\n\n // Floating table (w:tblpPr)\n const floating = parseFloatingTableProperties(findChild(tblPrElement, 'w', 'tblpPr'));\n if (floating) formatting.floating = floating;\n\n // Bidirectional (w:bidiVisual)\n const bidi = parseBooleanElement(findChild(tblPrElement, 'w', 'bidiVisual'));\n if (bidi) formatting.bidi = true;\n\n if (Object.keys(formatting).length === 0) return undefined;\n\n return formatting;\n}\n\n// ============================================================================\n// TABLE ROW PROPERTIES PARSING (w:trPr)\n// ============================================================================\n\n/**\n * Parse table row properties (w:trPr)\n *\n * @param trPrElement - The w:trPr element\n * @returns Parsed row formatting\n */\nexport function parseTableRowProperties(\n trPrElement: XmlElement | null\n): TableRowFormatting | undefined {\n if (!trPrElement) return undefined;\n\n const formatting: TableRowFormatting = {};\n\n // Row height (w:trHeight)\n const heightElement = findChild(trPrElement, 'w', 'trHeight');\n if (heightElement) {\n const height = parseWidth(heightElement);\n if (height) formatting.height = height;\n\n const hRule = getAttribute(heightElement, 'w', 'hRule');\n if (hRule === 'auto' || hRule === 'atLeast' || hRule === 'exact') {\n formatting.heightRule = hRule;\n }\n }\n\n // Header row (w:tblHeader)\n const header = parseBooleanElement(findChild(trPrElement, 'w', 'tblHeader'));\n if (header) formatting.header = true;\n\n // Can't split (w:cantSplit)\n const cantSplit = parseBooleanElement(findChild(trPrElement, 'w', 'cantSplit'));\n if (cantSplit) formatting.cantSplit = true;\n\n // Row justification (w:jc)\n const jcElement = findChild(trPrElement, 'w', 'jc');\n if (jcElement) {\n const jcVal = getAttribute(jcElement, 'w', 'val');\n if (jcVal === 'left' || jcVal === 'center' || jcVal === 'right') {\n formatting.justification = jcVal;\n }\n }\n\n // Hidden row (w:hidden)\n const hidden = parseBooleanElement(findChild(trPrElement, 'w', 'hidden'));\n if (hidden) formatting.hidden = true;\n\n if (Object.keys(formatting).length === 0) return undefined;\n\n return formatting;\n}\n\n// ============================================================================\n// TABLE CELL PROPERTIES PARSING (w:tcPr)\n// ============================================================================\n\n/**\n * Parse conditional format style (for table style conditional formatting)\n *\n * @param cnfElement - The w:cnfStyle element\n * @returns Parsed conditional format or undefined\n */\nexport function parseConditionalFormatStyle(\n cnfElement: XmlElement | null\n): ConditionalFormatStyle | undefined {\n if (!cnfElement) return undefined;\n\n const style: ConditionalFormatStyle = {};\n\n // Parse individual flags\n const firstRow = getAttribute(cnfElement, 'w', 'firstRow');\n if (firstRow === '1' || firstRow === 'true') style.firstRow = true;\n\n const lastRow = getAttribute(cnfElement, 'w', 'lastRow');\n if (lastRow === '1' || lastRow === 'true') style.lastRow = true;\n\n const firstColumn = getAttribute(cnfElement, 'w', 'firstColumn');\n if (firstColumn === '1' || firstColumn === 'true') style.firstColumn = true;\n\n const lastColumn = getAttribute(cnfElement, 'w', 'lastColumn');\n if (lastColumn === '1' || lastColumn === 'true') style.lastColumn = true;\n\n const oddHBand = getAttribute(cnfElement, 'w', 'oddHBand');\n if (oddHBand === '1' || oddHBand === 'true') style.oddHBand = true;\n\n const evenHBand = getAttribute(cnfElement, 'w', 'evenHBand');\n if (evenHBand === '1' || evenHBand === 'true') style.evenHBand = true;\n\n const oddVBand = getAttribute(cnfElement, 'w', 'oddVBand');\n if (oddVBand === '1' || oddVBand === 'true') style.oddVBand = true;\n\n const evenVBand = getAttribute(cnfElement, 'w', 'evenVBand');\n if (evenVBand === '1' || evenVBand === 'true') style.evenVBand = true;\n\n // Corner cells\n const nwCell = getAttribute(cnfElement, 'w', 'firstRowFirstColumn');\n if (nwCell === '1' || nwCell === 'true') style.nwCell = true;\n\n const neCell = getAttribute(cnfElement, 'w', 'firstRowLastColumn');\n if (neCell === '1' || neCell === 'true') style.neCell = true;\n\n const swCell = getAttribute(cnfElement, 'w', 'lastRowFirstColumn');\n if (swCell === '1' || swCell === 'true') style.swCell = true;\n\n const seCell = getAttribute(cnfElement, 'w', 'lastRowLastColumn');\n if (seCell === '1' || seCell === 'true') style.seCell = true;\n\n // Also check for the val attribute (binary flags string)\n const val = getAttribute(cnfElement, 'w', 'val');\n if (val && val.length === 12) {\n // Binary string format: XXXXXXXXXXXXXX\n // Position meanings from left to right\n if (val[0] === '1') style.firstRow = true;\n if (val[1] === '1') style.lastRow = true;\n if (val[2] === '1') style.firstColumn = true;\n if (val[3] === '1') style.lastColumn = true;\n if (val[4] === '1') style.oddVBand = true;\n if (val[5] === '1') style.evenVBand = true;\n if (val[6] === '1') style.oddHBand = true;\n if (val[7] === '1') style.evenHBand = true;\n if (val[8] === '1') style.nwCell = true;\n if (val[9] === '1') style.neCell = true;\n if (val[10] === '1') style.swCell = true;\n if (val[11] === '1') style.seCell = true;\n }\n\n if (Object.keys(style).length === 0) return undefined;\n\n return style;\n}\n\n/**\n * Parse table cell properties (w:tcPr)\n *\n * @param tcPrElement - The w:tcPr element\n * @returns Parsed cell formatting\n */\nexport function parseTableCellProperties(\n tcPrElement: XmlElement | null\n): TableCellFormatting | undefined {\n if (!tcPrElement) return undefined;\n\n const formatting: TableCellFormatting = {};\n\n // Cell width (w:tcW)\n const width = parseWidth(findChild(tcPrElement, 'w', 'tcW'));\n if (width) formatting.width = width;\n\n // Cell borders (w:tcBorders)\n const borders = parseTableBorders(findChild(tcPrElement, 'w', 'tcBorders'));\n if (borders) formatting.borders = borders;\n\n // Cell margins (w:tcMar)\n const margins = parseCellMargins(findChild(tcPrElement, 'w', 'tcMar'));\n if (margins) formatting.margins = margins;\n\n // Shading (w:shd)\n const shading = parseShading(findChild(tcPrElement, 'w', 'shd'));\n if (shading) formatting.shading = shading;\n\n // Vertical alignment (w:vAlign)\n const vAlignElement = findChild(tcPrElement, 'w', 'vAlign');\n if (vAlignElement) {\n const vAlign = getAttribute(vAlignElement, 'w', 'val');\n if (vAlign === 'top' || vAlign === 'center' || vAlign === 'bottom') {\n formatting.verticalAlign = vAlign;\n }\n }\n\n // Text direction (w:textDirection)\n const textDirElement = findChild(tcPrElement, 'w', 'textDirection');\n if (textDirElement) {\n const textDir = getAttribute(textDirElement, 'w', 'val');\n if (textDir) {\n formatting.textDirection = textDir as TableCellFormatting['textDirection'];\n }\n }\n\n // Grid span (horizontal merge) (w:gridSpan)\n const gridSpanElement = findChild(tcPrElement, 'w', 'gridSpan');\n if (gridSpanElement) {\n const gridSpan = parseNumericAttribute(gridSpanElement, 'w', 'val');\n if (gridSpan !== undefined && gridSpan > 1) {\n formatting.gridSpan = gridSpan;\n }\n }\n\n // Vertical merge (w:vMerge)\n const vMergeElement = findChild(tcPrElement, 'w', 'vMerge');\n if (vMergeElement) {\n const vMergeVal = getAttribute(vMergeElement, 'w', 'val');\n if (vMergeVal === 'restart') {\n formatting.vMerge = 'restart';\n } else {\n // No val attribute or val=\"continue\" means continuation\n formatting.vMerge = 'continue';\n }\n }\n\n // Fit text (w:tcFitText)\n const fitText = parseBooleanElement(findChild(tcPrElement, 'w', 'tcFitText'));\n if (fitText) formatting.fitText = true;\n\n // No wrap (w:noWrap)\n const noWrap = parseBooleanElement(findChild(tcPrElement, 'w', 'noWrap'));\n if (noWrap) formatting.noWrap = true;\n\n // Hide mark (w:hideMark)\n const hideMark = parseBooleanElement(findChild(tcPrElement, 'w', 'hideMark'));\n if (hideMark) formatting.hideMark = true;\n\n // Conditional format style (w:cnfStyle)\n const conditionalFormat = parseConditionalFormatStyle(findChild(tcPrElement, 'w', 'cnfStyle'));\n if (conditionalFormat) formatting.conditionalFormat = conditionalFormat;\n\n if (Object.keys(formatting).length === 0) return undefined;\n\n return formatting;\n}\n\n// ============================================================================\n// CELL CONTENT PARSING\n// ============================================================================\n\n/**\n * Parse table cell content (paragraphs, nested tables)\n *\n * @param tcElement - The w:tc element\n * @param styles - Style definitions\n * @param theme - Theme for color/font resolution\n * @param numbering - Numbering definitions for lists\n * @param rels - Relationships for hyperlinks\n * @param media - Media files for images\n * @returns Array of content blocks\n */\nfunction parseCellContent(\n tcElement: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): (Paragraph | Table)[] {\n const content: (Paragraph | Table)[] = [];\n\n // Get all child elements\n const elements = tcElement.elements || [];\n\n for (const child of elements) {\n if (!child.name) continue;\n\n const localName = child.name.split(':').pop();\n\n if (localName === 'p') {\n // Parse paragraph\n const para = parseParagraph(child, styles, theme, numbering, rels, media);\n content.push(para);\n } else if (localName === 'tbl') {\n // Parse nested table (recursive)\n const table = parseTable(child, styles, theme, numbering, rels, media);\n content.push(table);\n }\n // Other content types in cells are rare but could be added\n }\n\n // Ensure at least one empty paragraph (Word requires this)\n if (content.length === 0) {\n content.push({\n type: 'paragraph',\n content: [],\n });\n }\n\n return content;\n}\n\n// ============================================================================\n// TABLE CELL PARSING\n// ============================================================================\n\n/**\n * Parse a table cell (w:tc)\n *\n * @param tcElement - The w:tc element\n * @param styles - Style definitions\n * @param theme - Theme for color/font resolution\n * @param numbering - Numbering definitions for lists\n * @param rels - Relationships for hyperlinks\n * @param media - Media files for images\n * @returns Parsed table cell\n */\nexport function parseTableCell(\n tcElement: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): TableCell {\n const cell: TableCell = {\n type: 'tableCell',\n content: [],\n };\n\n // Parse cell properties (w:tcPr)\n const formatting = parseTableCellProperties(findChild(tcElement, 'w', 'tcPr'));\n if (formatting) {\n cell.formatting = formatting;\n }\n\n // Parse content\n cell.content = parseCellContent(tcElement, styles, theme, numbering, rels, media);\n\n return cell;\n}\n\n// ============================================================================\n// TABLE ROW PARSING\n// ============================================================================\n\n/**\n * Parse a table row (w:tr)\n *\n * @param trElement - The w:tr element\n * @param styles - Style definitions\n * @param theme - Theme for color/font resolution\n * @param numbering - Numbering definitions for lists\n * @param rels - Relationships for hyperlinks\n * @param media - Media files for images\n * @returns Parsed table row\n */\nexport function parseTableRow(\n trElement: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): TableRow {\n const row: TableRow = {\n type: 'tableRow',\n cells: [],\n };\n\n // Parse row properties (w:trPr)\n const formatting = parseTableRowProperties(findChild(trElement, 'w', 'trPr'));\n if (formatting) {\n row.formatting = formatting;\n }\n\n // Parse cells\n const cells = findChildren(trElement, 'w', 'tc');\n for (const cellElement of cells) {\n const cell = parseTableCell(cellElement, styles, theme, numbering, rels, media);\n row.cells.push(cell);\n }\n\n return row;\n}\n\n// ============================================================================\n// TABLE GRID PARSING\n// ============================================================================\n\n/**\n * Parse table grid (w:tblGrid) for column widths\n *\n * @param tblGridElement - The w:tblGrid element\n * @returns Array of column widths in twips\n */\nexport function parseTableGrid(tblGridElement: XmlElement | null): number[] | undefined {\n if (!tblGridElement) return undefined;\n\n const widths: number[] = [];\n\n const gridCols = findChildren(tblGridElement, 'w', 'gridCol');\n for (const col of gridCols) {\n const width = parseNumericAttribute(col, 'w', 'w') ?? 0;\n widths.push(width);\n }\n\n return widths.length > 0 ? widths : undefined;\n}\n\n// ============================================================================\n// MAIN TABLE PARSING\n// ============================================================================\n\n/**\n * Parse a table element (w:tbl)\n *\n * @param tblElement - The w:tbl element\n * @param styles - Style definitions\n * @param theme - Theme for color/font resolution\n * @param numbering - Numbering definitions for lists\n * @param rels - Relationships for hyperlinks\n * @param media - Media files for images\n * @returns Parsed table\n */\nexport function parseTable(\n tblElement: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): Table {\n const table: Table = {\n type: 'table',\n rows: [],\n };\n\n // Parse table properties (w:tblPr)\n const formatting = parseTableProperties(findChild(tblElement, 'w', 'tblPr'));\n if (formatting) {\n table.formatting = formatting;\n }\n\n // Parse table grid (w:tblGrid)\n const columnWidths = parseTableGrid(findChild(tblElement, 'w', 'tblGrid'));\n if (columnWidths) {\n table.columnWidths = columnWidths;\n }\n\n // Parse rows\n const rows = findChildren(tblElement, 'w', 'tr');\n for (const rowElement of rows) {\n const row = parseTableRow(rowElement, styles, theme, numbering, rels, media);\n table.rows.push(row);\n }\n\n return table;\n}\n\n// ============================================================================\n// TABLE UTILITIES\n// ============================================================================\n\n/**\n * Get the number of columns in a table\n *\n * Uses the table grid if available, otherwise counts cells in first row.\n *\n * @param table - The table to measure\n * @returns Number of columns\n */\nexport function getTableColumnCount(table: Table): number {\n if (table.columnWidths && table.columnWidths.length > 0) {\n return table.columnWidths.length;\n }\n\n if (table.rows.length === 0) return 0;\n\n // Count cells in first row, accounting for grid span\n return table.rows[0].cells.reduce((count, cell) => {\n return count + (cell.formatting?.gridSpan ?? 1);\n }, 0);\n}\n\n/**\n * Get the number of rows in a table\n *\n * @param table - The table to measure\n * @returns Number of rows\n */\nexport function getTableRowCount(table: Table): number {\n return table.rows.length;\n}\n\n/**\n * Check if a cell is part of a vertical merge\n *\n * @param cell - The cell to check\n * @returns true if cell continues a vertical merge\n */\nexport function isCellMergeContinuation(cell: TableCell): boolean {\n return cell.formatting?.vMerge === 'continue';\n}\n\n/**\n * Check if a cell starts a vertical merge\n *\n * @param cell - The cell to check\n * @returns true if cell starts a vertical merge\n */\nexport function isCellMergeStart(cell: TableCell): boolean {\n return cell.formatting?.vMerge === 'restart';\n}\n\n/**\n * Check if a cell spans multiple columns\n *\n * @param cell - The cell to check\n * @returns true if cell spans multiple columns\n */\nexport function isCellHorizontallyMerged(cell: TableCell): boolean {\n return (cell.formatting?.gridSpan ?? 1) > 1;\n}\n\n/**\n * Get the plain text content of a table\n *\n * @param table - The table to extract text from\n * @returns Plain text content\n */\nexport function getTableText(table: Table): string {\n const rows: string[] = [];\n\n for (const row of table.rows) {\n const cells: string[] = [];\n\n for (const cell of row.cells) {\n const cellText = cell.content\n .filter((c): c is Paragraph => c.type === 'paragraph')\n .map((p) => getParagraphText(p))\n .join('\\n');\n cells.push(cellText);\n }\n\n rows.push(cells.join('\\t'));\n }\n\n return rows.join('\\n');\n}\n\n/**\n * Helper to get paragraph text (simplified)\n */\nfunction getParagraphText(para: Paragraph): string {\n return para.content\n .filter((c) => 'content' in c)\n .flatMap((run) => {\n if (!('content' in run)) return [];\n return (run as any).content.filter((c: any) => c.type === 'text').map((c: any) => c.text);\n })\n .join('');\n}\n\n/**\n * Check if table has header row\n *\n * @param table - The table to check\n * @returns true if first row is marked as header\n */\nexport function hasHeaderRow(table: Table): boolean {\n if (table.rows.length === 0) return false;\n return table.rows[0].formatting?.header === true;\n}\n\n/**\n * Get all header rows from a table\n *\n * @param table - The table to search\n * @returns Array of header rows\n */\nexport function getHeaderRows(table: Table): TableRow[] {\n return table.rows.filter((row) => row.formatting?.header === true);\n}\n\n/**\n * Check if table is a floating table\n *\n * @param table - The table to check\n * @returns true if table has floating properties\n */\nexport function isFloatingTable(table: Table): boolean {\n return table.formatting?.floating !== undefined;\n}\n","/**\n * Header/Footer Parser - Parse header*.xml and footer*.xml files\n *\n * Headers and footers are stored in separate XML files within the DOCX package:\n * - word/header1.xml, word/header2.xml, etc.\n * - word/footer1.xml, word/footer2.xml, etc.\n *\n * Each header/footer is referenced from document.xml via:\n * - w:sectPr > w:headerReference (type=\"default|first|even\", r:id=\"rIdX\")\n * - w:sectPr > w:footerReference (type=\"default|first|even\", r:id=\"rIdX\")\n *\n * Header/footer types:\n * - default: Used for all pages unless first/even specified\n * - first: Used only for the first page of a section\n * - even: Used for even-numbered pages (when different odd/even enabled)\n *\n * Content structure:\n * - w:hdr or w:ftr root element\n * - Contains w:p (paragraphs) and w:tbl (tables)\n * - Can contain images, shapes, page numbers, etc.\n *\n * OOXML Reference:\n * - Root: w:hdr (header) or w:ftr (footer)\n * - Content: w:p, w:tbl\n */\n\nimport type {\n HeaderFooter,\n HeaderFooterType,\n HeaderReference,\n FooterReference,\n Paragraph,\n Table,\n Theme,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport type { NumberingMap } from './numberingParser';\nimport { parseXml, findChildren, getAttribute, type XmlElement } from './xmlParser';\nimport { parseParagraph } from './paragraphParser';\nimport { parseTable } from './tableParser';\n\n// ============================================================================\n// HEADER/FOOTER MAP INTERFACE\n// ============================================================================\n\n/**\n * Map of header/footer ID to HeaderFooter content\n */\nexport interface HeaderFooterMap {\n /** Map of rId to HeaderFooter */\n byId: Map<string, HeaderFooter>;\n\n /** Get header/footer by rId */\n get(rId: string): HeaderFooter | undefined;\n\n /** Check if header/footer exists */\n has(rId: string): boolean;\n\n /** Get all headers/footers */\n getAll(): HeaderFooter[];\n\n /** Get by type */\n getByType(type: HeaderFooterType): HeaderFooter | undefined;\n}\n\n// ============================================================================\n// HEADER/FOOTER REFERENCE PARSING\n// ============================================================================\n\n/**\n * Parse header type attribute\n */\nfunction parseHeaderFooterType(typeAttr: string | null): HeaderFooterType {\n switch (typeAttr) {\n case 'first':\n return 'first';\n case 'even':\n return 'even';\n case 'default':\n default:\n return 'default';\n }\n}\n\n/**\n * Parse a header reference from sectPr (w:headerReference)\n *\n * @param element - The w:headerReference element\n * @returns HeaderReference with type and rId\n */\nexport function parseHeaderReference(element: XmlElement): HeaderReference {\n const typeAttr = getAttribute(element, 'w', 'type');\n const rId = getAttribute(element, 'r', 'id') ?? '';\n\n return {\n type: parseHeaderFooterType(typeAttr),\n rId,\n };\n}\n\n/**\n * Parse a footer reference from sectPr (w:footerReference)\n *\n * @param element - The w:footerReference element\n * @returns FooterReference with type and rId\n */\nexport function parseFooterReference(element: XmlElement): FooterReference {\n const typeAttr = getAttribute(element, 'w', 'type');\n const rId = getAttribute(element, 'r', 'id') ?? '';\n\n return {\n type: parseHeaderFooterType(typeAttr),\n rId,\n };\n}\n\n/**\n * Parse all header references from a sectPr element\n *\n * @param sectPr - The w:sectPr element\n * @returns Array of HeaderReference objects\n */\nexport function parseHeaderReferences(sectPr: XmlElement): HeaderReference[] {\n const refs: HeaderReference[] = [];\n const headerRefElements = findChildren(sectPr, 'w', 'headerReference');\n\n for (const el of headerRefElements) {\n refs.push(parseHeaderReference(el));\n }\n\n return refs;\n}\n\n/**\n * Parse all footer references from a sectPr element\n *\n * @param sectPr - The w:sectPr element\n * @returns Array of FooterReference objects\n */\nexport function parseFooterReferences(sectPr: XmlElement): FooterReference[] {\n const refs: FooterReference[] = [];\n const footerRefElements = findChildren(sectPr, 'w', 'footerReference');\n\n for (const el of footerRefElements) {\n refs.push(parseFooterReference(el));\n }\n\n return refs;\n}\n\n// ============================================================================\n// HEADER/FOOTER CONTENT PARSING\n// ============================================================================\n\n/**\n * Parse header/footer content (paragraphs and tables)\n *\n * @param root - Root element (w:hdr or w:ftr)\n * @param styles - Style map for applying styles\n * @param theme - Theme for color resolution\n * @param numbering - Numbering definitions for lists\n * @param rels - Relationships for resolving hyperlinks/images\n * @param media - Media files for images\n * @returns Array of content elements (Paragraph | Table)\n */\nfunction parseHeaderFooterContent(\n root: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): (Paragraph | Table)[] {\n const content: (Paragraph | Table)[] = [];\n\n // Get all child elements\n const elements = root.elements ?? [];\n\n for (const el of elements) {\n if (el.type !== 'element') continue;\n\n const name = el.name ?? '';\n\n // Parse paragraphs\n if (name === 'w:p' || name.endsWith(':p')) {\n const paragraph = parseParagraph(el, styles, theme, numbering, rels, media);\n content.push(paragraph);\n }\n // Parse tables\n else if (name === 'w:tbl' || name.endsWith(':tbl')) {\n const table = parseTable(el, styles, theme, numbering, rels, media);\n content.push(table);\n }\n // SDT (structured document tags) can contain paragraphs/tables\n else if (name === 'w:sdt' || name.endsWith(':sdt')) {\n // Find sdtContent\n const sdtContentEl = (el.elements ?? []).find(\n (child: XmlElement) =>\n child.type === 'element' &&\n (child.name === 'w:sdtContent' || child.name?.endsWith(':sdtContent'))\n );\n if (sdtContentEl) {\n // Recursively parse content inside SDT\n const sdtContent = parseHeaderFooterContent(\n sdtContentEl,\n styles,\n theme,\n numbering,\n rels,\n media\n );\n content.push(...sdtContent);\n }\n }\n }\n\n return content;\n}\n\n/**\n * Parse a header XML file (word/header*.xml)\n *\n * @param headerXml - The raw XML content of the header file\n * @param hdrFtrType - The type of header (default, first, even)\n * @param styles - Parsed style map for applying styles\n * @param theme - Parsed theme for color resolution\n * @param numbering - Parsed numbering definitions for lists\n * @param rels - Relationships for resolving hyperlinks/images\n * @param media - Media files for images\n * @returns HeaderFooter object\n */\nexport function parseHeader(\n headerXml: string,\n hdrFtrType: HeaderFooterType = 'default',\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): HeaderFooter {\n const result: HeaderFooter = {\n type: 'header',\n hdrFtrType,\n content: [],\n };\n\n if (!headerXml) {\n return result;\n }\n\n const doc = parseXml(headerXml);\n if (!doc) {\n return result;\n }\n\n // Find the root header element (w:hdr)\n const rootElement = doc.elements?.find(\n (el: XmlElement) => el.type === 'element' && (el.name === 'w:hdr' || el.name?.endsWith(':hdr'))\n ) as XmlElement | undefined;\n\n if (!rootElement) {\n return result;\n }\n\n // Parse content\n result.content = parseHeaderFooterContent(rootElement, styles, theme, numbering, rels, media);\n\n return result;\n}\n\n/**\n * Parse a footer XML file (word/footer*.xml)\n *\n * @param footerXml - The raw XML content of the footer file\n * @param hdrFtrType - The type of footer (default, first, even)\n * @param styles - Parsed style map for applying styles\n * @param theme - Parsed theme for color resolution\n * @param numbering - Parsed numbering definitions for lists\n * @param rels - Relationships for resolving hyperlinks/images\n * @param media - Media files for images\n * @returns HeaderFooter object\n */\nexport function parseFooter(\n footerXml: string,\n hdrFtrType: HeaderFooterType = 'default',\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): HeaderFooter {\n const result: HeaderFooter = {\n type: 'footer',\n hdrFtrType,\n content: [],\n };\n\n if (!footerXml) {\n return result;\n }\n\n const doc = parseXml(footerXml);\n if (!doc) {\n return result;\n }\n\n // Find the root footer element (w:ftr)\n const rootElement = doc.elements?.find(\n (el: XmlElement) => el.type === 'element' && (el.name === 'w:ftr' || el.name?.endsWith(':ftr'))\n ) as XmlElement | undefined;\n\n if (!rootElement) {\n return result;\n }\n\n // Parse content\n result.content = parseHeaderFooterContent(rootElement, styles, theme, numbering, rels, media);\n\n return result;\n}\n\n/**\n * Generic function to parse either header or footer\n *\n * @param xml - Raw XML content\n * @param isHeader - true for header, false for footer\n * @param hdrFtrType - The type (default, first, even)\n * @param styles - Style map\n * @param theme - Theme\n * @param numbering - Numbering definitions\n * @param rels - Relationships\n * @param media - Media files\n * @returns HeaderFooter object\n */\nexport function parseHeaderFooter(\n xml: string,\n isHeader: boolean,\n hdrFtrType: HeaderFooterType = 'default',\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): HeaderFooter {\n if (isHeader) {\n return parseHeader(xml, hdrFtrType, styles, theme, numbering, rels, media);\n } else {\n return parseFooter(xml, hdrFtrType, styles, theme, numbering, rels, media);\n }\n}\n\n// ============================================================================\n// HEADER/FOOTER MAP CREATION\n// ============================================================================\n\n/**\n * Create a HeaderFooterMap from parsed headers/footers\n */\nfunction createHeaderFooterMap(byId: Map<string, HeaderFooter>): HeaderFooterMap {\n return {\n byId,\n\n get(rId: string): HeaderFooter | undefined {\n return byId.get(rId);\n },\n\n has(rId: string): boolean {\n return byId.has(rId);\n },\n\n getAll(): HeaderFooter[] {\n return Array.from(byId.values());\n },\n\n getByType(type: HeaderFooterType): HeaderFooter | undefined {\n for (const hf of byId.values()) {\n if (hf.hdrFtrType === type) {\n return hf;\n }\n }\n return undefined;\n },\n };\n}\n\n/**\n * Create an empty HeaderFooterMap\n */\nexport function createEmptyHeaderFooterMap(): HeaderFooterMap {\n return createHeaderFooterMap(new Map());\n}\n\n/**\n * Build a HeaderFooterMap from references and XML content\n *\n * @param references - Header or footer references from sectPr\n * @param xmlContents - Map of rId to XML content\n * @param isHeader - true for headers, false for footers\n * @param styles - Style map\n * @param theme - Theme\n * @param numbering - Numbering definitions\n * @param rels - Relationships\n * @param media - Media files\n * @returns HeaderFooterMap with all parsed headers/footers\n */\nexport function buildHeaderFooterMap(\n references: (HeaderReference | FooterReference)[],\n xmlContents: Map<string, string>,\n isHeader: boolean,\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): HeaderFooterMap {\n const byId = new Map<string, HeaderFooter>();\n\n for (const ref of references) {\n const xml = xmlContents.get(ref.rId);\n if (xml) {\n const hf = parseHeaderFooter(xml, isHeader, ref.type, styles, theme, numbering, rels, media);\n byId.set(ref.rId, hf);\n }\n }\n\n return createHeaderFooterMap(byId);\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Get plain text content of a header/footer\n */\nexport function getHeaderFooterText(hf: HeaderFooter): string {\n const texts: string[] = [];\n\n for (const item of hf.content) {\n if (item.type === 'paragraph') {\n const paraTexts: string[] = [];\n for (const content of item.content) {\n if (content.type === 'run') {\n for (const runContent of content.content) {\n if (runContent.type === 'text') {\n paraTexts.push(runContent.text);\n }\n }\n }\n }\n texts.push(paraTexts.join(''));\n } else if (item.type === 'table') {\n // Extract text from table cells\n for (const row of item.rows) {\n for (const cell of row.cells) {\n for (const cellContent of cell.content) {\n if (cellContent.type === 'paragraph') {\n const paraTexts: string[] = [];\n for (const content of cellContent.content) {\n if (content.type === 'run') {\n for (const runContent of content.content) {\n if (runContent.type === 'text') {\n paraTexts.push(runContent.text);\n }\n }\n }\n }\n texts.push(paraTexts.join(''));\n }\n }\n }\n }\n }\n }\n\n return texts.join('\\n');\n}\n\n/**\n * Check if header/footer is empty (no content)\n */\nexport function isEmptyHeaderFooter(hf: HeaderFooter): boolean {\n if (hf.content.length === 0) return true;\n\n // Check if all content is empty paragraphs\n for (const item of hf.content) {\n if (item.type === 'table') return false;\n if (item.type === 'paragraph' && item.content.length > 0) {\n // Check if paragraph has any actual content\n for (const content of item.content) {\n if (content.type !== 'run') return false;\n for (const rc of content.content) {\n if (rc.type === 'text' && rc.text.length > 0) return false;\n if (rc.type !== 'text') return false; // Has image, field, etc.\n }\n }\n }\n }\n\n return true;\n}\n\n/**\n * Check if header/footer has page number field\n */\nexport function hasPageNumberField(hf: HeaderFooter): boolean {\n for (const item of hf.content) {\n if (item.type === 'paragraph') {\n for (const content of item.content) {\n if (content.type === 'simpleField' || content.type === 'complexField') {\n if (content.fieldType === 'PAGE' || content.fieldType === 'NUMPAGES') {\n return true;\n }\n }\n if (content.type === 'run') {\n for (const rc of content.content) {\n if (rc.type === 'fieldChar' && rc.charType === 'begin') {\n // Part of a complex field - would need to check instruction\n // For simplicity, we'll check the field content in the paragraph\n continue;\n }\n }\n }\n }\n }\n }\n return false;\n}\n\n/**\n * Get the header for a given page considering type rules\n *\n * @param headers - Map of type to HeaderFooter\n * @param pageNumber - 1-based page number\n * @param isFirstPage - Whether this is the first page of the section\n * @param hasDifferentFirstPage - Whether different first page is enabled\n * @param hasDifferentOddEven - Whether different odd/even pages is enabled\n * @returns The appropriate HeaderFooter or undefined\n */\nexport function getHeaderForPage(\n headers: Map<HeaderFooterType, HeaderFooter>,\n pageNumber: number,\n isFirstPage: boolean,\n hasDifferentFirstPage: boolean,\n hasDifferentOddEven: boolean\n): HeaderFooter | undefined {\n // First page header takes priority if enabled\n if (isFirstPage && hasDifferentFirstPage) {\n const firstHeader = headers.get('first');\n if (firstHeader) return firstHeader;\n }\n\n // Even page header if enabled and page is even\n if (hasDifferentOddEven && pageNumber % 2 === 0) {\n const evenHeader = headers.get('even');\n if (evenHeader) return evenHeader;\n }\n\n // Default header for everything else\n return headers.get('default');\n}\n\n/**\n * Get the footer for a given page considering type rules\n * (Same logic as getHeaderForPage)\n */\nexport function getFooterForPage(\n footers: Map<HeaderFooterType, HeaderFooter>,\n pageNumber: number,\n isFirstPage: boolean,\n hasDifferentFirstPage: boolean,\n hasDifferentOddEven: boolean\n): HeaderFooter | undefined {\n if (isFirstPage && hasDifferentFirstPage) {\n const firstFooter = footers.get('first');\n if (firstFooter) return firstFooter;\n }\n\n if (hasDifferentOddEven && pageNumber % 2 === 0) {\n const evenFooter = footers.get('even');\n if (evenFooter) return evenFooter;\n }\n\n return footers.get('default');\n}\n\n/**\n * Convert HeaderFooterMap to type-indexed Map\n *\n * @param map - HeaderFooterMap\n * @returns Map indexed by HeaderFooterType\n */\nexport function headerFooterMapToTypeMap(\n map: HeaderFooterMap\n): Map<HeaderFooterType, HeaderFooter> {\n const result = new Map<HeaderFooterType, HeaderFooter>();\n\n for (const hf of map.getAll()) {\n // If there are multiple with same type, later ones overwrite\n result.set(hf.hdrFtrType, hf);\n }\n\n return result;\n}\n\n/**\n * Check if a HeaderFooter contains any images\n */\nexport function hasImages(hf: HeaderFooter): boolean {\n for (const item of hf.content) {\n if (item.type === 'paragraph') {\n for (const content of item.content) {\n if (content.type === 'run') {\n for (const rc of content.content) {\n if (rc.type === 'drawing') return true;\n }\n }\n }\n }\n }\n return false;\n}\n\n/**\n * Check if a HeaderFooter contains any tables\n */\nexport function hasTables(hf: HeaderFooter): boolean {\n for (const item of hf.content) {\n if (item.type === 'table') return true;\n }\n return false;\n}\n","/**\n * Footnote/Endnote Parser - Parse footnotes.xml and endnotes.xml\n *\n * Footnotes and endnotes are stored in separate XML files within the DOCX package:\n * - word/footnotes.xml - Contains all footnote definitions\n * - word/endnotes.xml - Contains all endnote definitions\n *\n * Each note contains:\n * - An ID that matches references in document.xml (w:footnoteReference, w:endnoteReference)\n * - A type (normal, separator, continuationSeparator, continuationNotice)\n * - Content (paragraphs)\n *\n * The references in the document body are parsed by runParser as NoteReferenceContent.\n *\n * OOXML Reference:\n * - Footnote: w:footnote[@w:id][@w:type]\n * - Endnote: w:endnote[@w:id][@w:type]\n * - Content: w:p (paragraphs)\n */\n\nimport type {\n Footnote,\n Endnote,\n FootnoteProperties,\n EndnoteProperties,\n FootnotePosition,\n EndnotePosition,\n NoteNumberRestart,\n NumberFormat,\n Paragraph,\n Theme,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport type { NumberingMap } from './numberingParser';\nimport {\n parseXml,\n findChild,\n findChildren,\n getAttribute,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\nimport { parseParagraph } from './paragraphParser';\n\n// ============================================================================\n// FOOTNOTE MAP INTERFACE\n// ============================================================================\n\n/**\n * Footnote map returned by parseFootnotes\n */\nexport interface FootnoteMap {\n /** All footnotes indexed by ID */\n byId: Map<number, Footnote>;\n\n /** Array of all footnotes in document order */\n footnotes: Footnote[];\n\n /** Get footnote by ID */\n getFootnote(id: number): Footnote | undefined;\n\n /** Check if footnote exists */\n hasFootnote(id: number): boolean;\n\n /** Get all normal (non-separator) footnotes */\n getNormalFootnotes(): Footnote[];\n\n /** Get separator footnote if exists */\n getSeparator(): Footnote | undefined;\n\n /** Get continuation separator if exists */\n getContinuationSeparator(): Footnote | undefined;\n}\n\n/**\n * Endnote map returned by parseEndnotes\n */\nexport interface EndnoteMap {\n /** All endnotes indexed by ID */\n byId: Map<number, Endnote>;\n\n /** Array of all endnotes in document order */\n endnotes: Endnote[];\n\n /** Get endnote by ID */\n getEndnote(id: number): Endnote | undefined;\n\n /** Check if endnote exists */\n hasEndnote(id: number): boolean;\n\n /** Get all normal (non-separator) endnotes */\n getNormalEndnotes(): Endnote[];\n\n /** Get separator endnote if exists */\n getSeparator(): Endnote | undefined;\n\n /** Get continuation separator if exists */\n getContinuationSeparator(): Endnote | undefined;\n}\n\n// ============================================================================\n// NOTE TYPE PARSING\n// ============================================================================\n\n/**\n * Parse note type attribute\n */\nfunction parseNoteType(\n typeAttr: string | null\n): 'normal' | 'separator' | 'continuationSeparator' | 'continuationNotice' {\n switch (typeAttr) {\n case 'separator':\n return 'separator';\n case 'continuationSeparator':\n return 'continuationSeparator';\n case 'continuationNotice':\n return 'continuationNotice';\n default:\n return 'normal';\n }\n}\n\n// ============================================================================\n// FOOTNOTE PARSING\n// ============================================================================\n\n/**\n * Parse a single footnote element (w:footnote)\n */\nfunction parseFootnote(\n element: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n _media: Map<string, MediaFile> | null\n): Footnote {\n const id = parseNumericAttribute(element, 'w', 'id') ?? 0;\n const typeAttr = getAttribute(element, 'w', 'type');\n const noteType = parseNoteType(typeAttr);\n\n // Parse content paragraphs\n const paragraphElements = findChildren(element, 'w', 'p');\n const content: Paragraph[] = paragraphElements.map((pEl) =>\n parseParagraph(pEl, styles, theme, numbering, rels)\n );\n\n return {\n type: 'footnote',\n id,\n noteType,\n content,\n };\n}\n\n/**\n * Parse footnotes.xml\n *\n * @param footnotesXml - The raw XML content of word/footnotes.xml\n * @param styles - Parsed style map for applying styles\n * @param theme - Parsed theme for color resolution\n * @param numbering - Parsed numbering definitions for lists\n * @param rels - Relationships for resolving hyperlinks\n * @param media - Media files for images\n * @returns FootnoteMap with all footnotes\n */\nexport function parseFootnotes(\n footnotesXml: string | null,\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): FootnoteMap {\n const byId = new Map<number, Footnote>();\n const footnotes: Footnote[] = [];\n\n if (!footnotesXml) {\n return createFootnoteMap(byId, footnotes);\n }\n\n const doc = parseXml(footnotesXml);\n if (!doc) {\n return createFootnoteMap(byId, footnotes);\n }\n\n // Find the root footnotes element\n const rootElement = doc.elements?.find(\n (el: XmlElement) =>\n el.type === 'element' && (el.name === 'w:footnotes' || el.name?.endsWith(':footnotes'))\n ) as XmlElement | undefined;\n\n if (!rootElement) {\n return createFootnoteMap(byId, footnotes);\n }\n\n // Parse all footnote elements\n const footnoteElements = findChildren(rootElement, 'w', 'footnote');\n\n for (const fnEl of footnoteElements) {\n const footnote = parseFootnote(fnEl, styles, theme, numbering, rels, media);\n byId.set(footnote.id, footnote);\n footnotes.push(footnote);\n }\n\n return createFootnoteMap(byId, footnotes);\n}\n\n/**\n * Create FootnoteMap object with helper methods\n */\nfunction createFootnoteMap(byId: Map<number, Footnote>, footnotes: Footnote[]): FootnoteMap {\n return {\n byId,\n footnotes,\n\n getFootnote(id: number): Footnote | undefined {\n return byId.get(id);\n },\n\n hasFootnote(id: number): boolean {\n return byId.has(id);\n },\n\n getNormalFootnotes(): Footnote[] {\n return footnotes.filter((fn) => fn.noteType === 'normal');\n },\n\n getSeparator(): Footnote | undefined {\n return footnotes.find((fn) => fn.noteType === 'separator');\n },\n\n getContinuationSeparator(): Footnote | undefined {\n return footnotes.find((fn) => fn.noteType === 'continuationSeparator');\n },\n };\n}\n\n// ============================================================================\n// ENDNOTE PARSING\n// ============================================================================\n\n/**\n * Parse a single endnote element (w:endnote)\n */\nfunction parseEndnote(\n element: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n _media: Map<string, MediaFile> | null\n): Endnote {\n const id = parseNumericAttribute(element, 'w', 'id') ?? 0;\n const typeAttr = getAttribute(element, 'w', 'type');\n const noteType = parseNoteType(typeAttr);\n\n // Parse content paragraphs\n const paragraphElements = findChildren(element, 'w', 'p');\n const content: Paragraph[] = paragraphElements.map((pEl) =>\n parseParagraph(pEl, styles, theme, numbering, rels)\n );\n\n return {\n type: 'endnote',\n id,\n noteType,\n content,\n };\n}\n\n/**\n * Parse endnotes.xml\n *\n * @param endnotesXml - The raw XML content of word/endnotes.xml\n * @param styles - Parsed style map for applying styles\n * @param theme - Parsed theme for color resolution\n * @param numbering - Parsed numbering definitions for lists\n * @param rels - Relationships for resolving hyperlinks\n * @param media - Media files for images\n * @returns EndnoteMap with all endnotes\n */\nexport function parseEndnotes(\n endnotesXml: string | null,\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): EndnoteMap {\n const byId = new Map<number, Endnote>();\n const endnotes: Endnote[] = [];\n\n if (!endnotesXml) {\n return createEndnoteMap(byId, endnotes);\n }\n\n const doc = parseXml(endnotesXml);\n if (!doc) {\n return createEndnoteMap(byId, endnotes);\n }\n\n // Find the root endnotes element\n const rootElement = doc.elements?.find(\n (el: XmlElement) =>\n el.type === 'element' && (el.name === 'w:endnotes' || el.name?.endsWith(':endnotes'))\n ) as XmlElement | undefined;\n\n if (!rootElement) {\n return createEndnoteMap(byId, endnotes);\n }\n\n // Parse all endnote elements\n const endnoteElements = findChildren(rootElement, 'w', 'endnote');\n\n for (const enEl of endnoteElements) {\n const endnote = parseEndnote(enEl, styles, theme, numbering, rels, media);\n byId.set(endnote.id, endnote);\n endnotes.push(endnote);\n }\n\n return createEndnoteMap(byId, endnotes);\n}\n\n/**\n * Create EndnoteMap object with helper methods\n */\nfunction createEndnoteMap(byId: Map<number, Endnote>, endnotes: Endnote[]): EndnoteMap {\n return {\n byId,\n endnotes,\n\n getEndnote(id: number): Endnote | undefined {\n return byId.get(id);\n },\n\n hasEndnote(id: number): boolean {\n return byId.has(id);\n },\n\n getNormalEndnotes(): Endnote[] {\n return endnotes.filter((en) => en.noteType === 'normal');\n },\n\n getSeparator(): Endnote | undefined {\n return endnotes.find((en) => en.noteType === 'separator');\n },\n\n getContinuationSeparator(): Endnote | undefined {\n return endnotes.find((en) => en.noteType === 'continuationSeparator');\n },\n };\n}\n\n// ============================================================================\n// FOOTNOTE/ENDNOTE PROPERTIES PARSING\n// ============================================================================\n\n/**\n * Parse number format from w:numFmt element\n */\nfunction parseNumberFormat(numFmtAttr: string | null): NumberFormat | undefined {\n if (!numFmtAttr) return undefined;\n\n // Map OOXML numFmt values to our NumberFormat type\n const formatMap: Record<string, NumberFormat> = {\n decimal: 'decimal',\n upperRoman: 'upperRoman',\n lowerRoman: 'lowerRoman',\n upperLetter: 'upperLetter',\n lowerLetter: 'lowerLetter',\n ordinal: 'ordinal',\n cardinalText: 'cardinalText',\n ordinalText: 'ordinalText',\n bullet: 'bullet',\n chicago: 'chicago',\n none: 'none',\n };\n\n return formatMap[numFmtAttr] as NumberFormat | undefined;\n}\n\n/**\n * Parse footnote position\n */\nfunction parseFootnotePosition(posAttr: string | null): FootnotePosition | undefined {\n switch (posAttr) {\n case 'pageBottom':\n return 'pageBottom';\n case 'beneathText':\n return 'beneathText';\n case 'sectEnd':\n return 'sectEnd';\n case 'docEnd':\n return 'docEnd';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse endnote position\n */\nfunction parseEndnotePosition(posAttr: string | null): EndnotePosition | undefined {\n switch (posAttr) {\n case 'sectEnd':\n return 'sectEnd';\n case 'docEnd':\n return 'docEnd';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse number restart type\n */\nfunction parseNumberRestart(restartAttr: string | null): NoteNumberRestart | undefined {\n switch (restartAttr) {\n case 'continuous':\n return 'continuous';\n case 'eachSect':\n return 'eachSect';\n case 'eachPage':\n return 'eachPage';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse footnote properties from w:footnotePr element\n * (Can appear in w:sectPr or w:settings)\n */\nexport function parseFootnoteProperties(element: XmlElement | null): FootnoteProperties {\n const props: FootnoteProperties = {};\n\n if (!element) return props;\n\n // Position (w:pos)\n const posEl = findChild(element, 'w', 'pos');\n if (posEl) {\n const posAttr = getAttribute(posEl, 'w', 'val');\n props.position = parseFootnotePosition(posAttr);\n }\n\n // Number format (w:numFmt)\n const numFmtEl = findChild(element, 'w', 'numFmt');\n if (numFmtEl) {\n const fmtAttr = getAttribute(numFmtEl, 'w', 'val');\n props.numFmt = parseNumberFormat(fmtAttr);\n }\n\n // Start number (w:numStart)\n const numStartEl = findChild(element, 'w', 'numStart');\n if (numStartEl) {\n props.numStart = parseNumericAttribute(numStartEl, 'w', 'val') ?? undefined;\n }\n\n // Number restart (w:numRestart)\n const numRestartEl = findChild(element, 'w', 'numRestart');\n if (numRestartEl) {\n const restartAttr = getAttribute(numRestartEl, 'w', 'val');\n props.numRestart = parseNumberRestart(restartAttr);\n }\n\n return props;\n}\n\n/**\n * Parse endnote properties from w:endnotePr element\n * (Can appear in w:sectPr or w:settings)\n */\nexport function parseEndnoteProperties(element: XmlElement | null): EndnoteProperties {\n const props: EndnoteProperties = {};\n\n if (!element) return props;\n\n // Position (w:pos)\n const posEl = findChild(element, 'w', 'pos');\n if (posEl) {\n const posAttr = getAttribute(posEl, 'w', 'val');\n props.position = parseEndnotePosition(posAttr);\n }\n\n // Number format (w:numFmt)\n const numFmtEl = findChild(element, 'w', 'numFmt');\n if (numFmtEl) {\n const fmtAttr = getAttribute(numFmtEl, 'w', 'val');\n props.numFmt = parseNumberFormat(fmtAttr);\n }\n\n // Start number (w:numStart)\n const numStartEl = findChild(element, 'w', 'numStart');\n if (numStartEl) {\n props.numStart = parseNumericAttribute(numStartEl, 'w', 'val') ?? undefined;\n }\n\n // Number restart (w:numRestart)\n const numRestartEl = findChild(element, 'w', 'numRestart');\n if (numRestartEl) {\n const restartAttr = getAttribute(numRestartEl, 'w', 'val');\n props.numRestart = parseNumberRestart(restartAttr);\n }\n\n return props;\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Get plain text content of a footnote\n */\nexport function getFootnoteText(footnote: Footnote): string {\n // Import getParagraphText dynamically to avoid circular dependency\n const texts: string[] = [];\n\n for (const para of footnote.content) {\n const paraTexts: string[] = [];\n for (const content of para.content) {\n if (content.type === 'run') {\n for (const runContent of content.content) {\n if (runContent.type === 'text') {\n paraTexts.push(runContent.text);\n }\n }\n }\n }\n texts.push(paraTexts.join(''));\n }\n\n return texts.join('\\n');\n}\n\n/**\n * Get plain text content of an endnote\n */\nexport function getEndnoteText(endnote: Endnote): string {\n const texts: string[] = [];\n\n for (const para of endnote.content) {\n const paraTexts: string[] = [];\n for (const content of para.content) {\n if (content.type === 'run') {\n for (const runContent of content.content) {\n if (runContent.type === 'text') {\n paraTexts.push(runContent.text);\n }\n }\n }\n }\n texts.push(paraTexts.join(''));\n }\n\n return texts.join('\\n');\n}\n\n/**\n * Check if a footnote is a separator (not regular content)\n */\nexport function isSeparatorFootnote(footnote: Footnote): boolean {\n return (\n footnote.noteType === 'separator' ||\n footnote.noteType === 'continuationSeparator' ||\n footnote.noteType === 'continuationNotice'\n );\n}\n\n/**\n * Check if an endnote is a separator (not regular content)\n */\nexport function isSeparatorEndnote(endnote: Endnote): boolean {\n return (\n endnote.noteType === 'separator' ||\n endnote.noteType === 'continuationSeparator' ||\n endnote.noteType === 'continuationNotice'\n );\n}\n\n/**\n * Get footnote number for display (excluding separators)\n * @param footnote - The footnote to get the number for\n * @param footnoteMap - The footnote map\n * @param startNumber - Starting number (default 1)\n * @returns The display number, or null for separator footnotes\n */\nexport function getFootnoteDisplayNumber(\n footnote: Footnote,\n footnoteMap: FootnoteMap,\n startNumber: number = 1\n): number | null {\n if (isSeparatorFootnote(footnote)) {\n return null;\n }\n\n const normalFootnotes = footnoteMap.getNormalFootnotes();\n const index = normalFootnotes.findIndex((fn) => fn.id === footnote.id);\n\n if (index === -1) {\n return null;\n }\n\n return startNumber + index;\n}\n\n/**\n * Get endnote number for display (excluding separators)\n * @param endnote - The endnote to get the number for\n * @param endnoteMap - The endnote map\n * @param startNumber - Starting number (default 1)\n * @returns The display number, or null for separator endnotes\n */\nexport function getEndnoteDisplayNumber(\n endnote: Endnote,\n endnoteMap: EndnoteMap,\n startNumber: number = 1\n): number | null {\n if (isSeparatorEndnote(endnote)) {\n return null;\n }\n\n const normalEndnotes = endnoteMap.getNormalEndnotes();\n const index = normalEndnotes.findIndex((en) => en.id === endnote.id);\n\n if (index === -1) {\n return null;\n }\n\n return startNumber + index;\n}\n\n/**\n * Create an empty footnote map\n */\nexport function createEmptyFootnoteMap(): FootnoteMap {\n return createFootnoteMap(new Map(), []);\n}\n\n/**\n * Create an empty endnote map\n */\nexport function createEmptyEndnoteMap(): EndnoteMap {\n return createEndnoteMap(new Map(), []);\n}\n\n/**\n * Merge multiple footnote maps (e.g., from different documents)\n */\nexport function mergeFootnoteMaps(...maps: FootnoteMap[]): FootnoteMap {\n const byId = new Map<number, Footnote>();\n const footnotes: Footnote[] = [];\n\n for (const map of maps) {\n for (const fn of map.footnotes) {\n if (!byId.has(fn.id)) {\n byId.set(fn.id, fn);\n footnotes.push(fn);\n }\n }\n }\n\n return createFootnoteMap(byId, footnotes);\n}\n\n/**\n * Merge multiple endnote maps (e.g., from different documents)\n */\nexport function mergeEndnoteMaps(...maps: EndnoteMap[]): EndnoteMap {\n const byId = new Map<number, Endnote>();\n const endnotes: Endnote[] = [];\n\n for (const map of maps) {\n for (const en of map.endnotes) {\n if (!byId.has(en.id)) {\n byId.set(en.id, en);\n endnotes.push(en);\n }\n }\n }\n\n return createEndnoteMap(byId, endnotes);\n}\n","/**\n * Section Properties Parser - Parse section properties (w:sectPr)\n *\n * Section properties define page layout and settings for a section of the document.\n * They appear in two places:\n * 1. Within a paragraph's properties (w:p/w:pPr/w:sectPr) - marks end of a section\n * 2. At the end of the document body (w:body/w:sectPr) - final section properties\n *\n * OOXML Reference:\n * - w:pgSz: Page size (width, height, orientation)\n * - w:pgMar: Page margins (top, bottom, left, right, header, footer, gutter)\n * - w:cols: Column definitions\n * - w:type: Section start type\n * - w:vAlign: Vertical alignment\n * - w:headerReference, w:footerReference: Header/footer references\n * - w:titlePg: Different first page\n * - w:lnNumType: Line numbering\n * - w:pgBorders: Page borders\n * - w:docGrid: Document grid\n * - w:footnotePr, w:endnotePr: Footnote/endnote properties\n */\n\nimport type {\n SectionProperties,\n PageOrientation,\n SectionStart,\n VerticalAlign,\n LineNumberRestart,\n Column,\n BorderSpec,\n ColorValue,\n ThemeColorSlot,\n RelationshipMap,\n} from '../types/document';\nimport {\n findChild,\n findChildren,\n getAttribute,\n parseNumericAttribute,\n parseBooleanElement,\n type XmlElement,\n} from './xmlParser';\nimport { parseHeaderReference, parseFooterReference } from './headerFooterParser';\nimport { parseFootnoteProperties, parseEndnoteProperties } from './footnoteParser';\n\n// ============================================================================\n// HELPER PARSERS\n// ============================================================================\n\n/**\n * Parse a color element/attribute for page borders/background\n */\nfunction parseColorValue(\n colorStr: string | null,\n themeColor: string | null,\n themeTint: string | null,\n themeShade: string | null\n): ColorValue | undefined {\n if (!colorStr && !themeColor) return undefined;\n\n const color: ColorValue = {};\n\n if (colorStr && colorStr !== 'auto') {\n color.rgb = colorStr;\n } else if (colorStr === 'auto') {\n color.auto = true;\n }\n\n if (themeColor) {\n color.themeColor = themeColor as ThemeColorSlot;\n }\n if (themeTint) {\n color.themeTint = themeTint;\n }\n if (themeShade) {\n color.themeShade = themeShade;\n }\n\n return Object.keys(color).length > 0 ? color : undefined;\n}\n\n/**\n * Parse a border element for page borders\n */\nfunction parseBorderSpec(element: XmlElement | null): BorderSpec | undefined {\n if (!element) return undefined;\n\n const styleStr = getAttribute(element, 'w', 'val') ?? 'none';\n const style = styleStr as BorderSpec['style'];\n\n const border: BorderSpec = { style };\n\n // Size in eighths of a point\n const sz = parseNumericAttribute(element, 'w', 'sz');\n if (sz !== undefined) {\n border.size = sz;\n }\n\n // Space from text/page edge in points\n const space = parseNumericAttribute(element, 'w', 'space');\n if (space !== undefined) {\n border.space = space;\n }\n\n // Color\n const colorVal = getAttribute(element, 'w', 'color');\n const themeColor = getAttribute(element, 'w', 'themeColor');\n const themeTint = getAttribute(element, 'w', 'themeTint');\n const themeShade = getAttribute(element, 'w', 'themeShade');\n const color = parseColorValue(colorVal, themeColor, themeTint, themeShade);\n if (color) {\n border.color = color;\n }\n\n // Shadow effect\n const shadow = getAttribute(element, 'w', 'shadow');\n if (shadow === '1' || shadow === 'true') {\n border.shadow = true;\n }\n\n // Frame effect\n const frame = getAttribute(element, 'w', 'frame');\n if (frame === '1' || frame === 'true') {\n border.frame = true;\n }\n\n return border;\n}\n\n/**\n * Parse page orientation\n */\nfunction parseOrientation(orient: string | null): PageOrientation | undefined {\n switch (orient) {\n case 'landscape':\n return 'landscape';\n case 'portrait':\n return 'portrait';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse section start type\n */\nfunction parseSectionStart(type: string | null): SectionStart | undefined {\n switch (type) {\n case 'continuous':\n return 'continuous';\n case 'nextPage':\n return 'nextPage';\n case 'oddPage':\n return 'oddPage';\n case 'evenPage':\n return 'evenPage';\n case 'nextColumn':\n return 'nextColumn';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse vertical alignment\n */\nfunction parseVerticalAlign(align: string | null): VerticalAlign | undefined {\n switch (align) {\n case 'top':\n return 'top';\n case 'center':\n return 'center';\n case 'both':\n return 'both';\n case 'bottom':\n return 'bottom';\n default:\n return undefined;\n }\n}\n\n/**\n * Parse line number restart type\n */\nfunction parseLineNumberRestart(restart: string | null): LineNumberRestart | undefined {\n switch (restart) {\n case 'continuous':\n return 'continuous';\n case 'newPage':\n return 'newPage';\n case 'newSection':\n return 'newSection';\n default:\n return undefined;\n }\n}\n\n// ============================================================================\n// MAIN PARSER\n// ============================================================================\n\n/**\n * Parse section properties (w:sectPr)\n *\n * @param sectPr - The w:sectPr element\n * @param rels - Optional relationships for resolving header/footer references\n * @returns SectionProperties object\n */\nexport function parseSectionProperties(\n sectPr: XmlElement | null,\n _rels?: RelationshipMap | null\n): SectionProperties {\n const props: SectionProperties = {};\n\n if (!sectPr) return props;\n\n // ============================================================================\n // PAGE SIZE (w:pgSz)\n // ============================================================================\n const pgSz = findChild(sectPr, 'w', 'pgSz');\n if (pgSz) {\n // Width in twips\n const w = parseNumericAttribute(pgSz, 'w', 'w');\n if (w !== undefined) {\n props.pageWidth = w;\n }\n\n // Height in twips\n const h = parseNumericAttribute(pgSz, 'w', 'h');\n if (h !== undefined) {\n props.pageHeight = h;\n }\n\n // Orientation\n const orient = getAttribute(pgSz, 'w', 'orient');\n const orientation = parseOrientation(orient);\n if (orientation) {\n props.orientation = orientation;\n }\n }\n\n // ============================================================================\n // PAGE MARGINS (w:pgMar)\n // ============================================================================\n const pgMar = findChild(sectPr, 'w', 'pgMar');\n if (pgMar) {\n // Top margin in twips\n const top = parseNumericAttribute(pgMar, 'w', 'top');\n if (top !== undefined) {\n props.marginTop = top;\n }\n\n // Bottom margin in twips\n const bottom = parseNumericAttribute(pgMar, 'w', 'bottom');\n if (bottom !== undefined) {\n props.marginBottom = bottom;\n }\n\n // Left margin in twips\n const left = parseNumericAttribute(pgMar, 'w', 'left');\n if (left !== undefined) {\n props.marginLeft = left;\n }\n\n // Right margin in twips\n const right = parseNumericAttribute(pgMar, 'w', 'right');\n if (right !== undefined) {\n props.marginRight = right;\n }\n\n // Header distance from top in twips\n const header = parseNumericAttribute(pgMar, 'w', 'header');\n if (header !== undefined) {\n props.headerDistance = header;\n }\n\n // Footer distance from bottom in twips\n const footer = parseNumericAttribute(pgMar, 'w', 'footer');\n if (footer !== undefined) {\n props.footerDistance = footer;\n }\n\n // Gutter margin in twips\n const gutter = parseNumericAttribute(pgMar, 'w', 'gutter');\n if (gutter !== undefined) {\n props.gutter = gutter;\n }\n }\n\n // ============================================================================\n // COLUMNS (w:cols)\n // ============================================================================\n const cols = findChild(sectPr, 'w', 'cols');\n if (cols) {\n // Number of columns\n const num = parseNumericAttribute(cols, 'w', 'num');\n if (num !== undefined) {\n props.columnCount = num;\n }\n\n // Space between columns in twips\n const space = parseNumericAttribute(cols, 'w', 'space');\n if (space !== undefined) {\n props.columnSpace = space;\n }\n\n // Equal width\n const equalWidth = getAttribute(cols, 'w', 'equalWidth');\n if (equalWidth === '1' || equalWidth === 'true') {\n props.equalWidth = true;\n } else if (equalWidth === '0' || equalWidth === 'false') {\n props.equalWidth = false;\n }\n\n // Separator line between columns\n const sep = getAttribute(cols, 'w', 'sep');\n if (sep === '1' || sep === 'true') {\n props.separator = true;\n }\n\n // Individual column definitions (w:col)\n const colElements = findChildren(cols, 'w', 'col');\n if (colElements.length > 0) {\n props.columns = [];\n for (const colEl of colElements) {\n const column: Column = {};\n\n const colWidth = parseNumericAttribute(colEl, 'w', 'w');\n if (colWidth !== undefined) {\n column.width = colWidth;\n }\n\n const colSpace = parseNumericAttribute(colEl, 'w', 'space');\n if (colSpace !== undefined) {\n column.space = colSpace;\n }\n\n props.columns.push(column);\n }\n }\n }\n\n // ============================================================================\n // SECTION TYPE (w:type)\n // ============================================================================\n const typeEl = findChild(sectPr, 'w', 'type');\n if (typeEl) {\n const val = getAttribute(typeEl, 'w', 'val');\n const sectionStart = parseSectionStart(val);\n if (sectionStart) {\n props.sectionStart = sectionStart;\n }\n }\n\n // ============================================================================\n // VERTICAL ALIGNMENT (w:vAlign)\n // ============================================================================\n const vAlign = findChild(sectPr, 'w', 'vAlign');\n if (vAlign) {\n const val = getAttribute(vAlign, 'w', 'val');\n const verticalAlign = parseVerticalAlign(val);\n if (verticalAlign) {\n props.verticalAlign = verticalAlign;\n }\n }\n\n // ============================================================================\n // BIDIRECTIONAL (w:bidi)\n // ============================================================================\n const bidi = findChild(sectPr, 'w', 'bidi');\n if (bidi) {\n props.bidi = parseBooleanElement(bidi);\n }\n\n // ============================================================================\n // HEADER REFERENCES (w:headerReference)\n // ============================================================================\n const headerRefs = findChildren(sectPr, 'w', 'headerReference');\n if (headerRefs.length > 0) {\n props.headerReferences = headerRefs.map((el) => parseHeaderReference(el));\n }\n\n // ============================================================================\n // FOOTER REFERENCES (w:footerReference)\n // ============================================================================\n const footerRefs = findChildren(sectPr, 'w', 'footerReference');\n if (footerRefs.length > 0) {\n props.footerReferences = footerRefs.map((el) => parseFooterReference(el));\n }\n\n // ============================================================================\n // TITLE PAGE / DIFFERENT FIRST PAGE (w:titlePg)\n // ============================================================================\n const titlePg = findChild(sectPr, 'w', 'titlePg');\n if (titlePg) {\n props.titlePg = parseBooleanElement(titlePg);\n }\n\n // ============================================================================\n // DIFFERENT ODD/EVEN HEADERS (w:evenAndOddHeaders)\n // Note: This is typically in settings.xml, but can also be in sectPr\n // ============================================================================\n const evenAndOddHeaders = findChild(sectPr, 'w', 'evenAndOddHeaders');\n if (evenAndOddHeaders) {\n props.evenAndOddHeaders = parseBooleanElement(evenAndOddHeaders);\n }\n\n // ============================================================================\n // LINE NUMBERS (w:lnNumType)\n // ============================================================================\n const lnNumType = findChild(sectPr, 'w', 'lnNumType');\n if (lnNumType) {\n props.lineNumbers = {};\n\n const start = parseNumericAttribute(lnNumType, 'w', 'start');\n if (start !== undefined) {\n props.lineNumbers.start = start;\n }\n\n const countBy = parseNumericAttribute(lnNumType, 'w', 'countBy');\n if (countBy !== undefined) {\n props.lineNumbers.countBy = countBy;\n }\n\n const distance = parseNumericAttribute(lnNumType, 'w', 'distance');\n if (distance !== undefined) {\n props.lineNumbers.distance = distance;\n }\n\n const restart = getAttribute(lnNumType, 'w', 'restart');\n const restartValue = parseLineNumberRestart(restart);\n if (restartValue) {\n props.lineNumbers.restart = restartValue;\n }\n }\n\n // ============================================================================\n // PAGE BORDERS (w:pgBorders)\n // ============================================================================\n const pgBorders = findChild(sectPr, 'w', 'pgBorders');\n if (pgBorders) {\n props.pageBorders = {};\n\n // Top border\n const topBorder = parseBorderSpec(findChild(pgBorders, 'w', 'top'));\n if (topBorder) {\n props.pageBorders.top = topBorder;\n }\n\n // Bottom border\n const bottomBorder = parseBorderSpec(findChild(pgBorders, 'w', 'bottom'));\n if (bottomBorder) {\n props.pageBorders.bottom = bottomBorder;\n }\n\n // Left border\n const leftBorder = parseBorderSpec(findChild(pgBorders, 'w', 'left'));\n if (leftBorder) {\n props.pageBorders.left = leftBorder;\n }\n\n // Right border\n const rightBorder = parseBorderSpec(findChild(pgBorders, 'w', 'right'));\n if (rightBorder) {\n props.pageBorders.right = rightBorder;\n }\n\n // Display setting (allPages, firstPage, notFirstPage)\n const display = getAttribute(pgBorders, 'w', 'display');\n if (display === 'allPages' || display === 'firstPage' || display === 'notFirstPage') {\n props.pageBorders.display = display;\n }\n\n // Offset from (page or text)\n const offsetFrom = getAttribute(pgBorders, 'w', 'offsetFrom');\n if (offsetFrom === 'page' || offsetFrom === 'text') {\n props.pageBorders.offsetFrom = offsetFrom;\n }\n\n // Z-order (front or back)\n const zOrder = getAttribute(pgBorders, 'w', 'zOrder');\n if (zOrder === 'front' || zOrder === 'back') {\n props.pageBorders.zOrder = zOrder;\n }\n }\n\n // ============================================================================\n // PAGE BACKGROUND (w:background)\n // Note: Background is usually at document level, but checking here too\n // ============================================================================\n const background = findChild(sectPr, 'w', 'background');\n if (background) {\n props.background = {};\n\n const colorVal = getAttribute(background, 'w', 'color');\n if (colorVal && colorVal !== 'auto') {\n props.background.color = { rgb: colorVal };\n }\n\n const themeColor = getAttribute(background, 'w', 'themeColor');\n if (themeColor) {\n props.background.themeColor = themeColor as ThemeColorSlot;\n }\n\n const themeTint = getAttribute(background, 'w', 'themeTint');\n if (themeTint) {\n props.background.themeTint = themeTint;\n }\n\n const themeShade = getAttribute(background, 'w', 'themeShade');\n if (themeShade) {\n props.background.themeShade = themeShade;\n }\n }\n\n // ============================================================================\n // FOOTNOTE PROPERTIES (w:footnotePr)\n // ============================================================================\n const footnotePr = findChild(sectPr, 'w', 'footnotePr');\n if (footnotePr) {\n const fnProps = parseFootnoteProperties(footnotePr);\n if (Object.keys(fnProps).length > 0) {\n props.footnotePr = fnProps;\n }\n }\n\n // ============================================================================\n // ENDNOTE PROPERTIES (w:endnotePr)\n // ============================================================================\n const endnotePr = findChild(sectPr, 'w', 'endnotePr');\n if (endnotePr) {\n const enProps = parseEndnoteProperties(endnotePr);\n if (Object.keys(enProps).length > 0) {\n props.endnotePr = enProps;\n }\n }\n\n // ============================================================================\n // DOCUMENT GRID (w:docGrid)\n // ============================================================================\n const docGrid = findChild(sectPr, 'w', 'docGrid');\n if (docGrid) {\n props.docGrid = {};\n\n const gridType = getAttribute(docGrid, 'w', 'type');\n if (\n gridType === 'default' ||\n gridType === 'lines' ||\n gridType === 'linesAndChars' ||\n gridType === 'snapToChars'\n ) {\n props.docGrid.type = gridType;\n }\n\n const linePitch = parseNumericAttribute(docGrid, 'w', 'linePitch');\n if (linePitch !== undefined) {\n props.docGrid.linePitch = linePitch;\n }\n\n const charSpace = parseNumericAttribute(docGrid, 'w', 'charSpace');\n if (charSpace !== undefined) {\n props.docGrid.charSpace = charSpace;\n }\n }\n\n // ============================================================================\n // PAPER SOURCE (w:paperSrc)\n // ============================================================================\n const paperSrc = findChild(sectPr, 'w', 'paperSrc');\n if (paperSrc) {\n const first = parseNumericAttribute(paperSrc, 'w', 'first');\n if (first !== undefined) {\n props.paperSrcFirst = first;\n }\n\n const other = parseNumericAttribute(paperSrc, 'w', 'other');\n if (other !== undefined) {\n props.paperSrcOther = other;\n }\n }\n\n return props;\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Get page width in pixels (96 DPI)\n *\n * @param props - Section properties\n * @param defaultWidth - Default width in twips (default: 12240 = 8.5 inches)\n * @returns Width in pixels\n */\nexport function getPageWidthPixels(props: SectionProperties, defaultWidth: number = 12240): number {\n const twips = props.pageWidth ?? defaultWidth;\n // 1 inch = 1440 twips, 1 inch = 96 pixels at 96 DPI\n return Math.round((twips / 1440) * 96);\n}\n\n/**\n * Get page height in pixels (96 DPI)\n *\n * @param props - Section properties\n * @param defaultHeight - Default height in twips (default: 15840 = 11 inches)\n * @returns Height in pixels\n */\nexport function getPageHeightPixels(\n props: SectionProperties,\n defaultHeight: number = 15840\n): number {\n const twips = props.pageHeight ?? defaultHeight;\n return Math.round((twips / 1440) * 96);\n}\n\n/**\n * Get content width (page width minus margins) in pixels\n *\n * @param props - Section properties\n * @returns Content width in pixels\n */\nexport function getContentWidthPixels(props: SectionProperties): number {\n const pageWidth = props.pageWidth ?? 12240;\n const marginLeft = props.marginLeft ?? 1440; // 1 inch default\n const marginRight = props.marginRight ?? 1440;\n const twips = pageWidth - marginLeft - marginRight;\n return Math.round((twips / 1440) * 96);\n}\n\n/**\n * Get content height (page height minus margins) in pixels\n *\n * @param props - Section properties\n * @returns Content height in pixels\n */\nexport function getContentHeightPixels(props: SectionProperties): number {\n const pageHeight = props.pageHeight ?? 15840;\n const marginTop = props.marginTop ?? 1440;\n const marginBottom = props.marginBottom ?? 1440;\n const twips = pageHeight - marginTop - marginBottom;\n return Math.round((twips / 1440) * 96);\n}\n\n/**\n * Get margins in pixels\n *\n * @param props - Section properties\n * @returns Object with all margins in pixels\n */\nexport function getMarginsPixels(props: SectionProperties): {\n top: number;\n bottom: number;\n left: number;\n right: number;\n header: number;\n footer: number;\n gutter: number;\n} {\n const twipsToPixels = (twips: number | undefined, defaultTwips: number) => {\n return Math.round(((twips ?? defaultTwips) / 1440) * 96);\n };\n\n return {\n top: twipsToPixels(props.marginTop, 1440),\n bottom: twipsToPixels(props.marginBottom, 1440),\n left: twipsToPixels(props.marginLeft, 1440),\n right: twipsToPixels(props.marginRight, 1440),\n header: twipsToPixels(props.headerDistance, 720), // 0.5 inch default\n footer: twipsToPixels(props.footerDistance, 720),\n gutter: twipsToPixels(props.gutter, 0),\n };\n}\n\n/**\n * Check if section has different first page header/footer\n */\nexport function hasDifferentFirstPage(props: SectionProperties): boolean {\n return props.titlePg === true;\n}\n\n/**\n * Check if section has different odd/even page headers/footers\n */\nexport function hasDifferentOddEven(props: SectionProperties): boolean {\n return props.evenAndOddHeaders === true;\n}\n\n/**\n * Get effective column count (minimum 1)\n */\nexport function getColumnCount(props: SectionProperties): number {\n return Math.max(1, props.columnCount ?? 1);\n}\n\n/**\n * Check if section is landscape\n */\nexport function isLandscape(props: SectionProperties): boolean {\n return props.orientation === 'landscape';\n}\n\n/**\n * Check if section has page borders\n */\nexport function hasPageBorders(props: SectionProperties): boolean {\n if (!props.pageBorders) return false;\n return !!(\n props.pageBorders.top ||\n props.pageBorders.bottom ||\n props.pageBorders.left ||\n props.pageBorders.right\n );\n}\n\n/**\n * Check if section has line numbers\n */\nexport function hasLineNumbers(props: SectionProperties): boolean {\n return !!props.lineNumbers;\n}\n\n/**\n * Get default section properties (US Letter size, 1 inch margins)\n */\nexport function getDefaultSectionProperties(): SectionProperties {\n return {\n pageWidth: 12240, // 8.5 inches\n pageHeight: 15840, // 11 inches\n orientation: 'portrait',\n marginTop: 1440, // 1 inch\n marginBottom: 1440,\n marginLeft: 1440,\n marginRight: 1440,\n headerDistance: 720, // 0.5 inch\n footerDistance: 720,\n gutter: 0,\n columnCount: 1,\n columnSpace: 720, // 0.5 inch\n equalWidth: true,\n sectionStart: 'nextPage',\n verticalAlign: 'top',\n };\n}\n\n/**\n * Merge section properties (later values override earlier)\n *\n * @param base - Base properties\n * @param override - Override properties\n * @returns Merged properties\n */\nexport function mergeSectionProperties(\n base: SectionProperties,\n override: SectionProperties\n): SectionProperties {\n const result: SectionProperties = { ...base };\n\n // Simple properties - override if present\n if (override.pageWidth !== undefined) result.pageWidth = override.pageWidth;\n if (override.pageHeight !== undefined) result.pageHeight = override.pageHeight;\n if (override.orientation !== undefined) result.orientation = override.orientation;\n if (override.marginTop !== undefined) result.marginTop = override.marginTop;\n if (override.marginBottom !== undefined) result.marginBottom = override.marginBottom;\n if (override.marginLeft !== undefined) result.marginLeft = override.marginLeft;\n if (override.marginRight !== undefined) result.marginRight = override.marginRight;\n if (override.headerDistance !== undefined) result.headerDistance = override.headerDistance;\n if (override.footerDistance !== undefined) result.footerDistance = override.footerDistance;\n if (override.gutter !== undefined) result.gutter = override.gutter;\n if (override.columnCount !== undefined) result.columnCount = override.columnCount;\n if (override.columnSpace !== undefined) result.columnSpace = override.columnSpace;\n if (override.equalWidth !== undefined) result.equalWidth = override.equalWidth;\n if (override.separator !== undefined) result.separator = override.separator;\n if (override.columns !== undefined) result.columns = override.columns;\n if (override.sectionStart !== undefined) result.sectionStart = override.sectionStart;\n if (override.verticalAlign !== undefined) result.verticalAlign = override.verticalAlign;\n if (override.bidi !== undefined) result.bidi = override.bidi;\n if (override.headerReferences !== undefined) result.headerReferences = override.headerReferences;\n if (override.footerReferences !== undefined) result.footerReferences = override.footerReferences;\n if (override.titlePg !== undefined) result.titlePg = override.titlePg;\n if (override.evenAndOddHeaders !== undefined)\n result.evenAndOddHeaders = override.evenAndOddHeaders;\n if (override.lineNumbers !== undefined) result.lineNumbers = override.lineNumbers;\n if (override.pageBorders !== undefined) result.pageBorders = override.pageBorders;\n if (override.background !== undefined) result.background = override.background;\n if (override.footnotePr !== undefined) result.footnotePr = override.footnotePr;\n if (override.endnotePr !== undefined) result.endnotePr = override.endnotePr;\n if (override.docGrid !== undefined) result.docGrid = override.docGrid;\n if (override.paperSrcFirst !== undefined) result.paperSrcFirst = override.paperSrcFirst;\n if (override.paperSrcOther !== undefined) result.paperSrcOther = override.paperSrcOther;\n\n return result;\n}\n","/**\n * Run Consolidator - Merge consecutive runs with identical formatting\n *\n * DOCX files often contain many small runs with the same formatting,\n * created by Word for various reasons (spell checking, revision tracking,\n * cursor positioning, etc.). This causes:\n * - 252+ tiny <span> elements instead of a few\n * - Poor editing UX (cursor jumps between spans)\n * - Performance issues\n *\n * This module provides utilities to consolidate runs with identical\n * formatting into single runs, reducing fragmentation.\n */\n\nimport type {\n Run,\n RunContent,\n TextContent,\n TextFormatting,\n ParagraphContent,\n Paragraph,\n Hyperlink,\n} from '../types/document';\n\n/**\n * Check if two TextFormatting objects are equivalent\n *\n * Uses deep comparison of all properties to determine if runs\n * can be merged without losing formatting information.\n */\nexport function formattingEquals(\n a: TextFormatting | undefined,\n b: TextFormatting | undefined\n): boolean {\n // Both undefined - equal\n if (!a && !b) return true;\n\n // One undefined - not equal\n if (!a || !b) return false;\n\n // Compare boolean properties\n if (a.bold !== b.bold) return false;\n if (a.boldCs !== b.boldCs) return false;\n if (a.italic !== b.italic) return false;\n if (a.italicCs !== b.italicCs) return false;\n if (a.strike !== b.strike) return false;\n if (a.doubleStrike !== b.doubleStrike) return false;\n if (a.smallCaps !== b.smallCaps) return false;\n if (a.allCaps !== b.allCaps) return false;\n if (a.hidden !== b.hidden) return false;\n if (a.emboss !== b.emboss) return false;\n if (a.imprint !== b.imprint) return false;\n if (a.outline !== b.outline) return false;\n if (a.shadow !== b.shadow) return false;\n if (a.rtl !== b.rtl) return false;\n if (a.cs !== b.cs) return false;\n\n // Compare numeric properties\n if (a.fontSize !== b.fontSize) return false;\n if (a.fontSizeCs !== b.fontSizeCs) return false;\n if (a.spacing !== b.spacing) return false;\n if (a.position !== b.position) return false;\n if (a.scale !== b.scale) return false;\n if (a.kerning !== b.kerning) return false;\n\n // Compare string properties\n if (a.vertAlign !== b.vertAlign) return false;\n if (a.highlight !== b.highlight) return false;\n if (a.effect !== b.effect) return false;\n if (a.emphasisMark !== b.emphasisMark) return false;\n if (a.styleId !== b.styleId) return false;\n\n // Compare underline (object with style and optional color)\n if (!underlineEquals(a.underline, b.underline)) return false;\n\n // Compare color (object with rgb, themeColor, etc.)\n if (!colorEquals(a.color, b.color)) return false;\n\n // Compare shading (object with color, fill, pattern)\n if (!shadingEquals(a.shading, b.shading)) return false;\n\n // Compare fontFamily (complex object with multiple properties)\n if (!fontFamilyEquals(a.fontFamily, b.fontFamily)) return false;\n\n return true;\n}\n\n/**\n * Compare underline settings\n */\nfunction underlineEquals(a: TextFormatting['underline'], b: TextFormatting['underline']): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n\n if (a.style !== b.style) return false;\n return colorEquals(a.color, b.color);\n}\n\n/**\n * Compare color values\n */\nfunction colorEquals(a: TextFormatting['color'], b: TextFormatting['color']): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n\n return (\n a.rgb === b.rgb &&\n a.auto === b.auto &&\n a.themeColor === b.themeColor &&\n a.themeTint === b.themeTint &&\n a.themeShade === b.themeShade\n );\n}\n\n/**\n * Compare shading properties\n */\nfunction shadingEquals(a: TextFormatting['shading'], b: TextFormatting['shading']): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n\n if (a.pattern !== b.pattern) return false;\n if (!colorEquals(a.color, b.color)) return false;\n if (!colorEquals(a.fill, b.fill)) return false;\n\n return true;\n}\n\n/**\n * Compare font family settings\n */\nfunction fontFamilyEquals(\n a: TextFormatting['fontFamily'],\n b: TextFormatting['fontFamily']\n): boolean {\n if (!a && !b) return true;\n if (!a || !b) return false;\n\n return (\n a.ascii === b.ascii &&\n a.hAnsi === b.hAnsi &&\n a.eastAsia === b.eastAsia &&\n a.cs === b.cs &&\n a.asciiTheme === b.asciiTheme &&\n a.hAnsiTheme === b.hAnsiTheme &&\n a.eastAsiaTheme === b.eastAsiaTheme &&\n a.csTheme === b.csTheme\n );\n}\n\n/**\n * Check if a run contains only text content\n * (runs with special content like images, fields, etc. should not be merged)\n */\nexport function isTextOnlyRun(run: Run): boolean {\n return run.content.every(\n (c) => c.type === 'text' || c.type === 'softHyphen' || c.type === 'noBreakHyphen'\n );\n}\n\n/**\n * Check if run content can be merged (simple text types)\n */\nfunction isMergeableContent(content: RunContent): boolean {\n return (\n content.type === 'text' || content.type === 'softHyphen' || content.type === 'noBreakHyphen'\n );\n}\n\n/**\n * Check if a run can be merged with another run\n * Runs with breaks, tabs, images, fields, etc. act as merge boundaries\n */\nexport function canMergeRun(run: Run): boolean {\n // Empty runs can be merged\n if (run.content.length === 0) return true;\n\n // Runs with only text/hyphen content can be merged\n return run.content.every(isMergeableContent);\n}\n\n/**\n * Merge the content of two runs into a single content array\n */\nfunction mergeRunContent(content1: RunContent[], content2: RunContent[]): RunContent[] {\n // Combine all content\n const result: RunContent[] = [];\n\n // Add all from first run\n for (const c of content1) {\n result.push(c);\n }\n\n // Merge text at boundary if possible\n if (\n result.length > 0 &&\n content2.length > 0 &&\n result[result.length - 1].type === 'text' &&\n content2[0].type === 'text'\n ) {\n // Merge the two text nodes\n const lastText = result[result.length - 1] as TextContent;\n const firstText = content2[0] as TextContent;\n\n result[result.length - 1] = {\n type: 'text',\n text: lastText.text + firstText.text,\n preserveSpace: lastText.preserveSpace || firstText.preserveSpace || undefined,\n };\n\n // Add rest of content2\n for (let i = 1; i < content2.length; i++) {\n result.push(content2[i]);\n }\n } else {\n // Just append all of content2\n for (const c of content2) {\n result.push(c);\n }\n }\n\n return result;\n}\n\n/**\n * Consolidate an array of runs by merging consecutive runs with identical formatting\n *\n * @param runs - Array of runs to consolidate\n * @returns Consolidated array with fewer, larger runs\n */\nexport function consolidateRuns(runs: Run[]): Run[] {\n if (runs.length <= 1) return runs;\n\n const result: Run[] = [];\n let current: Run | null = null;\n\n for (const run of runs) {\n // Skip empty runs\n if (run.content.length === 0) continue;\n\n // If no current run, start with this one\n if (current === null) {\n current = { ...run, content: [...run.content] };\n continue;\n }\n\n // Check if we can merge this run with current\n if (\n canMergeRun(current) &&\n canMergeRun(run) &&\n formattingEquals(current.formatting, run.formatting)\n ) {\n // Merge the runs\n current = {\n type: 'run',\n formatting: current.formatting,\n content: mergeRunContent(current.content, run.content),\n };\n } else {\n // Can't merge - save current and start new\n result.push(current);\n current = { ...run, content: [...run.content] };\n }\n }\n\n // Don't forget the last run\n if (current !== null) {\n result.push(current);\n }\n\n return result;\n}\n\n/**\n * Consolidate runs within a paragraph content array\n *\n * This handles the full paragraph structure, consolidating runs while\n * preserving hyperlinks, bookmarks, and fields as merge boundaries.\n */\nexport function consolidateParagraphContent(content: ParagraphContent[]): ParagraphContent[] {\n if (content.length <= 1) return content;\n\n const result: ParagraphContent[] = [];\n const pendingRuns: Run[] = [];\n\n function flushRuns(): void {\n if (pendingRuns.length > 0) {\n const consolidated = consolidateRuns(pendingRuns);\n result.push(...consolidated);\n pendingRuns.length = 0;\n }\n }\n\n for (const item of content) {\n if (item.type === 'run') {\n pendingRuns.push(item);\n } else {\n // Non-run content acts as a merge boundary\n flushRuns();\n\n // Handle hyperlinks - consolidate their internal runs\n if (item.type === 'hyperlink') {\n const hyperlink: Hyperlink = {\n ...item,\n children: consolidateParagraphContent(item.children) as Hyperlink['children'],\n };\n result.push(hyperlink);\n } else {\n result.push(item);\n }\n }\n }\n\n // Flush any remaining runs\n flushRuns();\n\n return result;\n}\n\n/**\n * Consolidate all runs within a paragraph\n *\n * @param paragraph - Paragraph to consolidate\n * @returns New paragraph with consolidated runs\n */\nexport function consolidateParagraph(paragraph: Paragraph): Paragraph {\n if (!paragraph.content || paragraph.content.length === 0) {\n return paragraph;\n }\n\n return {\n ...paragraph,\n content: consolidateParagraphContent(paragraph.content),\n };\n}\n\n/**\n * Get the number of runs in a paragraph (for debugging/metrics)\n */\nexport function countRuns(paragraph: Paragraph): number {\n let count = 0;\n\n function countInContent(content: ParagraphContent[]): void {\n for (const item of content) {\n if (item.type === 'run') {\n count++;\n } else if (item.type === 'hyperlink') {\n countInContent(item.children);\n }\n }\n }\n\n if (paragraph.content) {\n countInContent(paragraph.content);\n }\n\n return count;\n}\n\n/**\n * Calculate the consolidation ratio (reduction in number of runs)\n * Useful for debugging and metrics\n */\nexport function getConsolidationStats(\n originalParagraphs: Paragraph[],\n consolidatedParagraphs: Paragraph[]\n): {\n originalRunCount: number;\n consolidatedRunCount: number;\n reductionPercentage: number;\n} {\n const originalCount = originalParagraphs.reduce((sum, p) => sum + countRuns(p), 0);\n const consolidatedCount = consolidatedParagraphs.reduce((sum, p) => sum + countRuns(p), 0);\n\n const reduction =\n originalCount > 0 ? ((originalCount - consolidatedCount) / originalCount) * 100 : 0;\n\n return {\n originalRunCount: originalCount,\n consolidatedRunCount: consolidatedCount,\n reductionPercentage: Math.round(reduction * 10) / 10,\n };\n}\n","/**\n * Paragraph Parser - Parse paragraphs (w:p) with complete formatting\n *\n * A paragraph is the fundamental block-level element containing text runs,\n * hyperlinks, bookmarks, and fields.\n *\n * OOXML Reference:\n * - Paragraph: w:p\n * - Paragraph properties: w:pPr\n * - Content: runs, hyperlinks, bookmarks, fields\n */\n\nimport type {\n Paragraph,\n ParagraphContent,\n ParagraphFormatting,\n Run,\n Hyperlink,\n BookmarkStart,\n BookmarkEnd,\n SimpleField,\n ComplexField,\n FieldType,\n Theme,\n ColorValue,\n BorderSpec,\n ShadingProperties,\n TabStop,\n TabStopAlignment,\n TabLeader,\n LineSpacingRule,\n ParagraphAlignment,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport type { NumberingMap } from './numberingParser';\nimport {\n findChild,\n findChildren,\n getAttribute,\n getChildElements,\n parseBooleanElement,\n parseNumericAttribute,\n type XmlElement,\n} from './xmlParser';\nimport { parseRun, parseRunProperties } from './runParser';\nimport { parseHyperlink as parseHyperlinkFromModule } from './hyperlinkParser';\nimport {\n parseBookmarkStart as parseBookmarkStartFromModule,\n parseBookmarkEnd as parseBookmarkEndFromModule,\n} from './bookmarkParser';\nimport { parseSectionProperties } from './sectionParser';\nimport { consolidateParagraphContent } from './runConsolidator';\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Parse color value from attributes\n */\nfunction parseColorValue(\n rgb: string | null,\n themeColor: string | null,\n themeTint: string | null,\n themeShade: string | null\n): ColorValue {\n const color: ColorValue = {};\n\n if (rgb && rgb !== 'auto') {\n color.rgb = rgb;\n } else if (rgb === 'auto') {\n color.auto = true;\n }\n\n if (themeColor) {\n color.themeColor = themeColor as ColorValue['themeColor'];\n }\n\n if (themeTint) {\n color.themeTint = themeTint;\n }\n\n if (themeShade) {\n color.themeShade = themeShade;\n }\n\n return color;\n}\n\n/**\n * Parse shading properties (w:shd)\n */\nfunction parseShadingProperties(shd: XmlElement | null): ShadingProperties | undefined {\n if (!shd) return undefined;\n\n const props: ShadingProperties = {};\n\n const color = getAttribute(shd, 'w', 'color');\n if (color && color !== 'auto') {\n props.color = { rgb: color };\n }\n\n const fill = getAttribute(shd, 'w', 'fill');\n if (fill && fill !== 'auto') {\n props.fill = { rgb: fill };\n }\n\n const themeFill = getAttribute(shd, 'w', 'themeFill');\n if (themeFill) {\n props.fill = props.fill || {};\n props.fill.themeColor = themeFill as ColorValue['themeColor'];\n }\n\n const themeFillTint = getAttribute(shd, 'w', 'themeFillTint');\n if (themeFillTint && props.fill) {\n props.fill.themeTint = themeFillTint;\n }\n\n const themeFillShade = getAttribute(shd, 'w', 'themeFillShade');\n if (themeFillShade && props.fill) {\n props.fill.themeShade = themeFillShade;\n }\n\n const pattern = getAttribute(shd, 'w', 'val');\n if (pattern) {\n props.pattern = pattern as ShadingProperties['pattern'];\n }\n\n return Object.keys(props).length > 0 ? props : undefined;\n}\n\n/**\n * Parse border specification (w:top, w:bottom, w:left, w:right, etc.)\n */\nfunction parseBorderSpec(border: XmlElement | null): BorderSpec | undefined {\n if (!border) return undefined;\n\n const style = getAttribute(border, 'w', 'val');\n if (!style) return undefined;\n\n const spec: BorderSpec = {\n style: style as BorderSpec['style'],\n };\n\n const colorVal = getAttribute(border, 'w', 'color');\n const themeColor = getAttribute(border, 'w', 'themeColor');\n if (colorVal || themeColor) {\n spec.color = parseColorValue(\n colorVal,\n themeColor,\n getAttribute(border, 'w', 'themeTint'),\n getAttribute(border, 'w', 'themeShade')\n );\n }\n\n const sz = parseNumericAttribute(border, 'w', 'sz');\n if (sz !== undefined) spec.size = sz;\n\n const space = parseNumericAttribute(border, 'w', 'space');\n if (space !== undefined) spec.space = space;\n\n const shadowAttr = getAttribute(border, 'w', 'shadow');\n if (shadowAttr) spec.shadow = shadowAttr === '1' || shadowAttr === 'true';\n\n const frame = getAttribute(border, 'w', 'frame');\n if (frame) spec.frame = frame === '1' || frame === 'true';\n\n return spec;\n}\n\n/**\n * Parse tab stops (w:tabs)\n */\nfunction parseTabStops(tabs: XmlElement | null): TabStop[] | undefined {\n if (!tabs) return undefined;\n\n const tabElements = findChildren(tabs, 'w', 'tab');\n if (tabElements.length === 0) return undefined;\n\n const result: TabStop[] = [];\n\n for (const tab of tabElements) {\n const pos = parseNumericAttribute(tab, 'w', 'pos');\n const val = getAttribute(tab, 'w', 'val');\n\n if (pos !== undefined && val) {\n const tabStop: TabStop = {\n position: pos,\n alignment: val as TabStopAlignment,\n };\n\n const leader = getAttribute(tab, 'w', 'leader');\n if (leader) {\n tabStop.leader = leader as TabLeader;\n }\n\n result.push(tabStop);\n }\n }\n\n return result.length > 0 ? result : undefined;\n}\n\n/**\n * Parse frame properties (w:framePr)\n */\nfunction parseFrameProperties(\n framePr: XmlElement | null\n): ParagraphFormatting['frame'] | undefined {\n if (!framePr) return undefined;\n\n const frame: ParagraphFormatting['frame'] = {};\n\n const w = parseNumericAttribute(framePr, 'w', 'w');\n if (w !== undefined) frame.width = w;\n\n const h = parseNumericAttribute(framePr, 'w', 'h');\n if (h !== undefined) frame.height = h;\n\n const hAnchor = getAttribute(framePr, 'w', 'hAnchor');\n if (hAnchor === 'text' || hAnchor === 'margin' || hAnchor === 'page') {\n frame.hAnchor = hAnchor;\n }\n\n const vAnchor = getAttribute(framePr, 'w', 'vAnchor');\n if (vAnchor === 'text' || vAnchor === 'margin' || vAnchor === 'page') {\n frame.vAnchor = vAnchor;\n }\n\n const x = parseNumericAttribute(framePr, 'w', 'x');\n if (x !== undefined) frame.x = x;\n\n const y = parseNumericAttribute(framePr, 'w', 'y');\n if (y !== undefined) frame.y = y;\n\n const xAlign = getAttribute(framePr, 'w', 'xAlign');\n if (xAlign) {\n frame.xAlign = xAlign as NonNullable<ParagraphFormatting['frame']>['xAlign'];\n }\n\n const yAlign = getAttribute(framePr, 'w', 'yAlign');\n if (yAlign) {\n frame.yAlign = yAlign as NonNullable<ParagraphFormatting['frame']>['yAlign'];\n }\n\n const wrap = getAttribute(framePr, 'w', 'wrap');\n if (wrap) {\n frame.wrap = wrap as NonNullable<ParagraphFormatting['frame']>['wrap'];\n }\n\n return Object.keys(frame).length > 0 ? frame : undefined;\n}\n\n// ============================================================================\n// PARAGRAPH PROPERTIES PARSER\n// ============================================================================\n\n/**\n * Parse paragraph formatting properties (w:pPr)\n *\n * Handles ALL pPr properties:\n * - w:jc (alignment: left, center, right, both/justify)\n * - w:spacing (before, after, line, lineRule)\n * - w:ind (left, right, firstLine, hanging)\n * - w:pBdr (paragraph borders: top, bottom, left, right, between)\n * - w:shd (paragraph shading/background)\n * - w:tabs (tab stops with positions and types)\n * - w:keepNext, w:keepLines, w:widowControl, w:pageBreakBefore\n * - w:bidi (right-to-left)\n * - w:numPr (list info)\n * - w:pStyle (style reference)\n * - w:outlineLvl (outline level)\n * - w:framePr (frame properties)\n * - w:rPr (default run properties)\n */\nexport function parseParagraphProperties(\n pPr: XmlElement | null,\n theme: Theme | null,\n styles?: StyleMap\n): ParagraphFormatting | undefined {\n if (!pPr) return undefined;\n\n const formatting: ParagraphFormatting = {};\n\n // === Alignment ===\n const jc = findChild(pPr, 'w', 'jc');\n if (jc) {\n const val = getAttribute(jc, 'w', 'val');\n if (val) {\n formatting.alignment = val as ParagraphAlignment;\n }\n }\n\n // === Bidi (right-to-left) ===\n const bidi = findChild(pPr, 'w', 'bidi');\n if (bidi) {\n formatting.bidi = parseBooleanElement(bidi);\n }\n\n // === Spacing ===\n const spacing = findChild(pPr, 'w', 'spacing');\n if (spacing) {\n const before = parseNumericAttribute(spacing, 'w', 'before');\n if (before !== undefined) formatting.spaceBefore = before;\n\n const after = parseNumericAttribute(spacing, 'w', 'after');\n if (after !== undefined) formatting.spaceAfter = after;\n\n const line = parseNumericAttribute(spacing, 'w', 'line');\n if (line !== undefined) formatting.lineSpacing = line;\n\n const lineRule = getAttribute(spacing, 'w', 'lineRule');\n if (lineRule) {\n formatting.lineSpacingRule = lineRule as LineSpacingRule;\n }\n\n const beforeAuto = getAttribute(spacing, 'w', 'beforeAutospacing');\n if (beforeAuto) {\n formatting.beforeAutospacing = beforeAuto === '1' || beforeAuto === 'true';\n }\n\n const afterAuto = getAttribute(spacing, 'w', 'afterAutospacing');\n if (afterAuto) {\n formatting.afterAutospacing = afterAuto === '1' || afterAuto === 'true';\n }\n }\n\n // === Indentation ===\n const ind = findChild(pPr, 'w', 'ind');\n if (ind) {\n const left = parseNumericAttribute(ind, 'w', 'left');\n if (left !== undefined) formatting.indentLeft = left;\n\n const right = parseNumericAttribute(ind, 'w', 'right');\n if (right !== undefined) formatting.indentRight = right;\n\n const firstLine = parseNumericAttribute(ind, 'w', 'firstLine');\n if (firstLine !== undefined) formatting.indentFirstLine = firstLine;\n\n const hanging = parseNumericAttribute(ind, 'w', 'hanging');\n if (hanging !== undefined) {\n // Hanging indent is stored as negative first line indent\n formatting.indentFirstLine = -hanging;\n formatting.hangingIndent = true;\n }\n\n // Also check for w:start and w:end (alternative attributes)\n const start = parseNumericAttribute(ind, 'w', 'start');\n if (start !== undefined && formatting.indentLeft === undefined) {\n formatting.indentLeft = start;\n }\n\n const end = parseNumericAttribute(ind, 'w', 'end');\n if (end !== undefined && formatting.indentRight === undefined) {\n formatting.indentRight = end;\n }\n }\n\n // === Borders ===\n const pBdr = findChild(pPr, 'w', 'pBdr');\n if (pBdr) {\n const borders: ParagraphFormatting['borders'] = {};\n\n const top = parseBorderSpec(findChild(pBdr, 'w', 'top'));\n if (top) borders.top = top;\n\n const bottom = parseBorderSpec(findChild(pBdr, 'w', 'bottom'));\n if (bottom) borders.bottom = bottom;\n\n const left = parseBorderSpec(findChild(pBdr, 'w', 'left'));\n if (left) borders.left = left;\n\n const right = parseBorderSpec(findChild(pBdr, 'w', 'right'));\n if (right) borders.right = right;\n\n const between = parseBorderSpec(findChild(pBdr, 'w', 'between'));\n if (between) borders.between = between;\n\n const bar = parseBorderSpec(findChild(pBdr, 'w', 'bar'));\n if (bar) borders.bar = bar;\n\n if (Object.keys(borders).length > 0) {\n formatting.borders = borders;\n }\n }\n\n // === Shading ===\n const shd = findChild(pPr, 'w', 'shd');\n if (shd) {\n formatting.shading = parseShadingProperties(shd);\n }\n\n // === Tab Stops ===\n const tabs = findChild(pPr, 'w', 'tabs');\n if (tabs) {\n formatting.tabs = parseTabStops(tabs);\n }\n\n // === Page Break Control ===\n const keepNext = findChild(pPr, 'w', 'keepNext');\n if (keepNext) {\n formatting.keepNext = parseBooleanElement(keepNext);\n }\n\n const keepLines = findChild(pPr, 'w', 'keepLines');\n if (keepLines) {\n formatting.keepLines = parseBooleanElement(keepLines);\n }\n\n const widowControl = findChild(pPr, 'w', 'widowControl');\n if (widowControl) {\n formatting.widowControl = parseBooleanElement(widowControl);\n }\n\n const pageBreakBefore = findChild(pPr, 'w', 'pageBreakBefore');\n if (pageBreakBefore) {\n formatting.pageBreakBefore = parseBooleanElement(pageBreakBefore);\n }\n\n // === Numbering Properties (List Info) ===\n const numPr = findChild(pPr, 'w', 'numPr');\n if (numPr) {\n const numIdEl = findChild(numPr, 'w', 'numId');\n const ilvlEl = findChild(numPr, 'w', 'ilvl');\n\n if (numIdEl || ilvlEl) {\n formatting.numPr = {};\n\n if (numIdEl) {\n const val = parseNumericAttribute(numIdEl, 'w', 'val');\n if (val !== undefined) formatting.numPr.numId = val;\n }\n\n if (ilvlEl) {\n const val = parseNumericAttribute(ilvlEl, 'w', 'val');\n if (val !== undefined) formatting.numPr.ilvl = val;\n }\n }\n }\n\n // === Outline Level ===\n const outlineLvl = findChild(pPr, 'w', 'outlineLvl');\n if (outlineLvl) {\n const val = parseNumericAttribute(outlineLvl, 'w', 'val');\n if (val !== undefined) formatting.outlineLevel = val;\n }\n\n // === Style Reference ===\n const pStyle = findChild(pPr, 'w', 'pStyle');\n if (pStyle) {\n const val = getAttribute(pStyle, 'w', 'val');\n if (val) formatting.styleId = val;\n }\n\n // === Frame Properties ===\n const framePr = findChild(pPr, 'w', 'framePr');\n if (framePr) {\n formatting.frame = parseFrameProperties(framePr);\n }\n\n // === Suppress Line Numbers ===\n const suppressLineNumbers = findChild(pPr, 'w', 'suppressLineNumbers');\n if (suppressLineNumbers) {\n formatting.suppressLineNumbers = parseBooleanElement(suppressLineNumbers);\n }\n\n // === Suppress Auto Hyphens ===\n const suppressAutoHyphens = findChild(pPr, 'w', 'suppressAutoHyphens');\n if (suppressAutoHyphens) {\n formatting.suppressAutoHyphens = parseBooleanElement(suppressAutoHyphens);\n }\n\n // === Default Run Properties ===\n const rPr = findChild(pPr, 'w', 'rPr');\n if (rPr) {\n formatting.runProperties = parseRunProperties(rPr, theme, styles);\n }\n\n return Object.keys(formatting).length > 0 ? formatting : undefined;\n}\n\n// ============================================================================\n// PARAGRAPH CONTENT PARSERS\n// ============================================================================\n\n/**\n * Get the local name of an element (without namespace prefix)\n */\nfunction getLocalName(name: string | undefined): string {\n if (!name) return '';\n const colonIndex = name.indexOf(':');\n return colonIndex >= 0 ? name.substring(colonIndex + 1) : name;\n}\n\n/**\n * Parse hyperlink element (w:hyperlink)\n *\n * Delegates to hyperlinkParser module which resolves URLs via relationships.\n */\nfunction parseHyperlink(\n node: XmlElement,\n rels: RelationshipMap | null,\n styles: StyleMap | null,\n theme: Theme | null,\n media: Map<string, MediaFile> | null\n): Hyperlink {\n return parseHyperlinkFromModule(node, rels, styles, theme, media);\n}\n\n/**\n * Parse bookmark start (w:bookmarkStart)\n * Delegates to bookmarkParser module.\n */\nfunction parseBookmarkStart(node: XmlElement): BookmarkStart {\n return parseBookmarkStartFromModule(node);\n}\n\n/**\n * Parse bookmark end (w:bookmarkEnd)\n * Delegates to bookmarkParser module.\n */\nfunction parseBookmarkEnd(node: XmlElement): BookmarkEnd {\n return parseBookmarkEndFromModule(node);\n}\n\n/**\n * Parse field type from instruction string\n */\nfunction parseFieldType(instruction: string): FieldType {\n // Extract the field name (first word)\n const match = instruction.trim().match(/^\\\\?([A-Z]+)/i);\n if (!match) return 'UNKNOWN';\n\n const fieldName = match[1].toUpperCase();\n\n const knownFields: FieldType[] = [\n 'PAGE',\n 'NUMPAGES',\n 'NUMWORDS',\n 'NUMCHARS',\n 'DATE',\n 'TIME',\n 'CREATEDATE',\n 'SAVEDATE',\n 'PRINTDATE',\n 'AUTHOR',\n 'TITLE',\n 'SUBJECT',\n 'KEYWORDS',\n 'COMMENTS',\n 'FILENAME',\n 'FILESIZE',\n 'TEMPLATE',\n 'DOCPROPERTY',\n 'DOCVARIABLE',\n 'REF',\n 'PAGEREF',\n 'NOTEREF',\n 'HYPERLINK',\n 'TOC',\n 'TOA',\n 'INDEX',\n 'SEQ',\n 'STYLEREF',\n 'AUTONUM',\n 'AUTONUMLGL',\n 'AUTONUMOUT',\n 'IF',\n 'MERGEFIELD',\n 'NEXT',\n 'NEXTIF',\n 'ASK',\n 'SET',\n 'QUOTE',\n 'INCLUDETEXT',\n 'INCLUDEPICTURE',\n 'SYMBOL',\n 'ADVANCE',\n 'EDITTIME',\n 'REVNUM',\n 'SECTION',\n 'SECTIONPAGES',\n 'USERADDRESS',\n 'USERNAME',\n 'USERINITIALS',\n ];\n\n if (knownFields.includes(fieldName as FieldType)) {\n return fieldName as FieldType;\n }\n\n return 'UNKNOWN';\n}\n\n/**\n * Parse simple field (w:fldSimple)\n */\nfunction parseSimpleField(\n node: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): SimpleField {\n const instruction = getAttribute(node, 'w', 'instr') ?? '';\n const fieldType = parseFieldType(instruction);\n\n const field: SimpleField = {\n type: 'simpleField',\n instruction,\n fieldType,\n content: [],\n };\n\n // Check for fldLock\n const fldLock = getAttribute(node, 'w', 'fldLock');\n if (fldLock === '1' || fldLock === 'true') {\n field.fldLock = true;\n }\n\n // Check for dirty\n const dirty = getAttribute(node, 'w', 'dirty');\n if (dirty === '1' || dirty === 'true') {\n field.dirty = true;\n }\n\n // Parse child runs (the display value)\n const children = getChildElements(node);\n for (const child of children) {\n const localName = getLocalName(child.name);\n if (localName === 'r') {\n field.content.push(parseRun(child, styles, theme, rels, media));\n }\n }\n\n return field;\n}\n\n/**\n * Parse all content within a paragraph\n *\n * Returns the parsed content and any complex fields that span multiple runs\n */\nfunction parseParagraphContents(\n paraElement: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n _numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): ParagraphContent[] {\n const contents: ParagraphContent[] = [];\n const children = getChildElements(paraElement);\n\n // State for tracking complex fields\n let inComplexField = false;\n let complexFieldInstr = '';\n let complexFieldCodeRuns: Run[] = [];\n let complexFieldResultRuns: Run[] = [];\n let afterSeparator = false;\n let complexFieldLock = false;\n let complexFieldDirty = false;\n\n for (const child of children) {\n const localName = getLocalName(child.name);\n\n switch (localName) {\n case 'r': {\n // Check for field characters in this run\n const run = parseRun(child, styles, theme, rels, media);\n\n // Look for field characters\n let hasFieldBegin = false;\n let hasFieldSeparate = false;\n let hasFieldEnd = false;\n let instrText = '';\n\n for (const content of run.content) {\n if (content.type === 'fieldChar') {\n if (content.charType === 'begin') {\n hasFieldBegin = true;\n if (content.fldLock) complexFieldLock = true;\n if (content.dirty) complexFieldDirty = true;\n } else if (content.charType === 'separate') {\n hasFieldSeparate = true;\n } else if (content.charType === 'end') {\n hasFieldEnd = true;\n }\n } else if (content.type === 'instrText') {\n instrText += content.text;\n }\n }\n\n if (hasFieldBegin) {\n // Starting a new complex field\n inComplexField = true;\n afterSeparator = false;\n complexFieldInstr = '';\n complexFieldCodeRuns = [];\n complexFieldResultRuns = [];\n complexFieldLock = false;\n complexFieldDirty = false;\n }\n\n if (inComplexField) {\n if (instrText) {\n complexFieldInstr += instrText;\n }\n\n if (hasFieldSeparate) {\n afterSeparator = true;\n }\n\n if (afterSeparator && !hasFieldEnd) {\n // Add to result runs (excluding the separator run itself)\n if (!hasFieldSeparate) {\n complexFieldResultRuns.push(run);\n }\n } else if (!afterSeparator && !hasFieldBegin) {\n // Add to code runs\n complexFieldCodeRuns.push(run);\n }\n\n if (hasFieldEnd) {\n // Close the complex field\n const complexField: ComplexField = {\n type: 'complexField',\n instruction: complexFieldInstr.trim(),\n fieldType: parseFieldType(complexFieldInstr),\n fieldCode: complexFieldCodeRuns,\n fieldResult: complexFieldResultRuns,\n };\n\n if (complexFieldLock) complexField.fldLock = true;\n if (complexFieldDirty) complexField.dirty = true;\n\n contents.push(complexField);\n inComplexField = false;\n }\n } else {\n // Regular run, not part of a field\n contents.push(run);\n }\n break;\n }\n\n case 'hyperlink':\n contents.push(parseHyperlink(child, rels, styles, theme, media));\n break;\n\n case 'bookmarkStart':\n contents.push(parseBookmarkStart(child));\n break;\n\n case 'bookmarkEnd':\n contents.push(parseBookmarkEnd(child));\n break;\n\n case 'fldSimple':\n contents.push(parseSimpleField(child, styles, theme, rels, media));\n break;\n\n case 'pPr':\n // Already handled separately\n break;\n\n case 'proofErr':\n case 'permStart':\n case 'permEnd':\n case 'customXml':\n // Skip these elements\n break;\n\n case 'sdt': {\n // Structured document tag - extract content from sdtContent\n const sdtContent = (child.elements ?? []).find(\n (el: XmlElement) =>\n el.type === 'element' &&\n (el.name === 'w:sdtContent' || el.name?.endsWith(':sdtContent'))\n );\n if (sdtContent) {\n // Recursively parse the content inside SDT\n const sdtParsed = parseParagraphContents(sdtContent, styles, theme, null, rels, media);\n contents.push(...sdtParsed);\n }\n break;\n }\n\n case 'smartTag':\n case 'del':\n case 'ins':\n case 'moveTo':\n case 'moveFrom':\n // Track changes - skip for now (would need revision mode)\n break;\n\n case 'commentRangeStart':\n case 'commentRangeEnd':\n // Comments - skip for now\n break;\n\n case 'oMath':\n case 'oMathPara':\n // Math content - skip for now (would need math parser)\n break;\n\n default:\n // Unknown element - skip\n break;\n }\n }\n\n return contents;\n}\n\n// ============================================================================\n// MAIN PARAGRAPH PARSER\n// ============================================================================\n\n/**\n * Parse a paragraph element (w:p)\n *\n * @param node - The w:p XML element\n * @param styles - Style map for resolving style references\n * @param theme - Theme for resolving theme colors/fonts\n * @param numbering - Numbering definitions for list info\n * @param rels - Relationship map for resolving hyperlink URLs\n * @param media - Media files map for image data\n * @returns Parsed Paragraph object\n */\nexport function parseParagraph(\n node: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): Paragraph {\n const paragraph: Paragraph = {\n type: 'paragraph',\n content: [],\n };\n\n // Get paragraph ID attributes (Word 2010+ uses these for collaboration)\n const paraId = getAttribute(node, 'w14', 'paraId') ?? getAttribute(node, 'w', 'paraId');\n if (paraId) {\n paragraph.paraId = paraId;\n }\n\n const textId = getAttribute(node, 'w14', 'textId') ?? getAttribute(node, 'w', 'textId');\n if (textId) {\n paragraph.textId = textId;\n }\n\n // Parse paragraph properties (w:pPr)\n const pPr = findChild(node, 'w', 'pPr');\n if (pPr) {\n paragraph.formatting = parseParagraphProperties(pPr, theme, styles ?? undefined);\n\n // Check for section properties within paragraph (marks end of a section)\n const sectPr = findChild(pPr, 'w', 'sectPr');\n if (sectPr) {\n paragraph.sectionProperties = parseSectionProperties(sectPr, rels);\n }\n }\n\n // Parse paragraph contents (runs, hyperlinks, bookmarks, fields)\n const rawContent = parseParagraphContents(node, styles, theme, numbering, rels, media);\n\n // Consolidate consecutive runs with identical formatting\n // This reduces fragmentation (e.g., 252 tiny runs → a few larger runs)\n paragraph.content = consolidateParagraphContent(rawContent);\n\n // Compute list rendering if this is a list item\n if (paragraph.formatting?.numPr && numbering) {\n const { numId, ilvl = 0 } = paragraph.formatting.numPr;\n if (numId !== undefined && numId !== 0) {\n const level = numbering.getLevel(numId, ilvl);\n if (level) {\n paragraph.listRendering = {\n level: ilvl,\n numId,\n marker: level.lvlText,\n isBullet: level.numFmt === 'bullet',\n numFmt: level.numFmt,\n };\n\n // Apply level's paragraph properties (indentation)\n // For list items, the numbering definition's indentation should control\n // the layout, so we override paragraph-level indentation with level's\n if (level.pPr) {\n if (!paragraph.formatting) {\n paragraph.formatting = {};\n }\n // Apply level indent - this overrides any paragraph-level indent\n // since list indentation should come from the numbering definition\n if (level.pPr.indentLeft !== undefined) {\n paragraph.formatting.indentLeft = level.pPr.indentLeft;\n }\n if (level.pPr.indentFirstLine !== undefined) {\n paragraph.formatting.indentFirstLine = level.pPr.indentFirstLine;\n }\n if (level.pPr.hangingIndent !== undefined) {\n paragraph.formatting.hangingIndent = level.pPr.hangingIndent;\n }\n }\n }\n }\n }\n\n return paragraph;\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Get plain text from a paragraph\n *\n * @param paragraph - Parsed Paragraph object\n * @returns Concatenated text content\n */\nexport function getParagraphText(paragraph: Paragraph): string {\n let text = '';\n\n for (const content of paragraph.content) {\n if (content.type === 'run') {\n for (const runContent of content.content) {\n if (runContent.type === 'text') {\n text += runContent.text;\n } else if (runContent.type === 'tab') {\n text += '\\t';\n } else if (runContent.type === 'break') {\n if (runContent.breakType === 'page') {\n text += '\\f';\n } else {\n text += '\\n';\n }\n }\n }\n } else if (content.type === 'hyperlink') {\n for (const child of content.children) {\n if (child.type === 'run') {\n for (const runContent of child.content) {\n if (runContent.type === 'text') {\n text += runContent.text;\n }\n }\n }\n }\n } else if (content.type === 'simpleField') {\n for (const child of content.content) {\n if (child.type === 'run') {\n for (const runContent of child.content) {\n if (runContent.type === 'text') {\n text += runContent.text;\n }\n }\n }\n }\n } else if (content.type === 'complexField') {\n for (const run of content.fieldResult) {\n for (const runContent of run.content) {\n if (runContent.type === 'text') {\n text += runContent.text;\n }\n }\n }\n }\n }\n\n return text;\n}\n\n/**\n * Check if a paragraph is empty (no visible content)\n *\n * @param paragraph - Parsed Paragraph object\n * @returns true if paragraph has no visible content\n */\nexport function isEmptyParagraph(paragraph: Paragraph): boolean {\n return (\n getParagraphText(paragraph).trim() === '' &&\n !paragraph.content.some(\n (c) =>\n c.type === 'run' && c.content.some((rc) => rc.type === 'drawing' || rc.type === 'shape')\n )\n );\n}\n\n/**\n * Check if a paragraph is a list item\n *\n * @param paragraph - Parsed Paragraph object\n * @returns true if paragraph has numbering properties\n */\nexport function isListItem(paragraph: Paragraph): boolean {\n return (\n paragraph.formatting?.numPr !== undefined &&\n paragraph.formatting.numPr.numId !== undefined &&\n paragraph.formatting.numPr.numId !== 0\n );\n}\n\n/**\n * Get the list level of a paragraph (0-8)\n *\n * @param paragraph - Parsed Paragraph object\n * @returns List level or undefined if not a list item\n */\nexport function getListLevel(paragraph: Paragraph): number | undefined {\n if (!isListItem(paragraph)) return undefined;\n return paragraph.formatting?.numPr?.ilvl ?? 0;\n}\n\n/**\n * Check if paragraph has a specific style\n *\n * @param paragraph - Parsed Paragraph object\n * @param styleId - Style ID to check for\n * @returns true if paragraph has the specified style\n */\nexport function hasStyle(paragraph: Paragraph, styleId: string): boolean {\n return paragraph.formatting?.styleId === styleId;\n}\n\n/**\n * Check if paragraph starts with a template variable {{...}}\n *\n * @param paragraph - Parsed Paragraph object\n * @returns The variable name or null\n */\nexport function getTemplateVariable(paragraph: Paragraph): string | null {\n const text = getParagraphText(paragraph);\n const match = text.match(/\\{\\{([^}]+)\\}\\}/);\n return match ? match[1] : null;\n}\n","/**\n * Document Body Parser - Parse document.xml body content\n *\n * Parses the main document body (w:body) containing paragraphs, tables,\n * and section properties. Also detects template variables {{...}}.\n *\n * OOXML Reference:\n * - Root: w:document\n * - Body: w:body\n * - Content: w:p (paragraphs), w:tbl (tables), w:sdt (structured document tags)\n * - Final section properties: w:body/w:sectPr\n */\n\nimport type {\n DocumentBody,\n BlockContent,\n Section,\n Paragraph,\n Table,\n SectionProperties,\n Theme,\n RelationshipMap,\n MediaFile,\n} from '../types/document';\nimport type { StyleMap } from './styleParser';\nimport type { NumberingMap } from './numberingParser';\nimport { parseXml, findChild, getChildElements, type XmlElement } from './xmlParser';\nimport { parseParagraph, getParagraphText } from './paragraphParser';\nimport { parseTable } from './tableParser';\nimport { parseSectionProperties, getDefaultSectionProperties } from './sectionParser';\n\n// ============================================================================\n// LIST MARKER COMPUTATION\n// ============================================================================\n\n/**\n * Convert Symbol font bullet characters to Unicode equivalents\n *\n * DOCX often uses characters from Symbol, Wingdings, or Webdings fonts\n * that don't render correctly without the font. This maps them to\n * standard Unicode bullets that work with any font.\n */\nfunction convertBulletToUnicode(bulletChar: string): string {\n // If empty or whitespace, use standard bullet\n if (!bulletChar || bulletChar.trim() === '') {\n return '•';\n }\n\n // Get the character code\n const charCode = bulletChar.charCodeAt(0);\n\n // Map common Symbol/Wingdings characters to Unicode\n // Symbol font mappings (often used for bullets)\n const symbolMap: Record<number, string> = {\n // Symbol font\n 0x00b7: '•', // Middle dot → bullet\n 0x006f: '○', // lowercase o → white circle (used in Symbol font)\n 0x00a7: '■', // Section sign → black square (Symbol)\n 0x00fc: '✓', // Checkmark in Symbol/Wingdings\n\n // Wingdings mappings (character codes when Wingdings not available)\n 0x006e: '■', // Wingdings n → black square\n 0x0071: '○', // Wingdings q → white circle\n 0x0075: '◆', // Wingdings u → black diamond\n 0x0076: '❖', // Wingdings v → diamond\n 0x00a8: '✓', // Wingdings checkmark\n 0x00fb: '✓', // Checkmark\n 0x00fe: '✓', // Checkmark variant\n\n // Common control characters that might appear\n 0xf0b7: '•', // Private use area bullet\n 0xf06e: '■', // Private use area square\n 0xf06f: '○', // Private use area circle\n 0xf0a7: '■', // Private use area\n 0xf0fc: '✓', // Private use area checkmark\n\n // Other common bullet-like characters\n 0x2022: '•', // Already a bullet\n 0x25cf: '●', // Black circle\n 0x25cb: '○', // White circle\n 0x25a0: '■', // Black square\n 0x25a1: '□', // White square\n 0x25c6: '◆', // Black diamond\n 0x25c7: '◇', // White diamond\n 0x2013: '–', // En dash\n 0x2014: '—', // Em dash\n 0x003e: '>', // Greater than (used as arrow)\n 0x002d: '-', // Hyphen\n };\n\n // Check if we have a mapping for this character\n if (symbolMap[charCode]) {\n return symbolMap[charCode];\n }\n\n // If it's in the private use area (often Symbol/Wingdings), use bullet\n if (charCode >= 0xe000 && charCode <= 0xf8ff) {\n return '•';\n }\n\n // If it's a control character or non-printable, use bullet\n if (charCode < 32 || (charCode >= 127 && charCode < 160)) {\n return '•';\n }\n\n // Otherwise, use the character as-is (might be a valid Unicode bullet)\n return bulletChar;\n}\n\n/**\n * Compute the actual list marker for a paragraph\n *\n * Replaces %1, %2, etc. in lvlText with actual counter values.\n * Tracks and increments counters as list items are encountered.\n *\n * @param paragraph - The paragraph to compute marker for\n * @param numbering - Numbering definitions\n * @param listCounters - Map tracking counters per numId\n */\nfunction computeListMarker(\n paragraph: Paragraph,\n numbering: NumberingMap | null,\n listCounters: Map<number, number[]>\n): void {\n const listRendering = paragraph.listRendering;\n if (!listRendering || !numbering) return;\n\n const { numId, level } = listRendering;\n if (numId === undefined || numId === 0) return;\n\n // Initialize counters for this numId if not exists\n if (!listCounters.has(numId)) {\n listCounters.set(numId, new Array(9).fill(0)); // Up to 9 levels\n }\n\n const counters = listCounters.get(numId)!;\n\n // Increment counter at current level\n counters[level] = (counters[level] || 0) + 1;\n\n // Reset all deeper level counters when we go to a shallower level\n for (let i = level + 1; i < counters.length; i++) {\n counters[i] = 0;\n }\n\n // Get the lvlText pattern (e.g., \"%1.%2.%3.\")\n const pattern = listRendering.marker;\n\n // For bullet lists, convert Symbol font characters to proper Unicode\n if (listRendering.isBullet) {\n // DOCX often uses Symbol font characters that don't render correctly\n // Map common Symbol font codes to Unicode equivalents\n const bulletChar = pattern || '';\n listRendering.marker = convertBulletToUnicode(bulletChar);\n return;\n }\n\n // Compute the actual marker by replacing %1, %2, etc.\n let computedMarker = pattern;\n\n // Replace %1, %2, etc. with actual counter values\n // Format each level according to its numFmt\n for (let lvl = 0; lvl <= level; lvl++) {\n const placeholder = `%${lvl + 1}`;\n if (computedMarker.includes(placeholder)) {\n const value = counters[lvl];\n const levelInfo = numbering.getLevel(numId, lvl);\n const formatted = formatNumber(value, levelInfo?.numFmt || 'decimal');\n computedMarker = computedMarker.replace(placeholder, formatted);\n }\n }\n\n // Update the marker with the computed value\n listRendering.marker = computedMarker;\n}\n\n/**\n * Format a number according to OOXML number format\n */\nfunction formatNumber(value: number, numFmt: string): string {\n switch (numFmt) {\n case 'decimal':\n case 'decimalZero':\n return String(value);\n case 'lowerLetter':\n return String.fromCharCode(96 + ((value - 1) % 26) + 1); // a, b, c...\n case 'upperLetter':\n return String.fromCharCode(64 + ((value - 1) % 26) + 1); // A, B, C...\n case 'lowerRoman':\n return toRoman(value).toLowerCase();\n case 'upperRoman':\n return toRoman(value);\n case 'bullet':\n return '•';\n default:\n return String(value);\n }\n}\n\n/**\n * Convert number to Roman numerals\n */\nfunction toRoman(num: number): string {\n const romanNumerals: [number, string][] = [\n [1000, 'M'],\n [900, 'CM'],\n [500, 'D'],\n [400, 'CD'],\n [100, 'C'],\n [90, 'XC'],\n [50, 'L'],\n [40, 'XL'],\n [10, 'X'],\n [9, 'IX'],\n [5, 'V'],\n [4, 'IV'],\n [1, 'I'],\n ];\n\n let result = '';\n for (const [value, symbol] of romanNumerals) {\n while (num >= value) {\n result += symbol;\n num -= value;\n }\n }\n return result;\n}\n\n// ============================================================================\n// TEMPLATE VARIABLE DETECTION\n// ============================================================================\n\n/**\n * Regular expression to match template variables {{...}}\n */\nconst TEMPLATE_VARIABLE_REGEX = /\\{\\{([^{}]+)\\}\\}/g;\n\n/**\n * Extract template variables from text\n *\n * @param text - Text to search for variables\n * @returns Array of unique variable names (without braces)\n */\nexport function extractTemplateVariables(text: string): string[] {\n const variables: string[] = [];\n let match: RegExpExecArray | null;\n\n // Reset regex state\n TEMPLATE_VARIABLE_REGEX.lastIndex = 0;\n\n while ((match = TEMPLATE_VARIABLE_REGEX.exec(text)) !== null) {\n const varName = match[1].trim();\n if (varName && !variables.includes(varName)) {\n variables.push(varName);\n }\n }\n\n return variables;\n}\n\n/**\n * Extract all template variables from document content\n *\n * @param content - Array of paragraphs and tables\n * @returns Array of unique variable names\n */\nexport function extractAllTemplateVariables(content: BlockContent[]): string[] {\n const variables: string[] = [];\n\n for (const block of content) {\n if (block.type === 'paragraph') {\n const text = getParagraphText(block);\n const vars = extractTemplateVariables(text);\n for (const v of vars) {\n if (!variables.includes(v)) {\n variables.push(v);\n }\n }\n } else if (block.type === 'table') {\n // Recursively check table cells\n const tableVars = extractTableVariables(block);\n for (const v of tableVars) {\n if (!variables.includes(v)) {\n variables.push(v);\n }\n }\n }\n }\n\n return variables;\n}\n\n/**\n * Extract template variables from a table\n */\nfunction extractTableVariables(table: Table): string[] {\n const variables: string[] = [];\n\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const cellContent of cell.content) {\n if (cellContent.type === 'paragraph') {\n const text = getParagraphText(cellContent);\n const vars = extractTemplateVariables(text);\n for (const v of vars) {\n if (!variables.includes(v)) {\n variables.push(v);\n }\n }\n } else if (cellContent.type === 'table') {\n // Nested table\n const nestedVars = extractTableVariables(cellContent);\n for (const v of nestedVars) {\n if (!variables.includes(v)) {\n variables.push(v);\n }\n }\n }\n }\n }\n }\n\n return variables;\n}\n\n// ============================================================================\n// CONTENT PARSING\n// ============================================================================\n\n/**\n * Parse block content from an element (body or SDT content)\n *\n * @param parent - Parent element containing content\n * @param styles - Style map\n * @param theme - Theme\n * @param numbering - Numbering definitions\n * @param rels - Relationships\n * @param media - Media files\n * @returns Array of block content (paragraphs, tables)\n */\nfunction parseBlockContent(\n parent: XmlElement,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap | null,\n media: Map<string, MediaFile> | null\n): BlockContent[] {\n const content: BlockContent[] = [];\n const children = getChildElements(parent);\n\n // Track list counters for computing markers\n // Map: numId -> array of counters for each level\n const listCounters = new Map<number, number[]>();\n\n for (const child of children) {\n const name = child.name ?? '';\n\n // Paragraph (w:p)\n if (name === 'w:p' || name.endsWith(':p')) {\n const paragraph = parseParagraph(child, styles, theme, numbering, rels, media);\n // Compute list marker if this is a list item\n computeListMarker(paragraph, numbering, listCounters);\n content.push(paragraph);\n }\n // Table (w:tbl)\n else if (name === 'w:tbl' || name.endsWith(':tbl')) {\n const table = parseTable(child, styles, theme, numbering, rels, media);\n content.push(table);\n }\n // Structured Document Tag (w:sdt) - container for content\n else if (name === 'w:sdt' || name.endsWith(':sdt')) {\n // Find the content element inside SDT\n const sdtContent = (child.elements ?? []).find(\n (el: XmlElement) =>\n el.type === 'element' && (el.name === 'w:sdtContent' || el.name?.endsWith(':sdtContent'))\n );\n if (sdtContent) {\n // Recursively parse content inside SDT\n const sdtBlockContent = parseBlockContent(\n sdtContent,\n styles,\n theme,\n numbering,\n rels,\n media\n );\n content.push(...sdtBlockContent);\n }\n }\n // Section properties (w:sectPr) - handled separately at body level\n // Skip here as we handle it after content parsing\n }\n\n return content;\n}\n\n// ============================================================================\n// SECTION BUILDING\n// ============================================================================\n\n/**\n * Build sections from content based on section properties in paragraphs\n *\n * In OOXML, sections are delimited by:\n * 1. w:pPr/w:sectPr within a paragraph (marks end of a section)\n * 2. w:body/w:sectPr (final section properties)\n *\n * @param content - All block content\n * @param finalSectPr - Final section properties from body\n * @returns Array of sections\n */\nfunction buildSections(\n content: BlockContent[],\n finalSectPr: SectionProperties | undefined\n): Section[] {\n const sections: Section[] = [];\n let currentSectionContent: BlockContent[] = [];\n\n for (const block of content) {\n currentSectionContent.push(block);\n\n // Check if this paragraph ends a section\n if (block.type === 'paragraph' && block.sectionProperties) {\n // This paragraph ends a section\n sections.push({\n properties: block.sectionProperties,\n content: currentSectionContent,\n });\n\n // Start new section\n currentSectionContent = [];\n }\n }\n\n // Add final section with remaining content\n if (currentSectionContent.length > 0 || sections.length === 0) {\n sections.push({\n properties: finalSectPr ?? getDefaultSectionProperties(),\n content: currentSectionContent,\n });\n }\n\n return sections;\n}\n\n// ============================================================================\n// MAIN PARSER\n// ============================================================================\n\n/**\n * Parse document.xml body content\n *\n * @param xml - Raw XML content of document.xml\n * @param styles - Parsed style map\n * @param theme - Parsed theme\n * @param numbering - Parsed numbering definitions\n * @param rels - Document relationships\n * @param media - Media files\n * @returns DocumentBody with content, sections, and template variables\n */\nexport function parseDocumentBody(\n xml: string,\n styles: StyleMap | null = null,\n theme: Theme | null = null,\n numbering: NumberingMap | null = null,\n rels: RelationshipMap | null = null,\n media: Map<string, MediaFile> | null = null\n): DocumentBody {\n const result: DocumentBody = {\n content: [],\n };\n\n if (!xml) {\n return result;\n }\n\n // Parse XML\n const doc = parseXml(xml);\n if (!doc) {\n return result;\n }\n\n // Find root document element (w:document)\n const documentEl = (doc.elements ?? []).find(\n (el: XmlElement) =>\n el.type === 'element' && (el.name === 'w:document' || el.name?.endsWith(':document'))\n );\n if (!documentEl) {\n return result;\n }\n\n // Find body element (w:body)\n const bodyEl = findChild(documentEl, 'w', 'body');\n if (!bodyEl) {\n return result;\n }\n\n // Parse all block content (paragraphs, tables)\n result.content = parseBlockContent(bodyEl, styles, theme, numbering, rels, media);\n\n // Parse final section properties (w:body/w:sectPr)\n const finalSectPr = findChild(bodyEl, 'w', 'sectPr');\n if (finalSectPr) {\n result.finalSectionProperties = parseSectionProperties(finalSectPr, rels);\n }\n\n // Build sections from content\n result.sections = buildSections(result.content, result.finalSectionProperties);\n\n return result;\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Get all paragraphs from document body (flattened)\n */\nexport function getAllParagraphs(body: DocumentBody): Paragraph[] {\n const paragraphs: Paragraph[] = [];\n\n for (const block of body.content) {\n if (block.type === 'paragraph') {\n paragraphs.push(block);\n } else if (block.type === 'table') {\n // Get paragraphs from table cells\n paragraphs.push(...getTableParagraphs(block));\n }\n }\n\n return paragraphs;\n}\n\n/**\n * Get all paragraphs from a table (recursively)\n */\nfunction getTableParagraphs(table: Table): Paragraph[] {\n const paragraphs: Paragraph[] = [];\n\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const content of cell.content) {\n if (content.type === 'paragraph') {\n paragraphs.push(content);\n } else if (content.type === 'table') {\n paragraphs.push(...getTableParagraphs(content));\n }\n }\n }\n }\n\n return paragraphs;\n}\n\n/**\n * Get all tables from document body\n */\nexport function getAllTables(body: DocumentBody): Table[] {\n const tables: Table[] = [];\n\n for (const block of body.content) {\n if (block.type === 'table') {\n tables.push(block);\n // Also get nested tables\n tables.push(...getNestedTables(block));\n }\n }\n\n return tables;\n}\n\n/**\n * Get nested tables from a table (recursively)\n */\nfunction getNestedTables(table: Table): Table[] {\n const tables: Table[] = [];\n\n for (const row of table.rows) {\n for (const cell of row.cells) {\n for (const content of cell.content) {\n if (content.type === 'table') {\n tables.push(content);\n tables.push(...getNestedTables(content));\n }\n }\n }\n }\n\n return tables;\n}\n\n/**\n * Get plain text from entire document body\n */\nexport function getDocumentText(body: DocumentBody): string {\n const lines: string[] = [];\n\n for (const block of body.content) {\n if (block.type === 'paragraph') {\n lines.push(getParagraphText(block));\n } else if (block.type === 'table') {\n lines.push(getTableText(block));\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Get plain text from a table\n */\nfunction getTableText(table: Table): string {\n const lines: string[] = [];\n\n for (const row of table.rows) {\n const rowTexts: string[] = [];\n for (const cell of row.cells) {\n const cellTexts: string[] = [];\n for (const content of cell.content) {\n if (content.type === 'paragraph') {\n cellTexts.push(getParagraphText(content));\n } else if (content.type === 'table') {\n cellTexts.push(getTableText(content));\n }\n }\n rowTexts.push(cellTexts.join('\\n'));\n }\n lines.push(rowTexts.join('\\t'));\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Count total paragraphs in document\n */\nexport function getParagraphCount(body: DocumentBody): number {\n return getAllParagraphs(body).length;\n}\n\n/**\n * Count total words in document (approximate)\n */\nexport function getWordCount(body: DocumentBody): number {\n const text = getDocumentText(body);\n // Simple word counting - split by whitespace\n const words = text.trim().split(/\\s+/);\n return words.length > 0 && words[0] !== '' ? words.length : 0;\n}\n\n/**\n * Count total characters in document\n */\nexport function getCharacterCount(body: DocumentBody): number {\n return getDocumentText(body).length;\n}\n\n/**\n * Get section count\n */\nexport function getSectionCount(body: DocumentBody): number {\n return body.sections?.length ?? 1;\n}\n\n/**\n * Check if document has template variables\n */\nexport function hasTemplateVariables(body: DocumentBody): boolean {\n return extractAllTemplateVariables(body.content).length > 0;\n}\n\n/**\n * Get document outline (first N characters of each paragraph)\n *\n * @param body - Document body\n * @param maxCharsPerPara - Max characters per paragraph (default: 100)\n * @param maxParagraphs - Max paragraphs to include (default: 50)\n * @returns Array of paragraph previews\n */\nexport function getDocumentOutline(\n body: DocumentBody,\n maxCharsPerPara: number = 100,\n maxParagraphs: number = 50\n): string[] {\n const outline: string[] = [];\n const paragraphs = getAllParagraphs(body);\n\n for (let i = 0; i < Math.min(paragraphs.length, maxParagraphs); i++) {\n const text = getParagraphText(paragraphs[i]).trim();\n if (text.length > 0) {\n outline.push(\n text.length > maxCharsPerPara ? text.substring(0, maxCharsPerPara) + '...' : text\n );\n }\n }\n\n return outline;\n}\n","/**\n * Google Fonts Loader\n *\n * Dynamically loads fonts from Google Fonts API with:\n * - Loading state tracking\n * - Duplicate prevention\n * - Callback notifications\n * - Font availability detection\n */\n\n// Track loaded fonts to avoid duplicate requests\nconst loadedFonts = new Set<string>();\n\n// Track fonts currently being loaded\nconst loadingFonts = new Map<string, Promise<boolean>>();\n\n// Callbacks to notify when fonts are loaded\nconst loadCallbacks = new Set<(fonts: string[]) => void>();\n\n// Track overall loading state\nlet isLoadingAny = false;\n\n/**\n * Generate Google Fonts CSS URL for a font family\n *\n * @param fontFamily - The font family name (e.g., \"Roboto\", \"Open Sans\")\n * @param weights - Font weights to load (default: 400, 700)\n * @param styles - Font styles to load (default: normal, italic)\n * @returns Google Fonts CSS URL\n */\nfunction getGoogleFontsUrl(\n fontFamily: string,\n weights: number[] = [400, 700],\n styles: ('normal' | 'italic')[] = ['normal', 'italic']\n): string {\n // Encode font family name for URL\n const encodedFamily = encodeURIComponent(fontFamily);\n\n // Build weight/style combinations\n // Format: ital,wght@0,400;0,700;1,400;1,700\n const combinations: string[] = [];\n\n for (const style of styles) {\n const italVal = style === 'italic' ? 1 : 0;\n for (const weight of weights) {\n combinations.push(`${italVal},${weight}`);\n }\n }\n\n // Sort and join\n combinations.sort();\n const spec = combinations.join(';');\n\n return `https://fonts.googleapis.com/css2?family=${encodedFamily}:ital,wght@${spec}&display=swap`;\n}\n\n/**\n * Load a font from Google Fonts\n *\n * @param fontFamily - The font family name to load\n * @param options - Optional configuration\n * @returns Promise resolving to true if font loaded successfully, false otherwise\n */\nexport async function loadFont(\n fontFamily: string,\n options?: {\n weights?: number[];\n styles?: ('normal' | 'italic')[];\n }\n): Promise<boolean> {\n // Normalize font family name\n const normalizedFamily = fontFamily.trim();\n\n // Already loaded?\n if (loadedFonts.has(normalizedFamily)) {\n return true;\n }\n\n // Currently loading? Return existing promise\n const existingLoad = loadingFonts.get(normalizedFamily);\n if (existingLoad) {\n return existingLoad;\n }\n\n // Create load promise\n const loadPromise = (async (): Promise<boolean> => {\n isLoadingAny = true;\n\n try {\n // Generate Google Fonts URL\n const url = getGoogleFontsUrl(normalizedFamily, options?.weights, options?.styles);\n\n // Create link element\n const link = document.createElement('link');\n link.rel = 'stylesheet';\n link.href = url;\n\n // Wait for load or error\n const loaded = await new Promise<boolean>((resolve) => {\n link.onload = () => resolve(true);\n link.onerror = () => resolve(false);\n\n // Append to head\n document.head.appendChild(link);\n\n // Timeout after 5 seconds\n setTimeout(() => resolve(false), 5000);\n });\n\n if (loaded) {\n // Wait a bit for the font to be available\n await waitForFontAvailable(normalizedFamily, 3000);\n\n loadedFonts.add(normalizedFamily);\n\n // Notify callbacks\n notifyCallbacks([normalizedFamily]);\n\n return true;\n }\n\n return false;\n } catch (error) {\n console.warn(`Failed to load font \"${normalizedFamily}\":`, error);\n return false;\n } finally {\n loadingFonts.delete(normalizedFamily);\n\n // Check if still loading any fonts\n if (loadingFonts.size === 0) {\n isLoadingAny = false;\n }\n }\n })();\n\n loadingFonts.set(normalizedFamily, loadPromise);\n return loadPromise;\n}\n\n/**\n * Load multiple fonts from Google Fonts\n *\n * @param families - Array of font family names to load\n * @param options - Optional configuration\n * @returns Promise resolving when all fonts are loaded (or failed)\n */\nexport async function loadFonts(\n families: string[],\n options?: {\n weights?: number[];\n styles?: ('normal' | 'italic')[];\n }\n): Promise<void> {\n // Filter out already loaded fonts\n const toLoad = families.filter((family) => !loadedFonts.has(family.trim()));\n\n if (toLoad.length === 0) {\n return;\n }\n\n // Load all fonts in parallel\n await Promise.all(toLoad.map((family) => loadFont(family, options)));\n}\n\n/**\n * Check if a font is loaded\n *\n * @param fontFamily - The font family name to check\n * @returns true if the font is loaded, false otherwise\n */\nexport function isFontLoaded(fontFamily: string): boolean {\n return loadedFonts.has(fontFamily.trim());\n}\n\n/**\n * Check if any fonts are currently loading\n *\n * @returns true if any fonts are loading, false otherwise\n */\nexport function isLoading(): boolean {\n return isLoadingAny;\n}\n\n/**\n * Get list of all loaded fonts\n *\n * @returns Array of loaded font family names\n */\nexport function getLoadedFonts(): string[] {\n return Array.from(loadedFonts);\n}\n\n/**\n * Register a callback to be notified when fonts are loaded\n *\n * @param callback - Function to call when fonts are loaded\n * @returns Cleanup function to remove the callback\n */\nexport function onFontsLoaded(callback: (fonts: string[]) => void): () => void {\n loadCallbacks.add(callback);\n\n // Return cleanup function\n return () => {\n loadCallbacks.delete(callback);\n };\n}\n\n/**\n * Notify all registered callbacks\n */\nfunction notifyCallbacks(fonts: string[]): void {\n for (const callback of loadCallbacks) {\n try {\n callback(fonts);\n } catch (error) {\n console.warn('Font load callback error:', error);\n }\n }\n}\n\n/**\n * Wait for a font to be available using the CSS Font Loading API\n *\n * @param fontFamily - The font family to wait for\n * @param timeout - Maximum time to wait in milliseconds\n * @returns Promise resolving when font is available or timeout\n */\nasync function waitForFontAvailable(fontFamily: string, timeout: number): Promise<boolean> {\n // Use CSS Font Loading API if available\n if ('fonts' in document) {\n try {\n // Try to wait for the font\n const fontFace = `400 16px \"${fontFamily}\"`;\n await Promise.race([\n document.fonts.load(fontFace),\n new Promise((resolve) => setTimeout(resolve, timeout)),\n ]);\n\n return document.fonts.check(fontFace);\n } catch {\n // Fall through to fallback\n }\n }\n\n // Fallback: just wait a bit\n await new Promise((resolve) => setTimeout(resolve, 100));\n return true;\n}\n\n/**\n * Check if a font is available on the system using canvas measurement\n *\n * This uses the technique of comparing text width with the target font\n * vs a known fallback font. If they differ, the font is available.\n *\n * @param fontFamily - The font family name to check\n * @param fallbackFont - Fallback font to compare against\n * @returns true if font is available, false otherwise\n */\nexport function canRenderFont(fontFamily: string, fallbackFont: string = 'sans-serif'): boolean {\n // Skip if we're not in a browser\n if (typeof document === 'undefined') {\n return false;\n }\n\n const _canRenderFont = (fontName: string, fallback: string): boolean => {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n\n if (!ctx) {\n return false;\n }\n\n ctx.textBaseline = 'top';\n\n const text = 'abcdefghijklmnopqrstuvwxyz0123456789';\n\n // Measure with fallback font only\n ctx.font = `72px ${fallback}`;\n const fallbackWidth = ctx.measureText(text).width;\n\n // Measure with target font (with fallback)\n ctx.font = `72px \"${fontName}\", ${fallback}`;\n const customWidth = ctx.measureText(text).width;\n\n // If widths differ, the custom font was used\n return customWidth !== fallbackWidth;\n };\n\n // Check with primary fallback\n if (_canRenderFont(fontFamily, fallbackFont)) {\n return true;\n }\n\n // Check with opposite fallback (handles edge case where font name\n // matches the browser's default sans-serif or serif)\n const oppositeFallback = fallbackFont === 'sans-serif' ? 'serif' : 'sans-serif';\n return _canRenderFont(fontFamily, oppositeFallback);\n}\n\n/**\n * Load a font from a raw buffer (e.g., embedded in DOCX)\n *\n * @param fontFamily - The font family name\n * @param buffer - Font file buffer (TTF, OTF, WOFF, WOFF2)\n * @param options - Font options\n * @returns Promise resolving when font is loaded\n */\nexport async function loadFontFromBuffer(\n fontFamily: string,\n buffer: ArrayBuffer,\n options?: {\n weight?: number | string;\n style?: 'normal' | 'italic';\n }\n): Promise<boolean> {\n const normalizedFamily = fontFamily.trim();\n\n // Already loaded?\n if (loadedFonts.has(normalizedFamily)) {\n return true;\n }\n\n try {\n // Create blob URL\n const blob = new Blob([buffer], { type: 'font/ttf' });\n const url = URL.createObjectURL(blob);\n\n // Create @font-face CSS\n const style = document.createElement('style');\n style.textContent = `\n @font-face {\n font-family: \"${normalizedFamily}\";\n src: url(${url}) format('truetype');\n font-weight: ${options?.weight ?? 'normal'};\n font-style: ${options?.style ?? 'normal'};\n font-display: swap;\n }\n `;\n\n document.head.appendChild(style);\n\n // Wait for font to be available\n await waitForFontAvailable(normalizedFamily, 3000);\n\n loadedFonts.add(normalizedFamily);\n notifyCallbacks([normalizedFamily]);\n\n return true;\n } catch (error) {\n console.warn(`Failed to load font \"${normalizedFamily}\" from buffer:`, error);\n return false;\n }\n}\n\n/**\n * Mapping from common Office/system fonts to Google Fonts equivalents\n *\n * Google Fonts doesn't have exact matches for many Microsoft fonts,\n * but these are close alternatives that work well for document rendering.\n */\nexport const FONT_MAPPING: Record<string, string> = {\n // Microsoft Office fonts → Google Fonts equivalents\n Calibri: 'Carlito',\n Cambria: 'Caladea',\n Arial: 'Arimo',\n 'Times New Roman': 'Tinos',\n 'Courier New': 'Cousine',\n Garamond: 'EB Garamond',\n 'Book Antiqua': 'EB Garamond',\n Georgia: 'Tinos',\n Verdana: 'Open Sans',\n Tahoma: 'Open Sans',\n 'Trebuchet MS': 'Source Sans Pro',\n 'Century Gothic': 'Poppins',\n 'Franklin Gothic': 'Libre Franklin',\n Palatino: 'EB Garamond',\n 'Palatino Linotype': 'EB Garamond',\n 'Lucida Sans': 'Open Sans',\n 'Segoe UI': 'Open Sans',\n Impact: 'Anton',\n 'Comic Sans MS': 'Comic Neue',\n Consolas: 'Inconsolata',\n 'Lucida Console': 'Inconsolata',\n Monaco: 'Fira Code',\n};\n\n/**\n * Get the Google Fonts equivalent for a font name\n *\n * @param fontName - The original font name from the document\n * @returns The Google Fonts equivalent, or the original name if no mapping exists\n */\nexport function getGoogleFontEquivalent(fontName: string): string {\n const trimmed = fontName.trim();\n return FONT_MAPPING[trimmed] || trimmed;\n}\n\n/**\n * Load a font, automatically mapping to Google Fonts equivalent if needed.\n * If the font needs mapping, also creates a CSS alias so the original font\n * name works in stylesheets.\n *\n * @param fontFamily - The font family name (may be an Office font)\n * @returns Promise resolving to true if font loaded\n */\nexport async function loadFontWithMapping(fontFamily: string): Promise<boolean> {\n const trimmed = fontFamily.trim();\n const googleFont = getGoogleFontEquivalent(trimmed);\n\n // If there's a mapping, fetch the CSS and create alias with original name\n // This avoids loading the font twice (once for Google name, once for alias)\n if (googleFont !== trimmed) {\n await createFontAlias(trimmed, googleFont);\n loadedFonts.add(trimmed);\n loadedFonts.add(googleFont);\n return true;\n }\n\n // No mapping needed, load directly\n return loadFont(googleFont);\n}\n\n/**\n * Create a CSS font-family alias by fetching the Google Fonts CSS and\n * rewriting it to use the original font name.\n *\n * @param originalName - The original font name (e.g., \"Garamond\")\n * @param googleFontName - The Google Font name (e.g., \"EB Garamond\")\n */\nasync function createFontAlias(originalName: string, googleFontName: string): Promise<void> {\n // Create a style element with @font-face that aliases the original name\n const styleId = `font-alias-${originalName.toLowerCase().replace(/\\s+/g, '-')}`;\n\n // Don't create duplicate aliases\n if (document.getElementById(styleId)) {\n return;\n }\n\n try {\n // Fetch the Google Fonts CSS to get the actual font URLs\n const url = getGoogleFontsUrl(googleFontName, [400, 700], ['normal', 'italic']);\n const response = await fetch(url);\n\n if (!response.ok) {\n console.warn(`Failed to fetch Google Fonts CSS for \"${googleFontName}\": ${response.status}`);\n return;\n }\n\n const css = await response.text();\n\n // Replace the Google Font name with the original name in all @font-face rules\n // The CSS contains: font-family: 'EB Garamond';\n // We want: font-family: 'Garamond';\n const regex = new RegExp(`font-family:\\\\s*['\"]${escapeRegExp(googleFontName)}['\"]`, 'gi');\n const aliasedCss = css.replace(regex, `font-family: '${originalName}'`);\n\n const style = document.createElement('style');\n style.id = styleId;\n style.textContent = aliasedCss;\n\n document.head.appendChild(style);\n console.log(`Loaded font: \"${originalName}\" (via ${googleFontName})`);\n } catch (error) {\n console.warn(`Failed to create font alias for \"${originalName}\":`, error);\n }\n}\n\n/**\n * Escape special regex characters in a string\n */\nfunction escapeRegExp(string: string): string {\n return string.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Load multiple fonts with automatic mapping to Google Fonts equivalents\n *\n * @param families - Array of font family names\n * @returns Promise resolving when all fonts are loaded\n */\nexport async function loadFontsWithMapping(families: string[]): Promise<void> {\n // Remove duplicates\n const uniqueFonts = [...new Set(families.map((f) => f.trim()))];\n // Load each font with mapping (creates aliases for Office → Google font mappings)\n await Promise.all(uniqueFonts.map((family) => loadFontWithMapping(family)));\n}\n\n/**\n * Preload a list of common document fonts\n *\n * This preloads fonts commonly used in DOCX documents that have\n * Google Fonts equivalents.\n */\nexport async function preloadCommonFonts(): Promise<void> {\n const commonFonts = [\n 'Carlito', // Calibri equivalent\n 'Caladea', // Cambria equivalent\n 'Arimo', // Arial equivalent\n 'Tinos', // Times New Roman equivalent\n 'Cousine', // Courier New equivalent\n 'EB Garamond', // Garamond equivalent\n ];\n\n await loadFonts(commonFonts);\n}\n\n/**\n * Extract all font families used in a document\n *\n * Uses loose typing to handle any document-like structure.\n *\n * @param document - The parsed document\n * @returns Set of unique font family names\n */\nexport function extractFontsFromDocument(document: unknown): Set<string> {\n const fonts = new Set<string>();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const doc = document as any;\n if (!doc?.package) return fonts;\n\n // Extract from document content\n const content = doc.package?.document?.content;\n if (Array.isArray(content)) {\n for (const paragraph of content) {\n if (paragraph?.type === 'paragraph' && Array.isArray(paragraph.content)) {\n for (const run of paragraph.content) {\n if (run?.type === 'run' && run.formatting?.fontFamily) {\n const { ascii, hAnsi } = run.formatting.fontFamily;\n if (ascii) fonts.add(ascii);\n if (hAnsi && hAnsi !== ascii) fonts.add(hAnsi);\n }\n }\n }\n }\n }\n\n // Extract from styles\n const styles = doc.package?.styles?.styles;\n if (Array.isArray(styles)) {\n for (const style of styles) {\n if (style?.runProperties?.fontFamily) {\n const { ascii, hAnsi } = style.runProperties.fontFamily;\n if (ascii) fonts.add(ascii);\n if (hAnsi && hAnsi !== ascii) fonts.add(hAnsi);\n }\n }\n }\n\n return fonts;\n}\n\n/**\n * Extract fonts from a document and load them from Google Fonts\n *\n * @param document - The parsed document\n * @returns Promise resolving when fonts are loaded\n */\nexport async function loadDocumentFonts(document: unknown): Promise<void> {\n const fonts = extractFontsFromDocument(document);\n\n if (fonts.size === 0) {\n return;\n }\n\n console.log('Loading document fonts:', Array.from(fonts));\n await loadFontsWithMapping(Array.from(fonts));\n}\n","/**\n * Main Parser Orchestrator - Unified parseDocx function\n *\n * Coordinates all sub-parsers to produce a complete Document model.\n * Handles loading order, dependency resolution, and font preloading.\n *\n * Parsing order:\n * 1. Unzip DOCX package\n * 2. Parse relationships\n * 3. Parse theme (needed for style color/font resolution)\n * 4. Parse styles (depends on theme)\n * 5. Parse numbering\n * 6. Parse document body (depends on styles, theme, numbering, rels)\n * 7. Parse headers/footers (depends on styles, theme, numbering, rels)\n * 8. Parse footnotes/endnotes (depends on styles, theme, numbering, rels)\n * 9. Extract and load fonts\n * 10. Build media file map\n * 11. Assemble final Document\n */\n\nimport type {\n Document,\n DocxPackage,\n DocumentBody,\n Theme,\n Footnote,\n Endnote,\n HeaderFooter,\n RelationshipMap,\n MediaFile,\n StyleDefinitions,\n} from '../types/document';\nimport { unzipDocx, getMediaMimeType, type RawDocxContent } from './unzip';\nimport { parseRelationships, RELATIONSHIP_TYPES } from './relsParser';\nimport { parseTheme } from './themeParser';\nimport { parseStyles, parseStyleDefinitions, type StyleMap } from './styleParser';\nimport { parseNumbering, type NumberingMap } from './numberingParser';\nimport { parseDocumentBody, extractAllTemplateVariables } from './documentParser';\nimport { parseHeader, parseFooter } from './headerFooterParser';\nimport { parseFootnotes, parseEndnotes } from './footnoteParser';\nimport { loadFontsWithMapping } from '../utils/fontLoader';\n\n// ============================================================================\n// PROGRESS CALLBACK\n// ============================================================================\n\n/**\n * Progress callback for tracking parsing stages\n */\nexport type ProgressCallback = (stage: string, percent: number) => void;\n\n/**\n * Parsing options\n */\nexport interface ParseOptions {\n /** Progress callback for tracking parsing stages */\n onProgress?: ProgressCallback;\n /** Whether to preload fonts (default: true) */\n preloadFonts?: boolean;\n /** Whether to parse headers/footers (default: true) */\n parseHeadersFooters?: boolean;\n /** Whether to parse footnotes/endnotes (default: true) */\n parseNotes?: boolean;\n /** Whether to detect template variables (default: true) */\n detectVariables?: boolean;\n}\n\n// ============================================================================\n// MAIN PARSER\n// ============================================================================\n\n/**\n * Parse a DOCX file into a complete Document model\n *\n * @param buffer - DOCX file as ArrayBuffer\n * @param options - Parsing options\n * @returns Promise resolving to Document\n * @throws Error if parsing fails\n */\nexport async function parseDocx(\n buffer: ArrayBuffer,\n options: ParseOptions = {}\n): Promise<Document> {\n const {\n onProgress = () => {},\n preloadFonts = true,\n parseHeadersFooters = true,\n parseNotes = true,\n detectVariables = true,\n } = options;\n\n const warnings: string[] = [];\n\n try {\n // ========================================================================\n // STAGE 1: Unzip DOCX package (0-10%)\n // ========================================================================\n onProgress('Extracting DOCX...', 0);\n const raw = await unzipDocx(buffer);\n onProgress('Extracted DOCX', 10);\n\n // ========================================================================\n // STAGE 2: Parse relationships (10-15%)\n // ========================================================================\n onProgress('Parsing relationships...', 10);\n const rels = raw.documentRels ? parseRelationships(raw.documentRels) : new Map();\n onProgress('Parsed relationships', 15);\n\n // ========================================================================\n // STAGE 3: Parse theme (15-20%)\n // ========================================================================\n onProgress('Parsing theme...', 15);\n const theme = parseTheme(raw.themeXml);\n onProgress('Parsed theme', 20);\n\n // ========================================================================\n // STAGE 4: Parse styles (20-30%)\n // ========================================================================\n onProgress('Parsing styles...', 20);\n let styles: StyleMap | null = null;\n let styleDefinitions: StyleDefinitions | undefined;\n\n if (raw.stylesXml) {\n styles = parseStyles(raw.stylesXml, theme);\n styleDefinitions = parseStyleDefinitions(raw.stylesXml, theme);\n }\n onProgress('Parsed styles', 30);\n\n // ========================================================================\n // STAGE 5: Parse numbering (30-35%)\n // ========================================================================\n onProgress('Parsing numbering...', 30);\n const numbering = parseNumbering(raw.numberingXml);\n onProgress('Parsed numbering', 35);\n\n // ========================================================================\n // STAGE 6: Build media file map (35-40%)\n // ========================================================================\n onProgress('Processing media files...', 35);\n const media = buildMediaMap(raw, rels);\n onProgress('Processed media', 40);\n\n // ========================================================================\n // STAGE 7: Parse document body (40-55%)\n // ========================================================================\n onProgress('Parsing document body...', 40);\n let documentBody: DocumentBody = { content: [] };\n\n if (raw.documentXml) {\n documentBody = parseDocumentBody(raw.documentXml, styles, theme, numbering, rels, media);\n } else {\n warnings.push('No document.xml found in DOCX');\n }\n onProgress('Parsed document body', 55);\n\n // ========================================================================\n // STAGE 8: Parse headers/footers (55-65%)\n // ========================================================================\n let headers: Map<string, HeaderFooter> | undefined;\n let footers: Map<string, HeaderFooter> | undefined;\n\n if (parseHeadersFooters) {\n onProgress('Parsing headers/footers...', 55);\n const { headers: h, footers: f } = parseHeadersAndFooters(\n raw,\n styles,\n theme,\n numbering,\n rels,\n media\n );\n headers = h;\n footers = f;\n onProgress('Parsed headers/footers', 65);\n } else {\n onProgress('Skipping headers/footers', 65);\n }\n\n // ========================================================================\n // STAGE 9: Parse footnotes/endnotes (65-75%)\n // ========================================================================\n let footnotes: Footnote[] | undefined;\n let endnotes: Endnote[] | undefined;\n\n if (parseNotes) {\n onProgress('Parsing footnotes/endnotes...', 65);\n const { footnotes: fn, endnotes: en } = parseNotesContent(\n raw,\n styles,\n theme,\n numbering,\n rels,\n media\n );\n footnotes = fn;\n endnotes = en;\n onProgress('Parsed footnotes/endnotes', 75);\n } else {\n onProgress('Skipping footnotes/endnotes', 75);\n }\n\n // ========================================================================\n // STAGE 10: Detect template variables (75-80%)\n // ========================================================================\n let templateVariables: string[] | undefined;\n\n if (detectVariables) {\n onProgress('Detecting template variables...', 75);\n templateVariables = extractAllTemplateVariables(documentBody.content);\n onProgress('Detected variables', 80);\n } else {\n onProgress('Skipping variable detection', 80);\n }\n\n // ========================================================================\n // STAGE 11: Extract and load fonts (80-95%)\n // ========================================================================\n if (preloadFonts) {\n onProgress('Loading fonts...', 80);\n await loadDocumentFonts(theme, styleDefinitions, documentBody);\n onProgress('Loaded fonts', 95);\n } else {\n onProgress('Skipping font loading', 95);\n }\n\n // ========================================================================\n // STAGE 12: Assemble final Document (95-100%)\n // ========================================================================\n onProgress('Assembling document...', 95);\n\n const pkg: DocxPackage = {\n document: documentBody,\n styles: styleDefinitions,\n theme,\n numbering: numbering.definitions,\n headers,\n footers,\n footnotes,\n endnotes,\n relationships: rels,\n media,\n };\n\n const document: Document = {\n package: pkg,\n originalBuffer: buffer,\n templateVariables,\n warnings: warnings.length > 0 ? warnings : undefined,\n };\n\n onProgress('Complete', 100);\n return document;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to parse DOCX: ${message}`);\n }\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Build media file map from raw content and relationships\n */\nfunction buildMediaMap(raw: RawDocxContent, _rels: RelationshipMap): Map<string, MediaFile> {\n const media = new Map<string, MediaFile>();\n\n // Process each media file\n for (const [path, data] of raw.media.entries()) {\n const filename = path.split('/').pop() || path;\n const mimeType = getMediaMimeType(path);\n\n // Create a data URL for the image\n const bytes = new Uint8Array(data);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n const dataUrl = `data:${mimeType};base64,${base64}`;\n\n const mediaFile: MediaFile = {\n path,\n filename,\n mimeType,\n data,\n dataUrl,\n };\n\n // Store by path and also by relationship target path\n media.set(path, mediaFile);\n\n // Also map normalized paths (without \"word/\" prefix)\n const normalizedPath = path.replace(/^word\\//, '');\n if (normalizedPath !== path) {\n media.set(normalizedPath, mediaFile);\n }\n }\n\n return media;\n}\n\n/**\n * Parse headers and footers from raw content\n */\n/**\n * Case-insensitive lookup in a Map\n * ZIP files may have inconsistent casing for paths/filenames\n */\nfunction getMapCaseInsensitive<T>(map: Map<string, T>, targetKey: string): T | undefined {\n const lowerTarget = targetKey.toLowerCase();\n for (const [key, value] of map.entries()) {\n if (key.toLowerCase() === lowerTarget) {\n return value;\n }\n }\n return undefined;\n}\n\nfunction parseHeadersAndFooters(\n raw: RawDocxContent,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap,\n media: Map<string, MediaFile>\n): { headers: Map<string, HeaderFooter>; footers: Map<string, HeaderFooter> } {\n const headers = new Map<string, HeaderFooter>();\n const footers = new Map<string, HeaderFooter>();\n\n // We need to map the relationship IDs to header/footer files\n // The relationships tell us which rId maps to which header/footer file\n\n // Find header/footer references in relationships\n for (const [rId, rel] of rels.entries()) {\n if (rel.type === RELATIONSHIP_TYPES.header && rel.target) {\n // Get the header XML for this relationship\n // Use case-insensitive lookup since ZIP files may have inconsistent casing\n const filename = rel.target.split('/').pop() || rel.target;\n const headerXml = getMapCaseInsensitive(raw.headers, filename);\n\n if (headerXml) {\n // Get header-specific relationships (e.g., word/_rels/header1.xml.rels)\n const headerRelsPath = `word/_rels/${filename}.rels`;\n const headerRelsXml = getMapCaseInsensitive(raw.allXml, headerRelsPath);\n const headerRels = headerRelsXml ? parseRelationships(headerRelsXml) : rels;\n\n const header = parseHeader(\n headerXml,\n 'default', // We'll update this based on sectPr references\n styles,\n theme,\n numbering,\n headerRels,\n media\n );\n headers.set(rId, header);\n }\n } else if (rel.type === RELATIONSHIP_TYPES.footer && rel.target) {\n // Use case-insensitive lookup since ZIP files may have inconsistent casing\n const filename = rel.target.split('/').pop() || rel.target;\n const footerXml = getMapCaseInsensitive(raw.footers, filename);\n\n if (footerXml) {\n // Get footer-specific relationships (e.g., word/_rels/footer1.xml.rels)\n const footerRelsPath = `word/_rels/${filename}.rels`;\n const footerRelsXml = getMapCaseInsensitive(raw.allXml, footerRelsPath);\n const footerRels = footerRelsXml ? parseRelationships(footerRelsXml) : rels;\n\n const footer = parseFooter(\n footerXml,\n 'default',\n styles,\n theme,\n numbering,\n footerRels,\n media\n );\n footers.set(rId, footer);\n }\n }\n }\n\n return { headers, footers };\n}\n\n/**\n * Parse footnotes and endnotes from raw content\n */\nfunction parseNotesContent(\n raw: RawDocxContent,\n styles: StyleMap | null,\n theme: Theme | null,\n numbering: NumberingMap | null,\n rels: RelationshipMap,\n media: Map<string, MediaFile>\n): { footnotes: Footnote[]; endnotes: Endnote[] } {\n const footnoteMap = parseFootnotes(raw.footnotesXml, styles, theme, numbering, rels, media);\n\n const endnoteMap = parseEndnotes(raw.endnotesXml, styles, theme, numbering, rels, media);\n\n return {\n footnotes: footnoteMap.getNormalFootnotes(),\n endnotes: endnoteMap.getNormalEndnotes(),\n };\n}\n\n/**\n * Extract fonts from document and load them\n */\nasync function loadDocumentFonts(\n theme: Theme | null,\n styleDefinitions: StyleDefinitions | undefined,\n documentBody: DocumentBody\n): Promise<void> {\n const docxFonts = new Set<string>();\n\n // Extract fonts from theme\n if (theme?.fontScheme) {\n const { majorFont, minorFont } = theme.fontScheme;\n if (majorFont?.latin) docxFonts.add(majorFont.latin);\n if (minorFont?.latin) docxFonts.add(minorFont.latin);\n }\n\n // Extract fonts from style defaults\n if (styleDefinitions?.docDefaults?.rPr?.fontFamily?.ascii) {\n docxFonts.add(styleDefinitions.docDefaults.rPr.fontFamily.ascii);\n }\n\n // Extract fonts from styles\n if (styleDefinitions?.styles) {\n for (const style of styleDefinitions.styles) {\n if (style.rPr?.fontFamily?.ascii) {\n docxFonts.add(style.rPr.fontFamily.ascii);\n }\n if (style.rPr?.fontFamily?.hAnsi) {\n docxFonts.add(style.rPr.fontFamily.hAnsi);\n }\n }\n }\n\n // Extract fonts from document content (inline run formatting)\n if (documentBody.content) {\n for (const block of documentBody.content) {\n if (block.type === 'paragraph') {\n for (const item of block.content) {\n if (item.type === 'run' && item.formatting?.fontFamily) {\n if (item.formatting.fontFamily.ascii) {\n docxFonts.add(item.formatting.fontFamily.ascii);\n }\n if (item.formatting.fontFamily.hAnsi) {\n docxFonts.add(item.formatting.fontFamily.hAnsi);\n }\n }\n }\n }\n }\n }\n\n // Load fonts with mapping (creates aliases so original names work in CSS)\n if (docxFonts.size > 0) {\n try {\n await loadFontsWithMapping(Array.from(docxFonts));\n } catch (error) {\n // Font loading is non-critical, continue without fonts\n console.warn('Failed to load some fonts:', error);\n }\n }\n}\n\n// ============================================================================\n// CONVENIENCE FUNCTIONS\n// ============================================================================\n\n/**\n * Quick parse - parse a DOCX without font loading\n * Useful for quick content extraction or when fonts aren't needed\n */\nexport async function quickParseDocx(buffer: ArrayBuffer): Promise<Document> {\n return parseDocx(buffer, {\n preloadFonts: false,\n parseHeadersFooters: false,\n parseNotes: false,\n detectVariables: true,\n });\n}\n\n/**\n * Full parse - parse everything including fonts\n */\nexport async function fullParseDocx(\n buffer: ArrayBuffer,\n onProgress?: ProgressCallback\n): Promise<Document> {\n return parseDocx(buffer, {\n onProgress,\n preloadFonts: true,\n parseHeadersFooters: true,\n parseNotes: true,\n detectVariables: true,\n });\n}\n\n/**\n * Get template variables from a DOCX without full parsing\n * Faster than full parse when you only need variables\n */\nexport async function getDocxVariables(buffer: ArrayBuffer): Promise<string[]> {\n const raw = await unzipDocx(buffer);\n\n if (!raw.documentXml) {\n return [];\n }\n\n // Quick parse just the document body\n const documentBody = parseDocumentBody(raw.documentXml);\n return extractAllTemplateVariables(documentBody.content);\n}\n\n/**\n * Get document summary without full parsing\n */\nexport async function getDocxSummary(buffer: ArrayBuffer): Promise<{\n hasDocument: boolean;\n hasStyles: boolean;\n hasTheme: boolean;\n hasNumbering: boolean;\n headerCount: number;\n footerCount: number;\n mediaCount: number;\n variableCount: number;\n}> {\n const raw = await unzipDocx(buffer);\n const variables = raw.documentXml\n ? extractAllTemplateVariables(parseDocumentBody(raw.documentXml).content)\n : [];\n\n return {\n hasDocument: raw.documentXml !== null,\n hasStyles: raw.stylesXml !== null,\n hasTheme: raw.themeXml !== null,\n hasNumbering: raw.numberingXml !== null,\n headerCount: raw.headers.size,\n footerCount: raw.footers.size,\n mediaCount: raw.media.size,\n variableCount: variables.length,\n };\n}\n","/**\n * DOCX Repacker - Repack modified document into valid DOCX\n *\n * Takes a Document with modified content and creates a new DOCX file\n * by updating document.xml while preserving all other files from\n * the original ZIP archive.\n *\n * This ensures round-trip fidelity:\n * - styles.xml, theme1.xml, fontTable.xml remain untouched\n * - Media files preserved\n * - Relationships preserved\n * - Only document.xml is updated with new content\n *\n * OOXML Package Structure:\n * - [Content_Types].xml - Content type declarations\n * - _rels/.rels - Package relationships\n * - word/document.xml - Main document (modified)\n * - word/styles.xml - Styles (preserved)\n * - word/theme/theme1.xml - Theme (preserved)\n * - word/numbering.xml - Numbering (preserved)\n * - word/fontTable.xml - Font table (preserved)\n * - word/settings.xml - Settings (preserved)\n * - word/header*.xml - Headers (preserved)\n * - word/footer*.xml - Footers (preserved)\n * - word/footnotes.xml - Footnotes (preserved)\n * - word/endnotes.xml - Endnotes (preserved)\n * - word/media/* - Media files (preserved)\n * - word/_rels/document.xml.rels - Document relationships (preserved)\n * - docProps/* - Document properties (preserved)\n */\n\nimport JSZip from 'jszip';\nimport type { Document } from '../types/document';\nimport { serializeDocument } from './serializer/documentSerializer';\nimport { type RawDocxContent } from './unzip';\n\n// ============================================================================\n// MAIN REPACKER\n// ============================================================================\n\n/**\n * Options for repacking DOCX\n */\nexport interface RepackOptions {\n /** Compression level (0-9, default: 6) */\n compressionLevel?: number;\n /** Whether to update modification date in docProps/core.xml */\n updateModifiedDate?: boolean;\n /** Custom modifier name for lastModifiedBy */\n modifiedBy?: string;\n}\n\n/**\n * Repack a Document into a valid DOCX file\n *\n * @param doc - Document with modified content\n * @param options - Optional repack options\n * @returns Promise resolving to DOCX as ArrayBuffer\n * @throws Error if document has no original buffer for round-trip\n */\nexport async function repackDocx(doc: Document, options: RepackOptions = {}): Promise<ArrayBuffer> {\n // Validate we have an original buffer to base on\n if (!doc.originalBuffer) {\n throw new Error(\n 'Cannot repack document: no original buffer for round-trip. ' +\n 'Use createDocx() for new documents.'\n );\n }\n\n const { compressionLevel = 6, updateModifiedDate = true, modifiedBy } = options;\n\n // Load the original ZIP\n const originalZip = await JSZip.loadAsync(doc.originalBuffer);\n\n // Create a new ZIP with all original files\n const newZip = new JSZip();\n\n // Copy all files from original ZIP\n for (const [path, file] of Object.entries(originalZip.files)) {\n // Skip directories\n if (file.dir) {\n newZip.folder(path.replace(/\\/$/, ''));\n continue;\n }\n\n // Get original file content\n const content = await file.async('arraybuffer');\n\n // Add to new ZIP (we'll update specific files below)\n newZip.file(path, content, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n }\n\n // Serialize and update document.xml\n const documentXml = serializeDocument(doc);\n newZip.file('word/document.xml', documentXml, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n\n // Optionally update modification date in docProps/core.xml\n if (updateModifiedDate) {\n const corePropsPath = 'docProps/core.xml';\n const corePropsFile = originalZip.file(corePropsPath);\n\n if (corePropsFile) {\n const originalCoreProps = await corePropsFile.async('text');\n const updatedCoreProps = updateCoreProperties(originalCoreProps, {\n updateModifiedDate,\n modifiedBy,\n });\n\n newZip.file(corePropsPath, updatedCoreProps, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n }\n }\n\n // Generate the new DOCX file\n const arrayBuffer = await newZip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n\n return arrayBuffer;\n}\n\n/**\n * Repack a Document using raw content for more control\n *\n * @param doc - Document with modified content\n * @param rawContent - Original raw content from unzipDocx\n * @param options - Optional repack options\n * @returns Promise resolving to DOCX as ArrayBuffer\n */\nexport async function repackDocxFromRaw(\n doc: Document,\n rawContent: RawDocxContent,\n options: RepackOptions = {}\n): Promise<ArrayBuffer> {\n const { compressionLevel = 6, updateModifiedDate = true, modifiedBy } = options;\n\n // Create a new ZIP with all original files\n const newZip = new JSZip();\n\n // Copy all files from original ZIP\n for (const [path, file] of Object.entries(rawContent.originalZip.files)) {\n // Skip directories\n if (file.dir) {\n newZip.folder(path.replace(/\\/$/, ''));\n continue;\n }\n\n // Get original file content\n const content = await file.async('arraybuffer');\n\n // Add to new ZIP\n newZip.file(path, content, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n }\n\n // Serialize and update document.xml\n const documentXml = serializeDocument(doc);\n newZip.file('word/document.xml', documentXml, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n\n // Optionally update core properties\n if (updateModifiedDate && rawContent.corePropsXml) {\n const updatedCoreProps = updateCoreProperties(rawContent.corePropsXml, {\n updateModifiedDate,\n modifiedBy,\n });\n\n newZip.file('docProps/core.xml', updatedCoreProps, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n }\n\n // Generate the new DOCX file\n const arrayBuffer = await newZip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n\n return arrayBuffer;\n}\n\n// ============================================================================\n// SELECTIVE UPDATES\n// ============================================================================\n\n/**\n * Update only document.xml in a DOCX buffer (minimal changes)\n *\n * @param originalBuffer - Original DOCX as ArrayBuffer\n * @param newDocumentXml - New document.xml content\n * @param options - Optional repack options\n * @returns Promise resolving to DOCX as ArrayBuffer\n */\nexport async function updateDocumentXml(\n originalBuffer: ArrayBuffer,\n newDocumentXml: string,\n options: RepackOptions = {}\n): Promise<ArrayBuffer> {\n const { compressionLevel = 6 } = options;\n\n // Load original ZIP\n const zip = await JSZip.loadAsync(originalBuffer);\n\n // Update document.xml\n zip.file('word/document.xml', newDocumentXml, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n\n // Generate new DOCX\n return zip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n}\n\n/**\n * Update a specific XML file in a DOCX buffer\n *\n * @param originalBuffer - Original DOCX as ArrayBuffer\n * @param path - Path within the ZIP (e.g., \"word/styles.xml\")\n * @param content - New XML content\n * @param options - Optional repack options\n * @returns Promise resolving to DOCX as ArrayBuffer\n */\nexport async function updateXmlFile(\n originalBuffer: ArrayBuffer,\n path: string,\n content: string,\n options: RepackOptions = {}\n): Promise<ArrayBuffer> {\n const { compressionLevel = 6 } = options;\n\n const zip = await JSZip.loadAsync(originalBuffer);\n\n zip.file(path, content, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n\n return zip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n}\n\n/**\n * Update multiple files in a DOCX buffer\n *\n * @param originalBuffer - Original DOCX as ArrayBuffer\n * @param updates - Map of path -> content for files to update\n * @param options - Optional repack options\n * @returns Promise resolving to DOCX as ArrayBuffer\n */\nexport async function updateMultipleFiles(\n originalBuffer: ArrayBuffer,\n updates: Map<string, string | ArrayBuffer>,\n options: RepackOptions = {}\n): Promise<ArrayBuffer> {\n const { compressionLevel = 6 } = options;\n\n const zip = await JSZip.loadAsync(originalBuffer);\n\n for (const [path, content] of updates) {\n zip.file(path, content, {\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n }\n\n return zip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: compressionLevel },\n });\n}\n\n// ============================================================================\n// RELATIONSHIP MANAGEMENT\n// ============================================================================\n\n/**\n * Add a new relationship to document.xml.rels\n *\n * @param originalBuffer - Original DOCX as ArrayBuffer\n * @param relationship - New relationship to add\n * @returns Promise resolving to { buffer: ArrayBuffer, rId: string }\n */\nexport async function addRelationship(\n originalBuffer: ArrayBuffer,\n relationship: {\n type: string;\n target: string;\n targetMode?: 'External' | 'Internal';\n }\n): Promise<{ buffer: ArrayBuffer; rId: string }> {\n const zip = await JSZip.loadAsync(originalBuffer);\n\n // Read existing relationships\n const relsPath = 'word/_rels/document.xml.rels';\n const relsFile = zip.file(relsPath);\n\n if (!relsFile) {\n throw new Error('document.xml.rels not found in DOCX');\n }\n\n const relsXml = await relsFile.async('text');\n\n // Find highest existing rId\n const rIdMatches = relsXml.matchAll(/Id=\"rId(\\d+)\"/g);\n let maxId = 0;\n for (const match of rIdMatches) {\n const id = parseInt(match[1], 10);\n if (id > maxId) maxId = id;\n }\n\n // Generate new rId\n const newRId = `rId${maxId + 1}`;\n\n // Build new relationship element\n const targetModeAttr = relationship.targetMode === 'External' ? ' TargetMode=\"External\"' : '';\n\n const newRelElement = `<Relationship Id=\"${newRId}\" Type=\"${relationship.type}\" Target=\"${escapeXmlAttr(relationship.target)}\"${targetModeAttr}/>`;\n\n // Insert before closing tag\n const updatedRelsXml = relsXml.replace('</Relationships>', `${newRelElement}</Relationships>`);\n\n // Update the ZIP\n zip.file(relsPath, updatedRelsXml);\n\n const buffer = await zip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n });\n\n return { buffer, rId: newRId };\n}\n\n/**\n * Add a media file to the DOCX\n *\n * @param originalBuffer - Original DOCX as ArrayBuffer\n * @param filename - Filename for the media (e.g., \"image1.png\")\n * @param data - Binary data for the media file\n * @param mimeType - MIME type (e.g., \"image/png\")\n * @returns Promise resolving to { buffer: ArrayBuffer, rId: string, path: string }\n */\nexport async function addMedia(\n originalBuffer: ArrayBuffer,\n filename: string,\n data: ArrayBuffer,\n mimeType: string\n): Promise<{ buffer: ArrayBuffer; rId: string; path: string }> {\n const zip = await JSZip.loadAsync(originalBuffer);\n\n // Determine media path\n const mediaPath = `word/media/${filename}`;\n\n // Add media file\n zip.file(mediaPath, data);\n\n // Add relationship\n const relResult = await addRelationship(await zip.generateAsync({ type: 'arraybuffer' }), {\n type: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/image',\n target: `media/${filename}`,\n });\n\n // Update content types if needed\n const contentTypesFile = zip.file('[Content_Types].xml');\n if (contentTypesFile) {\n const contentTypesXml = await contentTypesFile.async('text');\n const extension = filename.split('.').pop()?.toLowerCase() || '';\n\n // Check if extension is already registered\n const hasExtension = contentTypesXml.includes(`Extension=\"${extension}\"`);\n\n if (!hasExtension && extension) {\n // Add content type for this extension\n const contentType = getContentTypeForExtension(extension, mimeType);\n const extensionElement = `<Default Extension=\"${extension}\" ContentType=\"${contentType}\"/>`;\n\n // Insert after other defaults\n const updatedContentTypes = contentTypesXml.replace(\n '</Types>',\n `${extensionElement}</Types>`\n );\n\n const finalZip = await JSZip.loadAsync(relResult.buffer);\n finalZip.file('[Content_Types].xml', updatedContentTypes);\n\n return {\n buffer: await finalZip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n }),\n rId: relResult.rId,\n path: mediaPath,\n };\n }\n }\n\n return {\n buffer: relResult.buffer,\n rId: relResult.rId,\n path: mediaPath,\n };\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Update core properties XML with new modification date\n */\nfunction updateCoreProperties(\n corePropsXml: string,\n options: { updateModifiedDate?: boolean; modifiedBy?: string }\n): string {\n let result = corePropsXml;\n\n if (options.updateModifiedDate) {\n const now = new Date().toISOString();\n\n // Update dcterms:modified\n if (result.includes('<dcterms:modified')) {\n result = result.replace(\n /<dcterms:modified[^>]*>[^<]*<\\/dcterms:modified>/,\n `<dcterms:modified xsi:type=\"dcterms:W3CDTF\">${now}</dcterms:modified>`\n );\n } else {\n // Add modified date if not present\n result = result.replace(\n '</cp:coreProperties>',\n `<dcterms:modified xsi:type=\"dcterms:W3CDTF\">${now}</dcterms:modified></cp:coreProperties>`\n );\n }\n }\n\n if (options.modifiedBy) {\n // Update cp:lastModifiedBy\n if (result.includes('<cp:lastModifiedBy')) {\n result = result.replace(\n /<cp:lastModifiedBy>[^<]*<\\/cp:lastModifiedBy>/,\n `<cp:lastModifiedBy>${escapeXmlText(options.modifiedBy)}</cp:lastModifiedBy>`\n );\n } else {\n // Add lastModifiedBy if not present\n result = result.replace(\n '</cp:coreProperties>',\n `<cp:lastModifiedBy>${escapeXmlText(options.modifiedBy)}</cp:lastModifiedBy></cp:coreProperties>`\n );\n }\n }\n\n return result;\n}\n\n/**\n * Escape special XML characters in text content\n */\nfunction escapeXmlText(text: string): string {\n return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');\n}\n\n/**\n * Escape special XML characters in attribute values\n */\nfunction escapeXmlAttr(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n/**\n * Get content type for a file extension\n */\nfunction getContentTypeForExtension(extension: string, mimeType: string): string {\n // Use provided mime type or fall back to common types\n if (mimeType) return mimeType;\n\n const contentTypes: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n bmp: 'image/bmp',\n tif: 'image/tiff',\n tiff: 'image/tiff',\n svg: 'image/svg+xml',\n webp: 'image/webp',\n wmf: 'image/x-wmf',\n emf: 'image/x-emf',\n };\n\n return contentTypes[extension] || 'application/octet-stream';\n}\n\n// ============================================================================\n// VALIDATION\n// ============================================================================\n\n/**\n * Validate that a buffer is a valid DOCX file\n *\n * @param buffer - Buffer to validate\n * @returns Promise resolving to validation result\n */\nexport async function validateDocx(buffer: ArrayBuffer): Promise<{\n valid: boolean;\n errors: string[];\n warnings: string[];\n}> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n try {\n const zip = await JSZip.loadAsync(buffer);\n\n // Check for required files\n const requiredFiles = ['[Content_Types].xml', 'word/document.xml'];\n\n for (const file of requiredFiles) {\n if (!zip.file(file)) {\n errors.push(`Missing required file: ${file}`);\n }\n }\n\n // Check for recommended files\n const recommendedFiles = ['_rels/.rels', 'word/_rels/document.xml.rels', 'word/styles.xml'];\n\n for (const file of recommendedFiles) {\n if (!zip.file(file)) {\n warnings.push(`Missing recommended file: ${file}`);\n }\n }\n\n // Validate document.xml is valid XML\n const docFile = zip.file('word/document.xml');\n if (docFile) {\n const docXml = await docFile.async('text');\n\n // Basic XML validation\n if (!docXml.includes('<?xml')) {\n warnings.push('document.xml missing XML declaration');\n }\n\n if (!docXml.includes('<w:document')) {\n errors.push('document.xml missing w:document element');\n }\n\n if (!docXml.includes('<w:body>')) {\n errors.push('document.xml missing w:body element');\n }\n }\n\n // Validate Content_Types.xml\n const ctFile = zip.file('[Content_Types].xml');\n if (ctFile) {\n const ctXml = await ctFile.async('text');\n\n if (\n !ctXml.includes('word/document.xml') &&\n !ctXml.includes(\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'\n )\n ) {\n warnings.push('Content_Types.xml may be missing document.xml type declaration');\n }\n }\n } catch (error) {\n errors.push(\n `Failed to read as ZIP: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\n/**\n * Check if buffer looks like a DOCX file (quick check)\n *\n * @param buffer - Buffer to check\n * @returns true if buffer starts with ZIP signature\n */\nexport function isDocxBuffer(buffer: ArrayBuffer): boolean {\n if (buffer.byteLength < 4) return false;\n\n const view = new Uint8Array(buffer);\n\n // ZIP file signature: PK (0x50, 0x4B)\n return view[0] === 0x50 && view[1] === 0x4b;\n}\n\n// ============================================================================\n// CREATE NEW DOCX\n// ============================================================================\n\n/**\n * Create a new empty DOCX file\n *\n * @returns Promise resolving to minimal DOCX as ArrayBuffer\n */\nexport async function createEmptyDocx(): Promise<ArrayBuffer> {\n const zip = new JSZip();\n\n // Content Types\n zip.file(\n '[Content_Types].xml',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">\n <Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>\n <Default Extension=\"xml\" ContentType=\"application/xml\"/>\n <Override PartName=\"/word/document.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml\"/>\n <Override PartName=\"/word/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml\"/>\n <Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\"/>\n <Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\"/>\n</Types>`\n );\n\n // Package relationships\n zip.file(\n '_rels/.rels',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument\" Target=\"word/document.xml\"/>\n <Relationship Id=\"rId2\" Type=\"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties\" Target=\"docProps/core.xml\"/>\n <Relationship Id=\"rId3\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties\" Target=\"docProps/app.xml\"/>\n</Relationships>`\n );\n\n // Document relationships\n zip.file(\n 'word/_rels/document.xml.rels',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">\n <Relationship Id=\"rId1\" Type=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles\" Target=\"styles.xml\"/>\n</Relationships>`\n );\n\n // Document\n zip.file(\n 'word/document.xml',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<w:document xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\">\n <w:body>\n <w:p>\n <w:r>\n <w:t></w:t>\n </w:r>\n </w:p>\n <w:sectPr>\n <w:pgSz w:w=\"12240\" w:h=\"15840\"/>\n <w:pgMar w:top=\"1440\" w:right=\"1440\" w:bottom=\"1440\" w:left=\"1440\" w:header=\"720\" w:footer=\"720\" w:gutter=\"0\"/>\n </w:sectPr>\n </w:body>\n</w:document>`\n );\n\n // Minimal styles\n zip.file(\n 'word/styles.xml',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<w:styles xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\">\n <w:docDefaults>\n <w:rPrDefault>\n <w:rPr>\n <w:rFonts w:ascii=\"Calibri\" w:hAnsi=\"Calibri\"/>\n <w:sz w:val=\"22\"/>\n </w:rPr>\n </w:rPrDefault>\n <w:pPrDefault>\n <w:pPr>\n <w:spacing w:after=\"200\" w:line=\"276\" w:lineRule=\"auto\"/>\n </w:pPr>\n </w:pPrDefault>\n </w:docDefaults>\n <w:style w:type=\"paragraph\" w:default=\"1\" w:styleId=\"Normal\">\n <w:name w:val=\"Normal\"/>\n </w:style>\n</w:styles>`\n );\n\n // Core properties\n const now = new Date().toISOString();\n zip.file(\n 'docProps/core.xml',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<cp:coreProperties xmlns:cp=\"http://schemas.openxmlformats.org/package/2006/metadata/core-properties\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:dcterms=\"http://purl.org/dc/terms/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n <dc:creator>EigenPal DOCX Editor</dc:creator>\n <dcterms:created xsi:type=\"dcterms:W3CDTF\">${now}</dcterms:created>\n <dcterms:modified xsi:type=\"dcterms:W3CDTF\">${now}</dcterms:modified>\n</cp:coreProperties>`\n );\n\n // App properties\n zip.file(\n 'docProps/app.xml',\n `<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<Properties xmlns=\"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties\">\n <Application>EigenPal DOCX Editor</Application>\n <AppVersion>1.0.0</AppVersion>\n</Properties>`\n );\n\n return zip.generateAsync({\n type: 'arraybuffer',\n compression: 'DEFLATE',\n compressionOptions: { level: 6 },\n });\n}\n\n/**\n * Create a new DOCX from a Document (without requiring original buffer)\n *\n * @param doc - Document to serialize\n * @returns Promise resolving to DOCX as ArrayBuffer\n */\nexport async function createDocx(doc: Document): Promise<ArrayBuffer> {\n // Start with an empty DOCX\n const emptyBuffer = await createEmptyDocx();\n\n // Add document as original buffer\n const docWithBuffer: Document = {\n ...doc,\n originalBuffer: emptyBuffer,\n };\n\n // Repack with the document content\n return repackDocx(docWithBuffer);\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport default repackDocx;\n","/**\n * Run Serializer - Serialize runs to OOXML XML\n *\n * Converts Run objects back to <w:r> XML format for DOCX files.\n * Handles all formatting properties and content types.\n *\n * OOXML Reference:\n * - Run: w:r\n * - Run properties: w:rPr\n * - Text content: w:t\n */\n\nimport type {\n Run,\n RunContent,\n TextContent,\n TabContent,\n BreakContent,\n SymbolContent,\n NoteReferenceContent,\n FieldCharContent,\n InstrTextContent,\n SoftHyphenContent,\n NoBreakHyphenContent,\n DrawingContent,\n ShapeContent,\n TextFormatting,\n ColorValue,\n ShadingProperties,\n} from '../../types/document';\n\n// ============================================================================\n// XML ESCAPING\n// ============================================================================\n\n/**\n * Escape special XML characters\n */\nfunction escapeXml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n// ============================================================================\n// COLOR SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a color element (w:color)\n */\nfunction serializeColorElement(color: ColorValue | undefined): string {\n if (!color) return '';\n\n const attrs: string[] = [];\n\n if (color.auto) {\n attrs.push('w:val=\"auto\"');\n } else if (color.rgb) {\n attrs.push(`w:val=\"${color.rgb}\"`);\n }\n\n if (color.themeColor) {\n attrs.push(`w:themeColor=\"${color.themeColor}\"`);\n }\n\n if (color.themeTint) {\n attrs.push(`w:themeTint=\"${color.themeTint}\"`);\n }\n\n if (color.themeShade) {\n attrs.push(`w:themeShade=\"${color.themeShade}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:color ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// SHADING SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize shading properties (w:shd)\n */\nfunction serializeShading(shading: ShadingProperties | undefined): string {\n if (!shading) return '';\n\n const attrs: string[] = [];\n\n // Pattern/val\n if (shading.pattern) {\n attrs.push(`w:val=\"${shading.pattern}\"`);\n } else {\n attrs.push('w:val=\"clear\"');\n }\n\n // Color (pattern color)\n if (shading.color?.rgb) {\n attrs.push(`w:color=\"${shading.color.rgb}\"`);\n } else if (shading.color?.auto) {\n attrs.push('w:color=\"auto\"');\n }\n\n // Fill (background color)\n if (shading.fill?.rgb) {\n attrs.push(`w:fill=\"${shading.fill.rgb}\"`);\n } else if (shading.fill?.auto) {\n attrs.push('w:fill=\"auto\"');\n }\n\n // Theme fill\n if (shading.fill?.themeColor) {\n attrs.push(`w:themeFill=\"${shading.fill.themeColor}\"`);\n }\n\n if (shading.fill?.themeTint) {\n attrs.push(`w:themeFillTint=\"${shading.fill.themeTint}\"`);\n }\n\n if (shading.fill?.themeShade) {\n attrs.push(`w:themeFillShade=\"${shading.fill.themeShade}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:shd ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// TEXT FORMATTING SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize text formatting properties to w:rPr XML\n */\nexport function serializeTextFormatting(formatting: TextFormatting | undefined): string {\n if (!formatting) return '';\n\n const parts: string[] = [];\n\n // Style reference (must be first)\n if (formatting.styleId) {\n parts.push(`<w:rStyle w:val=\"${escapeXml(formatting.styleId)}\"/>`);\n }\n\n // Font family (w:rFonts)\n if (formatting.fontFamily) {\n const fontAttrs: string[] = [];\n if (formatting.fontFamily.ascii) {\n fontAttrs.push(`w:ascii=\"${escapeXml(formatting.fontFamily.ascii)}\"`);\n }\n if (formatting.fontFamily.hAnsi) {\n fontAttrs.push(`w:hAnsi=\"${escapeXml(formatting.fontFamily.hAnsi)}\"`);\n }\n if (formatting.fontFamily.eastAsia) {\n fontAttrs.push(`w:eastAsia=\"${escapeXml(formatting.fontFamily.eastAsia)}\"`);\n }\n if (formatting.fontFamily.cs) {\n fontAttrs.push(`w:cs=\"${escapeXml(formatting.fontFamily.cs)}\"`);\n }\n if (formatting.fontFamily.asciiTheme) {\n fontAttrs.push(`w:asciiTheme=\"${formatting.fontFamily.asciiTheme}\"`);\n }\n if (formatting.fontFamily.hAnsiTheme) {\n fontAttrs.push(`w:hAnsiTheme=\"${formatting.fontFamily.hAnsiTheme}\"`);\n }\n if (formatting.fontFamily.eastAsiaTheme) {\n fontAttrs.push(`w:eastAsiaTheme=\"${formatting.fontFamily.eastAsiaTheme}\"`);\n }\n if (formatting.fontFamily.csTheme) {\n fontAttrs.push(`w:csTheme=\"${formatting.fontFamily.csTheme}\"`);\n }\n if (fontAttrs.length > 0) {\n parts.push(`<w:rFonts ${fontAttrs.join(' ')}/>`);\n }\n }\n\n // Bold\n if (formatting.bold === true) {\n parts.push('<w:b/>');\n } else if (formatting.bold === false) {\n parts.push('<w:b w:val=\"0\"/>');\n }\n\n if (formatting.boldCs === true) {\n parts.push('<w:bCs/>');\n } else if (formatting.boldCs === false) {\n parts.push('<w:bCs w:val=\"0\"/>');\n }\n\n // Italic\n if (formatting.italic === true) {\n parts.push('<w:i/>');\n } else if (formatting.italic === false) {\n parts.push('<w:i w:val=\"0\"/>');\n }\n\n if (formatting.italicCs === true) {\n parts.push('<w:iCs/>');\n } else if (formatting.italicCs === false) {\n parts.push('<w:iCs w:val=\"0\"/>');\n }\n\n // Caps\n if (formatting.allCaps) {\n parts.push('<w:caps/>');\n }\n\n if (formatting.smallCaps) {\n parts.push('<w:smallCaps/>');\n }\n\n // Strike\n if (formatting.strike) {\n parts.push('<w:strike/>');\n }\n\n if (formatting.doubleStrike) {\n parts.push('<w:dstrike/>');\n }\n\n // Outline\n if (formatting.outline) {\n parts.push('<w:outline/>');\n }\n\n // Shadow\n if (formatting.shadow) {\n parts.push('<w:shadow/>');\n }\n\n // Emboss\n if (formatting.emboss) {\n parts.push('<w:emboss/>');\n }\n\n // Imprint\n if (formatting.imprint) {\n parts.push('<w:imprint/>');\n }\n\n // Hidden\n if (formatting.hidden) {\n parts.push('<w:vanish/>');\n }\n\n // Color\n const colorXml = serializeColorElement(formatting.color);\n if (colorXml) {\n parts.push(colorXml);\n }\n\n // Spacing\n if (formatting.spacing !== undefined) {\n parts.push(`<w:spacing w:val=\"${formatting.spacing}\"/>`);\n }\n\n // Scale (w:w)\n if (formatting.scale !== undefined) {\n parts.push(`<w:w w:val=\"${formatting.scale}\"/>`);\n }\n\n // Kerning\n if (formatting.kerning !== undefined) {\n parts.push(`<w:kern w:val=\"${formatting.kerning}\"/>`);\n }\n\n // Position\n if (formatting.position !== undefined) {\n parts.push(`<w:position w:val=\"${formatting.position}\"/>`);\n }\n\n // Font size\n if (formatting.fontSize !== undefined) {\n parts.push(`<w:sz w:val=\"${formatting.fontSize}\"/>`);\n }\n\n if (formatting.fontSizeCs !== undefined) {\n parts.push(`<w:szCs w:val=\"${formatting.fontSizeCs}\"/>`);\n }\n\n // Highlight\n if (formatting.highlight && formatting.highlight !== 'none') {\n parts.push(`<w:highlight w:val=\"${formatting.highlight}\"/>`);\n }\n\n // Underline\n if (formatting.underline) {\n const uAttrs: string[] = [`w:val=\"${formatting.underline.style}\"`];\n if (formatting.underline.color) {\n if (formatting.underline.color.rgb) {\n uAttrs.push(`w:color=\"${formatting.underline.color.rgb}\"`);\n }\n if (formatting.underline.color.themeColor) {\n uAttrs.push(`w:themeColor=\"${formatting.underline.color.themeColor}\"`);\n }\n }\n parts.push(`<w:u ${uAttrs.join(' ')}/>`);\n }\n\n // Effect\n if (formatting.effect && formatting.effect !== 'none') {\n parts.push(`<w:effect w:val=\"${formatting.effect}\"/>`);\n }\n\n // Emphasis mark\n if (formatting.emphasisMark && formatting.emphasisMark !== 'none') {\n parts.push(`<w:em w:val=\"${formatting.emphasisMark}\"/>`);\n }\n\n // Shading\n const shadingXml = serializeShading(formatting.shading);\n if (shadingXml) {\n parts.push(shadingXml);\n }\n\n // Vertical alignment\n if (formatting.vertAlign && formatting.vertAlign !== 'baseline') {\n parts.push(`<w:vertAlign w:val=\"${formatting.vertAlign}\"/>`);\n }\n\n // RTL and CS\n if (formatting.rtl) {\n parts.push('<w:rtl/>');\n }\n\n if (formatting.cs) {\n parts.push('<w:cs/>');\n }\n\n if (parts.length === 0) return '';\n\n return `<w:rPr>${parts.join('')}</w:rPr>`;\n}\n\n// ============================================================================\n// RUN CONTENT SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize text content (w:t)\n */\nfunction serializeTextContent(content: TextContent): string {\n const needsPreserve =\n content.preserveSpace ||\n content.text.startsWith(' ') ||\n content.text.endsWith(' ') ||\n content.text.includes(' ');\n\n const spaceAttr = needsPreserve ? ' xml:space=\"preserve\"' : '';\n\n return `<w:t${spaceAttr}>${escapeXml(content.text)}</w:t>`;\n}\n\n/**\n * Serialize tab content (w:tab)\n */\nfunction serializeTabContent(_content: TabContent): string {\n return '<w:tab/>';\n}\n\n/**\n * Serialize break content (w:br)\n */\nfunction serializeBreakContent(content: BreakContent): string {\n const attrs: string[] = [];\n\n if (content.breakType === 'page') {\n attrs.push('w:type=\"page\"');\n } else if (content.breakType === 'column') {\n attrs.push('w:type=\"column\"');\n } else if (content.breakType === 'textWrapping') {\n attrs.push('w:type=\"textWrapping\"');\n if (content.clear && content.clear !== 'none') {\n attrs.push(`w:clear=\"${content.clear}\"`);\n }\n }\n\n if (attrs.length === 0) {\n return '<w:br/>';\n }\n\n return `<w:br ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize symbol content (w:sym)\n */\nfunction serializeSymbolContent(content: SymbolContent): string {\n return `<w:sym w:font=\"${escapeXml(content.font)}\" w:char=\"${escapeXml(content.char)}\"/>`;\n}\n\n/**\n * Serialize footnote/endnote reference\n */\nfunction serializeNoteReference(content: NoteReferenceContent): string {\n if (content.type === 'footnoteRef') {\n return `<w:footnoteReference w:id=\"${content.id}\"/>`;\n } else {\n return `<w:endnoteReference w:id=\"${content.id}\"/>`;\n }\n}\n\n/**\n * Serialize field character (w:fldChar)\n */\nfunction serializeFieldChar(content: FieldCharContent): string {\n const attrs: string[] = [`w:fldCharType=\"${content.charType}\"`];\n\n if (content.fldLock) {\n attrs.push('w:fldLock=\"true\"');\n }\n\n if (content.dirty) {\n attrs.push('w:dirty=\"true\"');\n }\n\n return `<w:fldChar ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize field instruction text (w:instrText)\n */\nfunction serializeInstrText(content: InstrTextContent): string {\n const needsPreserve =\n content.text.startsWith(' ') || content.text.endsWith(' ') || content.text.includes(' ');\n\n const spaceAttr = needsPreserve ? ' xml:space=\"preserve\"' : '';\n\n return `<w:instrText${spaceAttr}>${escapeXml(content.text)}</w:instrText>`;\n}\n\n/**\n * Serialize soft hyphen (w:softHyphen)\n */\nfunction serializeSoftHyphen(_content: SoftHyphenContent): string {\n return '<w:softHyphen/>';\n}\n\n/**\n * Serialize non-breaking hyphen (w:noBreakHyphen)\n */\nfunction serializeNoBreakHyphen(_content: NoBreakHyphenContent): string {\n return '<w:noBreakHyphen/>';\n}\n\n/**\n * Serialize drawing/image content (w:drawing)\n * Note: Full image serialization requires additional work on drawing XML\n * This provides a placeholder structure\n */\nfunction serializeDrawingContent(content: DrawingContent): string {\n // TODO: Implement full drawing serialization with inline/anchor, extent, docPr, etc.\n // For now, return a comment placeholder indicating where image would go\n if (content.image.rId) {\n return `<!-- Drawing with rId=\"${content.image.rId}\" -->`;\n }\n return '<!-- Drawing placeholder -->';\n}\n\n/**\n * Serialize shape content\n * Note: Full shape serialization requires additional work\n */\nfunction serializeShapeContent(content: ShapeContent): string {\n // TODO: Implement full shape serialization\n return `<!-- Shape: ${content.shape.shapeType || 'unknown'} -->`;\n}\n\n/**\n * Serialize a single run content item\n */\nfunction serializeRunContent(content: RunContent): string {\n switch (content.type) {\n case 'text':\n return serializeTextContent(content);\n case 'tab':\n return serializeTabContent(content);\n case 'break':\n return serializeBreakContent(content);\n case 'symbol':\n return serializeSymbolContent(content);\n case 'footnoteRef':\n case 'endnoteRef':\n return serializeNoteReference(content);\n case 'fieldChar':\n return serializeFieldChar(content);\n case 'instrText':\n return serializeInstrText(content);\n case 'softHyphen':\n return serializeSoftHyphen(content);\n case 'noBreakHyphen':\n return serializeNoBreakHyphen(content);\n case 'drawing':\n return serializeDrawingContent(content);\n case 'shape':\n return serializeShapeContent(content);\n default:\n return '';\n }\n}\n\n// ============================================================================\n// MAIN SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a run to OOXML XML (w:r)\n *\n * @param run - The run to serialize\n * @returns XML string for the run\n */\nexport function serializeRun(run: Run): string {\n const parts: string[] = [];\n\n // Add run properties if present\n const rPrXml = serializeTextFormatting(run.formatting);\n if (rPrXml) {\n parts.push(rPrXml);\n }\n\n // Add run content\n for (const content of run.content) {\n const contentXml = serializeRunContent(content);\n if (contentXml) {\n parts.push(contentXml);\n }\n }\n\n return `<w:r>${parts.join('')}</w:r>`;\n}\n\n/**\n * Serialize multiple runs to OOXML XML\n *\n * @param runs - The runs to serialize\n * @returns XML string for all runs\n */\nexport function serializeRuns(runs: Run[]): string {\n return runs.map(serializeRun).join('');\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Check if a run has any content\n */\nexport function hasRunContent(run: Run): boolean {\n return run.content.length > 0;\n}\n\n/**\n * Check if a run has formatting\n */\nexport function hasRunFormatting(run: Run): boolean {\n return run.formatting !== undefined && Object.keys(run.formatting).length > 0;\n}\n\n/**\n * Get plain text from a run (for comparison/debugging)\n */\nexport function getRunPlainText(run: Run): string {\n return run.content\n .filter((c): c is TextContent => c.type === 'text')\n .map((c) => c.text)\n .join('');\n}\n\n/**\n * Create an empty run\n */\nexport function createEmptyRun(): Run {\n return {\n type: 'run',\n content: [],\n };\n}\n\n/**\n * Create a text run\n */\nexport function createTextRun(text: string, formatting?: TextFormatting): Run {\n return {\n type: 'run',\n formatting,\n content: [{ type: 'text', text }],\n };\n}\n\n/**\n * Create a break run\n */\nexport function createBreakRun(\n breakType?: 'page' | 'column' | 'textWrapping',\n formatting?: TextFormatting\n): Run {\n return {\n type: 'run',\n formatting,\n content: [{ type: 'break', breakType }],\n };\n}\n\n/**\n * Create a tab run\n */\nexport function createTabRun(formatting?: TextFormatting): Run {\n return {\n type: 'run',\n formatting,\n content: [{ type: 'tab' }],\n };\n}\n\nexport default serializeRun;\n","/**\n * Paragraph Serializer - Serialize paragraphs to OOXML XML\n *\n * Converts Paragraph objects back to <w:p> XML format for DOCX files.\n * Handles all paragraph properties and child content (runs, hyperlinks, fields, bookmarks).\n *\n * OOXML Reference:\n * - Paragraph: w:p\n * - Paragraph properties: w:pPr\n * - Runs, hyperlinks, bookmarks, fields as child elements\n */\n\nimport type {\n Paragraph,\n ParagraphContent,\n ParagraphFormatting,\n Hyperlink,\n BookmarkStart,\n BookmarkEnd,\n SimpleField,\n ComplexField,\n TabStop,\n BorderSpec,\n ShadingProperties,\n TextFormatting,\n} from '../../types/document';\n\nimport { serializeRun, serializeTextFormatting } from './runSerializer';\n\n// ============================================================================\n// XML ESCAPING\n// ============================================================================\n\n/**\n * Escape special XML characters\n */\nfunction escapeXml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n// ============================================================================\n// BORDER SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a single border element\n */\nfunction serializeBorder(border: BorderSpec | undefined, elementName: string): string {\n if (!border || border.style === 'none' || border.style === 'nil') {\n return '';\n }\n\n const attrs: string[] = [`w:val=\"${border.style}\"`];\n\n if (border.size !== undefined) {\n attrs.push(`w:sz=\"${border.size}\"`);\n }\n\n if (border.space !== undefined) {\n attrs.push(`w:space=\"${border.space}\"`);\n }\n\n // Color\n if (border.color) {\n if (border.color.auto) {\n attrs.push('w:color=\"auto\"');\n } else if (border.color.rgb) {\n attrs.push(`w:color=\"${border.color.rgb}\"`);\n }\n\n if (border.color.themeColor) {\n attrs.push(`w:themeColor=\"${border.color.themeColor}\"`);\n }\n\n if (border.color.themeTint) {\n attrs.push(`w:themeTint=\"${border.color.themeTint}\"`);\n }\n\n if (border.color.themeShade) {\n attrs.push(`w:themeShade=\"${border.color.themeShade}\"`);\n }\n }\n\n if (border.shadow) {\n attrs.push('w:shadow=\"true\"');\n }\n\n if (border.frame) {\n attrs.push('w:frame=\"true\"');\n }\n\n return `<w:${elementName} ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize paragraph borders (w:pBdr)\n */\nfunction serializeParagraphBorders(borders: ParagraphFormatting['borders']): string {\n if (!borders) return '';\n\n const parts: string[] = [];\n\n if (borders.top) {\n const topXml = serializeBorder(borders.top, 'top');\n if (topXml) parts.push(topXml);\n }\n\n if (borders.left) {\n const leftXml = serializeBorder(borders.left, 'left');\n if (leftXml) parts.push(leftXml);\n }\n\n if (borders.bottom) {\n const bottomXml = serializeBorder(borders.bottom, 'bottom');\n if (bottomXml) parts.push(bottomXml);\n }\n\n if (borders.right) {\n const rightXml = serializeBorder(borders.right, 'right');\n if (rightXml) parts.push(rightXml);\n }\n\n if (borders.between) {\n const betweenXml = serializeBorder(borders.between, 'between');\n if (betweenXml) parts.push(betweenXml);\n }\n\n if (borders.bar) {\n const barXml = serializeBorder(borders.bar, 'bar');\n if (barXml) parts.push(barXml);\n }\n\n if (parts.length === 0) return '';\n\n return `<w:pBdr>${parts.join('')}</w:pBdr>`;\n}\n\n// ============================================================================\n// SHADING SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize shading properties (w:shd)\n */\nfunction serializeShading(shading: ShadingProperties | undefined): string {\n if (!shading) return '';\n\n const attrs: string[] = [];\n\n // Pattern/val\n if (shading.pattern) {\n attrs.push(`w:val=\"${shading.pattern}\"`);\n } else {\n attrs.push('w:val=\"clear\"');\n }\n\n // Color (pattern color)\n if (shading.color?.rgb) {\n attrs.push(`w:color=\"${shading.color.rgb}\"`);\n } else if (shading.color?.auto) {\n attrs.push('w:color=\"auto\"');\n }\n\n // Fill (background color)\n if (shading.fill?.rgb) {\n attrs.push(`w:fill=\"${shading.fill.rgb}\"`);\n } else if (shading.fill?.auto) {\n attrs.push('w:fill=\"auto\"');\n }\n\n // Theme fill\n if (shading.fill?.themeColor) {\n attrs.push(`w:themeFill=\"${shading.fill.themeColor}\"`);\n }\n\n if (shading.fill?.themeTint) {\n attrs.push(`w:themeFillTint=\"${shading.fill.themeTint}\"`);\n }\n\n if (shading.fill?.themeShade) {\n attrs.push(`w:themeFillShade=\"${shading.fill.themeShade}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:shd ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// TAB STOPS SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize tab stops (w:tabs)\n */\nfunction serializeTabStops(tabs: TabStop[] | undefined): string {\n if (!tabs || tabs.length === 0) return '';\n\n const tabElements = tabs.map((tab) => {\n const attrs: string[] = [`w:val=\"${tab.alignment}\"`, `w:pos=\"${tab.position}\"`];\n\n if (tab.leader && tab.leader !== 'none') {\n attrs.push(`w:leader=\"${tab.leader}\"`);\n }\n\n return `<w:tab ${attrs.join(' ')}/>`;\n });\n\n return `<w:tabs>${tabElements.join('')}</w:tabs>`;\n}\n\n// ============================================================================\n// SPACING SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize spacing properties (w:spacing)\n */\nfunction serializeSpacing(formatting: ParagraphFormatting): string {\n const attrs: string[] = [];\n\n if (formatting.spaceBefore !== undefined) {\n attrs.push(`w:before=\"${formatting.spaceBefore}\"`);\n }\n\n if (formatting.spaceAfter !== undefined) {\n attrs.push(`w:after=\"${formatting.spaceAfter}\"`);\n }\n\n if (formatting.lineSpacing !== undefined) {\n attrs.push(`w:line=\"${formatting.lineSpacing}\"`);\n }\n\n if (formatting.lineSpacingRule) {\n attrs.push(`w:lineRule=\"${formatting.lineSpacingRule}\"`);\n }\n\n if (formatting.beforeAutospacing) {\n attrs.push('w:beforeAutospacing=\"1\"');\n }\n\n if (formatting.afterAutospacing) {\n attrs.push('w:afterAutospacing=\"1\"');\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:spacing ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// INDENTATION SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize indentation properties (w:ind)\n */\nfunction serializeIndentation(formatting: ParagraphFormatting): string {\n const attrs: string[] = [];\n\n if (formatting.indentLeft !== undefined) {\n attrs.push(`w:left=\"${formatting.indentLeft}\"`);\n }\n\n if (formatting.indentRight !== undefined) {\n attrs.push(`w:right=\"${formatting.indentRight}\"`);\n }\n\n if (formatting.indentFirstLine !== undefined) {\n if (formatting.hangingIndent) {\n // Hanging indent is stored as positive value but uses w:hanging attribute\n attrs.push(`w:hanging=\"${Math.abs(formatting.indentFirstLine)}\"`);\n } else if (formatting.indentFirstLine !== 0) {\n attrs.push(`w:firstLine=\"${formatting.indentFirstLine}\"`);\n }\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:ind ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// NUMBERING SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize numbering properties (w:numPr)\n */\nfunction serializeNumbering(numPr: ParagraphFormatting['numPr']): string {\n if (!numPr) return '';\n\n const parts: string[] = [];\n\n if (numPr.ilvl !== undefined) {\n parts.push(`<w:ilvl w:val=\"${numPr.ilvl}\"/>`);\n }\n\n if (numPr.numId !== undefined) {\n parts.push(`<w:numId w:val=\"${numPr.numId}\"/>`);\n }\n\n if (parts.length === 0) return '';\n\n return `<w:numPr>${parts.join('')}</w:numPr>`;\n}\n\n// ============================================================================\n// FRAME PROPERTIES SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize frame properties (w:framePr)\n */\nfunction serializeFrameProperties(frame: ParagraphFormatting['frame']): string {\n if (!frame) return '';\n\n const attrs: string[] = [];\n\n if (frame.width !== undefined) {\n attrs.push(`w:w=\"${frame.width}\"`);\n }\n\n if (frame.height !== undefined) {\n attrs.push(`w:h=\"${frame.height}\"`);\n }\n\n if (frame.hAnchor) {\n attrs.push(`w:hAnchor=\"${frame.hAnchor}\"`);\n }\n\n if (frame.vAnchor) {\n attrs.push(`w:vAnchor=\"${frame.vAnchor}\"`);\n }\n\n if (frame.x !== undefined) {\n attrs.push(`w:x=\"${frame.x}\"`);\n }\n\n if (frame.y !== undefined) {\n attrs.push(`w:y=\"${frame.y}\"`);\n }\n\n if (frame.xAlign) {\n attrs.push(`w:xAlign=\"${frame.xAlign}\"`);\n }\n\n if (frame.yAlign) {\n attrs.push(`w:yAlign=\"${frame.yAlign}\"`);\n }\n\n if (frame.wrap) {\n attrs.push(`w:wrap=\"${frame.wrap}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:framePr ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// PARAGRAPH PROPERTIES SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize paragraph formatting properties to w:pPr XML\n */\nexport function serializeParagraphFormatting(formatting: ParagraphFormatting | undefined): string {\n if (!formatting) return '';\n\n const parts: string[] = [];\n\n // Style reference (must be first)\n if (formatting.styleId) {\n parts.push(`<w:pStyle w:val=\"${escapeXml(formatting.styleId)}\"/>`);\n }\n\n // Keep next/lines/widow\n if (formatting.keepNext) {\n parts.push('<w:keepNext/>');\n }\n\n if (formatting.keepLines) {\n parts.push('<w:keepLines/>');\n }\n\n if (formatting.pageBreakBefore) {\n parts.push('<w:pageBreakBefore/>');\n }\n\n // Frame properties\n const frameXml = serializeFrameProperties(formatting.frame);\n if (frameXml) {\n parts.push(frameXml);\n }\n\n // Widow control\n if (formatting.widowControl === false) {\n parts.push('<w:widowControl w:val=\"0\"/>');\n } else if (formatting.widowControl === true) {\n parts.push('<w:widowControl/>');\n }\n\n // Numbering\n const numPrXml = serializeNumbering(formatting.numPr);\n if (numPrXml) {\n parts.push(numPrXml);\n }\n\n // Paragraph borders\n const bordersXml = serializeParagraphBorders(formatting.borders);\n if (bordersXml) {\n parts.push(bordersXml);\n }\n\n // Shading\n const shadingXml = serializeShading(formatting.shading);\n if (shadingXml) {\n parts.push(shadingXml);\n }\n\n // Tabs\n const tabsXml = serializeTabStops(formatting.tabs);\n if (tabsXml) {\n parts.push(tabsXml);\n }\n\n // Suppress line numbers\n if (formatting.suppressLineNumbers) {\n parts.push('<w:suppressLineNumbers/>');\n }\n\n // Suppress auto hyphens\n if (formatting.suppressAutoHyphens) {\n parts.push('<w:suppressAutoHyphens/>');\n }\n\n // Spacing\n const spacingXml = serializeSpacing(formatting);\n if (spacingXml) {\n parts.push(spacingXml);\n }\n\n // Indentation\n const indXml = serializeIndentation(formatting);\n if (indXml) {\n parts.push(indXml);\n }\n\n // Text direction (bidi)\n if (formatting.bidi) {\n parts.push('<w:bidi/>');\n }\n\n // Justification\n if (formatting.alignment) {\n parts.push(`<w:jc w:val=\"${formatting.alignment}\"/>`);\n }\n\n // Outline level\n if (formatting.outlineLevel !== undefined) {\n parts.push(`<w:outlineLvl w:val=\"${formatting.outlineLevel}\"/>`);\n }\n\n // Run properties (default run formatting for paragraph)\n if (formatting.runProperties) {\n const rPrXml = serializeTextFormatting(formatting.runProperties);\n if (rPrXml) {\n parts.push(rPrXml);\n }\n }\n\n if (parts.length === 0) return '';\n\n return `<w:pPr>${parts.join('')}</w:pPr>`;\n}\n\n// ============================================================================\n// CONTENT SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a hyperlink (w:hyperlink)\n */\nfunction serializeHyperlink(hyperlink: Hyperlink): string {\n const attrs: string[] = [];\n\n if (hyperlink.rId) {\n attrs.push(`r:id=\"${hyperlink.rId}\"`);\n }\n\n if (hyperlink.anchor) {\n attrs.push(`w:anchor=\"${escapeXml(hyperlink.anchor)}\"`);\n }\n\n if (hyperlink.tooltip) {\n attrs.push(`w:tooltip=\"${escapeXml(hyperlink.tooltip)}\"`);\n }\n\n if (hyperlink.target) {\n attrs.push(`w:tgtFrame=\"${escapeXml(hyperlink.target)}\"`);\n }\n\n if (hyperlink.history === false) {\n attrs.push('w:history=\"0\"');\n }\n\n if (hyperlink.docLocation) {\n attrs.push(`w:docLocation=\"${escapeXml(hyperlink.docLocation)}\"`);\n }\n\n // Serialize children\n const childrenXml = hyperlink.children\n .map((child) => {\n if (child.type === 'run') {\n return serializeRun(child);\n } else if (child.type === 'bookmarkStart') {\n return serializeBookmarkStart(child);\n } else if (child.type === 'bookmarkEnd') {\n return serializeBookmarkEnd(child);\n }\n return '';\n })\n .join('');\n\n const attrsStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';\n return `<w:hyperlink${attrsStr}>${childrenXml}</w:hyperlink>`;\n}\n\n/**\n * Serialize bookmark start (w:bookmarkStart)\n */\nfunction serializeBookmarkStart(bookmark: BookmarkStart): string {\n const attrs: string[] = [`w:id=\"${bookmark.id}\"`, `w:name=\"${escapeXml(bookmark.name)}\"`];\n\n if (bookmark.colFirst !== undefined) {\n attrs.push(`w:colFirst=\"${bookmark.colFirst}\"`);\n }\n\n if (bookmark.colLast !== undefined) {\n attrs.push(`w:colLast=\"${bookmark.colLast}\"`);\n }\n\n return `<w:bookmarkStart ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize bookmark end (w:bookmarkEnd)\n */\nfunction serializeBookmarkEnd(bookmark: BookmarkEnd): string {\n return `<w:bookmarkEnd w:id=\"${bookmark.id}\"/>`;\n}\n\n/**\n * Serialize a simple field (w:fldSimple)\n */\nfunction serializeSimpleField(field: SimpleField): string {\n const attrs: string[] = [`w:instr=\"${escapeXml(field.instruction)}\"`];\n\n if (field.fldLock) {\n attrs.push('w:fldLock=\"true\"');\n }\n\n if (field.dirty) {\n attrs.push('w:dirty=\"true\"');\n }\n\n // Serialize content\n const contentXml = field.content\n .map((item) => {\n if (item.type === 'run') {\n return serializeRun(item);\n } else if (item.type === 'hyperlink') {\n return serializeHyperlink(item);\n }\n return '';\n })\n .join('');\n\n return `<w:fldSimple ${attrs.join(' ')}>${contentXml}</w:fldSimple>`;\n}\n\n/**\n * Serialize a complex field\n * Complex fields are represented by multiple runs with fldChar elements,\n * so we convert them back to that structure\n */\nfunction serializeComplexField(field: ComplexField): string {\n const parts: string[] = [];\n\n // Begin field character\n const beginAttrs: string[] = ['w:fldCharType=\"begin\"'];\n if (field.fldLock) {\n beginAttrs.push('w:fldLock=\"true\"');\n }\n if (field.dirty) {\n beginAttrs.push('w:dirty=\"true\"');\n }\n parts.push(`<w:r><w:fldChar ${beginAttrs.join(' ')}/></w:r>`);\n\n // Field code (instrText)\n if (field.fieldCode.length > 0) {\n parts.push(...field.fieldCode.map((run) => serializeRun(run)));\n } else {\n // Fallback: create instrText from instruction\n const needsPreserve =\n field.instruction.startsWith(' ') ||\n field.instruction.endsWith(' ') ||\n field.instruction.includes(' ');\n const spaceAttr = needsPreserve ? ' xml:space=\"preserve\"' : '';\n parts.push(`<w:r><w:instrText${spaceAttr}>${escapeXml(field.instruction)}</w:instrText></w:r>`);\n }\n\n // Separate field character\n parts.push('<w:r><w:fldChar w:fldCharType=\"separate\"/></w:r>');\n\n // Field result\n parts.push(...field.fieldResult.map((run) => serializeRun(run)));\n\n // End field character\n parts.push('<w:r><w:fldChar w:fldCharType=\"end\"/></w:r>');\n\n return parts.join('');\n}\n\n/**\n * Serialize a single paragraph content item\n */\nfunction serializeParagraphContent(content: ParagraphContent): string {\n switch (content.type) {\n case 'run':\n return serializeRun(content);\n case 'hyperlink':\n return serializeHyperlink(content);\n case 'bookmarkStart':\n return serializeBookmarkStart(content);\n case 'bookmarkEnd':\n return serializeBookmarkEnd(content);\n case 'simpleField':\n return serializeSimpleField(content);\n case 'complexField':\n return serializeComplexField(content);\n default:\n return '';\n }\n}\n\n// ============================================================================\n// MAIN SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a paragraph to OOXML XML (w:p)\n *\n * @param paragraph - The paragraph to serialize\n * @returns XML string for the paragraph\n */\nexport function serializeParagraph(paragraph: Paragraph): string {\n const parts: string[] = [];\n\n // Paragraph ID attributes\n const attrs: string[] = [];\n if (paragraph.paraId) {\n attrs.push(`w14:paraId=\"${paragraph.paraId}\"`);\n }\n if (paragraph.textId) {\n attrs.push(`w14:textId=\"${paragraph.textId}\"`);\n }\n const attrsStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';\n\n // Add paragraph properties if present\n const pPrXml = serializeParagraphFormatting(paragraph.formatting);\n if (pPrXml) {\n parts.push(pPrXml);\n }\n\n // Add paragraph content\n for (const content of paragraph.content) {\n const contentXml = serializeParagraphContent(content);\n if (contentXml) {\n parts.push(contentXml);\n }\n }\n\n return `<w:p${attrsStr}>${parts.join('')}</w:p>`;\n}\n\n/**\n * Serialize multiple paragraphs to OOXML XML\n *\n * @param paragraphs - The paragraphs to serialize\n * @returns XML string for all paragraphs\n */\nexport function serializeParagraphs(paragraphs: Paragraph[]): string {\n return paragraphs.map(serializeParagraph).join('');\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Check if a paragraph has any content\n */\nexport function hasParagraphContent(paragraph: Paragraph): boolean {\n return paragraph.content.length > 0;\n}\n\n/**\n * Check if a paragraph has formatting\n */\nexport function hasParagraphFormatting(paragraph: Paragraph): boolean {\n return paragraph.formatting !== undefined && Object.keys(paragraph.formatting).length > 0;\n}\n\n/**\n * Get plain text from a paragraph (for comparison/debugging)\n */\nexport function getParagraphPlainText(paragraph: Paragraph): string {\n const texts: string[] = [];\n\n for (const content of paragraph.content) {\n if (content.type === 'run') {\n for (const item of content.content) {\n if (item.type === 'text') {\n texts.push(item.text);\n } else if (item.type === 'tab') {\n texts.push('\\t');\n } else if (item.type === 'break') {\n texts.push('\\n');\n }\n }\n } else if (content.type === 'hyperlink') {\n for (const child of content.children) {\n if (child.type === 'run') {\n for (const item of child.content) {\n if (item.type === 'text') {\n texts.push(item.text);\n }\n }\n }\n }\n } else if (content.type === 'simpleField') {\n for (const item of content.content) {\n if (item.type === 'run') {\n for (const subItem of item.content) {\n if (subItem.type === 'text') {\n texts.push(subItem.text);\n }\n }\n }\n }\n } else if (content.type === 'complexField') {\n for (const run of content.fieldResult) {\n for (const item of run.content) {\n if (item.type === 'text') {\n texts.push(item.text);\n }\n }\n }\n }\n }\n\n return texts.join('');\n}\n\n/**\n * Create an empty paragraph\n */\nexport function createEmptyParagraph(formatting?: ParagraphFormatting): Paragraph {\n return {\n type: 'paragraph',\n formatting,\n content: [],\n };\n}\n\n/**\n * Create a paragraph with a single text run\n */\nexport function createTextParagraph(\n text: string,\n paragraphFormatting?: ParagraphFormatting,\n textFormatting?: TextFormatting\n): Paragraph {\n return {\n type: 'paragraph',\n formatting: paragraphFormatting,\n content: [\n {\n type: 'run',\n formatting: textFormatting,\n content: [{ type: 'text', text }],\n },\n ],\n };\n}\n\n/**\n * Check if paragraph is a list item\n */\nexport function isListParagraph(paragraph: Paragraph): boolean {\n return paragraph.formatting?.numPr !== undefined;\n}\n\n/**\n * Get list level of a paragraph (0-8, or -1 if not a list)\n */\nexport function getListLevel(paragraph: Paragraph): number {\n return paragraph.formatting?.numPr?.ilvl ?? -1;\n}\n\nexport default serializeParagraph;\n","/**\n * Table Serializer - Serialize tables to OOXML XML\n *\n * Converts Table objects back to <w:tbl> XML format for DOCX files.\n * Handles all table, row, and cell properties including merged cells.\n *\n * OOXML Reference:\n * - Table: w:tbl\n * - Table properties: w:tblPr\n * - Table grid: w:tblGrid\n * - Table row: w:tr\n * - Row properties: w:trPr\n * - Table cell: w:tc\n * - Cell properties: w:tcPr\n */\n\nimport type {\n Table,\n TableRow,\n TableCell,\n TableFormatting,\n TableRowFormatting,\n TableCellFormatting,\n TableMeasurement,\n TableBorders,\n TableLook,\n CellMargins,\n FloatingTableProperties,\n ConditionalFormatStyle,\n BorderSpec,\n ShadingProperties,\n Paragraph,\n} from '../../types/document';\n\nimport { serializeParagraph } from './paragraphSerializer';\n\n// ============================================================================\n// XML ESCAPING\n// ============================================================================\n\n/**\n * Escape special XML characters\n */\nfunction escapeXml(text: string): string {\n return text\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n}\n\n// ============================================================================\n// MEASUREMENT SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a table measurement (width, height)\n */\nfunction serializeMeasurement(\n measurement: TableMeasurement | undefined,\n elementName: string\n): string {\n if (!measurement) return '';\n\n const attrs: string[] = [`w:w=\"${measurement.value}\"`, `w:type=\"${measurement.type}\"`];\n\n return `<w:${elementName} ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// BORDER SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a single border element\n */\nfunction serializeBorder(border: BorderSpec | undefined, elementName: string): string {\n if (!border || border.style === 'none' || border.style === 'nil') {\n return '';\n }\n\n const attrs: string[] = [`w:val=\"${border.style}\"`];\n\n if (border.size !== undefined) {\n attrs.push(`w:sz=\"${border.size}\"`);\n }\n\n if (border.space !== undefined) {\n attrs.push(`w:space=\"${border.space}\"`);\n }\n\n // Color\n if (border.color) {\n if (border.color.auto) {\n attrs.push('w:color=\"auto\"');\n } else if (border.color.rgb) {\n attrs.push(`w:color=\"${border.color.rgb}\"`);\n }\n\n if (border.color.themeColor) {\n attrs.push(`w:themeColor=\"${border.color.themeColor}\"`);\n }\n\n if (border.color.themeTint) {\n attrs.push(`w:themeTint=\"${border.color.themeTint}\"`);\n }\n\n if (border.color.themeShade) {\n attrs.push(`w:themeShade=\"${border.color.themeShade}\"`);\n }\n }\n\n if (border.shadow) {\n attrs.push('w:shadow=\"true\"');\n }\n\n if (border.frame) {\n attrs.push('w:frame=\"true\"');\n }\n\n return `<w:${elementName} ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize table borders (w:tblBorders or w:tcBorders)\n */\nfunction serializeTableBorders(borders: TableBorders | undefined, elementName: string): string {\n if (!borders) return '';\n\n const parts: string[] = [];\n\n if (borders.top) {\n const topXml = serializeBorder(borders.top, 'top');\n if (topXml) parts.push(topXml);\n }\n\n if (borders.left) {\n const leftXml = serializeBorder(borders.left, 'left');\n if (leftXml) parts.push(leftXml);\n }\n\n if (borders.bottom) {\n const bottomXml = serializeBorder(borders.bottom, 'bottom');\n if (bottomXml) parts.push(bottomXml);\n }\n\n if (borders.right) {\n const rightXml = serializeBorder(borders.right, 'right');\n if (rightXml) parts.push(rightXml);\n }\n\n if (borders.insideH) {\n const insideHXml = serializeBorder(borders.insideH, 'insideH');\n if (insideHXml) parts.push(insideHXml);\n }\n\n if (borders.insideV) {\n const insideVXml = serializeBorder(borders.insideV, 'insideV');\n if (insideVXml) parts.push(insideVXml);\n }\n\n if (parts.length === 0) return '';\n\n return `<w:${elementName}>${parts.join('')}</w:${elementName}>`;\n}\n\n// ============================================================================\n// CELL MARGINS SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize cell margins (w:tblCellMar or w:tcMar)\n */\nfunction serializeCellMargins(margins: CellMargins | undefined, elementName: string): string {\n if (!margins) return '';\n\n const parts: string[] = [];\n\n if (margins.top) {\n parts.push(serializeMeasurement(margins.top, 'top'));\n }\n\n if (margins.left) {\n parts.push(serializeMeasurement(margins.left, 'left'));\n }\n\n if (margins.bottom) {\n parts.push(serializeMeasurement(margins.bottom, 'bottom'));\n }\n\n if (margins.right) {\n parts.push(serializeMeasurement(margins.right, 'right'));\n }\n\n if (parts.length === 0) return '';\n\n return `<w:${elementName}>${parts.join('')}</w:${elementName}>`;\n}\n\n// ============================================================================\n// SHADING SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize shading properties (w:shd)\n */\nfunction serializeShading(shading: ShadingProperties | undefined): string {\n if (!shading) return '';\n\n const attrs: string[] = [];\n\n // Pattern/val\n if (shading.pattern) {\n attrs.push(`w:val=\"${shading.pattern}\"`);\n } else {\n attrs.push('w:val=\"clear\"');\n }\n\n // Color (pattern color)\n if (shading.color?.rgb) {\n attrs.push(`w:color=\"${shading.color.rgb}\"`);\n } else if (shading.color?.auto) {\n attrs.push('w:color=\"auto\"');\n }\n\n // Fill (background color)\n if (shading.fill?.rgb) {\n attrs.push(`w:fill=\"${shading.fill.rgb}\"`);\n } else if (shading.fill?.auto) {\n attrs.push('w:fill=\"auto\"');\n }\n\n // Theme fill\n if (shading.fill?.themeColor) {\n attrs.push(`w:themeFill=\"${shading.fill.themeColor}\"`);\n }\n\n if (shading.fill?.themeTint) {\n attrs.push(`w:themeFillTint=\"${shading.fill.themeTint}\"`);\n }\n\n if (shading.fill?.themeShade) {\n attrs.push(`w:themeFillShade=\"${shading.fill.themeShade}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:shd ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// TABLE LOOK SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize table look flags (w:tblLook)\n */\nfunction serializeTableLook(look: TableLook | undefined): string {\n if (!look) return '';\n\n const attrs: string[] = [];\n\n if (look.firstRow) {\n attrs.push('w:firstRow=\"1\"');\n }\n\n if (look.lastRow) {\n attrs.push('w:lastRow=\"1\"');\n }\n\n if (look.firstColumn) {\n attrs.push('w:firstColumn=\"1\"');\n }\n\n if (look.lastColumn) {\n attrs.push('w:lastColumn=\"1\"');\n }\n\n if (look.noHBand) {\n attrs.push('w:noHBand=\"1\"');\n }\n\n if (look.noVBand) {\n attrs.push('w:noVBand=\"1\"');\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:tblLook ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// FLOATING TABLE PROPERTIES SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize floating table properties (w:tblpPr)\n */\nfunction serializeFloatingTableProperties(floating: FloatingTableProperties | undefined): string {\n if (!floating) return '';\n\n const attrs: string[] = [];\n\n if (floating.horzAnchor) {\n attrs.push(`w:horzAnchor=\"${floating.horzAnchor}\"`);\n }\n\n if (floating.vertAnchor) {\n attrs.push(`w:vertAnchor=\"${floating.vertAnchor}\"`);\n }\n\n if (floating.tblpX !== undefined) {\n attrs.push(`w:tblpX=\"${floating.tblpX}\"`);\n }\n\n if (floating.tblpXSpec) {\n attrs.push(`w:tblpXSpec=\"${floating.tblpXSpec}\"`);\n }\n\n if (floating.tblpY !== undefined) {\n attrs.push(`w:tblpY=\"${floating.tblpY}\"`);\n }\n\n if (floating.tblpYSpec) {\n attrs.push(`w:tblpYSpec=\"${floating.tblpYSpec}\"`);\n }\n\n if (floating.topFromText !== undefined) {\n attrs.push(`w:topFromText=\"${floating.topFromText}\"`);\n }\n\n if (floating.bottomFromText !== undefined) {\n attrs.push(`w:bottomFromText=\"${floating.bottomFromText}\"`);\n }\n\n if (floating.leftFromText !== undefined) {\n attrs.push(`w:leftFromText=\"${floating.leftFromText}\"`);\n }\n\n if (floating.rightFromText !== undefined) {\n attrs.push(`w:rightFromText=\"${floating.rightFromText}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:tblpPr ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// TABLE PROPERTIES SERIALIZATION (w:tblPr)\n// ============================================================================\n\n/**\n * Serialize table formatting properties (w:tblPr)\n */\nexport function serializeTableFormatting(formatting: TableFormatting | undefined): string {\n if (!formatting) return '';\n\n const parts: string[] = [];\n\n // Table style (must be first)\n if (formatting.styleId) {\n parts.push(`<w:tblStyle w:val=\"${escapeXml(formatting.styleId)}\"/>`);\n }\n\n // Floating table properties\n const floatingXml = serializeFloatingTableProperties(formatting.floating);\n if (floatingXml) {\n parts.push(floatingXml);\n }\n\n // Bidirectional\n if (formatting.bidi) {\n parts.push('<w:bidiVisual/>');\n }\n\n // Table width\n const widthXml = serializeMeasurement(formatting.width, 'tblW');\n if (widthXml) {\n parts.push(widthXml);\n }\n\n // Table justification\n if (formatting.justification) {\n parts.push(`<w:jc w:val=\"${formatting.justification}\"/>`);\n }\n\n // Cell spacing\n const cellSpacingXml = serializeMeasurement(formatting.cellSpacing, 'tblCellSpacing');\n if (cellSpacingXml) {\n parts.push(cellSpacingXml);\n }\n\n // Table indent\n const indentXml = serializeMeasurement(formatting.indent, 'tblInd');\n if (indentXml) {\n parts.push(indentXml);\n }\n\n // Table borders\n const bordersXml = serializeTableBorders(formatting.borders, 'tblBorders');\n if (bordersXml) {\n parts.push(bordersXml);\n }\n\n // Default cell margins\n const marginsXml = serializeCellMargins(formatting.cellMargins, 'tblCellMar');\n if (marginsXml) {\n parts.push(marginsXml);\n }\n\n // Table layout\n if (formatting.layout) {\n parts.push(`<w:tblLayout w:type=\"${formatting.layout}\"/>`);\n }\n\n // Shading\n const shadingXml = serializeShading(formatting.shading);\n if (shadingXml) {\n parts.push(shadingXml);\n }\n\n // Table look\n const lookXml = serializeTableLook(formatting.look);\n if (lookXml) {\n parts.push(lookXml);\n }\n\n // Overlap\n if (formatting.overlap) {\n parts.push(`<w:tblOverlap w:val=\"${formatting.overlap}\"/>`);\n }\n\n if (parts.length === 0) return '';\n\n return `<w:tblPr>${parts.join('')}</w:tblPr>`;\n}\n\n// ============================================================================\n// TABLE ROW PROPERTIES SERIALIZATION (w:trPr)\n// ============================================================================\n\n/**\n * Serialize table row formatting properties (w:trPr)\n */\nexport function serializeTableRowFormatting(formatting: TableRowFormatting | undefined): string {\n if (!formatting) return '';\n\n const parts: string[] = [];\n\n // Can't split\n if (formatting.cantSplit) {\n parts.push('<w:cantSplit/>');\n }\n\n // Header row\n if (formatting.header) {\n parts.push('<w:tblHeader/>');\n }\n\n // Row height\n if (formatting.height) {\n const attrs: string[] = [`w:val=\"${formatting.height.value}\"`];\n\n if (formatting.heightRule) {\n attrs.push(`w:hRule=\"${formatting.heightRule}\"`);\n }\n\n parts.push(`<w:trHeight ${attrs.join(' ')}/>`);\n }\n\n // Row justification\n if (formatting.justification) {\n parts.push(`<w:jc w:val=\"${formatting.justification}\"/>`);\n }\n\n // Hidden\n if (formatting.hidden) {\n parts.push('<w:hidden/>');\n }\n\n if (parts.length === 0) return '';\n\n return `<w:trPr>${parts.join('')}</w:trPr>`;\n}\n\n// ============================================================================\n// CONDITIONAL FORMAT STYLE SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize conditional format style (w:cnfStyle)\n */\nfunction serializeConditionalFormatStyle(style: ConditionalFormatStyle | undefined): string {\n if (!style) return '';\n\n // Build the 12-character binary string\n const bits = [\n style.firstRow ? '1' : '0',\n style.lastRow ? '1' : '0',\n style.firstColumn ? '1' : '0',\n style.lastColumn ? '1' : '0',\n style.oddVBand ? '1' : '0',\n style.evenVBand ? '1' : '0',\n style.oddHBand ? '1' : '0',\n style.evenHBand ? '1' : '0',\n style.nwCell ? '1' : '0',\n style.neCell ? '1' : '0',\n style.swCell ? '1' : '0',\n style.seCell ? '1' : '0',\n ];\n\n const val = bits.join('');\n\n // Only serialize if any bits are set\n if (val === '000000000000') return '';\n\n return `<w:cnfStyle w:val=\"${val}\"/>`;\n}\n\n// ============================================================================\n// TABLE CELL PROPERTIES SERIALIZATION (w:tcPr)\n// ============================================================================\n\n/**\n * Serialize table cell formatting properties (w:tcPr)\n */\nexport function serializeTableCellFormatting(formatting: TableCellFormatting | undefined): string {\n if (!formatting) return '';\n\n const parts: string[] = [];\n\n // Conditional format style\n const cnfStyleXml = serializeConditionalFormatStyle(formatting.conditionalFormat);\n if (cnfStyleXml) {\n parts.push(cnfStyleXml);\n }\n\n // Cell width\n const widthXml = serializeMeasurement(formatting.width, 'tcW');\n if (widthXml) {\n parts.push(widthXml);\n }\n\n // Grid span (horizontal merge)\n if (formatting.gridSpan && formatting.gridSpan > 1) {\n parts.push(`<w:gridSpan w:val=\"${formatting.gridSpan}\"/>`);\n }\n\n // Vertical merge\n if (formatting.vMerge) {\n if (formatting.vMerge === 'restart') {\n parts.push('<w:vMerge w:val=\"restart\"/>');\n } else {\n // continue is the default when w:vMerge has no value\n parts.push('<w:vMerge/>');\n }\n }\n\n // Cell borders\n const bordersXml = serializeTableBorders(formatting.borders, 'tcBorders');\n if (bordersXml) {\n parts.push(bordersXml);\n }\n\n // Shading\n const shadingXml = serializeShading(formatting.shading);\n if (shadingXml) {\n parts.push(shadingXml);\n }\n\n // No wrap\n if (formatting.noWrap) {\n parts.push('<w:noWrap/>');\n }\n\n // Cell margins\n const marginsXml = serializeCellMargins(formatting.margins, 'tcMar');\n if (marginsXml) {\n parts.push(marginsXml);\n }\n\n // Text direction\n if (formatting.textDirection) {\n parts.push(`<w:textDirection w:val=\"${formatting.textDirection}\"/>`);\n }\n\n // Fit text\n if (formatting.fitText) {\n parts.push('<w:tcFitText/>');\n }\n\n // Vertical alignment\n if (formatting.verticalAlign) {\n parts.push(`<w:vAlign w:val=\"${formatting.verticalAlign}\"/>`);\n }\n\n // Hide mark\n if (formatting.hideMark) {\n parts.push('<w:hideMark/>');\n }\n\n if (parts.length === 0) return '';\n\n return `<w:tcPr>${parts.join('')}</w:tcPr>`;\n}\n\n// ============================================================================\n// TABLE GRID SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize table grid (w:tblGrid)\n */\nfunction serializeTableGrid(columnWidths: number[] | undefined): string {\n if (!columnWidths || columnWidths.length === 0) return '';\n\n const cols = columnWidths.map((w) => `<w:gridCol w:w=\"${w}\"/>`);\n\n return `<w:tblGrid>${cols.join('')}</w:tblGrid>`;\n}\n\n// ============================================================================\n// CELL CONTENT SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize cell content (paragraphs, nested tables)\n */\nfunction serializeCellContent(content: (Paragraph | Table)[]): string {\n const parts: string[] = [];\n\n for (const item of content) {\n if (item.type === 'paragraph') {\n parts.push(serializeParagraph(item));\n } else if (item.type === 'table') {\n parts.push(serializeTable(item));\n }\n }\n\n // Ensure at least one empty paragraph (Word requires this)\n if (parts.length === 0) {\n parts.push('<w:p/>');\n }\n\n return parts.join('');\n}\n\n// ============================================================================\n// TABLE CELL SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a table cell (w:tc)\n */\nexport function serializeTableCell(cell: TableCell): string {\n const parts: string[] = [];\n\n // Cell properties\n const tcPrXml = serializeTableCellFormatting(cell.formatting);\n if (tcPrXml) {\n parts.push(tcPrXml);\n }\n\n // Cell content\n parts.push(serializeCellContent(cell.content));\n\n return `<w:tc>${parts.join('')}</w:tc>`;\n}\n\n// ============================================================================\n// TABLE ROW SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a table row (w:tr)\n */\nexport function serializeTableRow(row: TableRow): string {\n const parts: string[] = [];\n\n // Row properties\n const trPrXml = serializeTableRowFormatting(row.formatting);\n if (trPrXml) {\n parts.push(trPrXml);\n }\n\n // Cells\n for (const cell of row.cells) {\n parts.push(serializeTableCell(cell));\n }\n\n return `<w:tr>${parts.join('')}</w:tr>`;\n}\n\n// ============================================================================\n// MAIN TABLE SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a table to OOXML XML (w:tbl)\n *\n * @param table - The table to serialize\n * @returns XML string for the table\n */\nexport function serializeTable(table: Table): string {\n const parts: string[] = [];\n\n // Table properties\n const tblPrXml = serializeTableFormatting(table.formatting);\n if (tblPrXml) {\n parts.push(tblPrXml);\n }\n\n // Table grid\n const tblGridXml = serializeTableGrid(table.columnWidths);\n if (tblGridXml) {\n parts.push(tblGridXml);\n }\n\n // Rows\n for (const row of table.rows) {\n parts.push(serializeTableRow(row));\n }\n\n return `<w:tbl>${parts.join('')}</w:tbl>`;\n}\n\n/**\n * Serialize multiple tables to OOXML XML\n *\n * @param tables - The tables to serialize\n * @returns XML string for all tables\n */\nexport function serializeTables(tables: Table[]): string {\n return tables.map(serializeTable).join('');\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Check if a table has any rows\n */\nexport function hasTableRows(table: Table): boolean {\n return table.rows.length > 0;\n}\n\n/**\n * Check if a table has formatting\n */\nexport function hasTableFormatting(table: Table): boolean {\n return table.formatting !== undefined && Object.keys(table.formatting).length > 0;\n}\n\n/**\n * Check if a row has any cells\n */\nexport function hasRowCells(row: TableRow): boolean {\n return row.cells.length > 0;\n}\n\n/**\n * Check if a row has formatting\n */\nexport function hasRowFormatting(row: TableRow): boolean {\n return row.formatting !== undefined && Object.keys(row.formatting).length > 0;\n}\n\n/**\n * Check if a cell has any content\n */\nexport function hasCellContent(cell: TableCell): boolean {\n return cell.content.length > 0;\n}\n\n/**\n * Check if a cell has formatting\n */\nexport function hasCellFormatting(cell: TableCell): boolean {\n return cell.formatting !== undefined && Object.keys(cell.formatting).length > 0;\n}\n\n/**\n * Get the number of columns in a table\n */\nexport function getTableColumnCount(table: Table): number {\n if (table.columnWidths && table.columnWidths.length > 0) {\n return table.columnWidths.length;\n }\n\n if (table.rows.length === 0) return 0;\n\n // Count cells in first row, accounting for grid span\n return table.rows[0].cells.reduce((count, cell) => {\n return count + (cell.formatting?.gridSpan ?? 1);\n }, 0);\n}\n\n/**\n * Get the number of rows in a table\n */\nexport function getTableRowCount(table: Table): number {\n return table.rows.length;\n}\n\n/**\n * Create an empty table\n */\nexport function createEmptyTable(rows: number = 1, cols: number = 1): Table {\n const tableRows: TableRow[] = [];\n\n for (let r = 0; r < rows; r++) {\n const cells: TableCell[] = [];\n for (let c = 0; c < cols; c++) {\n cells.push({\n type: 'tableCell',\n content: [{ type: 'paragraph', content: [] }],\n });\n }\n tableRows.push({\n type: 'tableRow',\n cells,\n });\n }\n\n return {\n type: 'table',\n rows: tableRows,\n };\n}\n\n/**\n * Create a table cell with text content\n */\nexport function createTextCell(text: string, formatting?: TableCellFormatting): TableCell {\n return {\n type: 'tableCell',\n formatting,\n content: [\n {\n type: 'paragraph',\n content: [\n {\n type: 'run',\n content: [{ type: 'text', text }],\n },\n ],\n },\n ],\n };\n}\n\nexport default serializeTable;\n","/**\n * Document Serializer - Serialize complete document.xml\n *\n * Converts Document objects back to valid document.xml OOXML format.\n * Combines all content (paragraphs, tables) with section properties\n * and proper namespace declarations.\n *\n * OOXML Reference:\n * - Document root: w:document\n * - Document body: w:body\n * - Section properties: w:sectPr\n */\n\nimport type {\n Document,\n DocumentBody,\n BlockContent,\n SectionProperties,\n HeaderReference,\n FooterReference,\n FootnoteProperties,\n EndnoteProperties,\n BorderSpec,\n} from '../../types/document';\n\nimport { serializeParagraph } from './paragraphSerializer';\nimport { serializeTable } from './tableSerializer';\n\n// ============================================================================\n// XML NAMESPACES\n// ============================================================================\n\n/**\n * Standard OOXML namespaces for document.xml\n */\nconst NAMESPACES = {\n wpc: 'http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas',\n cx: 'http://schemas.microsoft.com/office/drawing/2014/chartex',\n cx1: 'http://schemas.microsoft.com/office/drawing/2015/9/8/chartex',\n cx2: 'http://schemas.microsoft.com/office/drawing/2015/10/21/chartex',\n cx3: 'http://schemas.microsoft.com/office/drawing/2016/5/9/chartex',\n cx4: 'http://schemas.microsoft.com/office/drawing/2016/5/10/chartex',\n cx5: 'http://schemas.microsoft.com/office/drawing/2016/5/11/chartex',\n cx6: 'http://schemas.microsoft.com/office/drawing/2016/5/12/chartex',\n cx7: 'http://schemas.microsoft.com/office/drawing/2016/5/13/chartex',\n cx8: 'http://schemas.microsoft.com/office/drawing/2016/5/14/chartex',\n mc: 'http://schemas.openxmlformats.org/markup-compatibility/2006',\n aink: 'http://schemas.microsoft.com/office/drawing/2016/ink',\n am3d: 'http://schemas.microsoft.com/office/drawing/2017/model3d',\n o: 'urn:schemas-microsoft-com:office:office',\n oel: 'http://schemas.microsoft.com/office/2019/extlst',\n r: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',\n m: 'http://schemas.openxmlformats.org/officeDocument/2006/math',\n v: 'urn:schemas-microsoft-com:vml',\n wp14: 'http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing',\n wp: 'http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing',\n w10: 'urn:schemas-microsoft-com:office:word',\n w: 'http://schemas.openxmlformats.org/wordprocessingml/2006/main',\n w14: 'http://schemas.microsoft.com/office/word/2010/wordml',\n w15: 'http://schemas.microsoft.com/office/word/2012/wordml',\n w16cex: 'http://schemas.microsoft.com/office/word/2018/wordml/cex',\n w16cid: 'http://schemas.microsoft.com/office/word/2016/wordml/cid',\n w16: 'http://schemas.microsoft.com/office/word/2018/wordml',\n w16sdtdh: 'http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash',\n w16se: 'http://schemas.microsoft.com/office/word/2015/wordml/symex',\n wpg: 'http://schemas.microsoft.com/office/word/2010/wordprocessingGroup',\n wpi: 'http://schemas.microsoft.com/office/word/2010/wordprocessingInk',\n wne: 'http://schemas.microsoft.com/office/word/2006/wordml',\n wps: 'http://schemas.microsoft.com/office/word/2010/wordprocessingShape',\n};\n\n/**\n * Build namespace declaration string for document element\n */\nfunction buildNamespaceDeclarations(): string {\n // Minimal set of commonly used namespaces\n const minimalNamespaces = {\n wpc: NAMESPACES.wpc,\n mc: NAMESPACES.mc,\n o: NAMESPACES.o,\n r: NAMESPACES.r,\n m: NAMESPACES.m,\n v: NAMESPACES.v,\n wp14: NAMESPACES.wp14,\n wp: NAMESPACES.wp,\n w10: NAMESPACES.w10,\n w: NAMESPACES.w,\n w14: NAMESPACES.w14,\n w15: NAMESPACES.w15,\n wpg: NAMESPACES.wpg,\n wps: NAMESPACES.wps,\n };\n\n return Object.entries(minimalNamespaces)\n .map(([prefix, uri]) => `xmlns:${prefix}=\"${uri}\"`)\n .join(' ');\n}\n\n// ============================================================================\n// XML ESCAPING\n// ============================================================================\n\n// ============================================================================\n// BORDER SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a border element\n */\nfunction serializeBorder(border: BorderSpec | undefined, elementName: string): string {\n if (!border || border.style === 'none' || border.style === 'nil') {\n return '';\n }\n\n const attrs: string[] = [`w:val=\"${border.style}\"`];\n\n if (border.size !== undefined) {\n attrs.push(`w:sz=\"${border.size}\"`);\n }\n\n if (border.space !== undefined) {\n attrs.push(`w:space=\"${border.space}\"`);\n }\n\n if (border.color) {\n if (border.color.auto) {\n attrs.push('w:color=\"auto\"');\n } else if (border.color.rgb) {\n attrs.push(`w:color=\"${border.color.rgb}\"`);\n }\n\n if (border.color.themeColor) {\n attrs.push(`w:themeColor=\"${border.color.themeColor}\"`);\n }\n\n if (border.color.themeTint) {\n attrs.push(`w:themeTint=\"${border.color.themeTint}\"`);\n }\n\n if (border.color.themeShade) {\n attrs.push(`w:themeShade=\"${border.color.themeShade}\"`);\n }\n }\n\n if (border.shadow) {\n attrs.push('w:shadow=\"true\"');\n }\n\n if (border.frame) {\n attrs.push('w:frame=\"true\"');\n }\n\n return `<w:${elementName} ${attrs.join(' ')}/>`;\n}\n\n// ============================================================================\n// SECTION PROPERTIES SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize header reference (w:headerReference)\n */\nfunction serializeHeaderReference(ref: HeaderReference): string {\n const attrs: string[] = [`w:type=\"${ref.type}\"`, `r:id=\"${ref.rId}\"`];\n\n return `<w:headerReference ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize footer reference (w:footerReference)\n */\nfunction serializeFooterReference(ref: FooterReference): string {\n const attrs: string[] = [`w:type=\"${ref.type}\"`, `r:id=\"${ref.rId}\"`];\n\n return `<w:footerReference ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize footnote properties (w:footnotePr)\n */\nfunction serializeFootnoteProperties(props: FootnoteProperties | undefined): string {\n if (!props) return '';\n\n const parts: string[] = [];\n\n if (props.position) {\n parts.push(`<w:pos w:val=\"${props.position}\"/>`);\n }\n\n if (props.numFmt) {\n parts.push(`<w:numFmt w:val=\"${props.numFmt}\"/>`);\n }\n\n if (props.numStart !== undefined) {\n parts.push(`<w:numStart w:val=\"${props.numStart}\"/>`);\n }\n\n if (props.numRestart) {\n parts.push(`<w:numRestart w:val=\"${props.numRestart}\"/>`);\n }\n\n if (parts.length === 0) return '';\n\n return `<w:footnotePr>${parts.join('')}</w:footnotePr>`;\n}\n\n/**\n * Serialize endnote properties (w:endnotePr)\n */\nfunction serializeEndnoteProperties(props: EndnoteProperties | undefined): string {\n if (!props) return '';\n\n const parts: string[] = [];\n\n if (props.position) {\n parts.push(`<w:pos w:val=\"${props.position}\"/>`);\n }\n\n if (props.numFmt) {\n parts.push(`<w:numFmt w:val=\"${props.numFmt}\"/>`);\n }\n\n if (props.numStart !== undefined) {\n parts.push(`<w:numStart w:val=\"${props.numStart}\"/>`);\n }\n\n if (props.numRestart) {\n parts.push(`<w:numRestart w:val=\"${props.numRestart}\"/>`);\n }\n\n if (parts.length === 0) return '';\n\n return `<w:endnotePr>${parts.join('')}</w:endnotePr>`;\n}\n\n/**\n * Serialize page size (w:pgSz)\n */\nfunction serializePageSize(props: SectionProperties): string {\n const attrs: string[] = [];\n\n if (props.pageWidth !== undefined) {\n attrs.push(`w:w=\"${props.pageWidth}\"`);\n }\n\n if (props.pageHeight !== undefined) {\n attrs.push(`w:h=\"${props.pageHeight}\"`);\n }\n\n if (props.orientation === 'landscape') {\n attrs.push('w:orient=\"landscape\"');\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:pgSz ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize page margins (w:pgMar)\n */\nfunction serializePageMargins(props: SectionProperties): string {\n const attrs: string[] = [];\n\n if (props.marginTop !== undefined) {\n attrs.push(`w:top=\"${props.marginTop}\"`);\n }\n\n if (props.marginRight !== undefined) {\n attrs.push(`w:right=\"${props.marginRight}\"`);\n }\n\n if (props.marginBottom !== undefined) {\n attrs.push(`w:bottom=\"${props.marginBottom}\"`);\n }\n\n if (props.marginLeft !== undefined) {\n attrs.push(`w:left=\"${props.marginLeft}\"`);\n }\n\n if (props.headerDistance !== undefined) {\n attrs.push(`w:header=\"${props.headerDistance}\"`);\n }\n\n if (props.footerDistance !== undefined) {\n attrs.push(`w:footer=\"${props.footerDistance}\"`);\n }\n\n if (props.gutter !== undefined) {\n attrs.push(`w:gutter=\"${props.gutter}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:pgMar ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize columns (w:cols)\n */\nfunction serializeColumns(props: SectionProperties): string {\n if (!props.columnCount && !props.columns?.length) return '';\n\n const attrs: string[] = [];\n\n if (props.columnCount !== undefined && props.columnCount > 1) {\n attrs.push(`w:num=\"${props.columnCount}\"`);\n }\n\n if (props.columnSpace !== undefined) {\n attrs.push(`w:space=\"${props.columnSpace}\"`);\n }\n\n if (props.equalWidth !== undefined) {\n attrs.push(`w:equalWidth=\"${props.equalWidth ? '1' : '0'}\"`);\n }\n\n if (props.separator) {\n attrs.push('w:sep=\"1\"');\n }\n\n // Individual column definitions\n let colElements = '';\n if (props.columns && props.columns.length > 0) {\n colElements = props.columns\n .map((col) => {\n const colAttrs: string[] = [];\n if (col.width !== undefined) {\n colAttrs.push(`w:w=\"${col.width}\"`);\n }\n if (col.space !== undefined) {\n colAttrs.push(`w:space=\"${col.space}\"`);\n }\n return `<w:col ${colAttrs.join(' ')}/>`;\n })\n .join('');\n }\n\n if (attrs.length === 0 && !colElements) return '';\n\n const attrsStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';\n return `<w:cols${attrsStr}>${colElements}</w:cols>`;\n}\n\n/**\n * Serialize line numbers (w:lnNumType)\n */\nfunction serializeLineNumbers(props: SectionProperties): string {\n if (!props.lineNumbers) return '';\n\n const ln = props.lineNumbers;\n const attrs: string[] = [];\n\n if (ln.countBy !== undefined) {\n attrs.push(`w:countBy=\"${ln.countBy}\"`);\n }\n\n if (ln.start !== undefined) {\n attrs.push(`w:start=\"${ln.start}\"`);\n }\n\n if (ln.distance !== undefined) {\n attrs.push(`w:distance=\"${ln.distance}\"`);\n }\n\n if (ln.restart) {\n attrs.push(`w:restart=\"${ln.restart}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:lnNumType ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize page borders (w:pgBorders)\n */\nfunction serializePageBorders(props: SectionProperties): string {\n if (!props.pageBorders) return '';\n\n const pb = props.pageBorders;\n const attrs: string[] = [];\n const borderElements: string[] = [];\n\n if (pb.display) {\n attrs.push(`w:display=\"${pb.display}\"`);\n }\n\n if (pb.offsetFrom) {\n attrs.push(`w:offsetFrom=\"${pb.offsetFrom}\"`);\n }\n\n if (pb.zOrder) {\n attrs.push(`w:zOrder=\"${pb.zOrder}\"`);\n }\n\n if (pb.top) {\n const topXml = serializeBorder(pb.top, 'top');\n if (topXml) borderElements.push(topXml);\n }\n\n if (pb.left) {\n const leftXml = serializeBorder(pb.left, 'left');\n if (leftXml) borderElements.push(leftXml);\n }\n\n if (pb.bottom) {\n const bottomXml = serializeBorder(pb.bottom, 'bottom');\n if (bottomXml) borderElements.push(bottomXml);\n }\n\n if (pb.right) {\n const rightXml = serializeBorder(pb.right, 'right');\n if (rightXml) borderElements.push(rightXml);\n }\n\n if (borderElements.length === 0) return '';\n\n const attrsStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';\n return `<w:pgBorders${attrsStr}>${borderElements.join('')}</w:pgBorders>`;\n}\n\n/**\n * Serialize document grid (w:docGrid)\n */\nfunction serializeDocGrid(props: SectionProperties): string {\n if (!props.docGrid) return '';\n\n const dg = props.docGrid;\n const attrs: string[] = [];\n\n if (dg.type) {\n attrs.push(`w:type=\"${dg.type}\"`);\n }\n\n if (dg.linePitch !== undefined) {\n attrs.push(`w:linePitch=\"${dg.linePitch}\"`);\n }\n\n if (dg.charSpace !== undefined) {\n attrs.push(`w:charSpace=\"${dg.charSpace}\"`);\n }\n\n if (attrs.length === 0) return '';\n\n return `<w:docGrid ${attrs.join(' ')}/>`;\n}\n\n/**\n * Serialize section properties (w:sectPr)\n */\nexport function serializeSectionProperties(props: SectionProperties | undefined): string {\n if (!props) return '';\n\n const parts: string[] = [];\n\n // Header references\n if (props.headerReferences) {\n for (const ref of props.headerReferences) {\n parts.push(serializeHeaderReference(ref));\n }\n }\n\n // Footer references\n if (props.footerReferences) {\n for (const ref of props.footerReferences) {\n parts.push(serializeFooterReference(ref));\n }\n }\n\n // Footnote properties\n const footnotePrXml = serializeFootnoteProperties(props.footnotePr);\n if (footnotePrXml) {\n parts.push(footnotePrXml);\n }\n\n // Endnote properties\n const endnotePrXml = serializeEndnoteProperties(props.endnotePr);\n if (endnotePrXml) {\n parts.push(endnotePrXml);\n }\n\n // Section type\n if (props.sectionStart) {\n parts.push(`<w:type w:val=\"${props.sectionStart}\"/>`);\n }\n\n // Page size\n const pgSzXml = serializePageSize(props);\n if (pgSzXml) {\n parts.push(pgSzXml);\n }\n\n // Page margins\n const pgMarXml = serializePageMargins(props);\n if (pgMarXml) {\n parts.push(pgMarXml);\n }\n\n // Paper source\n if (props.paperSrcFirst !== undefined || props.paperSrcOther !== undefined) {\n const attrs: string[] = [];\n if (props.paperSrcFirst !== undefined) {\n attrs.push(`w:first=\"${props.paperSrcFirst}\"`);\n }\n if (props.paperSrcOther !== undefined) {\n attrs.push(`w:other=\"${props.paperSrcOther}\"`);\n }\n parts.push(`<w:paperSrc ${attrs.join(' ')}/>`);\n }\n\n // Page borders\n const pgBordersXml = serializePageBorders(props);\n if (pgBordersXml) {\n parts.push(pgBordersXml);\n }\n\n // Line numbers\n const lnNumXml = serializeLineNumbers(props);\n if (lnNumXml) {\n parts.push(lnNumXml);\n }\n\n // Columns\n const colsXml = serializeColumns(props);\n if (colsXml) {\n parts.push(colsXml);\n }\n\n // Document grid\n const docGridXml = serializeDocGrid(props);\n if (docGridXml) {\n parts.push(docGridXml);\n }\n\n // Vertical alignment\n if (props.verticalAlign) {\n parts.push(`<w:vAlign w:val=\"${props.verticalAlign}\"/>`);\n }\n\n // Bidirectional\n if (props.bidi) {\n parts.push('<w:bidi/>');\n }\n\n // Title page (different first page header/footer)\n if (props.titlePg) {\n parts.push('<w:titlePg/>');\n }\n\n // Even and odd headers\n if (props.evenAndOddHeaders) {\n parts.push('<w:evenAndOddHeaders/>');\n }\n\n if (parts.length === 0) return '';\n\n return `<w:sectPr>${parts.join('')}</w:sectPr>`;\n}\n\n// ============================================================================\n// CONTENT SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a single block content item (paragraph or table)\n */\nfunction serializeBlockContent(block: BlockContent): string {\n if (block.type === 'paragraph') {\n return serializeParagraph(block);\n } else if (block.type === 'table') {\n return serializeTable(block);\n }\n return '';\n}\n\n/**\n * Serialize document body content\n */\nfunction serializeBodyContent(content: BlockContent[]): string {\n return content.map((block) => serializeBlockContent(block)).join('');\n}\n\n// ============================================================================\n// MAIN DOCUMENT SERIALIZATION\n// ============================================================================\n\n/**\n * Serialize a DocumentBody to document.xml body content\n *\n * @param body - The document body to serialize\n * @returns XML string for the body element (without body tags)\n */\nexport function serializeDocumentBody(body: DocumentBody): string {\n const parts: string[] = [];\n\n // Serialize all content blocks\n parts.push(serializeBodyContent(body.content));\n\n // Final section properties (at the end of body)\n if (body.finalSectionProperties) {\n parts.push(serializeSectionProperties(body.finalSectionProperties));\n }\n\n return parts.join('');\n}\n\n/**\n * Serialize a complete Document to valid document.xml\n *\n * @param doc - The document to serialize\n * @returns Complete XML string for document.xml\n */\nexport function serializeDocument(doc: Document): string {\n const parts: string[] = [];\n\n // XML declaration\n parts.push('<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>');\n\n // Document element with namespaces\n const nsDecl = buildNamespaceDeclarations();\n parts.push(`<w:document ${nsDecl} mc:Ignorable=\"w14 w15 wp14\">`);\n\n // Document body\n parts.push('<w:body>');\n parts.push(serializeDocumentBody(doc.package.document));\n parts.push('</w:body>');\n\n // Close document element\n parts.push('</w:document>');\n\n return parts.join('');\n}\n\n/**\n * Serialize just the document body (useful for partial updates)\n *\n * @param body - The document body to serialize\n * @returns XML string for the w:body element\n */\nexport function serializeDocumentBodyElement(body: DocumentBody): string {\n return `<w:body>${serializeDocumentBody(body)}</w:body>`;\n}\n\n// ============================================================================\n// UTILITY FUNCTIONS\n// ============================================================================\n\n/**\n * Check if document has any content\n */\nexport function hasDocumentContent(doc: Document): boolean {\n return doc.package.document.content.length > 0;\n}\n\n/**\n * Check if document has sections\n */\nexport function hasDocumentSections(doc: Document): boolean {\n return (doc.package.document.sections?.length ?? 0) > 0;\n}\n\n/**\n * Check if document has section properties\n */\nexport function hasSectionProperties(doc: Document): boolean {\n return doc.package.document.finalSectionProperties !== undefined;\n}\n\n/**\n * Get document content count (paragraphs + tables)\n */\nexport function getDocumentContentCount(doc: Document): number {\n return doc.package.document.content.length;\n}\n\n/**\n * Get paragraph count in document\n */\nexport function getDocumentParagraphCount(doc: Document): number {\n return doc.package.document.content.filter((b) => b.type === 'paragraph').length;\n}\n\n/**\n * Get table count in document\n */\nexport function getDocumentTableCount(doc: Document): number {\n return doc.package.document.content.filter((b) => b.type === 'table').length;\n}\n\n/**\n * Get plain text from document (for comparison/debugging)\n */\nexport function getDocumentPlainText(doc: Document): string {\n const texts: string[] = [];\n\n for (const block of doc.package.document.content) {\n if (block.type === 'paragraph') {\n for (const content of block.content) {\n if (content.type === 'run') {\n for (const item of content.content) {\n if (item.type === 'text') {\n texts.push(item.text);\n } else if (item.type === 'tab') {\n texts.push('\\t');\n } else if (item.type === 'break') {\n texts.push('\\n');\n }\n }\n }\n }\n texts.push('\\n'); // Paragraph break\n }\n }\n\n return texts.join('');\n}\n\n/**\n * Create an empty document\n */\nexport function createEmptyDocument(): Document {\n return {\n package: {\n document: {\n content: [],\n },\n },\n };\n}\n\n/**\n * Create a simple document with text content\n */\nexport function createSimpleDocument(\n paragraphs: Array<{ text: string; styleId?: string }>\n): Document {\n return {\n package: {\n document: {\n content: paragraphs.map((p) => ({\n type: 'paragraph' as const,\n formatting: p.styleId ? { styleId: p.styleId } : undefined,\n content: [\n {\n type: 'run' as const,\n content: [{ type: 'text' as const, text: p.text }],\n },\n ],\n })),\n },\n },\n };\n}\n\nexport default serializeDocument;\n","/**\n * Command Executor\n *\n * Executes agent commands on a document immutably:\n * - Handles all command types from AgentCommand\n * - Preserves surrounding formatting\n * - Returns new document (immutable updates)\n */\n\nimport type {\n Document,\n DocumentBody,\n Paragraph,\n Run,\n TextContent,\n ParagraphContent,\n BlockContent,\n Table,\n TableRow,\n TableCell,\n TextFormatting,\n Image,\n Hyperlink,\n} from '../types/document';\n\nimport type {\n AgentCommand,\n InsertTextCommand,\n ReplaceTextCommand,\n DeleteTextCommand,\n FormatTextCommand,\n FormatParagraphCommand,\n ApplyStyleCommand,\n InsertTableCommand,\n InsertImageCommand,\n InsertHyperlinkCommand,\n RemoveHyperlinkCommand,\n InsertParagraphBreakCommand,\n MergeParagraphsCommand,\n SplitParagraphCommand,\n SetVariableCommand,\n ApplyVariablesCommand,\n} from '../types/agentApi';\n\nimport { pluginRegistry } from '../core-plugins/registry';\n\n// ============================================================================\n// MAIN EXECUTOR\n// ============================================================================\n\n/**\n * Execute an agent command on a document\n * Returns a new document with the command applied (immutable)\n *\n * Dispatch order:\n * 1. Try plugin handlers first (allows plugins to override built-in commands)\n * 2. Fall back to built-in handlers\n *\n * @param doc - The document to modify\n * @param command - The command to execute\n * @returns New document with command applied\n */\nexport function executeCommand(doc: Document, command: AgentCommand): Document {\n // Try plugin handlers first\n const pluginHandler = pluginRegistry.getCommandHandler(command.type);\n if (pluginHandler) {\n // Plugin commands use a more flexible type\n return pluginHandler(doc, command as unknown as import('../core-plugins/types').PluginCommand);\n }\n\n // Fall back to built-in handlers\n switch (command.type) {\n case 'insertText':\n return executeInsertText(doc, command);\n case 'replaceText':\n return executeReplaceText(doc, command);\n case 'deleteText':\n return executeDeleteText(doc, command);\n case 'formatText':\n return executeFormatText(doc, command);\n case 'formatParagraph':\n return executeFormatParagraph(doc, command);\n case 'applyStyle':\n return executeApplyStyle(doc, command);\n case 'insertTable':\n return executeInsertTable(doc, command);\n case 'insertImage':\n return executeInsertImage(doc, command);\n case 'insertHyperlink':\n return executeInsertHyperlink(doc, command);\n case 'removeHyperlink':\n return executeRemoveHyperlink(doc, command);\n case 'insertParagraphBreak':\n return executeInsertParagraphBreak(doc, command);\n case 'mergeParagraphs':\n return executeMergeParagraphs(doc, command);\n case 'splitParagraph':\n return executeSplitParagraph(doc, command);\n case 'setVariable':\n return executeSetVariable(doc, command);\n case 'applyVariables':\n return executeApplyVariables(doc, command);\n default:\n // Exhaustive check - should never happen with proper types\n const _exhaustive: never = command;\n throw new Error(`Unknown command type: ${(_exhaustive as AgentCommand).type}`);\n }\n}\n\n/**\n * Execute multiple commands in sequence\n *\n * @param doc - The document to modify\n * @param commands - Commands to execute in order\n * @returns New document with all commands applied\n */\nexport function executeCommands(doc: Document, commands: AgentCommand[]): Document {\n return commands.reduce((currentDoc, command) => executeCommand(currentDoc, command), doc);\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Deep clone a document for immutable updates\n */\nfunction cloneDocument(doc: Document): Document {\n return JSON.parse(JSON.stringify(doc));\n}\n\n/**\n * Get the block index for a paragraph index\n */\nfunction getBlockIndexForParagraph(body: DocumentBody, paragraphIndex: number): number {\n let currentParagraphIndex = 0;\n for (let i = 0; i < body.content.length; i++) {\n if (body.content[i].type === 'paragraph') {\n if (currentParagraphIndex === paragraphIndex) {\n return i;\n }\n currentParagraphIndex++;\n }\n }\n return -1;\n}\n\n/**\n * Get plain text from a paragraph\n */\nfunction getParagraphText(paragraph: Paragraph): string {\n let text = '';\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n for (const content of item.content) {\n if (content.type === 'text') {\n text += content.text;\n }\n }\n } else if (item.type === 'hyperlink') {\n for (const child of item.children) {\n if (child.type === 'run') {\n for (const content of child.content) {\n if (content.type === 'text') {\n text += content.text;\n }\n }\n }\n }\n }\n }\n return text;\n}\n\n/**\n * Create a new run with text\n */\nfunction createTextRun(text: string, formatting?: TextFormatting): Run {\n return {\n type: 'run',\n formatting,\n content: [\n {\n type: 'text',\n text,\n },\n ],\n };\n}\n\n/**\n * Insert text at a specific offset within a paragraph\n * Returns new paragraph content\n */\nfunction insertTextAtOffset(\n paragraph: Paragraph,\n offset: number,\n text: string,\n formatting?: TextFormatting\n): ParagraphContent[] {\n const newContent: ParagraphContent[] = [];\n let currentOffset = 0;\n let inserted = false;\n\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n const runText = item.content\n .filter((c): c is TextContent => c.type === 'text')\n .map((c) => c.text)\n .join('');\n\n const runStart = currentOffset;\n const runEnd = currentOffset + runText.length;\n\n if (!inserted && offset >= runStart && offset <= runEnd) {\n // Insert within this run\n const insertPos = offset - runStart;\n\n if (insertPos > 0) {\n // Text before insertion point\n newContent.push({\n ...item,\n content: [{ type: 'text', text: runText.slice(0, insertPos) }],\n });\n }\n\n // New text\n newContent.push(createTextRun(text, formatting || item.formatting));\n\n if (insertPos < runText.length) {\n // Text after insertion point\n newContent.push({\n ...item,\n content: [{ type: 'text', text: runText.slice(insertPos) }],\n });\n }\n\n inserted = true;\n } else {\n newContent.push(item);\n }\n\n currentOffset = runEnd;\n } else {\n newContent.push(item);\n }\n }\n\n // If not inserted yet, append at the end\n if (!inserted) {\n newContent.push(createTextRun(text, formatting));\n }\n\n return newContent;\n}\n\n/**\n * Delete text in a range within a single paragraph\n */\nfunction deleteTextInParagraph(\n paragraph: Paragraph,\n startOffset: number,\n endOffset: number\n): ParagraphContent[] {\n const newContent: ParagraphContent[] = [];\n let currentOffset = 0;\n\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n const runText = item.content\n .filter((c): c is TextContent => c.type === 'text')\n .map((c) => c.text)\n .join('');\n\n const runStart = currentOffset;\n const runEnd = currentOffset + runText.length;\n\n // Check if run overlaps with deletion range\n if (runEnd <= startOffset || runStart >= endOffset) {\n // No overlap, keep entire run\n newContent.push(item);\n } else {\n // Partial overlap\n let newText = '';\n\n if (runStart < startOffset) {\n // Keep text before start\n newText += runText.slice(0, startOffset - runStart);\n }\n\n if (runEnd > endOffset) {\n // Keep text after end\n newText += runText.slice(endOffset - runStart);\n }\n\n if (newText.length > 0) {\n newContent.push({\n ...item,\n content: [{ type: 'text', text: newText }],\n });\n }\n }\n\n currentOffset = runEnd;\n } else {\n newContent.push(item);\n }\n }\n\n return newContent;\n}\n\n/**\n * Apply formatting to text in a range within a paragraph\n */\nfunction applyFormattingInParagraph(\n paragraph: Paragraph,\n startOffset: number,\n endOffset: number,\n formatting: Partial<TextFormatting>\n): ParagraphContent[] {\n const newContent: ParagraphContent[] = [];\n let currentOffset = 0;\n\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n const runText = item.content\n .filter((c): c is TextContent => c.type === 'text')\n .map((c) => c.text)\n .join('');\n\n const runStart = currentOffset;\n const runEnd = currentOffset + runText.length;\n\n // Check if run overlaps with formatting range\n if (runEnd <= startOffset || runStart >= endOffset) {\n // No overlap, keep entire run unchanged\n newContent.push(item);\n } else if (runStart >= startOffset && runEnd <= endOffset) {\n // Entire run is within range, apply formatting\n newContent.push({\n ...item,\n formatting: { ...item.formatting, ...formatting },\n });\n } else {\n // Partial overlap - need to split run\n const overlapStart = Math.max(startOffset, runStart);\n const overlapEnd = Math.min(endOffset, runEnd);\n\n // Text before overlap\n if (runStart < overlapStart) {\n newContent.push({\n ...item,\n content: [{ type: 'text', text: runText.slice(0, overlapStart - runStart) }],\n });\n }\n\n // Overlapping text with formatting\n newContent.push({\n ...item,\n formatting: { ...item.formatting, ...formatting },\n content: [\n {\n type: 'text',\n text: runText.slice(overlapStart - runStart, overlapEnd - runStart),\n },\n ],\n });\n\n // Text after overlap\n if (runEnd > overlapEnd) {\n newContent.push({\n ...item,\n content: [{ type: 'text', text: runText.slice(overlapEnd - runStart) }],\n });\n }\n }\n\n currentOffset = runEnd;\n } else {\n newContent.push(item);\n }\n }\n\n return newContent;\n}\n\n// ============================================================================\n// COMMAND IMPLEMENTATIONS\n// ============================================================================\n\n/**\n * Insert text at a position\n */\nfunction executeInsertText(doc: Document, command: InsertTextCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n const blockIndex = getBlockIndexForParagraph(body, command.position.paragraphIndex);\n\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${command.position.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n paragraph.content = insertTextAtOffset(\n paragraph,\n command.position.offset,\n command.text,\n command.formatting\n );\n\n return newDoc;\n}\n\n/**\n * Replace text in a range\n */\nfunction executeReplaceText(doc: Document, command: ReplaceTextCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const { start, end } = command.range;\n\n if (start.paragraphIndex === end.paragraphIndex) {\n // Same paragraph\n const blockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${start.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n\n // Delete the range first\n paragraph.content = deleteTextInParagraph(paragraph, start.offset, end.offset);\n\n // Then insert the new text\n paragraph.content = insertTextAtOffset(\n paragraph,\n start.offset,\n command.text,\n command.formatting\n );\n } else {\n // Multiple paragraphs - simplify by deleting and inserting\n // Delete from start to end of first paragraph\n const startBlockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n const startParagraph = body.content[startBlockIndex] as Paragraph;\n const startText = getParagraphText(startParagraph);\n\n startParagraph.content = deleteTextInParagraph(startParagraph, start.offset, startText.length);\n startParagraph.content = insertTextAtOffset(\n startParagraph,\n start.offset,\n command.text,\n command.formatting\n );\n\n // Delete intermediate paragraphs and beginning of last paragraph\n const paragraphsToRemove: number[] = [];\n for (let i = start.paragraphIndex + 1; i <= end.paragraphIndex; i++) {\n paragraphsToRemove.push(getBlockIndexForParagraph(body, i));\n }\n\n // Remove in reverse order to preserve indices\n for (let i = paragraphsToRemove.length - 1; i >= 0; i--) {\n if (paragraphsToRemove[i] !== -1) {\n body.content.splice(paragraphsToRemove[i], 1);\n }\n }\n }\n\n return newDoc;\n}\n\n/**\n * Delete text in a range\n */\nfunction executeDeleteText(doc: Document, command: DeleteTextCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const { start, end } = command.range;\n\n if (start.paragraphIndex === end.paragraphIndex) {\n // Same paragraph\n const blockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${start.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n paragraph.content = deleteTextInParagraph(paragraph, start.offset, end.offset);\n } else {\n // Multiple paragraphs\n // Truncate first paragraph\n const startBlockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n const startParagraph = body.content[startBlockIndex] as Paragraph;\n const startText = getParagraphText(startParagraph);\n startParagraph.content = deleteTextInParagraph(startParagraph, start.offset, startText.length);\n\n // Delete intermediate paragraphs and truncate last\n const endBlockIndex = getBlockIndexForParagraph(body, end.paragraphIndex);\n const endParagraph = body.content[endBlockIndex] as Paragraph;\n endParagraph.content = deleteTextInParagraph(endParagraph, 0, end.offset);\n\n // Merge last paragraph content into first\n startParagraph.content.push(...endParagraph.content);\n\n // Remove paragraphs between start and end (inclusive of end)\n const indicesToRemove: number[] = [];\n for (let i = start.paragraphIndex + 1; i <= end.paragraphIndex; i++) {\n indicesToRemove.push(getBlockIndexForParagraph(body, i));\n }\n\n for (let i = indicesToRemove.length - 1; i >= 0; i--) {\n if (indicesToRemove[i] !== -1) {\n body.content.splice(indicesToRemove[i], 1);\n }\n }\n }\n\n return newDoc;\n}\n\n/**\n * Apply formatting to a range\n */\nfunction executeFormatText(doc: Document, command: FormatTextCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const { start, end } = command.range;\n\n if (start.paragraphIndex === end.paragraphIndex) {\n // Same paragraph\n const blockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${start.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n paragraph.content = applyFormattingInParagraph(\n paragraph,\n start.offset,\n end.offset,\n command.formatting\n );\n } else {\n // Multiple paragraphs\n for (let i = start.paragraphIndex; i <= end.paragraphIndex; i++) {\n const blockIndex = getBlockIndexForParagraph(body, i);\n if (blockIndex === -1) continue;\n\n const paragraph = body.content[blockIndex] as Paragraph;\n const paragraphText = getParagraphText(paragraph);\n\n let startOffset = 0;\n let endOffset = paragraphText.length;\n\n if (i === start.paragraphIndex) {\n startOffset = start.offset;\n }\n if (i === end.paragraphIndex) {\n endOffset = end.offset;\n }\n\n paragraph.content = applyFormattingInParagraph(\n paragraph,\n startOffset,\n endOffset,\n command.formatting\n );\n }\n }\n\n return newDoc;\n}\n\n/**\n * Apply paragraph formatting\n */\nfunction executeFormatParagraph(doc: Document, command: FormatParagraphCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const blockIndex = getBlockIndexForParagraph(body, command.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${command.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n paragraph.formatting = { ...paragraph.formatting, ...command.formatting };\n\n // Handle listRendering when numPr changes\n if ('numPr' in command.formatting) {\n const numPr = command.formatting.numPr;\n if (numPr && numPr.numId !== undefined && numPr.numId !== 0) {\n // Setting a list - compute listRendering\n const ilvl = numPr.ilvl ?? 0;\n const isBullet = numPr.numId === 1; // numId 1 is typically bullets, 2 is numbered\n\n // Try to get marker from numbering definitions if available\n let marker = isBullet ? '•' : `${1}.`; // Default markers\n\n if (newDoc.package.numbering) {\n const num = newDoc.package.numbering.nums.find((n) => n.numId === numPr.numId);\n if (num) {\n const abstractNum = newDoc.package.numbering.abstractNums.find(\n (a) => a.abstractNumId === num.abstractNumId\n );\n if (abstractNum) {\n const level = abstractNum.levels.find((l) => l.ilvl === ilvl);\n if (level) {\n marker = level.lvlText || marker;\n }\n }\n }\n }\n\n paragraph.listRendering = {\n level: ilvl,\n numId: numPr.numId,\n marker,\n isBullet,\n };\n } else {\n // Removing list - clear listRendering\n delete paragraph.listRendering;\n }\n }\n\n return newDoc;\n}\n\n/**\n * Apply a named style to a paragraph\n */\nfunction executeApplyStyle(doc: Document, command: ApplyStyleCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const blockIndex = getBlockIndexForParagraph(body, command.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${command.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n paragraph.formatting = {\n ...paragraph.formatting,\n styleId: command.styleId,\n };\n\n return newDoc;\n}\n\n/**\n * Insert a table at a position\n */\nfunction executeInsertTable(doc: Document, command: InsertTableCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n // Create table structure\n const rows: TableRow[] = [];\n\n for (let r = 0; r < command.rows; r++) {\n const cells: TableCell[] = [];\n\n for (let c = 0; c < command.columns; c++) {\n const cellText = command.data?.[r]?.[c] || '';\n cells.push({\n type: 'tableCell',\n content: [\n {\n type: 'paragraph',\n content: cellText ? [createTextRun(cellText)] : [],\n },\n ],\n });\n }\n\n rows.push({\n type: 'tableRow',\n formatting: r === 0 && command.hasHeader ? { header: true } : undefined,\n cells,\n });\n }\n\n const table: Table = {\n type: 'table',\n rows,\n };\n\n // Insert table after the specified paragraph\n const blockIndex = getBlockIndexForParagraph(body, command.position.paragraphIndex);\n if (blockIndex === -1) {\n body.content.push(table);\n } else {\n body.content.splice(blockIndex + 1, 0, table);\n }\n\n return newDoc;\n}\n\n/**\n * Insert an image at a position\n */\nfunction executeInsertImage(doc: Document, command: InsertImageCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const blockIndex = getBlockIndexForParagraph(body, command.position.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${command.position.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n\n // Create image\n const image: Image = {\n type: 'image',\n rId: `rId_img_${Date.now()}`,\n src: command.src,\n alt: command.alt,\n size: {\n width: (command.width || 100) * 914400, // Convert pixels to EMU\n height: (command.height || 100) * 914400,\n },\n wrap: { type: 'inline' },\n };\n\n // Create run with drawing content\n const imageRun: Run = {\n type: 'run',\n content: [\n {\n type: 'drawing',\n image,\n },\n ],\n };\n\n // Insert image run at offset\n const newContent = insertTextAtOffset(paragraph, command.position.offset, '', undefined);\n // Find insertion point and add image\n let inserted = false;\n let currentOffset = 0;\n\n for (let i = 0; i < newContent.length; i++) {\n const item = newContent[i];\n if (item.type === 'run') {\n const runText = item.content\n .filter((c): c is TextContent => c.type === 'text')\n .map((c) => c.text)\n .join('');\n currentOffset += runText.length;\n\n if (!inserted && currentOffset >= command.position.offset) {\n newContent.splice(i + 1, 0, imageRun);\n inserted = true;\n break;\n }\n }\n }\n\n if (!inserted) {\n newContent.push(imageRun);\n }\n\n paragraph.content = newContent;\n\n return newDoc;\n}\n\n/**\n * Insert a hyperlink at a range\n */\nfunction executeInsertHyperlink(doc: Document, command: InsertHyperlinkCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const { start, end } = command.range;\n\n if (start.paragraphIndex !== end.paragraphIndex) {\n throw new Error('Hyperlinks cannot span multiple paragraphs');\n }\n\n const blockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${start.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n const paragraphText = getParagraphText(paragraph);\n\n // Get the text that will become the link\n const linkText = command.displayText || paragraphText.slice(start.offset, end.offset);\n\n // Delete the original text\n paragraph.content = deleteTextInParagraph(paragraph, start.offset, end.offset);\n\n // Create hyperlink\n const hyperlink: Hyperlink = {\n type: 'hyperlink',\n href: command.url,\n tooltip: command.tooltip,\n children: [createTextRun(linkText)],\n };\n\n // Insert hyperlink at position\n let inserted = false;\n let currentOffset = 0;\n const newContent: ParagraphContent[] = [];\n\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n const runText = item.content\n .filter((c): c is TextContent => c.type === 'text')\n .map((c) => c.text)\n .join('');\n\n const runEnd = currentOffset + runText.length;\n\n if (!inserted && currentOffset <= start.offset && start.offset <= runEnd) {\n const insertPos = start.offset - currentOffset;\n\n if (insertPos > 0) {\n newContent.push({\n ...item,\n content: [{ type: 'text', text: runText.slice(0, insertPos) }],\n });\n }\n\n newContent.push(hyperlink);\n\n if (insertPos < runText.length) {\n newContent.push({\n ...item,\n content: [{ type: 'text', text: runText.slice(insertPos) }],\n });\n }\n\n inserted = true;\n } else {\n newContent.push(item);\n }\n\n currentOffset = runEnd;\n } else {\n newContent.push(item);\n }\n }\n\n if (!inserted) {\n newContent.push(hyperlink);\n }\n\n paragraph.content = newContent;\n\n return newDoc;\n}\n\n/**\n * Remove a hyperlink but keep the text\n */\nfunction executeRemoveHyperlink(doc: Document, command: RemoveHyperlinkCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const { start } = command.range;\n\n const blockIndex = getBlockIndexForParagraph(body, start.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${start.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n const newContent: ParagraphContent[] = [];\n\n for (const item of paragraph.content) {\n if (item.type === 'hyperlink') {\n // Convert hyperlink children to regular runs\n for (const child of item.children) {\n if (child.type === 'run') {\n newContent.push(child);\n }\n }\n } else {\n newContent.push(item);\n }\n }\n\n paragraph.content = newContent;\n\n return newDoc;\n}\n\n/**\n * Insert a paragraph break\n */\nfunction executeInsertParagraphBreak(\n doc: Document,\n command: InsertParagraphBreakCommand\n): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const blockIndex = getBlockIndexForParagraph(body, command.position.paragraphIndex);\n if (blockIndex === -1) {\n throw new Error(`Paragraph index ${command.position.paragraphIndex} not found`);\n }\n\n const paragraph = body.content[blockIndex] as Paragraph;\n const paragraphText = getParagraphText(paragraph);\n\n // Split the paragraph at the offset\n const beforeContent = deleteTextInParagraph(\n { ...paragraph, content: [...paragraph.content] },\n command.position.offset,\n paragraphText.length\n );\n\n const afterContent = deleteTextInParagraph(\n { ...paragraph, content: [...paragraph.content] },\n 0,\n command.position.offset\n );\n\n // Update current paragraph with content before break\n paragraph.content = beforeContent;\n\n // Create new paragraph with content after break\n const newParagraph: Paragraph = {\n type: 'paragraph',\n formatting: paragraph.formatting,\n content: afterContent,\n };\n\n // Insert new paragraph after current one\n body.content.splice(blockIndex + 1, 0, newParagraph);\n\n return newDoc;\n}\n\n/**\n * Merge paragraphs\n */\nfunction executeMergeParagraphs(doc: Document, command: MergeParagraphsCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n const startBlockIndex = getBlockIndexForParagraph(body, command.paragraphIndex);\n if (startBlockIndex === -1) {\n throw new Error(`Paragraph index ${command.paragraphIndex} not found`);\n }\n\n const baseParagraph = body.content[startBlockIndex] as Paragraph;\n\n // Collect all content from paragraphs to merge\n const indicesToRemove: number[] = [];\n\n for (let i = 1; i <= command.count; i++) {\n const blockIndex = getBlockIndexForParagraph(body, command.paragraphIndex + i);\n if (blockIndex !== -1) {\n const para = body.content[blockIndex] as Paragraph;\n baseParagraph.content.push(...para.content);\n indicesToRemove.push(blockIndex);\n }\n }\n\n // Remove merged paragraphs in reverse order\n for (let i = indicesToRemove.length - 1; i >= 0; i--) {\n body.content.splice(indicesToRemove[i], 1);\n }\n\n return newDoc;\n}\n\n/**\n * Split a paragraph at a position\n */\nfunction executeSplitParagraph(doc: Document, command: SplitParagraphCommand): Document {\n // Split is the same as insert paragraph break\n return executeInsertParagraphBreak(doc, {\n type: 'insertParagraphBreak',\n position: command.position,\n });\n}\n\n/**\n * Set a template variable value\n */\nfunction executeSetVariable(doc: Document, command: SetVariableCommand): Document {\n const newDoc = cloneDocument(doc);\n\n // Store variable in document for later application\n if (!newDoc.templateVariables) {\n newDoc.templateVariables = [];\n }\n\n if (!newDoc.templateVariables.includes(command.name)) {\n newDoc.templateVariables.push(command.name);\n }\n\n // Note: Actual variable substitution happens in applyVariables\n return newDoc;\n}\n\n/**\n * Apply all template variables\n */\nfunction executeApplyVariables(doc: Document, command: ApplyVariablesCommand): Document {\n const newDoc = cloneDocument(doc);\n const body = newDoc.package.document;\n\n // Replace {variable} patterns in all text content\n function replaceVariablesInRun(run: Run): void {\n for (const content of run.content) {\n if (content.type === 'text') {\n for (const [name, value] of Object.entries(command.values)) {\n const pattern = new RegExp(`\\\\{${name}\\\\}`, 'g');\n content.text = content.text.replace(pattern, value);\n }\n }\n }\n }\n\n function replaceVariablesInParagraph(paragraph: Paragraph): void {\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n replaceVariablesInRun(item);\n } else if (item.type === 'hyperlink') {\n for (const child of item.children) {\n if (child.type === 'run') {\n replaceVariablesInRun(child);\n }\n }\n }\n }\n }\n\n function replaceVariablesInBlock(block: BlockContent): void {\n if (block.type === 'paragraph') {\n replaceVariablesInParagraph(block);\n } else if (block.type === 'table') {\n for (const row of block.rows) {\n for (const cell of row.cells) {\n for (const cellBlock of cell.content) {\n replaceVariablesInBlock(cellBlock);\n }\n }\n }\n }\n }\n\n for (const block of body.content) {\n replaceVariablesInBlock(block);\n }\n\n return newDoc;\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport default executeCommand;\n","/**\n * Core MCP Tools\n *\n * Built-in MCP tools for document operations that are always available.\n * These provide basic document manipulation without requiring plugins.\n */\n\nimport type {\n McpToolDefinition,\n McpToolContext,\n McpToolResult,\n JsonSchema,\n} from '../core-plugins/types';\nimport { parseDocx } from '../docx/parser';\nimport { repackDocx, createDocx } from '../docx/rezip';\nimport { executeCommand } from '../agent/executor';\n\n// ============================================================================\n// SCHEMAS\n// ============================================================================\n\nconst documentIdSchema: JsonSchema = {\n type: 'string',\n description: 'Document ID returned from docx_load',\n};\n\nconst positionSchema: JsonSchema = {\n type: 'object',\n properties: {\n paragraphIndex: {\n type: 'number',\n description: 'Index of the paragraph (0-indexed)',\n minimum: 0,\n },\n offset: {\n type: 'number',\n description: 'Character offset within the paragraph',\n minimum: 0,\n },\n },\n required: ['paragraphIndex', 'offset'],\n};\n\nconst rangeSchema: JsonSchema = {\n type: 'object',\n properties: {\n start: positionSchema,\n end: positionSchema,\n },\n required: ['start', 'end'],\n};\n\n// ============================================================================\n// DOCUMENT LOADING/SAVING\n// ============================================================================\n\n/**\n * Load a DOCX document from base64\n */\nexport const loadDocumentTool: McpToolDefinition = {\n name: 'docx_load',\n description: `Load a DOCX document from base64-encoded content.\nReturns a document ID that can be used with other tools.\nThe document remains in session memory until closed.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'Base64-encoded DOCX file content',\n },\n source: {\n type: 'string',\n description: 'Optional source filename or identifier for reference',\n },\n },\n required: ['content'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { content, source } = input as { content: string; source?: string };\n\n try {\n // Decode base64 to ArrayBuffer\n const binaryString = atob(content);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n const buffer = bytes.buffer;\n\n // Parse the document\n const document = await parseDocx(buffer);\n\n // Generate document ID\n const docId = `doc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n // Store in session\n context.session.documents.set(docId, {\n id: docId,\n document,\n buffer,\n source,\n lastModified: Date.now(),\n });\n\n // Get basic info\n const paragraphCount = document.package.document.content.filter(\n (b) => b.type === 'paragraph'\n ).length;\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n documentId: docId,\n source,\n paragraphCount,\n message: 'Document loaded successfully',\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to load document: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'low',\n },\n};\n\n/**\n * Save a document to base64\n */\nexport const saveDocumentTool: McpToolDefinition = {\n name: 'docx_save',\n description: `Export the document to base64-encoded DOCX format.\nReturns the document as a base64 string that can be saved to a file.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n },\n required: ['documentId'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId } = input as { documentId: string };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n try {\n // Repack or create the DOCX\n let buffer: ArrayBuffer;\n if (loaded.buffer) {\n // Preserve original structure\n buffer = await repackDocx(loaded.document);\n } else {\n // Create from scratch\n buffer = await createDocx(loaded.document);\n }\n\n // Encode to base64\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n const base64 = btoa(binary);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n documentId,\n base64,\n size: buffer.byteLength,\n message: 'Document exported successfully',\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to save document: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: true,\n complexity: 'low',\n },\n};\n\n/**\n * Close a document\n */\nexport const closeDocumentTool: McpToolDefinition = {\n name: 'docx_close',\n description: `Close a document and free its memory.\nUse this when done working with a document.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n },\n required: ['documentId'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId } = input as { documentId: string };\n\n if (!context.session.documents.has(documentId)) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n context.session.documents.delete(documentId);\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n documentId,\n message: 'Document closed',\n }),\n },\n ],\n };\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'low',\n },\n};\n\n// ============================================================================\n// DOCUMENT INFORMATION\n// ============================================================================\n\n/**\n * Get document information\n */\nexport const getDocumentInfoTool: McpToolDefinition = {\n name: 'docx_get_info',\n description: `Get metadata and statistics about a document.\nReturns paragraph count, word count, table count, and other useful info.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n },\n required: ['documentId'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId } = input as { documentId: string };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n const doc = loaded.document;\n const body = doc.package.document;\n\n const paragraphs = body.content.filter((b) => b.type === 'paragraph');\n const tables = body.content.filter((b) => b.type === 'table');\n\n // Count words\n let wordCount = 0;\n for (const para of paragraphs) {\n if (para.type === 'paragraph') {\n const text = getParagraphText(para);\n wordCount += text.split(/\\s+/).filter((w) => w.length > 0).length;\n }\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n documentId,\n paragraphCount: paragraphs.length,\n tableCount: tables.length,\n wordCount,\n hasStyles: !!doc.package.styles,\n hasTheme: !!doc.package.theme,\n source: loaded.source,\n lastModified: loaded.lastModified,\n }),\n },\n ],\n };\n },\n\n annotations: {\n category: 'core',\n readOnly: true,\n complexity: 'low',\n },\n};\n\n/**\n * Get document plain text\n */\nexport const getDocumentTextTool: McpToolDefinition = {\n name: 'docx_get_text',\n description: `Get the plain text content of the document.\nReturns all text concatenated with paragraph breaks.\nUseful for understanding document content before making edits.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n maxLength: {\n type: 'number',\n description: 'Maximum characters to return (default: 10000)',\n default: 10000,\n },\n },\n required: ['documentId'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId, maxLength = 10000 } = input as {\n documentId: string;\n maxLength?: number;\n };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n const body = loaded.document.package.document;\n const texts: string[] = [];\n\n for (const block of body.content) {\n if (block.type === 'paragraph') {\n texts.push(getParagraphText(block));\n } else if (block.type === 'table') {\n texts.push('[TABLE]');\n }\n }\n\n let text = texts.join('\\n');\n const truncated = text.length > maxLength;\n if (truncated) {\n text = text.slice(0, maxLength) + '...';\n }\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n documentId,\n text,\n truncated,\n totalLength: truncated ? texts.join('\\n').length : text.length,\n }),\n },\n ],\n };\n },\n\n annotations: {\n category: 'core',\n readOnly: true,\n complexity: 'low',\n },\n};\n\n// ============================================================================\n// TEXT MANIPULATION\n// ============================================================================\n\n/**\n * Insert text at a position\n */\nexport const insertTextTool: McpToolDefinition = {\n name: 'docx_insert_text',\n description: `Insert text at a specific position in the document.\nPosition is specified by paragraph index (0-indexed) and character offset.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n position: positionSchema,\n text: {\n type: 'string',\n description: 'Text to insert',\n },\n },\n required: ['documentId', 'position', 'text'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId, position, text } = input as {\n documentId: string;\n position: { paragraphIndex: number; offset: number };\n text: string;\n };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n try {\n const newDoc = executeCommand(loaded.document, {\n type: 'insertText',\n position,\n text,\n });\n\n loaded.document = newDoc;\n loaded.lastModified = Date.now();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: true,\n insertedLength: text.length,\n position,\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to insert text: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'low',\n },\n};\n\n/**\n * Replace text in a range\n */\nexport const replaceTextTool: McpToolDefinition = {\n name: 'docx_replace_text',\n description: `Replace text in a range with new text.\nSpecify start and end positions to define the range to replace.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n range: rangeSchema,\n text: {\n type: 'string',\n description: 'Replacement text',\n },\n },\n required: ['documentId', 'range', 'text'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId, range, text } = input as {\n documentId: string;\n range: {\n start: { paragraphIndex: number; offset: number };\n end: { paragraphIndex: number; offset: number };\n };\n text: string;\n };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n try {\n const newDoc = executeCommand(loaded.document, {\n type: 'replaceText',\n range,\n text,\n });\n\n loaded.document = newDoc;\n loaded.lastModified = Date.now();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: true,\n replacedRange: range,\n newTextLength: text.length,\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to replace text: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'low',\n },\n};\n\n/**\n * Delete text in a range\n */\nexport const deleteTextTool: McpToolDefinition = {\n name: 'docx_delete_text',\n description: `Delete text in a range.\nSpecify start and end positions to define the range to delete.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n range: rangeSchema,\n },\n required: ['documentId', 'range'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId, range } = input as {\n documentId: string;\n range: {\n start: { paragraphIndex: number; offset: number };\n end: { paragraphIndex: number; offset: number };\n };\n };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n try {\n const newDoc = executeCommand(loaded.document, {\n type: 'deleteText',\n range,\n });\n\n loaded.document = newDoc;\n loaded.lastModified = Date.now();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: true,\n deletedRange: range,\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to delete text: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'low',\n },\n};\n\n// ============================================================================\n// FORMATTING\n// ============================================================================\n\n/**\n * Apply text formatting\n */\nexport const formatTextTool: McpToolDefinition = {\n name: 'docx_format_text',\n description: `Apply formatting to text in a range.\nSupports bold, italic, underline, font size, font family, color, and highlight.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n range: rangeSchema,\n formatting: {\n type: 'object',\n description: 'Formatting options to apply',\n properties: {\n bold: { type: 'boolean' },\n italic: { type: 'boolean' },\n underline: { type: 'boolean' },\n strikethrough: { type: 'boolean' },\n fontSize: { type: 'number', description: 'Font size in points' },\n fontFamily: { type: 'string' },\n color: { type: 'string', description: 'Hex color (e.g., \"#FF0000\")' },\n highlight: { type: 'string', description: 'Highlight color name' },\n },\n },\n },\n required: ['documentId', 'range', 'formatting'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId, range, formatting } = input as {\n documentId: string;\n range: {\n start: { paragraphIndex: number; offset: number };\n end: { paragraphIndex: number; offset: number };\n };\n formatting: Record<string, unknown>;\n };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n try {\n const newDoc = executeCommand(loaded.document, {\n type: 'formatText',\n range,\n formatting,\n });\n\n loaded.document = newDoc;\n loaded.lastModified = Date.now();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: true,\n range,\n appliedFormatting: formatting,\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to format text: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'medium',\n },\n};\n\n/**\n * Apply paragraph style\n */\nexport const applyStyleTool: McpToolDefinition = {\n name: 'docx_apply_style',\n description: `Apply a named style to a paragraph.\nUse document styles like \"Heading1\", \"Heading2\", \"Normal\", etc.`,\n\n inputSchema: {\n type: 'object',\n properties: {\n documentId: documentIdSchema,\n paragraphIndex: {\n type: 'number',\n description: 'Index of the paragraph (0-indexed)',\n minimum: 0,\n },\n styleId: {\n type: 'string',\n description: 'Style ID (e.g., \"Heading1\", \"Normal\")',\n },\n },\n required: ['documentId', 'paragraphIndex', 'styleId'],\n },\n\n handler: async (input: unknown, context: McpToolContext): Promise<McpToolResult> => {\n const { documentId, paragraphIndex, styleId } = input as {\n documentId: string;\n paragraphIndex: number;\n styleId: string;\n };\n\n const loaded = context.session.documents.get(documentId);\n if (!loaded) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Document not found: ${documentId}` }],\n };\n }\n\n try {\n const newDoc = executeCommand(loaded.document, {\n type: 'applyStyle',\n paragraphIndex,\n styleId,\n });\n\n loaded.document = newDoc;\n loaded.lastModified = Date.now();\n\n return {\n content: [\n {\n type: 'text',\n text: JSON.stringify({\n success: true,\n paragraphIndex,\n styleId,\n }),\n },\n ],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: 'text', text: `Failed to apply style: ${(error as Error).message}` }],\n };\n }\n },\n\n annotations: {\n category: 'core',\n readOnly: false,\n complexity: 'low',\n },\n};\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\nimport type { Paragraph, Run, Hyperlink } from '../types/document';\n\nfunction getParagraphText(paragraph: Paragraph): string {\n const texts: string[] = [];\n\n for (const item of paragraph.content) {\n if (item.type === 'run') {\n texts.push(getRunText(item));\n } else if (item.type === 'hyperlink') {\n texts.push(getHyperlinkText(item));\n }\n }\n\n return texts.join('');\n}\n\nfunction getRunText(run: Run): string {\n return run.content\n .filter((c) => c.type === 'text')\n .map((c) => (c as { type: 'text'; text: string }).text)\n .join('');\n}\n\nfunction getHyperlinkText(hyperlink: Hyperlink): string {\n const texts: string[] = [];\n for (const child of hyperlink.children) {\n if (child.type === 'run') {\n texts.push(getRunText(child));\n }\n }\n return texts.join('');\n}\n\n// ============================================================================\n// EXPORT ALL CORE TOOLS\n// ============================================================================\n\nexport const coreMcpTools: McpToolDefinition[] = [\n // Document loading/saving\n loadDocumentTool,\n saveDocumentTool,\n closeDocumentTool,\n\n // Document information\n getDocumentInfoTool,\n getDocumentTextTool,\n\n // Text manipulation\n insertTextTool,\n replaceTextTool,\n deleteTextTool,\n\n // Formatting\n formatTextTool,\n applyStyleTool,\n];\n\nexport default coreMcpTools;\n","/**\n * MCP Server\n *\n * Model Context Protocol server that exposes document editing tools to AI clients.\n * Discovers and registers tools from the plugin system plus core built-in tools.\n *\n * @example\n * ```ts\n * import { createMcpServer, startStdioServer } from '@eigenpal/docx-editor/mcp';\n * import { pluginRegistry, docxtemplaterPlugin } from '@eigenpal/docx-editor/core-plugins';\n *\n * // Register plugins\n * pluginRegistry.register(docxtemplaterPlugin);\n *\n * // Start MCP server\n * startStdioServer();\n * ```\n */\n\nimport type {\n McpToolDefinition,\n McpToolContext,\n McpSession,\n LoadedDocument,\n JsonSchema,\n} from '../core-plugins/types';\nimport { pluginRegistry } from '../core-plugins/registry';\nimport { coreMcpTools } from './core-tools';\n\n// ============================================================================\n// TYPES\n// ============================================================================\n\n/**\n * MCP Server configuration\n */\nexport interface McpServerConfig {\n /** Server name */\n name?: string;\n\n /** Server version */\n version?: string;\n\n /** Include core tools (default: true) */\n includeCoreTools?: boolean;\n\n /** Enable debug logging */\n debug?: boolean;\n\n /** Custom tools to add */\n additionalTools?: McpToolDefinition[];\n}\n\n/**\n * MCP Server instance\n */\nexport interface McpServer {\n /** All registered tools */\n tools: Map<string, McpToolDefinition>;\n\n /** Active session */\n session: McpSession;\n\n /** Handle a tool call */\n handleToolCall(toolName: string, input: unknown): Promise<unknown>;\n\n /** List available tools */\n listTools(): McpToolInfo[];\n\n /** Get server info */\n getInfo(): { name: string; version: string; toolCount: number };\n}\n\n/**\n * Tool info for listing\n */\nexport interface McpToolInfo {\n name: string;\n description: string;\n inputSchema: JsonSchema;\n category?: string;\n}\n\n// ============================================================================\n// SERVER CREATION\n// ============================================================================\n\n/**\n * Create an MCP server instance\n *\n * @param config - Server configuration\n * @returns MCP server instance\n */\nexport function createMcpServer(config: McpServerConfig = {}): McpServer {\n const {\n name = 'docx-editor',\n version = '0.1.0',\n includeCoreTools = true,\n debug = false,\n additionalTools = [],\n } = config;\n\n const tools = new Map<string, McpToolDefinition>();\n\n // Create session\n const session: McpSession = {\n id: `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n documents: new Map<string, LoadedDocument>(),\n data: new Map<string, unknown>(),\n };\n\n // Register core tools\n if (includeCoreTools) {\n for (const tool of coreMcpTools) {\n tools.set(tool.name, tool);\n if (debug) {\n console.log(`[MCP] Registered core tool: ${tool.name}`);\n }\n }\n }\n\n // Register plugin tools\n const pluginTools = pluginRegistry.getMcpTools();\n for (const tool of pluginTools) {\n if (tools.has(tool.name)) {\n console.warn(`[MCP] Tool '${tool.name}' from plugin overrides existing tool`);\n }\n tools.set(tool.name, tool);\n if (debug) {\n console.log(`[MCP] Registered plugin tool: ${tool.name}`);\n }\n }\n\n // Register additional tools\n for (const tool of additionalTools) {\n tools.set(tool.name, tool);\n if (debug) {\n console.log(`[MCP] Registered additional tool: ${tool.name}`);\n }\n }\n\n // Create logger\n const log = debug\n ? (message: string, data?: unknown) => {\n console.log(`[MCP] ${message}`, data ?? '');\n }\n : () => {};\n\n // Handle tool call\n async function handleToolCall(toolName: string, input: unknown): Promise<unknown> {\n const tool = tools.get(toolName);\n if (!tool) {\n throw new Error(`Unknown tool: ${toolName}`);\n }\n\n log(`Calling tool: ${toolName}`, input);\n\n // Create context\n const context: McpToolContext = {\n session,\n log,\n };\n\n // Execute handler\n try {\n const result = await tool.handler(input, context);\n log(`Tool ${toolName} completed`, result);\n return result;\n } catch (error) {\n log(`Tool ${toolName} failed`, error);\n throw error;\n }\n }\n\n // List tools\n function listTools(): McpToolInfo[] {\n return Array.from(tools.values()).map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: convertToJsonSchema(tool.inputSchema),\n category: tool.annotations?.category,\n }));\n }\n\n // Get info\n function getInfo() {\n return {\n name,\n version,\n toolCount: tools.size,\n };\n }\n\n return {\n tools,\n session,\n handleToolCall,\n listTools,\n getInfo,\n };\n}\n\n// ============================================================================\n// JSON-RPC PROTOCOL\n// ============================================================================\n\n/**\n * JSON-RPC request\n */\ninterface JsonRpcRequest {\n jsonrpc: '2.0';\n id: string | number;\n method: string;\n params?: unknown;\n}\n\n/**\n * JSON-RPC response\n */\ninterface JsonRpcResponse {\n jsonrpc: '2.0';\n id: string | number;\n result?: unknown;\n error?: {\n code: number;\n message: string;\n data?: unknown;\n };\n}\n\n/**\n * Handle a JSON-RPC request\n */\nexport async function handleJsonRpcRequest(\n server: McpServer,\n request: JsonRpcRequest\n): Promise<JsonRpcResponse> {\n const { id, method, params } = request;\n\n try {\n switch (method) {\n case 'initialize': {\n return {\n jsonrpc: '2.0',\n id,\n result: {\n protocolVersion: '2024-11-05',\n capabilities: {\n tools: {},\n },\n serverInfo: server.getInfo(),\n },\n };\n }\n\n case 'tools/list': {\n const tools = server.listTools();\n return {\n jsonrpc: '2.0',\n id,\n result: {\n tools: tools.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n })),\n },\n };\n }\n\n case 'tools/call': {\n const { name, arguments: args } = params as {\n name: string;\n arguments: unknown;\n };\n const result = await server.handleToolCall(name, args);\n return {\n jsonrpc: '2.0',\n id,\n result,\n };\n }\n\n default:\n return {\n jsonrpc: '2.0',\n id,\n error: {\n code: -32601,\n message: `Method not found: ${method}`,\n },\n };\n }\n } catch (error) {\n return {\n jsonrpc: '2.0',\n id,\n error: {\n code: -32000,\n message: (error as Error).message,\n },\n };\n }\n}\n\n// ============================================================================\n// STDIO TRANSPORT\n// ============================================================================\n\n/**\n * Start the MCP server with stdio transport\n *\n * Reads JSON-RPC requests from stdin, writes responses to stdout.\n * This is the standard way to run an MCP server for Claude Desktop.\n */\nexport async function startStdioServer(config: McpServerConfig = {}): Promise<void> {\n const server = createMcpServer(config);\n\n if (config.debug) {\n console.error(`[MCP] Server started: ${server.getInfo().name} v${server.getInfo().version}`);\n console.error(`[MCP] Tools registered: ${server.tools.size}`);\n }\n\n // Read from stdin\n const readline = await import('readline');\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: false,\n });\n\n let buffer = '';\n\n rl.on('line', async (line) => {\n buffer += line;\n\n // Try to parse complete JSON\n try {\n const request = JSON.parse(buffer) as JsonRpcRequest;\n buffer = '';\n\n const response = await handleJsonRpcRequest(server, request);\n\n // Write response to stdout\n process.stdout.write(JSON.stringify(response) + '\\n');\n } catch {\n // Incomplete JSON, wait for more\n }\n });\n\n rl.on('close', () => {\n if (config.debug) {\n console.error('[MCP] Server closed');\n }\n process.exit(0);\n });\n}\n\n// ============================================================================\n// HELPER FUNCTIONS\n// ============================================================================\n\n/**\n * Convert schema to JSON Schema format\n */\nfunction convertToJsonSchema(schema: JsonSchema | unknown): JsonSchema {\n // If it's already a JSON Schema object, return it\n if (\n typeof schema === 'object' &&\n schema !== null &&\n ('type' in schema || 'properties' in schema)\n ) {\n return schema as JsonSchema;\n }\n\n // If it's a Zod-like schema, try to convert\n // For now, just return a basic object schema\n return {\n type: 'object',\n properties: {},\n };\n}\n\n// ============================================================================\n// EXPORTS\n// ============================================================================\n\nexport { coreMcpTools } from './core-tools';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACuCO,IAAM,iBAAN,MAAqB;AAAA,EAArB;AACL,wBAAQ,WAAmC,oBAAI,IAAI;AACnD,wBAAQ,mBAA8E,oBAAI,IAAI;AAC9F,wBAAQ,kBAA2C,oBAAI,IAAI;AAC3D,wBAAQ,eAA2B,oBAAI,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAa3C,SAAS,QAAoB,SAAmD;AAC9E,UAAM,WAAqB,CAAC;AAG5B,QAAI,CAAC,OAAO,IAAI;AACd,aAAO,EAAE,SAAS,OAAO,OAAO,yBAAyB;AAAA,IAC3D;AAEA,QAAI,KAAK,QAAQ,IAAI,OAAO,EAAE,GAAG;AAC/B,aAAO,EAAE,SAAS,OAAO,OAAO,WAAW,OAAO,EAAE,0BAA0B;AAAA,IAChF;AAGA,QAAI,OAAO,cAAc;AACvB,iBAAW,SAAS,OAAO,cAAc;AACvC,YAAI,CAAC,KAAK,QAAQ,IAAI,KAAK,GAAG;AAC5B,iBAAO;AAAA,YACL,SAAS;AAAA,YACT,OAAO,WAAW,OAAO,EAAE,eAAe,KAAK;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,OAAO,iBAAiB;AAC1B,iBAAW,CAAC,aAAa,OAAO,KAAK,OAAO,QAAQ,OAAO,eAAe,GAAG;AAC3E,YAAI,KAAK,gBAAgB,IAAI,WAAW,GAAG;AACzC,gBAAM,WAAW,KAAK,gBAAgB,IAAI,WAAW;AACrD,mBAAS;AAAA,YACP,YAAY,WAAW,WAAW,OAAO,EAAE,6BAA6B,SAAS,QAAQ;AAAA,UAC3F;AAAA,QACF;AACA,aAAK,gBAAgB,IAAI,aAAa,EAAE,UAAU,OAAO,IAAI,QAAQ,CAAC;AAAA,MACxE;AAAA,IACF;AAGA,SAAK,QAAQ,IAAI,OAAO,IAAI,MAAM;AAGlC,QAAI,OAAO,cAAc,CAAC,KAAK,YAAY,IAAI,OAAO,EAAE,GAAG;AACzD,UAAI;AACF,cAAM,SAAS,OAAO,WAAW;AACjC,YAAI,kBAAkB,SAAS;AAE7B,iBACG,KAAK,MAAM;AACV,iBAAK,YAAY,IAAI,OAAO,EAAE;AAAA,UAChC,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,iBAAK,KAAK,EAAE,MAAM,SAAS,UAAU,OAAO,IAAI,OAAO,IAAa,CAAC;AAAA,UACvE,CAAC;AAAA,QACL,OAAO;AACL,eAAK,YAAY,IAAI,OAAO,EAAE;AAAA,QAChC;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,KAAK,EAAE,MAAM,SAAS,UAAU,OAAO,IAAI,OAAO,IAAa,CAAC;AAAA,MACvE;AAAA,IACF;AAGA,QAAI,SAAS,OAAO;AAClB,cAAQ,IAAI,uCAAuC,OAAO,EAAE,EAAE;AAAA,IAChE;AAGA,SAAK,KAAK,EAAE,MAAM,cAAc,OAAO,CAAC;AAExC,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,IAC7C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,UAA2B;AACpC,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACxC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAGA,eAAW,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS;AAClC,UAAI,EAAE,cAAc,SAAS,QAAQ,GAAG;AACtC,gBAAQ,KAAK,sBAAsB,QAAQ,OAAO,EAAE,iBAAiB;AACrE,eAAO;AAAA,MACT;AAAA,IACF;AAGA,eAAW,CAAC,aAAa,EAAE,UAAU,IAAI,CAAC,KAAK,KAAK,iBAAiB;AACnE,UAAI,QAAQ,UAAU;AACpB,aAAK,gBAAgB,OAAO,WAAW;AAAA,MACzC;AAAA,IACF;AAGA,QAAI,OAAO,SAAS;AAClB,UAAI;AACF,cAAM,SAAS,OAAO,QAAQ;AAC9B,YAAI,kBAAkB,SAAS;AAC7B,iBAAO,MAAM,CAAC,QAAQ;AACpB,iBAAK,KAAK,EAAE,MAAM,SAAS,UAAU,OAAO,IAAa,CAAC;AAAA,UAC5D,CAAC;AAAA,QACH;AAAA,MACF,SAAS,KAAK;AACZ,aAAK,KAAK,EAAE,MAAM,SAAS,UAAU,OAAO,IAAa,CAAC;AAAA,MAC5D;AAAA,IACF;AAGA,SAAK,QAAQ,OAAO,QAAQ;AAC5B,SAAK,YAAY,OAAO,QAAQ;AAGhC,SAAK,KAAK,EAAE,MAAM,gBAAgB,SAAS,CAAC;AAE5C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAI,IAAoC;AACtC,WAAO,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,SAAuB;AACrB,WAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,IAAqB;AACvB,WAAO,KAAK,QAAQ,IAAI,EAAE;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,kBAAkB,aAAiD;AACjE,UAAM,QAAQ,KAAK,gBAAgB,IAAI,WAAW;AAClD,WAAO,OAAO;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAA4B;AAC1B,WAAO,MAAM,KAAK,KAAK,gBAAgB,KAAK,CAAC;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,kBAAkB,aAA8B;AAC9C,WAAO,KAAK,gBAAgB,IAAI,WAAW;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,cAAmC;AACjC,UAAM,QAA6B,CAAC;AAEpC,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,UAAI,OAAO,UAAU;AACnB,cAAM,KAAK,GAAG,OAAO,QAAQ;AAAA,MAC/B;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,qBAAqB,UAAuC;AAC1D,UAAM,SAAS,KAAK,QAAQ,IAAI,QAAQ;AACxC,WAAO,QAAQ,YAAY,CAAC;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,UAAiD;AAC1D,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,UAAI,OAAO,UAAU;AACnB,cAAM,OAAO,OAAO,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AAC5D,YAAI,KAAM,QAAO;AAAA,MACnB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,iBAAiB,UAAqC;AACpD,SAAK,eAAe,IAAI,QAAQ;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAAoB,UAAqC;AACvD,SAAK,eAAe,OAAO,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKQ,KAAK,OAA0B;AACrC,eAAW,YAAY,KAAK,gBAAgB;AAC1C,UAAI;AACF,iBAAS,KAAK;AAAA,MAChB,SAAS,KAAK;AACZ,gBAAQ,MAAM,0CAA0C,GAAG;AAAA,MAC7D;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,QAAc;AAEZ,eAAW,UAAU,KAAK,QAAQ,OAAO,GAAG;AAC1C,UAAI,OAAO,SAAS;AAClB,YAAI;AACF,iBAAO,QAAQ;AAAA,QACjB,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF;AAEA,SAAK,QAAQ,MAAM;AACnB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,YAAY,MAAM;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA,EAKA,eAKE;AACA,WAAO;AAAA,MACL,SAAS,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC;AAAA,MACvC,cAAc,MAAM,KAAK,KAAK,gBAAgB,KAAK,CAAC;AAAA,MACpD,UAAU,KAAK,YAAY,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,MAC9C,aAAa,MAAM,KAAK,KAAK,WAAW;AAAA,IAC1C;AAAA,EACF;AACF;AAWO,IAAM,iBAAiB,IAAI,eAAe;;;AC/WjD,mBAAkB;AA8DlB,eAAsB,UAAU,QAA8C;AAC5E,QAAM,MAAM,MAAM,aAAAA,QAAM,UAAU,MAAM;AAExC,QAAM,UAA0B;AAAA,IAC9B,aAAa;AAAA,IACb,WAAW;AAAA,IACX,UAAU;AAAA,IACV,cAAc;AAAA,IACd,cAAc;AAAA,IACd,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,SAAS,oBAAI,IAAI;AAAA,IACjB,SAAS,oBAAI,IAAI;AAAA,IACjB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,aAAa;AAAA,IACb,cAAc;AAAA,IACd,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,OAAO,oBAAI,IAAI;AAAA,IACf,OAAO,oBAAI,IAAI;AAAA,IACf,QAAQ,oBAAI,IAAI;AAAA,IAChB,aAAa;AAAA,IACb,gBAAgB;AAAA,EAClB;AAGA,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,IAAI,KAAK,GAAG;AAEpD,QAAI,KAAK,IAAK;AAEd,UAAM,YAAY,KAAK,YAAY;AAGnC,QAAI,UAAU,SAAS,MAAM,KAAK,UAAU,SAAS,OAAO,GAAG;AAC7D,YAAM,aAAa,MAAM,KAAK,MAAM,MAAM;AAC1C,cAAQ,OAAO,IAAI,MAAM,UAAU;AAGnC,UAAI,cAAc,qBAAqB;AACrC,gBAAQ,cAAc;AAAA,MACxB,WAAW,cAAc,mBAAmB;AAC1C,gBAAQ,YAAY;AAAA,MACtB,WAAW,cAAc,yBAAyB;AAChD,gBAAQ,WAAW;AAAA,MACrB,WAAW,cAAc,sBAAsB;AAC7C,gBAAQ,eAAe;AAAA,MACzB,WAAW,cAAc,sBAAsB;AAC7C,gBAAQ,eAAe;AAAA,MACzB,WAAW,cAAc,qBAAqB;AAC5C,gBAAQ,cAAc;AAAA,MACxB,WAAW,cAAc,wBAAwB;AAC/C,gBAAQ,iBAAiB;AAAA,MAC3B,WAAW,cAAc,sBAAsB;AAC7C,gBAAQ,eAAe;AAAA,MACzB,WAAW,cAAc,qBAAqB;AAC5C,gBAAQ,cAAc;AAAA,MACxB,WAAW,cAAc,qBAAqB;AAC5C,gBAAQ,cAAc;AAAA,MACxB,WAAW,cAAc,gCAAgC;AACvD,gBAAQ,eAAe;AAAA,MACzB,WAAW,cAAc,eAAe;AACtC,gBAAQ,cAAc;AAAA,MACxB,WAAW,cAAc,uBAAuB;AAC9C,gBAAQ,kBAAkB;AAAA,MAC5B,WAAW,cAAc,qBAAqB;AAC5C,gBAAQ,eAAe;AAAA,MACzB,WAAW,cAAc,oBAAoB;AAC3C,gBAAQ,cAAc;AAAA,MACxB,WAAW,cAAc,uBAAuB;AAC9C,gBAAQ,iBAAiB;AAAA,MAC3B,WAAW,UAAU,MAAM,wBAAwB,GAAG;AACpD,cAAM,WAAW,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AAC1C,gBAAQ,QAAQ,IAAI,UAAU,UAAU;AAAA,MAC1C,WAAW,UAAU,MAAM,wBAAwB,GAAG;AACpD,cAAM,WAAW,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AAC1C,gBAAQ,QAAQ,IAAI,UAAU,UAAU;AAAA,MAC1C;AAAA,IACF,WAAW,UAAU,WAAW,aAAa,GAAG;AAE9C,YAAM,gBAAgB,MAAM,KAAK,MAAM,aAAa;AACpD,cAAQ,MAAM,IAAI,MAAM,aAAa;AAAA,IACvC,WAAW,UAAU,WAAW,aAAa,GAAG;AAE9C,YAAM,gBAAgB,MAAM,KAAK,MAAM,aAAa;AACpD,cAAQ,MAAM,IAAI,MAAM,aAAa;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AA0BO,SAAS,iBAAiB,MAAsB;AACrD,QAAM,MAAM,KAAK,YAAY,EAAE,MAAM,GAAG,EAAE,IAAI;AAE9C,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;;;ACrNA,oBAAmD;AAmD5C,SAAS,SAAS,KAAyB;AAChD,QAAM,aAAS,sBAAO,KAAK;AAAA,IACzB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,eAAe;AAAA,IACf,aAAa;AAAA;AAAA;AAAA;AAAA,IAIb,MAAM;AAAA,IACN,eAAe;AAAA,IACf,SAAS;AAAA,EACX,CAAC;AAED,SAAO;AACT;AAKO,SAAS,iBAAiB,KAAgC;AAC/D,MAAI;AACF,UAAM,SAAS,SAAS,GAAG;AAG3B,QAAI,OAAO,YAAY,OAAO,SAAS,SAAS,GAAG;AAEjD,aAAO,OAAO,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,KAAK;AAAA,IAC9D;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,YAAQ,KAAK,wBAAwB,KAAK;AAC1C,WAAO;AAAA,EACT;AACF;AAMO,SAAS,aAAa,MAAsB;AACjD,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,SAAO,cAAc,IAAI,KAAK,UAAU,aAAa,CAAC,IAAI;AAC5D;AAsCO,SAAS,UACd,QACA,WACA,WACmB;AACnB,MAAI,CAAC,UAAU,CAAC,OAAO,SAAU,QAAO;AAExC,QAAM,WAAW,GAAG,SAAS,IAAI,SAAS;AAE1C,aAAW,SAAS,OAAO,UAAU;AACnC,QAAI,MAAM,SAAS,UAAW;AAE9B,QAAI,MAAM,SAAS,UAAU;AAC3B,aAAO;AAAA,IACT;AAGA,QAAI,aAAa,MAAM,QAAQ,EAAE,MAAM,WAAW;AAChD,aAAO;AAAA,IACT;AAAA,EACF;AAEA,SAAO;AACT;AAUO,SAAS,aACd,QACA,WACA,WACc;AACd,MAAI,CAAC,UAAU,CAAC,OAAO,SAAU,QAAO,CAAC;AAEzC,QAAM,WAAW,GAAG,SAAS,IAAI,SAAS;AAC1C,QAAM,UAAwB,CAAC;AAE/B,aAAW,SAAS,OAAO,UAAU;AACnC,QAAI,MAAM,SAAS,UAAW;AAE9B,QAAI,MAAM,SAAS,YAAY,aAAa,MAAM,QAAQ,EAAE,MAAM,WAAW;AAC3E,cAAQ,KAAK,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;AAkDO,SAAS,iBAAiB,QAAqD;AACpF,MAAI,CAAC,UAAU,CAAC,OAAO,SAAU,QAAO,CAAC;AACzC,SAAO,OAAO,SAAS,OAAO,CAAC,UAAU,MAAM,SAAS,SAAS;AACnE;AAUO,SAAS,aACd,SACA,WACA,MACe;AACf,MAAI,CAAC,WAAW,CAAC,QAAQ,WAAY,QAAO;AAE5C,QAAM,QAAQ,QAAQ;AAGtB,MAAI,WAAW;AACb,UAAM,eAAe,GAAG,SAAS,IAAI,IAAI;AACzC,QAAI,gBAAgB,OAAO;AACzB,aAAO,MAAM,YAAY;AAAA,IAC3B;AAAA,EACF;AAGA,MAAI,QAAQ,OAAO;AACjB,WAAO,MAAM,IAAI;AAAA,EACnB;AAEA,SAAO;AACT;AA2CO,SAAS,eAAe,SAAgD;AAC7E,MAAI,CAAC,QAAS,QAAO;AAGrB,MAAI,UAAU,WAAW,OAAO,QAAQ,SAAS,UAAU;AACzD,WAAO,QAAQ;AAAA,EACjB;AAGA,MAAI,CAAC,QAAQ,SAAU,QAAO;AAE9B,MAAI,OAAO;AACX,aAAW,SAAS,QAAQ,UAAU;AACpC,QAAI,MAAM,SAAS,UAAU,UAAU,OAAO;AAC5C,cAAQ,MAAM,QAAQ;AAAA,IACxB,WAAW,MAAM,SAAS,WAAW;AAEnC,cAAQ,eAAe,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AACT;AAsDO,SAAS,kBAAkB,SAKzB;AACP,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO;AAAA,IACL,KAAK,aAAa,SAAS,KAAK,KAAK,KAAK;AAAA,IAC1C,YAAY,aAAa,SAAS,KAAK,YAAY,KAAK;AAAA,IACxD,WAAW,aAAa,SAAS,KAAK,WAAW,KAAK;AAAA,IACtD,YAAY,aAAa,SAAS,KAAK,YAAY,KAAK;AAAA,EAC1D;AACF;AAWO,SAAS,sBACd,SACA,WACA,MACA,QAAgB,GACI;AACpB,QAAM,QAAQ,aAAa,SAAS,WAAW,IAAI;AACnD,MAAI,UAAU,KAAM,QAAO;AAE3B,QAAM,MAAM,SAAS,OAAO,EAAE;AAC9B,MAAI,MAAM,GAAG,EAAG,QAAO;AAEvB,SAAO,MAAM;AACf;AAcO,SAAS,oBACd,SACA,YAAoB,KACX;AACT,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,MAAM,aAAa,SAAS,WAAW,KAAK;AAGlD,MAAI,QAAQ,KAAM,QAAO;AAGzB,MAAI,QAAQ,OAAO,QAAQ,WAAW,QAAQ,OAAO;AACnD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;;;ACncO,IAAM,qBAAqB;AAAA,EAChC,OAAO;AAAA,EACP,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AAAA,EACP,UAAU;AAAA,EACV,aAAa;AAAA,EACb,WAAW;AAAA,EACX,OAAO;AAAA,EACP,aAAa;AAAA,EACb,gBACE;AAAA,EACF,gBACE;AAAA,EACF,oBACE;AAAA,EACF,kBACE;AAAA,EACF,WAAW;AACb;AAQO,SAAS,mBAAmB,SAAkC;AACnE,QAAM,MAAuB,oBAAI,IAAI;AAErC,MAAI,CAAC,WAAW,QAAQ,KAAK,EAAE,WAAW,GAAG;AAC3C,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,iBAAiB,OAAO;AACrC,MAAI,CAAC,MAAM;AACT,YAAQ,KAAK,mCAAmC;AAChD,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,iBAAiB,IAAI;AAEtC,aAAW,SAAS,UAAU;AAE5B,UAAM,OAAO,MAAM,QAAQ;AAC3B,QAAI,CAAC,KAAK,SAAS,cAAc,KAAK,CAAC,KAAK,SAAS,eAAe,GAAG;AACrE;AAAA,IACF;AAGA,UAAM,KAAK,aAAa,OAAO,MAAM,IAAI;AACzC,UAAM,OAAO,aAAa,OAAO,MAAM,MAAM;AAC7C,UAAM,SAAS,aAAa,OAAO,MAAM,QAAQ;AACjD,UAAM,aAAa,aAAa,OAAO,MAAM,YAAY;AAEzD,QAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ;AAC3B,cAAQ,KAAK,6CAA6C,EAAE,IAAI,MAAM,OAAO,CAAC;AAC9E;AAAA,IACF;AAEA,UAAM,eAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,eAAe,YAAY;AAC7B,mBAAa,aAAa;AAAA,IAC5B,WAAW,eAAe,YAAY;AACpC,mBAAa,aAAa;AAAA,IAC5B;AAGA,QAAI,IAAI,IAAI,YAAY;AAAA,EAC1B;AAEA,SAAO;AACT;AA8BO,SAAS,oBAAoB,KAA4B;AAC9D,SAAO,IAAI,SAAS,mBAAmB,aAAa,IAAI,eAAe;AACzE;;;ACvHA,IAAM,iBAAmC;AAAA,EACvC,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,KAAK;AAAA;AAAA,EACL,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,SAAS;AAAA;AAAA,EACT,OAAO;AAAA;AAAA,EACP,UAAU;AAAA;AACZ;AAKA,IAAM,gBAAiC;AAAA,EACrC,WAAW;AAAA,IACT,OAAO;AAAA,IACP,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO,CAAC;AAAA,EACV;AAAA,EACA,WAAW;AAAA,IACT,OAAO;AAAA,IACP,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO,CAAC;AAAA,EACV;AACF;AAKA,IAAM,gBAAuB;AAAA,EAC3B,MAAM;AAAA,EACN,aAAa;AAAA,EACb,YAAY;AACd;AAKA,IAAM,cAAc;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAQA,SAASC,mBAAkB,SAA2C;AACpE,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,YAAY,aAAa,QAAQ,QAAQ,EAAE;AAEjD,UAAQ,WAAW;AAAA,IACjB,KAAK,WAAW;AAEd,YAAM,MAAM,aAAa,SAAS,KAAK,KAAK,KAAK,aAAa,SAAS,MAAM,KAAK;AAClF,aAAO,OAAO;AAAA,IAChB;AAAA,IAEA,KAAK,UAAU;AAGb,YAAM,UACJ,aAAa,SAAS,KAAK,SAAS,KAAK,aAAa,SAAS,MAAM,SAAS;AAChF,UAAI,QAAS,QAAO;AAGpB,YAAM,MAAM,aAAa,SAAS,KAAK,KAAK,KAAK,aAAa,SAAS,MAAM,KAAK;AAClF,cAAQ,KAAK;AAAA,QACX,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AAAA,QACL,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT,KAAK;AACH,iBAAO;AAAA,QACT;AACE,iBAAO;AAAA,MACX;AAAA,IACF;AAAA,IAEA,KAAK,aAAa;AAIhB,YAAM,MAAM,aAAa,SAAS,KAAK,KAAK,KAAK,aAAa,SAAS,MAAM,KAAK;AAGlF,aAAO,QAAQ,UAAU,OAAO;AAAA,IAClC;AAAA,IAEA;AACE,aAAO;AAAA,EACX;AACF;AAQA,SAAS,iBAAiB,WAAgD;AACxE,QAAM,SAA2B,EAAE,GAAG,eAAe;AAErD,MAAI,CAAC,UAAW,QAAO;AAGvB,aAAW,QAAQ,aAAa;AAE9B,UAAM,cAAc,UAAU,WAAW,KAAK,IAAI;AAElD,QAAI,aAAa;AAEf,YAAM,WAAW,iBAAiB,WAAW;AAC7C,UAAI,SAAS,SAAS,GAAG;AACvB,cAAM,QAAQA,mBAAkB,SAAS,CAAC,CAAC;AAC3C,YAAI,OAAO;AACT,iBAAO,IAAI,IAAI;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAQA,SAAS,gBAAgB,aAA2C;AAClE,QAAM,SAAoB;AAAA,IACxB,OAAO;AAAA,IACP,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO,CAAC;AAAA,EACV;AAEA,MAAI,CAAC,YAAa,QAAO;AAGzB,QAAM,UAAU,UAAU,aAAa,KAAK,OAAO;AACnD,MAAI,SAAS;AACX,WAAO,QACL,aAAa,SAAS,KAAK,UAAU,KAAK,aAAa,SAAS,MAAM,UAAU,KAAK;AAAA,EACzF;AAEA,QAAM,OAAO,UAAU,aAAa,KAAK,IAAI;AAC7C,MAAI,MAAM;AACR,WAAO,KAAK,aAAa,MAAM,KAAK,UAAU,KAAK,aAAa,MAAM,MAAM,UAAU,KAAK;AAAA,EAC7F;AAEA,QAAM,OAAO,UAAU,aAAa,KAAK,IAAI;AAC7C,MAAI,MAAM;AACR,WAAO,KAAK,aAAa,MAAM,KAAK,UAAU,KAAK,aAAa,MAAM,MAAM,UAAU,KAAK;AAAA,EAC7F;AAGA,QAAM,eAAe,aAAa,aAAa,KAAK,MAAM;AAC1D,aAAW,QAAQ,cAAc;AAC/B,UAAM,SAAS,aAAa,MAAM,KAAK,QAAQ,KAAK,aAAa,MAAM,MAAM,QAAQ;AACrF,UAAM,WAAW,aAAa,MAAM,KAAK,UAAU,KAAK,aAAa,MAAM,MAAM,UAAU;AAE3F,QAAI,UAAU,UAAU;AACtB,aAAO,QAAQ,OAAO,SAAS,CAAC;AAChC,aAAO,MAAM,MAAM,IAAI;AAAA,IACzB;AAAA,EACF;AAEA,SAAO;AACT;AAQA,SAAS,gBAAgB,YAAgD;AACvE,QAAM,SAA0B,EAAE,GAAG,cAAc;AAEnD,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,cAAc,UAAU,YAAY,KAAK,WAAW;AAC1D,MAAI,aAAa;AACf,WAAO,YAAY,gBAAgB,WAAW;AAAA,EAChD;AAEA,QAAM,cAAc,UAAU,YAAY,KAAK,WAAW;AAC1D,MAAI,aAAa;AACf,WAAO,YAAY,gBAAgB,WAAW;AAAA,EAChD;AAEA,SAAO;AACT;AAQO,SAAS,WAAW,UAAgC;AAEzD,MAAI,CAAC,UAAU;AACb,WAAO,EAAE,GAAG,cAAc;AAAA,EAC5B;AAEA,MAAI;AACF,UAAM,MAAM,iBAAiB,QAAQ;AACrC,QAAI,CAAC,KAAK;AACR,aAAO,EAAE,GAAG,cAAc;AAAA,IAC5B;AAGA,UAAM,YACJ,aAAa,KAAK,KAAK,MAAM,KAAK,aAAa,KAAK,MAAM,MAAM,KAAK;AAGvE,UAAM,gBAAgB,UAAU,KAAK,KAAK,eAAe;AAGzD,UAAM,YAAY,UAAU,eAAe,KAAK,WAAW;AAC3D,UAAM,cAAc,iBAAiB,SAAS;AAG9C,UAAM,eAAe,UAAU,eAAe,KAAK,YAAY;AAC/D,UAAM,aAAa,gBAAgB,YAAY;AAE/C,WAAO;AAAA,MACL,MAAM;AAAA,MACN;AAAA,MACA;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,KAAK,0BAA0B,KAAK;AAC5C,WAAO,EAAE,GAAG,cAAc;AAAA,EAC5B;AACF;AA2BO,SAAS,aAAa,OAAiC,SAAiB,SAAiB;AAC9F,MAAI,CAAC,OAAO,YAAY,WAAW;AACjC,WAAO,cAAc,WAAW,SAAS;AAAA,EAC3C;AAEA,QAAM,YAAY,MAAM,WAAW;AAEnC,MAAI,WAAW,QAAS,QAAO,UAAU,SAAS;AAClD,MAAI,WAAW,KAAM,QAAO,UAAU,MAAM;AAC5C,MAAI,WAAW,KAAM,QAAO,UAAU,MAAM;AAG5C,MAAI,UAAU,QAAQ,MAAM,GAAG;AAC7B,WAAO,UAAU,MAAM,MAAM;AAAA,EAC/B;AAGA,SAAO,UAAU,SAAS;AAC5B;AASO,SAAS,aAAa,OAAiC,SAAiB,SAAiB;AAC9F,MAAI,CAAC,OAAO,YAAY,WAAW;AACjC,WAAO,cAAc,WAAW,SAAS;AAAA,EAC3C;AAEA,QAAM,YAAY,MAAM,WAAW;AAEnC,MAAI,WAAW,QAAS,QAAO,UAAU,SAAS;AAClD,MAAI,WAAW,KAAM,QAAO,UAAU,MAAM;AAC5C,MAAI,WAAW,KAAM,QAAO,UAAU,MAAM;AAG5C,MAAI,UAAU,QAAQ,MAAM,GAAG;AAC7B,WAAO,UAAU,MAAM,MAAM;AAAA,EAC/B;AAGA,SAAO,UAAU,SAAS;AAC5B;AAWO,SAAS,oBAAoB,OAAiC,UAA0B;AAC7F,MAAI,CAAC,SAAU,QAAO;AAGtB,QAAM,UAAU,SAAS,YAAY,EAAE,SAAS,OAAO;AACvD,QAAM,UAAU,SAAS,YAAY,EAAE,SAAS,OAAO;AAGvD,MAAI,SAAS;AACb,QAAM,WAAW,SAAS,YAAY;AAEtC,MAAI,SAAS,SAAS,UAAU,GAAG;AACjC,aAAS;AAAA,EACX,WAAW,SAAS,SAAS,MAAM,KAAK,SAAS,SAAS,IAAI,GAAG;AAC/D,aAAS;AAAA,EACX;AAGA,MAAI,SAAS;AACX,WAAO,aAAa,OAAO,MAAM;AAAA,EACnC,WAAW,SAAS;AAClB,WAAO,aAAa,OAAO,MAAM;AAAA,EACnC;AAGA,SAAO,aAAa,OAAO,OAAO;AACpC;;;AC1VA,SAAS,mBACP,KACA,OAC4B;AAC5B,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,aAA6B,CAAC;AAGpC,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,EAAG,YAAW,OAAO,oBAAoB,CAAC;AAE9C,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,IAAK,YAAW,SAAS,oBAAoB,GAAG;AAGpD,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,EAAG,YAAW,SAAS,oBAAoB,CAAC;AAEhD,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,IAAK,YAAW,WAAW,oBAAoB,GAAG;AAGtD,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,GAAG;AACL,UAAM,QAAQ,aAAa,GAAG,KAAK,KAAK;AACxC,QAAI,OAAO;AACT,iBAAW,YAAY,EAAE,MAAM;AAC/B,YAAM,WAAW,aAAa,GAAG,KAAK,OAAO;AAC7C,YAAM,aAAa,aAAa,GAAG,KAAK,YAAY;AACpD,UAAI,YAAY,YAAY;AAC1B,mBAAW,UAAU,QAAQ;AAAA,UAC3B;AAAA,UACA;AAAA,UACA,aAAa,GAAG,KAAK,WAAW;AAAA,UAChC,aAAa,GAAG,KAAK,YAAY;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAE1D,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,QAAS,YAAW,eAAe,oBAAoB,OAAO;AAGlE,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,WAAW;AACb,UAAM,MAAM,aAAa,WAAW,KAAK,KAAK;AAC9C,QAAI,QAAQ,iBAAiB,QAAQ,eAAe,QAAQ,YAAY;AACtE,iBAAW,YAAY;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,UAAW,YAAW,YAAY,oBAAoB,SAAS;AAEnE,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,KAAM,YAAW,UAAU,oBAAoB,IAAI;AAGvD,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,QAAQ,UAAU,KAAK,KAAK,OAAO;AACzC,MAAI,OAAO;AACT,eAAW,QAAQ;AAAA,MACjB,aAAa,OAAO,KAAK,KAAK;AAAA,MAC9B,aAAa,OAAO,KAAK,YAAY;AAAA,MACrC,aAAa,OAAO,KAAK,WAAW;AAAA,MACpC,aAAa,OAAO,KAAK,YAAY;AAAA,IACvC;AAAA,EACF;AAGA,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,WAAW;AACb,UAAM,MAAM,aAAa,WAAW,KAAK,KAAK;AAC9C,QAAI,KAAK;AACP,iBAAW,YAAY;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,eAAW,UAAU,uBAAuB,GAAG;AAAA,EACjD;AAGA,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,IAAI;AACN,UAAM,MAAM,sBAAsB,IAAI,KAAK,KAAK;AAChD,QAAI,QAAQ,OAAW,YAAW,WAAW;AAAA,EAC/C;AAEA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,UAAM,MAAM,sBAAsB,MAAM,KAAK,KAAK;AAClD,QAAI,QAAQ,OAAW,YAAW,aAAa;AAAA,EACjD;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,eAAW,aAAa;AAAA,MACtB,OAAO,aAAa,QAAQ,KAAK,OAAO,KAAK;AAAA,MAC7C,OAAO,aAAa,QAAQ,KAAK,OAAO,KAAK;AAAA,MAC7C,UAAU,aAAa,QAAQ,KAAK,UAAU,KAAK;AAAA,MACnD,IAAI,aAAa,QAAQ,KAAK,IAAI,KAAK;AAAA,IACzC;AAGA,UAAM,aAAa,aAAa,QAAQ,KAAK,YAAY;AACzD,QAAI,YAAY;AACd,iBAAW,WAAW,aAAa;AAMnC,UAAI,SAAS,CAAC,WAAW,WAAW,OAAO;AACzC,mBAAW,WAAW,QAAQ,oBAAoB,OAAO,UAAU;AAAA,MACrE;AAAA,IACF;AACA,UAAM,aAAa,aAAa,QAAQ,KAAK,YAAY;AACzD,QAAI,YAAY;AACd,iBAAW,WAAW,aAAa;AACnC,UAAI,SAAS,CAAC,WAAW,WAAW,OAAO;AACzC,mBAAW,WAAW,QAAQ,oBAAoB,OAAO,UAAU;AAAA,MACrE;AAAA,IACF;AACA,UAAM,gBAAgB,aAAa,QAAQ,KAAK,eAAe;AAC/D,QAAI,eAAe;AACjB,iBAAW,WAAW,gBAAgB;AACtC,UAAI,SAAS,CAAC,WAAW,WAAW,UAAU;AAC5C,mBAAW,WAAW,WAAW,oBAAoB,OAAO,aAAa;AAAA,MAC3E;AAAA,IACF;AACA,UAAM,UAAU,aAAa,QAAQ,KAAK,SAAS;AACnD,QAAI,SAAS;AACX,iBAAW,WAAW,UAAU;AAChC,UAAI,SAAS,CAAC,WAAW,WAAW,IAAI;AACtC,mBAAW,WAAW,KAAK,oBAAoB,OAAO,OAAO;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,SAAS;AACX,UAAM,MAAM,sBAAsB,SAAS,KAAK,KAAK;AACrD,QAAI,QAAQ,OAAW,YAAW,UAAU;AAAA,EAC9C;AAGA,QAAM,WAAW,UAAU,KAAK,KAAK,UAAU;AAC/C,MAAI,UAAU;AACZ,UAAM,MAAM,sBAAsB,UAAU,KAAK,KAAK;AACtD,QAAI,QAAQ,OAAW,YAAW,WAAW;AAAA,EAC/C;AAGA,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,GAAG;AACL,UAAM,MAAM,sBAAsB,GAAG,KAAK,KAAK;AAC/C,QAAI,QAAQ,OAAW,YAAW,QAAQ;AAAA,EAC5C;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,UAAM,MAAM,sBAAsB,MAAM,KAAK,KAAK;AAClD,QAAI,QAAQ,OAAW,YAAW,UAAU;AAAA,EAC9C;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,IAAK,YAAW,SAAS;AAAA,EAC/B;AAGA,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,IAAI;AACN,UAAM,MAAM,aAAa,IAAI,KAAK,KAAK;AACvC,QAAI,IAAK,YAAW,eAAe;AAAA,EACrC;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAE1D,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,QAAS,YAAW,UAAU,oBAAoB,OAAO;AAE7D,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,QAAS,YAAW,UAAU,oBAAoB,OAAO;AAE7D,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,IAAK,YAAW,MAAM,oBAAoB,GAAG;AAEjD,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,GAAI,YAAW,KAAK,oBAAoB,EAAE;AAG9C,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,IAAK,YAAW,UAAU;AAAA,EAChC;AAEA,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AAKA,SAAS,gBACP,KACA,YACA,WACA,YACY;AACZ,QAAM,QAAoB,CAAC;AAE3B,MAAI,OAAO,QAAQ,QAAQ;AACzB,UAAM,MAAM;AAAA,EACd,WAAW,QAAQ,QAAQ;AACzB,UAAM,OAAO;AAAA,EACf;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,MAAI,WAAW;AACb,UAAM,YAAY;AAAA,EACpB;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO;AACT;AAKA,SAAS,uBAAuB,KAAuD;AACrF,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,QAA2B,CAAC;AAElC,QAAM,QAAQ,aAAa,KAAK,KAAK,OAAO;AAC5C,MAAI,SAAS,UAAU,QAAQ;AAC7B,UAAM,QAAQ,EAAE,KAAK,MAAM;AAAA,EAC7B;AAEA,QAAM,OAAO,aAAa,KAAK,KAAK,MAAM;AAC1C,MAAI,QAAQ,SAAS,QAAQ;AAC3B,UAAM,OAAO,EAAE,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,YAAY,aAAa,KAAK,KAAK,WAAW;AACpD,MAAI,WAAW;AACb,UAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,QAAM,gBAAgB,aAAa,KAAK,KAAK,eAAe;AAC5D,MAAI,iBAAiB,MAAM,MAAM;AAC/B,UAAM,KAAK,YAAY;AAAA,EACzB;AAEA,QAAM,iBAAiB,aAAa,KAAK,KAAK,gBAAgB;AAC9D,MAAI,kBAAkB,MAAM,MAAM;AAChC,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,QAAM,UAAU,aAAa,KAAK,KAAK,KAAK;AAC5C,MAAI,SAAS;AACX,UAAM,UAAU;AAAA,EAClB;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAKA,SAAS,gBAAgB,QAAmD;AAC1E,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,aAAa,QAAQ,KAAK,KAAK;AAC7C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,OAAmB;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,WAAW,aAAa,QAAQ,KAAK,OAAO;AAClD,QAAM,aAAa,aAAa,QAAQ,KAAK,YAAY;AACzD,MAAI,YAAY,YAAY;AAC1B,SAAK,QAAQ;AAAA,MACX;AAAA,MACA;AAAA,MACA,aAAa,QAAQ,KAAK,WAAW;AAAA,MACrC,aAAa,QAAQ,KAAK,YAAY;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,KAAK,sBAAsB,QAAQ,KAAK,IAAI;AAClD,MAAI,OAAO,OAAW,MAAK,OAAO;AAElC,QAAM,QAAQ,sBAAsB,QAAQ,KAAK,OAAO;AACxD,MAAI,UAAU,OAAW,MAAK,QAAQ;AAEtC,QAAM,aAAa,aAAa,QAAQ,KAAK,QAAQ;AACrD,MAAI,WAAY,MAAK,SAAS,eAAe,OAAO,eAAe;AAEnE,QAAM,QAAQ,aAAa,QAAQ,KAAK,OAAO;AAC/C,MAAI,MAAO,MAAK,QAAQ,UAAU,OAAO,UAAU;AAEnD,SAAO;AACT;AAKA,SAAS,cAAc,MAAgD;AACrE,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,cAAc,aAAa,MAAM,KAAK,KAAK;AACjD,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,QAAM,SAAoB,CAAC;AAE3B,aAAW,OAAO,aAAa;AAC7B,UAAM,MAAM,sBAAsB,KAAK,KAAK,KAAK;AACjD,UAAM,MAAM,aAAa,KAAK,KAAK,KAAK;AAExC,QAAI,QAAQ,UAAa,KAAK;AAC5B,YAAM,UAAmB;AAAA,QACvB,UAAU;AAAA,QACV,WAAW;AAAA,MACb;AAEA,YAAM,SAAS,aAAa,KAAK,KAAK,QAAQ;AAC9C,UAAI,QAAQ;AACV,gBAAQ,SAAS;AAAA,MACnB;AAEA,aAAO,KAAK,OAAO;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;AAKA,SAAS,yBACP,KACA,OACiC;AACjC,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,aAAkC,CAAC;AAGzC,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,IAAI;AACN,UAAM,MAAM,aAAa,IAAI,KAAK,KAAK;AACvC,QAAI,IAAK,YAAW,YAAY;AAAA,EAClC;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,KAAM,YAAW,OAAO,oBAAoB,IAAI;AAGpD,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,SAAS;AACX,UAAM,SAAS,sBAAsB,SAAS,KAAK,QAAQ;AAC3D,QAAI,WAAW,OAAW,YAAW,cAAc;AAEnD,UAAM,QAAQ,sBAAsB,SAAS,KAAK,OAAO;AACzD,QAAI,UAAU,OAAW,YAAW,aAAa;AAEjD,UAAM,OAAO,sBAAsB,SAAS,KAAK,MAAM;AACvD,QAAI,SAAS,OAAW,YAAW,cAAc;AAEjD,UAAM,WAAW,aAAa,SAAS,KAAK,UAAU;AACtD,QAAI,SAAU,YAAW,kBAAkB;AAE3C,UAAM,aAAa,aAAa,SAAS,KAAK,mBAAmB;AACjE,QAAI,WAAY,YAAW,oBAAoB,eAAe,OAAO,eAAe;AAEpF,UAAM,YAAY,aAAa,SAAS,KAAK,kBAAkB;AAC/D,QAAI,UAAW,YAAW,mBAAmB,cAAc,OAAO,cAAc;AAAA,EAClF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,UAAM,OAAO,sBAAsB,KAAK,KAAK,MAAM;AACnD,QAAI,SAAS,OAAW,YAAW,aAAa;AAEhD,UAAM,QAAQ,sBAAsB,KAAK,KAAK,OAAO;AACrD,QAAI,UAAU,OAAW,YAAW,cAAc;AAElD,UAAM,YAAY,sBAAsB,KAAK,KAAK,WAAW;AAC7D,QAAI,cAAc,OAAW,YAAW,kBAAkB;AAE1D,UAAM,UAAU,sBAAsB,KAAK,KAAK,SAAS;AACzD,QAAI,YAAY,QAAW;AACzB,iBAAW,kBAAkB,CAAC;AAC9B,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,UAAM,UAA0C,CAAC;AACjD,UAAM,MAAM,gBAAgB,UAAU,MAAM,KAAK,KAAK,CAAC;AACvD,QAAI,IAAK,SAAQ,MAAM;AACvB,UAAM,SAAS,gBAAgB,UAAU,MAAM,KAAK,QAAQ,CAAC;AAC7D,QAAI,OAAQ,SAAQ,SAAS;AAC7B,UAAM,OAAO,gBAAgB,UAAU,MAAM,KAAK,MAAM,CAAC;AACzD,QAAI,KAAM,SAAQ,OAAO;AACzB,UAAM,QAAQ,gBAAgB,UAAU,MAAM,KAAK,OAAO,CAAC;AAC3D,QAAI,MAAO,SAAQ,QAAQ;AAC3B,UAAM,UAAU,gBAAgB,UAAU,MAAM,KAAK,SAAS,CAAC;AAC/D,QAAI,QAAS,SAAQ,UAAU;AAC/B,UAAM,MAAM,gBAAgB,UAAU,MAAM,KAAK,KAAK,CAAC;AACvD,QAAI,IAAK,SAAQ,MAAM;AAEvB,QAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,eAAW,UAAU,uBAAuB,GAAG;AAAA,EACjD;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,eAAW,OAAO,cAAc,IAAI;AAAA,EACtC;AAGA,QAAM,WAAW,UAAU,KAAK,KAAK,UAAU;AAC/C,MAAI,SAAU,YAAW,WAAW,oBAAoB,QAAQ;AAEhE,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,UAAW,YAAW,YAAY,oBAAoB,SAAS;AAEnE,QAAM,eAAe,UAAU,KAAK,KAAK,cAAc;AACvD,MAAI,aAAc,YAAW,eAAe,oBAAoB,YAAY;AAE5E,QAAM,kBAAkB,UAAU,KAAK,KAAK,iBAAiB;AAC7D,MAAI,gBAAiB,YAAW,kBAAkB,oBAAoB,eAAe;AAGrF,QAAM,QAAQ,UAAU,KAAK,KAAK,OAAO;AACzC,MAAI,OAAO;AACT,UAAM,QAAQ,UAAU,OAAO,KAAK,OAAO;AAC3C,UAAM,OAAO,UAAU,OAAO,KAAK,MAAM;AAEzC,QAAI,SAAS,MAAM;AACjB,iBAAW,QAAQ,CAAC;AACpB,UAAI,OAAO;AACT,cAAM,MAAM,sBAAsB,OAAO,KAAK,KAAK;AACnD,YAAI,QAAQ,OAAW,YAAW,MAAM,QAAQ;AAAA,MAClD;AACA,UAAI,MAAM;AACR,cAAM,MAAM,sBAAsB,MAAM,KAAK,KAAK;AAClD,YAAI,QAAQ,OAAW,YAAW,MAAM,OAAO;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,UAAU,KAAK,KAAK,YAAY;AACnD,MAAI,YAAY;AACd,UAAM,MAAM,sBAAsB,YAAY,KAAK,KAAK;AACxD,QAAI,QAAQ,OAAW,YAAW,eAAe;AAAA,EACnD;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,IAAK,YAAW,UAAU;AAAA,EAChC;AAGA,QAAM,sBAAsB,UAAU,KAAK,KAAK,qBAAqB;AACrE,MAAI;AACF,eAAW,sBAAsB,oBAAoB,mBAAmB;AAG1E,QAAM,sBAAsB,UAAU,KAAK,KAAK,qBAAqB;AACrE,MAAI;AACF,eAAW,sBAAsB,oBAAoB,mBAAmB;AAG1E,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,eAAW,gBAAgB,mBAAmB,KAAK,KAAK;AAAA,EAC1D;AAEA,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AAKA,SAAS,sBAAsB,SAA0D;AACvF,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,IAAI,sBAAsB,SAAS,KAAK,GAAG;AACjD,QAAM,OAAO,aAAa,SAAS,KAAK,MAAM;AAE9C,MAAI,MAAM,UAAa,MAAM;AAC3B,WAAO;AAAA,MACL,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,YAAyD;AAClF,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,UAAwB,CAAC;AAE/B,QAAM,MAAM,gBAAgB,UAAU,YAAY,KAAK,KAAK,CAAC;AAC7D,MAAI,IAAK,SAAQ,MAAM;AAEvB,QAAM,SAAS,gBAAgB,UAAU,YAAY,KAAK,QAAQ,CAAC;AACnE,MAAI,OAAQ,SAAQ,SAAS;AAE7B,QAAM,OAAO,gBAAgB,UAAU,YAAY,KAAK,MAAM,CAAC;AAC/D,MAAI,KAAM,SAAQ,OAAO;AAEzB,QAAM,QAAQ,gBAAgB,UAAU,YAAY,KAAK,OAAO,CAAC;AACjE,MAAI,MAAO,SAAQ,QAAQ;AAE3B,QAAM,UAAU,gBAAgB,UAAU,YAAY,KAAK,SAAS,CAAC;AACrE,MAAI,QAAS,SAAQ,UAAU;AAE/B,QAAM,UAAU,gBAAgB,UAAU,YAAY,KAAK,SAAS,CAAC;AACrE,MAAI,QAAS,SAAQ,UAAU;AAE/B,SAAO,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AACrD;AAKA,SAAS,iBAAiB,YAAwD;AAChF,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,UAAuB,CAAC;AAE9B,QAAM,MAAM,sBAAsB,UAAU,YAAY,KAAK,KAAK,CAAC;AACnE,MAAI,IAAK,SAAQ,MAAM;AAEvB,QAAM,SAAS,sBAAsB,UAAU,YAAY,KAAK,QAAQ,CAAC;AACzE,MAAI,OAAQ,SAAQ,SAAS;AAE7B,QAAM,OAAO,sBAAsB,UAAU,YAAY,KAAK,MAAM,CAAC;AACrE,MAAI,KAAM,SAAQ,OAAO;AAEzB,QAAM,QAAQ,sBAAsB,UAAU,YAAY,KAAK,OAAO,CAAC;AACvE,MAAI,MAAO,SAAQ,QAAQ;AAE3B,SAAO,OAAO,KAAK,OAAO,EAAE,SAAS,IAAI,UAAU;AACrD;AAKA,SAAS,eAAe,SAAmD;AACzE,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,OAAkB,CAAC;AAGzB,QAAM,MAAM,aAAa,SAAS,KAAK,KAAK;AAC5C,MAAI,KAAK;AAEP,UAAM,MAAM,SAAS,KAAK,EAAE;AAC5B,QAAI,CAAC,MAAM,GAAG,GAAG;AACf,WAAK,YAAY,MAAM,QAAY;AACnC,WAAK,WAAW,MAAM,QAAY;AAClC,WAAK,eAAe,MAAM,SAAY;AACtC,WAAK,cAAc,MAAM,SAAY;AACrC,WAAK,WAAW,MAAM,SAAY;AAClC,WAAK,WAAW,MAAM,UAAY;AAAA,IACpC;AAAA,EACF;AAGA,QAAM,cAAc,aAAa,SAAS,KAAK,aAAa;AAC5D,MAAI,YAAa,MAAK,cAAc,gBAAgB;AAEpD,QAAM,WAAW,aAAa,SAAS,KAAK,UAAU;AACtD,MAAI,SAAU,MAAK,WAAW,aAAa;AAE3C,QAAM,aAAa,aAAa,SAAS,KAAK,YAAY;AAC1D,MAAI,WAAY,MAAK,aAAa,eAAe;AAEjD,QAAM,UAAU,aAAa,SAAS,KAAK,SAAS;AACpD,MAAI,QAAS,MAAK,UAAU,YAAY;AAExC,QAAM,UAAU,aAAa,SAAS,KAAK,SAAS;AACpD,MAAI,QAAS,MAAK,UAAU,YAAY;AAExC,QAAM,UAAU,aAAa,SAAS,KAAK,SAAS;AACpD,MAAI,QAAS,MAAK,UAAU,YAAY;AAExC,SAAO,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,OAAO;AAC/C;AAKA,SAAS,qBACP,OACA,QAC6B;AAC7B,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,aAA8B,CAAC;AAGrC,QAAM,OAAO,UAAU,OAAO,KAAK,MAAM;AACzC,MAAI,MAAM;AACR,eAAW,QAAQ,sBAAsB,IAAI;AAAA,EAC/C;AAGA,QAAM,KAAK,UAAU,OAAO,KAAK,IAAI;AACrC,MAAI,IAAI;AACN,UAAM,MAAM,aAAa,IAAI,KAAK,KAAK;AACvC,QAAI,QAAQ,UAAU,QAAQ,YAAY,QAAQ,SAAS;AACzD,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,iBAAiB,UAAU,OAAO,KAAK,gBAAgB;AAC7D,MAAI,gBAAgB;AAClB,eAAW,cAAc,sBAAsB,cAAc;AAAA,EAC/D;AAGA,QAAM,SAAS,UAAU,OAAO,KAAK,QAAQ;AAC7C,MAAI,QAAQ;AACV,eAAW,SAAS,sBAAsB,MAAM;AAAA,EAClD;AAGA,QAAM,aAAa,UAAU,OAAO,KAAK,YAAY;AACrD,MAAI,YAAY;AACd,eAAW,UAAU,kBAAkB,UAAU;AAAA,EACnD;AAGA,QAAM,aAAa,UAAU,OAAO,KAAK,YAAY;AACrD,MAAI,YAAY;AACd,eAAW,cAAc,iBAAiB,UAAU;AAAA,EACtD;AAGA,QAAM,YAAY,UAAU,OAAO,KAAK,WAAW;AACnD,MAAI,WAAW;AACb,UAAM,MAAM,aAAa,WAAW,KAAK,MAAM;AAC/C,QAAI,QAAQ,WAAW,QAAQ,WAAW;AACxC,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF;AAGA,QAAM,WAAW,UAAU,OAAO,KAAK,UAAU;AACjD,MAAI,UAAU;AACZ,UAAM,MAAM,aAAa,UAAU,KAAK,KAAK;AAC7C,QAAI,IAAK,YAAW,UAAU;AAAA,EAChC;AAGA,QAAM,UAAU,UAAU,OAAO,KAAK,SAAS;AAC/C,MAAI,SAAS;AACX,eAAW,OAAO,eAAe,OAAO;AAAA,EAC1C;AAGA,QAAM,MAAM,UAAU,OAAO,KAAK,KAAK;AACvC,MAAI,KAAK;AACP,eAAW,UAAU,uBAAuB,GAAG;AAAA,EACjD;AAGA,QAAM,aAAa,UAAU,OAAO,KAAK,YAAY;AACrD,MAAI,WAAY,YAAW,OAAO,oBAAoB,UAAU;AAEhE,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AAKA,SAAS,wBAAwB,MAAyD;AACxF,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,aAAiC,CAAC;AAGxC,QAAM,WAAW,UAAU,MAAM,KAAK,UAAU;AAChD,MAAI,UAAU;AACZ,eAAW,SAAS,sBAAsB,QAAQ;AAClD,UAAM,QAAQ,aAAa,UAAU,KAAK,OAAO;AACjD,QAAI,OAAO;AACT,iBAAW,aAAa;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,YAAY,UAAU,MAAM,KAAK,WAAW;AAClD,MAAI,UAAW,YAAW,SAAS,oBAAoB,SAAS;AAGhE,QAAM,YAAY,UAAU,MAAM,KAAK,WAAW;AAClD,MAAI,UAAW,YAAW,YAAY,oBAAoB,SAAS;AAGnE,QAAM,KAAK,UAAU,MAAM,KAAK,IAAI;AACpC,MAAI,IAAI;AACN,UAAM,MAAM,aAAa,IAAI,KAAK,KAAK;AACvC,QAAI,QAAQ,UAAU,QAAQ,YAAY,QAAQ,SAAS;AACzD,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,MAAM,KAAK,QAAQ;AAC5C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAE1D,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AAKA,SAAS,yBACP,MACA,QACiC;AACjC,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,aAAkC,CAAC;AAGzC,QAAM,MAAM,UAAU,MAAM,KAAK,KAAK;AACtC,MAAI,KAAK;AACP,eAAW,QAAQ,sBAAsB,GAAG;AAAA,EAC9C;AAGA,QAAM,YAAY,UAAU,MAAM,KAAK,WAAW;AAClD,MAAI,WAAW;AACb,eAAW,UAAU,kBAAkB,SAAS;AAAA,EAClD;AAGA,QAAM,QAAQ,UAAU,MAAM,KAAK,OAAO;AAC1C,MAAI,OAAO;AACT,eAAW,UAAU,iBAAiB,KAAK;AAAA,EAC7C;AAGA,QAAM,MAAM,UAAU,MAAM,KAAK,KAAK;AACtC,MAAI,KAAK;AACP,eAAW,UAAU,uBAAuB,GAAG;AAAA,EACjD;AAGA,QAAM,SAAS,UAAU,MAAM,KAAK,QAAQ;AAC5C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,QAAQ,SAAS,QAAQ,YAAY,QAAQ,UAAU;AACzD,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,gBAAgB,UAAU,MAAM,KAAK,eAAe;AAC1D,MAAI,eAAe;AACjB,UAAM,MAAM,aAAa,eAAe,KAAK,KAAK;AAClD,QAAI,IAAK,YAAW,gBAAgB;AAAA,EACtC;AAGA,QAAM,WAAW,UAAU,MAAM,KAAK,UAAU;AAChD,MAAI,UAAU;AACZ,UAAM,MAAM,sBAAsB,UAAU,KAAK,KAAK;AACtD,QAAI,QAAQ,OAAW,YAAW,WAAW;AAAA,EAC/C;AAGA,QAAM,SAAS,UAAU,MAAM,KAAK,QAAQ;AAC5C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,eAAW,SAAS,QAAQ,YAAY,YAAY;AAAA,EACtD;AAGA,QAAM,YAAY,UAAU,MAAM,KAAK,WAAW;AAClD,MAAI,UAAW,YAAW,UAAU,oBAAoB,SAAS;AAGjE,QAAM,SAAS,UAAU,MAAM,KAAK,QAAQ;AAC5C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,WAAW,UAAU,MAAM,KAAK,UAAU;AAChD,MAAI,SAAU,YAAW,WAAW,oBAAoB,QAAQ;AAEhE,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AAKA,SAAS,WAAW,SAAqB,OAA4B;AACnE,QAAM,QAAe;AAAA,IACnB,SAAS,aAAa,SAAS,KAAK,SAAS,KAAK;AAAA,IAClD,MAAO,aAAa,SAAS,KAAK,MAAM,KAAmB;AAAA,EAC7D;AAGA,QAAM,cAAc,aAAa,SAAS,KAAK,SAAS;AACxD,MAAI,YAAa,OAAM,UAAU,gBAAgB,OAAO,gBAAgB;AAGxE,QAAM,SAAS,UAAU,SAAS,KAAK,MAAM;AAC7C,MAAI,QAAQ;AACV,UAAM,OAAO,aAAa,QAAQ,KAAK,KAAK,KAAK;AAAA,EACnD;AAGA,QAAM,UAAU,UAAU,SAAS,KAAK,SAAS;AACjD,MAAI,SAAS;AACX,UAAM,UAAU,aAAa,SAAS,KAAK,KAAK,KAAK;AAAA,EACvD;AAGA,QAAM,OAAO,UAAU,SAAS,KAAK,MAAM;AAC3C,MAAI,MAAM;AACR,UAAM,OAAO,aAAa,MAAM,KAAK,KAAK,KAAK;AAAA,EACjD;AAGA,QAAM,OAAO,UAAU,SAAS,KAAK,MAAM;AAC3C,MAAI,MAAM;AACR,UAAM,OAAO,aAAa,MAAM,KAAK,KAAK,KAAK;AAAA,EACjD;AAGA,QAAM,aAAa,UAAU,SAAS,KAAK,YAAY;AACvD,MAAI,YAAY;AACd,UAAM,MAAM,sBAAsB,YAAY,KAAK,KAAK;AACxD,QAAI,QAAQ,OAAW,OAAM,aAAa;AAAA,EAC5C;AAGA,QAAM,SAAS,UAAU,SAAS,KAAK,QAAQ;AAC/C,MAAI,OAAQ,OAAM,SAAS,oBAAoB,MAAM;AAErD,QAAM,aAAa,UAAU,SAAS,KAAK,YAAY;AACvD,MAAI,WAAY,OAAM,aAAa,oBAAoB,UAAU;AAGjE,QAAM,iBAAiB,UAAU,SAAS,KAAK,gBAAgB;AAC/D,MAAI,eAAgB,OAAM,iBAAiB,oBAAoB,cAAc;AAG7E,QAAM,UAAU,UAAU,SAAS,KAAK,SAAS;AACjD,MAAI,QAAS,OAAM,UAAU,oBAAoB,OAAO;AAGxD,QAAM,WAAW,UAAU,SAAS,KAAK,UAAU;AACnD,MAAI,SAAU,OAAM,WAAW,oBAAoB,QAAQ;AAG3D,QAAM,MAAM,UAAU,SAAS,KAAK,KAAK;AACzC,MAAI,KAAK;AACP,UAAM,MAAM,yBAAyB,KAAK,KAAK;AAAA,EACjD;AAGA,QAAM,MAAM,UAAU,SAAS,KAAK,KAAK;AACzC,MAAI,KAAK;AACP,UAAM,MAAM,mBAAmB,KAAK,KAAK;AAAA,EAC3C;AAGA,QAAM,QAAQ,UAAU,SAAS,KAAK,OAAO;AAC7C,MAAI,OAAO;AACT,UAAM,QAAQ,qBAAqB,OAAO,KAAK;AAAA,EACjD;AAGA,QAAM,OAAO,UAAU,SAAS,KAAK,MAAM;AAC3C,MAAI,MAAM;AACR,UAAM,OAAO,wBAAwB,IAAI;AAAA,EAC3C;AAGA,QAAM,OAAO,UAAU,SAAS,KAAK,MAAM;AAC3C,MAAI,MAAM;AACR,UAAM,OAAO,yBAAyB,MAAM,KAAK;AAAA,EACnD;AAGA,QAAM,cAAc,aAAa,SAAS,KAAK,YAAY;AAC3D,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,aAAa,CAAC;AAEpB,eAAW,cAAc,aAAa;AACpC,YAAM,WAAW,aAAa,YAAY,KAAK,MAAM;AACrD,UAAI,UAAU;AACZ,cAAM,mBAA6D;AAAA,UACjE,MAAM;AAAA,QACR;AAEA,cAAM,UAAU,UAAU,YAAY,KAAK,KAAK;AAChD,YAAI,QAAS,kBAAiB,MAAM,yBAAyB,SAAS,KAAK;AAE3E,cAAM,UAAU,UAAU,YAAY,KAAK,KAAK;AAChD,YAAI,QAAS,kBAAiB,MAAM,mBAAmB,SAAS,KAAK;AAErE,cAAM,YAAY,UAAU,YAAY,KAAK,OAAO;AACpD,YAAI,UAAW,kBAAiB,QAAQ,qBAAqB,WAAW,KAAK;AAE7E,cAAM,WAAW,UAAU,YAAY,KAAK,MAAM;AAClD,YAAI,SAAU,kBAAiB,OAAO,wBAAwB,QAAQ;AAEtE,cAAM,WAAW,UAAU,YAAY,KAAK,MAAM;AAClD,YAAI,SAAU,kBAAiB,OAAO,yBAAyB,UAAU,KAAK;AAE9E,cAAM,WAAW,KAAK,gBAAgB;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,iBACP,aACA,OACyB;AACzB,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,SAAsB,CAAC;AAG7B,QAAM,aAAa,UAAU,aAAa,KAAK,YAAY;AAC3D,MAAI,YAAY;AACd,UAAM,MAAM,UAAU,YAAY,KAAK,KAAK;AAC5C,QAAI,KAAK;AACP,aAAO,MAAM,mBAAmB,KAAK,KAAK;AAAA,IAC5C;AAAA,EACF;AAGA,QAAM,aAAa,UAAU,aAAa,KAAK,YAAY;AAC3D,MAAI,YAAY;AACd,UAAM,MAAM,UAAU,YAAY,KAAK,KAAK;AAC5C,QAAI,KAAK;AACP,aAAO,MAAM,yBAAyB,KAAK,KAAK;AAAA,IAClD;AAAA,EACF;AAEA,SAAO,OAAO,OAAO,OAAO,MAAM,SAAS;AAC7C;AAKA,SAAS,oBACP,QACA,QAC4B;AAC5B,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,OAAQ,QAAO,SAAS,EAAE,GAAG,OAAO,IAAI;AAE7C,QAAM,SAAS,EAAE,GAAG,OAAO;AAG3B,aAAW,OAAO,OAAO,KAAK,MAAM,GAA+B;AACjE,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU,QAAW;AACvB,MAAC,OAAe,GAAG,IACjB,OAAO,UAAU,YAAY,UAAU,OACnC,EAAE,GAAK,OAAO,GAAG,KAAa,CAAC,GAAI,GAAG,MAAM,IAC5C;AAAA,IACR;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,yBACP,QACA,QACiC;AACjC,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,CAAC,OAAQ,QAAO,SAAS,EAAE,GAAG,OAAO,IAAI;AAE7C,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,OAAO,KAAK,MAAM,GAAoC;AACtE,UAAM,QAAQ,OAAO,GAAG;AACxB,QAAI,UAAU,QAAW;AACvB,UAAI,QAAQ,iBAAiB;AAC3B,eAAO,gBAAgB,oBAAoB,OAAO,eAAe,OAAO,aAAa;AAAA,MACvF,WAAW,QAAQ,aAAa,QAAQ,WAAW,QAAQ,SAAS;AAClE,cAAM,YAAY,OAAO,GAAG;AAC5B,cAAM,cAAc;AACpB,QAAC,OAAmC,GAAG,IAAI,EAAE,GAAI,aAAa,CAAC,GAAI,GAAI,eAAe,CAAC,EAAG;AAAA,MAC5F,WAAW,QAAQ,UAAU,MAAM,QAAQ,KAAK,GAAG;AACjD,eAAO,OAAO,CAAC,GAAG,KAAK;AAAA,MACzB,OAAO;AACL,QAAC,OAAe,GAAG,IAAI;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,wBACP,OACA,UACA,OACA,UAAuB,oBAAI,IAAI,GACxB;AAEP,MAAI,QAAQ,IAAI,MAAM,OAAO,GAAG;AAC9B,WAAO;AAAA,EACT;AACA,UAAQ,IAAI,MAAM,OAAO;AAGzB,MAAI,CAAC,MAAM,SAAS;AAClB,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,SAAS,IAAI,MAAM,OAAO;AAC9C,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,QAAM,iBAAiB,wBAAwB,aAAa,UAAU,OAAO,OAAO;AAGpF,QAAM,WAAkB;AAAA,IACtB,GAAG;AAAA,IACH,KAAK,yBAAyB,eAAe,KAAK,MAAM,GAAG;AAAA,IAC3D,KAAK,oBAAoB,eAAe,KAAK,MAAM,GAAG;AAAA,EACxD;AAGA,MAAI,MAAM,SAAS,SAAS;AAC1B,QAAI,eAAe,SAAS,MAAM,OAAO;AACvC,eAAS,QAAQ,EAAE,GAAI,eAAe,SAAS,CAAC,GAAI,GAAI,MAAM,SAAS,CAAC,EAAG;AAAA,IAC7E;AACA,QAAI,eAAe,QAAQ,MAAM,MAAM;AACrC,eAAS,OAAO,EAAE,GAAI,eAAe,QAAQ,CAAC,GAAI,GAAI,MAAM,QAAQ,CAAC,EAAG;AAAA,IAC1E;AACA,QAAI,eAAe,QAAQ,MAAM,MAAM;AACrC,eAAS,OAAO,EAAE,GAAI,eAAe,QAAQ,CAAC,GAAI,GAAI,MAAM,QAAQ,CAAC,EAAG;AAAA,IAC1E;AAAA,EACF;AAEA,SAAO;AACT;AASO,SAAS,YAAY,WAAmB,OAA+B;AAC5E,QAAM,WAAqB,oBAAI,IAAI;AAEnC,MAAI;AACF,UAAM,MAAM,iBAAiB,SAAS;AACtC,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AAGA,UAAM,gBAAgB,aAAa,KAAK,KAAK,OAAO;AACpD,eAAW,WAAW,eAAe;AACnC,YAAM,QAAQ,WAAW,SAAS,KAAK;AACvC,UAAI,MAAM,SAAS;AACjB,iBAAS,IAAI,MAAM,SAAS,KAAK;AAAA,MACnC;AAAA,IACF;AAGA,eAAW,CAAC,SAAS,KAAK,KAAK,UAAU;AACvC,YAAM,WAAW,wBAAwB,OAAO,UAAU,KAAK;AAC/D,eAAS,IAAI,SAAS,QAAQ;AAAA,IAChC;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,KAAK,2BAA2B,KAAK;AAAA,EAC/C;AAEA,SAAO;AACT;AASO,SAAS,sBAAsB,WAAmB,OAAuC;AAC9F,QAAM,SAA2B;AAAA,IAC/B,QAAQ,CAAC;AAAA,EACX;AAEA,MAAI;AACF,UAAM,MAAM,iBAAiB,SAAS;AACtC,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,IACT;AAGA,UAAM,gBAAgB,UAAU,KAAK,KAAK,aAAa;AACvD,WAAO,cAAc,iBAAiB,eAAe,KAAK;AAG1D,UAAM,iBAAiB,UAAU,KAAK,KAAK,cAAc;AACzD,QAAI,gBAAgB;AAClB,aAAO,eAAe;AAAA,QACpB,gBAAgB,aAAa,gBAAgB,KAAK,gBAAgB,MAAM;AAAA,QACxE,eAAe,sBAAsB,gBAAgB,KAAK,eAAe;AAAA,QACzE,eAAe,aAAa,gBAAgB,KAAK,eAAe,MAAM;AAAA,QACtE,mBAAmB,aAAa,gBAAgB,KAAK,mBAAmB,MAAM;AAAA,QAC9E,YAAY,aAAa,gBAAgB,KAAK,YAAY,MAAM;AAAA,QAChE,OAAO,sBAAsB,gBAAgB,KAAK,OAAO;AAAA,MAC3D;AAAA,IACF;AAGA,UAAM,WAAW,YAAY,WAAW,KAAK;AAC7C,WAAO,SAAS,MAAM,KAAK,SAAS,OAAO,CAAC;AAAA,EAC9C,SAAS,OAAO;AACd,YAAQ,KAAK,sCAAsC,KAAK;AAAA,EAC1D;AAEA,SAAO;AACT;;;AC5rCO,SAAS,eAAe,cAA2C;AACxE,QAAM,cAAoC;AAAA,IACxC,cAAc,CAAC;AAAA,IACf,MAAM,CAAC;AAAA,EACT;AAEA,MAAI,CAAC,cAAc;AACjB,WAAO,mBAAmB,WAAW;AAAA,EACvC;AAEA,QAAM,OAAO,iBAAiB,YAAY;AAC1C,MAAI,CAAC,MAAM;AACT,WAAO,mBAAmB,WAAW;AAAA,EACvC;AAGA,QAAM,sBAAsB,aAAa,MAAM,KAAK,aAAa;AACjE,aAAW,eAAe,qBAAqB;AAC7C,UAAM,SAAS,uBAAuB,WAAW;AACjD,QAAI,QAAQ;AACV,kBAAY,aAAa,KAAK,MAAM;AAAA,IACtC;AAAA,EACF;AAGA,QAAM,cAAc,aAAa,MAAM,KAAK,KAAK;AACjD,aAAW,OAAO,aAAa;AAC7B,UAAM,SAAS,uBAAuB,GAAG;AACzC,QAAI,QAAQ;AACV,kBAAY,KAAK,KAAK,MAAM;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO,mBAAmB,WAAW;AACvC;AAKA,SAAS,uBAAuB,SAA+C;AAC7E,QAAM,mBAAmB,aAAa,SAAS,KAAK,eAAe;AACnE,MAAI,qBAAqB,KAAM,QAAO;AAEtC,QAAM,gBAAgB,SAAS,kBAAkB,EAAE;AACnD,MAAI,MAAM,aAAa,EAAG,QAAO;AAEjC,QAAM,cAAiC;AAAA,IACrC;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAGA,QAAM,mBAAmB,UAAU,SAAS,KAAK,gBAAgB;AACjE,MAAI,kBAAkB;AACpB,UAAM,SAAS,aAAa,kBAAkB,KAAK,KAAK;AACxD,QAAI,WAAW,sBAAsB,WAAW,gBAAgB,WAAW,eAAe;AACxF,kBAAY,iBAAiB;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,SAAS,KAAK,MAAM;AAC7C,MAAI,QAAQ;AACV,gBAAY,OAAO,aAAa,QAAQ,KAAK,KAAK,KAAK;AAAA,EACzD;AAGA,QAAM,iBAAiB,UAAU,SAAS,KAAK,cAAc;AAC7D,MAAI,gBAAgB;AAClB,gBAAY,eAAe,aAAa,gBAAgB,KAAK,KAAK,KAAK;AAAA,EACzE;AAEA,QAAM,cAAc,UAAU,SAAS,KAAK,WAAW;AACvD,MAAI,aAAa;AACf,gBAAY,YAAY,aAAa,aAAa,KAAK,KAAK,KAAK;AAAA,EACnE;AAGA,QAAM,gBAAgB,aAAa,SAAS,KAAK,KAAK;AACtD,aAAW,SAAS,eAAe;AACjC,UAAM,QAAQ,eAAe,KAAK;AAClC,QAAI,OAAO;AACT,kBAAY,OAAO,KAAK,KAAK;AAAA,IAC/B;AAAA,EACF;AAGA,cAAY,OAAO,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AAEjD,SAAO;AACT;AAKA,SAAS,uBAAuB,SAA+C;AAC7E,QAAM,WAAW,aAAa,SAAS,KAAK,OAAO;AACnD,MAAI,aAAa,KAAM,QAAO;AAE9B,QAAM,QAAQ,SAAS,UAAU,EAAE;AACnC,MAAI,MAAM,KAAK,EAAG,QAAO;AAGzB,QAAM,kBAAkB,UAAU,SAAS,KAAK,eAAe;AAC/D,MAAI,CAAC,gBAAiB,QAAO;AAE7B,QAAM,mBAAmB,aAAa,iBAAiB,KAAK,KAAK;AACjE,MAAI,qBAAqB,KAAM,QAAO;AAEtC,QAAM,gBAAgB,SAAS,kBAAkB,EAAE;AACnD,MAAI,MAAM,aAAa,EAAG,QAAO;AAEjC,QAAM,WAA8B;AAAA,IAClC;AAAA,IACA;AAAA,EACF;AAGA,QAAM,mBAAmB,aAAa,SAAS,KAAK,aAAa;AACjE,MAAI,iBAAiB,SAAS,GAAG;AAC/B,aAAS,iBAAiB,CAAC;AAE3B,eAAW,cAAc,kBAAkB;AACzC,YAAM,UAAU,aAAa,YAAY,KAAK,MAAM;AACpD,UAAI,YAAY,KAAM;AAEtB,YAAM,OAAO,SAAS,SAAS,EAAE;AACjC,UAAI,MAAM,IAAI,EAAG;AAEjB,YAAM,WAIF,EAAE,KAAK;AAGX,YAAM,kBAAkB,UAAU,YAAY,KAAK,eAAe;AAClE,UAAI,iBAAiB;AACnB,cAAM,WAAW,aAAa,iBAAiB,KAAK,KAAK;AACzD,YAAI,aAAa,MAAM;AACrB,gBAAM,WAAW,SAAS,UAAU,EAAE;AACtC,cAAI,CAAC,MAAM,QAAQ,GAAG;AACpB,qBAAS,gBAAgB;AAAA,UAC3B;AAAA,QACF;AAAA,MACF;AAGA,YAAM,QAAQ,UAAU,YAAY,KAAK,KAAK;AAC9C,UAAI,OAAO;AACT,iBAAS,MAAM,eAAe,KAAK,KAAK;AAAA,MAC1C;AAEA,eAAS,eAAe,KAAK,QAAQ;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,eAAe,SAAuC;AAC7D,QAAM,UAAU,aAAa,SAAS,KAAK,MAAM;AACjD,MAAI,YAAY,KAAM,QAAO;AAE7B,QAAM,OAAO,SAAS,SAAS,EAAE;AACjC,MAAI,MAAM,IAAI,KAAK,OAAO,KAAK,OAAO,EAAG,QAAO;AAEhD,QAAM,QAAmB;AAAA,IACvB;AAAA,IACA,QAAQ;AAAA;AAAA,IACR,SAAS;AAAA,EACX;AAGA,QAAM,UAAU,UAAU,SAAS,KAAK,OAAO;AAC/C,MAAI,SAAS;AACX,UAAM,WAAW,aAAa,SAAS,KAAK,KAAK;AACjD,QAAI,aAAa,MAAM;AACrB,YAAM,WAAW,SAAS,UAAU,EAAE;AACtC,UAAI,CAAC,MAAM,QAAQ,GAAG;AACpB,cAAM,QAAQ;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,UAAU,SAAS,KAAK,QAAQ;AACjD,MAAI,UAAU;AACZ,UAAM,SAAS,aAAa,UAAU,KAAK,KAAK;AAChD,QAAI,QAAQ;AACV,YAAM,SAAS,kBAAkB,MAAM;AAAA,IACzC;AAAA,EACF;AAGA,QAAM,YAAY,UAAU,SAAS,KAAK,SAAS;AACnD,MAAI,WAAW;AACb,UAAM,UAAU,aAAa,WAAW,KAAK,KAAK,KAAK;AAAA,EACzD;AAGA,QAAM,UAAU,UAAU,SAAS,KAAK,OAAO;AAC/C,MAAI,SAAS;AACX,UAAM,QAAQ,aAAa,SAAS,KAAK,KAAK;AAC9C,QAAI,UAAU,UAAU,UAAU,YAAY,UAAU,SAAS;AAC/D,YAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,SAAS,KAAK,MAAM;AAC7C,MAAI,QAAQ;AACV,UAAM,UAAU,aAAa,QAAQ,KAAK,KAAK;AAC/C,QAAI,YAAY,SAAS,YAAY,WAAW,YAAY,WAAW;AACrE,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAGA,QAAM,UAAU,UAAU,SAAS,KAAK,OAAO;AAC/C,MAAI,SAAS;AACX,UAAM,QAAQ,oBAAoB,OAAO;AAAA,EAC3C;AAGA,QAAM,eAAe,UAAU,SAAS,KAAK,YAAY;AACzD,MAAI,cAAc;AAChB,UAAM,aAAa,aAAa,cAAc,KAAK,KAAK;AACxD,QAAI,eAAe,MAAM;AACvB,YAAM,aAAa,SAAS,YAAY,EAAE;AAC1C,UAAI,CAAC,MAAM,UAAU,GAAG;AACtB,cAAM,aAAa;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAGA,QAAM,WAAW,UAAU,SAAS,KAAK,QAAQ;AACjD,MAAI,UAAU;AACZ,UAAM,SAAS;AAAA,MACb,QAAQ,oBAAoB,QAAQ;AAAA,MACpC,aAAa,sBAAsB,UAAU,KAAK,aAAa;AAAA,MAC/D,cAAc,sBAAsB,UAAU,KAAK,cAAc;AAAA,IACnE;AAAA,EACF;AAGA,QAAM,QAAQ,UAAU,SAAS,KAAK,KAAK;AAC3C,MAAI,OAAO;AACT,UAAM,MAAM,yBAAyB,KAAK;AAAA,EAC5C;AAGA,QAAM,QAAQ,UAAU,SAAS,KAAK,KAAK;AAC3C,MAAI,OAAO;AACT,UAAM,MAAM,mBAAmB,KAAK;AAAA,EACtC;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,QAA8B;AAEvD,QAAM,YAA0C;AAAA,IAC9C,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,IACT,cAAc;AAAA,IACd,aAAa;AAAA,IACb,KAAK;AAAA,IACL,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,MAAM;AAAA,IACN,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,SAAS;AAAA;AAAA,IAET,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,OAAO;AAAA,IACP,OAAO;AAAA,IACP,kBAAkB;AAAA,IAClB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,4BAA4B;AAAA,IAC5B,uBAAuB;AAAA,IACvB,mBAAmB;AAAA,IACnB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,8BAA8B;AAAA,IAC9B,yBAAyB;AAAA,IACzB,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,IACjB,4BAA4B;AAAA,IAC5B,mBAAmB;AAAA,IACnB,2BAA2B;AAAA,IAC3B,2BAA2B;AAAA,IAC3B,kBAAkB;AAAA,IAClB,iBAAiB;AAAA,IACjB,wBAAwB;AAAA,IACxB,yBAAyB;AAAA,IACzB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,cAAc;AAAA,IACd,cAAc;AAAA,IACd,cAAc;AAAA,IACd,SAAS;AAAA,IACT,SAAS;AAAA,IACT,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,eAAe;AAAA,IACf,aAAa;AAAA,IACb,aAAa;AAAA,IACb,cAAc;AAAA,EAChB;AAEA,SAAO,UAAU,MAAM,KAAK;AAC9B;AAMA,SAAS,yBAAyB,KAAsC;AACtE,QAAM,aAAkC,CAAC;AAGzC,QAAM,QAAQ,UAAU,KAAK,KAAK,KAAK;AACvC,MAAI,OAAO;AACT,UAAM,OAAO,sBAAsB,OAAO,KAAK,MAAM;AACrD,UAAM,QAAQ,sBAAsB,OAAO,KAAK,OAAO;AACvD,UAAM,YAAY,sBAAsB,OAAO,KAAK,WAAW;AAC/D,UAAM,UAAU,sBAAsB,OAAO,KAAK,SAAS;AAE3D,QAAI,SAAS,OAAW,YAAW,aAAa;AAChD,QAAI,UAAU,OAAW,YAAW,cAAc;AAElD,QAAI,YAAY,QAAW;AACzB,iBAAW,kBAAkB,CAAC;AAC9B,iBAAW,gBAAgB;AAAA,IAC7B,WAAW,cAAc,QAAW;AAClC,iBAAW,kBAAkB;AAAA,IAC/B;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,MAAM;AACzC,MAAI,QAAQ;AACV,eAAW,OAAO,CAAC;AACnB,UAAM,cAAc,aAAa,QAAQ,KAAK,KAAK;AACnD,eAAW,SAAS,aAAa;AAC/B,YAAM,MAAM,sBAAsB,OAAO,KAAK,KAAK;AACnD,YAAM,MAAM,aAAa,OAAO,KAAK,KAAK;AAC1C,YAAM,SAAS,aAAa,OAAO,KAAK,QAAQ;AAEhD,UAAI,QAAQ,UAAa,KAAK;AAC5B,mBAAW,KAAK,KAAK;AAAA,UACnB,UAAU;AAAA,UACV,WAAW,kBAAkB,GAAG;AAAA,UAChC,QAAQ,eAAe,MAAM;AAAA,QAC/B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBACP,KACmE;AACnE,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,eACP,KAC8E;AAC9E,MAAI,CAAC,IAAK,QAAO;AACjB,UAAQ,KAAK;AAAA,IACX,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAMA,SAAS,mBAAmB,KAAiC;AAC3D,QAAM,aAA6B,CAAC;AAGpC,QAAM,WAAW,UAAU,KAAK,KAAK,QAAQ;AAC7C,MAAI,UAAU;AACZ,eAAW,aAAa;AAAA,MACtB,OAAO,aAAa,UAAU,KAAK,OAAO,KAAK;AAAA,MAC/C,OAAO,aAAa,UAAU,KAAK,OAAO,KAAK;AAAA,MAC/C,UAAU,aAAa,UAAU,KAAK,UAAU,KAAK;AAAA,MACrD,IAAI,aAAa,UAAU,KAAK,IAAI,KAAK;AAAA,IAC3C;AAAA,EACF;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,IAAI;AACrC,MAAI,MAAM;AACR,UAAM,OAAO,sBAAsB,MAAM,KAAK,KAAK;AACnD,QAAI,SAAS,QAAW;AACtB,iBAAW,WAAW;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,UAAU,UAAU,KAAK,KAAK,OAAO;AAC3C,MAAI,SAAS;AACX,UAAM,MAAM,aAAa,SAAS,KAAK,KAAK;AAC5C,UAAM,aAAa,aAAa,SAAS,KAAK,YAAY;AAE1D,QAAI,QAAQ,QAAQ;AAClB,iBAAW,QAAQ,EAAE,MAAM,KAAK;AAAA,IAClC,WAAW,YAAY;AACrB,iBAAW,QAAQ;AAAA,QACjB;AAAA,QACA,WAAW,aAAa,SAAS,KAAK,WAAW,KAAK;AAAA,QACtD,YAAY,aAAa,SAAS,KAAK,YAAY,KAAK;AAAA,MAC1D;AAAA,IACF,WAAW,KAAK;AACd,iBAAW,QAAQ,EAAE,KAAK,IAAI;AAAA,IAChC;AAAA,EACF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,GAAG;AACnC,MAAI,KAAK;AACP,eAAW,OAAO,oBAAoB,GAAG;AAAA,EAC3C;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,GAAG;AACnC,MAAI,KAAK;AACP,eAAW,SAAS,oBAAoB,GAAG;AAAA,EAC7C;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,aAAiD;AAE3E,QAAM,cAAc,oBAAI,IAA+B;AACvD,aAAW,OAAO,YAAY,cAAc;AAC1C,gBAAY,IAAI,IAAI,eAAe,GAAG;AAAA,EACxC;AAEA,QAAM,SAAS,oBAAI,IAA+B;AAClD,aAAW,OAAO,YAAY,MAAM;AAClC,WAAO,IAAI,IAAI,OAAO,GAAG;AAAA,EAC3B;AAEA,SAAO;AAAA,IACL;AAAA,IAEA,SAAS,OAAe,MAAgC;AACtD,YAAM,MAAM,OAAO,IAAI,KAAK;AAC5B,UAAI,CAAC,IAAK,QAAO;AAGjB,UAAI,IAAI,gBAAgB;AACtB,cAAM,WAAW,IAAI,eAAe,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC/D,YAAI,UAAU;AACZ,cAAI,SAAS,KAAK;AAEhB,mBAAO,SAAS;AAAA,UAClB;AAEA,gBAAMC,eAAc,YAAY,IAAI,IAAI,aAAa;AACrD,cAAIA,cAAa;AACf,kBAAM,YAAYA,aAAY,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAChE,gBAAI,aAAa,SAAS,kBAAkB,QAAW;AACrD,qBAAO;AAAA,gBACL,GAAG;AAAA,gBACH,OAAO,SAAS;AAAA,cAClB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,YAAM,cAAc,YAAY,IAAI,IAAI,aAAa;AACrD,UAAI,CAAC,YAAa,QAAO;AAEzB,aAAO,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI,KAAK;AAAA,IAC5D;AAAA,IAEA,YAAY,eAAiD;AAC3D,aAAO,YAAY,IAAI,aAAa,KAAK;AAAA,IAC3C;AAAA,IAEA,aAAa,OAAwB;AACnC,aAAO,OAAO,IAAI,KAAK;AAAA,IACzB;AAAA,EACF;AACF;;;AC/gBA,SAAS,aAAa,KAAoD;AACxE,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,MAAM,SAAS,KAAK,EAAE;AAC5B,MAAI,MAAM,GAAG,EAAG,QAAO;AACvB,SAAO,MAAM;AACf;AASA,SAAS,eAAe,QAAoB,UAAqC;AAC/E,QAAM,WAAW,iBAAiB,MAAM;AACxC,aAAW,SAAS,UAAU;AAC5B,QAAI,MAAM,SAAS,UAAU;AAC3B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,UAAU,QAAoB,OAAoC;AACzE,QAAM,WAAW,iBAAiB,MAAM;AACxC,aAAW,SAAS,UAAU;AAC5B,QAAI,MAAM,SAAS,MAAM,QAAQ,EAAE,GAAG;AACpC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAYA,SAAS,YAAY,QAAsC;AACzD,MAAI,CAAC,QAAQ;AACX,WAAO,EAAE,OAAO,GAAG,QAAQ,EAAE;AAAA,EAC/B;AAEA,QAAM,KAAK,sBAAsB,QAAQ,MAAM,IAAI,KAAK;AACxD,QAAM,KAAK,sBAAsB,QAAQ,MAAM,IAAI,KAAK;AAExD,SAAO,EAAE,OAAO,IAAI,QAAQ,GAAG;AACjC;AAQA,SAAS,kBAAkB,cAA2D;AACpF,MAAI,CAAC,aAAc,QAAO;AAE1B,QAAM,IAAI,sBAAsB,cAAc,MAAM,GAAG,KAAK;AAC5D,QAAM,IAAI,sBAAsB,cAAc,MAAM,GAAG,KAAK;AAC5D,QAAM,IAAI,sBAAsB,cAAc,MAAM,GAAG,KAAK;AAC5D,QAAM,IAAI,sBAAsB,cAAc,MAAM,GAAG,KAAK;AAE5D,MAAI,MAAM,KAAK,MAAM,KAAK,MAAM,KAAK,MAAM,GAAG;AAC5C,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,EACV;AACF;AAYA,SAAS,cAAc,OAMrB;AACA,MAAI,CAAC,MAAO,QAAO,CAAC;AAEpB,QAAM,KAAK,aAAa,OAAO,MAAM,IAAI,KAAK;AAC9C,QAAM,OAAO,aAAa,OAAO,MAAM,MAAM,KAAK;AAClD,QAAM,QAAQ,aAAa,OAAO,MAAM,OAAO,KAAK;AACpD,QAAM,QAAQ,aAAa,OAAO,MAAM,OAAO,KAAK;AAIpD,QAAM,aAAa,aAAa,OAAO,MAAM,YAAY,MAAM;AAE/D,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL;AAAA,IACA,YAAY,cAAc;AAAA,EAC5B;AACF;AASA,SAAS,eAAe,MAAkE;AACxF,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,aAAa,aAAa,MAAM,MAAM,cAAc,KAAK;AAG/D,QAAM,UAAU,eAAe,MAAM,UAAU;AAC/C,MAAI,SAAS;AACX,UAAM,YAAY,QAAQ,WAAW,CAAC,GAAG,QAAQ;AACjD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,eAAe,MAAM,cAAc;AACvD,MAAI,aAAa;AACf,UAAM,aAAa,OAAO,YAAY,WAAW,CAAC,GAAG,QAAQ,GAAG;AAChE,UAAM,YAAY,SAAS,YAAY,EAAE;AACzC,WAAO;AAAA,MACL;AAAA,MACA,WAAW,MAAM,SAAS,IAAI,IAAI;AAAA,IACpC;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,EACF;AACF;AAKA,SAAS,eAAe,MAAgE;AACtF,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,aAAa,aAAa,MAAM,MAAM,cAAc,KAAK;AAG/D,QAAM,UAAU,eAAe,MAAM,UAAU;AAC/C,MAAI,SAAS;AACX,UAAM,YAAY,QAAQ,WAAW,CAAC,GAAG,QAAQ;AACjD,WAAO;AAAA,MACL;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,eAAe,MAAM,cAAc;AACvD,MAAI,aAAa;AACf,UAAM,aAAa,OAAO,YAAY,WAAW,CAAC,GAAG,QAAQ,GAAG;AAChE,UAAM,YAAY,SAAS,YAAY,EAAE;AACzC,WAAO;AAAA,MACL;AAAA,MACA,WAAW,MAAM,SAAS,IAAI,IAAI;AAAA,IACpC;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,EACF;AACF;AASA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKA,SAAS,iBAAiB,QAA2B,WAA+B;AAClF,MAAI,CAAC,QAAQ;AAEX,WAAO;AAAA,MACL,MAAM,YAAY,WAAW;AAAA,IAC/B;AAAA,EACF;AAEA,QAAM,WAAW,OAAO,QAAQ;AAChC,QAAM,WAAW,SAAS,QAAQ,OAAO,EAAE;AAG3C,QAAM,QAAQ,sBAAsB,QAAQ,MAAM,OAAO,KAAK;AAC9D,QAAM,QAAQ,sBAAsB,QAAQ,MAAM,OAAO,KAAK;AAC9D,QAAM,QAAQ,sBAAsB,QAAQ,MAAM,OAAO,KAAK;AAC9D,QAAM,QAAQ,sBAAsB,QAAQ,MAAM,OAAO,KAAK;AAG9D,QAAM,WAAW,aAAa,QAAQ,MAAM,UAAU,KAAK;AAE3D,MAAI;AACJ,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,YAAY,WAAW;AAC9B;AAAA,IACF,KAAK;AACH,aAAO;AACP;AAAA,IACF,KAAK;AACH,aAAO;AACP;AAAA,IACF,KAAK;AACH,aAAO;AACP;AAAA,IACF,KAAK;AACH,aAAO;AACP;AAAA,IACF;AACE,aAAO;AAAA,EACX;AAEA,QAAM,OAAkB,EAAE,KAAK;AAE/B,MAAI,UAAU;AACZ,SAAK,WAAW;AAAA,EAClB;AAEA,MAAI,UAAU,OAAW,MAAK,QAAQ;AACtC,MAAI,UAAU,OAAW,MAAK,QAAQ;AACtC,MAAI,UAAU,OAAW,MAAK,QAAQ;AACtC,MAAI,UAAU,OAAW,MAAK,QAAQ;AAEtC,SAAO;AACT;AASA,SAAS,eAAe,MAAqD;AAC3E,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,MAAM,aAAa,MAAM,MAAM,KAAK;AAC1C,QAAM,QAAQ,aAAa,MAAM,MAAM,OAAO,MAAM;AACpD,QAAM,QAAQ,aAAa,MAAM,MAAM,OAAO,MAAM;AAEpD,QAAM,WAAW,aAAa,GAAG;AAEjC,MAAI,aAAa,UAAa,CAAC,SAAS,CAAC,OAAO;AAC9C,WAAO;AAAA,EACT;AAEA,QAAM,YAA4B,CAAC;AACnC,MAAI,aAAa,OAAW,WAAU,WAAW;AACjD,MAAI,MAAO,WAAU,QAAQ;AAC7B,MAAI,MAAO,WAAU,QAAQ;AAE7B,SAAO;AACT;AAWA,SAAS,gBAAgB,WAA0C;AAEjE,QAAM,UAAU,eAAe,WAAW,WAAW;AACrD,MAAI,CAAC,QAAS,QAAO;AAGrB,QAAM,cAAc,eAAe,SAAS,eAAe;AAC3D,MAAI,CAAC,YAAa,QAAO;AAGzB,QAAM,MAAM,eAAe,aAAa,SAAS;AACjD,MAAI,CAAC,IAAK,QAAO;AAGjB,QAAM,WAAW,eAAe,KAAK,cAAc;AACnD,MAAI,CAAC,SAAU,QAAO;AAGtB,QAAM,OAAO,eAAe,UAAU,QAAQ;AAC9C,SAAO;AACT;AAKA,SAAS,eAAe,MAAiC;AACvD,MAAI,CAAC,KAAM,QAAO;AAGlB,QAAM,SAAS,aAAa,MAAM,KAAK,OAAO;AAC9C,MAAI,OAAQ,QAAO;AAGnB,QAAM,QAAQ,aAAa,MAAM,MAAM,OAAO;AAC9C,MAAI,MAAO,QAAO;AAGlB,QAAM,QAAQ,aAAa,MAAM,KAAK,MAAM;AAC5C,MAAI,MAAO,QAAO;AAElB,SAAO;AACT;AAOA,SAAS,qBAAqB,WAA0C;AACtE,QAAM,UAAU,eAAe,WAAW,WAAW;AACrD,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,cAAc,eAAe,SAAS,eAAe;AAC3D,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,MAAM,eAAe,aAAa,SAAS;AACjD,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,OAAO,eAAe,KAAK,UAAU;AAC3C,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,OAAO,eAAe,MAAM,QAAQ;AAC1C,SAAO;AACT;AASA,SAAS,mBAAmB,YAA4B;AACtD,MAAI,CAAC,WAAY,QAAO;AAGxB,MAAI,aAAa,WAAW,QAAQ,QAAQ,EAAE;AAG9C,MAAI,WAAW,WAAW,QAAQ,GAAG;AACnC,iBAAa,QAAQ,UAAU;AAAA,EACjC,WAAW,CAAC,WAAW,WAAW,OAAO,GAAG;AAC1C,iBAAa,QAAQ,UAAU;AAAA,EACjC;AAEA,SAAO;AACT;AAKA,SAAS,YAAY,MAAsB;AACzC,QAAM,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY,KAAK;AAEpD,QAAM,YAAoC;AAAA,IACxC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AAEA,SAAO,UAAU,GAAG,KAAK;AAC3B;AAUA,SAAS,iBACP,KACA,MACA,OACwD;AACxD,MAAI,CAAC,OAAO,CAAC,MAAM;AACjB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,MAAM,KAAK,IAAI,GAAG;AACxB,MAAI,CAAC,KAAK;AACR,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,aAAa,IAAI;AACvB,MAAI,CAAC,YAAY;AACf,WAAO,CAAC;AAAA,EACV;AAGA,QAAM,iBAAiB,mBAAmB,UAAU;AACpD,QAAM,WAAW,WAAW,MAAM,GAAG,EAAE,IAAI;AAG3C,QAAM,2BAA2B,CAC/B,KACA,eAC0B;AAC1B,UAAM,YAAY,WAAW,YAAY;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,IAAI,QAAQ,GAAG;AACxC,UAAI,IAAI,YAAY,MAAM,WAAW;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAGA,MAAI,OAAO;AAET,UAAM,YAAY,yBAAyB,OAAO,cAAc;AAChE,QAAI,WAAW;AACb,aAAO;AAAA,QACL,KAAK,UAAU,WAAW,UAAU;AAAA;AAAA,QACpC,UAAU,UAAU;AAAA,QACpB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,UAAU,WAAW,QAAQ,QAAQ,EAAE;AAC7C,UAAM,eAAe,yBAAyB,OAAO,OAAO;AAC5D,QAAI,cAAc;AAChB,aAAO;AAAA,QACL,KAAK,aAAa,WAAW,aAAa;AAAA,QAC1C,UAAU,aAAa;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,iBAAiB,QAAQ,OAAO;AACtC,UAAM,oBAAoB,yBAAyB,OAAO,cAAc;AACxE,QAAI,mBAAmB;AACrB,aAAO;AAAA,QACL,KAAK,kBAAkB,WAAW,kBAAkB;AAAA,QACpD,UAAU,kBAAkB;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AAAA,IACL,UAAU,YAAY,UAAU;AAAA,IAChC;AAAA,EACF;AACF;AAcA,SAAS,YACP,UACA,MACA,OACO;AAEP,QAAM,SAAS,eAAe,UAAU,WAAW;AACnD,QAAM,OAAO,YAAY,MAAM;AAG/B,QAAM,eAAe,eAAe,UAAU,iBAAiB;AAC/D,QAAM,UAAU,kBAAkB,YAAY;AAG9C,QAAM,QAAQ,eAAe,UAAU,UAAU;AACjD,QAAM,QAAQ,cAAc,KAAK;AAGjC,QAAM,OAAO,gBAAgB,QAAQ;AACrC,QAAM,MAAM,eAAe,IAAI;AAG/B,QAAM,YAAY,iBAAiB,KAAK,MAAM,KAAK;AAGnD,QAAM,OAAO,qBAAqB,QAAQ;AAC1C,QAAM,YAAY,eAAe,IAAI;AAErC,QAAM,QAAe;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,MAAM,EAAE,MAAM,SAAS;AAAA,EACzB;AAGA,MAAI,MAAM,GAAI,OAAM,KAAK,MAAM;AAC/B,MAAI,MAAM,IAAK,OAAM,MAAM,MAAM;AACjC,MAAI,MAAM,MAAO,OAAM,QAAQ,MAAM;AACrC,MAAI,MAAM,WAAY,OAAM,aAAa;AACzC,MAAI,UAAU,IAAK,OAAM,MAAM,UAAU;AACzC,MAAI,UAAU,SAAU,OAAM,WAAW,UAAU;AACnD,MAAI,UAAU,SAAU,OAAM,WAAW,UAAU;AACnD,MAAI,QAAS,OAAM,UAAU;AAC7B,MAAI,UAAW,OAAM,YAAY;AAEjC,SAAO;AACT;AAUA,SAAS,YACP,UACA,MACA,OACO;AAEP,QAAM,SAAS,eAAe,UAAU,WAAW;AACnD,QAAM,OAAO,YAAY,MAAM;AAG/B,QAAM,eAAe,eAAe,UAAU,iBAAiB;AAC/D,QAAM,UAAU,kBAAkB,YAAY;AAG9C,QAAM,QAAQ,eAAe,UAAU,UAAU;AACjD,QAAM,QAAQ,cAAc,KAAK;AAGjC,QAAM,YAAY,aAAa,UAAU,MAAM,WAAW,MAAM;AAGhE,QAAM,SAAS,UAAU,UAAU,aAAa;AAChD,QAAM,OAAO,iBAAiB,QAAQ,SAAS;AAG/C,QAAM,OAAO,eAAe,UAAU,cAAc;AACpD,QAAM,OAAO,eAAe,UAAU,cAAc;AACpD,QAAM,aAAa,eAAe,IAAI;AACtC,QAAM,WAAW,eAAe,IAAI;AAEpC,MAAI;AACJ,MAAI,cAAc,UAAU;AAC1B,eAAW;AAAA,MACT,YAAY,cAAc,EAAE,YAAY,SAAS;AAAA,MACjD,UAAU,YAAY,EAAE,YAAY,YAAY;AAAA,IAClD;AAAA,EACF;AAGA,QAAM,OAAO,gBAAgB,QAAQ;AACrC,QAAM,MAAM,eAAe,IAAI;AAG/B,QAAM,YAAY,iBAAiB,KAAK,MAAM,KAAK;AAGnD,QAAM,OAAO,qBAAqB,QAAQ;AAC1C,QAAM,YAAY,eAAe,IAAI;AAErC,QAAM,QAAe;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAGA,MAAI,MAAM,GAAI,OAAM,KAAK,MAAM;AAC/B,MAAI,MAAM,IAAK,OAAM,MAAM,MAAM;AACjC,MAAI,MAAM,MAAO,OAAM,QAAQ,MAAM;AACrC,MAAI,MAAM,WAAY,OAAM,aAAa;AACzC,MAAI,UAAU,IAAK,OAAM,MAAM,UAAU;AACzC,MAAI,UAAU,SAAU,OAAM,WAAW,UAAU;AACnD,MAAI,UAAU,SAAU,OAAM,WAAW,UAAU;AACnD,MAAI,SAAU,OAAM,WAAW;AAC/B,MAAI,QAAS,OAAM,UAAU;AAC7B,MAAI,UAAW,OAAM,YAAY;AAEjC,SAAO;AACT;AAYO,SAAS,aACd,WACA,MACA,OACc;AACd,QAAM,WAAW,iBAAiB,SAAS;AAE3C,aAAW,SAAS,UAAU;AAC5B,UAAM,OAAO,MAAM,QAAQ;AAE3B,QAAI,SAAS,aAAa;AACxB,aAAO,YAAY,OAAO,MAAM,KAAK;AAAA,IACvC;AAEA,QAAI,SAAS,aAAa;AACxB,aAAO,YAAY,OAAO,MAAM,KAAK;AAAA,IACvC;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,WACd,MACA,MACA,OACc;AACd,SAAO,aAAa,MAAM,MAAM,KAAK;AACvC;;;AC1sBA,SAASC,iBACP,KACA,YACA,WACA,YACY;AACZ,QAAM,QAAoB,CAAC;AAE3B,MAAI,OAAO,QAAQ,QAAQ;AACzB,UAAM,MAAM;AAAA,EACd,WAAW,QAAQ,QAAQ;AACzB,UAAM,OAAO;AAAA,EACf;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,MAAI,WAAW;AACb,UAAM,YAAY;AAAA,EACpB;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO;AACT;AAKA,SAASC,wBAAuB,KAAuD;AACrF,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,QAA2B,CAAC;AAElC,QAAM,QAAQ,aAAa,KAAK,KAAK,OAAO;AAC5C,MAAI,SAAS,UAAU,QAAQ;AAC7B,UAAM,QAAQ,EAAE,KAAK,MAAM;AAAA,EAC7B;AAEA,QAAM,OAAO,aAAa,KAAK,KAAK,MAAM;AAC1C,MAAI,QAAQ,SAAS,QAAQ;AAC3B,UAAM,OAAO,EAAE,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,YAAY,aAAa,KAAK,KAAK,WAAW;AACpD,MAAI,WAAW;AACb,UAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,QAAM,gBAAgB,aAAa,KAAK,KAAK,eAAe;AAC5D,MAAI,iBAAiB,MAAM,MAAM;AAC/B,UAAM,KAAK,YAAY;AAAA,EACzB;AAEA,QAAM,iBAAiB,aAAa,KAAK,KAAK,gBAAgB;AAC9D,MAAI,kBAAkB,MAAM,MAAM;AAChC,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,QAAM,UAAU,aAAa,KAAK,KAAK,KAAK;AAC5C,MAAI,SAAS;AACX,UAAM,UAAU;AAAA,EAClB;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAmBO,SAASC,oBACd,KACA,OACA,SAC4B;AAC5B,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,aAA6B,CAAC;AAGpC,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,EAAG,YAAW,OAAO,oBAAoB,CAAC;AAE9C,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,IAAK,YAAW,SAAS,oBAAoB,GAAG;AAGpD,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,EAAG,YAAW,SAAS,oBAAoB,CAAC;AAEhD,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,IAAK,YAAW,WAAW,oBAAoB,GAAG;AAGtD,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,GAAG;AACL,UAAM,QAAQ,aAAa,GAAG,KAAK,KAAK;AACxC,QAAI,OAAO;AACT,iBAAW,YAAY,EAAE,MAAM;AAC/B,YAAM,WAAW,aAAa,GAAG,KAAK,OAAO;AAC7C,YAAM,aAAa,aAAa,GAAG,KAAK,YAAY;AACpD,UAAI,YAAY,YAAY;AAC1B,mBAAW,UAAU,QAAQF;AAAA,UAC3B;AAAA,UACA;AAAA,UACA,aAAa,GAAG,KAAK,WAAW;AAAA,UAChC,aAAa,GAAG,KAAK,YAAY;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,QAAS,YAAW,eAAe,oBAAoB,OAAO;AAGlE,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,WAAW;AACb,UAAM,MAAM,aAAa,WAAW,KAAK,KAAK;AAC9C,QAAI,QAAQ,iBAAiB,QAAQ,eAAe,QAAQ,YAAY;AACtE,iBAAW,YAAY;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,UAAW,YAAW,YAAY,oBAAoB,SAAS;AAGnE,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,KAAM,YAAW,UAAU,oBAAoB,IAAI;AAGvD,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,QAAQ,UAAU,KAAK,KAAK,OAAO;AACzC,MAAI,OAAO;AACT,eAAW,QAAQA;AAAA,MACjB,aAAa,OAAO,KAAK,KAAK;AAAA,MAC9B,aAAa,OAAO,KAAK,YAAY;AAAA,MACrC,aAAa,OAAO,KAAK,WAAW;AAAA,MACpC,aAAa,OAAO,KAAK,YAAY;AAAA,IACvC;AAAA,EACF;AAGA,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,WAAW;AACb,UAAM,MAAM,aAAa,WAAW,KAAK,KAAK;AAC9C,QAAI,KAAK;AACP,iBAAW,YAAY;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,eAAW,UAAUC,wBAAuB,GAAG;AAAA,EACjD;AAGA,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,IAAI;AACN,UAAM,MAAM,sBAAsB,IAAI,KAAK,KAAK;AAChD,QAAI,QAAQ,OAAW,YAAW,WAAW;AAAA,EAC/C;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,UAAM,MAAM,sBAAsB,MAAM,KAAK,KAAK;AAClD,QAAI,QAAQ,OAAW,YAAW,aAAa;AAAA,EACjD;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,eAAW,aAAa;AAAA,MACtB,OAAO,aAAa,QAAQ,KAAK,OAAO,KAAK;AAAA,MAC7C,OAAO,aAAa,QAAQ,KAAK,OAAO,KAAK;AAAA,MAC7C,UAAU,aAAa,QAAQ,KAAK,UAAU,KAAK;AAAA,MACnD,IAAI,aAAa,QAAQ,KAAK,IAAI,KAAK;AAAA,IACzC;AAGA,UAAM,aAAa,aAAa,QAAQ,KAAK,YAAY;AACzD,QAAI,YAAY;AACd,iBAAW,WAAW,aAAa;AAMnC,UAAI,SAAS,CAAC,WAAW,WAAW,OAAO;AACzC,mBAAW,WAAW,QAAQ,oBAAoB,OAAO,UAAU;AAAA,MACrE;AAAA,IACF;AAEA,UAAM,aAAa,aAAa,QAAQ,KAAK,YAAY;AACzD,QAAI,YAAY;AACd,iBAAW,WAAW,aAAa;AACnC,UAAI,SAAS,CAAC,WAAW,WAAW,OAAO;AACzC,mBAAW,WAAW,QAAQ,oBAAoB,OAAO,UAAU;AAAA,MACrE;AAAA,IACF;AAEA,UAAM,gBAAgB,aAAa,QAAQ,KAAK,eAAe;AAC/D,QAAI,eAAe;AACjB,iBAAW,WAAW,gBAAgB;AACtC,UAAI,SAAS,CAAC,WAAW,WAAW,UAAU;AAC5C,mBAAW,WAAW,WAAW,oBAAoB,OAAO,aAAa;AAAA,MAC3E;AAAA,IACF;AAEA,UAAM,UAAU,aAAa,QAAQ,KAAK,SAAS;AACnD,QAAI,SAAS;AACX,iBAAW,WAAW,UAAU;AAChC,UAAI,SAAS,CAAC,WAAW,WAAW,IAAI;AACtC,mBAAW,WAAW,KAAK,oBAAoB,OAAO,OAAO;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAGA,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,SAAS;AACX,UAAM,MAAM,sBAAsB,SAAS,KAAK,KAAK;AACrD,QAAI,QAAQ,OAAW,YAAW,UAAU;AAAA,EAC9C;AAGA,QAAM,WAAW,UAAU,KAAK,KAAK,UAAU;AAC/C,MAAI,UAAU;AACZ,UAAM,MAAM,sBAAsB,UAAU,KAAK,KAAK;AACtD,QAAI,QAAQ,OAAW,YAAW,WAAW;AAAA,EAC/C;AAGA,QAAM,IAAI,UAAU,KAAK,KAAK,GAAG;AACjC,MAAI,GAAG;AACL,UAAM,MAAM,sBAAsB,GAAG,KAAK,KAAK;AAC/C,QAAI,QAAQ,OAAW,YAAW,QAAQ;AAAA,EAC5C;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,UAAM,MAAM,sBAAsB,MAAM,KAAK,KAAK;AAClD,QAAI,QAAQ,OAAW,YAAW,UAAU;AAAA,EAC9C;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,IAAK,YAAW,SAAS;AAAA,EAC/B;AAGA,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,IAAI;AACN,UAAM,MAAM,aAAa,IAAI,KAAK,KAAK;AACvC,QAAI,IAAK,YAAW,eAAe;AAAA,EACrC;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,QAAS,YAAW,UAAU,oBAAoB,OAAO;AAG7D,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,QAAS,YAAW,UAAU,oBAAoB,OAAO;AAG7D,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,OAAQ,YAAW,SAAS,oBAAoB,MAAM;AAG1D,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,IAAK,YAAW,MAAM,oBAAoB,GAAG;AAGjD,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,GAAI,YAAW,KAAK,oBAAoB,EAAE;AAG9C,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,IAAK,YAAW,UAAU;AAAA,EAChC;AAEA,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AAKA,SAAS,iBAAiB,SAAkC;AAC1D,QAAM,OAAO,eAAe,OAAO;AACnC,QAAM,gBAAgB,aAAa,SAAS,OAAO,OAAO,MAAM;AAEhE,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,eAAe,iBAAiB;AAAA,EAClC;AACF;AAKA,SAAS,kBAA8B;AACrC,SAAO,EAAE,MAAM,MAAM;AACvB;AAKA,SAAS,kBAAkB,SAAmC;AAC5D,QAAM,YAAY,aAAa,SAAS,KAAK,MAAM;AACnD,QAAM,QAAQ,aAAa,SAAS,KAAK,OAAO;AAEhD,QAAM,UAAwB,EAAE,MAAM,QAAQ;AAE9C,MAAI,cAAc,UAAU,cAAc,YAAY,cAAc,gBAAgB;AAClF,YAAQ,YAAY;AAAA,EACtB;AAEA,MAAI,UAAU,UAAU,UAAU,UAAU,UAAU,WAAW,UAAU,OAAO;AAChF,YAAQ,QAAQ;AAAA,EAClB;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,SAAoC;AAC9D,QAAM,OAAO,aAAa,SAAS,KAAK,MAAM,KAAK;AACnD,QAAM,OAAO,aAAa,SAAS,KAAK,MAAM,KAAK;AAEnD,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF;AACF;AAKA,SAAS,uBAAuB,SAA2C;AACzE,QAAM,KAAK,sBAAsB,SAAS,KAAK,IAAI,KAAK;AAExD,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAKA,SAAS,sBAAsB,SAA2C;AACxE,QAAM,KAAK,sBAAsB,SAAS,KAAK,IAAI,KAAK;AAExD,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAKA,SAAS,eAAe,SAAuC;AAC7D,QAAM,cAAc,aAAa,SAAS,KAAK,aAAa;AAC5D,QAAM,UACJ,aAAa,SAAS,KAAK,SAAS,MAAM,UAC1C,aAAa,SAAS,KAAK,SAAS,MAAM;AAC5C,QAAM,QACJ,aAAa,SAAS,KAAK,OAAO,MAAM,UAAU,aAAa,SAAS,KAAK,OAAO,MAAM;AAE5F,MAAI,WAAyC;AAC7C,MAAI,gBAAgB,WAAY,YAAW;AAAA,WAClC,gBAAgB,MAAO,YAAW;AAE3C,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,SAAS,WAAW;AAAA,IACpB,OAAO,SAAS;AAAA,EAClB;AACF;AAKA,SAAS,eAAe,SAAuC;AAC7D,QAAM,OAAO,eAAe,OAAO;AAEnC,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAQA,SAAS,oBACP,SACA,MACA,OACuB;AAEvB,QAAM,QAAQ,WAAW,SAAS,QAAQ,QAAW,SAAS,MAAS;AAEvE,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAKA,SAASE,cAAa,MAAkC;AACtD,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,SAAO,cAAc,IAAI,KAAK,UAAU,aAAa,CAAC,IAAI;AAC5D;AAKA,SAAS,iBACP,YACA,MACA,OACc;AACd,QAAM,WAAyB,CAAC;AAChC,QAAM,WAAW,iBAAiB,UAAU;AAE5C,aAAW,SAAS,UAAU;AAC5B,UAAM,YAAYA,cAAa,MAAM,IAAI;AAEzC,YAAQ,WAAW;AAAA,MACjB,KAAK;AAEH,iBAAS,KAAK,iBAAiB,KAAK,CAAC;AACrC;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,gBAAgB,CAAC;AAC/B;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,kBAAkB,KAAK,CAAC;AACtC;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,mBAAmB,KAAK,CAAC;AACvC;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,uBAAuB,KAAK,CAAC;AAC3C;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,sBAAsB,KAAK,CAAC;AAC1C;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,eAAe,KAAK,CAAC;AACnC;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,eAAe,KAAK,CAAC;AACnC;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,EAAE,MAAM,aAAa,CAAsB;AACzD;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,EAAE,MAAM,gBAAgB,CAAyB;AAC/D;AAAA,MAEF,KAAK;AAEH,cAAM,UAAU,oBAAoB,OAAO,MAAM,KAAK;AACtD,YAAI,SAAS;AACX,mBAAS,KAAK,OAAO;AAAA,QACvB;AACA;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAGH;AAAA,MAEF,KAAK;AAEH;AAAA,MAEF,KAAK;AAEH;AAAA,MAEF,KAAK;AAEH,iBAAS,KAAK,EAAE,MAAM,SAAS,WAAW,eAAe,CAAiB;AAC1E;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAGH;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAEH;AAAA,MAEF;AAGE;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,SACd,MACA,QACA,OACA,OAA+B,MAC/B,QAAuC,MAClC;AACL,QAAM,MAAW;AAAA,IACf,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,EACZ;AAGA,QAAM,MAAM,UAAU,MAAM,KAAK,KAAK;AACtC,MAAI,KAAK;AACP,QAAI,aAAaD,oBAAmB,KAAK,OAAO,UAAU,MAAS;AAAA,EACrE;AAGA,MAAI,UAAU,iBAAiB,MAAM,MAAM,KAAK;AAEhD,SAAO;AACT;;;ACvnBA,SAASE,cAAa,MAAkC;AACtD,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,SAAO,cAAc,IAAI,KAAK,UAAU,aAAa,CAAC,IAAI;AAC5D;AAOA,SAAS,mBAAmB,MAAiC;AAC3D,QAAM,KAAK,sBAAsB,MAAM,KAAK,IAAI,KAAK;AACrD,QAAM,OAAO,aAAa,MAAM,KAAK,MAAM,KAAK;AAEhD,QAAM,WAA0B;AAAA,IAC9B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF;AAGA,QAAM,WAAW,sBAAsB,MAAM,KAAK,UAAU;AAC5D,MAAI,aAAa,OAAW,UAAS,WAAW;AAEhD,QAAM,UAAU,sBAAsB,MAAM,KAAK,SAAS;AAC1D,MAAI,YAAY,OAAW,UAAS,UAAU;AAE9C,SAAO;AACT;AAKA,SAAS,iBAAiB,MAA+B;AACvD,QAAM,KAAK,sBAAsB,MAAM,KAAK,IAAI,KAAK;AAErD,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAeO,SAAS,eACd,MACA,MACA,SAA0B,MAC1B,QAAsB,MACtB,QAAuC,MAC5B;AACX,QAAM,YAAuB;AAAA,IAC3B,MAAM;AAAA,IACN,UAAU,CAAC;AAAA,EACb;AAIA,QAAM,MAAM,aAAa,MAAM,KAAK,IAAI;AACxC,MAAI,KAAK;AACP,cAAU,MAAM;AAGhB,QAAI,MAAM;AACR,YAAM,MAAM,KAAK,IAAI,GAAG;AACxB,UAAI,KAAK;AAEP,YAAI,oBAAoB,GAAG,GAAG;AAC5B,oBAAU,OAAO,IAAI;AAAA,QACvB,OAAO;AAEL,oBAAU,OAAO,IAAI;AAAA,QACvB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAIA,QAAM,SAAS,aAAa,MAAM,KAAK,QAAQ;AAC/C,MAAI,QAAQ;AACV,cAAU,SAAS;AAEnB,QAAI,CAAC,UAAU,MAAM;AACnB,gBAAU,OAAO,IAAI,MAAM;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,UAAU,aAAa,MAAM,KAAK,SAAS;AACjD,MAAI,SAAS;AACX,cAAU,UAAU;AAAA,EACtB;AAIA,QAAM,WAAW,aAAa,MAAM,KAAK,UAAU;AACnD,MAAI,UAAU;AACZ,cAAU,SAAS;AAAA,EACrB;AAIA,QAAM,UAAU,aAAa,MAAM,KAAK,SAAS;AACjD,MAAI,YAAY,OAAO,YAAY,QAAQ;AACzC,cAAU,UAAU;AAAA,EACtB;AAIA,QAAM,cAAc,aAAa,MAAM,KAAK,aAAa;AACzD,MAAI,aAAa;AACf,cAAU,cAAc;AAAA,EAC1B;AAIA,QAAM,WAAW,iBAAiB,IAAI;AACtC,aAAW,SAAS,UAAU;AAC5B,UAAM,YAAYA,cAAa,MAAM,IAAI;AAEzC,YAAQ,WAAW;AAAA,MACjB,KAAK;AACH,kBAAU,SAAS,KAAK,SAAS,OAAO,QAAQ,OAAO,MAAM,KAAK,CAAC;AACnE;AAAA,MAEF,KAAK;AACH,kBAAU,SAAS,KAAK,mBAAmB,KAAK,CAAC;AACjD;AAAA,MAEF,KAAK;AACH,kBAAU,SAAS,KAAK,iBAAiB,KAAK,CAAC;AAC/C;AAAA,IAIJ;AAAA,EACF;AAEA,SAAO;AACT;;;AC9JO,SAASC,oBAAmB,MAAiC;AAClE,QAAM,KAAK,sBAAsB,MAAM,KAAK,IAAI,KAAK;AACrD,QAAM,OAAO,aAAa,MAAM,KAAK,MAAM,KAAK;AAEhD,QAAM,WAA0B;AAAA,IAC9B,MAAM;AAAA,IACN;AAAA,IACA;AAAA,EACF;AAGA,QAAM,WAAW,sBAAsB,MAAM,KAAK,UAAU;AAC5D,MAAI,aAAa,QAAW;AAC1B,aAAS,WAAW;AAAA,EACtB;AAEA,QAAM,UAAU,sBAAsB,MAAM,KAAK,SAAS;AAC1D,MAAI,YAAY,QAAW;AACzB,aAAS,UAAU;AAAA,EACrB;AAEA,SAAO;AACT;AAUO,SAASC,kBAAiB,MAA+B;AAC9D,QAAM,KAAK,sBAAsB,MAAM,KAAK,IAAI,KAAK;AAErD,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,EACF;AACF;;;ACTO,SAASC,uBAAsB,SAA0D;AAC9F,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAQ,sBAAsB,SAAS,KAAK,GAAG,KAAK;AAC1D,QAAM,UAAU,aAAa,SAAS,KAAK,MAAM,KAAK;AAEtD,MAAI,OAAuB;AAC3B,MAAI,YAAY,UAAU,YAAY,SAAS,YAAY,SAAS,YAAY,OAAO;AACrF,WAAO;AAAA,EACT;AAEA,SAAO,EAAE,OAAO,KAAK;AACvB;AAKA,SAAS,WAAW,SAA0D;AAC5E,SAAOA,uBAAsB,OAAO;AACtC;AAYO,SAASC,iBAAgB,SAAoD;AAClF,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,WAAW,aAAa,SAAS,KAAK,KAAK,KAAK;AACtD,QAAM,QAAQ;AAEd,QAAM,SAAqB,EAAE,MAAM;AAGnC,QAAM,KAAK,sBAAsB,SAAS,KAAK,IAAI;AACnD,MAAI,OAAO,QAAW;AACpB,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,QAAQ,sBAAsB,SAAS,KAAK,OAAO;AACzD,MAAI,UAAU,QAAW;AACvB,WAAO,QAAQ;AAAA,EACjB;AAGA,QAAM,YAAY,kBAAkB,OAAO;AAC3C,MAAI,WAAW;AACb,WAAO,QAAQ;AAAA,MACb,KAAK,UAAU;AAAA,MACf,YAAY,UAAU;AAAA,MACtB,WAAW,UAAU;AAAA,MACrB,YAAY,UAAU;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,SAAS,aAAa,SAAS,KAAK,QAAQ;AAClD,MAAI,WAAW,OAAO,WAAW,QAAQ;AACvC,WAAO,SAAS;AAAA,EAClB;AAGA,QAAM,QAAQ,aAAa,SAAS,KAAK,OAAO;AAChD,MAAI,UAAU,OAAO,UAAU,QAAQ;AACrC,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;AAQO,SAASC,mBAAkB,gBAA6D;AAC7F,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,UAAwB,CAAC;AAE/B,QAAM,MAAMD,iBAAgB,UAAU,gBAAgB,KAAK,KAAK,CAAC;AACjE,MAAI,IAAK,SAAQ,MAAM;AAEvB,QAAM,SAASA,iBAAgB,UAAU,gBAAgB,KAAK,QAAQ,CAAC;AACvE,MAAI,OAAQ,SAAQ,SAAS;AAE7B,QAAM,OAAOA;AAAA,IACX,UAAU,gBAAgB,KAAK,MAAM,KAAK,UAAU,gBAAgB,KAAK,OAAO;AAAA,EAClF;AACA,MAAI,KAAM,SAAQ,OAAO;AAEzB,QAAM,QAAQA;AAAA,IACZ,UAAU,gBAAgB,KAAK,OAAO,KAAK,UAAU,gBAAgB,KAAK,KAAK;AAAA,EACjF;AACA,MAAI,MAAO,SAAQ,QAAQ;AAE3B,QAAM,UAAUA,iBAAgB,UAAU,gBAAgB,KAAK,SAAS,CAAC;AACzE,MAAI,QAAS,SAAQ,UAAU;AAE/B,QAAM,UAAUA,iBAAgB,UAAU,gBAAgB,KAAK,SAAS,CAAC;AACzE,MAAI,QAAS,SAAQ,UAAU;AAG/B,MAAI,OAAO,KAAK,OAAO,EAAE,WAAW,EAAG,QAAO;AAE9C,SAAO;AACT;AAYO,SAASE,kBAAiB,gBAA4D;AAC3F,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,UAAuB,CAAC;AAE9B,QAAM,MAAM,WAAW,UAAU,gBAAgB,KAAK,KAAK,CAAC;AAC5D,MAAI,IAAK,SAAQ,MAAM;AAEvB,QAAM,SAAS,WAAW,UAAU,gBAAgB,KAAK,QAAQ,CAAC;AAClE,MAAI,OAAQ,SAAQ,SAAS;AAE7B,QAAM,OAAO;AAAA,IACX,UAAU,gBAAgB,KAAK,MAAM,KAAK,UAAU,gBAAgB,KAAK,OAAO;AAAA,EAClF;AACA,MAAI,KAAM,SAAQ,OAAO;AAEzB,QAAM,QAAQ;AAAA,IACZ,UAAU,gBAAgB,KAAK,OAAO,KAAK,UAAU,gBAAgB,KAAK,KAAK;AAAA,EACjF;AACA,MAAI,MAAO,SAAQ,QAAQ;AAE3B,MAAI,OAAO,KAAK,OAAO,EAAE,WAAW,EAAG,QAAO;AAE9C,SAAO;AACT;AAYO,SAAS,aAAa,YAA8D;AACzF,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,UAA6B,CAAC;AAGpC,QAAM,UAAU,aAAa,YAAY,KAAK,MAAM;AACpD,MAAI,WAAW,YAAY,QAAQ;AACjC,YAAQ,OAAO,EAAE,KAAK,QAAQ;AAAA,EAChC;AAGA,QAAM,YAAY,aAAa,YAAY,KAAK,WAAW;AAC3D,MAAI,WAAW;AACb,YAAQ,OAAO,EAAE,YAAY,UAAiB;AAE9C,UAAM,gBAAgB,aAAa,YAAY,KAAK,eAAe;AACnE,QAAI,iBAAiB,QAAQ,MAAM;AACjC,cAAQ,KAAK,YAAY;AAAA,IAC3B;AAEA,UAAM,iBAAiB,aAAa,YAAY,KAAK,gBAAgB;AACrE,QAAI,kBAAkB,QAAQ,MAAM;AAClC,cAAQ,KAAK,aAAa;AAAA,IAC5B;AAAA,EACF;AAGA,QAAM,WAAW,aAAa,YAAY,KAAK,OAAO;AACtD,MAAI,YAAY,aAAa,QAAQ;AACnC,YAAQ,QAAQ,EAAE,KAAK,SAAS;AAAA,EAClC;AAGA,QAAM,UAAU,aAAa,YAAY,KAAK,KAAK;AACnD,MAAI,SAAS;AACX,YAAQ,UAAU;AAAA,EACpB;AAEA,MAAI,OAAO,KAAK,OAAO,EAAE,WAAW,EAAG,QAAO;AAE9C,SAAO;AACT;AAYO,SAASC,gBAAe,aAAuD;AACpF,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,OAAkB,CAAC;AAGzB,QAAM,WAAW,aAAa,aAAa,KAAK,UAAU;AAC1D,MAAI,aAAa,OAAO,aAAa,OAAQ,MAAK,WAAW;AAE7D,QAAM,UAAU,aAAa,aAAa,KAAK,SAAS;AACxD,MAAI,YAAY,OAAO,YAAY,OAAQ,MAAK,UAAU;AAE1D,QAAM,cAAc,aAAa,aAAa,KAAK,aAAa;AAChE,MAAI,gBAAgB,OAAO,gBAAgB,OAAQ,MAAK,cAAc;AAEtE,QAAM,aAAa,aAAa,aAAa,KAAK,YAAY;AAC9D,MAAI,eAAe,OAAO,eAAe,OAAQ,MAAK,aAAa;AAEnE,QAAM,UAAU,aAAa,aAAa,KAAK,SAAS;AACxD,MAAI,YAAY,OAAO,YAAY,OAAQ,MAAK,UAAU;AAE1D,QAAM,UAAU,aAAa,aAAa,KAAK,SAAS;AACxD,MAAI,YAAY,OAAO,YAAY,OAAQ,MAAK,UAAU;AAG1D,QAAM,MAAM,aAAa,aAAa,KAAK,KAAK;AAChD,MAAI,KAAK;AACP,UAAM,QAAQ,SAAS,KAAK,EAAE;AAC9B,QAAI,CAAC,MAAM,KAAK,GAAG;AACjB,UAAI,QAAQ,GAAQ,MAAK,WAAW;AACpC,UAAI,QAAQ,GAAQ,MAAK,UAAU;AACnC,UAAI,QAAQ,IAAQ,MAAK,cAAc;AACvC,UAAI,QAAQ,IAAQ,MAAK,aAAa;AACtC,UAAI,QAAQ,IAAQ,MAAK,UAAU;AACnC,UAAI,QAAQ,KAAQ,MAAK,UAAU;AAAA,IACrC;AAAA,EACF;AAEA,MAAI,OAAO,KAAK,IAAI,EAAE,WAAW,EAAG,QAAO;AAE3C,SAAO;AACT;AAYO,SAAS,6BACd,eACqC;AACrC,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,WAAoC,CAAC;AAG3C,QAAM,aAAa,aAAa,eAAe,KAAK,YAAY;AAChE,MAAI,eAAe,YAAY,eAAe,UAAU,eAAe,QAAQ;AAC7E,aAAS,aAAa;AAAA,EACxB;AAGA,QAAM,aAAa,aAAa,eAAe,KAAK,YAAY;AAChE,MAAI,eAAe,YAAY,eAAe,UAAU,eAAe,QAAQ;AAC7E,aAAS,aAAa;AAAA,EACxB;AAGA,QAAM,QAAQ,sBAAsB,eAAe,KAAK,OAAO;AAC/D,MAAI,UAAU,OAAW,UAAS,QAAQ;AAE1C,QAAM,YAAY,aAAa,eAAe,KAAK,WAAW;AAC9D,MAAI,WAAW;AACb,aAAS,YAAY;AAAA,EACvB;AAGA,QAAM,QAAQ,sBAAsB,eAAe,KAAK,OAAO;AAC/D,MAAI,UAAU,OAAW,UAAS,QAAQ;AAE1C,QAAM,YAAY,aAAa,eAAe,KAAK,WAAW;AAC9D,MAAI,WAAW;AACb,aAAS,YAAY;AAAA,EACvB;AAGA,QAAM,cAAc,sBAAsB,eAAe,KAAK,aAAa;AAC3E,MAAI,gBAAgB,OAAW,UAAS,cAAc;AAEtD,QAAM,iBAAiB,sBAAsB,eAAe,KAAK,gBAAgB;AACjF,MAAI,mBAAmB,OAAW,UAAS,iBAAiB;AAE5D,QAAM,eAAe,sBAAsB,eAAe,KAAK,cAAc;AAC7E,MAAI,iBAAiB,OAAW,UAAS,eAAe;AAExD,QAAM,gBAAgB,sBAAsB,eAAe,KAAK,eAAe;AAC/E,MAAI,kBAAkB,OAAW,UAAS,gBAAgB;AAE1D,MAAI,OAAO,KAAK,QAAQ,EAAE,WAAW,EAAG,QAAO;AAE/C,SAAO;AACT;AAYO,SAASC,sBAAqB,cAA8D;AACjG,MAAI,CAAC,aAAc,QAAO;AAE1B,QAAM,aAA8B,CAAC;AAGrC,QAAM,QAAQ,WAAW,UAAU,cAAc,KAAK,MAAM,CAAC;AAC7D,MAAI,MAAO,YAAW,QAAQ;AAG9B,QAAM,YAAY,UAAU,cAAc,KAAK,IAAI;AACnD,MAAI,WAAW;AACb,UAAM,QAAQ,aAAa,WAAW,KAAK,KAAK;AAChD,QAAI,UAAU,UAAU,UAAU,YAAY,UAAU,WAAW,UAAU,SAAS;AACpF,iBAAW,gBAAgB,UAAU,UAAU,SAAS;AAAA,IAC1D;AAAA,EACF;AAGA,QAAM,cAAc,WAAW,UAAU,cAAc,KAAK,gBAAgB,CAAC;AAC7E,MAAI,YAAa,YAAW,cAAc;AAG1C,QAAM,SAAS,WAAW,UAAU,cAAc,KAAK,QAAQ,CAAC;AAChE,MAAI,OAAQ,YAAW,SAAS;AAGhC,QAAM,UAAUH,mBAAkB,UAAU,cAAc,KAAK,YAAY,CAAC;AAC5E,MAAI,QAAS,YAAW,UAAU;AAGlC,QAAM,cAAcC,kBAAiB,UAAU,cAAc,KAAK,YAAY,CAAC;AAC/E,MAAI,YAAa,YAAW,cAAc;AAG1C,QAAM,gBAAgB,UAAU,cAAc,KAAK,WAAW;AAC9D,MAAI,eAAe;AACjB,UAAM,YAAY,aAAa,eAAe,KAAK,MAAM;AACzD,QAAI,cAAc,WAAW,cAAc,WAAW;AACpD,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF;AAGA,QAAM,eAAe,UAAU,cAAc,KAAK,UAAU;AAC5D,MAAI,cAAc;AAChB,UAAM,UAAU,aAAa,cAAc,KAAK,KAAK;AACrD,QAAI,QAAS,YAAW,UAAU;AAAA,EACpC;AAGA,QAAM,OAAOC,gBAAe,UAAU,cAAc,KAAK,SAAS,CAAC;AACnE,MAAI,KAAM,YAAW,OAAO;AAG5B,QAAM,UAAU,aAAa,UAAU,cAAc,KAAK,KAAK,CAAC;AAChE,MAAI,QAAS,YAAW,UAAU;AAGlC,QAAM,iBAAiB,UAAU,cAAc,KAAK,YAAY;AAChE,MAAI,gBAAgB;AAClB,UAAM,aAAa,aAAa,gBAAgB,KAAK,KAAK;AAC1D,QAAI,eAAe,WAAW,eAAe,WAAW;AACtD,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,WAAW,6BAA6B,UAAU,cAAc,KAAK,QAAQ,CAAC;AACpF,MAAI,SAAU,YAAW,WAAW;AAGpC,QAAM,OAAO,oBAAoB,UAAU,cAAc,KAAK,YAAY,CAAC;AAC3E,MAAI,KAAM,YAAW,OAAO;AAE5B,MAAI,OAAO,KAAK,UAAU,EAAE,WAAW,EAAG,QAAO;AAEjD,SAAO;AACT;AAYO,SAASE,yBACd,aACgC;AAChC,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,aAAiC,CAAC;AAGxC,QAAM,gBAAgB,UAAU,aAAa,KAAK,UAAU;AAC5D,MAAI,eAAe;AACjB,UAAM,SAAS,WAAW,aAAa;AACvC,QAAI,OAAQ,YAAW,SAAS;AAEhC,UAAM,QAAQ,aAAa,eAAe,KAAK,OAAO;AACtD,QAAI,UAAU,UAAU,UAAU,aAAa,UAAU,SAAS;AAChE,iBAAW,aAAa;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,SAAS,oBAAoB,UAAU,aAAa,KAAK,WAAW,CAAC;AAC3E,MAAI,OAAQ,YAAW,SAAS;AAGhC,QAAM,YAAY,oBAAoB,UAAU,aAAa,KAAK,WAAW,CAAC;AAC9E,MAAI,UAAW,YAAW,YAAY;AAGtC,QAAM,YAAY,UAAU,aAAa,KAAK,IAAI;AAClD,MAAI,WAAW;AACb,UAAM,QAAQ,aAAa,WAAW,KAAK,KAAK;AAChD,QAAI,UAAU,UAAU,UAAU,YAAY,UAAU,SAAS;AAC/D,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,SAAS,oBAAoB,UAAU,aAAa,KAAK,QAAQ,CAAC;AACxE,MAAI,OAAQ,YAAW,SAAS;AAEhC,MAAI,OAAO,KAAK,UAAU,EAAE,WAAW,EAAG,QAAO;AAEjD,SAAO;AACT;AAYO,SAAS,4BACd,YACoC;AACpC,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAgC,CAAC;AAGvC,QAAM,WAAW,aAAa,YAAY,KAAK,UAAU;AACzD,MAAI,aAAa,OAAO,aAAa,OAAQ,OAAM,WAAW;AAE9D,QAAM,UAAU,aAAa,YAAY,KAAK,SAAS;AACvD,MAAI,YAAY,OAAO,YAAY,OAAQ,OAAM,UAAU;AAE3D,QAAM,cAAc,aAAa,YAAY,KAAK,aAAa;AAC/D,MAAI,gBAAgB,OAAO,gBAAgB,OAAQ,OAAM,cAAc;AAEvE,QAAM,aAAa,aAAa,YAAY,KAAK,YAAY;AAC7D,MAAI,eAAe,OAAO,eAAe,OAAQ,OAAM,aAAa;AAEpE,QAAM,WAAW,aAAa,YAAY,KAAK,UAAU;AACzD,MAAI,aAAa,OAAO,aAAa,OAAQ,OAAM,WAAW;AAE9D,QAAM,YAAY,aAAa,YAAY,KAAK,WAAW;AAC3D,MAAI,cAAc,OAAO,cAAc,OAAQ,OAAM,YAAY;AAEjE,QAAM,WAAW,aAAa,YAAY,KAAK,UAAU;AACzD,MAAI,aAAa,OAAO,aAAa,OAAQ,OAAM,WAAW;AAE9D,QAAM,YAAY,aAAa,YAAY,KAAK,WAAW;AAC3D,MAAI,cAAc,OAAO,cAAc,OAAQ,OAAM,YAAY;AAGjE,QAAM,SAAS,aAAa,YAAY,KAAK,qBAAqB;AAClE,MAAI,WAAW,OAAO,WAAW,OAAQ,OAAM,SAAS;AAExD,QAAM,SAAS,aAAa,YAAY,KAAK,oBAAoB;AACjE,MAAI,WAAW,OAAO,WAAW,OAAQ,OAAM,SAAS;AAExD,QAAM,SAAS,aAAa,YAAY,KAAK,oBAAoB;AACjE,MAAI,WAAW,OAAO,WAAW,OAAQ,OAAM,SAAS;AAExD,QAAM,SAAS,aAAa,YAAY,KAAK,mBAAmB;AAChE,MAAI,WAAW,OAAO,WAAW,OAAQ,OAAM,SAAS;AAGxD,QAAM,MAAM,aAAa,YAAY,KAAK,KAAK;AAC/C,MAAI,OAAO,IAAI,WAAW,IAAI;AAG5B,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,WAAW;AACrC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,UAAU;AACpC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,cAAc;AACxC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,aAAa;AACvC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,WAAW;AACrC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,YAAY;AACtC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,WAAW;AACrC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,YAAY;AACtC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,SAAS;AACnC,QAAI,IAAI,CAAC,MAAM,IAAK,OAAM,SAAS;AACnC,QAAI,IAAI,EAAE,MAAM,IAAK,OAAM,SAAS;AACpC,QAAI,IAAI,EAAE,MAAM,IAAK,OAAM,SAAS;AAAA,EACtC;AAEA,MAAI,OAAO,KAAK,KAAK,EAAE,WAAW,EAAG,QAAO;AAE5C,SAAO;AACT;AAQO,SAASC,0BACd,aACiC;AACjC,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,aAAkC,CAAC;AAGzC,QAAM,QAAQ,WAAW,UAAU,aAAa,KAAK,KAAK,CAAC;AAC3D,MAAI,MAAO,YAAW,QAAQ;AAG9B,QAAM,UAAUL,mBAAkB,UAAU,aAAa,KAAK,WAAW,CAAC;AAC1E,MAAI,QAAS,YAAW,UAAU;AAGlC,QAAM,UAAUC,kBAAiB,UAAU,aAAa,KAAK,OAAO,CAAC;AACrE,MAAI,QAAS,YAAW,UAAU;AAGlC,QAAM,UAAU,aAAa,UAAU,aAAa,KAAK,KAAK,CAAC;AAC/D,MAAI,QAAS,YAAW,UAAU;AAGlC,QAAM,gBAAgB,UAAU,aAAa,KAAK,QAAQ;AAC1D,MAAI,eAAe;AACjB,UAAM,SAAS,aAAa,eAAe,KAAK,KAAK;AACrD,QAAI,WAAW,SAAS,WAAW,YAAY,WAAW,UAAU;AAClE,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,iBAAiB,UAAU,aAAa,KAAK,eAAe;AAClE,MAAI,gBAAgB;AAClB,UAAM,UAAU,aAAa,gBAAgB,KAAK,KAAK;AACvD,QAAI,SAAS;AACX,iBAAW,gBAAgB;AAAA,IAC7B;AAAA,EACF;AAGA,QAAM,kBAAkB,UAAU,aAAa,KAAK,UAAU;AAC9D,MAAI,iBAAiB;AACnB,UAAM,WAAW,sBAAsB,iBAAiB,KAAK,KAAK;AAClE,QAAI,aAAa,UAAa,WAAW,GAAG;AAC1C,iBAAW,WAAW;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,gBAAgB,UAAU,aAAa,KAAK,QAAQ;AAC1D,MAAI,eAAe;AACjB,UAAM,YAAY,aAAa,eAAe,KAAK,KAAK;AACxD,QAAI,cAAc,WAAW;AAC3B,iBAAW,SAAS;AAAA,IACtB,OAAO;AAEL,iBAAW,SAAS;AAAA,IACtB;AAAA,EACF;AAGA,QAAM,UAAU,oBAAoB,UAAU,aAAa,KAAK,WAAW,CAAC;AAC5E,MAAI,QAAS,YAAW,UAAU;AAGlC,QAAM,SAAS,oBAAoB,UAAU,aAAa,KAAK,QAAQ,CAAC;AACxE,MAAI,OAAQ,YAAW,SAAS;AAGhC,QAAM,WAAW,oBAAoB,UAAU,aAAa,KAAK,UAAU,CAAC;AAC5E,MAAI,SAAU,YAAW,WAAW;AAGpC,QAAM,oBAAoB,4BAA4B,UAAU,aAAa,KAAK,UAAU,CAAC;AAC7F,MAAI,kBAAmB,YAAW,oBAAoB;AAEtD,MAAI,OAAO,KAAK,UAAU,EAAE,WAAW,EAAG,QAAO;AAEjD,SAAO;AACT;AAiBA,SAAS,iBACP,WACA,QACA,OACA,WACA,MACA,OACuB;AACvB,QAAM,UAAiC,CAAC;AAGxC,QAAM,WAAW,UAAU,YAAY,CAAC;AAExC,aAAW,SAAS,UAAU;AAC5B,QAAI,CAAC,MAAM,KAAM;AAEjB,UAAM,YAAY,MAAM,KAAK,MAAM,GAAG,EAAE,IAAI;AAE5C,QAAI,cAAc,KAAK;AAErB,YAAM,OAAO,eAAe,OAAO,QAAQ,OAAO,WAAW,MAAM,KAAK;AACxE,cAAQ,KAAK,IAAI;AAAA,IACnB,WAAW,cAAc,OAAO;AAE9B,YAAM,QAAQ,WAAW,OAAO,QAAQ,OAAO,WAAW,MAAM,KAAK;AACrE,cAAQ,KAAK,KAAK;AAAA,IACpB;AAAA,EAEF;AAGA,MAAI,QAAQ,WAAW,GAAG;AACxB,YAAQ,KAAK;AAAA,MACX,MAAM;AAAA,MACN,SAAS,CAAC;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAiBO,SAAS,eACd,WACA,QACA,OACA,WACA,MACA,OACW;AACX,QAAM,OAAkB;AAAA,IACtB,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,EACZ;AAGA,QAAM,aAAaI,0BAAyB,UAAU,WAAW,KAAK,MAAM,CAAC;AAC7E,MAAI,YAAY;AACd,SAAK,aAAa;AAAA,EACpB;AAGA,OAAK,UAAU,iBAAiB,WAAW,QAAQ,OAAO,WAAW,MAAM,KAAK;AAEhF,SAAO;AACT;AAiBO,SAAS,cACd,WACA,QACA,OACA,WACA,MACA,OACU;AACV,QAAM,MAAgB;AAAA,IACpB,MAAM;AAAA,IACN,OAAO,CAAC;AAAA,EACV;AAGA,QAAM,aAAaD,yBAAwB,UAAU,WAAW,KAAK,MAAM,CAAC;AAC5E,MAAI,YAAY;AACd,QAAI,aAAa;AAAA,EACnB;AAGA,QAAM,QAAQ,aAAa,WAAW,KAAK,IAAI;AAC/C,aAAW,eAAe,OAAO;AAC/B,UAAM,OAAO,eAAe,aAAa,QAAQ,OAAO,WAAW,MAAM,KAAK;AAC9E,QAAI,MAAM,KAAK,IAAI;AAAA,EACrB;AAEA,SAAO;AACT;AAYO,SAAS,eAAe,gBAAyD;AACtF,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,SAAmB,CAAC;AAE1B,QAAM,WAAW,aAAa,gBAAgB,KAAK,SAAS;AAC5D,aAAW,OAAO,UAAU;AAC1B,UAAM,QAAQ,sBAAsB,KAAK,KAAK,GAAG,KAAK;AACtD,WAAO,KAAK,KAAK;AAAA,EACnB;AAEA,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;AAiBO,SAAS,WACd,YACA,QACA,OACA,WACA,MACA,OACO;AACP,QAAM,QAAe;AAAA,IACnB,MAAM;AAAA,IACN,MAAM,CAAC;AAAA,EACT;AAGA,QAAM,aAAaD,sBAAqB,UAAU,YAAY,KAAK,OAAO,CAAC;AAC3E,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAGA,QAAM,eAAe,eAAe,UAAU,YAAY,KAAK,SAAS,CAAC;AACzE,MAAI,cAAc;AAChB,UAAM,eAAe;AAAA,EACvB;AAGA,QAAM,OAAO,aAAa,YAAY,KAAK,IAAI;AAC/C,aAAW,cAAc,MAAM;AAC7B,UAAM,MAAM,cAAc,YAAY,QAAQ,OAAO,WAAW,MAAM,KAAK;AAC3E,UAAM,KAAK,KAAK,GAAG;AAAA,EACrB;AAEA,SAAO;AACT;;;AC10BA,SAAS,sBAAsB,UAA2C;AACxE,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AAAA,IACL;AACE,aAAO;AAAA,EACX;AACF;AAQO,SAAS,qBAAqB,SAAsC;AACzE,QAAM,WAAW,aAAa,SAAS,KAAK,MAAM;AAClD,QAAM,MAAM,aAAa,SAAS,KAAK,IAAI,KAAK;AAEhD,SAAO;AAAA,IACL,MAAM,sBAAsB,QAAQ;AAAA,IACpC;AAAA,EACF;AACF;AAQO,SAAS,qBAAqB,SAAsC;AACzE,QAAM,WAAW,aAAa,SAAS,KAAK,MAAM;AAClD,QAAM,MAAM,aAAa,SAAS,KAAK,IAAI,KAAK;AAEhD,SAAO;AAAA,IACL,MAAM,sBAAsB,QAAQ;AAAA,IACpC;AAAA,EACF;AACF;AAmDA,SAAS,yBACP,MACA,QACA,OACA,WACA,MACA,OACuB;AACvB,QAAM,UAAiC,CAAC;AAGxC,QAAM,WAAW,KAAK,YAAY,CAAC;AAEnC,aAAW,MAAM,UAAU;AACzB,QAAI,GAAG,SAAS,UAAW;AAE3B,UAAM,OAAO,GAAG,QAAQ;AAGxB,QAAI,SAAS,SAAS,KAAK,SAAS,IAAI,GAAG;AACzC,YAAM,YAAY,eAAe,IAAI,QAAQ,OAAO,WAAW,MAAM,KAAK;AAC1E,cAAQ,KAAK,SAAS;AAAA,IACxB,WAES,SAAS,WAAW,KAAK,SAAS,MAAM,GAAG;AAClD,YAAM,QAAQ,WAAW,IAAI,QAAQ,OAAO,WAAW,MAAM,KAAK;AAClE,cAAQ,KAAK,KAAK;AAAA,IACpB,WAES,SAAS,WAAW,KAAK,SAAS,MAAM,GAAG;AAElD,YAAM,gBAAgB,GAAG,YAAY,CAAC,GAAG;AAAA,QACvC,CAAC,UACC,MAAM,SAAS,cACd,MAAM,SAAS,kBAAkB,MAAM,MAAM,SAAS,aAAa;AAAA,MACxE;AACA,UAAI,cAAc;AAEhB,cAAM,aAAa;AAAA,UACjB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,gBAAQ,KAAK,GAAG,UAAU;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAcO,SAAS,YACd,WACA,aAA+B,WAC/B,SAA0B,MAC1B,QAAsB,MACtB,YAAiC,MACjC,OAA+B,MAC/B,QAAuC,MACzB;AACd,QAAM,SAAuB;AAAA,IAC3B,MAAM;AAAA,IACN;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AAEA,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,SAAS,SAAS;AAC9B,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,IAAI,UAAU;AAAA,IAChC,CAAC,OAAmB,GAAG,SAAS,cAAc,GAAG,SAAS,WAAW,GAAG,MAAM,SAAS,MAAM;AAAA,EAC/F;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,SAAO,UAAU,yBAAyB,aAAa,QAAQ,OAAO,WAAW,MAAM,KAAK;AAE5F,SAAO;AACT;AAcO,SAAS,YACd,WACA,aAA+B,WAC/B,SAA0B,MAC1B,QAAsB,MACtB,YAAiC,MACjC,OAA+B,MAC/B,QAAuC,MACzB;AACd,QAAM,SAAuB;AAAA,IAC3B,MAAM;AAAA,IACN;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AAEA,MAAI,CAAC,WAAW;AACd,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,SAAS,SAAS;AAC9B,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,IAAI,UAAU;AAAA,IAChC,CAAC,OAAmB,GAAG,SAAS,cAAc,GAAG,SAAS,WAAW,GAAG,MAAM,SAAS,MAAM;AAAA,EAC/F;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AAGA,SAAO,UAAU,yBAAyB,aAAa,QAAQ,OAAO,WAAW,MAAM,KAAK;AAE5F,SAAO;AACT;;;ACpNA,SAAS,cACP,UACyE;AACzE,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AASA,SAAS,cACP,SACA,QACA,OACA,WACA,MACA,QACU;AACV,QAAM,KAAK,sBAAsB,SAAS,KAAK,IAAI,KAAK;AACxD,QAAM,WAAW,aAAa,SAAS,KAAK,MAAM;AAClD,QAAM,WAAW,cAAc,QAAQ;AAGvC,QAAM,oBAAoB,aAAa,SAAS,KAAK,GAAG;AACxD,QAAM,UAAuB,kBAAkB;AAAA,IAAI,CAAC,QAClD,eAAe,KAAK,QAAQ,OAAO,WAAW,IAAI;AAAA,EACpD;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAaO,SAAS,eACd,cACA,SAA0B,MAC1B,QAAsB,MACtB,YAAiC,MACjC,OAA+B,MAC/B,QAAuC,MAC1B;AACb,QAAM,OAAO,oBAAI,IAAsB;AACvC,QAAM,YAAwB,CAAC;AAE/B,MAAI,CAAC,cAAc;AACjB,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAEA,QAAM,MAAM,SAAS,YAAY;AACjC,MAAI,CAAC,KAAK;AACR,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAGA,QAAM,cAAc,IAAI,UAAU;AAAA,IAChC,CAAC,OACC,GAAG,SAAS,cAAc,GAAG,SAAS,iBAAiB,GAAG,MAAM,SAAS,YAAY;AAAA,EACzF;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO,kBAAkB,MAAM,SAAS;AAAA,EAC1C;AAGA,QAAM,mBAAmB,aAAa,aAAa,KAAK,UAAU;AAElE,aAAW,QAAQ,kBAAkB;AACnC,UAAM,WAAW,cAAc,MAAM,QAAQ,OAAO,WAAW,MAAM,KAAK;AAC1E,SAAK,IAAI,SAAS,IAAI,QAAQ;AAC9B,cAAU,KAAK,QAAQ;AAAA,EACzB;AAEA,SAAO,kBAAkB,MAAM,SAAS;AAC1C;AAKA,SAAS,kBAAkB,MAA6B,WAAoC;AAC1F,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IAEA,YAAY,IAAkC;AAC5C,aAAO,KAAK,IAAI,EAAE;AAAA,IACpB;AAAA,IAEA,YAAY,IAAqB;AAC/B,aAAO,KAAK,IAAI,EAAE;AAAA,IACpB;AAAA,IAEA,qBAAiC;AAC/B,aAAO,UAAU,OAAO,CAAC,OAAO,GAAG,aAAa,QAAQ;AAAA,IAC1D;AAAA,IAEA,eAAqC;AACnC,aAAO,UAAU,KAAK,CAAC,OAAO,GAAG,aAAa,WAAW;AAAA,IAC3D;AAAA,IAEA,2BAAiD;AAC/C,aAAO,UAAU,KAAK,CAAC,OAAO,GAAG,aAAa,uBAAuB;AAAA,IACvE;AAAA,EACF;AACF;AASA,SAAS,aACP,SACA,QACA,OACA,WACA,MACA,QACS;AACT,QAAM,KAAK,sBAAsB,SAAS,KAAK,IAAI,KAAK;AACxD,QAAM,WAAW,aAAa,SAAS,KAAK,MAAM;AAClD,QAAM,WAAW,cAAc,QAAQ;AAGvC,QAAM,oBAAoB,aAAa,SAAS,KAAK,GAAG;AACxD,QAAM,UAAuB,kBAAkB;AAAA,IAAI,CAAC,QAClD,eAAe,KAAK,QAAQ,OAAO,WAAW,IAAI;AAAA,EACpD;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAaO,SAAS,cACd,aACA,SAA0B,MAC1B,QAAsB,MACtB,YAAiC,MACjC,OAA+B,MAC/B,QAAuC,MAC3B;AACZ,QAAM,OAAO,oBAAI,IAAqB;AACtC,QAAM,WAAsB,CAAC;AAE7B,MAAI,CAAC,aAAa;AAChB,WAAO,iBAAiB,MAAM,QAAQ;AAAA,EACxC;AAEA,QAAM,MAAM,SAAS,WAAW;AAChC,MAAI,CAAC,KAAK;AACR,WAAO,iBAAiB,MAAM,QAAQ;AAAA,EACxC;AAGA,QAAM,cAAc,IAAI,UAAU;AAAA,IAChC,CAAC,OACC,GAAG,SAAS,cAAc,GAAG,SAAS,gBAAgB,GAAG,MAAM,SAAS,WAAW;AAAA,EACvF;AAEA,MAAI,CAAC,aAAa;AAChB,WAAO,iBAAiB,MAAM,QAAQ;AAAA,EACxC;AAGA,QAAM,kBAAkB,aAAa,aAAa,KAAK,SAAS;AAEhE,aAAW,QAAQ,iBAAiB;AAClC,UAAM,UAAU,aAAa,MAAM,QAAQ,OAAO,WAAW,MAAM,KAAK;AACxE,SAAK,IAAI,QAAQ,IAAI,OAAO;AAC5B,aAAS,KAAK,OAAO;AAAA,EACvB;AAEA,SAAO,iBAAiB,MAAM,QAAQ;AACxC;AAKA,SAAS,iBAAiB,MAA4B,UAAiC;AACrF,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IAEA,WAAW,IAAiC;AAC1C,aAAO,KAAK,IAAI,EAAE;AAAA,IACpB;AAAA,IAEA,WAAW,IAAqB;AAC9B,aAAO,KAAK,IAAI,EAAE;AAAA,IACpB;AAAA,IAEA,oBAA+B;AAC7B,aAAO,SAAS,OAAO,CAAC,OAAO,GAAG,aAAa,QAAQ;AAAA,IACzD;AAAA,IAEA,eAAoC;AAClC,aAAO,SAAS,KAAK,CAAC,OAAO,GAAG,aAAa,WAAW;AAAA,IAC1D;AAAA,IAEA,2BAAgD;AAC9C,aAAO,SAAS,KAAK,CAAC,OAAO,GAAG,aAAa,uBAAuB;AAAA,IACtE;AAAA,EACF;AACF;AASA,SAASG,mBAAkB,YAAqD;AAC9E,MAAI,CAAC,WAAY,QAAO;AAGxB,QAAM,YAA0C;AAAA,IAC9C,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,aAAa;AAAA,IACb,SAAS;AAAA,IACT,cAAc;AAAA,IACd,aAAa;AAAA,IACb,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,MAAM;AAAA,EACR;AAEA,SAAO,UAAU,UAAU;AAC7B;AAKA,SAAS,sBAAsB,SAAsD;AACnF,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,qBAAqB,SAAqD;AACjF,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,mBAAmB,aAA2D;AACrF,UAAQ,aAAa;AAAA,IACnB,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAMO,SAAS,wBAAwB,SAAgD;AACtF,QAAM,QAA4B,CAAC;AAEnC,MAAI,CAAC,QAAS,QAAO;AAGrB,QAAM,QAAQ,UAAU,SAAS,KAAK,KAAK;AAC3C,MAAI,OAAO;AACT,UAAM,UAAU,aAAa,OAAO,KAAK,KAAK;AAC9C,UAAM,WAAW,sBAAsB,OAAO;AAAA,EAChD;AAGA,QAAM,WAAW,UAAU,SAAS,KAAK,QAAQ;AACjD,MAAI,UAAU;AACZ,UAAM,UAAU,aAAa,UAAU,KAAK,KAAK;AACjD,UAAM,SAASA,mBAAkB,OAAO;AAAA,EAC1C;AAGA,QAAM,aAAa,UAAU,SAAS,KAAK,UAAU;AACrD,MAAI,YAAY;AACd,UAAM,WAAW,sBAAsB,YAAY,KAAK,KAAK,KAAK;AAAA,EACpE;AAGA,QAAM,eAAe,UAAU,SAAS,KAAK,YAAY;AACzD,MAAI,cAAc;AAChB,UAAM,cAAc,aAAa,cAAc,KAAK,KAAK;AACzD,UAAM,aAAa,mBAAmB,WAAW;AAAA,EACnD;AAEA,SAAO;AACT;AAMO,SAAS,uBAAuB,SAA+C;AACpF,QAAM,QAA2B,CAAC;AAElC,MAAI,CAAC,QAAS,QAAO;AAGrB,QAAM,QAAQ,UAAU,SAAS,KAAK,KAAK;AAC3C,MAAI,OAAO;AACT,UAAM,UAAU,aAAa,OAAO,KAAK,KAAK;AAC9C,UAAM,WAAW,qBAAqB,OAAO;AAAA,EAC/C;AAGA,QAAM,WAAW,UAAU,SAAS,KAAK,QAAQ;AACjD,MAAI,UAAU;AACZ,UAAM,UAAU,aAAa,UAAU,KAAK,KAAK;AACjD,UAAM,SAASA,mBAAkB,OAAO;AAAA,EAC1C;AAGA,QAAM,aAAa,UAAU,SAAS,KAAK,UAAU;AACrD,MAAI,YAAY;AACd,UAAM,WAAW,sBAAsB,YAAY,KAAK,KAAK,KAAK;AAAA,EACpE;AAGA,QAAM,eAAe,UAAU,SAAS,KAAK,YAAY;AACzD,MAAI,cAAc;AAChB,UAAM,cAAc,aAAa,cAAc,KAAK,KAAK;AACzD,UAAM,aAAa,mBAAmB,WAAW;AAAA,EACnD;AAEA,SAAO;AACT;;;ACxcA,SAASC,iBACP,UACA,YACA,WACA,YACwB;AACxB,MAAI,CAAC,YAAY,CAAC,WAAY,QAAO;AAErC,QAAM,QAAoB,CAAC;AAE3B,MAAI,YAAY,aAAa,QAAQ;AACnC,UAAM,MAAM;AAAA,EACd,WAAW,aAAa,QAAQ;AAC9B,UAAM,OAAO;AAAA,EACf;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AACA,MAAI,WAAW;AACb,UAAM,YAAY;AAAA,EACpB;AACA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAKA,SAASC,iBAAgB,SAAoD;AAC3E,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,WAAW,aAAa,SAAS,KAAK,KAAK,KAAK;AACtD,QAAM,QAAQ;AAEd,QAAM,SAAqB,EAAE,MAAM;AAGnC,QAAM,KAAK,sBAAsB,SAAS,KAAK,IAAI;AACnD,MAAI,OAAO,QAAW;AACpB,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,QAAQ,sBAAsB,SAAS,KAAK,OAAO;AACzD,MAAI,UAAU,QAAW;AACvB,WAAO,QAAQ;AAAA,EACjB;AAGA,QAAM,WAAW,aAAa,SAAS,KAAK,OAAO;AACnD,QAAM,aAAa,aAAa,SAAS,KAAK,YAAY;AAC1D,QAAM,YAAY,aAAa,SAAS,KAAK,WAAW;AACxD,QAAM,aAAa,aAAa,SAAS,KAAK,YAAY;AAC1D,QAAM,QAAQD,iBAAgB,UAAU,YAAY,WAAW,UAAU;AACzE,MAAI,OAAO;AACT,WAAO,QAAQ;AAAA,EACjB;AAGA,QAAM,SAAS,aAAa,SAAS,KAAK,QAAQ;AAClD,MAAI,WAAW,OAAO,WAAW,QAAQ;AACvC,WAAO,SAAS;AAAA,EAClB;AAGA,QAAM,QAAQ,aAAa,SAAS,KAAK,OAAO;AAChD,MAAI,UAAU,OAAO,UAAU,QAAQ;AACrC,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;AAKA,SAAS,iBAAiB,QAAoD;AAC5E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,kBAAkB,MAA+C;AACxE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,mBAAmB,OAAiD;AAC3E,UAAQ,OAAO;AAAA,IACb,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKA,SAAS,uBAAuB,SAAuD;AACrF,UAAQ,SAAS;AAAA,IACf,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAaO,SAAS,uBACd,QACA,OACmB;AACnB,QAAM,QAA2B,CAAC;AAElC,MAAI,CAAC,OAAQ,QAAO;AAKpB,QAAM,OAAO,UAAU,QAAQ,KAAK,MAAM;AAC1C,MAAI,MAAM;AAER,UAAM,IAAI,sBAAsB,MAAM,KAAK,GAAG;AAC9C,QAAI,MAAM,QAAW;AACnB,YAAM,YAAY;AAAA,IACpB;AAGA,UAAM,IAAI,sBAAsB,MAAM,KAAK,GAAG;AAC9C,QAAI,MAAM,QAAW;AACnB,YAAM,aAAa;AAAA,IACrB;AAGA,UAAM,SAAS,aAAa,MAAM,KAAK,QAAQ;AAC/C,UAAM,cAAc,iBAAiB,MAAM;AAC3C,QAAI,aAAa;AACf,YAAM,cAAc;AAAA,IACtB;AAAA,EACF;AAKA,QAAM,QAAQ,UAAU,QAAQ,KAAK,OAAO;AAC5C,MAAI,OAAO;AAET,UAAM,MAAM,sBAAsB,OAAO,KAAK,KAAK;AACnD,QAAI,QAAQ,QAAW;AACrB,YAAM,YAAY;AAAA,IACpB;AAGA,UAAM,SAAS,sBAAsB,OAAO,KAAK,QAAQ;AACzD,QAAI,WAAW,QAAW;AACxB,YAAM,eAAe;AAAA,IACvB;AAGA,UAAM,OAAO,sBAAsB,OAAO,KAAK,MAAM;AACrD,QAAI,SAAS,QAAW;AACtB,YAAM,aAAa;AAAA,IACrB;AAGA,UAAM,QAAQ,sBAAsB,OAAO,KAAK,OAAO;AACvD,QAAI,UAAU,QAAW;AACvB,YAAM,cAAc;AAAA,IACtB;AAGA,UAAM,SAAS,sBAAsB,OAAO,KAAK,QAAQ;AACzD,QAAI,WAAW,QAAW;AACxB,YAAM,iBAAiB;AAAA,IACzB;AAGA,UAAM,SAAS,sBAAsB,OAAO,KAAK,QAAQ;AACzD,QAAI,WAAW,QAAW;AACxB,YAAM,iBAAiB;AAAA,IACzB;AAGA,UAAM,SAAS,sBAAsB,OAAO,KAAK,QAAQ;AACzD,QAAI,WAAW,QAAW;AACxB,YAAM,SAAS;AAAA,IACjB;AAAA,EACF;AAKA,QAAM,OAAO,UAAU,QAAQ,KAAK,MAAM;AAC1C,MAAI,MAAM;AAER,UAAM,MAAM,sBAAsB,MAAM,KAAK,KAAK;AAClD,QAAI,QAAQ,QAAW;AACrB,YAAM,cAAc;AAAA,IACtB;AAGA,UAAM,QAAQ,sBAAsB,MAAM,KAAK,OAAO;AACtD,QAAI,UAAU,QAAW;AACvB,YAAM,cAAc;AAAA,IACtB;AAGA,UAAM,aAAa,aAAa,MAAM,KAAK,YAAY;AACvD,QAAI,eAAe,OAAO,eAAe,QAAQ;AAC/C,YAAM,aAAa;AAAA,IACrB,WAAW,eAAe,OAAO,eAAe,SAAS;AACvD,YAAM,aAAa;AAAA,IACrB;AAGA,UAAM,MAAM,aAAa,MAAM,KAAK,KAAK;AACzC,QAAI,QAAQ,OAAO,QAAQ,QAAQ;AACjC,YAAM,YAAY;AAAA,IACpB;AAGA,UAAM,cAAc,aAAa,MAAM,KAAK,KAAK;AACjD,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,UAAU,CAAC;AACjB,iBAAW,SAAS,aAAa;AAC/B,cAAM,SAAiB,CAAC;AAExB,cAAM,WAAW,sBAAsB,OAAO,KAAK,GAAG;AACtD,YAAI,aAAa,QAAW;AAC1B,iBAAO,QAAQ;AAAA,QACjB;AAEA,cAAM,WAAW,sBAAsB,OAAO,KAAK,OAAO;AAC1D,YAAI,aAAa,QAAW;AAC1B,iBAAO,QAAQ;AAAA,QACjB;AAEA,cAAM,QAAQ,KAAK,MAAM;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAKA,QAAM,SAAS,UAAU,QAAQ,KAAK,MAAM;AAC5C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,UAAM,eAAe,kBAAkB,GAAG;AAC1C,QAAI,cAAc;AAChB,YAAM,eAAe;AAAA,IACvB;AAAA,EACF;AAKA,QAAM,SAAS,UAAU,QAAQ,KAAK,QAAQ;AAC9C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,UAAM,gBAAgB,mBAAmB,GAAG;AAC5C,QAAI,eAAe;AACjB,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAKA,QAAM,OAAO,UAAU,QAAQ,KAAK,MAAM;AAC1C,MAAI,MAAM;AACR,UAAM,OAAO,oBAAoB,IAAI;AAAA,EACvC;AAKA,QAAM,aAAa,aAAa,QAAQ,KAAK,iBAAiB;AAC9D,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,mBAAmB,WAAW,IAAI,CAAC,OAAO,qBAAqB,EAAE,CAAC;AAAA,EAC1E;AAKA,QAAM,aAAa,aAAa,QAAQ,KAAK,iBAAiB;AAC9D,MAAI,WAAW,SAAS,GAAG;AACzB,UAAM,mBAAmB,WAAW,IAAI,CAAC,OAAO,qBAAqB,EAAE,CAAC;AAAA,EAC1E;AAKA,QAAM,UAAU,UAAU,QAAQ,KAAK,SAAS;AAChD,MAAI,SAAS;AACX,UAAM,UAAU,oBAAoB,OAAO;AAAA,EAC7C;AAMA,QAAM,oBAAoB,UAAU,QAAQ,KAAK,mBAAmB;AACpE,MAAI,mBAAmB;AACrB,UAAM,oBAAoB,oBAAoB,iBAAiB;AAAA,EACjE;AAKA,QAAM,YAAY,UAAU,QAAQ,KAAK,WAAW;AACpD,MAAI,WAAW;AACb,UAAM,cAAc,CAAC;AAErB,UAAM,QAAQ,sBAAsB,WAAW,KAAK,OAAO;AAC3D,QAAI,UAAU,QAAW;AACvB,YAAM,YAAY,QAAQ;AAAA,IAC5B;AAEA,UAAM,UAAU,sBAAsB,WAAW,KAAK,SAAS;AAC/D,QAAI,YAAY,QAAW;AACzB,YAAM,YAAY,UAAU;AAAA,IAC9B;AAEA,UAAM,WAAW,sBAAsB,WAAW,KAAK,UAAU;AACjE,QAAI,aAAa,QAAW;AAC1B,YAAM,YAAY,WAAW;AAAA,IAC/B;AAEA,UAAM,UAAU,aAAa,WAAW,KAAK,SAAS;AACtD,UAAM,eAAe,uBAAuB,OAAO;AACnD,QAAI,cAAc;AAChB,YAAM,YAAY,UAAU;AAAA,IAC9B;AAAA,EACF;AAKA,QAAM,YAAY,UAAU,QAAQ,KAAK,WAAW;AACpD,MAAI,WAAW;AACb,UAAM,cAAc,CAAC;AAGrB,UAAM,YAAYC,iBAAgB,UAAU,WAAW,KAAK,KAAK,CAAC;AAClE,QAAI,WAAW;AACb,YAAM,YAAY,MAAM;AAAA,IAC1B;AAGA,UAAM,eAAeA,iBAAgB,UAAU,WAAW,KAAK,QAAQ,CAAC;AACxE,QAAI,cAAc;AAChB,YAAM,YAAY,SAAS;AAAA,IAC7B;AAGA,UAAM,aAAaA,iBAAgB,UAAU,WAAW,KAAK,MAAM,CAAC;AACpE,QAAI,YAAY;AACd,YAAM,YAAY,OAAO;AAAA,IAC3B;AAGA,UAAM,cAAcA,iBAAgB,UAAU,WAAW,KAAK,OAAO,CAAC;AACtE,QAAI,aAAa;AACf,YAAM,YAAY,QAAQ;AAAA,IAC5B;AAGA,UAAM,UAAU,aAAa,WAAW,KAAK,SAAS;AACtD,QAAI,YAAY,cAAc,YAAY,eAAe,YAAY,gBAAgB;AACnF,YAAM,YAAY,UAAU;AAAA,IAC9B;AAGA,UAAM,aAAa,aAAa,WAAW,KAAK,YAAY;AAC5D,QAAI,eAAe,UAAU,eAAe,QAAQ;AAClD,YAAM,YAAY,aAAa;AAAA,IACjC;AAGA,UAAM,SAAS,aAAa,WAAW,KAAK,QAAQ;AACpD,QAAI,WAAW,WAAW,WAAW,QAAQ;AAC3C,YAAM,YAAY,SAAS;AAAA,IAC7B;AAAA,EACF;AAMA,QAAM,aAAa,UAAU,QAAQ,KAAK,YAAY;AACtD,MAAI,YAAY;AACd,UAAM,aAAa,CAAC;AAEpB,UAAM,WAAW,aAAa,YAAY,KAAK,OAAO;AACtD,QAAI,YAAY,aAAa,QAAQ;AACnC,YAAM,WAAW,QAAQ,EAAE,KAAK,SAAS;AAAA,IAC3C;AAEA,UAAM,aAAa,aAAa,YAAY,KAAK,YAAY;AAC7D,QAAI,YAAY;AACd,YAAM,WAAW,aAAa;AAAA,IAChC;AAEA,UAAM,YAAY,aAAa,YAAY,KAAK,WAAW;AAC3D,QAAI,WAAW;AACb,YAAM,WAAW,YAAY;AAAA,IAC/B;AAEA,UAAM,aAAa,aAAa,YAAY,KAAK,YAAY;AAC7D,QAAI,YAAY;AACd,YAAM,WAAW,aAAa;AAAA,IAChC;AAAA,EACF;AAKA,QAAM,aAAa,UAAU,QAAQ,KAAK,YAAY;AACtD,MAAI,YAAY;AACd,UAAM,UAAU,wBAAwB,UAAU;AAClD,QAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,YAAM,aAAa;AAAA,IACrB;AAAA,EACF;AAKA,QAAM,YAAY,UAAU,QAAQ,KAAK,WAAW;AACpD,MAAI,WAAW;AACb,UAAM,UAAU,uBAAuB,SAAS;AAChD,QAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,YAAM,YAAY;AAAA,IACpB;AAAA,EACF;AAKA,QAAM,UAAU,UAAU,QAAQ,KAAK,SAAS;AAChD,MAAI,SAAS;AACX,UAAM,UAAU,CAAC;AAEjB,UAAM,WAAW,aAAa,SAAS,KAAK,MAAM;AAClD,QACE,aAAa,aACb,aAAa,WACb,aAAa,mBACb,aAAa,eACb;AACA,YAAM,QAAQ,OAAO;AAAA,IACvB;AAEA,UAAM,YAAY,sBAAsB,SAAS,KAAK,WAAW;AACjE,QAAI,cAAc,QAAW;AAC3B,YAAM,QAAQ,YAAY;AAAA,IAC5B;AAEA,UAAM,YAAY,sBAAsB,SAAS,KAAK,WAAW;AACjE,QAAI,cAAc,QAAW;AAC3B,YAAM,QAAQ,YAAY;AAAA,IAC5B;AAAA,EACF;AAKA,QAAM,WAAW,UAAU,QAAQ,KAAK,UAAU;AAClD,MAAI,UAAU;AACZ,UAAM,QAAQ,sBAAsB,UAAU,KAAK,OAAO;AAC1D,QAAI,UAAU,QAAW;AACvB,YAAM,gBAAgB;AAAA,IACxB;AAEA,UAAM,QAAQ,sBAAsB,UAAU,KAAK,OAAO;AAC1D,QAAI,UAAU,QAAW;AACvB,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AA+IO,SAAS,8BAAiD;AAC/D,SAAO;AAAA,IACL,WAAW;AAAA;AAAA,IACX,YAAY;AAAA;AAAA,IACZ,aAAa;AAAA,IACb,WAAW;AAAA;AAAA,IACX,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,gBAAgB;AAAA;AAAA,IAChB,gBAAgB;AAAA,IAChB,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,aAAa;AAAA;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,eAAe;AAAA,EACjB;AACF;;;ACzsBO,SAAS,iBACd,GACA,GACS;AAET,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AAGrB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AAGrB,MAAI,EAAE,SAAS,EAAE,KAAM,QAAO;AAC9B,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,aAAa,EAAE,SAAU,QAAO;AACtC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,iBAAiB,EAAE,aAAc,QAAO;AAC9C,MAAI,EAAE,cAAc,EAAE,UAAW,QAAO;AACxC,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AACpC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AACpC,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AACpC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,QAAQ,EAAE,IAAK,QAAO;AAC5B,MAAI,EAAE,OAAO,EAAE,GAAI,QAAO;AAG1B,MAAI,EAAE,aAAa,EAAE,SAAU,QAAO;AACtC,MAAI,EAAE,eAAe,EAAE,WAAY,QAAO;AAC1C,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AACpC,MAAI,EAAE,aAAa,EAAE,SAAU,QAAO;AACtC,MAAI,EAAE,UAAU,EAAE,MAAO,QAAO;AAChC,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AAGpC,MAAI,EAAE,cAAc,EAAE,UAAW,QAAO;AACxC,MAAI,EAAE,cAAc,EAAE,UAAW,QAAO;AACxC,MAAI,EAAE,WAAW,EAAE,OAAQ,QAAO;AAClC,MAAI,EAAE,iBAAiB,EAAE,aAAc,QAAO;AAC9C,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AAGpC,MAAI,CAAC,gBAAgB,EAAE,WAAW,EAAE,SAAS,EAAG,QAAO;AAGvD,MAAI,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAG,QAAO;AAG3C,MAAI,CAAC,cAAc,EAAE,SAAS,EAAE,OAAO,EAAG,QAAO;AAGjD,MAAI,CAAC,iBAAiB,EAAE,YAAY,EAAE,UAAU,EAAG,QAAO;AAE1D,SAAO;AACT;AAKA,SAAS,gBAAgB,GAAgC,GAAyC;AAChG,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AAErB,MAAI,EAAE,UAAU,EAAE,MAAO,QAAO;AAChC,SAAO,YAAY,EAAE,OAAO,EAAE,KAAK;AACrC;AAKA,SAAS,YAAY,GAA4B,GAAqC;AACpF,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AAErB,SACE,EAAE,QAAQ,EAAE,OACZ,EAAE,SAAS,EAAE,QACb,EAAE,eAAe,EAAE,cACnB,EAAE,cAAc,EAAE,aAClB,EAAE,eAAe,EAAE;AAEvB;AAKA,SAAS,cAAc,GAA8B,GAAuC;AAC1F,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AAErB,MAAI,EAAE,YAAY,EAAE,QAAS,QAAO;AACpC,MAAI,CAAC,YAAY,EAAE,OAAO,EAAE,KAAK,EAAG,QAAO;AAC3C,MAAI,CAAC,YAAY,EAAE,MAAM,EAAE,IAAI,EAAG,QAAO;AAEzC,SAAO;AACT;AAKA,SAAS,iBACP,GACA,GACS;AACT,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AAErB,SACE,EAAE,UAAU,EAAE,SACd,EAAE,UAAU,EAAE,SACd,EAAE,aAAa,EAAE,YACjB,EAAE,OAAO,EAAE,MACX,EAAE,eAAe,EAAE,cACnB,EAAE,eAAe,EAAE,cACnB,EAAE,kBAAkB,EAAE,iBACtB,EAAE,YAAY,EAAE;AAEpB;AAeA,SAAS,mBAAmB,SAA8B;AACxD,SACE,QAAQ,SAAS,UAAU,QAAQ,SAAS,gBAAgB,QAAQ,SAAS;AAEjF;AAMO,SAAS,YAAY,KAAmB;AAE7C,MAAI,IAAI,QAAQ,WAAW,EAAG,QAAO;AAGrC,SAAO,IAAI,QAAQ,MAAM,kBAAkB;AAC7C;AAKA,SAAS,gBAAgB,UAAwB,UAAsC;AAErF,QAAM,SAAuB,CAAC;AAG9B,aAAW,KAAK,UAAU;AACxB,WAAO,KAAK,CAAC;AAAA,EACf;AAGA,MACE,OAAO,SAAS,KAChB,SAAS,SAAS,KAClB,OAAO,OAAO,SAAS,CAAC,EAAE,SAAS,UACnC,SAAS,CAAC,EAAE,SAAS,QACrB;AAEA,UAAM,WAAW,OAAO,OAAO,SAAS,CAAC;AACzC,UAAM,YAAY,SAAS,CAAC;AAE5B,WAAO,OAAO,SAAS,CAAC,IAAI;AAAA,MAC1B,MAAM;AAAA,MACN,MAAM,SAAS,OAAO,UAAU;AAAA,MAChC,eAAe,SAAS,iBAAiB,UAAU,iBAAiB;AAAA,IACtE;AAGA,aAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,aAAO,KAAK,SAAS,CAAC,CAAC;AAAA,IACzB;AAAA,EACF,OAAO;AAEL,eAAW,KAAK,UAAU;AACxB,aAAO,KAAK,CAAC;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,gBAAgB,MAAoB;AAClD,MAAI,KAAK,UAAU,EAAG,QAAO;AAE7B,QAAM,SAAgB,CAAC;AACvB,MAAI,UAAsB;AAE1B,aAAW,OAAO,MAAM;AAEtB,QAAI,IAAI,QAAQ,WAAW,EAAG;AAG9B,QAAI,YAAY,MAAM;AACpB,gBAAU,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,IAAI,OAAO,EAAE;AAC9C;AAAA,IACF;AAGA,QACE,YAAY,OAAO,KACnB,YAAY,GAAG,KACf,iBAAiB,QAAQ,YAAY,IAAI,UAAU,GACnD;AAEA,gBAAU;AAAA,QACR,MAAM;AAAA,QACN,YAAY,QAAQ;AAAA,QACpB,SAAS,gBAAgB,QAAQ,SAAS,IAAI,OAAO;AAAA,MACvD;AAAA,IACF,OAAO;AAEL,aAAO,KAAK,OAAO;AACnB,gBAAU,EAAE,GAAG,KAAK,SAAS,CAAC,GAAG,IAAI,OAAO,EAAE;AAAA,IAChD;AAAA,EACF;AAGA,MAAI,YAAY,MAAM;AACpB,WAAO,KAAK,OAAO;AAAA,EACrB;AAEA,SAAO;AACT;AAQO,SAAS,4BAA4B,SAAiD;AAC3F,MAAI,QAAQ,UAAU,EAAG,QAAO;AAEhC,QAAM,SAA6B,CAAC;AACpC,QAAM,cAAqB,CAAC;AAE5B,WAAS,YAAkB;AACzB,QAAI,YAAY,SAAS,GAAG;AAC1B,YAAM,eAAe,gBAAgB,WAAW;AAChD,aAAO,KAAK,GAAG,YAAY;AAC3B,kBAAY,SAAS;AAAA,IACvB;AAAA,EACF;AAEA,aAAW,QAAQ,SAAS;AAC1B,QAAI,KAAK,SAAS,OAAO;AACvB,kBAAY,KAAK,IAAI;AAAA,IACvB,OAAO;AAEL,gBAAU;AAGV,UAAI,KAAK,SAAS,aAAa;AAC7B,cAAM,YAAuB;AAAA,UAC3B,GAAG;AAAA,UACH,UAAU,4BAA4B,KAAK,QAAQ;AAAA,QACrD;AACA,eAAO,KAAK,SAAS;AAAA,MACvB,OAAO;AACL,eAAO,KAAK,IAAI;AAAA,MAClB;AAAA,IACF;AAAA,EACF;AAGA,YAAU;AAEV,SAAO;AACT;;;AC/PA,SAASC,iBACP,KACA,YACA,WACA,YACY;AACZ,QAAM,QAAoB,CAAC;AAE3B,MAAI,OAAO,QAAQ,QAAQ;AACzB,UAAM,MAAM;AAAA,EACd,WAAW,QAAQ,QAAQ;AACzB,UAAM,OAAO;AAAA,EACf;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,MAAI,WAAW;AACb,UAAM,YAAY;AAAA,EACpB;AAEA,MAAI,YAAY;AACd,UAAM,aAAa;AAAA,EACrB;AAEA,SAAO;AACT;AAKA,SAASC,wBAAuB,KAAuD;AACrF,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,QAA2B,CAAC;AAElC,QAAM,QAAQ,aAAa,KAAK,KAAK,OAAO;AAC5C,MAAI,SAAS,UAAU,QAAQ;AAC7B,UAAM,QAAQ,EAAE,KAAK,MAAM;AAAA,EAC7B;AAEA,QAAM,OAAO,aAAa,KAAK,KAAK,MAAM;AAC1C,MAAI,QAAQ,SAAS,QAAQ;AAC3B,UAAM,OAAO,EAAE,KAAK,KAAK;AAAA,EAC3B;AAEA,QAAM,YAAY,aAAa,KAAK,KAAK,WAAW;AACpD,MAAI,WAAW;AACb,UAAM,OAAO,MAAM,QAAQ,CAAC;AAC5B,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,QAAM,gBAAgB,aAAa,KAAK,KAAK,eAAe;AAC5D,MAAI,iBAAiB,MAAM,MAAM;AAC/B,UAAM,KAAK,YAAY;AAAA,EACzB;AAEA,QAAM,iBAAiB,aAAa,KAAK,KAAK,gBAAgB;AAC9D,MAAI,kBAAkB,MAAM,MAAM;AAChC,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,QAAM,UAAU,aAAa,KAAK,KAAK,KAAK;AAC5C,MAAI,SAAS;AACX,UAAM,UAAU;AAAA,EAClB;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAKA,SAASC,iBAAgB,QAAmD;AAC1E,MAAI,CAAC,OAAQ,QAAO;AAEpB,QAAM,QAAQ,aAAa,QAAQ,KAAK,KAAK;AAC7C,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,OAAmB;AAAA,IACvB;AAAA,EACF;AAEA,QAAM,WAAW,aAAa,QAAQ,KAAK,OAAO;AAClD,QAAM,aAAa,aAAa,QAAQ,KAAK,YAAY;AACzD,MAAI,YAAY,YAAY;AAC1B,SAAK,QAAQF;AAAA,MACX;AAAA,MACA;AAAA,MACA,aAAa,QAAQ,KAAK,WAAW;AAAA,MACrC,aAAa,QAAQ,KAAK,YAAY;AAAA,IACxC;AAAA,EACF;AAEA,QAAM,KAAK,sBAAsB,QAAQ,KAAK,IAAI;AAClD,MAAI,OAAO,OAAW,MAAK,OAAO;AAElC,QAAM,QAAQ,sBAAsB,QAAQ,KAAK,OAAO;AACxD,MAAI,UAAU,OAAW,MAAK,QAAQ;AAEtC,QAAM,aAAa,aAAa,QAAQ,KAAK,QAAQ;AACrD,MAAI,WAAY,MAAK,SAAS,eAAe,OAAO,eAAe;AAEnE,QAAM,QAAQ,aAAa,QAAQ,KAAK,OAAO;AAC/C,MAAI,MAAO,MAAK,QAAQ,UAAU,OAAO,UAAU;AAEnD,SAAO;AACT;AAKA,SAASG,eAAc,MAAgD;AACrE,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,cAAc,aAAa,MAAM,KAAK,KAAK;AACjD,MAAI,YAAY,WAAW,EAAG,QAAO;AAErC,QAAM,SAAoB,CAAC;AAE3B,aAAW,OAAO,aAAa;AAC7B,UAAM,MAAM,sBAAsB,KAAK,KAAK,KAAK;AACjD,UAAM,MAAM,aAAa,KAAK,KAAK,KAAK;AAExC,QAAI,QAAQ,UAAa,KAAK;AAC5B,YAAM,UAAmB;AAAA,QACvB,UAAU;AAAA,QACV,WAAW;AAAA,MACb;AAEA,YAAM,SAAS,aAAa,KAAK,KAAK,QAAQ;AAC9C,UAAI,QAAQ;AACV,gBAAQ,SAAS;AAAA,MACnB;AAEA,aAAO,KAAK,OAAO;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;AAKA,SAAS,qBACP,SAC0C;AAC1C,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAsC,CAAC;AAE7C,QAAM,IAAI,sBAAsB,SAAS,KAAK,GAAG;AACjD,MAAI,MAAM,OAAW,OAAM,QAAQ;AAEnC,QAAM,IAAI,sBAAsB,SAAS,KAAK,GAAG;AACjD,MAAI,MAAM,OAAW,OAAM,SAAS;AAEpC,QAAM,UAAU,aAAa,SAAS,KAAK,SAAS;AACpD,MAAI,YAAY,UAAU,YAAY,YAAY,YAAY,QAAQ;AACpE,UAAM,UAAU;AAAA,EAClB;AAEA,QAAM,UAAU,aAAa,SAAS,KAAK,SAAS;AACpD,MAAI,YAAY,UAAU,YAAY,YAAY,YAAY,QAAQ;AACpE,UAAM,UAAU;AAAA,EAClB;AAEA,QAAM,IAAI,sBAAsB,SAAS,KAAK,GAAG;AACjD,MAAI,MAAM,OAAW,OAAM,IAAI;AAE/B,QAAM,IAAI,sBAAsB,SAAS,KAAK,GAAG;AACjD,MAAI,MAAM,OAAW,OAAM,IAAI;AAE/B,QAAM,SAAS,aAAa,SAAS,KAAK,QAAQ;AAClD,MAAI,QAAQ;AACV,UAAM,SAAS;AAAA,EACjB;AAEA,QAAM,SAAS,aAAa,SAAS,KAAK,QAAQ;AAClD,MAAI,QAAQ;AACV,UAAM,SAAS;AAAA,EACjB;AAEA,QAAM,OAAO,aAAa,SAAS,KAAK,MAAM;AAC9C,MAAI,MAAM;AACR,UAAM,OAAO;AAAA,EACf;AAEA,SAAO,OAAO,KAAK,KAAK,EAAE,SAAS,IAAI,QAAQ;AACjD;AAwBO,SAASC,0BACd,KACA,OACA,QACiC;AACjC,MAAI,CAAC,IAAK,QAAO;AAEjB,QAAM,aAAkC,CAAC;AAGzC,QAAM,KAAK,UAAU,KAAK,KAAK,IAAI;AACnC,MAAI,IAAI;AACN,UAAM,MAAM,aAAa,IAAI,KAAK,KAAK;AACvC,QAAI,KAAK;AACP,iBAAW,YAAY;AAAA,IACzB;AAAA,EACF;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,eAAW,OAAO,oBAAoB,IAAI;AAAA,EAC5C;AAGA,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,SAAS;AACX,UAAM,SAAS,sBAAsB,SAAS,KAAK,QAAQ;AAC3D,QAAI,WAAW,OAAW,YAAW,cAAc;AAEnD,UAAM,QAAQ,sBAAsB,SAAS,KAAK,OAAO;AACzD,QAAI,UAAU,OAAW,YAAW,aAAa;AAEjD,UAAM,OAAO,sBAAsB,SAAS,KAAK,MAAM;AACvD,QAAI,SAAS,OAAW,YAAW,cAAc;AAEjD,UAAM,WAAW,aAAa,SAAS,KAAK,UAAU;AACtD,QAAI,UAAU;AACZ,iBAAW,kBAAkB;AAAA,IAC/B;AAEA,UAAM,aAAa,aAAa,SAAS,KAAK,mBAAmB;AACjE,QAAI,YAAY;AACd,iBAAW,oBAAoB,eAAe,OAAO,eAAe;AAAA,IACtE;AAEA,UAAM,YAAY,aAAa,SAAS,KAAK,kBAAkB;AAC/D,QAAI,WAAW;AACb,iBAAW,mBAAmB,cAAc,OAAO,cAAc;AAAA,IACnE;AAAA,EACF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,UAAM,OAAO,sBAAsB,KAAK,KAAK,MAAM;AACnD,QAAI,SAAS,OAAW,YAAW,aAAa;AAEhD,UAAM,QAAQ,sBAAsB,KAAK,KAAK,OAAO;AACrD,QAAI,UAAU,OAAW,YAAW,cAAc;AAElD,UAAM,YAAY,sBAAsB,KAAK,KAAK,WAAW;AAC7D,QAAI,cAAc,OAAW,YAAW,kBAAkB;AAE1D,UAAM,UAAU,sBAAsB,KAAK,KAAK,SAAS;AACzD,QAAI,YAAY,QAAW;AAEzB,iBAAW,kBAAkB,CAAC;AAC9B,iBAAW,gBAAgB;AAAA,IAC7B;AAGA,UAAM,QAAQ,sBAAsB,KAAK,KAAK,OAAO;AACrD,QAAI,UAAU,UAAa,WAAW,eAAe,QAAW;AAC9D,iBAAW,aAAa;AAAA,IAC1B;AAEA,UAAM,MAAM,sBAAsB,KAAK,KAAK,KAAK;AACjD,QAAI,QAAQ,UAAa,WAAW,gBAAgB,QAAW;AAC7D,iBAAW,cAAc;AAAA,IAC3B;AAAA,EACF;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,UAAM,UAA0C,CAAC;AAEjD,UAAM,MAAMF,iBAAgB,UAAU,MAAM,KAAK,KAAK,CAAC;AACvD,QAAI,IAAK,SAAQ,MAAM;AAEvB,UAAM,SAASA,iBAAgB,UAAU,MAAM,KAAK,QAAQ,CAAC;AAC7D,QAAI,OAAQ,SAAQ,SAAS;AAE7B,UAAM,OAAOA,iBAAgB,UAAU,MAAM,KAAK,MAAM,CAAC;AACzD,QAAI,KAAM,SAAQ,OAAO;AAEzB,UAAM,QAAQA,iBAAgB,UAAU,MAAM,KAAK,OAAO,CAAC;AAC3D,QAAI,MAAO,SAAQ,QAAQ;AAE3B,UAAM,UAAUA,iBAAgB,UAAU,MAAM,KAAK,SAAS,CAAC;AAC/D,QAAI,QAAS,SAAQ,UAAU;AAE/B,UAAM,MAAMA,iBAAgB,UAAU,MAAM,KAAK,KAAK,CAAC;AACvD,QAAI,IAAK,SAAQ,MAAM;AAEvB,QAAI,OAAO,KAAK,OAAO,EAAE,SAAS,GAAG;AACnC,iBAAW,UAAU;AAAA,IACvB;AAAA,EACF;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,eAAW,UAAUD,wBAAuB,GAAG;AAAA,EACjD;AAGA,QAAM,OAAO,UAAU,KAAK,KAAK,MAAM;AACvC,MAAI,MAAM;AACR,eAAW,OAAOE,eAAc,IAAI;AAAA,EACtC;AAGA,QAAM,WAAW,UAAU,KAAK,KAAK,UAAU;AAC/C,MAAI,UAAU;AACZ,eAAW,WAAW,oBAAoB,QAAQ;AAAA,EACpD;AAEA,QAAM,YAAY,UAAU,KAAK,KAAK,WAAW;AACjD,MAAI,WAAW;AACb,eAAW,YAAY,oBAAoB,SAAS;AAAA,EACtD;AAEA,QAAM,eAAe,UAAU,KAAK,KAAK,cAAc;AACvD,MAAI,cAAc;AAChB,eAAW,eAAe,oBAAoB,YAAY;AAAA,EAC5D;AAEA,QAAM,kBAAkB,UAAU,KAAK,KAAK,iBAAiB;AAC7D,MAAI,iBAAiB;AACnB,eAAW,kBAAkB,oBAAoB,eAAe;AAAA,EAClE;AAGA,QAAM,QAAQ,UAAU,KAAK,KAAK,OAAO;AACzC,MAAI,OAAO;AACT,UAAM,UAAU,UAAU,OAAO,KAAK,OAAO;AAC7C,UAAM,SAAS,UAAU,OAAO,KAAK,MAAM;AAE3C,QAAI,WAAW,QAAQ;AACrB,iBAAW,QAAQ,CAAC;AAEpB,UAAI,SAAS;AACX,cAAM,MAAM,sBAAsB,SAAS,KAAK,KAAK;AACrD,YAAI,QAAQ,OAAW,YAAW,MAAM,QAAQ;AAAA,MAClD;AAEA,UAAI,QAAQ;AACV,cAAM,MAAM,sBAAsB,QAAQ,KAAK,KAAK;AACpD,YAAI,QAAQ,OAAW,YAAW,MAAM,OAAO;AAAA,MACjD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,UAAU,KAAK,KAAK,YAAY;AACnD,MAAI,YAAY;AACd,UAAM,MAAM,sBAAsB,YAAY,KAAK,KAAK;AACxD,QAAI,QAAQ,OAAW,YAAW,eAAe;AAAA,EACnD;AAGA,QAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,MAAI,QAAQ;AACV,UAAM,MAAM,aAAa,QAAQ,KAAK,KAAK;AAC3C,QAAI,IAAK,YAAW,UAAU;AAAA,EAChC;AAGA,QAAM,UAAU,UAAU,KAAK,KAAK,SAAS;AAC7C,MAAI,SAAS;AACX,eAAW,QAAQ,qBAAqB,OAAO;AAAA,EACjD;AAGA,QAAM,sBAAsB,UAAU,KAAK,KAAK,qBAAqB;AACrE,MAAI,qBAAqB;AACvB,eAAW,sBAAsB,oBAAoB,mBAAmB;AAAA,EAC1E;AAGA,QAAM,sBAAsB,UAAU,KAAK,KAAK,qBAAqB;AACrE,MAAI,qBAAqB;AACvB,eAAW,sBAAsB,oBAAoB,mBAAmB;AAAA,EAC1E;AAGA,QAAM,MAAM,UAAU,KAAK,KAAK,KAAK;AACrC,MAAI,KAAK;AACP,eAAW,gBAAgBE,oBAAmB,KAAK,OAAO,MAAM;AAAA,EAClE;AAEA,SAAO,OAAO,KAAK,UAAU,EAAE,SAAS,IAAI,aAAa;AAC3D;AASA,SAASC,cAAa,MAAkC;AACtD,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,SAAO,cAAc,IAAI,KAAK,UAAU,aAAa,CAAC,IAAI;AAC5D;AAOA,SAASC,gBACP,MACA,MACA,QACA,OACA,OACW;AACX,SAAO,eAAyB,MAAM,MAAM,QAAQ,OAAO,KAAK;AAClE;AAMA,SAASC,oBAAmB,MAAiC;AAC3D,SAAOA,oBAA6B,IAAI;AAC1C;AAMA,SAASC,kBAAiB,MAA+B;AACvD,SAAOA,kBAA2B,IAAI;AACxC;AAKA,SAAS,eAAe,aAAgC;AAEtD,QAAM,QAAQ,YAAY,KAAK,EAAE,MAAM,eAAe;AACtD,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,YAAY,MAAM,CAAC,EAAE,YAAY;AAEvC,QAAM,cAA2B;AAAA,IAC/B;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,MAAI,YAAY,SAAS,SAAsB,GAAG;AAChD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKA,SAAS,iBACP,MACA,QACA,OACA,MACA,OACa;AACb,QAAM,cAAc,aAAa,MAAM,KAAK,OAAO,KAAK;AACxD,QAAM,YAAY,eAAe,WAAW;AAE5C,QAAM,QAAqB;AAAA,IACzB,MAAM;AAAA,IACN;AAAA,IACA;AAAA,IACA,SAAS,CAAC;AAAA,EACZ;AAGA,QAAM,UAAU,aAAa,MAAM,KAAK,SAAS;AACjD,MAAI,YAAY,OAAO,YAAY,QAAQ;AACzC,UAAM,UAAU;AAAA,EAClB;AAGA,QAAM,QAAQ,aAAa,MAAM,KAAK,OAAO;AAC7C,MAAI,UAAU,OAAO,UAAU,QAAQ;AACrC,UAAM,QAAQ;AAAA,EAChB;AAGA,QAAM,WAAW,iBAAiB,IAAI;AACtC,aAAW,SAAS,UAAU;AAC5B,UAAM,YAAYH,cAAa,MAAM,IAAI;AACzC,QAAI,cAAc,KAAK;AACrB,YAAM,QAAQ,KAAK,SAAS,OAAO,QAAQ,OAAO,MAAM,KAAK,CAAC;AAAA,IAChE;AAAA,EACF;AAEA,SAAO;AACT;AAOA,SAAS,uBACP,aACA,QACA,OACA,YACA,MACA,OACoB;AACpB,QAAM,WAA+B,CAAC;AACtC,QAAM,WAAW,iBAAiB,WAAW;AAG7C,MAAI,iBAAiB;AACrB,MAAI,oBAAoB;AACxB,MAAI,uBAA8B,CAAC;AACnC,MAAI,yBAAgC,CAAC;AACrC,MAAI,iBAAiB;AACrB,MAAI,mBAAmB;AACvB,MAAI,oBAAoB;AAExB,aAAW,SAAS,UAAU;AAC5B,UAAM,YAAYA,cAAa,MAAM,IAAI;AAEzC,YAAQ,WAAW;AAAA,MACjB,KAAK,KAAK;AAER,cAAM,MAAM,SAAS,OAAO,QAAQ,OAAO,MAAM,KAAK;AAGtD,YAAI,gBAAgB;AACpB,YAAI,mBAAmB;AACvB,YAAI,cAAc;AAClB,YAAI,YAAY;AAEhB,mBAAW,WAAW,IAAI,SAAS;AACjC,cAAI,QAAQ,SAAS,aAAa;AAChC,gBAAI,QAAQ,aAAa,SAAS;AAChC,8BAAgB;AAChB,kBAAI,QAAQ,QAAS,oBAAmB;AACxC,kBAAI,QAAQ,MAAO,qBAAoB;AAAA,YACzC,WAAW,QAAQ,aAAa,YAAY;AAC1C,iCAAmB;AAAA,YACrB,WAAW,QAAQ,aAAa,OAAO;AACrC,4BAAc;AAAA,YAChB;AAAA,UACF,WAAW,QAAQ,SAAS,aAAa;AACvC,yBAAa,QAAQ;AAAA,UACvB;AAAA,QACF;AAEA,YAAI,eAAe;AAEjB,2BAAiB;AACjB,2BAAiB;AACjB,8BAAoB;AACpB,iCAAuB,CAAC;AACxB,mCAAyB,CAAC;AAC1B,6BAAmB;AACnB,8BAAoB;AAAA,QACtB;AAEA,YAAI,gBAAgB;AAClB,cAAI,WAAW;AACb,iCAAqB;AAAA,UACvB;AAEA,cAAI,kBAAkB;AACpB,6BAAiB;AAAA,UACnB;AAEA,cAAI,kBAAkB,CAAC,aAAa;AAElC,gBAAI,CAAC,kBAAkB;AACrB,qCAAuB,KAAK,GAAG;AAAA,YACjC;AAAA,UACF,WAAW,CAAC,kBAAkB,CAAC,eAAe;AAE5C,iCAAqB,KAAK,GAAG;AAAA,UAC/B;AAEA,cAAI,aAAa;AAEf,kBAAM,eAA6B;AAAA,cACjC,MAAM;AAAA,cACN,aAAa,kBAAkB,KAAK;AAAA,cACpC,WAAW,eAAe,iBAAiB;AAAA,cAC3C,WAAW;AAAA,cACX,aAAa;AAAA,YACf;AAEA,gBAAI,iBAAkB,cAAa,UAAU;AAC7C,gBAAI,kBAAmB,cAAa,QAAQ;AAE5C,qBAAS,KAAK,YAAY;AAC1B,6BAAiB;AAAA,UACnB;AAAA,QACF,OAAO;AAEL,mBAAS,KAAK,GAAG;AAAA,QACnB;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AACH,iBAAS,KAAKC,gBAAe,OAAO,MAAM,QAAQ,OAAO,KAAK,CAAC;AAC/D;AAAA,MAEF,KAAK;AACH,iBAAS,KAAKC,oBAAmB,KAAK,CAAC;AACvC;AAAA,MAEF,KAAK;AACH,iBAAS,KAAKC,kBAAiB,KAAK,CAAC;AACrC;AAAA,MAEF,KAAK;AACH,iBAAS,KAAK,iBAAiB,OAAO,QAAQ,OAAO,MAAM,KAAK,CAAC;AACjE;AAAA,MAEF,KAAK;AAEH;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAEH;AAAA,MAEF,KAAK,OAAO;AAEV,cAAM,cAAc,MAAM,YAAY,CAAC,GAAG;AAAA,UACxC,CAAC,OACC,GAAG,SAAS,cACX,GAAG,SAAS,kBAAkB,GAAG,MAAM,SAAS,aAAa;AAAA,QAClE;AACA,YAAI,YAAY;AAEd,gBAAM,YAAY,uBAAuB,YAAY,QAAQ,OAAO,MAAM,MAAM,KAAK;AACrF,mBAAS,KAAK,GAAG,SAAS;AAAA,QAC5B;AACA;AAAA,MACF;AAAA,MAEA,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAEH;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAEH;AAAA,MAEF,KAAK;AAAA,MACL,KAAK;AAEH;AAAA,MAEF;AAEE;AAAA,IACJ;AAAA,EACF;AAEA,SAAO;AACT;AAiBO,SAAS,eACd,MACA,QACA,OACA,WACA,OAA+B,MAC/B,QAAuC,MAC5B;AACX,QAAM,YAAuB;AAAA,IAC3B,MAAM;AAAA,IACN,SAAS,CAAC;AAAA,EACZ;AAGA,QAAM,SAAS,aAAa,MAAM,OAAO,QAAQ,KAAK,aAAa,MAAM,KAAK,QAAQ;AACtF,MAAI,QAAQ;AACV,cAAU,SAAS;AAAA,EACrB;AAEA,QAAM,SAAS,aAAa,MAAM,OAAO,QAAQ,KAAK,aAAa,MAAM,KAAK,QAAQ;AACtF,MAAI,QAAQ;AACV,cAAU,SAAS;AAAA,EACrB;AAGA,QAAM,MAAM,UAAU,MAAM,KAAK,KAAK;AACtC,MAAI,KAAK;AACP,cAAU,aAAaL,0BAAyB,KAAK,OAAO,UAAU,MAAS;AAG/E,UAAM,SAAS,UAAU,KAAK,KAAK,QAAQ;AAC3C,QAAI,QAAQ;AACV,gBAAU,oBAAoB,uBAAuB,QAAQ,IAAI;AAAA,IACnE;AAAA,EACF;AAGA,QAAM,aAAa,uBAAuB,MAAM,QAAQ,OAAO,WAAW,MAAM,KAAK;AAIrF,YAAU,UAAU,4BAA4B,UAAU;AAG1D,MAAI,UAAU,YAAY,SAAS,WAAW;AAC5C,UAAM,EAAE,OAAO,OAAO,EAAE,IAAI,UAAU,WAAW;AACjD,QAAI,UAAU,UAAa,UAAU,GAAG;AACtC,YAAM,QAAQ,UAAU,SAAS,OAAO,IAAI;AAC5C,UAAI,OAAO;AACT,kBAAU,gBAAgB;AAAA,UACxB,OAAO;AAAA,UACP;AAAA,UACA,QAAQ,MAAM;AAAA,UACd,UAAU,MAAM,WAAW;AAAA,UAC3B,QAAQ,MAAM;AAAA,QAChB;AAKA,YAAI,MAAM,KAAK;AACb,cAAI,CAAC,UAAU,YAAY;AACzB,sBAAU,aAAa,CAAC;AAAA,UAC1B;AAGA,cAAI,MAAM,IAAI,eAAe,QAAW;AACtC,sBAAU,WAAW,aAAa,MAAM,IAAI;AAAA,UAC9C;AACA,cAAI,MAAM,IAAI,oBAAoB,QAAW;AAC3C,sBAAU,WAAW,kBAAkB,MAAM,IAAI;AAAA,UACnD;AACA,cAAI,MAAM,IAAI,kBAAkB,QAAW;AACzC,sBAAU,WAAW,gBAAgB,MAAM,IAAI;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAYO,SAAS,iBAAiB,WAA8B;AAC7D,MAAI,OAAO;AAEX,aAAW,WAAW,UAAU,SAAS;AACvC,QAAI,QAAQ,SAAS,OAAO;AAC1B,iBAAW,cAAc,QAAQ,SAAS;AACxC,YAAI,WAAW,SAAS,QAAQ;AAC9B,kBAAQ,WAAW;AAAA,QACrB,WAAW,WAAW,SAAS,OAAO;AACpC,kBAAQ;AAAA,QACV,WAAW,WAAW,SAAS,SAAS;AACtC,cAAI,WAAW,cAAc,QAAQ;AACnC,oBAAQ;AAAA,UACV,OAAO;AACL,oBAAQ;AAAA,UACV;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,QAAQ,SAAS,aAAa;AACvC,iBAAW,SAAS,QAAQ,UAAU;AACpC,YAAI,MAAM,SAAS,OAAO;AACxB,qBAAW,cAAc,MAAM,SAAS;AACtC,gBAAI,WAAW,SAAS,QAAQ;AAC9B,sBAAQ,WAAW;AAAA,YACrB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,QAAQ,SAAS,eAAe;AACzC,iBAAW,SAAS,QAAQ,SAAS;AACnC,YAAI,MAAM,SAAS,OAAO;AACxB,qBAAW,cAAc,MAAM,SAAS;AACtC,gBAAI,WAAW,SAAS,QAAQ;AAC9B,sBAAQ,WAAW;AAAA,YACrB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF,WAAW,QAAQ,SAAS,gBAAgB;AAC1C,iBAAW,OAAO,QAAQ,aAAa;AACrC,mBAAW,cAAc,IAAI,SAAS;AACpC,cAAI,WAAW,SAAS,QAAQ;AAC9B,oBAAQ,WAAW;AAAA,UACrB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACr6BA,SAAS,uBAAuB,YAA4B;AAE1D,MAAI,CAAC,cAAc,WAAW,KAAK,MAAM,IAAI;AAC3C,WAAO;AAAA,EACT;AAGA,QAAM,WAAW,WAAW,WAAW,CAAC;AAIxC,QAAM,YAAoC;AAAA;AAAA,IAExC,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA;AAAA,IAGR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA,IACR,KAAQ;AAAA;AAAA;AAAA,IAGR,OAAQ;AAAA;AAAA,IACR,OAAQ;AAAA;AAAA,IACR,OAAQ;AAAA;AAAA,IACR,OAAQ;AAAA;AAAA,IACR,OAAQ;AAAA;AAAA;AAAA,IAGR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,MAAQ;AAAA;AAAA,IACR,IAAQ;AAAA;AAAA,IACR,IAAQ;AAAA;AAAA,EACV;AAGA,MAAI,UAAU,QAAQ,GAAG;AACvB,WAAO,UAAU,QAAQ;AAAA,EAC3B;AAGA,MAAI,YAAY,SAAU,YAAY,OAAQ;AAC5C,WAAO;AAAA,EACT;AAGA,MAAI,WAAW,MAAO,YAAY,OAAO,WAAW,KAAM;AACxD,WAAO;AAAA,EACT;AAGA,SAAO;AACT;AAYA,SAAS,kBACP,WACA,WACA,cACM;AACN,QAAM,gBAAgB,UAAU;AAChC,MAAI,CAAC,iBAAiB,CAAC,UAAW;AAElC,QAAM,EAAE,OAAO,MAAM,IAAI;AACzB,MAAI,UAAU,UAAa,UAAU,EAAG;AAGxC,MAAI,CAAC,aAAa,IAAI,KAAK,GAAG;AAC5B,iBAAa,IAAI,OAAO,IAAI,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;AAAA,EAC9C;AAEA,QAAM,WAAW,aAAa,IAAI,KAAK;AAGvC,WAAS,KAAK,KAAK,SAAS,KAAK,KAAK,KAAK;AAG3C,WAAS,IAAI,QAAQ,GAAG,IAAI,SAAS,QAAQ,KAAK;AAChD,aAAS,CAAC,IAAI;AAAA,EAChB;AAGA,QAAM,UAAU,cAAc;AAG9B,MAAI,cAAc,UAAU;AAG1B,UAAM,aAAa,WAAW;AAC9B,kBAAc,SAAS,uBAAuB,UAAU;AACxD;AAAA,EACF;AAGA,MAAI,iBAAiB;AAIrB,WAAS,MAAM,GAAG,OAAO,OAAO,OAAO;AACrC,UAAM,cAAc,IAAI,MAAM,CAAC;AAC/B,QAAI,eAAe,SAAS,WAAW,GAAG;AACxC,YAAM,QAAQ,SAAS,GAAG;AAC1B,YAAM,YAAY,UAAU,SAAS,OAAO,GAAG;AAC/C,YAAM,YAAY,aAAa,OAAO,WAAW,UAAU,SAAS;AACpE,uBAAiB,eAAe,QAAQ,aAAa,SAAS;AAAA,IAChE;AAAA,EACF;AAGA,gBAAc,SAAS;AACzB;AAKA,SAAS,aAAa,OAAe,QAAwB;AAC3D,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO,OAAO,KAAK;AAAA,IACrB,KAAK;AACH,aAAO,OAAO,aAAa,MAAO,QAAQ,KAAK,KAAM,CAAC;AAAA;AAAA,IACxD,KAAK;AACH,aAAO,OAAO,aAAa,MAAO,QAAQ,KAAK,KAAM,CAAC;AAAA;AAAA,IACxD,KAAK;AACH,aAAO,QAAQ,KAAK,EAAE,YAAY;AAAA,IACpC,KAAK;AACH,aAAO,QAAQ,KAAK;AAAA,IACtB,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO,OAAO,KAAK;AAAA,EACvB;AACF;AAKA,SAAS,QAAQ,KAAqB;AACpC,QAAM,gBAAoC;AAAA,IACxC,CAAC,KAAM,GAAG;AAAA,IACV,CAAC,KAAK,IAAI;AAAA,IACV,CAAC,KAAK,GAAG;AAAA,IACT,CAAC,KAAK,IAAI;AAAA,IACV,CAAC,KAAK,GAAG;AAAA,IACT,CAAC,IAAI,IAAI;AAAA,IACT,CAAC,IAAI,GAAG;AAAA,IACR,CAAC,IAAI,IAAI;AAAA,IACT,CAAC,IAAI,GAAG;AAAA,IACR,CAAC,GAAG,IAAI;AAAA,IACR,CAAC,GAAG,GAAG;AAAA,IACP,CAAC,GAAG,IAAI;AAAA,IACR,CAAC,GAAG,GAAG;AAAA,EACT;AAEA,MAAI,SAAS;AACb,aAAW,CAAC,OAAO,MAAM,KAAK,eAAe;AAC3C,WAAO,OAAO,OAAO;AACnB,gBAAU;AACV,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AASA,IAAM,0BAA0B;AAQzB,SAAS,yBAAyB,MAAwB;AAC/D,QAAM,YAAsB,CAAC;AAC7B,MAAI;AAGJ,0BAAwB,YAAY;AAEpC,UAAQ,QAAQ,wBAAwB,KAAK,IAAI,OAAO,MAAM;AAC5D,UAAM,UAAU,MAAM,CAAC,EAAE,KAAK;AAC9B,QAAI,WAAW,CAAC,UAAU,SAAS,OAAO,GAAG;AAC3C,gBAAU,KAAK,OAAO;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAQO,SAAS,4BAA4B,SAAmC;AAC7E,QAAM,YAAsB,CAAC;AAE7B,aAAW,SAAS,SAAS;AAC3B,QAAI,MAAM,SAAS,aAAa;AAC9B,YAAM,OAAO,iBAAiB,KAAK;AACnC,YAAM,OAAO,yBAAyB,IAAI;AAC1C,iBAAW,KAAK,MAAM;AACpB,YAAI,CAAC,UAAU,SAAS,CAAC,GAAG;AAC1B,oBAAU,KAAK,CAAC;AAAA,QAClB;AAAA,MACF;AAAA,IACF,WAAW,MAAM,SAAS,SAAS;AAEjC,YAAM,YAAY,sBAAsB,KAAK;AAC7C,iBAAW,KAAK,WAAW;AACzB,YAAI,CAAC,UAAU,SAAS,CAAC,GAAG;AAC1B,oBAAU,KAAK,CAAC;AAAA,QAClB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,sBAAsB,OAAwB;AACrD,QAAM,YAAsB,CAAC;AAE7B,aAAW,OAAO,MAAM,MAAM;AAC5B,eAAW,QAAQ,IAAI,OAAO;AAC5B,iBAAW,eAAe,KAAK,SAAS;AACtC,YAAI,YAAY,SAAS,aAAa;AACpC,gBAAM,OAAO,iBAAiB,WAAW;AACzC,gBAAM,OAAO,yBAAyB,IAAI;AAC1C,qBAAW,KAAK,MAAM;AACpB,gBAAI,CAAC,UAAU,SAAS,CAAC,GAAG;AAC1B,wBAAU,KAAK,CAAC;AAAA,YAClB;AAAA,UACF;AAAA,QACF,WAAW,YAAY,SAAS,SAAS;AAEvC,gBAAM,aAAa,sBAAsB,WAAW;AACpD,qBAAW,KAAK,YAAY;AAC1B,gBAAI,CAAC,UAAU,SAAS,CAAC,GAAG;AAC1B,wBAAU,KAAK,CAAC;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAiBA,SAAS,kBACP,QACA,QACA,OACA,WACA,MACA,OACgB;AAChB,QAAM,UAA0B,CAAC;AACjC,QAAM,WAAW,iBAAiB,MAAM;AAIxC,QAAM,eAAe,oBAAI,IAAsB;AAE/C,aAAW,SAAS,UAAU;AAC5B,UAAM,OAAO,MAAM,QAAQ;AAG3B,QAAI,SAAS,SAAS,KAAK,SAAS,IAAI,GAAG;AACzC,YAAM,YAAY,eAAe,OAAO,QAAQ,OAAO,WAAW,MAAM,KAAK;AAE7E,wBAAkB,WAAW,WAAW,YAAY;AACpD,cAAQ,KAAK,SAAS;AAAA,IACxB,WAES,SAAS,WAAW,KAAK,SAAS,MAAM,GAAG;AAClD,YAAM,QAAQ,WAAW,OAAO,QAAQ,OAAO,WAAW,MAAM,KAAK;AACrE,cAAQ,KAAK,KAAK;AAAA,IACpB,WAES,SAAS,WAAW,KAAK,SAAS,MAAM,GAAG;AAElD,YAAM,cAAc,MAAM,YAAY,CAAC,GAAG;AAAA,QACxC,CAAC,OACC,GAAG,SAAS,cAAc,GAAG,SAAS,kBAAkB,GAAG,MAAM,SAAS,aAAa;AAAA,MAC3F;AACA,UAAI,YAAY;AAEd,cAAM,kBAAkB;AAAA,UACtB;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,gBAAQ,KAAK,GAAG,eAAe;AAAA,MACjC;AAAA,IACF;AAAA,EAGF;AAEA,SAAO;AACT;AAiBA,SAAS,cACP,SACA,aACW;AACX,QAAM,WAAsB,CAAC;AAC7B,MAAI,wBAAwC,CAAC;AAE7C,aAAW,SAAS,SAAS;AAC3B,0BAAsB,KAAK,KAAK;AAGhC,QAAI,MAAM,SAAS,eAAe,MAAM,mBAAmB;AAEzD,eAAS,KAAK;AAAA,QACZ,YAAY,MAAM;AAAA,QAClB,SAAS;AAAA,MACX,CAAC;AAGD,8BAAwB,CAAC;AAAA,IAC3B;AAAA,EACF;AAGA,MAAI,sBAAsB,SAAS,KAAK,SAAS,WAAW,GAAG;AAC7D,aAAS,KAAK;AAAA,MACZ,YAAY,eAAe,4BAA4B;AAAA,MACvD,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAiBO,SAAS,kBACd,KACA,SAA0B,MAC1B,QAAsB,MACtB,YAAiC,MACjC,OAA+B,MAC/B,QAAuC,MACzB;AACd,QAAM,SAAuB;AAAA,IAC3B,SAAS,CAAC;AAAA,EACZ;AAEA,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAGA,QAAM,MAAM,SAAS,GAAG;AACxB,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AAGA,QAAM,cAAc,IAAI,YAAY,CAAC,GAAG;AAAA,IACtC,CAAC,OACC,GAAG,SAAS,cAAc,GAAG,SAAS,gBAAgB,GAAG,MAAM,SAAS,WAAW;AAAA,EACvF;AACA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAGA,QAAM,SAAS,UAAU,YAAY,KAAK,MAAM;AAChD,MAAI,CAAC,QAAQ;AACX,WAAO;AAAA,EACT;AAGA,SAAO,UAAU,kBAAkB,QAAQ,QAAQ,OAAO,WAAW,MAAM,KAAK;AAGhF,QAAM,cAAc,UAAU,QAAQ,KAAK,QAAQ;AACnD,MAAI,aAAa;AACf,WAAO,yBAAyB,uBAAuB,aAAa,IAAI;AAAA,EAC1E;AAGA,SAAO,WAAW,cAAc,OAAO,SAAS,OAAO,sBAAsB;AAE7E,SAAO;AACT;;;ACrfA,IAAM,cAAc,oBAAI,IAAY;AAGpC,IAAM,eAAe,oBAAI,IAA8B;AAGvD,IAAM,gBAAgB,oBAAI,IAA+B;AAGzD,IAAI,eAAe;AAUnB,SAAS,kBACP,YACA,UAAoB,CAAC,KAAK,GAAG,GAC7B,SAAkC,CAAC,UAAU,QAAQ,GAC7C;AAER,QAAM,gBAAgB,mBAAmB,UAAU;AAInD,QAAM,eAAyB,CAAC;AAEhC,aAAW,SAAS,QAAQ;AAC1B,UAAM,UAAU,UAAU,WAAW,IAAI;AACzC,eAAW,UAAU,SAAS;AAC5B,mBAAa,KAAK,GAAG,OAAO,IAAI,MAAM,EAAE;AAAA,IAC1C;AAAA,EACF;AAGA,eAAa,KAAK;AAClB,QAAM,OAAO,aAAa,KAAK,GAAG;AAElC,SAAO,4CAA4C,aAAa,cAAc,IAAI;AACpF;AASA,eAAsB,SACpB,YACA,SAIkB;AAElB,QAAM,mBAAmB,WAAW,KAAK;AAGzC,MAAI,YAAY,IAAI,gBAAgB,GAAG;AACrC,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,aAAa,IAAI,gBAAgB;AACtD,MAAI,cAAc;AAChB,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,YAA8B;AACjD,mBAAe;AAEf,QAAI;AAEF,YAAM,MAAM,kBAAkB,kBAAkB,SAAS,SAAS,SAAS,MAAM;AAGjF,YAAM,OAAO,SAAS,cAAc,MAAM;AAC1C,WAAK,MAAM;AACX,WAAK,OAAO;AAGZ,YAAM,SAAS,MAAM,IAAI,QAAiB,CAAC,YAAY;AACrD,aAAK,SAAS,MAAM,QAAQ,IAAI;AAChC,aAAK,UAAU,MAAM,QAAQ,KAAK;AAGlC,iBAAS,KAAK,YAAY,IAAI;AAG9B,mBAAW,MAAM,QAAQ,KAAK,GAAG,GAAI;AAAA,MACvC,CAAC;AAED,UAAI,QAAQ;AAEV,cAAM,qBAAqB,kBAAkB,GAAI;AAEjD,oBAAY,IAAI,gBAAgB;AAGhC,wBAAgB,CAAC,gBAAgB,CAAC;AAElC,eAAO;AAAA,MACT;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,cAAQ,KAAK,wBAAwB,gBAAgB,MAAM,KAAK;AAChE,aAAO;AAAA,IACT,UAAE;AACA,mBAAa,OAAO,gBAAgB;AAGpC,UAAI,aAAa,SAAS,GAAG;AAC3B,uBAAe;AAAA,MACjB;AAAA,IACF;AAAA,EACF,GAAG;AAEH,eAAa,IAAI,kBAAkB,WAAW;AAC9C,SAAO;AACT;AAyEA,SAAS,gBAAgB,OAAuB;AAC9C,aAAW,YAAY,eAAe;AACpC,QAAI;AACF,eAAS,KAAK;AAAA,IAChB,SAAS,OAAO;AACd,cAAQ,KAAK,6BAA6B,KAAK;AAAA,IACjD;AAAA,EACF;AACF;AASA,eAAe,qBAAqB,YAAoB,SAAmC;AAEzF,MAAI,WAAW,UAAU;AACvB,QAAI;AAEF,YAAM,WAAW,aAAa,UAAU;AACxC,YAAM,QAAQ,KAAK;AAAA,QACjB,SAAS,MAAM,KAAK,QAAQ;AAAA,QAC5B,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,OAAO,CAAC;AAAA,MACvD,CAAC;AAED,aAAO,SAAS,MAAM,MAAM,QAAQ;AAAA,IACtC,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AACvD,SAAO;AACT;AAkHO,IAAM,eAAuC;AAAA;AAAA,EAElD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,OAAO;AAAA,EACP,mBAAmB;AAAA,EACnB,eAAe;AAAA,EACf,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,SAAS;AAAA,EACT,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,gBAAgB;AAAA,EAChB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,UAAU;AAAA,EACV,qBAAqB;AAAA,EACrB,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,iBAAiB;AAAA,EACjB,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,QAAQ;AACV;AAQO,SAAS,wBAAwB,UAA0B;AAChE,QAAM,UAAU,SAAS,KAAK;AAC9B,SAAO,aAAa,OAAO,KAAK;AAClC;AAUA,eAAsB,oBAAoB,YAAsC;AAC9E,QAAM,UAAU,WAAW,KAAK;AAChC,QAAM,aAAa,wBAAwB,OAAO;AAIlD,MAAI,eAAe,SAAS;AAC1B,UAAM,gBAAgB,SAAS,UAAU;AACzC,gBAAY,IAAI,OAAO;AACvB,gBAAY,IAAI,UAAU;AAC1B,WAAO;AAAA,EACT;AAGA,SAAO,SAAS,UAAU;AAC5B;AASA,eAAe,gBAAgB,cAAsB,gBAAuC;AAE1F,QAAM,UAAU,cAAc,aAAa,YAAY,EAAE,QAAQ,QAAQ,GAAG,CAAC;AAG7E,MAAI,SAAS,eAAe,OAAO,GAAG;AACpC;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,MAAM,kBAAkB,gBAAgB,CAAC,KAAK,GAAG,GAAG,CAAC,UAAU,QAAQ,CAAC;AAC9E,UAAM,WAAW,MAAM,MAAM,GAAG;AAEhC,QAAI,CAAC,SAAS,IAAI;AAChB,cAAQ,KAAK,yCAAyC,cAAc,MAAM,SAAS,MAAM,EAAE;AAC3F;AAAA,IACF;AAEA,UAAM,MAAM,MAAM,SAAS,KAAK;AAKhC,UAAM,QAAQ,IAAI,OAAO,uBAAuB,aAAa,cAAc,CAAC,QAAQ,IAAI;AACxF,UAAM,aAAa,IAAI,QAAQ,OAAO,iBAAiB,YAAY,GAAG;AAEtE,UAAM,QAAQ,SAAS,cAAc,OAAO;AAC5C,UAAM,KAAK;AACX,UAAM,cAAc;AAEpB,aAAS,KAAK,YAAY,KAAK;AAC/B,YAAQ,IAAI,iBAAiB,YAAY,UAAU,cAAc,GAAG;AAAA,EACtE,SAAS,OAAO;AACd,YAAQ,KAAK,oCAAoC,YAAY,MAAM,KAAK;AAAA,EAC1E;AACF;AAKA,SAAS,aAAa,QAAwB;AAC5C,SAAO,OAAO,QAAQ,uBAAuB,MAAM;AACrD;AAQA,eAAsB,qBAAqB,UAAmC;AAE5E,QAAM,cAAc,CAAC,GAAG,IAAI,IAAI,SAAS,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;AAE9D,QAAM,QAAQ,IAAI,YAAY,IAAI,CAAC,WAAW,oBAAoB,MAAM,CAAC,CAAC;AAC5E;;;ACvZA,eAAsB,UACpB,QACA,UAAwB,CAAC,GACN;AACnB,QAAM;AAAA,IACJ,aAAa,MAAM;AAAA,IAAC;AAAA,IACpB,eAAe;AAAA,IACf,sBAAsB;AAAA,IACtB,aAAa;AAAA,IACb,kBAAkB;AAAA,EACpB,IAAI;AAEJ,QAAM,WAAqB,CAAC;AAE5B,MAAI;AAIF,eAAW,sBAAsB,CAAC;AAClC,UAAM,MAAM,MAAM,UAAU,MAAM;AAClC,eAAW,kBAAkB,EAAE;AAK/B,eAAW,4BAA4B,EAAE;AACzC,UAAM,OAAO,IAAI,eAAe,mBAAmB,IAAI,YAAY,IAAI,oBAAI,IAAI;AAC/E,eAAW,wBAAwB,EAAE;AAKrC,eAAW,oBAAoB,EAAE;AACjC,UAAM,QAAQ,WAAW,IAAI,QAAQ;AACrC,eAAW,gBAAgB,EAAE;AAK7B,eAAW,qBAAqB,EAAE;AAClC,QAAI,SAA0B;AAC9B,QAAI;AAEJ,QAAI,IAAI,WAAW;AACjB,eAAS,YAAY,IAAI,WAAW,KAAK;AACzC,yBAAmB,sBAAsB,IAAI,WAAW,KAAK;AAAA,IAC/D;AACA,eAAW,iBAAiB,EAAE;AAK9B,eAAW,wBAAwB,EAAE;AACrC,UAAM,YAAY,eAAe,IAAI,YAAY;AACjD,eAAW,oBAAoB,EAAE;AAKjC,eAAW,6BAA6B,EAAE;AAC1C,UAAM,QAAQ,cAAc,KAAK,IAAI;AACrC,eAAW,mBAAmB,EAAE;AAKhC,eAAW,4BAA4B,EAAE;AACzC,QAAI,eAA6B,EAAE,SAAS,CAAC,EAAE;AAE/C,QAAI,IAAI,aAAa;AACnB,qBAAe,kBAAkB,IAAI,aAAa,QAAQ,OAAO,WAAW,MAAM,KAAK;AAAA,IACzF,OAAO;AACL,eAAS,KAAK,+BAA+B;AAAA,IAC/C;AACA,eAAW,wBAAwB,EAAE;AAKrC,QAAI;AACJ,QAAI;AAEJ,QAAI,qBAAqB;AACvB,iBAAW,8BAA8B,EAAE;AAC3C,YAAM,EAAE,SAAS,GAAG,SAAS,EAAE,IAAI;AAAA,QACjC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,gBAAU;AACV,gBAAU;AACV,iBAAW,0BAA0B,EAAE;AAAA,IACzC,OAAO;AACL,iBAAW,4BAA4B,EAAE;AAAA,IAC3C;AAKA,QAAI;AACJ,QAAI;AAEJ,QAAI,YAAY;AACd,iBAAW,iCAAiC,EAAE;AAC9C,YAAM,EAAE,WAAW,IAAI,UAAU,GAAG,IAAI;AAAA,QACtC;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,kBAAY;AACZ,iBAAW;AACX,iBAAW,6BAA6B,EAAE;AAAA,IAC5C,OAAO;AACL,iBAAW,+BAA+B,EAAE;AAAA,IAC9C;AAKA,QAAI;AAEJ,QAAI,iBAAiB;AACnB,iBAAW,mCAAmC,EAAE;AAChD,0BAAoB,4BAA4B,aAAa,OAAO;AACpE,iBAAW,sBAAsB,EAAE;AAAA,IACrC,OAAO;AACL,iBAAW,+BAA+B,EAAE;AAAA,IAC9C;AAKA,QAAI,cAAc;AAChB,iBAAW,oBAAoB,EAAE;AACjC,YAAM,kBAAkB,OAAO,kBAAkB,YAAY;AAC7D,iBAAW,gBAAgB,EAAE;AAAA,IAC/B,OAAO;AACL,iBAAW,yBAAyB,EAAE;AAAA,IACxC;AAKA,eAAW,0BAA0B,EAAE;AAEvC,UAAM,MAAmB;AAAA,MACvB,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA,WAAW,UAAU;AAAA,MACrB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe;AAAA,MACf;AAAA,IACF;AAEA,UAAMM,YAAqB;AAAA,MACzB,SAAS;AAAA,MACT,gBAAgB;AAAA,MAChB;AAAA,MACA,UAAU,SAAS,SAAS,IAAI,WAAW;AAAA,IAC7C;AAEA,eAAW,YAAY,GAAG;AAC1B,WAAOA;AAAA,EACT,SAAS,OAAO;AACd,UAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACrE,UAAM,IAAI,MAAM,yBAAyB,OAAO,EAAE;AAAA,EACpD;AACF;AASA,SAAS,cAAc,KAAqB,OAAgD;AAC1F,QAAM,QAAQ,oBAAI,IAAuB;AAGzC,aAAW,CAAC,MAAM,IAAI,KAAK,IAAI,MAAM,QAAQ,GAAG;AAC9C,UAAM,WAAW,KAAK,MAAM,GAAG,EAAE,IAAI,KAAK;AAC1C,UAAM,WAAW,iBAAiB,IAAI;AAGtC,UAAM,QAAQ,IAAI,WAAW,IAAI;AACjC,QAAI,SAAS;AACb,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAU,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,IACxC;AACA,UAAM,SAAS,KAAK,MAAM;AAC1B,UAAM,UAAU,QAAQ,QAAQ,WAAW,MAAM;AAEjD,UAAM,YAAuB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAGA,UAAM,IAAI,MAAM,SAAS;AAGzB,UAAM,iBAAiB,KAAK,QAAQ,WAAW,EAAE;AACjD,QAAI,mBAAmB,MAAM;AAC3B,YAAM,IAAI,gBAAgB,SAAS;AAAA,IACrC;AAAA,EACF;AAEA,SAAO;AACT;AASA,SAAS,sBAAyB,KAAqB,WAAkC;AACvF,QAAM,cAAc,UAAU,YAAY;AAC1C,aAAW,CAAC,KAAK,KAAK,KAAK,IAAI,QAAQ,GAAG;AACxC,QAAI,IAAI,YAAY,MAAM,aAAa;AACrC,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,uBACP,KACA,QACA,OACA,WACA,MACA,OAC4E;AAC5E,QAAM,UAAU,oBAAI,IAA0B;AAC9C,QAAM,UAAU,oBAAI,IAA0B;AAM9C,aAAW,CAAC,KAAK,GAAG,KAAK,KAAK,QAAQ,GAAG;AACvC,QAAI,IAAI,SAAS,mBAAmB,UAAU,IAAI,QAAQ;AAGxD,YAAM,WAAW,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI;AACpD,YAAM,YAAY,sBAAsB,IAAI,SAAS,QAAQ;AAE7D,UAAI,WAAW;AAEb,cAAM,iBAAiB,cAAc,QAAQ;AAC7C,cAAM,gBAAgB,sBAAsB,IAAI,QAAQ,cAAc;AACtE,cAAM,aAAa,gBAAgB,mBAAmB,aAAa,IAAI;AAEvE,cAAM,SAAS;AAAA,UACb;AAAA,UACA;AAAA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,gBAAQ,IAAI,KAAK,MAAM;AAAA,MACzB;AAAA,IACF,WAAW,IAAI,SAAS,mBAAmB,UAAU,IAAI,QAAQ;AAE/D,YAAM,WAAW,IAAI,OAAO,MAAM,GAAG,EAAE,IAAI,KAAK,IAAI;AACpD,YAAM,YAAY,sBAAsB,IAAI,SAAS,QAAQ;AAE7D,UAAI,WAAW;AAEb,cAAM,iBAAiB,cAAc,QAAQ;AAC7C,cAAM,gBAAgB,sBAAsB,IAAI,QAAQ,cAAc;AACtE,cAAM,aAAa,gBAAgB,mBAAmB,aAAa,IAAI;AAEvE,cAAM,SAAS;AAAA,UACb;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AACA,gBAAQ,IAAI,KAAK,MAAM;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAEA,SAAO,EAAE,SAAS,QAAQ;AAC5B;AAKA,SAAS,kBACP,KACA,QACA,OACA,WACA,MACA,OACgD;AAChD,QAAM,cAAc,eAAe,IAAI,cAAc,QAAQ,OAAO,WAAW,MAAM,KAAK;AAE1F,QAAM,aAAa,cAAc,IAAI,aAAa,QAAQ,OAAO,WAAW,MAAM,KAAK;AAEvF,SAAO;AAAA,IACL,WAAW,YAAY,mBAAmB;AAAA,IAC1C,UAAU,WAAW,kBAAkB;AAAA,EACzC;AACF;AAKA,eAAe,kBACb,OACA,kBACA,cACe;AACf,QAAM,YAAY,oBAAI,IAAY;AAGlC,MAAI,OAAO,YAAY;AACrB,UAAM,EAAE,WAAW,UAAU,IAAI,MAAM;AACvC,QAAI,WAAW,MAAO,WAAU,IAAI,UAAU,KAAK;AACnD,QAAI,WAAW,MAAO,WAAU,IAAI,UAAU,KAAK;AAAA,EACrD;AAGA,MAAI,kBAAkB,aAAa,KAAK,YAAY,OAAO;AACzD,cAAU,IAAI,iBAAiB,YAAY,IAAI,WAAW,KAAK;AAAA,EACjE;AAGA,MAAI,kBAAkB,QAAQ;AAC5B,eAAW,SAAS,iBAAiB,QAAQ;AAC3C,UAAI,MAAM,KAAK,YAAY,OAAO;AAChC,kBAAU,IAAI,MAAM,IAAI,WAAW,KAAK;AAAA,MAC1C;AACA,UAAI,MAAM,KAAK,YAAY,OAAO;AAChC,kBAAU,IAAI,MAAM,IAAI,WAAW,KAAK;AAAA,MAC1C;AAAA,IACF;AAAA,EACF;AAGA,MAAI,aAAa,SAAS;AACxB,eAAW,SAAS,aAAa,SAAS;AACxC,UAAI,MAAM,SAAS,aAAa;AAC9B,mBAAW,QAAQ,MAAM,SAAS;AAChC,cAAI,KAAK,SAAS,SAAS,KAAK,YAAY,YAAY;AACtD,gBAAI,KAAK,WAAW,WAAW,OAAO;AACpC,wBAAU,IAAI,KAAK,WAAW,WAAW,KAAK;AAAA,YAChD;AACA,gBAAI,KAAK,WAAW,WAAW,OAAO;AACpC,wBAAU,IAAI,KAAK,WAAW,WAAW,KAAK;AAAA,YAChD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,MAAI,UAAU,OAAO,GAAG;AACtB,QAAI;AACF,YAAM,qBAAqB,MAAM,KAAK,SAAS,CAAC;AAAA,IAClD,SAAS,OAAO;AAEd,cAAQ,KAAK,8BAA8B,KAAK;AAAA,IAClD;AAAA,EACF;AACF;;;ACtbA,IAAAC,gBAAkB;;;ACOlB,SAAS,UAAU,MAAsB;AACvC,SAAO,KACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AASA,SAAS,sBAAsB,OAAuC;AACpE,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,MAAM;AACd,UAAM,KAAK,cAAc;AAAA,EAC3B,WAAW,MAAM,KAAK;AACpB,UAAM,KAAK,UAAU,MAAM,GAAG,GAAG;AAAA,EACnC;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,KAAK,iBAAiB,MAAM,UAAU,GAAG;AAAA,EACjD;AAEA,MAAI,MAAM,WAAW;AACnB,UAAM,KAAK,gBAAgB,MAAM,SAAS,GAAG;AAAA,EAC/C;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,KAAK,iBAAiB,MAAM,UAAU,GAAG;AAAA,EACjD;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,YAAY,MAAM,KAAK,GAAG,CAAC;AACpC;AASA,SAAS,iBAAiB,SAAgD;AACxE,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAkB,CAAC;AAGzB,MAAI,QAAQ,SAAS;AACnB,UAAM,KAAK,UAAU,QAAQ,OAAO,GAAG;AAAA,EACzC,OAAO;AACL,UAAM,KAAK,eAAe;AAAA,EAC5B;AAGA,MAAI,QAAQ,OAAO,KAAK;AACtB,UAAM,KAAK,YAAY,QAAQ,MAAM,GAAG,GAAG;AAAA,EAC7C,WAAW,QAAQ,OAAO,MAAM;AAC9B,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,QAAQ,MAAM,KAAK;AACrB,UAAM,KAAK,WAAW,QAAQ,KAAK,GAAG,GAAG;AAAA,EAC3C,WAAW,QAAQ,MAAM,MAAM;AAC7B,UAAM,KAAK,eAAe;AAAA,EAC5B;AAGA,MAAI,QAAQ,MAAM,YAAY;AAC5B,UAAM,KAAK,gBAAgB,QAAQ,KAAK,UAAU,GAAG;AAAA,EACvD;AAEA,MAAI,QAAQ,MAAM,WAAW;AAC3B,UAAM,KAAK,oBAAoB,QAAQ,KAAK,SAAS,GAAG;AAAA,EAC1D;AAEA,MAAI,QAAQ,MAAM,YAAY;AAC5B,UAAM,KAAK,qBAAqB,QAAQ,KAAK,UAAU,GAAG;AAAA,EAC5D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,UAAU,MAAM,KAAK,GAAG,CAAC;AAClC;AASO,SAAS,wBAAwB,YAAgD;AACtF,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAkB,CAAC;AAGzB,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,oBAAoB,UAAU,WAAW,OAAO,CAAC,KAAK;AAAA,EACnE;AAGA,MAAI,WAAW,YAAY;AACzB,UAAM,YAAsB,CAAC;AAC7B,QAAI,WAAW,WAAW,OAAO;AAC/B,gBAAU,KAAK,YAAY,UAAU,WAAW,WAAW,KAAK,CAAC,GAAG;AAAA,IACtE;AACA,QAAI,WAAW,WAAW,OAAO;AAC/B,gBAAU,KAAK,YAAY,UAAU,WAAW,WAAW,KAAK,CAAC,GAAG;AAAA,IACtE;AACA,QAAI,WAAW,WAAW,UAAU;AAClC,gBAAU,KAAK,eAAe,UAAU,WAAW,WAAW,QAAQ,CAAC,GAAG;AAAA,IAC5E;AACA,QAAI,WAAW,WAAW,IAAI;AAC5B,gBAAU,KAAK,SAAS,UAAU,WAAW,WAAW,EAAE,CAAC,GAAG;AAAA,IAChE;AACA,QAAI,WAAW,WAAW,YAAY;AACpC,gBAAU,KAAK,iBAAiB,WAAW,WAAW,UAAU,GAAG;AAAA,IACrE;AACA,QAAI,WAAW,WAAW,YAAY;AACpC,gBAAU,KAAK,iBAAiB,WAAW,WAAW,UAAU,GAAG;AAAA,IACrE;AACA,QAAI,WAAW,WAAW,eAAe;AACvC,gBAAU,KAAK,oBAAoB,WAAW,WAAW,aAAa,GAAG;AAAA,IAC3E;AACA,QAAI,WAAW,WAAW,SAAS;AACjC,gBAAU,KAAK,cAAc,WAAW,WAAW,OAAO,GAAG;AAAA,IAC/D;AACA,QAAI,UAAU,SAAS,GAAG;AACxB,YAAM,KAAK,aAAa,UAAU,KAAK,GAAG,CAAC,IAAI;AAAA,IACjD;AAAA,EACF;AAGA,MAAI,WAAW,SAAS,MAAM;AAC5B,UAAM,KAAK,QAAQ;AAAA,EACrB,WAAW,WAAW,SAAS,OAAO;AACpC,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAEA,MAAI,WAAW,WAAW,MAAM;AAC9B,UAAM,KAAK,UAAU;AAAA,EACvB,WAAW,WAAW,WAAW,OAAO;AACtC,UAAM,KAAK,oBAAoB;AAAA,EACjC;AAGA,MAAI,WAAW,WAAW,MAAM;AAC9B,UAAM,KAAK,QAAQ;AAAA,EACrB,WAAW,WAAW,WAAW,OAAO;AACtC,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAEA,MAAI,WAAW,aAAa,MAAM;AAChC,UAAM,KAAK,UAAU;AAAA,EACvB,WAAW,WAAW,aAAa,OAAO;AACxC,UAAM,KAAK,oBAAoB;AAAA,EACjC;AAGA,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,WAAW;AAAA,EACxB;AAEA,MAAI,WAAW,WAAW;AACxB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,MAAI,WAAW,cAAc;AAC3B,UAAM,KAAK,cAAc;AAAA,EAC3B;AAGA,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,cAAc;AAAA,EAC3B;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAGA,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,cAAc;AAAA,EAC3B;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAGA,QAAM,WAAW,sBAAsB,WAAW,KAAK;AACvD,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,MAAI,WAAW,YAAY,QAAW;AACpC,UAAM,KAAK,qBAAqB,WAAW,OAAO,KAAK;AAAA,EACzD;AAGA,MAAI,WAAW,UAAU,QAAW;AAClC,UAAM,KAAK,eAAe,WAAW,KAAK,KAAK;AAAA,EACjD;AAGA,MAAI,WAAW,YAAY,QAAW;AACpC,UAAM,KAAK,kBAAkB,WAAW,OAAO,KAAK;AAAA,EACtD;AAGA,MAAI,WAAW,aAAa,QAAW;AACrC,UAAM,KAAK,sBAAsB,WAAW,QAAQ,KAAK;AAAA,EAC3D;AAGA,MAAI,WAAW,aAAa,QAAW;AACrC,UAAM,KAAK,gBAAgB,WAAW,QAAQ,KAAK;AAAA,EACrD;AAEA,MAAI,WAAW,eAAe,QAAW;AACvC,UAAM,KAAK,kBAAkB,WAAW,UAAU,KAAK;AAAA,EACzD;AAGA,MAAI,WAAW,aAAa,WAAW,cAAc,QAAQ;AAC3D,UAAM,KAAK,uBAAuB,WAAW,SAAS,KAAK;AAAA,EAC7D;AAGA,MAAI,WAAW,WAAW;AACxB,UAAM,SAAmB,CAAC,UAAU,WAAW,UAAU,KAAK,GAAG;AACjE,QAAI,WAAW,UAAU,OAAO;AAC9B,UAAI,WAAW,UAAU,MAAM,KAAK;AAClC,eAAO,KAAK,YAAY,WAAW,UAAU,MAAM,GAAG,GAAG;AAAA,MAC3D;AACA,UAAI,WAAW,UAAU,MAAM,YAAY;AACzC,eAAO,KAAK,iBAAiB,WAAW,UAAU,MAAM,UAAU,GAAG;AAAA,MACvE;AAAA,IACF;AACA,UAAM,KAAK,QAAQ,OAAO,KAAK,GAAG,CAAC,IAAI;AAAA,EACzC;AAGA,MAAI,WAAW,UAAU,WAAW,WAAW,QAAQ;AACrD,UAAM,KAAK,oBAAoB,WAAW,MAAM,KAAK;AAAA,EACvD;AAGA,MAAI,WAAW,gBAAgB,WAAW,iBAAiB,QAAQ;AACjE,UAAM,KAAK,gBAAgB,WAAW,YAAY,KAAK;AAAA,EACzD;AAGA,QAAM,aAAa,iBAAiB,WAAW,OAAO;AACtD,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,MAAI,WAAW,aAAa,WAAW,cAAc,YAAY;AAC/D,UAAM,KAAK,uBAAuB,WAAW,SAAS,KAAK;AAAA,EAC7D;AAGA,MAAI,WAAW,KAAK;AAClB,UAAM,KAAK,UAAU;AAAA,EACvB;AAEA,MAAI,WAAW,IAAI;AACjB,UAAM,KAAK,SAAS;AAAA,EACtB;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,UAAU,MAAM,KAAK,EAAE,CAAC;AACjC;AASA,SAAS,qBAAqB,SAA8B;AAC1D,QAAM,gBACJ,QAAQ,iBACR,QAAQ,KAAK,WAAW,GAAG,KAC3B,QAAQ,KAAK,SAAS,GAAG,KACzB,QAAQ,KAAK,SAAS,IAAI;AAE5B,QAAM,YAAY,gBAAgB,0BAA0B;AAE5D,SAAO,OAAO,SAAS,IAAI,UAAU,QAAQ,IAAI,CAAC;AACpD;AAKA,SAAS,oBAAoB,UAA8B;AACzD,SAAO;AACT;AAKA,SAAS,sBAAsB,SAA+B;AAC5D,QAAM,QAAkB,CAAC;AAEzB,MAAI,QAAQ,cAAc,QAAQ;AAChC,UAAM,KAAK,eAAe;AAAA,EAC5B,WAAW,QAAQ,cAAc,UAAU;AACzC,UAAM,KAAK,iBAAiB;AAAA,EAC9B,WAAW,QAAQ,cAAc,gBAAgB;AAC/C,UAAM,KAAK,uBAAuB;AAClC,QAAI,QAAQ,SAAS,QAAQ,UAAU,QAAQ;AAC7C,YAAM,KAAK,YAAY,QAAQ,KAAK,GAAG;AAAA,IACzC;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,MAAM,KAAK,GAAG,CAAC;AACjC;AAKA,SAAS,uBAAuB,SAAgC;AAC9D,SAAO,kBAAkB,UAAU,QAAQ,IAAI,CAAC,aAAa,UAAU,QAAQ,IAAI,CAAC;AACtF;AAKA,SAAS,uBAAuB,SAAuC;AACrE,MAAI,QAAQ,SAAS,eAAe;AAClC,WAAO,8BAA8B,QAAQ,EAAE;AAAA,EACjD,OAAO;AACL,WAAO,6BAA6B,QAAQ,EAAE;AAAA,EAChD;AACF;AAKA,SAAS,mBAAmB,SAAmC;AAC7D,QAAM,QAAkB,CAAC,kBAAkB,QAAQ,QAAQ,GAAG;AAE9D,MAAI,QAAQ,SAAS;AACnB,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAEA,MAAI,QAAQ,OAAO;AACjB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,SAAO,cAAc,MAAM,KAAK,GAAG,CAAC;AACtC;AAKA,SAAS,mBAAmB,SAAmC;AAC7D,QAAM,gBACJ,QAAQ,KAAK,WAAW,GAAG,KAAK,QAAQ,KAAK,SAAS,GAAG,KAAK,QAAQ,KAAK,SAAS,IAAI;AAE1F,QAAM,YAAY,gBAAgB,0BAA0B;AAE5D,SAAO,eAAe,SAAS,IAAI,UAAU,QAAQ,IAAI,CAAC;AAC5D;AAKA,SAAS,oBAAoB,UAAqC;AAChE,SAAO;AACT;AAKA,SAAS,uBAAuB,UAAwC;AACtE,SAAO;AACT;AAOA,SAAS,wBAAwB,SAAiC;AAGhE,MAAI,QAAQ,MAAM,KAAK;AACrB,WAAO,0BAA0B,QAAQ,MAAM,GAAG;AAAA,EACpD;AACA,SAAO;AACT;AAMA,SAAS,sBAAsB,SAA+B;AAE5D,SAAO,eAAe,QAAQ,MAAM,aAAa,SAAS;AAC5D;AAKA,SAAS,oBAAoB,SAA6B;AACxD,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,aAAO,qBAAqB,OAAO;AAAA,IACrC,KAAK;AACH,aAAO,oBAAoB,OAAO;AAAA,IACpC,KAAK;AACH,aAAO,sBAAsB,OAAO;AAAA,IACtC,KAAK;AACH,aAAO,uBAAuB,OAAO;AAAA,IACvC,KAAK;AAAA,IACL,KAAK;AACH,aAAO,uBAAuB,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,mBAAmB,OAAO;AAAA,IACnC,KAAK;AACH,aAAO,mBAAmB,OAAO;AAAA,IACnC,KAAK;AACH,aAAO,oBAAoB,OAAO;AAAA,IACpC,KAAK;AACH,aAAO,uBAAuB,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,wBAAwB,OAAO;AAAA,IACxC,KAAK;AACH,aAAO,sBAAsB,OAAO;AAAA,IACtC;AACE,aAAO;AAAA,EACX;AACF;AAYO,SAAS,aAAa,KAAkB;AAC7C,QAAM,QAAkB,CAAC;AAGzB,QAAM,SAAS,wBAAwB,IAAI,UAAU;AACrD,MAAI,QAAQ;AACV,UAAM,KAAK,MAAM;AAAA,EACnB;AAGA,aAAW,WAAW,IAAI,SAAS;AACjC,UAAM,aAAa,oBAAoB,OAAO;AAC9C,QAAI,YAAY;AACd,YAAM,KAAK,UAAU;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,QAAQ,MAAM,KAAK,EAAE,CAAC;AAC/B;;;ACnfA,SAASC,WAAU,MAAsB;AACvC,SAAO,KACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AASA,SAAS,gBAAgB,QAAgC,aAA6B;AACpF,MAAI,CAAC,UAAU,OAAO,UAAU,UAAU,OAAO,UAAU,OAAO;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC,UAAU,OAAO,KAAK,GAAG;AAElD,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,KAAK,SAAS,OAAO,IAAI,GAAG;AAAA,EACpC;AAEA,MAAI,OAAO,UAAU,QAAW;AAC9B,UAAM,KAAK,YAAY,OAAO,KAAK,GAAG;AAAA,EACxC;AAGA,MAAI,OAAO,OAAO;AAChB,QAAI,OAAO,MAAM,MAAM;AACrB,YAAM,KAAK,gBAAgB;AAAA,IAC7B,WAAW,OAAO,MAAM,KAAK;AAC3B,YAAM,KAAK,YAAY,OAAO,MAAM,GAAG,GAAG;AAAA,IAC5C;AAEA,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,KAAK,iBAAiB,OAAO,MAAM,UAAU,GAAG;AAAA,IACxD;AAEA,QAAI,OAAO,MAAM,WAAW;AAC1B,YAAM,KAAK,gBAAgB,OAAO,MAAM,SAAS,GAAG;AAAA,IACtD;AAEA,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,KAAK,iBAAiB,OAAO,MAAM,UAAU,GAAG;AAAA,IACxD;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ;AACjB,UAAM,KAAK,iBAAiB;AAAA,EAC9B;AAEA,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,SAAO,MAAM,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC;AAC7C;AAKA,SAAS,0BAA0B,SAAiD;AAClF,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAkB,CAAC;AAEzB,MAAI,QAAQ,KAAK;AACf,UAAM,SAAS,gBAAgB,QAAQ,KAAK,KAAK;AACjD,QAAI,OAAQ,OAAM,KAAK,MAAM;AAAA,EAC/B;AAEA,MAAI,QAAQ,MAAM;AAChB,UAAM,UAAU,gBAAgB,QAAQ,MAAM,MAAM;AACpD,QAAI,QAAS,OAAM,KAAK,OAAO;AAAA,EACjC;AAEA,MAAI,QAAQ,QAAQ;AAClB,UAAM,YAAY,gBAAgB,QAAQ,QAAQ,QAAQ;AAC1D,QAAI,UAAW,OAAM,KAAK,SAAS;AAAA,EACrC;AAEA,MAAI,QAAQ,OAAO;AACjB,UAAM,WAAW,gBAAgB,QAAQ,OAAO,OAAO;AACvD,QAAI,SAAU,OAAM,KAAK,QAAQ;AAAA,EACnC;AAEA,MAAI,QAAQ,SAAS;AACnB,UAAM,aAAa,gBAAgB,QAAQ,SAAS,SAAS;AAC7D,QAAI,WAAY,OAAM,KAAK,UAAU;AAAA,EACvC;AAEA,MAAI,QAAQ,KAAK;AACf,UAAM,SAAS,gBAAgB,QAAQ,KAAK,KAAK;AACjD,QAAI,OAAQ,OAAM,KAAK,MAAM;AAAA,EAC/B;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,WAAW,MAAM,KAAK,EAAE,CAAC;AAClC;AASA,SAASC,kBAAiB,SAAgD;AACxE,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAkB,CAAC;AAGzB,MAAI,QAAQ,SAAS;AACnB,UAAM,KAAK,UAAU,QAAQ,OAAO,GAAG;AAAA,EACzC,OAAO;AACL,UAAM,KAAK,eAAe;AAAA,EAC5B;AAGA,MAAI,QAAQ,OAAO,KAAK;AACtB,UAAM,KAAK,YAAY,QAAQ,MAAM,GAAG,GAAG;AAAA,EAC7C,WAAW,QAAQ,OAAO,MAAM;AAC9B,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,QAAQ,MAAM,KAAK;AACrB,UAAM,KAAK,WAAW,QAAQ,KAAK,GAAG,GAAG;AAAA,EAC3C,WAAW,QAAQ,MAAM,MAAM;AAC7B,UAAM,KAAK,eAAe;AAAA,EAC5B;AAGA,MAAI,QAAQ,MAAM,YAAY;AAC5B,UAAM,KAAK,gBAAgB,QAAQ,KAAK,UAAU,GAAG;AAAA,EACvD;AAEA,MAAI,QAAQ,MAAM,WAAW;AAC3B,UAAM,KAAK,oBAAoB,QAAQ,KAAK,SAAS,GAAG;AAAA,EAC1D;AAEA,MAAI,QAAQ,MAAM,YAAY;AAC5B,UAAM,KAAK,qBAAqB,QAAQ,KAAK,UAAU,GAAG;AAAA,EAC5D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,UAAU,MAAM,KAAK,GAAG,CAAC;AAClC;AASA,SAAS,kBAAkB,MAAqC;AAC9D,MAAI,CAAC,QAAQ,KAAK,WAAW,EAAG,QAAO;AAEvC,QAAM,cAAc,KAAK,IAAI,CAAC,QAAQ;AACpC,UAAM,QAAkB,CAAC,UAAU,IAAI,SAAS,KAAK,UAAU,IAAI,QAAQ,GAAG;AAE9E,QAAI,IAAI,UAAU,IAAI,WAAW,QAAQ;AACvC,YAAM,KAAK,aAAa,IAAI,MAAM,GAAG;AAAA,IACvC;AAEA,WAAO,UAAU,MAAM,KAAK,GAAG,CAAC;AAAA,EAClC,CAAC;AAED,SAAO,WAAW,YAAY,KAAK,EAAE,CAAC;AACxC;AASA,SAAS,iBAAiB,YAAyC;AACjE,QAAM,QAAkB,CAAC;AAEzB,MAAI,WAAW,gBAAgB,QAAW;AACxC,UAAM,KAAK,aAAa,WAAW,WAAW,GAAG;AAAA,EACnD;AAEA,MAAI,WAAW,eAAe,QAAW;AACvC,UAAM,KAAK,YAAY,WAAW,UAAU,GAAG;AAAA,EACjD;AAEA,MAAI,WAAW,gBAAgB,QAAW;AACxC,UAAM,KAAK,WAAW,WAAW,WAAW,GAAG;AAAA,EACjD;AAEA,MAAI,WAAW,iBAAiB;AAC9B,UAAM,KAAK,eAAe,WAAW,eAAe,GAAG;AAAA,EACzD;AAEA,MAAI,WAAW,mBAAmB;AAChC,UAAM,KAAK,yBAAyB;AAAA,EACtC;AAEA,MAAI,WAAW,kBAAkB;AAC/B,UAAM,KAAK,wBAAwB;AAAA,EACrC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,cAAc,MAAM,KAAK,GAAG,CAAC;AACtC;AASA,SAAS,qBAAqB,YAAyC;AACrE,QAAM,QAAkB,CAAC;AAEzB,MAAI,WAAW,eAAe,QAAW;AACvC,UAAM,KAAK,WAAW,WAAW,UAAU,GAAG;AAAA,EAChD;AAEA,MAAI,WAAW,gBAAgB,QAAW;AACxC,UAAM,KAAK,YAAY,WAAW,WAAW,GAAG;AAAA,EAClD;AAEA,MAAI,WAAW,oBAAoB,QAAW;AAC5C,QAAI,WAAW,eAAe;AAE5B,YAAM,KAAK,cAAc,KAAK,IAAI,WAAW,eAAe,CAAC,GAAG;AAAA,IAClE,WAAW,WAAW,oBAAoB,GAAG;AAC3C,YAAM,KAAK,gBAAgB,WAAW,eAAe,GAAG;AAAA,IAC1D;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,UAAU,MAAM,KAAK,GAAG,CAAC;AAClC;AASA,SAAS,mBAAmB,OAA6C;AACvE,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,SAAS,QAAW;AAC5B,UAAM,KAAK,kBAAkB,MAAM,IAAI,KAAK;AAAA,EAC9C;AAEA,MAAI,MAAM,UAAU,QAAW;AAC7B,UAAM,KAAK,mBAAmB,MAAM,KAAK,KAAK;AAAA,EAChD;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,YAAY,MAAM,KAAK,EAAE,CAAC;AACnC;AASA,SAAS,yBAAyB,OAA6C;AAC7E,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,UAAU,QAAW;AAC7B,UAAM,KAAK,QAAQ,MAAM,KAAK,GAAG;AAAA,EACnC;AAEA,MAAI,MAAM,WAAW,QAAW;AAC9B,UAAM,KAAK,QAAQ,MAAM,MAAM,GAAG;AAAA,EACpC;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,KAAK,cAAc,MAAM,OAAO,GAAG;AAAA,EAC3C;AAEA,MAAI,MAAM,SAAS;AACjB,UAAM,KAAK,cAAc,MAAM,OAAO,GAAG;AAAA,EAC3C;AAEA,MAAI,MAAM,MAAM,QAAW;AACzB,UAAM,KAAK,QAAQ,MAAM,CAAC,GAAG;AAAA,EAC/B;AAEA,MAAI,MAAM,MAAM,QAAW;AACzB,UAAM,KAAK,QAAQ,MAAM,CAAC,GAAG;AAAA,EAC/B;AAEA,MAAI,MAAM,QAAQ;AAChB,UAAM,KAAK,aAAa,MAAM,MAAM,GAAG;AAAA,EACzC;AAEA,MAAI,MAAM,QAAQ;AAChB,UAAM,KAAK,aAAa,MAAM,MAAM,GAAG;AAAA,EACzC;AAEA,MAAI,MAAM,MAAM;AACd,UAAM,KAAK,WAAW,MAAM,IAAI,GAAG;AAAA,EACrC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,cAAc,MAAM,KAAK,GAAG,CAAC;AACtC;AASO,SAAS,6BAA6B,YAAqD;AAChG,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAkB,CAAC;AAGzB,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,oBAAoBD,WAAU,WAAW,OAAO,CAAC,KAAK;AAAA,EACnE;AAGA,MAAI,WAAW,UAAU;AACvB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAEA,MAAI,WAAW,WAAW;AACxB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,MAAI,WAAW,iBAAiB;AAC9B,UAAM,KAAK,sBAAsB;AAAA,EACnC;AAGA,QAAM,WAAW,yBAAyB,WAAW,KAAK;AAC1D,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,MAAI,WAAW,iBAAiB,OAAO;AACrC,UAAM,KAAK,6BAA6B;AAAA,EAC1C,WAAW,WAAW,iBAAiB,MAAM;AAC3C,UAAM,KAAK,mBAAmB;AAAA,EAChC;AAGA,QAAM,WAAW,mBAAmB,WAAW,KAAK;AACpD,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,QAAM,aAAa,0BAA0B,WAAW,OAAO;AAC/D,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,aAAaC,kBAAiB,WAAW,OAAO;AACtD,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,UAAU,kBAAkB,WAAW,IAAI;AACjD,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAAA,EACpB;AAGA,MAAI,WAAW,qBAAqB;AAClC,UAAM,KAAK,0BAA0B;AAAA,EACvC;AAGA,MAAI,WAAW,qBAAqB;AAClC,UAAM,KAAK,0BAA0B;AAAA,EACvC;AAGA,QAAM,aAAa,iBAAiB,UAAU;AAC9C,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,SAAS,qBAAqB,UAAU;AAC9C,MAAI,QAAQ;AACV,UAAM,KAAK,MAAM;AAAA,EACnB;AAGA,MAAI,WAAW,MAAM;AACnB,UAAM,KAAK,WAAW;AAAA,EACxB;AAGA,MAAI,WAAW,WAAW;AACxB,UAAM,KAAK,gBAAgB,WAAW,SAAS,KAAK;AAAA,EACtD;AAGA,MAAI,WAAW,iBAAiB,QAAW;AACzC,UAAM,KAAK,wBAAwB,WAAW,YAAY,KAAK;AAAA,EACjE;AAGA,MAAI,WAAW,eAAe;AAC5B,UAAM,SAAS,wBAAwB,WAAW,aAAa;AAC/D,QAAI,QAAQ;AACV,YAAM,KAAK,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,UAAU,MAAM,KAAK,EAAE,CAAC;AACjC;AASA,SAAS,mBAAmB,WAA8B;AACxD,QAAM,QAAkB,CAAC;AAEzB,MAAI,UAAU,KAAK;AACjB,UAAM,KAAK,SAAS,UAAU,GAAG,GAAG;AAAA,EACtC;AAEA,MAAI,UAAU,QAAQ;AACpB,UAAM,KAAK,aAAaD,WAAU,UAAU,MAAM,CAAC,GAAG;AAAA,EACxD;AAEA,MAAI,UAAU,SAAS;AACrB,UAAM,KAAK,cAAcA,WAAU,UAAU,OAAO,CAAC,GAAG;AAAA,EAC1D;AAEA,MAAI,UAAU,QAAQ;AACpB,UAAM,KAAK,eAAeA,WAAU,UAAU,MAAM,CAAC,GAAG;AAAA,EAC1D;AAEA,MAAI,UAAU,YAAY,OAAO;AAC/B,UAAM,KAAK,eAAe;AAAA,EAC5B;AAEA,MAAI,UAAU,aAAa;AACzB,UAAM,KAAK,kBAAkBA,WAAU,UAAU,WAAW,CAAC,GAAG;AAAA,EAClE;AAGA,QAAM,cAAc,UAAU,SAC3B,IAAI,CAAC,UAAU;AACd,QAAI,MAAM,SAAS,OAAO;AACxB,aAAO,aAAa,KAAK;AAAA,IAC3B,WAAW,MAAM,SAAS,iBAAiB;AACzC,aAAO,uBAAuB,KAAK;AAAA,IACrC,WAAW,MAAM,SAAS,eAAe;AACvC,aAAO,qBAAqB,KAAK;AAAA,IACnC;AACA,WAAO;AAAA,EACT,CAAC,EACA,KAAK,EAAE;AAEV,QAAM,WAAW,MAAM,SAAS,IAAI,MAAM,MAAM,KAAK,GAAG,IAAI;AAC5D,SAAO,eAAe,QAAQ,IAAI,WAAW;AAC/C;AAKA,SAAS,uBAAuB,UAAiC;AAC/D,QAAM,QAAkB,CAAC,SAAS,SAAS,EAAE,KAAK,WAAWA,WAAU,SAAS,IAAI,CAAC,GAAG;AAExF,MAAI,SAAS,aAAa,QAAW;AACnC,UAAM,KAAK,eAAe,SAAS,QAAQ,GAAG;AAAA,EAChD;AAEA,MAAI,SAAS,YAAY,QAAW;AAClC,UAAM,KAAK,cAAc,SAAS,OAAO,GAAG;AAAA,EAC9C;AAEA,SAAO,oBAAoB,MAAM,KAAK,GAAG,CAAC;AAC5C;AAKA,SAAS,qBAAqB,UAA+B;AAC3D,SAAO,wBAAwB,SAAS,EAAE;AAC5C;AAKA,SAAS,qBAAqB,OAA4B;AACxD,QAAM,QAAkB,CAAC,YAAYA,WAAU,MAAM,WAAW,CAAC,GAAG;AAEpE,MAAI,MAAM,SAAS;AACjB,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAEA,MAAI,MAAM,OAAO;AACf,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,QAAM,aAAa,MAAM,QACtB,IAAI,CAAC,SAAS;AACb,QAAI,KAAK,SAAS,OAAO;AACvB,aAAO,aAAa,IAAI;AAAA,IAC1B,WAAW,KAAK,SAAS,aAAa;AACpC,aAAO,mBAAmB,IAAI;AAAA,IAChC;AACA,WAAO;AAAA,EACT,CAAC,EACA,KAAK,EAAE;AAEV,SAAO,gBAAgB,MAAM,KAAK,GAAG,CAAC,IAAI,UAAU;AACtD;AAOA,SAAS,sBAAsB,OAA6B;AAC1D,QAAM,QAAkB,CAAC;AAGzB,QAAM,aAAuB,CAAC,uBAAuB;AACrD,MAAI,MAAM,SAAS;AACjB,eAAW,KAAK,kBAAkB;AAAA,EACpC;AACA,MAAI,MAAM,OAAO;AACf,eAAW,KAAK,gBAAgB;AAAA,EAClC;AACA,QAAM,KAAK,mBAAmB,WAAW,KAAK,GAAG,CAAC,UAAU;AAG5D,MAAI,MAAM,UAAU,SAAS,GAAG;AAC9B,UAAM,KAAK,GAAG,MAAM,UAAU,IAAI,CAAC,QAAQ,aAAa,GAAG,CAAC,CAAC;AAAA,EAC/D,OAAO;AAEL,UAAM,gBACJ,MAAM,YAAY,WAAW,GAAG,KAChC,MAAM,YAAY,SAAS,GAAG,KAC9B,MAAM,YAAY,SAAS,IAAI;AACjC,UAAM,YAAY,gBAAgB,0BAA0B;AAC5D,UAAM,KAAK,oBAAoB,SAAS,IAAIA,WAAU,MAAM,WAAW,CAAC,sBAAsB;AAAA,EAChG;AAGA,QAAM,KAAK,kDAAkD;AAG7D,QAAM,KAAK,GAAG,MAAM,YAAY,IAAI,CAAC,QAAQ,aAAa,GAAG,CAAC,CAAC;AAG/D,QAAM,KAAK,6CAA6C;AAExD,SAAO,MAAM,KAAK,EAAE;AACtB;AAKA,SAAS,0BAA0B,SAAmC;AACpE,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,aAAO,aAAa,OAAO;AAAA,IAC7B,KAAK;AACH,aAAO,mBAAmB,OAAO;AAAA,IACnC,KAAK;AACH,aAAO,uBAAuB,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,qBAAqB,OAAO;AAAA,IACrC,KAAK;AACH,aAAO,qBAAqB,OAAO;AAAA,IACrC,KAAK;AACH,aAAO,sBAAsB,OAAO;AAAA,IACtC;AACE,aAAO;AAAA,EACX;AACF;AAYO,SAAS,mBAAmB,WAA8B;AAC/D,QAAM,QAAkB,CAAC;AAGzB,QAAM,QAAkB,CAAC;AACzB,MAAI,UAAU,QAAQ;AACpB,UAAM,KAAK,eAAe,UAAU,MAAM,GAAG;AAAA,EAC/C;AACA,MAAI,UAAU,QAAQ;AACpB,UAAM,KAAK,eAAe,UAAU,MAAM,GAAG;AAAA,EAC/C;AACA,QAAM,WAAW,MAAM,SAAS,IAAI,MAAM,MAAM,KAAK,GAAG,IAAI;AAG5D,QAAM,SAAS,6BAA6B,UAAU,UAAU;AAChE,MAAI,QAAQ;AACV,UAAM,KAAK,MAAM;AAAA,EACnB;AAGA,aAAW,WAAW,UAAU,SAAS;AACvC,UAAM,aAAa,0BAA0B,OAAO;AACpD,QAAI,YAAY;AACd,YAAM,KAAK,UAAU;AAAA,IACvB;AAAA,EACF;AAEA,SAAO,OAAO,QAAQ,IAAI,MAAM,KAAK,EAAE,CAAC;AAC1C;;;ACvoBA,SAASE,WAAU,MAAsB;AACvC,SAAO,KACJ,QAAQ,MAAM,OAAO,EACrB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,MAAM,EACpB,QAAQ,MAAM,QAAQ,EACtB,QAAQ,MAAM,QAAQ;AAC3B;AASA,SAAS,qBACP,aACA,aACQ;AACR,MAAI,CAAC,YAAa,QAAO;AAEzB,QAAM,QAAkB,CAAC,QAAQ,YAAY,KAAK,KAAK,WAAW,YAAY,IAAI,GAAG;AAErF,SAAO,MAAM,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC;AAC7C;AASA,SAASC,iBAAgB,QAAgC,aAA6B;AACpF,MAAI,CAAC,UAAU,OAAO,UAAU,UAAU,OAAO,UAAU,OAAO;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC,UAAU,OAAO,KAAK,GAAG;AAElD,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,KAAK,SAAS,OAAO,IAAI,GAAG;AAAA,EACpC;AAEA,MAAI,OAAO,UAAU,QAAW;AAC9B,UAAM,KAAK,YAAY,OAAO,KAAK,GAAG;AAAA,EACxC;AAGA,MAAI,OAAO,OAAO;AAChB,QAAI,OAAO,MAAM,MAAM;AACrB,YAAM,KAAK,gBAAgB;AAAA,IAC7B,WAAW,OAAO,MAAM,KAAK;AAC3B,YAAM,KAAK,YAAY,OAAO,MAAM,GAAG,GAAG;AAAA,IAC5C;AAEA,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,KAAK,iBAAiB,OAAO,MAAM,UAAU,GAAG;AAAA,IACxD;AAEA,QAAI,OAAO,MAAM,WAAW;AAC1B,YAAM,KAAK,gBAAgB,OAAO,MAAM,SAAS,GAAG;AAAA,IACtD;AAEA,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,KAAK,iBAAiB,OAAO,MAAM,UAAU,GAAG;AAAA,IACxD;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ;AACjB,UAAM,KAAK,iBAAiB;AAAA,EAC9B;AAEA,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,SAAO,MAAM,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC;AAC7C;AAKA,SAAS,sBAAsB,SAAmC,aAA6B;AAC7F,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAkB,CAAC;AAEzB,MAAI,QAAQ,KAAK;AACf,UAAM,SAASA,iBAAgB,QAAQ,KAAK,KAAK;AACjD,QAAI,OAAQ,OAAM,KAAK,MAAM;AAAA,EAC/B;AAEA,MAAI,QAAQ,MAAM;AAChB,UAAM,UAAUA,iBAAgB,QAAQ,MAAM,MAAM;AACpD,QAAI,QAAS,OAAM,KAAK,OAAO;AAAA,EACjC;AAEA,MAAI,QAAQ,QAAQ;AAClB,UAAM,YAAYA,iBAAgB,QAAQ,QAAQ,QAAQ;AAC1D,QAAI,UAAW,OAAM,KAAK,SAAS;AAAA,EACrC;AAEA,MAAI,QAAQ,OAAO;AACjB,UAAM,WAAWA,iBAAgB,QAAQ,OAAO,OAAO;AACvD,QAAI,SAAU,OAAM,KAAK,QAAQ;AAAA,EACnC;AAEA,MAAI,QAAQ,SAAS;AACnB,UAAM,aAAaA,iBAAgB,QAAQ,SAAS,SAAS;AAC7D,QAAI,WAAY,OAAM,KAAK,UAAU;AAAA,EACvC;AAEA,MAAI,QAAQ,SAAS;AACnB,UAAM,aAAaA,iBAAgB,QAAQ,SAAS,SAAS;AAC7D,QAAI,WAAY,OAAM,KAAK,UAAU;AAAA,EACvC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,MAAM,WAAW,IAAI,MAAM,KAAK,EAAE,CAAC,OAAO,WAAW;AAC9D;AASA,SAAS,qBAAqB,SAAkC,aAA6B;AAC3F,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAkB,CAAC;AAEzB,MAAI,QAAQ,KAAK;AACf,UAAM,KAAK,qBAAqB,QAAQ,KAAK,KAAK,CAAC;AAAA,EACrD;AAEA,MAAI,QAAQ,MAAM;AAChB,UAAM,KAAK,qBAAqB,QAAQ,MAAM,MAAM,CAAC;AAAA,EACvD;AAEA,MAAI,QAAQ,QAAQ;AAClB,UAAM,KAAK,qBAAqB,QAAQ,QAAQ,QAAQ,CAAC;AAAA,EAC3D;AAEA,MAAI,QAAQ,OAAO;AACjB,UAAM,KAAK,qBAAqB,QAAQ,OAAO,OAAO,CAAC;AAAA,EACzD;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,MAAM,WAAW,IAAI,MAAM,KAAK,EAAE,CAAC,OAAO,WAAW;AAC9D;AASA,SAASC,kBAAiB,SAAgD;AACxE,MAAI,CAAC,QAAS,QAAO;AAErB,QAAM,QAAkB,CAAC;AAGzB,MAAI,QAAQ,SAAS;AACnB,UAAM,KAAK,UAAU,QAAQ,OAAO,GAAG;AAAA,EACzC,OAAO;AACL,UAAM,KAAK,eAAe;AAAA,EAC5B;AAGA,MAAI,QAAQ,OAAO,KAAK;AACtB,UAAM,KAAK,YAAY,QAAQ,MAAM,GAAG,GAAG;AAAA,EAC7C,WAAW,QAAQ,OAAO,MAAM;AAC9B,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,QAAQ,MAAM,KAAK;AACrB,UAAM,KAAK,WAAW,QAAQ,KAAK,GAAG,GAAG;AAAA,EAC3C,WAAW,QAAQ,MAAM,MAAM;AAC7B,UAAM,KAAK,eAAe;AAAA,EAC5B;AAGA,MAAI,QAAQ,MAAM,YAAY;AAC5B,UAAM,KAAK,gBAAgB,QAAQ,KAAK,UAAU,GAAG;AAAA,EACvD;AAEA,MAAI,QAAQ,MAAM,WAAW;AAC3B,UAAM,KAAK,oBAAoB,QAAQ,KAAK,SAAS,GAAG;AAAA,EAC1D;AAEA,MAAI,QAAQ,MAAM,YAAY;AAC5B,UAAM,KAAK,qBAAqB,QAAQ,KAAK,UAAU,GAAG;AAAA,EAC5D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,UAAU,MAAM,KAAK,GAAG,CAAC;AAClC;AASA,SAAS,mBAAmB,MAAqC;AAC/D,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,QAAkB,CAAC;AAEzB,MAAI,KAAK,UAAU;AACjB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,MAAI,KAAK,SAAS;AAChB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAEA,MAAI,KAAK,aAAa;AACpB,UAAM,KAAK,mBAAmB;AAAA,EAChC;AAEA,MAAI,KAAK,YAAY;AACnB,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAEA,MAAI,KAAK,SAAS;AAChB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAEA,MAAI,KAAK,SAAS;AAChB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,cAAc,MAAM,KAAK,GAAG,CAAC;AACtC;AASA,SAAS,iCAAiC,UAAuD;AAC/F,MAAI,CAAC,SAAU,QAAO;AAEtB,QAAM,QAAkB,CAAC;AAEzB,MAAI,SAAS,YAAY;AACvB,UAAM,KAAK,iBAAiB,SAAS,UAAU,GAAG;AAAA,EACpD;AAEA,MAAI,SAAS,YAAY;AACvB,UAAM,KAAK,iBAAiB,SAAS,UAAU,GAAG;AAAA,EACpD;AAEA,MAAI,SAAS,UAAU,QAAW;AAChC,UAAM,KAAK,YAAY,SAAS,KAAK,GAAG;AAAA,EAC1C;AAEA,MAAI,SAAS,WAAW;AACtB,UAAM,KAAK,gBAAgB,SAAS,SAAS,GAAG;AAAA,EAClD;AAEA,MAAI,SAAS,UAAU,QAAW;AAChC,UAAM,KAAK,YAAY,SAAS,KAAK,GAAG;AAAA,EAC1C;AAEA,MAAI,SAAS,WAAW;AACtB,UAAM,KAAK,gBAAgB,SAAS,SAAS,GAAG;AAAA,EAClD;AAEA,MAAI,SAAS,gBAAgB,QAAW;AACtC,UAAM,KAAK,kBAAkB,SAAS,WAAW,GAAG;AAAA,EACtD;AAEA,MAAI,SAAS,mBAAmB,QAAW;AACzC,UAAM,KAAK,qBAAqB,SAAS,cAAc,GAAG;AAAA,EAC5D;AAEA,MAAI,SAAS,iBAAiB,QAAW;AACvC,UAAM,KAAK,mBAAmB,SAAS,YAAY,GAAG;AAAA,EACxD;AAEA,MAAI,SAAS,kBAAkB,QAAW;AACxC,UAAM,KAAK,oBAAoB,SAAS,aAAa,GAAG;AAAA,EAC1D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,aAAa,MAAM,KAAK,GAAG,CAAC;AACrC;AASO,SAAS,yBAAyB,YAAiD;AACxF,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAkB,CAAC;AAGzB,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,sBAAsBF,WAAU,WAAW,OAAO,CAAC,KAAK;AAAA,EACrE;AAGA,QAAM,cAAc,iCAAiC,WAAW,QAAQ;AACxE,MAAI,aAAa;AACf,UAAM,KAAK,WAAW;AAAA,EACxB;AAGA,MAAI,WAAW,MAAM;AACnB,UAAM,KAAK,iBAAiB;AAAA,EAC9B;AAGA,QAAM,WAAW,qBAAqB,WAAW,OAAO,MAAM;AAC9D,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,MAAI,WAAW,eAAe;AAC5B,UAAM,KAAK,gBAAgB,WAAW,aAAa,KAAK;AAAA,EAC1D;AAGA,QAAM,iBAAiB,qBAAqB,WAAW,aAAa,gBAAgB;AACpF,MAAI,gBAAgB;AAClB,UAAM,KAAK,cAAc;AAAA,EAC3B;AAGA,QAAM,YAAY,qBAAqB,WAAW,QAAQ,QAAQ;AAClE,MAAI,WAAW;AACb,UAAM,KAAK,SAAS;AAAA,EACtB;AAGA,QAAM,aAAa,sBAAsB,WAAW,SAAS,YAAY;AACzE,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,aAAa,qBAAqB,WAAW,aAAa,YAAY;AAC5E,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,wBAAwB,WAAW,MAAM,KAAK;AAAA,EAC3D;AAGA,QAAM,aAAaE,kBAAiB,WAAW,OAAO;AACtD,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,UAAU,mBAAmB,WAAW,IAAI;AAClD,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAAA,EACpB;AAGA,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,wBAAwB,WAAW,OAAO,KAAK;AAAA,EAC5D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,YAAY,MAAM,KAAK,EAAE,CAAC;AACnC;AASO,SAAS,4BAA4B,YAAoD;AAC9F,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAkB,CAAC;AAGzB,MAAI,WAAW,WAAW;AACxB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,QAAkB,CAAC,UAAU,WAAW,OAAO,KAAK,GAAG;AAE7D,QAAI,WAAW,YAAY;AACzB,YAAM,KAAK,YAAY,WAAW,UAAU,GAAG;AAAA,IACjD;AAEA,UAAM,KAAK,eAAe,MAAM,KAAK,GAAG,CAAC,IAAI;AAAA,EAC/C;AAGA,MAAI,WAAW,eAAe;AAC5B,UAAM,KAAK,gBAAgB,WAAW,aAAa,KAAK;AAAA,EAC1D;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,WAAW,MAAM,KAAK,EAAE,CAAC;AAClC;AASA,SAAS,gCAAgC,OAAmD;AAC1F,MAAI,CAAC,MAAO,QAAO;AAGnB,QAAM,OAAO;AAAA,IACX,MAAM,WAAW,MAAM;AAAA,IACvB,MAAM,UAAU,MAAM;AAAA,IACtB,MAAM,cAAc,MAAM;AAAA,IAC1B,MAAM,aAAa,MAAM;AAAA,IACzB,MAAM,WAAW,MAAM;AAAA,IACvB,MAAM,YAAY,MAAM;AAAA,IACxB,MAAM,WAAW,MAAM;AAAA,IACvB,MAAM,YAAY,MAAM;AAAA,IACxB,MAAM,SAAS,MAAM;AAAA,IACrB,MAAM,SAAS,MAAM;AAAA,IACrB,MAAM,SAAS,MAAM;AAAA,IACrB,MAAM,SAAS,MAAM;AAAA,EACvB;AAEA,QAAM,MAAM,KAAK,KAAK,EAAE;AAGxB,MAAI,QAAQ,eAAgB,QAAO;AAEnC,SAAO,sBAAsB,GAAG;AAClC;AASO,SAAS,6BAA6B,YAAqD;AAChG,MAAI,CAAC,WAAY,QAAO;AAExB,QAAM,QAAkB,CAAC;AAGzB,QAAM,cAAc,gCAAgC,WAAW,iBAAiB;AAChF,MAAI,aAAa;AACf,UAAM,KAAK,WAAW;AAAA,EACxB;AAGA,QAAM,WAAW,qBAAqB,WAAW,OAAO,KAAK;AAC7D,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,MAAI,WAAW,YAAY,WAAW,WAAW,GAAG;AAClD,UAAM,KAAK,sBAAsB,WAAW,QAAQ,KAAK;AAAA,EAC3D;AAGA,MAAI,WAAW,QAAQ;AACrB,QAAI,WAAW,WAAW,WAAW;AACnC,YAAM,KAAK,6BAA6B;AAAA,IAC1C,OAAO;AAEL,YAAM,KAAK,aAAa;AAAA,IAC1B;AAAA,EACF;AAGA,QAAM,aAAa,sBAAsB,WAAW,SAAS,WAAW;AACxE,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,QAAM,aAAaA,kBAAiB,WAAW,OAAO;AACtD,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,MAAI,WAAW,QAAQ;AACrB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAGA,QAAM,aAAa,qBAAqB,WAAW,SAAS,OAAO;AACnE,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,MAAI,WAAW,eAAe;AAC5B,UAAM,KAAK,2BAA2B,WAAW,aAAa,KAAK;AAAA,EACrE;AAGA,MAAI,WAAW,SAAS;AACtB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAGA,MAAI,WAAW,eAAe;AAC5B,UAAM,KAAK,oBAAoB,WAAW,aAAa,KAAK;AAAA,EAC9D;AAGA,MAAI,WAAW,UAAU;AACvB,UAAM,KAAK,eAAe;AAAA,EAC5B;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,WAAW,MAAM,KAAK,EAAE,CAAC;AAClC;AASA,SAAS,mBAAmB,cAA4C;AACtE,MAAI,CAAC,gBAAgB,aAAa,WAAW,EAAG,QAAO;AAEvD,QAAM,OAAO,aAAa,IAAI,CAAC,MAAM,mBAAmB,CAAC,KAAK;AAE9D,SAAO,cAAc,KAAK,KAAK,EAAE,CAAC;AACpC;AASA,SAAS,qBAAqB,SAAwC;AACpE,QAAM,QAAkB,CAAC;AAEzB,aAAW,QAAQ,SAAS;AAC1B,QAAI,KAAK,SAAS,aAAa;AAC7B,YAAM,KAAK,mBAAmB,IAAI,CAAC;AAAA,IACrC,WAAW,KAAK,SAAS,SAAS;AAChC,YAAM,KAAK,eAAe,IAAI,CAAC;AAAA,IACjC;AAAA,EACF;AAGA,MAAI,MAAM,WAAW,GAAG;AACtB,UAAM,KAAK,QAAQ;AAAA,EACrB;AAEA,SAAO,MAAM,KAAK,EAAE;AACtB;AASO,SAAS,mBAAmB,MAAyB;AAC1D,QAAM,QAAkB,CAAC;AAGzB,QAAM,UAAU,6BAA6B,KAAK,UAAU;AAC5D,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAAA,EACpB;AAGA,QAAM,KAAK,qBAAqB,KAAK,OAAO,CAAC;AAE7C,SAAO,SAAS,MAAM,KAAK,EAAE,CAAC;AAChC;AASO,SAAS,kBAAkB,KAAuB;AACvD,QAAM,QAAkB,CAAC;AAGzB,QAAM,UAAU,4BAA4B,IAAI,UAAU;AAC1D,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAAA,EACpB;AAGA,aAAW,QAAQ,IAAI,OAAO;AAC5B,UAAM,KAAK,mBAAmB,IAAI,CAAC;AAAA,EACrC;AAEA,SAAO,SAAS,MAAM,KAAK,EAAE,CAAC;AAChC;AAYO,SAAS,eAAe,OAAsB;AACnD,QAAM,QAAkB,CAAC;AAGzB,QAAM,WAAW,yBAAyB,MAAM,UAAU;AAC1D,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,QAAM,aAAa,mBAAmB,MAAM,YAAY;AACxD,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,aAAW,OAAO,MAAM,MAAM;AAC5B,UAAM,KAAK,kBAAkB,GAAG,CAAC;AAAA,EACnC;AAEA,SAAO,UAAU,MAAM,KAAK,EAAE,CAAC;AACjC;;;ACnrBA,IAAM,aAAa;AAAA,EACjB,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,MAAM;AAAA,EACN,GAAG;AAAA,EACH,KAAK;AAAA,EACL,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,MAAM;AAAA,EACN,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,GAAG;AAAA,EACH,KAAK;AAAA,EACL,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,UAAU;AAAA,EACV,OAAO;AAAA,EACP,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AAAA,EACL,KAAK;AACP;AAKA,SAAS,6BAAqC;AAE5C,QAAM,oBAAoB;AAAA,IACxB,KAAK,WAAW;AAAA,IAChB,IAAI,WAAW;AAAA,IACf,GAAG,WAAW;AAAA,IACd,GAAG,WAAW;AAAA,IACd,GAAG,WAAW;AAAA,IACd,GAAG,WAAW;AAAA,IACd,MAAM,WAAW;AAAA,IACjB,IAAI,WAAW;AAAA,IACf,KAAK,WAAW;AAAA,IAChB,GAAG,WAAW;AAAA,IACd,KAAK,WAAW;AAAA,IAChB,KAAK,WAAW;AAAA,IAChB,KAAK,WAAW;AAAA,IAChB,KAAK,WAAW;AAAA,EAClB;AAEA,SAAO,OAAO,QAAQ,iBAAiB,EACpC,IAAI,CAAC,CAAC,QAAQ,GAAG,MAAM,SAAS,MAAM,KAAK,GAAG,GAAG,EACjD,KAAK,GAAG;AACb;AAaA,SAASC,iBAAgB,QAAgC,aAA6B;AACpF,MAAI,CAAC,UAAU,OAAO,UAAU,UAAU,OAAO,UAAU,OAAO;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,QAAkB,CAAC,UAAU,OAAO,KAAK,GAAG;AAElD,MAAI,OAAO,SAAS,QAAW;AAC7B,UAAM,KAAK,SAAS,OAAO,IAAI,GAAG;AAAA,EACpC;AAEA,MAAI,OAAO,UAAU,QAAW;AAC9B,UAAM,KAAK,YAAY,OAAO,KAAK,GAAG;AAAA,EACxC;AAEA,MAAI,OAAO,OAAO;AAChB,QAAI,OAAO,MAAM,MAAM;AACrB,YAAM,KAAK,gBAAgB;AAAA,IAC7B,WAAW,OAAO,MAAM,KAAK;AAC3B,YAAM,KAAK,YAAY,OAAO,MAAM,GAAG,GAAG;AAAA,IAC5C;AAEA,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,KAAK,iBAAiB,OAAO,MAAM,UAAU,GAAG;AAAA,IACxD;AAEA,QAAI,OAAO,MAAM,WAAW;AAC1B,YAAM,KAAK,gBAAgB,OAAO,MAAM,SAAS,GAAG;AAAA,IACtD;AAEA,QAAI,OAAO,MAAM,YAAY;AAC3B,YAAM,KAAK,iBAAiB,OAAO,MAAM,UAAU,GAAG;AAAA,IACxD;AAAA,EACF;AAEA,MAAI,OAAO,QAAQ;AACjB,UAAM,KAAK,iBAAiB;AAAA,EAC9B;AAEA,MAAI,OAAO,OAAO;AAChB,UAAM,KAAK,gBAAgB;AAAA,EAC7B;AAEA,SAAO,MAAM,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC;AAC7C;AASA,SAAS,yBAAyB,KAA8B;AAC9D,QAAM,QAAkB,CAAC,WAAW,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG;AAEpE,SAAO,sBAAsB,MAAM,KAAK,GAAG,CAAC;AAC9C;AAKA,SAAS,yBAAyB,KAA8B;AAC9D,QAAM,QAAkB,CAAC,WAAW,IAAI,IAAI,KAAK,SAAS,IAAI,GAAG,GAAG;AAEpE,SAAO,sBAAsB,MAAM,KAAK,GAAG,CAAC;AAC9C;AAKA,SAAS,4BAA4B,OAA+C;AAClF,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,UAAU;AAClB,UAAM,KAAK,iBAAiB,MAAM,QAAQ,KAAK;AAAA,EACjD;AAEA,MAAI,MAAM,QAAQ;AAChB,UAAM,KAAK,oBAAoB,MAAM,MAAM,KAAK;AAAA,EAClD;AAEA,MAAI,MAAM,aAAa,QAAW;AAChC,UAAM,KAAK,sBAAsB,MAAM,QAAQ,KAAK;AAAA,EACtD;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,KAAK,wBAAwB,MAAM,UAAU,KAAK;AAAA,EAC1D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,iBAAiB,MAAM,KAAK,EAAE,CAAC;AACxC;AAKA,SAAS,2BAA2B,OAA8C;AAChF,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,UAAU;AAClB,UAAM,KAAK,iBAAiB,MAAM,QAAQ,KAAK;AAAA,EACjD;AAEA,MAAI,MAAM,QAAQ;AAChB,UAAM,KAAK,oBAAoB,MAAM,MAAM,KAAK;AAAA,EAClD;AAEA,MAAI,MAAM,aAAa,QAAW;AAChC,UAAM,KAAK,sBAAsB,MAAM,QAAQ,KAAK;AAAA,EACtD;AAEA,MAAI,MAAM,YAAY;AACpB,UAAM,KAAK,wBAAwB,MAAM,UAAU,KAAK;AAAA,EAC1D;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,gBAAgB,MAAM,KAAK,EAAE,CAAC;AACvC;AAKA,SAAS,kBAAkB,OAAkC;AAC3D,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,cAAc,QAAW;AACjC,UAAM,KAAK,QAAQ,MAAM,SAAS,GAAG;AAAA,EACvC;AAEA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,KAAK,QAAQ,MAAM,UAAU,GAAG;AAAA,EACxC;AAEA,MAAI,MAAM,gBAAgB,aAAa;AACrC,UAAM,KAAK,sBAAsB;AAAA,EACnC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,WAAW,MAAM,KAAK,GAAG,CAAC;AACnC;AAKA,SAAS,qBAAqB,OAAkC;AAC9D,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,cAAc,QAAW;AACjC,UAAM,KAAK,UAAU,MAAM,SAAS,GAAG;AAAA,EACzC;AAEA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,KAAK,YAAY,MAAM,WAAW,GAAG;AAAA,EAC7C;AAEA,MAAI,MAAM,iBAAiB,QAAW;AACpC,UAAM,KAAK,aAAa,MAAM,YAAY,GAAG;AAAA,EAC/C;AAEA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,KAAK,WAAW,MAAM,UAAU,GAAG;AAAA,EAC3C;AAEA,MAAI,MAAM,mBAAmB,QAAW;AACtC,UAAM,KAAK,aAAa,MAAM,cAAc,GAAG;AAAA,EACjD;AAEA,MAAI,MAAM,mBAAmB,QAAW;AACtC,UAAM,KAAK,aAAa,MAAM,cAAc,GAAG;AAAA,EACjD;AAEA,MAAI,MAAM,WAAW,QAAW;AAC9B,UAAM,KAAK,aAAa,MAAM,MAAM,GAAG;AAAA,EACzC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,YAAY,MAAM,KAAK,GAAG,CAAC;AACpC;AAKA,SAAS,iBAAiB,OAAkC;AAC1D,MAAI,CAAC,MAAM,eAAe,CAAC,MAAM,SAAS,OAAQ,QAAO;AAEzD,QAAM,QAAkB,CAAC;AAEzB,MAAI,MAAM,gBAAgB,UAAa,MAAM,cAAc,GAAG;AAC5D,UAAM,KAAK,UAAU,MAAM,WAAW,GAAG;AAAA,EAC3C;AAEA,MAAI,MAAM,gBAAgB,QAAW;AACnC,UAAM,KAAK,YAAY,MAAM,WAAW,GAAG;AAAA,EAC7C;AAEA,MAAI,MAAM,eAAe,QAAW;AAClC,UAAM,KAAK,iBAAiB,MAAM,aAAa,MAAM,GAAG,GAAG;AAAA,EAC7D;AAEA,MAAI,MAAM,WAAW;AACnB,UAAM,KAAK,WAAW;AAAA,EACxB;AAGA,MAAI,cAAc;AAClB,MAAI,MAAM,WAAW,MAAM,QAAQ,SAAS,GAAG;AAC7C,kBAAc,MAAM,QACjB,IAAI,CAAC,QAAQ;AACZ,YAAM,WAAqB,CAAC;AAC5B,UAAI,IAAI,UAAU,QAAW;AAC3B,iBAAS,KAAK,QAAQ,IAAI,KAAK,GAAG;AAAA,MACpC;AACA,UAAI,IAAI,UAAU,QAAW;AAC3B,iBAAS,KAAK,YAAY,IAAI,KAAK,GAAG;AAAA,MACxC;AACA,aAAO,UAAU,SAAS,KAAK,GAAG,CAAC;AAAA,IACrC,CAAC,EACA,KAAK,EAAE;AAAA,EACZ;AAEA,MAAI,MAAM,WAAW,KAAK,CAAC,YAAa,QAAO;AAE/C,QAAM,WAAW,MAAM,SAAS,IAAI,MAAM,MAAM,KAAK,GAAG,IAAI;AAC5D,SAAO,UAAU,QAAQ,IAAI,WAAW;AAC1C;AAKA,SAAS,qBAAqB,OAAkC;AAC9D,MAAI,CAAC,MAAM,YAAa,QAAO;AAE/B,QAAM,KAAK,MAAM;AACjB,QAAM,QAAkB,CAAC;AAEzB,MAAI,GAAG,YAAY,QAAW;AAC5B,UAAM,KAAK,cAAc,GAAG,OAAO,GAAG;AAAA,EACxC;AAEA,MAAI,GAAG,UAAU,QAAW;AAC1B,UAAM,KAAK,YAAY,GAAG,KAAK,GAAG;AAAA,EACpC;AAEA,MAAI,GAAG,aAAa,QAAW;AAC7B,UAAM,KAAK,eAAe,GAAG,QAAQ,GAAG;AAAA,EAC1C;AAEA,MAAI,GAAG,SAAS;AACd,UAAM,KAAK,cAAc,GAAG,OAAO,GAAG;AAAA,EACxC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,gBAAgB,MAAM,KAAK,GAAG,CAAC;AACxC;AAKA,SAAS,qBAAqB,OAAkC;AAC9D,MAAI,CAAC,MAAM,YAAa,QAAO;AAE/B,QAAM,KAAK,MAAM;AACjB,QAAM,QAAkB,CAAC;AACzB,QAAM,iBAA2B,CAAC;AAElC,MAAI,GAAG,SAAS;AACd,UAAM,KAAK,cAAc,GAAG,OAAO,GAAG;AAAA,EACxC;AAEA,MAAI,GAAG,YAAY;AACjB,UAAM,KAAK,iBAAiB,GAAG,UAAU,GAAG;AAAA,EAC9C;AAEA,MAAI,GAAG,QAAQ;AACb,UAAM,KAAK,aAAa,GAAG,MAAM,GAAG;AAAA,EACtC;AAEA,MAAI,GAAG,KAAK;AACV,UAAM,SAASA,iBAAgB,GAAG,KAAK,KAAK;AAC5C,QAAI,OAAQ,gBAAe,KAAK,MAAM;AAAA,EACxC;AAEA,MAAI,GAAG,MAAM;AACX,UAAM,UAAUA,iBAAgB,GAAG,MAAM,MAAM;AAC/C,QAAI,QAAS,gBAAe,KAAK,OAAO;AAAA,EAC1C;AAEA,MAAI,GAAG,QAAQ;AACb,UAAM,YAAYA,iBAAgB,GAAG,QAAQ,QAAQ;AACrD,QAAI,UAAW,gBAAe,KAAK,SAAS;AAAA,EAC9C;AAEA,MAAI,GAAG,OAAO;AACZ,UAAM,WAAWA,iBAAgB,GAAG,OAAO,OAAO;AAClD,QAAI,SAAU,gBAAe,KAAK,QAAQ;AAAA,EAC5C;AAEA,MAAI,eAAe,WAAW,EAAG,QAAO;AAExC,QAAM,WAAW,MAAM,SAAS,IAAI,MAAM,MAAM,KAAK,GAAG,IAAI;AAC5D,SAAO,eAAe,QAAQ,IAAI,eAAe,KAAK,EAAE,CAAC;AAC3D;AAKA,SAAS,iBAAiB,OAAkC;AAC1D,MAAI,CAAC,MAAM,QAAS,QAAO;AAE3B,QAAM,KAAK,MAAM;AACjB,QAAM,QAAkB,CAAC;AAEzB,MAAI,GAAG,MAAM;AACX,UAAM,KAAK,WAAW,GAAG,IAAI,GAAG;AAAA,EAClC;AAEA,MAAI,GAAG,cAAc,QAAW;AAC9B,UAAM,KAAK,gBAAgB,GAAG,SAAS,GAAG;AAAA,EAC5C;AAEA,MAAI,GAAG,cAAc,QAAW;AAC9B,UAAM,KAAK,gBAAgB,GAAG,SAAS,GAAG;AAAA,EAC5C;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,cAAc,MAAM,KAAK,GAAG,CAAC;AACtC;AAKO,SAAS,2BAA2B,OAA8C;AACvF,MAAI,CAAC,MAAO,QAAO;AAEnB,QAAM,QAAkB,CAAC;AAGzB,MAAI,MAAM,kBAAkB;AAC1B,eAAW,OAAO,MAAM,kBAAkB;AACxC,YAAM,KAAK,yBAAyB,GAAG,CAAC;AAAA,IAC1C;AAAA,EACF;AAGA,MAAI,MAAM,kBAAkB;AAC1B,eAAW,OAAO,MAAM,kBAAkB;AACxC,YAAM,KAAK,yBAAyB,GAAG,CAAC;AAAA,IAC1C;AAAA,EACF;AAGA,QAAM,gBAAgB,4BAA4B,MAAM,UAAU;AAClE,MAAI,eAAe;AACjB,UAAM,KAAK,aAAa;AAAA,EAC1B;AAGA,QAAM,eAAe,2BAA2B,MAAM,SAAS;AAC/D,MAAI,cAAc;AAChB,UAAM,KAAK,YAAY;AAAA,EACzB;AAGA,MAAI,MAAM,cAAc;AACtB,UAAM,KAAK,kBAAkB,MAAM,YAAY,KAAK;AAAA,EACtD;AAGA,QAAM,UAAU,kBAAkB,KAAK;AACvC,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAAA,EACpB;AAGA,QAAM,WAAW,qBAAqB,KAAK;AAC3C,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,MAAI,MAAM,kBAAkB,UAAa,MAAM,kBAAkB,QAAW;AAC1E,UAAM,QAAkB,CAAC;AACzB,QAAI,MAAM,kBAAkB,QAAW;AACrC,YAAM,KAAK,YAAY,MAAM,aAAa,GAAG;AAAA,IAC/C;AACA,QAAI,MAAM,kBAAkB,QAAW;AACrC,YAAM,KAAK,YAAY,MAAM,aAAa,GAAG;AAAA,IAC/C;AACA,UAAM,KAAK,eAAe,MAAM,KAAK,GAAG,CAAC,IAAI;AAAA,EAC/C;AAGA,QAAM,eAAe,qBAAqB,KAAK;AAC/C,MAAI,cAAc;AAChB,UAAM,KAAK,YAAY;AAAA,EACzB;AAGA,QAAM,WAAW,qBAAqB,KAAK;AAC3C,MAAI,UAAU;AACZ,UAAM,KAAK,QAAQ;AAAA,EACrB;AAGA,QAAM,UAAU,iBAAiB,KAAK;AACtC,MAAI,SAAS;AACX,UAAM,KAAK,OAAO;AAAA,EACpB;AAGA,QAAM,aAAa,iBAAiB,KAAK;AACzC,MAAI,YAAY;AACd,UAAM,KAAK,UAAU;AAAA,EACvB;AAGA,MAAI,MAAM,eAAe;AACvB,UAAM,KAAK,oBAAoB,MAAM,aAAa,KAAK;AAAA,EACzD;AAGA,MAAI,MAAM,MAAM;AACd,UAAM,KAAK,WAAW;AAAA,EACxB;AAGA,MAAI,MAAM,SAAS;AACjB,UAAM,KAAK,cAAc;AAAA,EAC3B;AAGA,MAAI,MAAM,mBAAmB;AAC3B,UAAM,KAAK,wBAAwB;AAAA,EACrC;AAEA,MAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,SAAO,aAAa,MAAM,KAAK,EAAE,CAAC;AACpC;AASA,SAAS,sBAAsB,OAA6B;AAC1D,MAAI,MAAM,SAAS,aAAa;AAC9B,WAAO,mBAAmB,KAAK;AAAA,EACjC,WAAW,MAAM,SAAS,SAAS;AACjC,WAAO,eAAe,KAAK;AAAA,EAC7B;AACA,SAAO;AACT;AAKA,SAAS,qBAAqB,SAAiC;AAC7D,SAAO,QAAQ,IAAI,CAAC,UAAU,sBAAsB,KAAK,CAAC,EAAE,KAAK,EAAE;AACrE;AAYO,SAAS,sBAAsB,MAA4B;AAChE,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,qBAAqB,KAAK,OAAO,CAAC;AAG7C,MAAI,KAAK,wBAAwB;AAC/B,UAAM,KAAK,2BAA2B,KAAK,sBAAsB,CAAC;AAAA,EACpE;AAEA,SAAO,MAAM,KAAK,EAAE;AACtB;AAQO,SAAS,kBAAkB,KAAuB;AACvD,QAAM,QAAkB,CAAC;AAGzB,QAAM,KAAK,yDAAyD;AAGpE,QAAM,SAAS,2BAA2B;AAC1C,QAAM,KAAK,eAAe,MAAM,+BAA+B;AAG/D,QAAM,KAAK,UAAU;AACrB,QAAM,KAAK,sBAAsB,IAAI,QAAQ,QAAQ,CAAC;AACtD,QAAM,KAAK,WAAW;AAGtB,QAAM,KAAK,eAAe;AAE1B,SAAO,MAAM,KAAK,EAAE;AACtB;;;AJ5jBA,eAAsB,WAAW,KAAe,UAAyB,CAAC,GAAyB;AAEjG,MAAI,CAAC,IAAI,gBAAgB;AACvB,UAAM,IAAI;AAAA,MACR;AAAA,IAEF;AAAA,EACF;AAEA,QAAM,EAAE,mBAAmB,GAAG,qBAAqB,MAAM,WAAW,IAAI;AAGxE,QAAM,cAAc,MAAM,cAAAC,QAAM,UAAU,IAAI,cAAc;AAG5D,QAAM,SAAS,IAAI,cAAAA,QAAM;AAGzB,aAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,YAAY,KAAK,GAAG;AAE5D,QAAI,KAAK,KAAK;AACZ,aAAO,OAAO,KAAK,QAAQ,OAAO,EAAE,CAAC;AACrC;AAAA,IACF;AAGA,UAAM,UAAU,MAAM,KAAK,MAAM,aAAa;AAG9C,WAAO,KAAK,MAAM,SAAS;AAAA,MACzB,aAAa;AAAA,MACb,oBAAoB,EAAE,OAAO,iBAAiB;AAAA,IAChD,CAAC;AAAA,EACH;AAGA,QAAM,cAAc,kBAAkB,GAAG;AACzC,SAAO,KAAK,qBAAqB,aAAa;AAAA,IAC5C,aAAa;AAAA,IACb,oBAAoB,EAAE,OAAO,iBAAiB;AAAA,EAChD,CAAC;AAGD,MAAI,oBAAoB;AACtB,UAAM,gBAAgB;AACtB,UAAM,gBAAgB,YAAY,KAAK,aAAa;AAEpD,QAAI,eAAe;AACjB,YAAM,oBAAoB,MAAM,cAAc,MAAM,MAAM;AAC1D,YAAM,mBAAmB,qBAAqB,mBAAmB;AAAA,QAC/D;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,KAAK,eAAe,kBAAkB;AAAA,QAC3C,aAAa;AAAA,QACb,oBAAoB,EAAE,OAAO,iBAAiB;AAAA,MAChD,CAAC;AAAA,IACH;AAAA,EACF;AAGA,QAAM,cAAc,MAAM,OAAO,cAAc;AAAA,IAC7C,MAAM;AAAA,IACN,aAAa;AAAA,IACb,oBAAoB,EAAE,OAAO,iBAAiB;AAAA,EAChD,CAAC;AAED,SAAO;AACT;AAkTA,SAAS,qBACP,cACA,SACQ;AACR,MAAI,SAAS;AAEb,MAAI,QAAQ,oBAAoB;AAC9B,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAGnC,QAAI,OAAO,SAAS,mBAAmB,GAAG;AACxC,eAAS,OAAO;AAAA,QACd;AAAA,QACA,+CAA+C,GAAG;AAAA,MACpD;AAAA,IACF,OAAO;AAEL,eAAS,OAAO;AAAA,QACd;AAAA,QACA,+CAA+C,GAAG;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,YAAY;AAEtB,QAAI,OAAO,SAAS,oBAAoB,GAAG;AACzC,eAAS,OAAO;AAAA,QACd;AAAA,QACA,sBAAsB,cAAc,QAAQ,UAAU,CAAC;AAAA,MACzD;AAAA,IACF,OAAO;AAEL,eAAS,OAAO;AAAA,QACd;AAAA,QACA,sBAAsB,cAAc,QAAQ,UAAU,CAAC;AAAA,MACzD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,cAAc,MAAsB;AAC3C,SAAO,KAAK,QAAQ,MAAM,OAAO,EAAE,QAAQ,MAAM,MAAM,EAAE,QAAQ,MAAM,MAAM;AAC/E;AAmJA,eAAsB,kBAAwC;AAC5D,QAAM,MAAM,IAAI,cAAAC,QAAM;AAGtB,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASF;AAGA,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF;AAGA,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA,EAIF;AAGA,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcF;AAGA,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBF;AAGA,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA,+CAG2C,GAAG;AAAA,gDACF,GAAG;AAAA;AAAA,EAEjD;AAGA,MAAI;AAAA,IACF;AAAA,IACA;AAAA;AAAA;AAAA;AAAA;AAAA,EAKF;AAEA,SAAO,IAAI,cAAc;AAAA,IACvB,MAAM;AAAA,IACN,aAAa;AAAA,IACb,oBAAoB,EAAE,OAAO,EAAE;AAAA,EACjC,CAAC;AACH;AAQA,eAAsB,WAAW,KAAqC;AAEpE,QAAM,cAAc,MAAM,gBAAgB;AAG1C,QAAM,gBAA0B;AAAA,IAC9B,GAAG;AAAA,IACH,gBAAgB;AAAA,EAClB;AAGA,SAAO,WAAW,aAAa;AACjC;;;AKvrBO,SAAS,eAAe,KAAe,SAAiC;AAE7E,QAAM,gBAAgB,eAAe,kBAAkB,QAAQ,IAAI;AACnE,MAAI,eAAe;AAEjB,WAAO,cAAc,KAAK,OAAmE;AAAA,EAC/F;AAGA,UAAQ,QAAQ,MAAM;AAAA,IACpB,KAAK;AACH,aAAO,kBAAkB,KAAK,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,mBAAmB,KAAK,OAAO;AAAA,IACxC,KAAK;AACH,aAAO,kBAAkB,KAAK,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,kBAAkB,KAAK,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,uBAAuB,KAAK,OAAO;AAAA,IAC5C,KAAK;AACH,aAAO,kBAAkB,KAAK,OAAO;AAAA,IACvC,KAAK;AACH,aAAO,mBAAmB,KAAK,OAAO;AAAA,IACxC,KAAK;AACH,aAAO,mBAAmB,KAAK,OAAO;AAAA,IACxC,KAAK;AACH,aAAO,uBAAuB,KAAK,OAAO;AAAA,IAC5C,KAAK;AACH,aAAO,uBAAuB,KAAK,OAAO;AAAA,IAC5C,KAAK;AACH,aAAO,4BAA4B,KAAK,OAAO;AAAA,IACjD,KAAK;AACH,aAAO,uBAAuB,KAAK,OAAO;AAAA,IAC5C,KAAK;AACH,aAAO,sBAAsB,KAAK,OAAO;AAAA,IAC3C,KAAK;AACH,aAAO,mBAAmB,KAAK,OAAO;AAAA,IACxC,KAAK;AACH,aAAO,sBAAsB,KAAK,OAAO;AAAA,IAC3C;AAEE,YAAM,cAAqB;AAC3B,YAAM,IAAI,MAAM,yBAA0B,YAA6B,IAAI,EAAE;AAAA,EACjF;AACF;AAoBA,SAAS,cAAc,KAAyB;AAC9C,SAAO,KAAK,MAAM,KAAK,UAAU,GAAG,CAAC;AACvC;AAKA,SAAS,0BAA0B,MAAoB,gBAAgC;AACrF,MAAI,wBAAwB;AAC5B,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,QAAQ,KAAK;AAC5C,QAAI,KAAK,QAAQ,CAAC,EAAE,SAAS,aAAa;AACxC,UAAI,0BAA0B,gBAAgB;AAC5C,eAAO;AAAA,MACT;AACA;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAASC,kBAAiB,WAA8B;AACtD,MAAI,OAAO;AACX,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,OAAO;AACvB,iBAAW,WAAW,KAAK,SAAS;AAClC,YAAI,QAAQ,SAAS,QAAQ;AAC3B,kBAAQ,QAAQ;AAAA,QAClB;AAAA,MACF;AAAA,IACF,WAAW,KAAK,SAAS,aAAa;AACpC,iBAAW,SAAS,KAAK,UAAU;AACjC,YAAI,MAAM,SAAS,OAAO;AACxB,qBAAW,WAAW,MAAM,SAAS;AACnC,gBAAI,QAAQ,SAAS,QAAQ;AAC3B,sBAAQ,QAAQ;AAAA,YAClB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAKA,SAAS,cAAc,MAAc,YAAkC;AACrE,SAAO;AAAA,IACL,MAAM;AAAA,IACN;AAAA,IACA,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAMA,SAAS,mBACP,WACA,QACA,MACA,YACoB;AACpB,QAAM,aAAiC,CAAC;AACxC,MAAI,gBAAgB;AACpB,MAAI,WAAW;AAEf,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,UAAU,KAAK,QAClB,OAAO,CAAC,MAAwB,EAAE,SAAS,MAAM,EACjD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE;AAEV,YAAM,WAAW;AACjB,YAAM,SAAS,gBAAgB,QAAQ;AAEvC,UAAI,CAAC,YAAY,UAAU,YAAY,UAAU,QAAQ;AAEvD,cAAM,YAAY,SAAS;AAE3B,YAAI,YAAY,GAAG;AAEjB,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,GAAG,SAAS,EAAE,CAAC;AAAA,UAC/D,CAAC;AAAA,QACH;AAGA,mBAAW,KAAK,cAAc,MAAM,cAAc,KAAK,UAAU,CAAC;AAElE,YAAI,YAAY,QAAQ,QAAQ;AAE9B,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,EAAE,CAAC;AAAA,UAC5D,CAAC;AAAA,QACH;AAEA,mBAAW;AAAA,MACb,OAAO;AACL,mBAAW,KAAK,IAAI;AAAA,MACtB;AAEA,sBAAgB;AAAA,IAClB,OAAO;AACL,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAGA,MAAI,CAAC,UAAU;AACb,eAAW,KAAK,cAAc,MAAM,UAAU,CAAC;AAAA,EACjD;AAEA,SAAO;AACT;AAKA,SAAS,sBACP,WACA,aACA,WACoB;AACpB,QAAM,aAAiC,CAAC;AACxC,MAAI,gBAAgB;AAEpB,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,UAAU,KAAK,QAClB,OAAO,CAAC,MAAwB,EAAE,SAAS,MAAM,EACjD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE;AAEV,YAAM,WAAW;AACjB,YAAM,SAAS,gBAAgB,QAAQ;AAGvC,UAAI,UAAU,eAAe,YAAY,WAAW;AAElD,mBAAW,KAAK,IAAI;AAAA,MACtB,OAAO;AAEL,YAAI,UAAU;AAEd,YAAI,WAAW,aAAa;AAE1B,qBAAW,QAAQ,MAAM,GAAG,cAAc,QAAQ;AAAA,QACpD;AAEA,YAAI,SAAS,WAAW;AAEtB,qBAAW,QAAQ,MAAM,YAAY,QAAQ;AAAA,QAC/C;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,CAAC;AAAA,UAC3C,CAAC;AAAA,QACH;AAAA,MACF;AAEA,sBAAgB;AAAA,IAClB,OAAO;AACL,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,2BACP,WACA,aACA,WACA,YACoB;AACpB,QAAM,aAAiC,CAAC;AACxC,MAAI,gBAAgB;AAEpB,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,UAAU,KAAK,QAClB,OAAO,CAAC,MAAwB,EAAE,SAAS,MAAM,EACjD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE;AAEV,YAAM,WAAW;AACjB,YAAM,SAAS,gBAAgB,QAAQ;AAGvC,UAAI,UAAU,eAAe,YAAY,WAAW;AAElD,mBAAW,KAAK,IAAI;AAAA,MACtB,WAAW,YAAY,eAAe,UAAU,WAAW;AAEzD,mBAAW,KAAK;AAAA,UACd,GAAG;AAAA,UACH,YAAY,EAAE,GAAG,KAAK,YAAY,GAAG,WAAW;AAAA,QAClD,CAAC;AAAA,MACH,OAAO;AAEL,cAAM,eAAe,KAAK,IAAI,aAAa,QAAQ;AACnD,cAAM,aAAa,KAAK,IAAI,WAAW,MAAM;AAG7C,YAAI,WAAW,cAAc;AAC3B,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,GAAG,eAAe,QAAQ,EAAE,CAAC;AAAA,UAC7E,CAAC;AAAA,QACH;AAGA,mBAAW,KAAK;AAAA,UACd,GAAG;AAAA,UACH,YAAY,EAAE,GAAG,KAAK,YAAY,GAAG,WAAW;AAAA,UAChD,SAAS;AAAA,YACP;AAAA,cACE,MAAM;AAAA,cACN,MAAM,QAAQ,MAAM,eAAe,UAAU,aAAa,QAAQ;AAAA,YACpE;AAAA,UACF;AAAA,QACF,CAAC;AAGD,YAAI,SAAS,YAAY;AACvB,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,aAAa,QAAQ,EAAE,CAAC;AAAA,UACxE,CAAC;AAAA,QACH;AAAA,MACF;AAEA,sBAAgB;AAAA,IAClB,OAAO;AACL,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AACT;AASA,SAAS,kBAAkB,KAAe,SAAsC;AAC9E,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAC5B,QAAM,aAAa,0BAA0B,MAAM,QAAQ,SAAS,cAAc;AAElF,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,QAAQ,SAAS,cAAc,YAAY;AAAA,EAChF;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,YAAU,UAAU;AAAA,IAClB;AAAA,IACA,QAAQ,SAAS;AAAA,IACjB,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,KAAe,SAAuC;AAChF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,EAAE,OAAO,IAAI,IAAI,QAAQ;AAE/B,MAAI,MAAM,mBAAmB,IAAI,gBAAgB;AAE/C,UAAM,aAAa,0BAA0B,MAAM,MAAM,cAAc;AACvE,QAAI,eAAe,IAAI;AACrB,YAAM,IAAI,MAAM,mBAAmB,MAAM,cAAc,YAAY;AAAA,IACrE;AAEA,UAAM,YAAY,KAAK,QAAQ,UAAU;AAGzC,cAAU,UAAU,sBAAsB,WAAW,MAAM,QAAQ,IAAI,MAAM;AAG7E,cAAU,UAAU;AAAA,MAClB;AAAA,MACA,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAAA,EACF,OAAO;AAGL,UAAM,kBAAkB,0BAA0B,MAAM,MAAM,cAAc;AAC5E,UAAM,iBAAiB,KAAK,QAAQ,eAAe;AACnD,UAAM,YAAYA,kBAAiB,cAAc;AAEjD,mBAAe,UAAU,sBAAsB,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAC7F,mBAAe,UAAU;AAAA,MACvB;AAAA,MACA,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,QAAQ;AAAA,IACV;AAGA,UAAM,qBAA+B,CAAC;AACtC,aAAS,IAAI,MAAM,iBAAiB,GAAG,KAAK,IAAI,gBAAgB,KAAK;AACnE,yBAAmB,KAAK,0BAA0B,MAAM,CAAC,CAAC;AAAA,IAC5D;AAGA,aAAS,IAAI,mBAAmB,SAAS,GAAG,KAAK,GAAG,KAAK;AACvD,UAAI,mBAAmB,CAAC,MAAM,IAAI;AAChC,aAAK,QAAQ,OAAO,mBAAmB,CAAC,GAAG,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,KAAe,SAAsC;AAC9E,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,EAAE,OAAO,IAAI,IAAI,QAAQ;AAE/B,MAAI,MAAM,mBAAmB,IAAI,gBAAgB;AAE/C,UAAM,aAAa,0BAA0B,MAAM,MAAM,cAAc;AACvE,QAAI,eAAe,IAAI;AACrB,YAAM,IAAI,MAAM,mBAAmB,MAAM,cAAc,YAAY;AAAA,IACrE;AAEA,UAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,cAAU,UAAU,sBAAsB,WAAW,MAAM,QAAQ,IAAI,MAAM;AAAA,EAC/E,OAAO;AAGL,UAAM,kBAAkB,0BAA0B,MAAM,MAAM,cAAc;AAC5E,UAAM,iBAAiB,KAAK,QAAQ,eAAe;AACnD,UAAM,YAAYA,kBAAiB,cAAc;AACjD,mBAAe,UAAU,sBAAsB,gBAAgB,MAAM,QAAQ,UAAU,MAAM;AAG7F,UAAM,gBAAgB,0BAA0B,MAAM,IAAI,cAAc;AACxE,UAAM,eAAe,KAAK,QAAQ,aAAa;AAC/C,iBAAa,UAAU,sBAAsB,cAAc,GAAG,IAAI,MAAM;AAGxE,mBAAe,QAAQ,KAAK,GAAG,aAAa,OAAO;AAGnD,UAAM,kBAA4B,CAAC;AACnC,aAAS,IAAI,MAAM,iBAAiB,GAAG,KAAK,IAAI,gBAAgB,KAAK;AACnE,sBAAgB,KAAK,0BAA0B,MAAM,CAAC,CAAC;AAAA,IACzD;AAEA,aAAS,IAAI,gBAAgB,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,UAAI,gBAAgB,CAAC,MAAM,IAAI;AAC7B,aAAK,QAAQ,OAAO,gBAAgB,CAAC,GAAG,CAAC;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,KAAe,SAAsC;AAC9E,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,EAAE,OAAO,IAAI,IAAI,QAAQ;AAE/B,MAAI,MAAM,mBAAmB,IAAI,gBAAgB;AAE/C,UAAM,aAAa,0BAA0B,MAAM,MAAM,cAAc;AACvE,QAAI,eAAe,IAAI;AACrB,YAAM,IAAI,MAAM,mBAAmB,MAAM,cAAc,YAAY;AAAA,IACrE;AAEA,UAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,cAAU,UAAU;AAAA,MAClB;AAAA,MACA,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ;AAAA,IACV;AAAA,EACF,OAAO;AAEL,aAAS,IAAI,MAAM,gBAAgB,KAAK,IAAI,gBAAgB,KAAK;AAC/D,YAAM,aAAa,0BAA0B,MAAM,CAAC;AACpD,UAAI,eAAe,GAAI;AAEvB,YAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,YAAM,gBAAgBA,kBAAiB,SAAS;AAEhD,UAAI,cAAc;AAClB,UAAI,YAAY,cAAc;AAE9B,UAAI,MAAM,MAAM,gBAAgB;AAC9B,sBAAc,MAAM;AAAA,MACtB;AACA,UAAI,MAAM,IAAI,gBAAgB;AAC5B,oBAAY,IAAI;AAAA,MAClB;AAEA,gBAAU,UAAU;AAAA,QAClB;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,uBAAuB,KAAe,SAA2C;AACxF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,aAAa,0BAA0B,MAAM,QAAQ,cAAc;AACzE,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,QAAQ,cAAc,YAAY;AAAA,EACvE;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,YAAU,aAAa,EAAE,GAAG,UAAU,YAAY,GAAG,QAAQ,WAAW;AAGxE,MAAI,WAAW,QAAQ,YAAY;AACjC,UAAM,QAAQ,QAAQ,WAAW;AACjC,QAAI,SAAS,MAAM,UAAU,UAAa,MAAM,UAAU,GAAG;AAE3D,YAAM,OAAO,MAAM,QAAQ;AAC3B,YAAM,WAAW,MAAM,UAAU;AAGjC,UAAI,SAAS,WAAW,WAAM,GAAG,CAAC;AAElC,UAAI,OAAO,QAAQ,WAAW;AAC5B,cAAM,MAAM,OAAO,QAAQ,UAAU,KAAK,KAAK,CAAC,MAAM,EAAE,UAAU,MAAM,KAAK;AAC7E,YAAI,KAAK;AACP,gBAAM,cAAc,OAAO,QAAQ,UAAU,aAAa;AAAA,YACxD,CAAC,MAAM,EAAE,kBAAkB,IAAI;AAAA,UACjC;AACA,cAAI,aAAa;AACf,kBAAM,QAAQ,YAAY,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAC5D,gBAAI,OAAO;AACT,uBAAS,MAAM,WAAW;AAAA,YAC5B;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,gBAAU,gBAAgB;AAAA,QACxB,OAAO;AAAA,QACP,OAAO,MAAM;AAAA,QACb;AAAA,QACA;AAAA,MACF;AAAA,IACF,OAAO;AAEL,aAAO,UAAU;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,kBAAkB,KAAe,SAAsC;AAC9E,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,aAAa,0BAA0B,MAAM,QAAQ,cAAc;AACzE,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,QAAQ,cAAc,YAAY;AAAA,EACvE;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,YAAU,aAAa;AAAA,IACrB,GAAG,UAAU;AAAA,IACb,SAAS,QAAQ;AAAA,EACnB;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,KAAe,SAAuC;AAChF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAG5B,QAAM,OAAmB,CAAC;AAE1B,WAAS,IAAI,GAAG,IAAI,QAAQ,MAAM,KAAK;AACrC,UAAM,QAAqB,CAAC;AAE5B,aAAS,IAAI,GAAG,IAAI,QAAQ,SAAS,KAAK;AACxC,YAAM,WAAW,QAAQ,OAAO,CAAC,IAAI,CAAC,KAAK;AAC3C,YAAM,KAAK;AAAA,QACT,MAAM;AAAA,QACN,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,SAAS,WAAW,CAAC,cAAc,QAAQ,CAAC,IAAI,CAAC;AAAA,UACnD;AAAA,QACF;AAAA,MACF,CAAC;AAAA,IACH;AAEA,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,YAAY,MAAM,KAAK,QAAQ,YAAY,EAAE,QAAQ,KAAK,IAAI;AAAA,MAC9D;AAAA,IACF,CAAC;AAAA,EACH;AAEA,QAAM,QAAe;AAAA,IACnB,MAAM;AAAA,IACN;AAAA,EACF;AAGA,QAAM,aAAa,0BAA0B,MAAM,QAAQ,SAAS,cAAc;AAClF,MAAI,eAAe,IAAI;AACrB,SAAK,QAAQ,KAAK,KAAK;AAAA,EACzB,OAAO;AACL,SAAK,QAAQ,OAAO,aAAa,GAAG,GAAG,KAAK;AAAA,EAC9C;AAEA,SAAO;AACT;AAKA,SAAS,mBAAmB,KAAe,SAAuC;AAChF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,aAAa,0BAA0B,MAAM,QAAQ,SAAS,cAAc;AAClF,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,QAAQ,SAAS,cAAc,YAAY;AAAA,EAChF;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AAGzC,QAAM,QAAe;AAAA,IACnB,MAAM;AAAA,IACN,KAAK,WAAW,KAAK,IAAI,CAAC;AAAA,IAC1B,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ;AAAA,IACb,MAAM;AAAA,MACJ,QAAQ,QAAQ,SAAS,OAAO;AAAA;AAAA,MAChC,SAAS,QAAQ,UAAU,OAAO;AAAA,IACpC;AAAA,IACA,MAAM,EAAE,MAAM,SAAS;AAAA,EACzB;AAGA,QAAM,WAAgB;AAAA,IACpB,MAAM;AAAA,IACN,SAAS;AAAA,MACP;AAAA,QACE,MAAM;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,aAAa,mBAAmB,WAAW,QAAQ,SAAS,QAAQ,IAAI,MAAS;AAEvF,MAAI,WAAW;AACf,MAAI,gBAAgB;AAEpB,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,OAAO,WAAW,CAAC;AACzB,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,UAAU,KAAK,QAClB,OAAO,CAAC,MAAwB,EAAE,SAAS,MAAM,EACjD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE;AACV,uBAAiB,QAAQ;AAEzB,UAAI,CAAC,YAAY,iBAAiB,QAAQ,SAAS,QAAQ;AACzD,mBAAW,OAAO,IAAI,GAAG,GAAG,QAAQ;AACpC,mBAAW;AACX;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,UAAU;AACb,eAAW,KAAK,QAAQ;AAAA,EAC1B;AAEA,YAAU,UAAU;AAEpB,SAAO;AACT;AAKA,SAAS,uBAAuB,KAAe,SAA2C;AACxF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,EAAE,OAAO,IAAI,IAAI,QAAQ;AAE/B,MAAI,MAAM,mBAAmB,IAAI,gBAAgB;AAC/C,UAAM,IAAI,MAAM,4CAA4C;AAAA,EAC9D;AAEA,QAAM,aAAa,0BAA0B,MAAM,MAAM,cAAc;AACvE,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,MAAM,cAAc,YAAY;AAAA,EACrE;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,QAAM,gBAAgBA,kBAAiB,SAAS;AAGhD,QAAM,WAAW,QAAQ,eAAe,cAAc,MAAM,MAAM,QAAQ,IAAI,MAAM;AAGpF,YAAU,UAAU,sBAAsB,WAAW,MAAM,QAAQ,IAAI,MAAM;AAG7E,QAAM,YAAuB;AAAA,IAC3B,MAAM;AAAA,IACN,MAAM,QAAQ;AAAA,IACd,SAAS,QAAQ;AAAA,IACjB,UAAU,CAAC,cAAc,QAAQ,CAAC;AAAA,EACpC;AAGA,MAAI,WAAW;AACf,MAAI,gBAAgB;AACpB,QAAM,aAAiC,CAAC;AAExC,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,UAAU,KAAK,QAClB,OAAO,CAAC,MAAwB,EAAE,SAAS,MAAM,EACjD,IAAI,CAAC,MAAM,EAAE,IAAI,EACjB,KAAK,EAAE;AAEV,YAAM,SAAS,gBAAgB,QAAQ;AAEvC,UAAI,CAAC,YAAY,iBAAiB,MAAM,UAAU,MAAM,UAAU,QAAQ;AACxE,cAAM,YAAY,MAAM,SAAS;AAEjC,YAAI,YAAY,GAAG;AACjB,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,GAAG,SAAS,EAAE,CAAC;AAAA,UAC/D,CAAC;AAAA,QACH;AAEA,mBAAW,KAAK,SAAS;AAEzB,YAAI,YAAY,QAAQ,QAAQ;AAC9B,qBAAW,KAAK;AAAA,YACd,GAAG;AAAA,YACH,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,EAAE,CAAC;AAAA,UAC5D,CAAC;AAAA,QACH;AAEA,mBAAW;AAAA,MACb,OAAO;AACL,mBAAW,KAAK,IAAI;AAAA,MACtB;AAEA,sBAAgB;AAAA,IAClB,OAAO;AACL,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,CAAC,UAAU;AACb,eAAW,KAAK,SAAS;AAAA,EAC3B;AAEA,YAAU,UAAU;AAEpB,SAAO;AACT;AAKA,SAAS,uBAAuB,KAAe,SAA2C;AACxF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,EAAE,MAAM,IAAI,QAAQ;AAE1B,QAAM,aAAa,0BAA0B,MAAM,MAAM,cAAc;AACvE,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,MAAM,cAAc,YAAY;AAAA,EACrE;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,QAAM,aAAiC,CAAC;AAExC,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,aAAa;AAE7B,iBAAW,SAAS,KAAK,UAAU;AACjC,YAAI,MAAM,SAAS,OAAO;AACxB,qBAAW,KAAK,KAAK;AAAA,QACvB;AAAA,MACF;AAAA,IACF,OAAO;AACL,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,YAAU,UAAU;AAEpB,SAAO;AACT;AAKA,SAAS,4BACP,KACA,SACU;AACV,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,aAAa,0BAA0B,MAAM,QAAQ,SAAS,cAAc;AAClF,MAAI,eAAe,IAAI;AACrB,UAAM,IAAI,MAAM,mBAAmB,QAAQ,SAAS,cAAc,YAAY;AAAA,EAChF;AAEA,QAAM,YAAY,KAAK,QAAQ,UAAU;AACzC,QAAM,gBAAgBA,kBAAiB,SAAS;AAGhD,QAAM,gBAAgB;AAAA,IACpB,EAAE,GAAG,WAAW,SAAS,CAAC,GAAG,UAAU,OAAO,EAAE;AAAA,IAChD,QAAQ,SAAS;AAAA,IACjB,cAAc;AAAA,EAChB;AAEA,QAAM,eAAe;AAAA,IACnB,EAAE,GAAG,WAAW,SAAS,CAAC,GAAG,UAAU,OAAO,EAAE;AAAA,IAChD;AAAA,IACA,QAAQ,SAAS;AAAA,EACnB;AAGA,YAAU,UAAU;AAGpB,QAAM,eAA0B;AAAA,IAC9B,MAAM;AAAA,IACN,YAAY,UAAU;AAAA,IACtB,SAAS;AAAA,EACX;AAGA,OAAK,QAAQ,OAAO,aAAa,GAAG,GAAG,YAAY;AAEnD,SAAO;AACT;AAKA,SAAS,uBAAuB,KAAe,SAA2C;AACxF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAE5B,QAAM,kBAAkB,0BAA0B,MAAM,QAAQ,cAAc;AAC9E,MAAI,oBAAoB,IAAI;AAC1B,UAAM,IAAI,MAAM,mBAAmB,QAAQ,cAAc,YAAY;AAAA,EACvE;AAEA,QAAM,gBAAgB,KAAK,QAAQ,eAAe;AAGlD,QAAM,kBAA4B,CAAC;AAEnC,WAAS,IAAI,GAAG,KAAK,QAAQ,OAAO,KAAK;AACvC,UAAM,aAAa,0BAA0B,MAAM,QAAQ,iBAAiB,CAAC;AAC7E,QAAI,eAAe,IAAI;AACrB,YAAM,OAAO,KAAK,QAAQ,UAAU;AACpC,oBAAc,QAAQ,KAAK,GAAG,KAAK,OAAO;AAC1C,sBAAgB,KAAK,UAAU;AAAA,IACjC;AAAA,EACF;AAGA,WAAS,IAAI,gBAAgB,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,SAAK,QAAQ,OAAO,gBAAgB,CAAC,GAAG,CAAC;AAAA,EAC3C;AAEA,SAAO;AACT;AAKA,SAAS,sBAAsB,KAAe,SAA0C;AAEtF,SAAO,4BAA4B,KAAK;AAAA,IACtC,MAAM;AAAA,IACN,UAAU,QAAQ;AAAA,EACpB,CAAC;AACH;AAKA,SAAS,mBAAmB,KAAe,SAAuC;AAChF,QAAM,SAAS,cAAc,GAAG;AAGhC,MAAI,CAAC,OAAO,mBAAmB;AAC7B,WAAO,oBAAoB,CAAC;AAAA,EAC9B;AAEA,MAAI,CAAC,OAAO,kBAAkB,SAAS,QAAQ,IAAI,GAAG;AACpD,WAAO,kBAAkB,KAAK,QAAQ,IAAI;AAAA,EAC5C;AAGA,SAAO;AACT;AAKA,SAAS,sBAAsB,KAAe,SAA0C;AACtF,QAAM,SAAS,cAAc,GAAG;AAChC,QAAM,OAAO,OAAO,QAAQ;AAG5B,WAAS,sBAAsB,KAAgB;AAC7C,eAAW,WAAW,IAAI,SAAS;AACjC,UAAI,QAAQ,SAAS,QAAQ;AAC3B,mBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AAC1D,gBAAM,UAAU,IAAI,OAAO,MAAM,IAAI,OAAO,GAAG;AAC/C,kBAAQ,OAAO,QAAQ,KAAK,QAAQ,SAAS,KAAK;AAAA,QACpD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,WAAS,4BAA4B,WAA4B;AAC/D,eAAW,QAAQ,UAAU,SAAS;AACpC,UAAI,KAAK,SAAS,OAAO;AACvB,8BAAsB,IAAI;AAAA,MAC5B,WAAW,KAAK,SAAS,aAAa;AACpC,mBAAW,SAAS,KAAK,UAAU;AACjC,cAAI,MAAM,SAAS,OAAO;AACxB,kCAAsB,KAAK;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,WAAS,wBAAwB,OAA2B;AAC1D,QAAI,MAAM,SAAS,aAAa;AAC9B,kCAA4B,KAAK;AAAA,IACnC,WAAW,MAAM,SAAS,SAAS;AACjC,iBAAW,OAAO,MAAM,MAAM;AAC5B,mBAAW,QAAQ,IAAI,OAAO;AAC5B,qBAAW,aAAa,KAAK,SAAS;AACpC,oCAAwB,SAAS;AAAA,UACnC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,aAAW,SAAS,KAAK,SAAS;AAChC,4BAAwB,KAAK;AAAA,EAC/B;AAEA,SAAO;AACT;;;AC/gCA,IAAM,mBAA+B;AAAA,EACnC,MAAM;AAAA,EACN,aAAa;AACf;AAEA,IAAM,iBAA6B;AAAA,EACjC,MAAM;AAAA,EACN,YAAY;AAAA,IACV,gBAAgB;AAAA,MACd,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EACA,UAAU,CAAC,kBAAkB,QAAQ;AACvC;AAEA,IAAM,cAA0B;AAAA,EAC9B,MAAM;AAAA,EACN,YAAY;AAAA,IACV,OAAO;AAAA,IACP,KAAK;AAAA,EACP;AAAA,EACA,UAAU,CAAC,SAAS,KAAK;AAC3B;AASO,IAAM,mBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,aAAa;AAAA;AAAA;AAAA,EAIb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,MACA,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,SAAS;AAAA,EACtB;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,SAAS,OAAO,IAAI;AAE5B,QAAI;AAEF,YAAM,eAAe,KAAK,OAAO;AACjC,YAAM,QAAQ,IAAI,WAAW,aAAa,MAAM;AAChD,eAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAM,CAAC,IAAI,aAAa,WAAW,CAAC;AAAA,MACtC;AACA,YAAM,SAAS,MAAM;AAGrB,YAAMC,YAAW,MAAM,UAAU,MAAM;AAGvC,YAAM,QAAQ,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAG1E,cAAQ,QAAQ,UAAU,IAAI,OAAO;AAAA,QACnC,IAAI;AAAA,QACJ,UAAAA;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc,KAAK,IAAI;AAAA,MACzB,CAAC;AAGD,YAAM,iBAAiBA,UAAS,QAAQ,SAAS,QAAQ;AAAA,QACvD,CAAC,MAAM,EAAE,SAAS;AAAA,MACpB,EAAE;AAEF,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,YAAY;AAAA,cACZ;AAAA,cACA;AAAA,cACA,SAAS;AAAA,YACX,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,4BAA6B,MAAgB,OAAO,GAAG,CAAC;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAKO,IAAM,mBAAsC;AAAA,EACjD,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,UAAU,CAAC,YAAY;AAAA,EACzB;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,WAAW,IAAI;AAEvB,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI;AAEF,UAAI;AACJ,UAAI,OAAO,QAAQ;AAEjB,iBAAS,MAAM,WAAW,OAAO,QAAQ;AAAA,MAC3C,OAAO;AAEL,iBAAS,MAAM,WAAW,OAAO,QAAQ;AAAA,MAC3C;AAGA,YAAM,QAAQ,IAAI,WAAW,MAAM;AACnC,UAAI,SAAS;AACb,eAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,kBAAU,OAAO,aAAa,MAAM,CAAC,CAAC;AAAA,MACxC;AACA,YAAM,SAAS,KAAK,MAAM;AAE1B,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB;AAAA,cACA;AAAA,cACA,MAAM,OAAO;AAAA,cACb,SAAS;AAAA,YACX,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,4BAA6B,MAAgB,OAAO,GAAG,CAAC;AAAA,MAC1F;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAKO,IAAM,oBAAuC;AAAA,EAClD,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,UAAU,CAAC,YAAY;AAAA,EACzB;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,WAAW,IAAI;AAEvB,QAAI,CAAC,QAAQ,QAAQ,UAAU,IAAI,UAAU,GAAG;AAC9C,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,YAAQ,QAAQ,UAAU,OAAO,UAAU;AAE3C,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA,SAAS;AAAA,UACX,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AASO,IAAM,sBAAyC;AAAA,EACpD,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,IACd;AAAA,IACA,UAAU,CAAC,YAAY;AAAA,EACzB;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,WAAW,IAAI;AAEvB,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,UAAM,MAAM,OAAO;AACnB,UAAM,OAAO,IAAI,QAAQ;AAEzB,UAAM,aAAa,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,WAAW;AACpE,UAAM,SAAS,KAAK,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,OAAO;AAG5D,QAAI,YAAY;AAChB,eAAW,QAAQ,YAAY;AAC7B,UAAI,KAAK,SAAS,aAAa;AAC7B,cAAM,OAAOC,kBAAiB,IAAI;AAClC,qBAAa,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE;AAAA,MAC7D;AAAA,IACF;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA,gBAAgB,WAAW;AAAA,YAC3B,YAAY,OAAO;AAAA,YACnB;AAAA,YACA,WAAW,CAAC,CAAC,IAAI,QAAQ;AAAA,YACzB,UAAU,CAAC,CAAC,IAAI,QAAQ;AAAA,YACxB,QAAQ,OAAO;AAAA,YACf,cAAc,OAAO;AAAA,UACvB,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAKO,IAAM,sBAAyC;AAAA,EACpD,MAAM;AAAA,EACN,aAAa;AAAA;AAAA;AAAA,EAIb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,MACZ,WAAW;AAAA,QACT,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,UAAU,CAAC,YAAY;AAAA,EACzB;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,YAAY,YAAY,IAAM,IAAI;AAK1C,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,UAAM,OAAO,OAAO,SAAS,QAAQ;AACrC,UAAM,QAAkB,CAAC;AAEzB,eAAW,SAAS,KAAK,SAAS;AAChC,UAAI,MAAM,SAAS,aAAa;AAC9B,cAAM,KAAKA,kBAAiB,KAAK,CAAC;AAAA,MACpC,WAAW,MAAM,SAAS,SAAS;AACjC,cAAM,KAAK,SAAS;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,OAAO,MAAM,KAAK,IAAI;AAC1B,UAAM,YAAY,KAAK,SAAS;AAChC,QAAI,WAAW;AACb,aAAO,KAAK,MAAM,GAAG,SAAS,IAAI;AAAA,IACpC;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,MAAM,KAAK,UAAU;AAAA,YACnB;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAa,YAAY,MAAM,KAAK,IAAI,EAAE,SAAS,KAAK;AAAA,UAC1D,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AASO,IAAM,iBAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,cAAc,YAAY,MAAM;AAAA,EAC7C;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,YAAY,UAAU,KAAK,IAAI;AAMvC,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,eAAe,OAAO,UAAU;AAAA,QAC7C,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,WAAW;AAClB,aAAO,eAAe,KAAK,IAAI;AAE/B,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,SAAS;AAAA,cACT,gBAAgB,KAAK;AAAA,cACrB;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,0BAA2B,MAAgB,OAAO,GAAG,CAAC;AAAA,MACxF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAKO,IAAM,kBAAqC;AAAA,EAChD,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,MAAM;AAAA,QACJ,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,cAAc,SAAS,MAAM;AAAA,EAC1C;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,YAAY,OAAO,KAAK,IAAI;AASpC,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,eAAe,OAAO,UAAU;AAAA,QAC7C,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,WAAW;AAClB,aAAO,eAAe,KAAK,IAAI;AAE/B,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,SAAS;AAAA,cACT,eAAe;AAAA,cACf,eAAe,KAAK;AAAA,YACtB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,2BAA4B,MAAgB,OAAO,GAAG,CAAC;AAAA,MACzF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAKO,IAAM,iBAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IACA,UAAU,CAAC,cAAc,OAAO;AAAA,EAClC;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,YAAY,MAAM,IAAI;AAQ9B,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,eAAe,OAAO,UAAU;AAAA,QAC7C,MAAM;AAAA,QACN;AAAA,MACF,CAAC;AAED,aAAO,WAAW;AAClB,aAAO,eAAe,KAAK,IAAI;AAE/B,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,SAAS;AAAA,cACT,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,0BAA2B,MAAgB,OAAO,GAAG,CAAC;AAAA,MACxF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AASO,IAAM,iBAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,MACZ,OAAO;AAAA,MACP,YAAY;AAAA,QACV,MAAM;AAAA,QACN,aAAa;AAAA,QACb,YAAY;AAAA,UACV,MAAM,EAAE,MAAM,UAAU;AAAA,UACxB,QAAQ,EAAE,MAAM,UAAU;AAAA,UAC1B,WAAW,EAAE,MAAM,UAAU;AAAA,UAC7B,eAAe,EAAE,MAAM,UAAU;AAAA,UACjC,UAAU,EAAE,MAAM,UAAU,aAAa,sBAAsB;AAAA,UAC/D,YAAY,EAAE,MAAM,SAAS;AAAA,UAC7B,OAAO,EAAE,MAAM,UAAU,aAAa,8BAA8B;AAAA,UACpE,WAAW,EAAE,MAAM,UAAU,aAAa,uBAAuB;AAAA,QACnE;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU,CAAC,cAAc,SAAS,YAAY;AAAA,EAChD;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,YAAY,OAAO,WAAW,IAAI;AAS1C,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,eAAe,OAAO,UAAU;AAAA,QAC7C,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,WAAW;AAClB,aAAO,eAAe,KAAK,IAAI;AAE/B,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,SAAS;AAAA,cACT;AAAA,cACA,mBAAmB;AAAA,YACrB,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,0BAA2B,MAAgB,OAAO,GAAG,CAAC;AAAA,MACxF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAKO,IAAM,iBAAoC;AAAA,EAC/C,MAAM;AAAA,EACN,aAAa;AAAA;AAAA,EAGb,aAAa;AAAA,IACX,MAAM;AAAA,IACN,YAAY;AAAA,MACV,YAAY;AAAA,MACZ,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,aAAa;AAAA,QACb,SAAS;AAAA,MACX;AAAA,MACA,SAAS;AAAA,QACP,MAAM;AAAA,QACN,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,UAAU,CAAC,cAAc,kBAAkB,SAAS;AAAA,EACtD;AAAA,EAEA,SAAS,OAAO,OAAgB,YAAoD;AAClF,UAAM,EAAE,YAAY,gBAAgB,QAAQ,IAAI;AAMhD,UAAM,SAAS,QAAQ,QAAQ,UAAU,IAAI,UAAU;AACvD,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,uBAAuB,UAAU,GAAG,CAAC;AAAA,MACvE;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,eAAe,OAAO,UAAU;AAAA,QAC7C,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF,CAAC;AAED,aAAO,WAAW;AAClB,aAAO,eAAe,KAAK,IAAI;AAE/B,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU;AAAA,cACnB,SAAS;AAAA,cACT;AAAA,cACA;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,SAAS,CAAC,EAAE,MAAM,QAAQ,MAAM,0BAA2B,MAAgB,OAAO,GAAG,CAAC;AAAA,MACxF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,aAAa;AAAA,IACX,UAAU;AAAA,IACV,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACF;AAQA,SAASA,kBAAiB,WAA8B;AACtD,QAAM,QAAkB,CAAC;AAEzB,aAAW,QAAQ,UAAU,SAAS;AACpC,QAAI,KAAK,SAAS,OAAO;AACvB,YAAM,KAAK,WAAW,IAAI,CAAC;AAAA,IAC7B,WAAW,KAAK,SAAS,aAAa;AACpC,YAAM,KAAK,iBAAiB,IAAI,CAAC;AAAA,IACnC;AAAA,EACF;AAEA,SAAO,MAAM,KAAK,EAAE;AACtB;AAEA,SAAS,WAAW,KAAkB;AACpC,SAAO,IAAI,QACR,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAqC,IAAI,EACrD,KAAK,EAAE;AACZ;AAEA,SAAS,iBAAiB,WAA8B;AACtD,QAAM,QAAkB,CAAC;AACzB,aAAW,SAAS,UAAU,UAAU;AACtC,QAAI,MAAM,SAAS,OAAO;AACxB,YAAM,KAAK,WAAW,KAAK,CAAC;AAAA,IAC9B;AAAA,EACF;AACA,SAAO,MAAM,KAAK,EAAE;AACtB;AAMO,IAAM,eAAoC;AAAA;AAAA,EAE/C;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA;AAAA,EACA;AACF;;;AC5vBO,SAAS,gBAAgB,SAA0B,CAAC,GAAc;AACvE,QAAM;AAAA,IACJ,OAAO;AAAA,IACP,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,QAAQ;AAAA,IACR,kBAAkB,CAAC;AAAA,EACrB,IAAI;AAEJ,QAAM,QAAQ,oBAAI,IAA+B;AAGjD,QAAM,UAAsB;AAAA,IAC1B,IAAI,WAAW,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAAA,IACpE,WAAW,oBAAI,IAA4B;AAAA,IAC3C,MAAM,oBAAI,IAAqB;AAAA,EACjC;AAGA,MAAI,kBAAkB;AACpB,eAAW,QAAQ,cAAc;AAC/B,YAAM,IAAI,KAAK,MAAM,IAAI;AACzB,UAAI,OAAO;AACT,gBAAQ,IAAI,+BAA+B,KAAK,IAAI,EAAE;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AAGA,QAAM,cAAc,eAAe,YAAY;AAC/C,aAAW,QAAQ,aAAa;AAC9B,QAAI,MAAM,IAAI,KAAK,IAAI,GAAG;AACxB,cAAQ,KAAK,eAAe,KAAK,IAAI,uCAAuC;AAAA,IAC9E;AACA,UAAM,IAAI,KAAK,MAAM,IAAI;AACzB,QAAI,OAAO;AACT,cAAQ,IAAI,iCAAiC,KAAK,IAAI,EAAE;AAAA,IAC1D;AAAA,EACF;AAGA,aAAW,QAAQ,iBAAiB;AAClC,UAAM,IAAI,KAAK,MAAM,IAAI;AACzB,QAAI,OAAO;AACT,cAAQ,IAAI,qCAAqC,KAAK,IAAI,EAAE;AAAA,IAC9D;AAAA,EACF;AAGA,QAAM,MAAM,QACR,CAAC,SAAiB,SAAmB;AACnC,YAAQ,IAAI,SAAS,OAAO,IAAI,QAAQ,EAAE;AAAA,EAC5C,IACA,MAAM;AAAA,EAAC;AAGX,iBAAe,eAAe,UAAkB,OAAkC;AAChF,UAAM,OAAO,MAAM,IAAI,QAAQ;AAC/B,QAAI,CAAC,MAAM;AACT,YAAM,IAAI,MAAM,iBAAiB,QAAQ,EAAE;AAAA,IAC7C;AAEA,QAAI,iBAAiB,QAAQ,IAAI,KAAK;AAGtC,UAAM,UAA0B;AAAA,MAC9B;AAAA,MACA;AAAA,IACF;AAGA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,QAAQ,OAAO,OAAO;AAChD,UAAI,QAAQ,QAAQ,cAAc,MAAM;AACxC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,QAAQ,QAAQ,WAAW,KAAK;AACpC,YAAM;AAAA,IACR;AAAA,EACF;AAGA,WAAS,YAA2B;AAClC,WAAO,MAAM,KAAK,MAAM,OAAO,CAAC,EAAE,IAAI,CAAC,UAAU;AAAA,MAC/C,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,aAAa,oBAAoB,KAAK,WAAW;AAAA,MACjD,UAAU,KAAK,aAAa;AAAA,IAC9B,EAAE;AAAA,EACJ;AAGA,WAAS,UAAU;AACjB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW,MAAM;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAiCA,eAAsB,qBACpB,QACA,SAC0B;AAC1B,QAAM,EAAE,IAAI,QAAQ,OAAO,IAAI;AAE/B,MAAI;AACF,YAAQ,QAAQ;AAAA,MACd,KAAK,cAAc;AACjB,eAAO;AAAA,UACL,SAAS;AAAA,UACT;AAAA,UACA,QAAQ;AAAA,YACN,iBAAiB;AAAA,YACjB,cAAc;AAAA,cACZ,OAAO,CAAC;AAAA,YACV;AAAA,YACA,YAAY,OAAO,QAAQ;AAAA,UAC7B;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,QAAQ,OAAO,UAAU;AAC/B,eAAO;AAAA,UACL,SAAS;AAAA,UACT;AAAA,UACA,QAAQ;AAAA,YACN,OAAO,MAAM,IAAI,CAAC,OAAO;AAAA,cACvB,MAAM,EAAE;AAAA,cACR,aAAa,EAAE;AAAA,cACf,aAAa,EAAE;AAAA,YACjB,EAAE;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAAA,MAEA,KAAK,cAAc;AACjB,cAAM,EAAE,MAAM,WAAW,KAAK,IAAI;AAIlC,cAAM,SAAS,MAAM,OAAO,eAAe,MAAM,IAAI;AACrD,eAAO;AAAA,UACL,SAAS;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MAEA;AACE,eAAO;AAAA,UACL,SAAS;AAAA,UACT;AAAA,UACA,OAAO;AAAA,YACL,MAAM;AAAA,YACN,SAAS,qBAAqB,MAAM;AAAA,UACtC;AAAA,QACF;AAAA,IACJ;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,SAAS;AAAA,MACT;AAAA,MACA,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAU,MAAgB;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACF;AAYA,eAAsB,iBAAiB,SAA0B,CAAC,GAAkB;AAClF,QAAM,SAAS,gBAAgB,MAAM;AAErC,MAAI,OAAO,OAAO;AAChB,YAAQ,MAAM,yBAAyB,OAAO,QAAQ,EAAE,IAAI,KAAK,OAAO,QAAQ,EAAE,OAAO,EAAE;AAC3F,YAAQ,MAAM,2BAA2B,OAAO,MAAM,IAAI,EAAE;AAAA,EAC9D;AAGA,QAAM,WAAW,MAAM,OAAO,UAAU;AACxC,QAAM,KAAK,SAAS,gBAAgB;AAAA,IAClC,OAAO,QAAQ;AAAA,IACf,QAAQ,QAAQ;AAAA,IAChB,UAAU;AAAA,EACZ,CAAC;AAED,MAAI,SAAS;AAEb,KAAG,GAAG,QAAQ,OAAO,SAAS;AAC5B,cAAU;AAGV,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,MAAM;AACjC,eAAS;AAET,YAAM,WAAW,MAAM,qBAAqB,QAAQ,OAAO;AAG3D,cAAQ,OAAO,MAAM,KAAK,UAAU,QAAQ,IAAI,IAAI;AAAA,IACtD,QAAQ;AAAA,IAER;AAAA,EACF,CAAC;AAED,KAAG,GAAG,SAAS,MAAM;AACnB,QAAI,OAAO,OAAO;AAChB,cAAQ,MAAM,qBAAqB;AAAA,IACrC;AACA,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;AASA,SAAS,oBAAoB,QAA0C;AAErE,MACE,OAAO,WAAW,YAClB,WAAW,SACV,UAAU,UAAU,gBAAgB,SACrC;AACA,WAAO;AAAA,EACT;AAIA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY,CAAC;AAAA,EACf;AACF;","names":["JSZip","parseColorElement","abstractNum","parseColorValue","parseShadingProperties","parseRunProperties","getLocalName","getLocalName","parseBookmarkStart","parseBookmarkEnd","parseTableMeasurement","parseBorderSpec","parseTableBorders","parseCellMargins","parseTableLook","parseTableProperties","parseTableRowProperties","parseTableCellProperties","parseNumberFormat","parseColorValue","parseBorderSpec","parseColorValue","parseShadingProperties","parseBorderSpec","parseTabStops","parseParagraphProperties","parseRunProperties","getLocalName","parseHyperlink","parseBookmarkStart","parseBookmarkEnd","document","import_jszip","escapeXml","serializeShading","escapeXml","serializeBorder","serializeShading","serializeBorder","JSZip","JSZip","getParagraphText","document","getParagraphText"]}
|